diff --git a/app/controller/cutil/formatter.go b/app/controller/cutil/formatter.go
index 0389185..b795677 100644
--- a/app/controller/cutil/formatter.go
+++ b/app/controller/cutil/formatter.go
@@ -3,6 +3,7 @@ package cutil
import (
"fmt"
h "html"
+ "regexp"
"strings"
"github.com/alecthomas/chroma"
@@ -19,24 +20,32 @@ var (
noLineNums *html.Formatter
)
-func FormatJSON(v any) (string, error) {
- return FormatLang(util.ToJSON(v), util.KeyJSON)
+func FormatJSON(v any, lineNumLinkAndTitle ...string) (string, error) {
+ return FormatLang(util.ToJSON(v), util.KeyJSON, lineNumLinkAndTitle...)
}
-func FormatLang(content string, lang string) (string, error) {
+func FormatLang(content string, lang string, lineNumLinkAndTitle ...string) (string, error) {
l := lexers.Get(lang)
- return FormatString(content, l)
+ return FormatString(content, l, lineNumLinkAndTitle...)
}
-func FormatFilename(content string, filename string) (string, error) {
+func FormatLangIgnoreErrors(content string, lang string, lineNumLinkAndTitle ...string) string {
+ ret, err := FormatLang(content, lang, lineNumLinkAndTitle...)
+ if err != nil {
+ return fmt.Sprintf("encoding error: %s\n%s", err.Error(), content)
+ }
+ return ret
+}
+
+func FormatFilename(content string, filename string, lineNumLinkAndTitle ...string) (string, error) {
l := lexers.Match(filename)
if l == nil {
l = lexers.Fallback
}
- return FormatString(content, l)
+ return FormatString(content, l, lineNumLinkAndTitle...)
}
-func FormatString(content string, l chroma.Lexer) (string, error) {
+func FormatString(content string, l chroma.Lexer, lineNumLinkAndTitle ...string) (string, error) {
if l == nil {
return "", errors.New("no lexer available for this content")
}
@@ -71,10 +80,37 @@ func FormatString(content string, l chroma.Lexer) (string, error) {
if l.Config().Name == "SQL" {
ret = strings.ReplaceAll(ret, `$`, `$`)
}
+ if len(lineNumLinkAndTitle) > 0 {
+ title := ""
+ if len(lineNumLinkAndTitle) > 1 {
+ title = lineNumLinkAndTitle[1]
+ }
+ ret = injectLinks(ret, lineNumLinkAndTitle[0], title)
+ }
ret = strings.Replace(ret, `
1
| `, "", 1)
return ret, nil
}
+var injectLinksRegex = regexp.MustCompile(`(.*?)`)
+
+func injectLinks(ret string, url string, title string) string {
+ return injectLinksRegex.ReplaceAllStringFunc(ret, func(match string) string {
+ content := injectLinksRegex.FindStringSubmatch(match)[1]
+ var num int
+ for _, x := range strings.TrimSpace(content) {
+ if x >= '0' && x <= '9' {
+ num = num*10 + int(x-'0')
+ } else {
+ break
+ }
+ }
+ u := strings.ReplaceAll(url, "{}", fmt.Sprint(num))
+ t := strings.ReplaceAll(title, "{}", fmt.Sprint(num))
+ anchor := fmt.Sprintf(``, t, u)
+ return strings.Replace(match, content, anchor+content+"", 1)
+ })
+}
+
func FormatMarkdown(s string) (string, error) {
match, end := "
"
idx := strings.Index(s, match)
diff --git a/views/vfile/Detail.html b/views/vfile/Detail.html
index 16f3060..a3aae4e 100644
--- a/views/vfile/Detail.html
+++ b/views/vfile/Detail.html
@@ -9,7 +9,7 @@
"github.com/kyleu/npn/app/util"
) %}
-{% func Detail(path []string, b []byte, urlPrefix string, additionalLinks map[string]string, as *app.State, ps *cutil.PageState) %}
+{% func Detail(path []string, b []byte, urlPrefix string, additionalLinks map[string]string, as *app.State, ps *cutil.PageState, lineNumLinkAndTitle ...string) %}
{%- if additionalLinks != nil && len(additionalLinks) > 0 -%}
{%- for k, v := range additionalLinks -%}
@@ -25,7 +25,7 @@
{%- if len(b) > (1024 * 128) -%}
File is {%d len(b) %} bytes, which is too large for the file viewer
{%- elseif utf8.Valid(b) -%}
- {%- code out, _ := cutil.FormatFilename(string(b), path[len(path)-1]) -%}
+ {%- code out, _ := cutil.FormatFilename(string(b), path[len(path)-1], lineNumLinkAndTitle...) -%}
{%s= out %}
{%- else -%}
diff --git a/views/vfile/Detail.html.go b/views/vfile/Detail.html.go
index a9268ca..ed7f17b 100644
--- a/views/vfile/Detail.html.go
+++ b/views/vfile/Detail.html.go
@@ -30,7 +30,7 @@ var (
)
//line views/vfile/Detail.html:12
-func StreamDetail(qw422016 *qt422016.Writer, path []string, b []byte, urlPrefix string, additionalLinks map[string]string, as *app.State, ps *cutil.PageState) {
+func StreamDetail(qw422016 *qt422016.Writer, path []string, b []byte, urlPrefix string, additionalLinks map[string]string, as *app.State, ps *cutil.PageState, lineNumLinkAndTitle ...string) {
//line views/vfile/Detail.html:12
qw422016.N().S(`
`)
@@ -101,7 +101,7 @@ func StreamDetail(qw422016 *qt422016.Writer, path []string, b []byte, urlPrefix
//line views/vfile/Detail.html:27
} else if utf8.Valid(b) {
//line views/vfile/Detail.html:28
- out, _ := cutil.FormatFilename(string(b), path[len(path)-1])
+ out, _ := cutil.FormatFilename(string(b), path[len(path)-1], lineNumLinkAndTitle...)
//line views/vfile/Detail.html:28
qw422016.N().S(` `)
@@ -193,22 +193,22 @@ func StreamDetail(qw422016 *qt422016.Writer, path []string, b []byte, urlPrefix
}
//line views/vfile/Detail.html:62
-func WriteDetail(qq422016 qtio422016.Writer, path []string, b []byte, urlPrefix string, additionalLinks map[string]string, as *app.State, ps *cutil.PageState) {
+func WriteDetail(qq422016 qtio422016.Writer, path []string, b []byte, urlPrefix string, additionalLinks map[string]string, as *app.State, ps *cutil.PageState, lineNumLinkAndTitle ...string) {
//line views/vfile/Detail.html:62
qw422016 := qt422016.AcquireWriter(qq422016)
//line views/vfile/Detail.html:62
- StreamDetail(qw422016, path, b, urlPrefix, additionalLinks, as, ps)
+ StreamDetail(qw422016, path, b, urlPrefix, additionalLinks, as, ps, lineNumLinkAndTitle...)
//line views/vfile/Detail.html:62
qt422016.ReleaseWriter(qw422016)
//line views/vfile/Detail.html:62
}
//line views/vfile/Detail.html:62
-func Detail(path []string, b []byte, urlPrefix string, additionalLinks map[string]string, as *app.State, ps *cutil.PageState) string {
+func Detail(path []string, b []byte, urlPrefix string, additionalLinks map[string]string, as *app.State, ps *cutil.PageState, lineNumLinkAndTitle ...string) string {
//line views/vfile/Detail.html:62
qb422016 := qt422016.AcquireByteBuffer()
//line views/vfile/Detail.html:62
- WriteDetail(qb422016, path, b, urlPrefix, additionalLinks, as, ps)
+ WriteDetail(qb422016, path, b, urlPrefix, additionalLinks, as, ps, lineNumLinkAndTitle...)
//line views/vfile/Detail.html:62
qs422016 := string(qb422016.B)
//line views/vfile/Detail.html:62