From e317f0d87949b044075884f8f7e3ef06d7badd4a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micka=C3=ABl=20Menu?= Date: Fri, 17 Dec 2021 13:07:21 +0100 Subject: [PATCH] Fix infinite loop when parsing a single-character hashtag (#119) --- CHANGELOG.md | 2 ++ internal/adapter/markdown/extensions/tag.go | 6 +++++- internal/adapter/markdown/markdown_test.go | 4 ++++ main.go | 20 ++++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e82679c..f101299 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,10 +9,12 @@ All notable changes to this project will be documented in this file. * New LSP commands: * [`zk.list`](docs/editors-integration.md#zklist) to search for notes. * [`zk.tag.list`](docs/editors-integration.md#zktaglist) to retrieve the list of tags. +* `--debug` mode which prints a stacktrace on `SIGINT`. ### Fixed * [#111](https://github.com/mickael-menu/zk/issues/111) Filenames take precedence over folders when matching a sub-path with wiki links. +* [#118](https://github.com/mickael-menu/zk/issues/118) Fix infinite loop when parsing a single-character hashtag. ## 0.8.0 diff --git a/internal/adapter/markdown/extensions/tag.go b/internal/adapter/markdown/extensions/tag.go index d33ecb7..e2c2b6f 100644 --- a/internal/adapter/markdown/extensions/tag.go +++ b/internal/adapter/markdown/extensions/tag.go @@ -106,7 +106,11 @@ func (p *hashtagParser) Parse(parent ast.Node, block text.Reader, pc parser.Cont } } - for i, char := range string(line[1:]) { + for i, char := range string(line) { + if i == 0 { + // Skip the first character, as it is # + continue + } if parsingMultiWordTag { multiWordTagEndPos = i } else { diff --git a/internal/adapter/markdown/markdown_test.go b/internal/adapter/markdown/markdown_test.go index 45d9df6..f12aa90 100644 --- a/internal/adapter/markdown/markdown_test.go +++ b/internal/adapter/markdown/markdown_test.go @@ -188,6 +188,10 @@ func TestParseHashtags(t *testing.T) { test("##invalid also#invalid", []string{}) // Bear's multi multi-word tags are disabled test("#multi word# end", []string{"multi"}) + + // Single character + // See https://github.com/mickael-menu/zk/issues/118 + test("#a", []string{"a"}) } func TestParseWordtags(t *testing.T) { diff --git a/main.go b/main.go index 029e17b..f2ad869 100644 --- a/main.go +++ b/main.go @@ -5,7 +5,9 @@ import ( "fmt" "os" "os/exec" + "os/signal" "path/filepath" + "runtime" "strings" "github.com/alecthomas/kong" @@ -31,6 +33,7 @@ var root struct { NotebookDir string `type:path placeholder:PATH help:"Turn off notebook auto-discovery and set manually the notebook where commands are run."` WorkingDir string `short:W type:path placeholder:PATH help:"Run as if zk was started in instead of the current working directory."` NoInput NoInput `help:"Never prompt or ask for confirmation."` + Debug bool `default:"0" help:"Print a debug stacktrace on SIGINT."` ShowHelp ShowHelp `cmd hidden default:"1"` LSP cmd.LSP `cmd hidden` @@ -84,6 +87,10 @@ func main() { ctx, err := parser.Parse(args) fatalIfError(err) + if root.Debug { + setupDebugMode() + } + // Index the current notebook except if the user is running the `index` // command, otherwise it would hide the stats. if ctx.Command() != "index" { @@ -131,6 +138,19 @@ func fatalIfError(err error) { } } +func setupDebugMode() { + c := make(chan os.Signal) + go func() { + stacktrace := make([]byte, 8192) + for _ = range c { + length := runtime.Stack(stacktrace, true) + fmt.Fprintf(os.Stderr, "%s\n", string(stacktrace[:length])) + os.Exit(1) + } + }() + signal.Notify(c, os.Interrupt) +} + // runAlias will execute a user alias if the command is one of them. func runAlias(container *cli.Container, args []string) (bool, error) { if len(args) < 1 {