diff --git a/modules/charset/escape_stream.go b/modules/charset/escape_stream.go
index 22e7f14f39..98a25e9e55 100644
--- a/modules/charset/escape_stream.go
+++ b/modules/charset/escape_stream.go
@@ -199,12 +199,20 @@ func (e *escapeStreamer) invisibleRune(r rune) error {
e.escaped.Escaped = true
e.escaped.HasInvisible = true
+ // Use Unicode Control Pictures for ASCII control chars
+ escaped := fmt.Sprintf("[U+%04X]", r)
+ if r >= 0 && r <= 0x1f {
+ escaped = string(0x2400 + r)
+ } else if r == 0x7f {
+ escaped = string(rune(0x2421))
+ }
+
if err := e.PassthroughHTMLStreamer.StartTag("span", html.Attribute{
Key: "class",
Val: "escaped-code-point",
}, html.Attribute{
Key: "data-escaped",
- Val: fmt.Sprintf("[U+%04X]", r),
+ Val: escaped,
}); err != nil {
return err
}
diff --git a/modules/charset/escape_test.go b/modules/charset/escape_test.go
index 9d796a0c18..d79a4df6c6 100644
--- a/modules/charset/escape_test.go
+++ b/modules/charset/escape_test.go
@@ -151,7 +151,7 @@ func TestEscapeControlReader(t *testing.T) {
for _, test := range escapeControlTests {
test.name += " (+Control)"
test.text = addPrefix("\u001E", test.text)
- test.result = addPrefix(``+"\u001e"+``, test.result)
+ test.result = addPrefix(``+"\u001e"+``, test.result)
test.status.Escaped = true
test.status.HasInvisible = true
tests = append(tests, test)
diff --git a/modules/highlight/highlight.go b/modules/highlight/highlight.go
index addc372f85..35d041527a 100644
--- a/modules/highlight/highlight.go
+++ b/modules/highlight/highlight.go
@@ -43,20 +43,12 @@ func globalVars() *globalVarsType {
globalVarsPtr.githubStyles = styles.Get("github")
globalVarsPtr.highlightMapping = setting.GetHighlightMapping()
globalVarsPtr.escCtrlCharsMap = make([]template.HTML, 256)
- // ASCII Table 0x00 - 0x1F
- controlCharNames := []string{
- "NUL", "SOH", "STX", "ETX", "EOT", "ENQ", "ACK", "BEL",
- "BS", "HT", "LF", "VT", "FF", "CR", "SO", "SI",
- "DLE", "DC1", "DC2", "DC3", "DC4", "NAK", "SYN", "ETB",
- "CAN", "EM", "SUB", "ESC", "FS", "GS", "RS", "US",
+ // ASCII control characters 0x00-0x1F map to Unicode Control Pictures U+2400-U+241F
+ for i := range 0x20 {
+ globalVarsPtr.escCtrlCharsMap[i] = template.HTML(`` + string(byte(i)) + ``)
}
- // Uncomment this line if you'd debug the layout without creating a special file, then Space (0x20) will also be escaped.
- // Don't worry, even if you forget to comment it out and push it to git repo, the CI tests will catch it and fail.
- // controlCharNames = append(controlCharNames, "SP")
- for i, s := range controlCharNames {
- globalVarsPtr.escCtrlCharsMap[i] = template.HTML(`` + string(byte(i)) + ``)
- }
- globalVarsPtr.escCtrlCharsMap[0x7f] = template.HTML(`` + string(byte(0x7f)) + ``)
+ // DEL (0x7F) maps to U+2421
+ globalVarsPtr.escCtrlCharsMap[0x7f] = template.HTML(`` + string(byte(0x7f)) + ``)
globalVarsPtr.escCtrlCharsMap['\t'] = ""
globalVarsPtr.escCtrlCharsMap['\n'] = ""
globalVarsPtr.escCtrlCharsMap['\r'] = ""
diff --git a/modules/highlight/highlight_test.go b/modules/highlight/highlight_test.go
index cad22ba9bb..2bd298e780 100644
--- a/modules/highlight/highlight_test.go
+++ b/modules/highlight/highlight_test.go
@@ -206,12 +206,12 @@ func TestUnsafeSplitHighlightedLines(t *testing.T) {
}
func TestEscape(t *testing.T) {
- assert.Equal(t, template.HTML("\t\r\n\x00\x1f&'\"<>"), escapeControlChars([]byte("\t\r\n\x00\x1f&'\"<>")))
- assert.Equal(t, template.HTML("\x00\x1f&'"<>\t\r\n"), escapeFullString("\x00\x1f&'\"<>\t\r\n"))
+ assert.Equal(t, template.HTML("\t\r\n\x00\x1f&'\"<>"), escapeControlChars([]byte("\t\r\n\x00\x1f&'\"<>")))
+ assert.Equal(t, template.HTML("\x00\x1f&'"<>\t\r\n"), escapeFullString("\x00\x1f&'\"<>\t\r\n"))
out, _ := RenderFullFile("a.py", "", []byte("# \x7f<>"))
- assert.Equal(t, template.HTML(`# `+string(byte(0x7f))+`<>`), out[0])
+ assert.Equal(t, template.HTML(`# `+string(byte(0x7f))+`<>`), out[0])
out = renderPlainText([]byte("# \x7f<>"))
- assert.Equal(t, template.HTML(`# `+string(byte(0x7f))+`<>`), out[0])
+ assert.Equal(t, template.HTML(`# `+string(byte(0x7f))+`<>`), out[0])
}
diff --git a/web_src/css/modules/charescape.css b/web_src/css/modules/charescape.css
index 0c9cbb55b5..0bbd0dd573 100644
--- a/web_src/css/modules/charescape.css
+++ b/web_src/css/modules/charescape.css
@@ -1,11 +1,10 @@
/*
Show the escaped and hide the real char:
- {real-char}
+ {real-char}
Only show the real-char:
{real-char}
*/
-.broken-code-point:not([data-escaped]),
-.broken-code-point[data-escaped]::before {
+.broken-code-point:not([data-escaped]) {
border-radius: 4px;
padding: 0 2px;
color: var(--color-body);
@@ -15,6 +14,7 @@ Only show the real-char:
.broken-code-point[data-escaped]::before {
visibility: visible;
content: attr(data-escaped);
+ color: var(--color-red);
}
.broken-code-point[data-escaped] .char {
/* make it copyable by selecting the text (AI suggestion, no other solution) */
@@ -26,11 +26,11 @@ Only show the real-char:
/*
Show the escaped and hide the real-char:
- {real-char}
+ {real-char}
Hide the escaped and show the real-char:
- {real-char}
+ {real-char}
*/
.unicode-escaped .escaped-code-point[data-escaped]::before {