Merge branch 'main' into json-link-sanitize

pull/403/head
Tillman Jex 1 month ago committed by GitHub
commit c0ca496601
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -21,7 +21,7 @@ jobs:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v4
uses: actions/configure-pages@v5
- name: Fix anchor tag in README
run: ex -s -c '%s/docs\/getting-started\.md/docs\/getting-started/|x' README.md
- name: Build with Jekyll

@ -43,3 +43,7 @@ Let's unpack this alias:
* `$ZK_NOTEBOOK_DIR` is set to the absolute path of the current [notebook](notebook.md) when running an alias. Using it allows you to run `zk daily` no matter where you are in the notebook folder hierarchy.
* We need to use double quotes around `$ZK_NOTEBOOK_DIR`, otherwise it will not be expanded.
If you want to edit today's note, simply use this alias:
```sh
$ zk daily
```

@ -160,10 +160,6 @@ func (d *document) LookForward(pos protocol.Position, length int) string {
return string(utf16.Decode(utf16Bytes[charIdx:(charIdx + length)]))
}
var wikiLinkRegex = regexp.MustCompile(`\[?\[\[(.+?)(?: *\| *(.+?))?\]\]`)
var markdownLinkRegex = regexp.MustCompile(`\[([^\]]+?[^\\])\]\((.+?[^\\])\)`)
var fileURIregex = regexp.MustCompile(`file:///`)
// LinkFromRoot returns a Link to this document from the root of the given
// notebook.
func (d *document) LinkFromRoot(nb *core.Notebook) (*documentLink, error) {
@ -194,6 +190,66 @@ func (d *document) DocumentLinkAt(pos protocol.Position) (*documentLink, error)
return nil, nil
}
// Recursive function to check whether a link is within inline code.
func linkWithinInlineCode(strBuffer string, linkStart, linkEnd int, insideInline bool) bool {
if backtickId := strings.Index(strBuffer, "`"); backtickId >= 0 && backtickId < linkEnd {
return linkWithinInlineCode(strBuffer[backtickId+1:],
linkStart-backtickId-1, linkEnd-backtickId-1, !insideInline)
} else {
return insideInline
}
}
var wikiLinkRegex = regexp.MustCompile(`\[?\[\[(.+?)(?: *\| *(.+?))?\]\]`)
var markdownLinkRegex = regexp.MustCompile(`\[([^\]]+?[^\\])\]\((.+?[^\\])\)`)
var fileURIregex = regexp.MustCompile(`file:///`)
var fencedStartRegex = regexp.MustCompile(`^(` + "```" + `|~~~).*`)
var fencedEndRegex = regexp.MustCompile(`^(` + "```" + `|~~~)\s*`)
var indentedRegex = regexp.MustCompile(`^(\s{4}|\t).+`)
var insideInline = false
var insideFenced = false
var insideIndented = false
var currentCodeBlockStart = -1
// check whether the current line in document is within a fenced or indented
// code block
func isLineWithinCodeBlock(lines []string, lineIndex int, line string) bool {
// if line is already within code fences or indented code block
if insideFenced {
if fencedEndRegex.FindStringIndex(line) != nil &&
lines[currentCodeBlockStart][:3] == line[:3] {
// Fenced code block ends with this line
insideFenced = false
currentCodeBlockStart = -1
}
return true
} else if insideIndented {
if indentedRegex.FindStringIndex(line) == nil && len(line) > 0 {
// Indeted code block ends with this line
insideIndented = false
currentCodeBlockStart = -1
} else {
return true
}
} else {
// Check whether the current line is the start of a code fence or
// indented code block
if fencedStartRegex.FindStringIndex(line) != nil {
insideFenced = true
currentCodeBlockStart = lineIndex
return true
} else if indentedRegex.FindStringIndex(line) != nil &&
(lineIndex > 0 && len(lines[lineIndex-1]) == 0 || lineIndex == 0) {
insideIndented = true
currentCodeBlockStart = lineIndex
return true
}
}
return false
}
// DocumentLinks returns all the internal and external links found in the
// document.
func (d *document) DocumentLinks() ([]documentLink, error) {
@ -202,6 +258,10 @@ func (d *document) DocumentLinks() ([]documentLink, error) {
lines := d.GetLines()
for lineIndex, line := range lines {
if isLineWithinCodeBlock(lines, lineIndex, line) {
continue
}
appendLink := func(href string, start, end int, hasTitle bool, isWikiLink bool) {
if href == "" {
return
@ -233,6 +293,10 @@ func (d *document) DocumentLinks() ([]documentLink, error) {
// note: match[0:1] is the entire match, match[2:3] is the contents of
// brackets, match[4:5] is contents of parentheses
for _, match := range markdownLinkRegex.FindAllStringSubmatchIndex(line, -1) {
// Ignore when inside backticks: `[title](file)`
if linkWithinInlineCode(line, match[0], match[1], insideInline) {
continue
}
// Ignore embedded images ![title](file.png)
if match[0] > 0 && line[match[0]-1] == '!' {
@ -259,10 +323,17 @@ func (d *document) DocumentLinks() ([]documentLink, error) {
}
for _, match := range wikiLinkRegex.FindAllStringSubmatchIndex(line, -1) {
// Ignore when inside backticks: `[[filename]]`
if linkWithinInlineCode(line, match[0], match[1], insideInline) {
continue
}
href := line[match[2]:match[3]]
hasTitle := match[4] != -1
appendLink(href, match[0], match[1], hasTitle, true)
}
if strings.Count(line, "`")%2 == 1 {
insideInline = !insideInline
}
}
return links, nil

@ -150,7 +150,8 @@ func (t *indexTask) execute(callback func(change paths.DiffChange)) (NoteIndexin
return false, nil
}
source := paths.Walk(t.path, t.logger, shouldIgnorePath)
notebookPath := &NotebookPath{Path: t.path}
source := paths.Walk(t.path, t.logger, notebookPath.Filename(), shouldIgnorePath)
target, err := t.index.IndexedPaths()
if err != nil {

@ -0,0 +1 @@
this is a hidden file, and should not be indexed / walked.

@ -10,7 +10,7 @@ import (
// Walk emits the metadata of each file stored in the directory if they pass
// the given shouldIgnorePath closure. Hidden files and directories are ignored.
func Walk(basePath string, logger util.Logger, shouldIgnorePath func(string) (bool, error)) <-chan Metadata {
func Walk(basePath string, logger util.Logger, notebookRoot string, shouldIgnorePath func(string) (bool, error)) <-chan Metadata {
c := make(chan Metadata, 50)
go func() {
defer close(c)
@ -22,9 +22,10 @@ func Walk(basePath string, logger util.Logger, shouldIgnorePath func(string) (bo
filename := info.Name()
isHidden := strings.HasPrefix(filename, ".")
isNotebookRoot := filename == notebookRoot
if info.IsDir() {
if isHidden {
if isHidden && !isNotebookRoot {
return filepath.SkipDir
}

@ -16,8 +16,38 @@ func TestWalk(t *testing.T) {
return filepath.Ext(path) != ".md", nil
}
notebookRoot := filepath.Base(path)
actual := make([]string, 0)
for m := range Walk(path, &util.NullLogger, shouldIgnore) {
for m := range Walk(path, &util.NullLogger, notebookRoot, shouldIgnore) {
assert.NotNil(t, m.Modified)
actual = append(actual, m.Path)
}
assert.Equal(t, actual, []string{
"Dir3/a.md",
"a.md",
"b.md",
"dir1/a.md",
"dir1/b.md",
"dir1/dir1/a.md",
"dir1 a space/a.md",
"dir2/a.md",
})
}
// Walk should ignore all hidden files and dirs (prefixed with "."), with
// exception of the notebook's root dir; i.e the root dir is allowed to be
// hidden.
func TestWalkHidden(t *testing.T) {
var path = fixtures.Path(".walk-hidden")
shouldIgnore := func(path string) (bool, error) {
return filepath.Ext(path) != ".md", nil
}
notebookRoot := filepath.Base(path)
actual := make([]string, 0)
for m := range Walk(path, &util.NullLogger, notebookRoot, shouldIgnore) {
assert.NotNil(t, m.Modified)
actual = append(actual, m.Path)
}

Loading…
Cancel
Save