+ filtered := make([]rune, 0, len(InvisibleRunes))
+ for _, r := range InvisibleRunes {
+ if r == ' ' || r == '\t' || r == '\n' {
+ continue
+ }
+ filtered = append(filtered, r)
+ }
+
+ table := rangetable.New(filtered...)
+ if err := runTemplate(generatorTemplate, output, table); err != nil {
+ fatalf("Unable to run template: %v", err)
+ }
+}
+
+func runTemplate(t *template.Template, filename string, data interface{}) error {
+ buf := bytes.NewBuffer(nil)
+ if err := t.Execute(buf, data); err != nil {
+ return fmt.Errorf("unable to execute template: %w", err)
+ }
+ bs, err := format.Source(buf.Bytes())
+ if err != nil {
+ verbosef("Bad source:\n%s", buf.String())
+ return fmt.Errorf("unable to format source: %w", err)
+ }
+ file, err := os.Create(filename)
+ if err != nil {
+ return fmt.Errorf("failed to create file %s because %w", filename, err)
+ }
+ defer file.Close()
+ _, err = file.Write(bs)
+ if err != nil {
+ return fmt.Errorf("unable to write generated source: %w", err)
+ }
+ return nil
+}
+
+var generatorTemplate = template.Must(template.New("invisibleTemplate").Parse(`// This file is generated by modules/charset/invisible/generate.go DO NOT EDIT
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package charset
+
+import "unicode"
+
+var InvisibleRanges = &unicode.RangeTable{
+ R16: []unicode.Range16{
+{{range .R16 }} {Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}},
+{{end}} },
+ R32: []unicode.Range32{
+{{range .R32}} {Lo:{{.Lo}}, Hi:{{.Hi}}, Stride: {{.Stride}}},
+{{end}} },
+ LatinOffset: {{.LatinOffset}},
+}
+`))
+
+func logf(format string, args ...interface{}) {
+ fmt.Fprintf(os.Stderr, format+"\n", args...)
+}
+
+func verbosef(format string, args ...interface{}) {
+ if verbose {
+ logf(format, args...)
+ }
+}
+
+func fatalf(format string, args ...interface{}) {
+ logf("fatal: "+format+"\n", args...)
+ os.Exit(1)
+}
diff --git a/modules/charset/invisible_gen.go b/modules/charset/invisible_gen.go
new file mode 100644
index 000000000..b3bfebe0c
--- /dev/null
+++ b/modules/charset/invisible_gen.go
@@ -0,0 +1,37 @@
+// This file is generated by modules/charset/invisible/generate.go DO NOT EDIT
+// Copyright 2022 The Gitea Authors. All rights reserved.
+// Use of this source code is governed by a MIT-style
+// license that can be found in the LICENSE file.
+
+package charset
+
+import "unicode"
+
+var InvisibleRanges = &unicode.RangeTable{
+ R16: []unicode.Range16{
+ {Lo: 11, Hi: 13, Stride: 1},
+ {Lo: 127, Hi: 160, Stride: 33},
+ {Lo: 173, Hi: 847, Stride: 674},
+ {Lo: 1564, Hi: 4447, Stride: 2883},
+ {Lo: 4448, Hi: 6068, Stride: 1620},
+ {Lo: 6069, Hi: 6155, Stride: 86},
+ {Lo: 6156, Hi: 6158, Stride: 1},
+ {Lo: 7355, Hi: 7356, Stride: 1},
+ {Lo: 8192, Hi: 8207, Stride: 1},
+ {Lo: 8234, Hi: 8239, Stride: 1},
+ {Lo: 8287, Hi: 8303, Stride: 1},
+ {Lo: 10240, Hi: 12288, Stride: 2048},
+ {Lo: 12644, Hi: 65024, Stride: 52380},
+ {Lo: 65025, Hi: 65039, Stride: 1},
+ {Lo: 65279, Hi: 65440, Stride: 161},
+ {Lo: 65520, Hi: 65528, Stride: 1},
+ {Lo: 65532, Hi: 65532, Stride: 1},
+ },
+ R32: []unicode.Range32{
+ {Lo: 78844, Hi: 119155, Stride: 40311},
+ {Lo: 119156, Hi: 119162, Stride: 1},
+ {Lo: 917504, Hi: 917631, Stride: 1},
+ {Lo: 917760, Hi: 917999, Stride: 1},
+ },
+ LatinOffset: 2,
+}
diff --git a/options/locale/locale_en-US.ini b/options/locale/locale_en-US.ini
index b534c43a8..2330057f8 100644
--- a/options/locale/locale_en-US.ini
+++ b/options/locale/locale_en-US.ini
@@ -1035,13 +1035,13 @@ file_view_rendered = View Rendered
file_view_raw = View Raw
file_permalink = Permalink
file_too_large = The file is too large to be shown.
-bidi_bad_header = `This file contains unexpected Bidirectional Unicode characters!`
-bidi_bad_description = `This file contains unexpected Bidirectional Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.`
-bidi_bad_description_escaped = `This file contains unexpected Bidirectional Unicode characters. Hidden unicode characters are escaped below. Use the Unescape button to show how they render.`
-unicode_header = `This file contains hidden Unicode characters!`
-unicode_description = `This file contains hidden Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.`
-unicode_description_escaped = `This file contains hidden Unicode characters. Hidden unicode characters are escaped below. Use the Unescape button to show how they render.`
-line_unicode = `This line has hidden unicode characters`
+invisible_runes_header = `This file contains invisible Unicode characters!`
+invisible_runes_description = `This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.`
+ambiguous_runes_header = `This file contains ambiguous Unicode characters!`
+ambiguous_runes_description = `This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.`
+invisible_runes_line = `This line has invisible unicode characters`
+ambiguous_runes_line = `This line has ambiguous unicode characters`
+ambiguous_character = `%[1]c [U+%04[1]X] is confusable with %[2]c [U+%04[2]X]`
escape_control_characters = Escape
unescape_control_characters = Unescape
diff --git a/routers/web/repo/blame.go b/routers/web/repo/blame.go
index 06c43aec1..c53a53b47 100644
--- a/routers/web/repo/blame.go
+++ b/routers/web/repo/blame.go
@@ -40,7 +40,7 @@ type blameRow struct {
CommitMessage string
CommitSince gotemplate.HTML
Code gotemplate.HTML
- EscapeStatus charset.EscapeStatus
+ EscapeStatus *charset.EscapeStatus
}
// RefBlame render blame page
@@ -235,7 +235,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
}
lines := make([]string, 0)
rows := make([]*blameRow, 0)
- escapeStatus := charset.EscapeStatus{}
+ escapeStatus := &charset.EscapeStatus{}
i := 0
commitCnt := 0
@@ -280,7 +280,7 @@ func renderBlame(ctx *context.Context, blameParts []git.BlamePart, commitNames m
fileName := fmt.Sprintf("%v", ctx.Data["FileName"])
line = highlight.Code(fileName, language, line)
- br.EscapeStatus, line = charset.EscapeControlString(line)
+ br.EscapeStatus, line = charset.EscapeControlHTML(line, ctx.Locale)
br.Code = gotemplate.HTML(line)
rows = append(rows, br)
escapeStatus = escapeStatus.Or(br.EscapeStatus)
diff --git a/routers/web/repo/lfs.go b/routers/web/repo/lfs.go
index 0e446f2de..baec48bfe 100644
--- a/routers/web/repo/lfs.go
+++ b/routers/web/repo/lfs.go
@@ -309,7 +309,7 @@ func LFSFileGet(ctx *context.Context) {
// Building code view blocks with line number on server side.
escapedContent := &bytes.Buffer{}
- ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, escapedContent)
+ ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, escapedContent, ctx.Locale)
var output bytes.Buffer
lines := strings.Split(escapedContent.String(), "\n")
diff --git a/routers/web/repo/view.go b/routers/web/repo/view.go
index 6a9c6b9bb..72ffda7e0 100644
--- a/routers/web/repo/view.go
+++ b/routers/web/repo/view.go
@@ -328,35 +328,31 @@ func renderReadmeFile(ctx *context.Context, readmeFile *namedBlob, readmeTreelin
if markupType := markup.Type(readmeFile.name); markupType != "" {
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = markupType
- var result strings.Builder
- err := markup.Render(&markup.RenderContext{
+
+ ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{
Ctx: ctx,
RelativePath: path.Join(ctx.Repo.TreePath, readmeFile.name), // ctx.Repo.TreePath is the directory not the Readme so we must append the Readme filename (and path).
URLPrefix: readmeTreelink,
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
GitRepo: ctx.Repo.GitRepo,
- }, rd, &result)
+ }, rd)
if err != nil {
- log.Error("Render failed: %v then fallback", err)
+ log.Error("Render failed for %s in %-v: %v Falling back to rendering source", readmeFile.name, ctx.Repo.Repository, err)
buf := &bytes.Buffer{}
- ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf)
+ ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale)
ctx.Data["FileContent"] = strings.ReplaceAll(
gotemplate.HTMLEscapeString(buf.String()), "\n", `
`,
)
- } else {
- ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String())
}
} else {
ctx.Data["IsRenderedHTML"] = true
buf := &bytes.Buffer{}
- ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, buf)
+ ctx.Data["EscapeStatus"], err = charset.EscapeControlReader(rd, &charset.BreakWriter{Writer: buf}, ctx.Locale, charset.RuneNBSP)
if err != nil {
log.Error("Read failed: %v", err)
}
- ctx.Data["FileContent"] = strings.ReplaceAll(
- gotemplate.HTMLEscapeString(buf.String()), "\n", `
`,
- )
+ ctx.Data["FileContent"] = buf.String()
}
}
@@ -498,32 +494,30 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
if markupType != "" && !shouldRenderSource {
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = markupType
- var result strings.Builder
if !detected {
markupType = ""
}
metas := ctx.Repo.Repository.ComposeDocumentMetas()
metas["BranchNameSubURL"] = ctx.Repo.BranchNameSubURL()
- err := markup.Render(&markup.RenderContext{
+ ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{
Ctx: ctx,
Type: markupType,
RelativePath: ctx.Repo.TreePath,
URLPrefix: path.Dir(treeLink),
Metas: metas,
GitRepo: ctx.Repo.GitRepo,
- }, rd, &result)
+ }, rd)
if err != nil {
ctx.ServerError("Render", err)
return
}
// to prevent iframe load third-party url
ctx.Resp.Header().Add("Content-Security-Policy", "frame-src 'self'")
- ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String())
} else if readmeExist && !shouldRenderSource {
buf := &bytes.Buffer{}
ctx.Data["IsRenderedHTML"] = true
- ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf)
+ ctx.Data["EscapeStatus"], _ = charset.EscapeControlReader(rd, buf, ctx.Locale)
ctx.Data["FileContent"] = strings.ReplaceAll(
gotemplate.HTMLEscapeString(buf.String()), "\n", `
`,
@@ -570,12 +564,13 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
log.Error("highlight.File failed, fallback to plain text: %v", err)
fileContent = highlight.PlainText(buf)
}
- status, _ := charset.EscapeControlReader(bytes.NewReader(buf), io.Discard)
- ctx.Data["EscapeStatus"] = status
- statuses := make([]charset.EscapeStatus, len(fileContent))
+ status := &charset.EscapeStatus{}
+ statuses := make([]*charset.EscapeStatus, len(fileContent))
for i, line := range fileContent {
- statuses[i], fileContent[i] = charset.EscapeControlString(line)
+ statuses[i], fileContent[i] = charset.EscapeControlHTML(line, ctx.Locale)
+ status = status.Or(statuses[i])
}
+ ctx.Data["EscapeStatus"] = status
ctx.Data["FileContent"] = fileContent
ctx.Data["LineEscapeStatus"] = statuses
}
@@ -613,20 +608,17 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
rd := io.MultiReader(bytes.NewReader(buf), dataRc)
ctx.Data["IsMarkup"] = true
ctx.Data["MarkupType"] = markupType
- var result strings.Builder
- err := markup.Render(&markup.RenderContext{
+ ctx.Data["EscapeStatus"], ctx.Data["FileContent"], err = markupRender(ctx, &markup.RenderContext{
Ctx: ctx,
RelativePath: ctx.Repo.TreePath,
URLPrefix: path.Dir(treeLink),
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
GitRepo: ctx.Repo.GitRepo,
- }, rd, &result)
+ }, rd)
if err != nil {
ctx.ServerError("Render", err)
return
}
-
- ctx.Data["EscapeStatus"], ctx.Data["FileContent"] = charset.EscapeControlString(result.String())
}
}
@@ -645,6 +637,23 @@ func renderFile(ctx *context.Context, entry *git.TreeEntry, treeLink, rawLink st
}
}
+func markupRender(ctx *context.Context, renderCtx *markup.RenderContext, input io.Reader) (escaped *charset.EscapeStatus, output string, err error) {
+ markupRd, markupWr := io.Pipe()
+ defer markupWr.Close()
+ done := make(chan struct{})
+ go func() {
+ sb := &strings.Builder{}
+ // We allow NBSP here this is rendered
+ escaped, _ = charset.EscapeControlReader(markupRd, sb, ctx.Locale, charset.RuneNBSP)
+ output = sb.String()
+ close(done)
+ }()
+ err = markup.Render(renderCtx, input, markupWr)
+ _ = markupWr.CloseWithError(err)
+ <-done
+ return escaped, output, err
+}
+
func safeURL(address string) string {
u, err := url.Parse(address)
if err != nil {
diff --git a/routers/web/repo/wiki.go b/routers/web/repo/wiki.go
index e4134028a..1af511f50 100644
--- a/routers/web/repo/wiki.go
+++ b/routers/web/repo/wiki.go
@@ -239,9 +239,28 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
Metas: ctx.Repo.Repository.ComposeDocumentMetas(),
IsWiki: true,
}
-
- var buf strings.Builder
- if err := markdown.Render(rctx, bytes.NewReader(data), &buf); err != nil {
+ buf := &strings.Builder{}
+
+ renderFn := func(data []byte) (escaped *charset.EscapeStatus, output string, err error) {
+ markupRd, markupWr := io.Pipe()
+ defer markupWr.Close()
+ done := make(chan struct{})
+ go func() {
+ // We allow NBSP here this is rendered
+ escaped, _ = charset.EscapeControlReader(markupRd, buf, ctx.Locale, charset.RuneNBSP)
+ output = buf.String()
+ buf.Reset()
+ close(done)
+ }()
+
+ err = markdown.Render(rctx, bytes.NewReader(data), markupWr)
+ _ = markupWr.CloseWithError(err)
+ <-done
+ return escaped, output, err
+ }
+
+ ctx.Data["EscapeStatus"], ctx.Data["content"], err = renderFn(data)
+ if err != nil {
if wikiRepo != nil {
wikiRepo.Close()
}
@@ -249,11 +268,10 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
return nil, nil
}
- ctx.Data["EscapeStatus"], ctx.Data["content"] = charset.EscapeControlString(buf.String())
-
if !isSideBar {
buf.Reset()
- if err := markdown.Render(rctx, bytes.NewReader(sidebarContent), &buf); err != nil {
+ ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"], err = renderFn(sidebarContent)
+ if err != nil {
if wikiRepo != nil {
wikiRepo.Close()
}
@@ -261,14 +279,14 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
return nil, nil
}
ctx.Data["sidebarPresent"] = sidebarContent != nil
- ctx.Data["sidebarEscapeStatus"], ctx.Data["sidebarContent"] = charset.EscapeControlString(buf.String())
} else {
ctx.Data["sidebarPresent"] = false
}
if !isFooter {
buf.Reset()
- if err := markdown.Render(rctx, bytes.NewReader(footerContent), &buf); err != nil {
+ ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"], err = renderFn(footerContent)
+ if err != nil {
if wikiRepo != nil {
wikiRepo.Close()
}
@@ -276,7 +294,6 @@ func renderViewPage(ctx *context.Context) (*git.Repository, *git.TreeEntry) {
return nil, nil
}
ctx.Data["footerPresent"] = footerContent != nil
- ctx.Data["footerEscapeStatus"], ctx.Data["footerContent"] = charset.EscapeControlString(buf.String())
} else {
ctx.Data["footerPresent"] = false
}
diff --git a/services/gitdiff/gitdiff.go b/services/gitdiff/gitdiff.go
index 6dd237bbc..9844992f5 100644
--- a/services/gitdiff/gitdiff.go
+++ b/services/gitdiff/gitdiff.go
@@ -32,6 +32,7 @@ import (
"code.gitea.io/gitea/modules/lfs"
"code.gitea.io/gitea/modules/log"
"code.gitea.io/gitea/modules/setting"
+ "code.gitea.io/gitea/modules/translation"
"github.com/sergi/go-diff/diffmatchpatch"
stdcharset "golang.org/x/net/html/charset"
@@ -169,11 +170,11 @@ func getDiffLineSectionInfo(treePath, line string, lastLeftIdx, lastRightIdx int
}
// escape a line's content or return
needed for copy/paste purposes
-func getLineContent(content string) DiffInline {
+func getLineContent(content string, locale translation.Locale) DiffInline {
if len(content) > 0 {
- return DiffInlineWithUnicodeEscape(template.HTML(html.EscapeString(content)))
+ return DiffInlineWithUnicodeEscape(template.HTML(html.EscapeString(content)), locale)
}
- return DiffInline{Content: "
"}
+ return DiffInline{EscapeStatus: &charset.EscapeStatus{}, Content: "
"}
}
// DiffSection represents a section of a DiffFile.
@@ -267,26 +268,26 @@ func init() {
// DiffInline is a struct that has a content and escape status
type DiffInline struct {
- EscapeStatus charset.EscapeStatus
+ EscapeStatus *charset.EscapeStatus
Content template.HTML
}
// DiffInlineWithUnicodeEscape makes a DiffInline with hidden unicode characters escaped
-func DiffInlineWithUnicodeEscape(s template.HTML) DiffInline {
- status, content := charset.EscapeControlString(string(s))
+func DiffInlineWithUnicodeEscape(s template.HTML, locale translation.Locale) DiffInline {
+ status, content := charset.EscapeControlHTML(string(s), locale)
return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
}
// DiffInlineWithHighlightCode makes a DiffInline with code highlight and hidden unicode characters escaped
-func DiffInlineWithHighlightCode(fileName, language, code string) DiffInline {
- status, content := charset.EscapeControlString(highlight.Code(fileName, language, code))
+func DiffInlineWithHighlightCode(fileName, language, code string, locale translation.Locale) DiffInline {
+ status, content := charset.EscapeControlHTML(highlight.Code(fileName, language, code), locale)
return DiffInline{EscapeStatus: status, Content: template.HTML(content)}
}
// GetComputedInlineDiffFor computes inline diff for the given line.
-func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) DiffInline {
+func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine, locale translation.Locale) DiffInline {
if setting.Git.DisableDiffHighlight {
- return getLineContent(diffLine.Content[1:])
+ return getLineContent(diffLine.Content[1:], locale)
}
var (
@@ -303,26 +304,26 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) Dif
// try to find equivalent diff line. ignore, otherwise
switch diffLine.Type {
case DiffLineSection:
- return getLineContent(diffLine.Content[1:])
+ return getLineContent(diffLine.Content[1:], locale)
case DiffLineAdd:
compareDiffLine = diffSection.GetLine(DiffLineDel, diffLine.RightIdx)
if compareDiffLine == nil {
- return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:])
+ return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
}
diff1 = compareDiffLine.Content
diff2 = diffLine.Content
case DiffLineDel:
compareDiffLine = diffSection.GetLine(DiffLineAdd, diffLine.LeftIdx)
if compareDiffLine == nil {
- return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:])
+ return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
}
diff1 = diffLine.Content
diff2 = compareDiffLine.Content
default:
if strings.IndexByte(" +-", diffLine.Content[0]) > -1 {
- return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:])
+ return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content[1:], locale)
}
- return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content)
+ return DiffInlineWithHighlightCode(diffSection.FileName, language, diffLine.Content, locale)
}
hcd := newHighlightCodeDiff()
@@ -330,7 +331,7 @@ func (diffSection *DiffSection) GetComputedInlineDiffFor(diffLine *DiffLine) Dif
// it seems that Gitea doesn't need the line wrapper of Chroma, so do not add them back
// if the line wrappers are still needed in the future, it can be added back by "diffToHTML(hcd.lineWrapperTags. ...)"
diffHTML := diffToHTML(nil, diffRecord, diffLine.Type)
- return DiffInlineWithUnicodeEscape(template.HTML(diffHTML))
+ return DiffInlineWithUnicodeEscape(template.HTML(diffHTML), locale)
}
// DiffFile represents a file diff.
diff --git a/templates/repo/blame.tmpl b/templates/repo/blame.tmpl
index 6b3f3eddd..b697573d2 100644
--- a/templates/repo/blame.tmpl
+++ b/templates/repo/blame.tmpl
@@ -55,7 +55,11 @@
{{if $.EscapeStatus.Escaped}}
- {{if $row.EscapeStatus.Escaped}}{{end}} |
+
+ {{if $row.EscapeStatus.Escaped}}
+
+ {{end}}
+ |
{{end}}
{{$row.Code}}
diff --git a/templates/repo/diff/blob_excerpt.tmpl b/templates/repo/diff/blob_excerpt.tmpl
index 04d271a44..c821d12d9 100644
--- a/templates/repo/diff/blob_excerpt.tmpl
+++ b/templates/repo/diff/blob_excerpt.tmpl
@@ -19,20 +19,25 @@
{{end}}
|
- {{$inlineDiff := $.section.GetComputedInlineDiffFor $line}}{{$inlineDiff.Content}} |
+ {{$inlineDiff := $.section.GetComputedInlineDiffFor $line $.locale}}{{/*
+ */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff "locale" $.locale}} |
{{else}}
- {{$inlineDiff := $.section.GetComputedInlineDiffFor $line}}
+ {{$inlineDiff := $.section.GetComputedInlineDiffFor $line $.locale}}
|
- {{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} |
+ {{if and $line.LeftIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} |
{{if $line.LeftIdx}}{{end}} |
{{/*
- */}}{{if $line.LeftIdx}}{{$inlineDiff.Content}}{{end}} {{/*
+ */}}{{if $line.LeftIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff "locale" $.locale}}{{else}}{{/*
+ */}} {{/*
+ */}}{{end}}{{/*
*/}} |
|
- {{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} |
+ {{if and $line.RightIdx $inlineDiff.EscapeStatus.Escaped}}{{end}} |
{{if $line.RightIdx}}{{end}} |
{{/*
- */}}{{if $line.RightIdx}}{{$inlineDiff.Content}}{{end}} {{/*
+ */}}{{if $line.RightIdx}}{{template "repo/diff/section_code" dict "diff" $inlineDiff "locale" $.locale}}{{else}}{{/*
+ */}} {{/*
+ */}}{{end}}{{/*
*/}} |
{{end}}
@@ -62,10 +67,10 @@
|
|
{{end}}
- {{$inlineDiff := $.section.GetComputedInlineDiffFor $line}}
- {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} |
+ {{$inlineDiff := $.section.GetComputedInlineDiffFor $line $.locale}}
+ {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} |
|
- {{$inlineDiff.Content}} |
+ {{$inlineDiff.Content}} |
{{end}}
{{end}}
diff --git a/templates/repo/diff/escape_title.tmpl b/templates/repo/diff/escape_title.tmpl
new file mode 100644
index 000000000..7aa5af425
--- /dev/null
+++ b/templates/repo/diff/escape_title.tmpl
@@ -0,0 +1,2 @@
+{{if .diff.EscapeStatus.HasInvisible}}{{.locale.Tr "repo.invisible_runes_line"}} {{end}}{{/*
+*/}}{{if .diff.EscapeStatus.HasAmbiguous}}{{.locale.Tr "repo.ambiguous_runes_line"}}{{end}}
diff --git a/templates/repo/diff/section_code.tmpl b/templates/repo/diff/section_code.tmpl
new file mode 100644
index 000000000..c95ce83fc
--- /dev/null
+++ b/templates/repo/diff/section_code.tmpl
@@ -0,0 +1,6 @@
+{{.diff.Content}}
diff --git a/templates/repo/diff/section_split.tmpl b/templates/repo/diff/section_split.tmpl
index 10ab6ffbb..aa30221f4 100644
--- a/templates/repo/diff/section_split.tmpl
+++ b/templates/repo/diff/section_split.tmpl
@@ -21,15 +21,17 @@
{{svg "octicon-fold"}}
{{end}}
- {{$inlineDiff := $section.GetComputedInlineDiffFor $line}}
- {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} |
- {{$inlineDiff.Content}} |
+ {{$inlineDiff := $section.GetComputedInlineDiffFor $line $.root.locale}}
+ {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} |
+ {{/*
+ */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff "locale" $.root.locale}}{{/*
+ */}} |
{{else if and (eq .GetType 3) $hasmatch}}{{/* DEL */}}
{{$match := index $section.Lines $line.Match}}
- {{- $leftDiff := ""}}{{if $line.LeftIdx}}{{$leftDiff = $section.GetComputedInlineDiffFor $line}}{{end}}
- {{- $rightDiff := ""}}{{if $match.RightIdx}}{{$rightDiff = $section.GetComputedInlineDiffFor $match}}{{end}}
+ {{- $leftDiff := ""}}{{if $line.LeftIdx}}{{$leftDiff = $section.GetComputedInlineDiffFor $line $.root.locale}}{{end}}
+ {{- $rightDiff := ""}}{{if $match.RightIdx}}{{$rightDiff = $section.GetComputedInlineDiffFor $match $.root.locale}}{{end}}
|
- {{if $line.LeftIdx}}{{if $leftDiff.EscapeStatus.Escaped}}{{end}}{{end}} |
+ {{if $line.LeftIdx}}{{if $leftDiff.EscapeStatus.Escaped}}{{end}}{{end}} |
|
{{/*
*/}}{{if and $.root.SignedUserID $.root.PageIsPullFiles}}{{/*
@@ -38,13 +40,13 @@
*/}}{{/*
*/}}{{end}}{{/*
*/}}{{if $line.LeftIdx}}{{/*
- */}}{{$leftDiff.Content}} {{/*
+ */}}{{template "repo/diff/section_code" dict "diff" $leftDiff "locale" $.root.locale}}{{/*
*/}}{{else}}{{/*
*/}} {{/*
*/}}{{end}}{{/*
*/}} |
|
- {{if $match.RightIdx}}{{if $rightDiff.EscapeStatus.Escaped}}{{end}}{{end}} |
+ {{if $match.RightIdx}}{{if $rightDiff.EscapeStatus.Escaped}}{{end}}{{end}} |
{{if $match.RightIdx}}{{end}} |
{{/*
*/}}{{if and $.root.SignedUserID $.root.PageIsPullFiles}}{{/*
@@ -53,15 +55,15 @@
*/}}{{/*
*/}}{{end}}{{/*
*/}}{{if $match.RightIdx}}{{/*
- */}}{{$rightDiff.Content}} {{/*
+ */}}{{template "repo/diff/section_code" dict "diff" $rightDiff "locale" $.root.locale}}{{/*
*/}}{{else}}{{/*
*/}} {{/*
*/}}{{end}}{{/*
*/}} |
{{else}}
- {{$inlineDiff := $section.GetComputedInlineDiffFor $line}}
+ {{$inlineDiff := $section.GetComputedInlineDiffFor $line $.root.locale}}
|
- {{if $line.LeftIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}{{end}}{{end}} |
+ {{if $line.LeftIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}{{end}}{{end}} |
{{if $line.LeftIdx}}{{end}} |
{{/*
*/}}{{if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 2))}}{{/*
@@ -70,13 +72,13 @@
*/}}{{/*
*/}}{{end}}{{/*
*/}}{{if $line.LeftIdx}}{{/*
- */}}{{$inlineDiff.Content}} {{/*
+ */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff "locale" $.root.locale}}{{/*
*/}}{{else}}{{/*
*/}} {{/*
*/}}{{end}}{{/*
*/}} |
|
- {{if $line.RightIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}{{end}}{{end}} |
+ {{if $line.RightIdx}}{{if $inlineDiff.EscapeStatus.Escaped}}{{end}}{{end}} |
{{if $line.RightIdx}}{{end}} |
{{/*
*/}}{{if and $.root.SignedUserID $.root.PageIsPullFiles (not (eq .GetType 3))}}{{/*
@@ -85,7 +87,7 @@
*/}}{{/*
*/}}{{end}}{{/*
*/}}{{if $line.RightIdx}}{{/*
- */}}{{$inlineDiff.Content}} {{/*
+ */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff "locale" $.root.locale}}{{/*
*/}}{{else}}{{/*
*/}} {{/*
*/}}{{end}}{{/*
diff --git a/templates/repo/diff/section_unified.tmpl b/templates/repo/diff/section_unified.tmpl
index 13f396d47..1d6c4fc22 100644
--- a/templates/repo/diff/section_unified.tmpl
+++ b/templates/repo/diff/section_unified.tmpl
@@ -25,12 +25,12 @@
| |
|
{{end}}
- {{$inlineDiff := $section.GetComputedInlineDiffFor $line -}}
- {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} |
+ {{$inlineDiff := $section.GetComputedInlineDiffFor $line $.root.locale -}}
+ {{if $inlineDiff.EscapeStatus.Escaped}}{{end}} |
|
{{if eq .GetType 4}}
{{/*
- */}}{{$inlineDiff.Content}} {{/*
+ */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff "locale" $.root.locale}}{{/*
*/}} |
{{else}}
{{/*
@@ -39,7 +39,7 @@
*/}}{{svg "octicon-plus"}}{{/*
*/}}{{/*
*/}}{{end}}{{/*
- */}}{{$inlineDiff.Content}} {{/*
+ */}}{{template "repo/diff/section_code" dict "diff" $inlineDiff "locale" $.root.locale}}{{/*
*/}} |
{{end}}
diff --git a/templates/repo/unicode_escape_prompt.tmpl b/templates/repo/unicode_escape_prompt.tmpl
index 94d353cdd..ab3452efa 100644
--- a/templates/repo/unicode_escape_prompt.tmpl
+++ b/templates/repo/unicode_escape_prompt.tmpl
@@ -1,19 +1,22 @@
{{if .EscapeStatus}}
- {{if .EscapeStatus.BadBIDI}}
+ {{if .EscapeStatus.HasInvisible}}
{{svg "octicon-x" 16 "close inside"}}
-
{{$.root.locale.Tr "repo.bidi_bad_description" | Str2html}}
+
{{$.root.locale.Tr "repo.invisible_runes_description" | Str2html}}
+ {{if .EscapeStatus.HasAmbiguous}}
+
{{$.root.locale.Tr "repo.ambiguous_runes_description" | Str2html}}
+ {{end}}
- {{else if .EscapeStatus.HasBIDI}}
+ {{else if .EscapeStatus.HasAmbiguous}}
{{svg "octicon-x" 16 "close inside"}}
-
{{$.root.locale.Tr "repo.unicode_description" | Str2html}}
+
{{$.root.locale.Tr "repo.ambiguous_runes_description" | Str2html}}
{{end}}
{{end}}
diff --git a/templates/repo/view_file.tmpl b/templates/repo/view_file.tmpl
index 34ed859d4..a76700a72 100644
--- a/templates/repo/view_file.tmpl
+++ b/templates/repo/view_file.tmpl
@@ -113,7 +113,7 @@
|
{{if $.EscapeStatus.Escaped}}
- {{if (index $.LineEscapeStatus $idx).Escaped}}{{end}} |
+ {{if (index $.LineEscapeStatus $idx).Escaped}}{{end}} |
{{end}}
{{$code | Safe}} |
diff --git a/web_src/less/_repository.less b/web_src/less/_repository.less
index fa634479f..b3f24ee03 100644
--- a/web_src/less/_repository.less
+++ b/web_src/less/_repository.less
@@ -82,7 +82,11 @@
.broken-code-point {
font-family: var(--fonts-monospace);
- color: blue;
+ color: var(--color-blue);
+ }
+
+ .unicode-escaped .ambiguous-code-point {
+ border: 1px var(--color-yellow) solid;
}
.metas {