+ 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 000000000000..b3bfebe0c0e0
--- /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 b534c43a8d7d..2330057f8720 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 06c43aec19fb..c53a53b47193 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 0e446f2de068..baec48bfea77 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 6a9c6b9bbace..72ffda7e0147 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 e4134028aa9d..1af511f50a3e 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,
}
+ buf := &strings.Builder{}
- var buf strings.Builder
- if err := markdown.Render(rctx, bytes.NewReader(data), &buf); err != nil {
+ 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 6dd237bbc8d4..9844992f5b11 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 6b3f3eddd7b3..b697573d24ea 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 04d271a444c5..c821d12d9094 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 000000000000..7aa5af4254a8
--- /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 000000000000..c95ce83fc416
--- /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 10ab6ffbb9e1..aa30221f430c 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 13f396d47e33..1d6c4fc22303 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 94d353cddf66..ab3452efa4bb 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 34ed859d40c2..a76700a7263f 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 fa634479f6d3..b3f24ee03d08 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 {