Skip to content

Commit cfd2878

Browse files
committed
feat: support custom dataview link text
1 parent 364df78 commit cfd2878

3 files changed

Lines changed: 46 additions & 0 deletions

File tree

docs/dataview.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,15 @@ FROM "Projects"
2323
SORT file.name
2424
```
2525

26+
Use `link(file.path, title)` when you want a clickable note link whose visible
27+
text comes from frontmatter instead of the file name:
28+
29+
```dataview
30+
TABLE link(file.path, title) AS "Name", status
31+
FROM "Projects"
32+
SORT file.name
33+
```
34+
2635
### FILTER clause
2736

2837
Add interactive column dropdown filters to any `TABLE` query:

internal/app/dataview.go

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import (
44
"fmt"
55
"html"
66
"html/template"
7+
"net/url"
78
"path/filepath"
89
"regexp"
910
"sort"
@@ -631,6 +632,11 @@ func evalFunc(r dataviewRow, name string, args []string) any {
631632
txt := displayPlain(evalValue(r, args[0]))
632633
return dataviewLink{URL: "#", Text: txt}
633634
}
635+
if len(args) == 2 {
636+
target := displayPlain(evalValue(r, args[0]))
637+
text := displayPlain(evalValue(r, args[1]))
638+
return dataviewLink{URL: dataviewLinkURL(target), Text: text}
639+
}
634640
case "dur", "duration":
635641
if len(args) == 1 {
636642
return parseDataviewDuration(args[0])
@@ -834,6 +840,21 @@ func noteFileName(n NoteMeta) string {
834840
return strings.TrimSuffix(filepath.Base(n.RelPath), filepath.Ext(n.RelPath))
835841
}
836842

843+
func dataviewLinkURL(target string) string {
844+
target = strings.TrimSpace(target)
845+
if target == "" {
846+
return "#"
847+
}
848+
if strings.HasPrefix(target, "http://") || strings.HasPrefix(target, "https://") || strings.HasPrefix(target, "/") || strings.HasPrefix(target, "#") {
849+
return target
850+
}
851+
parts := strings.Split(filepath.ToSlash(target), "/")
852+
for i, part := range parts {
853+
parts[i] = url.PathEscape(part)
854+
}
855+
return "/" + strings.Join(parts, "/")
856+
}
857+
837858
type dataviewLink struct{ URL, Text string }
838859

839860
func renderDataviewTable(q dataviewQuery, rows []dataviewRow) template.HTML {

internal/app/dataview_test.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,22 @@ func TestDataviewMultilineTableColumns(t *testing.T) {
8181
}
8282
}
8383

84+
func TestDataviewLinkFunctionUsesCustomText(t *testing.T) {
85+
v := makeDataviewVault(t)
86+
html := string(RenderDataviewBlock(v, `TABLE link(file.path, title) AS "Project"
87+
FROM "Projects"
88+
WHERE status = "active"
89+
SORT file.name`))
90+
for _, want := range []string{`href="/Projects/Alpha.md">Alpha Project</a>`, `href="/Projects/Gamma.md">Gamma Project</a>`} {
91+
if !strings.Contains(html, want) {
92+
t.Fatalf("custom link table missing %q in:\n%s", want, html)
93+
}
94+
}
95+
if strings.Contains(html, `href="#">Alpha Project</a>`) || strings.Contains(html, `>Alpha</a>`) {
96+
t.Fatalf("custom link should use file path URL and title text:\n%s", html)
97+
}
98+
}
99+
84100
func TestDataviewWhereLimitTagSourceFunctionsAndYamlLists(t *testing.T) {
85101
v := makeDataviewVault(t)
86102
query := `TABLE file.link as "Note", default(area, "none") as "Area", length(aliases) as "Aliases", choice(score >= 9, "high", "normal") as "Tier"

0 commit comments

Comments
 (0)