diff --git a/.gitignore b/.gitignore index b4afdb2..9d1c75f 100644 --- a/.gitignore +++ b/.gitignore @@ -14,4 +14,5 @@ # Dependency directories (remove the comment below to include it) # vendor/ -.zk +notebook.db +zk diff --git a/CHANGELOG.md b/CHANGELOG.md index bcff917..51df79b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ All notable changes to this project will be documented in this file. ### Added +* New `--date` flag for `zk new` to set the current date manually. * [#144](https://github.com/mickael-menu/zk/issues/144) LSP auto-completion of YAML frontmatter tags. ### Fixed diff --git a/Makefile b/Makefile index be9c47b..ef540c5 100644 --- a/Makefile +++ b/Makefile @@ -10,6 +10,14 @@ install: test: $(call go,test,./...) +# Run end-to-end tests. +tesh: build + @PATH=$(shell pwd):$(PATH) tesh tests tests + +# Update end-to-end tests. +tesh-update: build + PATH=$(shell pwd):$(PATH) tesh -u tests tests + # Produce a release bundle for all platforms. dist: dist-macos dist-linux rm -f zk diff --git a/internal/adapter/lsp/cmd_new.go b/internal/adapter/lsp/cmd_new.go index 8cf5fa1..23dfdc4 100644 --- a/internal/adapter/lsp/cmd_new.go +++ b/internal/adapter/lsp/cmd_new.go @@ -79,8 +79,12 @@ func executeCommandNew(notebook *core.Notebook, documents *documentStore, contex return nil, err } - currentDir := filepath.Dir(doc.Path) - linkFormatterContext, err := core.NewLinkFormatterContext(note.AsMinimalNote(), notebook.Path, currentDir) + path := core.NotebookPath{ + Path: note.Path, + BasePath: notebook.Path, + WorkingDir: filepath.Dir(doc.Path), + } + linkFormatterContext, err := core.NewLinkFormatterContext(path, note.Title, note.Metadata) if err != nil { return nil, err } diff --git a/internal/adapter/lsp/server.go b/internal/adapter/lsp/server.go index d3fb817..454da9c 100644 --- a/internal/adapter/lsp/server.go +++ b/internal/adapter/lsp/server.go @@ -33,14 +33,13 @@ type Server struct { // ServerOpts holds the options to create a new Server. type ServerOpts struct { - Name string - Version string - LogFile opt.String - Logger *util.ProxyLogger - Notebooks *core.NotebookStore - NoteContentParser core.NoteContentParser - TemplateLoader core.TemplateLoader - FS core.FileStorage + Name string + Version string + LogFile opt.String + Logger *util.ProxyLogger + Notebooks *core.NotebookStore + TemplateLoader core.TemplateLoader + FS core.FileStorage } // NewServer creates a new Server instance. @@ -61,13 +60,12 @@ func NewServer(opts ServerOpts) *Server { } server := &Server{ - server: glspServer, - notebooks: opts.Notebooks, - documents: newDocumentStore(fs, opts.Logger), - noteContentParser: opts.NoteContentParser, - templateLoader: opts.TemplateLoader, - fs: fs, - logger: opts.Logger, + server: glspServer, + notebooks: opts.Notebooks, + documents: newDocumentStore(fs, opts.Logger), + templateLoader: opts.TemplateLoader, + fs: fs, + logger: opts.Logger, } var clientCapabilities protocol.ClientCapabilities @@ -636,7 +634,7 @@ func (s *Server) refreshDiagnosticsOfDocument(doc *document, notify glsp.NotifyF // buildInvokedCompletionList builds the completion item response for a // completion started automatically when typing an identifier, or manually. func (s *Server) buildInvokedCompletionList(notebook *core.Notebook, doc *document, position protocol.Position) ([]protocol.CompletionItem, error) { - if !doc.IsTagPosition(position, s.noteContentParser) { + if !doc.IsTagPosition(position, notebook.Parser) { return nil, nil } return s.buildTagCompletionList(notebook, doc.WordAt(position)) @@ -810,8 +808,12 @@ func (s *Server) newCompletionItem(notebook *core.Notebook, note core.MinimalNot } func (s *Server) newTextEditForLink(notebook *core.Notebook, note core.MinimalNote, doc *document, pos protocol.Position, linkFormatter core.LinkFormatter) (interface{}, error) { - currentDir := filepath.Dir(doc.Path) - context, err := core.NewLinkFormatterContext(note, notebook.Path, currentDir) + path := core.NotebookPath{ + Path: note.Path, + BasePath: notebook.Path, + WorkingDir: filepath.Dir(doc.Path), + } + context, err := core.NewLinkFormatterContext(path, note.Title, note.Metadata) if err != nil { return nil, err } diff --git a/internal/adapter/term/term.go b/internal/adapter/term/term.go index dfe0db7..5b557c9 100644 --- a/internal/adapter/term/term.go +++ b/internal/adapter/term/term.go @@ -1,6 +1,7 @@ package term import ( + "fmt" "os" "strings" @@ -10,7 +11,8 @@ import ( // Terminal offers utilities to interact with the terminal. type Terminal struct { - NoInput bool + NoInput bool + ForceInput string } func New() *Terminal { @@ -38,7 +40,14 @@ func (t *Terminal) SupportsUTF8() bool { // Confirm is a shortcut to prompt a yes/no question to the user. func (t *Terminal) Confirm(msg string, defaultAnswer bool) (confirmed, skipped bool) { if !t.IsInteractive() { - return defaultAnswer, true + switch strings.ToLower(t.ForceInput) { + case "y": + return t.forceConfirm(msg, true) + case "n": + return t.forceConfirm(msg, false) + default: + return defaultAnswer, true + } } confirmed = false @@ -49,3 +58,16 @@ func (t *Terminal) Confirm(msg string, defaultAnswer bool) (confirmed, skipped b survey.AskOne(prompt, &confirmed) return confirmed, false } + +func (t *Terminal) forceConfirm(msg string, answer bool) (confirmed, skipped bool) { + msg = "? " + msg + " (" + if answer { + msg += "Y/n" + } else { + msg += "y/N" + } + msg += ")" + fmt.Println(msg) + + return answer, false +} diff --git a/internal/cli/cmd/index.go b/internal/cli/cmd/index.go index 1a323b7..42dd3f9 100644 --- a/internal/cli/cmd/index.go +++ b/internal/cli/cmd/index.go @@ -10,8 +10,8 @@ import ( // Index indexes the content of all the notes in the notebook. type Index struct { Force bool `short:"f" help:"Force indexing all the notes."` - Verbose bool `short:"v" help:"Print detailed information about the indexing process."` - Quiet bool `short:"q" help:"Do not print statistics nor progress."` + Verbose bool `short:"v" xor:"print" help:"Print detailed information about the indexing process."` + Quiet bool `short:"q" xor:"print" help:"Do not print statistics nor progress."` } func (cmd *Index) Help() string { diff --git a/internal/cli/cmd/list.go b/internal/cli/cmd/list.go index 585f621..444e704 100644 --- a/internal/cli/cmd/list.go +++ b/internal/cli/cmd/list.go @@ -168,13 +168,13 @@ Created: {{date created "short"}} "long": `{{style "title" title}} {{style "path" path}} Created: {{date created "short"}} -Modified: {{date created "short"}} +Modified: {{date modified "short"}} {{list snippets}}`, "full": `{{style "title" title}} {{style "path" path}} Created: {{date created "short"}} -Modified: {{date created "short"}} +Modified: {{date modified "short"}} Tags: {{join tags ", "}} {{prepend " " body}} diff --git a/internal/cli/cmd/list_test.go b/internal/cli/cmd/list_test.go index 5428f52..caad91d 100644 --- a/internal/cli/cmd/list_test.go +++ b/internal/cli/cmd/list_test.go @@ -38,13 +38,13 @@ Created: {{date created "short"}} test("long", `{{style "title" title}} {{style "path" path}} Created: {{date created "short"}} -Modified: {{date created "short"}} +Modified: {{date modified "short"}} {{list snippets}}`) test("full", `{{style "title" title}} {{style "path" path}} Created: {{date created "short"}} -Modified: {{date created "short"}} +Modified: {{date modified "short"}} Tags: {{join tags ", "}} {{prepend " " body}} diff --git a/internal/cli/cmd/lsp.go b/internal/cli/cmd/lsp.go index a0a4bda..286773e 100644 --- a/internal/cli/cmd/lsp.go +++ b/internal/cli/cmd/lsp.go @@ -13,14 +13,13 @@ type LSP struct { func (cmd *LSP) Run(container *cli.Container) error { server := lsp.NewServer(lsp.ServerOpts{ - Name: "zk", - Version: container.Version, - Logger: container.Logger, - LogFile: opt.NewNotEmptyString(cmd.Log), - Notebooks: container.Notebooks, - NoteContentParser: container.NoteContentParser, - TemplateLoader: container.TemplateLoader, - FS: container.FS, + Name: "zk", + Version: container.Version, + Logger: container.Logger, + LogFile: opt.NewNotEmptyString(cmd.Log), + Notebooks: container.Notebooks, + TemplateLoader: container.TemplateLoader, + FS: container.FS, }) return server.Run() diff --git a/internal/cli/cmd/new.go b/internal/cli/cmd/new.go index 1649e43..87ce4e9 100644 --- a/internal/cli/cmd/new.go +++ b/internal/cli/cmd/new.go @@ -9,6 +9,7 @@ import ( "github.com/mickael-menu/zk/internal/cli" "github.com/mickael-menu/zk/internal/core" + dateutil "github.com/mickael-menu/zk/internal/util/date" "github.com/mickael-menu/zk/internal/util/opt" osutil "github.com/mickael-menu/zk/internal/util/os" ) @@ -17,6 +18,7 @@ import ( type New struct { Directory string `arg optional default:"." help:"Directory in which to create the note."` Title string `short:t placeholder:TITLE help:"Title of the new note."` + Date string ` placeholder:DATE help:"Set the current date."` Group string `short:g placeholder:NAME help:"Name of the config group this note belongs to. Takes precedence over the config of the directory."` Extra map[string]string ` help:"Extra variables passed to the templates." mapsep:","` Template string ` placeholder:PATH help:"Custom template used to render the note."` @@ -35,6 +37,14 @@ func (cmd *New) Run(container *cli.Container) error { return err } + date := time.Now() + if cmd.Date != "" { + date, err = dateutil.TimeFromNatural(cmd.Date) + if err != nil { + return err + } + } + note, err := notebook.NewNote(core.NewNoteOpts{ Title: opt.NewNotEmptyString(cmd.Title), Content: content.Unwrap(), @@ -42,7 +52,7 @@ func (cmd *New) Run(container *cli.Container) error { Group: opt.NewNotEmptyString(cmd.Group), Template: opt.NewNotEmptyString(cmd.Template), Extra: cmd.Extra, - Date: time.Now(), + Date: date, DryRun: cmd.DryRun, }) diff --git a/internal/cli/container.go b/internal/cli/container.go index bfe3397..0c00443 100644 --- a/internal/cli/container.go +++ b/internal/cli/container.go @@ -31,10 +31,10 @@ type Container struct { Version string Config core.Config Logger *util.ProxyLogger + Styler *core.ProxyStyler Terminal *term.Terminal FS *fs.FileStorage TemplateLoader core.TemplateLoader - NoteContentParser core.NoteContentParser WorkingDir string Notebooks *core.NotebookStore currentNotebook *core.Notebook @@ -45,7 +45,7 @@ func NewContainer(version string) (*Container, error) { wrap := errors.Wrapper("initialization") term := term.New() - styler := term + styler := core.NewProxyStyler(term) logger := util.NewProxyLogger(util.NewStdLogger("zk: ", 0)) fs, err := fs.NewFileStorage("", logger) config := core.NewDefaultConfig() @@ -71,23 +71,14 @@ func NewContainer(version string) (*Container, error) { } } - noteContentParser := markdown.NewParser( - markdown.ParserOpts{ - HashtagEnabled: config.Format.Markdown.Hashtags, - MultiWordTagEnabled: config.Format.Markdown.MultiwordTags, - ColontagEnabled: config.Format.Markdown.ColonTags, - }, - logger, - ) - return &Container{ - Version: version, - Config: config, - Logger: logger, - Terminal: term, - FS: fs, - TemplateLoader: templateLoader, - NoteContentParser: noteContentParser, + Version: version, + Config: config, + Logger: logger, + Styler: styler, + Terminal: term, + FS: fs, + TemplateLoader: templateLoader, Notebooks: core.NewNotebookStore(config, core.NotebookStorePorts{ FS: fs, TemplateLoader: templateLoader, @@ -99,8 +90,15 @@ func NewContainer(version string) (*Container, error) { } notebook := core.NewNotebook(path, config, core.NotebookPorts{ - NoteIndex: sqlite.NewNoteIndex(db, logger), - NoteContentParser: noteContentParser, + NoteIndex: sqlite.NewNoteIndex(db, logger), + NoteContentParser: markdown.NewParser( + markdown.ParserOpts{ + HashtagEnabled: config.Format.Markdown.Hashtags, + MultiWordTagEnabled: config.Format.Markdown.MultiwordTags, + ColontagEnabled: config.Format.Markdown.ColonTags, + }, + logger, + ), TemplateLoaderFactory: func(language string) (core.TemplateLoader, error) { loader := handlebars.NewLoader(handlebars.LoaderOpts{ LookupPaths: []string{ diff --git a/internal/core/link_format.go b/internal/core/link_format.go index d93396a..ef6bb16 100644 --- a/internal/core/link_format.go +++ b/internal/core/link_format.go @@ -3,7 +3,6 @@ package core import ( "fmt" "net/url" - "path/filepath" "strings" "github.com/mickael-menu/zk/internal/util/errors" @@ -13,32 +12,31 @@ import ( // Metadata used to generate a link. type LinkFormatterContext struct { // Filename of the note - Filename string - // File path to the note, relative to the notebook root. - Path string + Filename string `json:"filename"` + // File path to the note, relative to the notebook root.link-encode-path + Path string `json:"path"` // Absolute file path to the note. - AbsPath string `handlebars:"abs-path"` + AbsPath string `json:"absPath" handlebars:"abs-path"` // File path to the note, relative to the current directory. - RelPath string `handlebars:"rel-path"` + RelPath string `json:"relPath" handlebars:"rel-path"` // Title of the note. - Title string + Title string `json:"title"` // Metadata extracted from the YAML frontmatter. - Metadata map[string]interface{} + Metadata map[string]interface{} `json:"metadata"` } -func NewLinkFormatterContext(note MinimalNote, notebookDir string, currentDir string) (LinkFormatterContext, error) { - absPath := filepath.Join(notebookDir, note.Path) - relPath, err := filepath.Rel(currentDir, absPath) +func NewLinkFormatterContext(path NotebookPath, title string, metadata map[string]interface{}) (LinkFormatterContext, error) { + relPath, err := path.PathRelToWorkingDir() if err != nil { return LinkFormatterContext{}, err } return LinkFormatterContext{ - Filename: filepath.Base(note.Path), - Path: note.Path, - AbsPath: absPath, + Filename: path.Filename(), + Path: path.Path, + AbsPath: path.AbsPath(), RelPath: relPath, - Title: note.Title, - Metadata: note.Metadata, + Title: title, + Metadata: metadata, }, nil } diff --git a/internal/core/note_format.go b/internal/core/note_format.go index c3bdf5c..563f9cd 100644 --- a/internal/core/note_format.go +++ b/internal/core/note_format.go @@ -3,7 +3,6 @@ package core import ( "encoding/json" "fmt" - "path/filepath" "regexp" "time" ) @@ -18,12 +17,12 @@ func newNoteFormatter(basePath string, template Template, linkFormatter LinkForm } return func(note ContextualNote) (string, error) { - path, err := fs.Rel(filepath.Join(basePath, note.Path)) - if err != nil { - return "", err + path := NotebookPath{ + Path: note.Path, + BasePath: basePath, + WorkingDir: fs.WorkingDir(), } - - absPath, err := fs.Abs(filepath.Join(basePath, note.Path)) + relPath, err := path.PathRelToWorkingDir() if err != nil { return "", err } @@ -36,17 +35,15 @@ func newNoteFormatter(basePath string, template Template, linkFormatter LinkForm return template.Render(noteFormatRenderContext{ Filename: note.Filename(), FilenameStem: note.FilenameStem(), - Path: path, - AbsPath: absPath, + Path: relPath, + AbsPath: path.AbsPath(), Title: note.Title, Link: newLazyStringer(func() string { - link, _ := linkFormatter(LinkFormatterContext{ - Path: note.Path, - RelPath: path, - AbsPath: absPath, - Title: note.Title, - Metadata: note.Metadata, - }) + context, err := NewLinkFormatterContext(path, note.Title, note.Metadata) + if err != nil { + return "" + } + link, _ := linkFormatter(context) return link }), Lead: note.Lead, diff --git a/internal/core/note_parse.go b/internal/core/note_parse.go index 1321bae..8e469f5 100644 --- a/internal/core/note_parse.go +++ b/internal/core/note_parse.go @@ -61,7 +61,7 @@ func (n *Notebook) ParseNoteWithContent(absPath string, content []byte) (*Note, } contentStr := string(content) - contentParts, err := n.parser.ParseNoteContent(contentStr) + contentParts, err := n.Parser.ParseNoteContent(contentStr) if err != nil { return nil, wrap(err) } diff --git a/internal/core/notebook.go b/internal/core/notebook.go index 0308539..489acb9 100644 --- a/internal/core/notebook.go +++ b/internal/core/notebook.go @@ -18,9 +18,9 @@ import ( type Notebook struct { Path string Config Config + Parser NoteContentParser index NoteIndex - parser NoteContentParser templateLoaderFactory TemplateLoaderFactory idGeneratorFactory IDGeneratorFactory fs FileStorage @@ -37,8 +37,8 @@ func NewNotebook( return &Notebook{ Path: path, Config: config, + Parser: ports.NoteContentParser, index: ports.NoteIndex, - parser: ports.NoteContentParser, templateLoaderFactory: ports.TemplateLoaderFactory, idGeneratorFactory: ports.IDGeneratorFactory, fs: ports.FS, diff --git a/internal/core/notebook_path.go b/internal/core/notebook_path.go new file mode 100644 index 0000000..7190699 --- /dev/null +++ b/internal/core/notebook_path.go @@ -0,0 +1,32 @@ +package core + +import "path/filepath" + +type NotebookPath struct { + // Path of a notebook file, relative to the notebook dir. + Path string + // Root directory of the notebook. + BasePath string + // Current working directory. + WorkingDir string +} + +// Filename returns the filename of the notebook file. +func (p NotebookPath) Filename() string { + return filepath.Base(p.Path) +} + +// AbsPath returns the absolute path to the notebook file. +func (p NotebookPath) AbsPath() string { + return filepath.Join(p.BasePath, p.Path) +} + +// PathRelToWorkingDir returns the path to the notebook file relative to the +// working dir. If the working dir is not set, returns the path relative to the +// notebook dir. +func (p NotebookPath) PathRelToWorkingDir() (string, error) { + if p.WorkingDir == "" { + return p.Path, nil + } + return filepath.Rel(p.WorkingDir, p.AbsPath()) +} diff --git a/internal/core/style.go b/internal/core/style.go index 0b11786..33b2742 100644 --- a/internal/core/style.go +++ b/internal/core/style.go @@ -1,5 +1,7 @@ package core +import "fmt" + // Style is a key representing a single styling rule. type Style string @@ -73,6 +75,26 @@ type Styler interface { MustStyle(text string, rules ...Style) string } +// ProxyStyler is a styler delegating to an underlying styler. +// Can be used to change the active styler during runtime. +type ProxyStyler struct { + Styler Styler +} + +func NewProxyStyler(styler Styler) *ProxyStyler { + return &ProxyStyler{styler} +} + +// Style implements Styler. +func (s ProxyStyler) Style(text string, rule ...Style) (string, error) { + return s.Styler.Style(text, rule...) +} + +// MustStyle implements Styler. +func (s ProxyStyler) MustStyle(text string, rule ...Style) string { + return s.Styler.MustStyle(text, rule...) +} + // NullStyler is a Styler with no styling rules. var NullStyler = nullStyler{} @@ -87,3 +109,21 @@ func (s nullStyler) Style(text string, rule ...Style) (string, error) { func (s nullStyler) MustStyle(text string, rule ...Style) string { return text } + +// TagStyler is a Styler which outputs XML tags. +var TagStyler = tagStyler{} + +type tagStyler struct{} + +// Style implements Styler. +func (s tagStyler) Style(text string, rules ...Style) (string, error) { + return s.MustStyle(text, rules...), nil +} + +// MustStyle implements Styler. +func (s tagStyler) MustStyle(text string, rules ...Style) string { + for _, rule := range rules { + text = fmt.Sprintf("<%s>%s", rule, text, rule) + } + return text +} diff --git a/main.go b/main.go index f2ad869..1eb0254 100644 --- a/main.go +++ b/main.go @@ -33,7 +33,10 @@ 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."` + // ForceInput is a debugging flag overriding the default value of interaction prompts. + ForceInput string `hidden xor:"input"` + Debug bool `default:"0" hidden help:"Print a debug stacktrace on SIGINT."` + DebugStyle bool `default:"0" hidden help:"Force styling output as XML tags."` ShowHelp ShowHelp `cmd hidden default:"1"` LSP cmd.LSP `cmd hidden` @@ -90,6 +93,11 @@ func main() { if root.Debug { setupDebugMode() } + if root.DebugStyle { + container.Styler.Styler = core.TagStyler + } + + container.Terminal.ForceInput = root.ForceInput // Index the current notebook except if the user is running the `index` // command, otherwise it would hide the stats. diff --git a/tests/cmd-edit.tesh b/tests/cmd-edit.tesh new file mode 100644 index 0000000..db2d74a --- /dev/null +++ b/tests/cmd-edit.tesh @@ -0,0 +1,56 @@ +$ cd edit + +# Editor resolution + +# Checks that no editor is set in the current environment. +$ echo $VISUAL $EDITOR $ZK_EDITOR +> + +# No editor set +1$ zk edit blue.md +2>zk: error: no editor set in config + +# Use the EDITOR env variable. +$ EDITOR=echo zk edit blue.md +>{{working-dir}}/blue.md + +# VISUAL takes precedence over EDITOR. +$ EDITOR=vim VISUAL=echo zk edit blue.md +>{{working-dir}}/blue.md + +# The tool/editor config takes precedence over EDITOR and VISUAL. +$ echo "[tool]\neditor = 'echo'" > .zk/config.toml + +$ EDITOR=vim VISUAL=vim zk edit blue.md +>{{working-dir}}/blue.md + +# ZK_EDITOR takes precedence over everything else. +$ echo "[tool]\n editor = 'vim'" > .zk/config.toml + +$ EDITOR=vim VISUAL=vim ZK_EDITOR=echo zk edit blue.md +>{{working-dir}}/blue.md + +# Filtering options + +# Sort by title descending +$ ZK_EDITOR=echo zk edit --sort title- +>{{working-dir}}/yellow.md {{working-dir}}/red.md {{working-dir}}/purple.md {{working-dir}}/green.md {{working-dir}}/blue.md + +# Edit confirmation + +# Opens without confirmation up to 5 notes at the same time. +$ ZK_EDITOR=echo zk edit +>{{working-dir}}/blue.md {{working-dir}}/green.md {{working-dir}}/purple.md {{working-dir}}/red.md {{working-dir}}/yellow.md + +# Requires confirmation for more than 5 notes. +$ touch orange.md + +$ ZK_EDITOR=echo zk edit --force-input n +>? Are you sure you want to open 6 notes in the editor? (y/N) + +1$ ZK_EDITOR=echo zk edit +2>zk: error: too many notes to be opened in the editor, aborting… + +# Force confirmation. +$ ZK_EDITOR=echo zk edit --force +>{{working-dir}}/orange.md {{working-dir}}/blue.md {{working-dir}}/green.md {{working-dir}}/purple.md {{working-dir}}/red.md {{working-dir}}/yellow.md diff --git a/tests/cmd-graph.tesh b/tests/cmd-graph.tesh new file mode 100644 index 0000000..04ed869 --- /dev/null +++ b/tests/cmd-graph.tesh @@ -0,0 +1,78 @@ +$ cd full-sample + +# Print help for `zk graph` +$ zk graph --help +>Usage: zk graph --format=STRING [ ...] +> +>Produce a graph of the notes matching the given criteria. +> +>Arguments: +> [ ...] Find notes matching the given path, including its descendants. +> +>Flags: +> -h, --help Show context-sensitive help. +> --notebook-dir=PATH Turn off notebook auto-discovery and set manually +> the notebook where commands are run. +> -W, --working-dir=PATH Run as if zk was started in instead of the +> current working directory. +> --no-input Never prompt or ask for confirmation. +> +>Formatting +> -f, --format=STRING Format of the graph among: json. +> -q, --quiet Do not print the total number of notes found. +> +>Filtering +> -i, --interactive Select notes interactively with fzf. +> -n, --limit=COUNT Limit the number of notes found. +> -m, --match=QUERY Terms to search for in the notes. +> -e, --exact-match Search for exact occurrences of the --match +> argument (case insensitive). +> -x, --exclude=PATH,... Ignore notes matching the given path, including +> its descendants. +> -t, --tag=TAG,... Find notes tagged with the given tags. +> --mention=PATH,... Find notes mentioning the title of the given +> ones. +> --mentioned-by=PATH,... Find notes whose title is mentioned in the +> given ones. +> -l, --link-to=PATH,... Find notes which are linking to the given ones. +> --no-link-to=PATH,... Find notes which are not linking to the given +> notes. +> -L, --linked-by=PATH,... Find notes which are linked by the given ones. +> --no-linked-by=PATH,... Find notes which are not linked by the given +> ones. +> --orphan Find notes which are not linked by any other +> note. +> --related=PATH,... Find notes which might be related to the given +> ones. +> --max-distance=COUNT Maximum distance between two linked notes. +> -r, --recursive Follow links recursively. +> --created=DATE +> --created-before=DATE Find notes created before the given date. +> --created-after=DATE Find notes created after the given date. +> --modified=DATE Find notes modified on the given date. +> --modified-before=DATE Find notes modified before the given date. +> --modified-after=DATE Find notes modified after the given date. +> +>Sorting +> -s, --sort=TERM,... Order the notes by the given criterion. + +# Format is required +1$ zk graph +2>zk: error: missing flags: --format=STRING + +# Test the JSON format. +$ zk graph -qn5 --format json +>{ +> "notes": [ +> {"filename":"uxjt.md","filenameStem":"uxjt","path":"uxjt.md","absPath":"{{working-dir}}/uxjt.md","title":"Buy low, sell high","link":"[Buy low, sell high](uxjt)","lead":"It's better to invest when the prices are low, because it will usually go up on the long term, despite the fact that [financial markets are random](fa2k).","body":"It's better to invest when the prices are low, because it will usually go up on the long term, despite the fact that [financial markets are random](fa2k).\n\nDon't wait until you think the stocks are at their lowest ([speculation](pywo)), instead buy some when the prices are dropping, and buy more every month if the prices continue to drop.\n\nInvesting a constant amount of money regularly (e.g. monthly) is a simple way to make sure you buy less stocks when the prices are high, and more when they are low. [Compound interests will work for you over time](smdc).\n\n:finance:","snippets":["It's better to invest when the prices are low, because it will usually go up on the long term, despite the fact that [financial markets are random](fa2k)."],"rawContent":"# Buy low, sell high\n\nIt's better to invest when the prices are low, because it will usually go up on the long term, despite the fact that [financial markets are random](fa2k).\n\nDon't wait until you think the stocks are at their lowest ([speculation](pywo)), instead buy some when the prices are dropping, and buy more every month if the prices continue to drop.\n\nInvesting a constant amount of money regularly (e.g. monthly) is a simple way to make sure you buy less stocks when the prices are high, and more when they are low. [Compound interests will work for you over time](smdc).\n\n:finance:\n","wordCount":103,"tags":["finance"],"metadata":{},"created":"{{match '[\-T\.\:0-9]+'}}Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"cc0e1a9cad8b526254ac1d87f1534c010c2ffe5d399a7c1af1da636a734b60c2"}, +> {"filename":"fwsj.md","filenameStem":"fwsj","path":"fwsj.md","absPath":"{{working-dir}}/fwsj.md","title":"Channel","link":"[Channel](fwsj)","lead":"* Channels are a great approach for safe concurrency.\n* It's an implementation of the [message passing](4oma) pattern.","body":"* Channels are a great approach for safe concurrency.\n* It's an implementation of the [message passing](4oma) pattern.\n\n:programming:","snippets":["* Channels are a great approach for safe concurrency.\n* It's an implementation of the [message passing](4oma) pattern."],"rawContent":"# Channel\n\n* Channels are a great approach for safe concurrency.\n* It's an implementation of the [message passing](4oma) pattern.\n\n:programming:\n","wordCount":21,"tags":["programming"],"metadata":{},"created":"{{match '[\-T\.\:0-9]+'}}Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"cafbb0c69c39729a2e7da6800c97fc5a1f1caa5667ab04c11e06a749610ca4e4"}, +> {"filename":"smdc.md","filenameStem":"smdc","path":"smdc.md","absPath":"{{working-dir}}/smdc.md","title":"Compound interests make you rich","link":"[Compound interests make you rich](smdc)","lead":"Since the growth is exponential, time is more important than the amount of money you invest with compound interests. Start investing right now!","body":"Since the growth is exponential, time is more important than the amount of money you invest with compound interests. Start investing right now!\n\nThis also means that small interest percentages add up to big amount. So [beware of financial products](4yib) eating your interests.\n\nBuy new shares with the interests to benefit from the compound interests, e.g. after a unique investment of $1,000 with a 10% interest rate:\n\n- without reinvesting the dividends:\n\t- 40 yrs = $5,000\n\t- 50 yrs = $6,000\n\t\n- with compound interest:\n\t- 40 yrs = $45,000\n\t- 50 yrs = $117,000\n\t\n## References\n\n- [These 3 Charts Show The Amazing Power Of Compound Interest](https://www.businessinsider.com/personal-finance/amazing-power-of-compound-interest-2014-7?r=DE\u0026IR=T)\n\n:finance:","snippets":["Since the growth is exponential, time is more important than the amount of money you invest with compound interests. Start investing right now!"],"rawContent":"# Compound interests make you rich\n\nSince the growth is exponential, time is more important than the amount of money you invest with compound interests. Start investing right now!\n\nThis also means that small interest percentages add up to big amount. So [beware of financial products](4yib) eating your interests.\n\nBuy new shares with the interests to benefit from the compound interests, e.g. after a unique investment of $1,000 with a 10% interest rate:\n\n- without reinvesting the dividends:\n\t- 40 yrs = $5,000\n\t- 50 yrs = $6,000\n\t\n- with compound interest:\n\t- 40 yrs = $45,000\n\t- 50 yrs = $117,000\n\t\n## References\n\n- [These 3 Charts Show The Amazing Power Of Compound Interest](https://www.businessinsider.com/personal-finance/amazing-power-of-compound-interest-2014-7?r=DE\u0026IR=T)\n\n:finance:\n","wordCount":116,"tags":["finance"],"metadata":{},"created":"{{match '[\-T\.\:0-9]+'}}Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"c14982f5c20b58fdbbdcf6430308ee732ebd04b4c4814ded011698d12d0aff6b"}, +> {"filename":"g7qa.md","filenameStem":"g7qa","path":"g7qa.md","absPath":"{{working-dir}}/g7qa.md","title":"Concurrency in Rust","link":"[Concurrency in Rust](g7qa)","lead":"* Thanks to the [Ownership pattern](88el), Rust has a model of [Fearless concurrency](2cl7).\n* Rust aims to have a small runtime, so it doesn't support [green threads](inbox/my59).\n * Crates exist to add support for green threads if needed.\n * Instead, Rust relies on the OS threads, a model called 1-1.","body":"* Thanks to the [Ownership pattern](88el), Rust has a model of [Fearless concurrency](2cl7).\n* Rust aims to have a small runtime, so it doesn't support [green threads](inbox/my59).\n * Crates exist to add support for green threads if needed.\n * Instead, Rust relies on the OS threads, a model called 1-1.\n\n* Rust offers a number of constructs for sharing data between threads:\n * [Channel](fwsj) for a safe [message passing](4oma) approach.\n * [Mutex](inbox/er4k) for managing shared state.\n\n:rust:programming:","snippets":["* Thanks to the [Ownership pattern](88el), Rust has a model of [Fearless concurrency](2cl7).\n* Rust aims to have a small runtime, so it doesn't support [green threads](inbox/my59).\n * Crates exist to add support for green threads if needed.\n * Instead, Rust relies on the OS threads, a model called 1-1."],"rawContent":"# Concurrency in Rust\n\n* Thanks to the [Ownership pattern](88el), Rust has a model of [Fearless concurrency](2cl7).\n* Rust aims to have a small runtime, so it doesn't support [green threads](inbox/my59).\n * Crates exist to add support for green threads if needed.\n * Instead, Rust relies on the OS threads, a model called 1-1.\n\n* Rust offers a number of constructs for sharing data between threads:\n * [Channel](fwsj) for a safe [message passing](4oma) approach.\n * [Mutex](inbox/er4k) for managing shared state.\n\n:rust:programming:\n","wordCount":81,"tags":["programming","rust"],"metadata":{},"created":"{{match '[\-T\.\:0-9]+'}}Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"03be1317b6917839ca3a6d1f8c60eab97086cfc2f4637f95f122522476ed0155"}, +> {"filename":"3cut.md","filenameStem":"3cut","path":"3cut.md","absPath":"{{working-dir}}/3cut.md","title":"Dangling pointers","link":"[Dangling pointers](3cut)","lead":"A *dangling pointer* is a reference that is kept to freed data. With C, reading it causes a *segmentation fault*.","body":"A *dangling pointer* is a reference that is kept to freed data. With C, reading it causes a *segmentation fault*.\n\nRust protects against *dangling pointers* by making sure data is not freed until it goes out of scope ([Ownership in Rust](88el)).\n\n:programming:","snippets":["A *dangling pointer* is a reference that is kept to freed data. With C, reading it causes a *segmentation fault*."],"rawContent":"---\naliases: [dangling reference]\n---\n\n# Dangling pointers\n\nA *dangling pointer* is a reference that is kept to freed data. With C, reading it causes a *segmentation fault*.\n\nRust protects against *dangling pointers* by making sure data is not freed until it goes out of scope ([Ownership in Rust](88el)).\n\n:programming:\n","wordCount":50,"tags":["programming"],"metadata":{"aliases":["dangling reference"]},"created":"{{match '[\-T\.\:0-9]+'}}Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"7f4a61afdbc077e286c5e0ac91a71bfdec45b6b0cf3a5e14408aba45bd4d58a8"} +> ], +> "links": [ +> {"title":"Channel","href":"fwsj","type":"markdown","isExternal":false,"rels":[],"snippet":"[Channel](fwsj) for a safe [message passing](4oma) approach.","snippetStart":423,"snippetEnd":483,"sourceId":11,"sourcePath":"g7qa.md","targetId":10,"targetPath":"fwsj.md"}, +> {"title":"Compound interests will work for you over time","href":"smdc","type":"markdown","isExternal":false,"rels":[],"snippet":"Investing a constant amount of money regularly (e.g. monthly) is a simple way to make sure you buy less stocks when the prices are high, and more when they are low. [Compound interests will work for you over time](smdc).","snippetStart":364,"snippetEnd":584,"sourceId":25,"sourcePath":"uxjt.md","targetId":22,"targetPath":"smdc.md"} +> ] +>} + diff --git a/tests/cmd-index.tesh b/tests/cmd-index.tesh new file mode 100644 index 0000000..76e2a5c --- /dev/null +++ b/tests/cmd-index.tesh @@ -0,0 +1,128 @@ +$ cd index + +# Print help for `zk index` +$ zk index --help +>Usage: zk index +> +>Index the notes to be searchable. +> +>You usually do not need to run `zk index` manually, as notes are indexed +>automatically when needed. +> +>Flags: +> -h, --help Show context-sensitive help. +> --notebook-dir=PATH Turn off notebook auto-discovery and set manually +> the notebook where commands are run. +> -W, --working-dir=PATH Run as if zk was started in instead of the +> current working directory. +> --no-input Never prompt or ask for confirmation. +> +> -f, --force Force indexing all the notes. +> -v, --verbose Print detailed information about the indexing +> process. +> -q, --quiet Do not print statistics nor progress. + +# Index initial notes. +$ zk index +>Indexed 3 notes in 0s +> + 0 added +> ~ 3 modified +> - 1 removed + +# No changes. +$ zk index +>Indexed 3 notes in 0s +> + 0 added +> ~ 0 modified +> - 0 removed + +# Add a new note. +$ touch eggplant/apple.md && zk index +>Indexed 4 notes in 0s +> + 1 added +> ~ 0 modified +> - 0 removed + +# Modify an existing note. +$ echo "More" >> banana.md && zk index +>Indexed 4 notes in 0s +> + 0 added +> ~ 1 modified +> - 0 removed + +# Delete a note. +$ rm banana.md + +$ zk index +>Indexed 3 notes in 0s +> + 0 added +> ~ 0 modified +> - 1 removed + +# Ignore path patterns. +$ touch carrot-ignored/ananas.md && zk index +>Indexed 3 notes in 0s +> + 0 added +> ~ 0 modified +> - 0 removed + +# Ignore unknown extensions. +$ touch orange.markdown && zk index +>Indexed 3 notes in 0s +> + 0 added +> ~ 0 modified +> - 0 removed + +# Force re-indexing all notes. +$ zk index --force +>Indexed 3 notes in 0s +> + 0 added +> ~ 3 modified +> - 0 removed + +# Force re-indexing all notes (short flag). +$ zk index -f +>Indexed 3 notes in 0s +> + 0 added +> ~ 3 modified +> - 0 removed + +# Quiet mode. +$ zk index --quiet + +# Quiet mode (short flag). +$ zk index -q + +# Verbose mode. +$ touch banana.md && echo "More" >> litchee.md && rm eggplant/apple.md && zk index --verbose +>- added banana.md +>- removed eggplant/apple.md +>- unchanged eggplant/clementine.md +>- modified litchee.md +>- ignored carrot-ignored/ananas.md: matched ignore glob "carrot-ignored/*" +>- ignored carrot-ignored/tomato.md: matched ignore glob "carrot-ignored/*" +>- ignored orange.markdown: expected extension "md" +> +>Indexed 3 notes in 0s +> + 1 added +> ~ 1 modified +> - 1 removed + +# Verbose mode (short flag). +$ zk index -v +>- unchanged banana.md +>- unchanged eggplant/clementine.md +>- unchanged litchee.md +>- ignored carrot-ignored/ananas.md: matched ignore glob "carrot-ignored/*" +>- ignored carrot-ignored/tomato.md: matched ignore glob "carrot-ignored/*" +>- ignored orange.markdown: expected extension "md" +> +>Indexed 3 notes in 0s +> + 0 added +> ~ 0 modified +> - 0 removed + +# Verbose and quiet can't be used together. +1$ zk index --verbose --quiet +2>zk: error: --verbose and --quiet can't be used together + diff --git a/tests/cmd-init-defaults.tesh b/tests/cmd-init-defaults.tesh new file mode 100644 index 0000000..5469082 --- /dev/null +++ b/tests/cmd-init-defaults.tesh @@ -0,0 +1,208 @@ +$ zk init --no-input > /dev/null + +# Test default config. +$ cat .zk/config.toml +># zk configuration file +># +># Uncomment the properties you want to customize. +> +># NOTE SETTINGS +># +># Defines the default options used when generating new notes. +>[note] +> +># Language used when writing notes. +># This is used to generate slugs or with date formats. +>#language = "en" +> +># The default title used for new note, if no `--title` flag is provided. +>#default-title = "Untitled" +> +># Template used to generate a note's filename, without extension. +>#filename = "\{{id}}" +> +># The file extension used for the notes. +>#extension = "md" +> +># Template used to generate a note's content. +># If not an absolute path, it is relative to .zk/templates/ +>template = "default.md" +> +># Path globs ignored while indexing existing notes. +>#ignore = [ +># "drafts/*", +># "log.md" +>#] +> +># Configure random ID generation. +> +># The charset used for random IDs. You can use: +># * letters: only letters from a to z. +># * numbers: 0 to 9 +># * alphanum: letters + numbers +># * hex: hexadecimal, from a to f and 0 to 9 +># * custom string: will use any character from the provided value +>#id-charset = "alphanum" +> +># Length of the generated IDs. +>#id-length = 4 +> +># Letter case for the random IDs, among lower, upper or mixed. +>#id-case = "lower" +> +> +># EXTRA VARIABLES +># +># A dictionary of variables you can use for any custom values when generating +># new notes. They are accessible in templates with \{{extra.}} +>[extra] +> +>#key = "value" +> +> +># GROUP OVERRIDES +># +># You can override global settings from [note] and [extra] for a particular +># group of notes by declaring a [group.""] section. +># +># Specify the list of directories which will automatically belong to the group +># with the optional `paths` property. +># +># Omitting `paths` is equivalent to providing a single path equal to the name of +># the group. This can be useful to quickly declare a group by the name of the +># directory it applies to. +> +>#[group.""] +>#paths = ["", ""] +>#[group."".note] +>#filename = "\{{date now}}" +>#[group."".extra] +>#key = "value" +> +> +># MARKDOWN SETTINGS +>[format.markdown] +> +># Format used to generate links between notes. +># Either "wiki", "markdown" or a custom template. Default is "markdown". +>link-format = "wiki" +># Indicates whether a link's path will be percent-encoded. +># Defaults to true for "markdown" format and false for "wiki" format. +>#link-encode-path = true +># Indicates whether a link's path file extension will be removed. +># Defaults to true. +>#link-drop-extension = true +> +># Enable support for #hashtags. +>hashtags = true +># Enable support for :colon:separated:tags:. +>colon-tags = false +># Enable support for Bear's #multi-word tags# +># Hashtags must be enabled for multi-word tags to work. +>multiword-tags = false +> +> +># EXTERNAL TOOLS +>[tool] +> +># Default editor used to open notes. When not set, the EDITOR or VISUAL +># environment variables are used. +>#editor = "vim" +> +># Pager used to scroll through long output. If you want to disable paging +># altogether, set it to an empty string "". +>#pager = "less -FIRX" +> +># Command used to preview a note during interactive fzf mode. +># Set it to an empty string "" to disable preview. +> +># bat is a great tool to render Markdown document with syntax highlighting. +>#https://github.com/sharkdp/bat +>#fzf-preview = "bat -p --color always {-1}" +> +> +># LSP +># +># Configure basic editor integration for LSP-compatible editors. +># See https://github.com/mickael-menu/zk/blob/main/docs/editors-integration.md +># +>[lsp] +> +>[lsp.diagnostics] +># Each diagnostic can have for value: none, hint, info, warning, error +> +># Report titles of wiki-links as hints. +>#wiki-title = "hint" +># Warn for dead links between notes. +>dead-link = "error" +> +>[lsp.completion] +># Customize the completion pop-up of your LSP client. +> +># Show the note title in the completion pop-up, or fallback on its path if empty. +>#note-label = "" +># Filter out the completion pop-up using the note title or its path. +>#note-filter-text = " " +># Show the note filename without extension as detail. +>#note-detail = "" +> +> +># NAMED FILTERS +># +># A named filter is a set of note filtering options used frequently together. +># +>[filter] +> +># Matches the notes created the last two weeks. For example: +># $ zk list recents --limit 15 +># $ zk edit recents --interactive +>#recents = "--sort created- --created-after 'last two weeks'" +> +> +># COMMAND ALIASES +># +># Aliases are user commands called with `zk [] []`. +># +># The alias will be executed with `$SHELL -c`, please refer to your shell's +># man page to see the available syntax. In most shells: +># * $@ can be used to expand all the provided flags and arguments +># * you can pipe commands together with the usual | character +># +>[alias] +># Here are a few aliases to get you started. +> +># Shortcut to a command. +>#ls = "zk list $@" +> +># Default flags for an existing command. +>#list = "zk list --quiet $@" +> +># Edit the last modified note. +>#editlast = "zk edit --limit 1 --sort modified- $@" +> +># Edit the notes selected interactively among the notes created the last two weeks. +># This alias doesn't take any argument, so we don't use $@. +>#recent = "zk edit --sort created- --created-after 'last two weeks' --interactive" +> +># Print paths separated with colons for the notes found with the given +># arguments. This can be useful to expand a complex search query into a flag +># taking only paths. For example: +># zk list --link-to "`zk path -m potatoe`" +>#path = "zk list --quiet --format \{{path}} --delimiter , $@" +> +># Show a random note. +>#lucky = "zk list --quiet --format full --sort random --limit 1" +> +># Returns the Git history for the notes found with the given arguments. +># Note the use of a pipe and the location of $@. +>#hist = "zk list --format path --delimiter0 --quiet $@ | xargs -t -0 git log --patch --" +> +># Edit this configuration file. +>#conf = '$EDITOR "$ZK_NOTEBOOK_DIR/.zk/config.toml"' + +# Test default template. +$ cat .zk/templates/default.md +># \{{title}} +> +>\{{content}} + diff --git a/tests/cmd-init.tesh b/tests/cmd-init.tesh new file mode 100644 index 0000000..c543cdc --- /dev/null +++ b/tests/cmd-init.tesh @@ -0,0 +1,42 @@ +# Print help for `zk init` +$ zk init --help +>Usage: zk init [] +> +>Create a new notebook in the given directory. +> +>Arguments: +> [] Directory containing the notebook. +> +>Flags: +> -h, --help Show context-sensitive help. +> --notebook-dir=PATH Turn off notebook auto-discovery and set manually +> the notebook where commands are run. +> -W, --working-dir=PATH Run as if zk was started in instead of the +> current working directory. +> --no-input Never prompt or ask for confirmation. + +# Creates a new notebook in a new directory. +$ zk init --no-input new-dir +> +>Initialized a notebook in {{working-dir}}/new-dir + +$ test -f new-dir/.zk/config.toml + +# Creates a new notebook in an existing directory. +$ mkdir existing-dir + +$ zk init --no-input existing-dir +> +>Initialized a notebook in {{working-dir}}/existing-dir + +$ test -f existing-dir/.zk/config.toml + +# Creates a new notebook in the current directory. +$ mkdir cur-dir && cd cur-dir + +$ zk init --no-input +> +>Initialized a notebook in {{working-dir}} + +$ test -f .zk/config.toml + diff --git a/tests/cmd-list-filter-date.tesh b/tests/cmd-list-filter-date.tesh new file mode 100644 index 0000000..9661402 --- /dev/null +++ b/tests/cmd-list-filter-date.tesh @@ -0,0 +1,98 @@ +$ cd full-sample + +# List a note created on a given day. +$ zk list -qf\{{title}} --created 2011-05-16T09:58:57Z +>When to prefer PUT over POST HTTP method? + +# List notes created today. +$ zk list -qf\{{title}} --created today +>Buy low, sell high +>Channel +>Compound interests make you rich +>Concurrency in Rust +>Dangling pointers +>Data race error +>Diversify your portfolio +>Do not communicate by sharing memory; instead, share memory by communicating +>Don't speculate +>Errors should be handled differently in an application versus a library +>Fearless concurrency +>Financial markets are random +>Green threads +>How to choose a broker? +>Investment business is a scam +>Message passing +>Mutex +>Null references: the billion dollar mistake +>Ownership in Rust +>Stick to your portfolio strategy +>Strings are a complicated data structure +>The Stack and the Heap +>The borrow checker +>Use small Hashable items with diffable data sources +>Zero-cost abstractions in Rust +>§How to invest in the stock markets? + +# List notes created before a given date. +$ zk list -qf\{{title}} --created-before "2 weeks ago" +>When to prefer PUT over POST HTTP method? + +# List notes created after a given date. +$ zk list -qf\{{title}} --created-after "2 weeks ago" +>Buy low, sell high +>Channel +>Compound interests make you rich +>Concurrency in Rust +>Dangling pointers +>Data race error +>Diversify your portfolio +>Do not communicate by sharing memory; instead, share memory by communicating +>Don't speculate +>Errors should be handled differently in an application versus a library +>Fearless concurrency +>Financial markets are random +>Green threads +>How to choose a broker? +>Investment business is a scam +>Message passing +>Mutex +>Null references: the billion dollar mistake +>Ownership in Rust +>Stick to your portfolio strategy +>Strings are a complicated data structure +>The Stack and the Heap +>The borrow checker +>Use small Hashable items with diffable data sources +>Zero-cost abstractions in Rust +>§How to invest in the stock markets? + +# List notes modified today. +$ zk list -qf\{{title}} --modified today +>Buy low, sell high +>Channel +>Compound interests make you rich +>Concurrency in Rust +>Dangling pointers +>Data race error +>Diversify your portfolio +>Do not communicate by sharing memory; instead, share memory by communicating +>Don't speculate +>Errors should be handled differently in an application versus a library +>Fearless concurrency +>Financial markets are random +>Green threads +>How to choose a broker? +>Investment business is a scam +>Message passing +>Mutex +>Null references: the billion dollar mistake +>Ownership in Rust +>Stick to your portfolio strategy +>Strings are a complicated data structure +>The Stack and the Heap +>The borrow checker +>Use small Hashable items with diffable data sources +>When to prefer PUT over POST HTTP method? +>Zero-cost abstractions in Rust +>§How to invest in the stock markets? + diff --git a/tests/cmd-list-filter-link.tesh b/tests/cmd-list-filter-link.tesh new file mode 100644 index 0000000..cce4c6a --- /dev/null +++ b/tests/cmd-list-filter-link.tesh @@ -0,0 +1,152 @@ +$ cd full-sample + +# Find notes linking to "Message passing". +$ zk list --debug-style -q --link-to 4oma.md +>Channel fwsj.md (just now) +> +> - It's an implementation of the [message passing](4oma) pattern. +> +>Concurrency in Rust g7qa.md (just now) +> +> - [Channel](fwsj) for a safe [message passing](4oma) approach. +> + +# Follow backlinks of "Message passing" recursively. +# FIXME: The snippets don't seem right. +$ zk list --debug-style -q --link-to 4oma.md --recursive +>Channel fwsj.md (just now) +> +> - It's an implementation of the [message passing](4oma) pattern. +> +>Concurrency in Rust g7qa.md (just now) +> +> - It's an implementation of the [message passing](4oma) pattern. +> - [Channel](fwsj) for a safe [message passing](4oma) approach. +> +>Mutex inbox/er4k.md (just now) +> +> - It's an implementation of the [message passing](4oma) pattern. +> + +# Follow backlinks of "Message passing" recursively, limiting to 1 level of indirection. +$ zk list --debug-style -q --link-to 4oma.md --recursive --max-distance 1 +>Channel fwsj.md (just now) +> +> - It's an implementation of the [message passing](4oma) pattern. +> +>Concurrency in Rust g7qa.md (just now) +> +> - [Channel](fwsj) for a safe [message passing](4oma) approach. +> + +# Find notes linked by "Mutex". +# The snippet is an extract from the Mutex note. +$ zk list --debug-style -q --linked-by inbox/er4k.m +>Channel fwsj.md (just now) +> +> - Managing mutexes is tricky, using [channels](../fwsj) is an easier alternative. +> +>Ownership in Rust 88el.md (just now) +> +> - Thanks to its [Ownership](../88el) pattern, Rust makes sure we can't mess up when using locks. +> + +# Find notes linked by "Mutex" recursively. +$ zk list --debug-style -q --linked-by inbox/er4k.m --recursive +>Channel fwsj.md (just now) +> +> - Managing mutexes is tricky, using [channels](../fwsj) is an easier alternative. +> +>Ownership in Rust 88el.md (just now) +> +> - Thanks to its [Ownership](../88el) pattern, Rust makes sure we can't mess up when using locks. +> +>Message passing 4oma.md (just now) +> +> - It's an implementation of the [message passing](4oma) pattern. +> +>The Stack and the Heap tdrj.md (just now) +> +> - The Ownership is a method to manage data on the Heap ([The Stack and the Heap](tdrj)). +> +>Do not communicate by sharing memory; instead, share memory by communicating ref/7fto.md (just now) +> +> - The Go language is advocating for this approach with their slogan: "[Do not communicate by sharing memory; instead, share memory by communicating](ref/7fto)". +> + +# Find notes linked by "Mutex" recursively, limiting to 2 levels. +$ zk list --debug-style -q --linked-by inbox/er4k.m --recursive --max-distance 2 +>Channel fwsj.md (just now) +> +> - Managing mutexes is tricky, using [channels](../fwsj) is an easier alternative. +> +>Ownership in Rust 88el.md (just now) +> +> - Thanks to its [Ownership](../88el) pattern, Rust makes sure we can't mess up when using locks. +> +>Message passing 4oma.md (just now) +> +> - It's an implementation of the [message passing](4oma) pattern. +> +>The Stack and the Heap tdrj.md (just now) +> +> - The Ownership is a method to manage data on the Heap ([The Stack and the Heap](tdrj)). +> + +# Find notes not linking to "Channel". +$ zk list -qf\{{title}} --no-link-to fwsj.md +>Buy low, sell high +>Channel +>Compound interests make you rich +>Dangling pointers +>Data race error +>Diversify your portfolio +>Do not communicate by sharing memory; instead, share memory by communicating +>Don't speculate +>Errors should be handled differently in an application versus a library +>Fearless concurrency +>Financial markets are random +>Green threads +>How to choose a broker? +>Investment business is a scam +>Message passing +>Null references: the billion dollar mistake +>Ownership in Rust +>Stick to your portfolio strategy +>Strings are a complicated data structure +>The Stack and the Heap +>The borrow checker +>Use small Hashable items with diffable data sources +>When to prefer PUT over POST HTTP method? +>Zero-cost abstractions in Rust +>§How to invest in the stock markets? + +# Find notes not linked by "Channel". +$ zk list -qf\{{title}} --no-linked-by fwsj.md +>Buy low, sell high +>Channel +>Compound interests make you rich +>Concurrency in Rust +>Dangling pointers +>Data race error +>Diversify your portfolio +>Do not communicate by sharing memory; instead, share memory by communicating +>Don't speculate +>Errors should be handled differently in an application versus a library +>Fearless concurrency +>Financial markets are random +>Green threads +>How to choose a broker? +>Investment business is a scam +>Mutex +>Null references: the billion dollar mistake +>Ownership in Rust +>Stick to your portfolio strategy +>Strings are a complicated data structure +>The Stack and the Heap +>The borrow checker +>Use small Hashable items with diffable data sources +>When to prefer PUT over POST HTTP method? +>Zero-cost abstractions in Rust +>§How to invest in the stock markets? + diff --git a/tests/cmd-list-filter-match.tesh b/tests/cmd-list-filter-match.tesh new file mode 100644 index 0000000..921b89a --- /dev/null +++ b/tests/cmd-list-filter-match.tesh @@ -0,0 +1,126 @@ +$ cd full-sample + +# Search for a multi-word term. +$ zk list -q --debug-style --match '"green thread"' +>Green threads inbox/my59.md (just now) +> +> - …Programming language-provided threads are known as green threads, and languages that use these green threads will execute them in… +> +>Concurrency in Rust g7qa.md (just now) +> +> - …so it doesn't support [green threads](inbox/my59). +> * Crates exist to add support for green threads if needed. +> * Instead, Rust relies… +> + +# Search for two terms (defaults to AND). +$ zk list -q --debug-style --match 'green channel' +>Concurrency in Rust g7qa.md (just now) +> +> - …runtime, so it doesn't support [green threads](inbox/my59). +> * Crates exist to add support for green threads if needed. +> * Instead, Rust… +> + +# Search for two terms with explicit AND. +$ zk list -q --debug-style --match 'green AND channel' +>Concurrency in Rust g7qa.md (just now) +> +> - …runtime, so it doesn't support [green threads](inbox/my59). +> * Crates exist to add support for green threads if needed. +> * Instead, Rust… +> + +# Search for two terms with OR. +$ zk list -q --debug-style --match 'green OR channel' +>Green threads inbox/my59.md (just now) +> +> - …Programming language-provided threads are known as green threads, and languages that use these green threads will execute them in… +> +>Concurrency in Rust g7qa.md (just now) +> +> - …runtime, so it doesn't support [green threads](inbox/my59). +> * Crates exist to add support for green threads if needed. +> * Instead, Rust… +> +>Channel fwsj.md (just now) +> +> - * Channels are a great approach for safe concurrency. +> * It's an implementation of the [message passing](4oma) pattern. +> +> :programming: +> +>Message passing 4oma.md (just now) +> +> - * A popular approach for safe concurrency is to use *message passing* instead of shared state. +> * Channels are an example of… +> +>Mutex inbox/er4k.md (just now) +> +> - …with a *locking system*. +> * Managing mutexes is tricky, using [channels](../fwsj) is an easier alternative. +> * The main risk is to… +> + +# Exclude a term. +$ zk list -q --debug-style --match 'green -channel' +>Green threads inbox/my59.md (just now) +> +> - …Programming language-provided threads are known as green threads, and languages that use these green threads will execute them in… +> + +# Search in the `title` field. +$ zk list -q --debug-style --match 'title:(green thread)' +>Green threads inbox/my59.md (just now) +> +> - > Many operating systems provide an API for creating new threads. This model where a language calls the operating system APIs… +> + +# Search with a prefix in `title`. +$ zk list -q --debug-style --match 'title:^do*' +>Do not communicate by sharing memory; instead, share memory by communicating ref/7fto.md (just now) +> +> - * Advocates for the use of [message passing](4oma) instead of shared state. +> * A slogan initially coined by Rob Pike ([Effective… +> +>Don't speculate pywo.md (just now) +> +> - You have more to loose by doing market timing (jumping in and out of the stocks market). Remember, [the less… +> + +# Search with a prefix. +$ zk list -q --debug-style --match 'mut*' +>Mutex inbox/er4k.md (just now) +> +> - * Abbreviation of *mutual exclusion*. +> * An approach to manage safely shared state by allowing only a single thread to access a… +> +>Data race error 3403.md (just now) +> +> - …Rust prevents *data races* by allowing only a single mutable reference of a value per scope. +> +> :programming: +> +>Concurrency in Rust g7qa.md (just now) +> +> - …data between threads: +> * [Channel](fwsj) for a safe [message passing](4oma) approach. +> * [Mutex](inbox/er4k) for managing shared state. +> +> :rust:programming: +> + +# Search for an exact match. +$ zk list -q --debug-style --exact-match --match '["न", "म", "स्", "ते"]' +>Strings are a complicated data structure oumc.md (just now) +> +> - Given the Hindi word "नमस्ते": +> + +# Search for an exact match (short flag). +$ zk list -q --debug-style -em '["न", "म", "स्", "ते"]' +>Strings are a complicated data structure oumc.md (just now) +> +> - Given the Hindi word "नमस्ते": +> + diff --git a/tests/cmd-list-filter-mention.tesh b/tests/cmd-list-filter-mention.tesh new file mode 100644 index 0000000..43011a2 --- /dev/null +++ b/tests/cmd-list-filter-mention.tesh @@ -0,0 +1,50 @@ +$ cd full-sample + +# List notes mentioning "Channels" (main title). +$ zk list -q --debug-style --mention fwsj.md +>Message passing 4oma.md (just now) +> +> - * A popular approach for safe concurrency is to use *message passing* instead of shared state. +> * Channels are an example of… +> +>Mutex inbox/er4k.md (just now) +> +> - …with a *locking system*. +> * Managing mutexes is tricky, using [channels](../fwsj) is an easier alternative. +> * The main risk is to… +> +>Concurrency in Rust g7qa.md (just now) +> +> - …a number of constructs for sharing data between threads: +> * [Channel](fwsj) for a safe [message passing](4oma) approach. +> * [Mutex](inbox/er4k… +> + +# List notes mentioning "Dangling pointers" (using alias from the metadata). +$ zk list -q --debug-style --mention 3cut.md +>The borrow checker hkvy.md (just now) +> +> - …to the scope of the owned data to prevent dangling references. It also makes sure that the relationship between *lifetimes… +> + +# List notes mentioned by "Message passing" (using the main title) +$ zk list -q --debug-style --mentioned-by 4oma.md +>Channel fwsj.md (just now) +> +> - * A popular approach for safe concurrency is to use *message passing* instead of shared state. +> * Channels are an example of… +> +>Do not communicate by sharing memory; instead, share memory by communicating ref/7fto.md (just now) +> +> - …advocating for this approach with their slogan: "[Do not communicate by sharing memory; instead, share memory by communicating](ref/7fto)". +> +> :programming: +> + +# List notes mentioned by "The borrow checker" (using alias from the metadata) +$ zk list -q --debug-style --mentioned-by hkvy.md +>Dangling pointers 3cut.md (just now) +> +> - …to the scope of the owned data to prevent dangling references. It also makes sure that the relationship between *lifetimes… +> + diff --git a/tests/cmd-list-filter-orphan.tesh b/tests/cmd-list-filter-orphan.tesh new file mode 100644 index 0000000..d2a1caa --- /dev/null +++ b/tests/cmd-list-filter-orphan.tesh @@ -0,0 +1,16 @@ +$ cd full-sample + +# List notes without any backlinks. +$ zk list -qf"\{{path}} \{{title}}" --orphan +>g7qa.md Concurrency in Rust +>3cut.md Dangling pointers +>3403.md Data race error +>inbox/akwm.md Errors should be handled differently in an application versus a library +>ref/eg7k.md Null references: the billion dollar mistake +>oumc.md Strings are a complicated data structure +>hkvy.md The borrow checker +>wtz9.md Use small Hashable items with diffable data sources +>inbox/dld4.md When to prefer PUT over POST HTTP method? +>zbon.md Zero-cost abstractions in Rust +>18is.md §How to invest in the stock markets? + diff --git a/tests/cmd-list-filter-path.tesh b/tests/cmd-list-filter-path.tesh new file mode 100644 index 0000000..4c8a827 --- /dev/null +++ b/tests/cmd-list-filter-path.tesh @@ -0,0 +1,160 @@ +$ cd full-sample + +# Select several notes. +$ zk list -qfpath g7qa.md inbox/akwm.md 3cut.md +>g7qa.md +>3cut.md +>inbox/akwm.md + +# Select notes with a path prefix `u`. +$ zk list -qfpath u 4oma.md +>uxjt.md +>4oma.md +>uok6.md + +# Select a folder. +$ zk list -qfpath inbox +>inbox/akwm.md +>inbox/my59.md +>inbox/er4k.md +>inbox/dld4.md + +# We must select a folder with its full name, not only a prefix. +$ zk list -fpath inb +2> +2>Found 0 note + +# Exclude several notes. +# Test combination with , or two flags. +$ zk list -qfpath --exclude g7qa.md,inbox/akwm.md --exclude 3cut.md +>uxjt.md +>fwsj.md +>smdc.md +>3403.md +>aqfd.md +>ref/7fto.md +>pywo.md +>2cl7.md +>fa2k.md +>inbox/my59.md +>k9bm.md +>4yib.md +>4oma.md +>inbox/er4k.md +>ref/eg7k.md +>88el.md +>uok6.md +>oumc.md +>tdrj.md +>hkvy.md +>wtz9.md +>inbox/dld4.md +>zbon.md +>18is.md + +# Exclude with short flag. +$ zk list -qfpath -x inbox,ref,1,2,3,4,5,6,7,8,a,b,c,d,e,f +>uxjt.md +>smdc.md +>g7qa.md +>pywo.md +>k9bm.md +>uok6.md +>oumc.md +>tdrj.md +>hkvy.md +>wtz9.md +>zbon.md + +# Exclude is not recursive. +$ zk list -qfpath --exclude . +>ref/7fto.md +>inbox/akwm.md +>inbox/my59.md +>inbox/er4k.md +>ref/eg7k.md +>inbox/dld4.md + +# Exclude notes with a path prefix `u`. +$ zk list -qfpath --exclude u,4oma.md +>fwsj.md +>smdc.md +>g7qa.md +>3cut.md +>3403.md +>aqfd.md +>ref/7fto.md +>pywo.md +>inbox/akwm.md +>2cl7.md +>fa2k.md +>inbox/my59.md +>k9bm.md +>4yib.md +>inbox/er4k.md +>ref/eg7k.md +>88el.md +>oumc.md +>tdrj.md +>hkvy.md +>wtz9.md +>inbox/dld4.md +>zbon.md +>18is.md + +# Exclude a folder. +$ zk list -qfpath --exclude inbox +>uxjt.md +>fwsj.md +>smdc.md +>g7qa.md +>3cut.md +>3403.md +>aqfd.md +>ref/7fto.md +>pywo.md +>2cl7.md +>fa2k.md +>k9bm.md +>4yib.md +>4oma.md +>ref/eg7k.md +>88el.md +>uok6.md +>oumc.md +>tdrj.md +>hkvy.md +>wtz9.md +>zbon.md +>18is.md + +# We must exclude a folder with its full name, not only a prefix. +$ zk list -qfpath --exclude inb +>uxjt.md +>fwsj.md +>smdc.md +>g7qa.md +>3cut.md +>3403.md +>aqfd.md +>ref/7fto.md +>pywo.md +>inbox/akwm.md +>2cl7.md +>fa2k.md +>inbox/my59.md +>k9bm.md +>4yib.md +>4oma.md +>inbox/er4k.md +>ref/eg7k.md +>88el.md +>uok6.md +>oumc.md +>tdrj.md +>hkvy.md +>wtz9.md +>inbox/dld4.md +>zbon.md +>18is.md + diff --git a/tests/cmd-list-filter-related.tesh b/tests/cmd-list-filter-related.tesh new file mode 100644 index 0000000..341b2e7 --- /dev/null +++ b/tests/cmd-list-filter-related.tesh @@ -0,0 +1,16 @@ +$ cd full-sample + +# List notes related to "Buy low, sell high" but not linked by it. +$ zk list -qf"\{{title}}" --related uxjt +>Investment business is a scam +>Stick to your portfolio strategy + +# List notes related to "Fearless concurrency" but not linked by it. +$ zk list -qf"\{{title}}" --related 2cl7.md +>The Stack and the Heap + +# List notes related to "Null references" +$ zk list -f"\{{title}}" --related ref/eg7k.md +2> +2>Found 0 note + diff --git a/tests/cmd-list-filter-tag.tesh b/tests/cmd-list-filter-tag.tesh new file mode 100644 index 0000000..54ddc6e --- /dev/null +++ b/tests/cmd-list-filter-tag.tesh @@ -0,0 +1,51 @@ +$ cd full-sample + +# Filter by a tag. +$ zk list -qf\{{title}} --tag programming +>Channel +>Concurrency in Rust +>Dangling pointers +>Data race error +>Do not communicate by sharing memory; instead, share memory by communicating +>Errors should be handled differently in an application versus a library +>Fearless concurrency +>Green threads +>Message passing +>Mutex +>Null references: the billion dollar mistake +>Ownership in Rust +>Strings are a complicated data structure +>The Stack and the Heap +>The borrow checker +>Use small Hashable items with diffable data sources +>When to prefer PUT over POST HTTP method? +>Zero-cost abstractions in Rust + +# Filter with multiple tags. +$ zk list -qf\{{title}} --tag programming,rust +>Concurrency in Rust +>Ownership in Rust +>The borrow checker +>Zero-cost abstractions in Rust + +# Filter with any of the given tags. +$ zk list -qf\{{title}} --tag "swift OR http" +>Use small Hashable items with diffable data sources +>When to prefer PUT over POST HTTP method? + +# Exclude notes with the given tags. +$ zk list -qf\{{title}} --tag "NOT programming" +>Buy low, sell high +>Compound interests make you rich +>Diversify your portfolio +>Don't speculate +>Financial markets are random +>How to choose a broker? +>Investment business is a scam +>Stick to your portfolio strategy +>§How to invest in the stock markets? + +# Filter by a tag prefix. +$ zk list -qf\{{title}} --tag "sw*" +>Use small Hashable items with diffable data sources + diff --git a/tests/cmd-list-format-custom.tesh b/tests/cmd-list-format-custom.tesh new file mode 100644 index 0000000..772be0e --- /dev/null +++ b/tests/cmd-list-format-custom.tesh @@ -0,0 +1,74 @@ +$ cd full-sample + +# Test custom format template. + +# JSON output of the template context. +$ zk list -qf "\{{json .}}" inbox/dld4.md +>{"filename":"dld4.md","filenameStem":"dld4","path":"inbox/dld4.md","absPath":"{{working-dir}}/inbox/dld4.md","title":"When to prefer PUT over POST HTTP method?","link":"[When to prefer PUT over POST HTTP method?](inbox/dld4)","lead":"`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.","body":"`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.\n\nA way to see it is:\n\n* `PUT` = SQL `UPDATE`\n* `POST` = SQL `INSERT`","snippets":["`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again."],"rawContent":"---\ndate: 2011-05-16 09:58:57\nkeywords: [programming, http]\ncategory: \"Best practice\"\n---\n\n# When to prefer PUT over POST HTTP method?\n\n`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.\n\nA way to see it is:\n\n* `PUT` = SQL `UPDATE`\n* `POST` = SQL `INSERT`\n","wordCount":66,"tags":["programming","http"],"metadata":{"category":"Best practice","date":"2011-05-16 09:58:57","keywords":["programming","http"]},"created":"2011-05-16T09:58:57Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"8cef4e35473a5ebf29d72b5d0e1bca4471dcf496f4971980840aafe4bf3d2298"} + +# Individual Handlebars template variables. + +$ zk list -qf "\{{filename}}" inbox/dld4.md +>dld4.md + +$ zk list -qf "\{{filename-stem}}" inbox/dld4.md +>dld4 + +$ zk list -qf "\{{path}}" inbox/dld4.md +>inbox/dld4.md + +$ zk list -qf "\{{abs-path}}" inbox/dld4.md +>{{working-dir}}/inbox/dld4.md + +$ zk list -qf "\{{title}}" inbox/dld4.md +>When to prefer PUT over POST HTTP method? + +$ zk list -qf "\{{link}}" inbox/dld4.md +>[When to prefer PUT over POST HTTP method?](inbox/dld4) + +$ zk list -qf "\{{lead}}" inbox/dld4.md +>`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. + +$ zk list -qf "\{{body}}" inbox/dld4.md +>`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. +> +>A way to see it is: +> +>* `PUT` = SQL `UPDATE` +>* `POST` = SQL `INSERT` + +$ zk list -qf "\{{snippets}}" inbox/dld4.md +>`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. + +$ zk list -qf "\{{raw-content}}" inbox/dld4.md +>--- +>date: 2011-05-16 09:58:57 +>keywords: [programming, http] +>category: "Best practice" +>--- +> +># When to prefer PUT over POST HTTP method? +> +>`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. +> +>A way to see it is: +> +>* `PUT` = SQL `UPDATE` +>* `POST` = SQL `INSERT` +> + +$ zk list -qf "\{{word-count}}" inbox/dld4.md +>66 + +$ zk list -qf "\{{json tags}}" inbox/dld4.md +>["programming","http"] + +$ zk list -qf "\{{json metadata}}" inbox/dld4.md +>{"category":"Best practice","date":"2011-05-16 09:58:57","keywords":["programming","http"]} + +$ zk list -qf "\{{created}}" inbox/dld4.md +>2011-05-16 09:58:57 +0000 UTC + +$ zk list -qf "\{{checksum}}" inbox/dld4.md +>8cef4e35473a5ebf29d72b5d0e1bca4471dcf496f4971980840aafe4bf3d2298 + diff --git a/tests/cmd-list-format-predefined.tesh b/tests/cmd-list-format-predefined.tesh new file mode 100644 index 0000000..56f4c08 --- /dev/null +++ b/tests/cmd-list-format-predefined.tesh @@ -0,0 +1,68 @@ +$ cd full-sample + +# The default format is `short`. +$ zk list --debug-style -q inbox/dld4.md +>When to prefer PUT over POST HTTP method? inbox/dld4.md ({{match '[0-9]+'}} years ago) +> +> - `PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. +> + +# `path` format. +$ zk list --debug-style -qfpath inbox/dld4.md +>inbox/dld4.md + +# `link` format. +$ zk list --debug-style -qflink inbox/dld4.md +>[When to prefer PUT over POST HTTP method?](inbox/dld4) + +# `oneline` format. +$ zk list --debug-style -qfoneline inbox/dld4.md +>When to prefer PUT over POST HTTP method? inbox/dld4.md ({{match '[0-9]+'}} years ago) + +# `short` format. +$ zk list --debug-style -qfshort inbox/dld4.md +>When to prefer PUT over POST HTTP method? inbox/dld4.md ({{match '[0-9]+'}} years ago) +> +> - `PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. +> + +# `medium` format. +$ zk list --debug-style -qfmedium inbox/dld4.md +>When to prefer PUT over POST HTTP method? inbox/dld4.md +>Created: 05/16/2011 +> +> - `PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. +> + +# `long` format. +$ zk list --debug-style -qflong inbox/dld4.md +>When to prefer PUT over POST HTTP method? inbox/dld4.md +>Created: 05/16/2011 +>Modified: {{match '[/0-9]+'}} +> +> - `PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. +> + +# `full` format. +$ zk list --debug-style -qffull inbox/dld4.md +>When to prefer PUT over POST HTTP method? inbox/dld4.md +>Created: 05/16/2011 +>Modified: {{match '[/0-9]+'}} +>Tags: programming, http +> +> `PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. +> +> A way to see it is: +> +> * `PUT` = SQL `UPDATE` +> * `POST` = SQL `INSERT` +> + +# JSON format. +$ zk list -qfjson inbox/dld4.md +>[{"filename":"dld4.md","filenameStem":"dld4","path":"inbox/dld4.md","absPath":"{{working-dir}}/inbox/dld4.md","title":"When to prefer PUT over POST HTTP method?","link":"[When to prefer PUT over POST HTTP method?](inbox/dld4)","lead":"`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.","body":"`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.\n\nA way to see it is:\n\n* `PUT` = SQL `UPDATE`\n* `POST` = SQL `INSERT`","snippets":["`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again."],"rawContent":"---\ndate: 2011-05-16 09:58:57\nkeywords: [programming, http]\ncategory: \"Best practice\"\n---\n\n# When to prefer PUT over POST HTTP method?\n\n`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.\n\nA way to see it is:\n\n* `PUT` = SQL `UPDATE`\n* `POST` = SQL `INSERT`\n","wordCount":66,"tags":["programming","http"],"metadata":{"category":"Best practice","date":"2011-05-16 09:58:57","keywords":["programming","http"]},"created":"2011-05-16T09:58:57Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"8cef4e35473a5ebf29d72b5d0e1bca4471dcf496f4971980840aafe4bf3d2298"}] + +# JSON Lines format. +$ zk list -qfjsonl inbox/dld4.md +>{"filename":"dld4.md","filenameStem":"dld4","path":"inbox/dld4.md","absPath":"{{working-dir}}/inbox/dld4.md","title":"When to prefer PUT over POST HTTP method?","link":"[When to prefer PUT over POST HTTP method?](inbox/dld4)","lead":"`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.","body":"`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.\n\nA way to see it is:\n\n* `PUT` = SQL `UPDATE`\n* `POST` = SQL `INSERT`","snippets":["`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again."],"rawContent":"---\ndate: 2011-05-16 09:58:57\nkeywords: [programming, http]\ncategory: \"Best practice\"\n---\n\n# When to prefer PUT over POST HTTP method?\n\n`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again.\n\nA way to see it is:\n\n* `PUT` = SQL `UPDATE`\n* `POST` = SQL `INSERT`\n","wordCount":66,"tags":["programming","http"],"metadata":{"category":"Best practice","date":"2011-05-16 09:58:57","keywords":["programming","http"]},"created":"2011-05-16T09:58:57Z","modified":"{{match '[\-T\.\:0-9]+'}}Z","checksum":"8cef4e35473a5ebf29d72b5d0e1bca4471dcf496f4971980840aafe4bf3d2298"} + diff --git a/tests/cmd-list-format.tesh b/tests/cmd-list-format.tesh new file mode 100644 index 0000000..e784284 --- /dev/null +++ b/tests/cmd-list-format.tesh @@ -0,0 +1,60 @@ +$ cd full-sample + +# Header. +$ zk list -n4 -qfpath --header "HEADER" +>HEADERuxjt.md +>fwsj.md +>smdc.md +>g7qa.md + +# Footer. +$ zk list -n4 -qfpath --footer "FOOTER\n" +>uxjt.md +>fwsj.md +>smdc.md +>g7qa.mdFOOTER + +# Delimiter. +$ zk list -n4 -qfpath --delimiter ";" +>uxjt.md;fwsj.md;smdc.md;g7qa.md + +# Delimiter (short flag). +$ zk list -n4 -qfpath -d, +>uxjt.md,fwsj.md,smdc.md,g7qa.md + +# Can't mix --delimiter0 and --delimiter +1$ zk list --delimiter0 --delimiter "," +2>zk: error: --delimiter and --delimiter0 can't be used together + +# Can't mix --delimiter0 and --header +1$ zk list --delimiter0 --header "-" +2>zk: error: --footer and --delimiter0 can't be used together + +# Can't mix --delimiter0 and --footer +1$ zk list --delimiter0 --footer "-" +2>zk: error: --footer and --delimiter0 can't be used together + +# Can't mix --format json and --header +1$ zk list --format json --header "-" +2>zk: error: --header can't be used with JSON format + +# Can't mix --format json and --footer +1$ zk list --format json --footer "-" +2>zk: error: --footer can't be used with JSON format + +# Can't mix --format json and --delimiter +1$ zk list --format json --delimiter "-" +2>zk: error: --delimiter can't be used with JSON format + +# Can't mix --format jsonl and --header +1$ zk list --format jsonl --header "-" +2>zk: error: --header can't be used with JSON format + +# Can't mix --format jsonl and --footer +1$ zk list --format jsonl --footer "-" +2>zk: error: --footer can't be used with JSON format + +# Can't mix --format jsonl and --delimiter +1$ zk list --format jsonl --delimiter "-" +2>zk: error: --delimiter can't be used with JSON format + diff --git a/tests/cmd-list-limit.tesh b/tests/cmd-list-limit.tesh new file mode 100644 index 0000000..087a3a4 --- /dev/null +++ b/tests/cmd-list-limit.tesh @@ -0,0 +1,90 @@ +$ cd full-sample + +# No limit. +$ zk list -fpath +>uxjt.md +>fwsj.md +>smdc.md +>g7qa.md +>3cut.md +>3403.md +>aqfd.md +>ref/7fto.md +>pywo.md +>inbox/akwm.md +>2cl7.md +>fa2k.md +>inbox/my59.md +>k9bm.md +>4yib.md +>4oma.md +>inbox/er4k.md +>ref/eg7k.md +>88el.md +>uok6.md +>oumc.md +>tdrj.md +>hkvy.md +>wtz9.md +>inbox/dld4.md +>zbon.md +>18is.md +2> +2>Found 27 notes + +# Limit. +$ zk list -fpath --limit 5 +>uxjt.md +>fwsj.md +>smdc.md +>g7qa.md +>3cut.md +2> +2>Found 5 notes + +# Limit with short flag. +$ zk list -fpath -n5 +>uxjt.md +>fwsj.md +>smdc.md +>g7qa.md +>3cut.md +2> +2>Found 5 notes + +# Invalid limit. +1$ zk list -fpath --limit a +2>zk: error: --limit: expected a valid 64 bit int but got "a" + +# Limit to 0 means no limit. +$ zk list -fpath --limit 0 +>uxjt.md +>fwsj.md +>smdc.md +>g7qa.md +>3cut.md +>3403.md +>aqfd.md +>ref/7fto.md +>pywo.md +>inbox/akwm.md +>2cl7.md +>fa2k.md +>inbox/my59.md +>k9bm.md +>4yib.md +>4oma.md +>inbox/er4k.md +>ref/eg7k.md +>88el.md +>uok6.md +>oumc.md +>tdrj.md +>hkvy.md +>wtz9.md +>inbox/dld4.md +>zbon.md +>18is.md +2> +2>Found 27 notes + diff --git a/tests/cmd-list-sort.tesh b/tests/cmd-list-sort.tesh new file mode 100644 index 0000000..b403352 --- /dev/null +++ b/tests/cmd-list-sort.tesh @@ -0,0 +1,252 @@ +$ cd full-sample + +# The default sort order is by title. +$ zk list -qf\{{title}} --sort title +>Buy low, sell high +>Channel +>Compound interests make you rich +>Concurrency in Rust +>Dangling pointers +>Data race error +>Diversify your portfolio +>Do not communicate by sharing memory; instead, share memory by communicating +>Don't speculate +>Errors should be handled differently in an application versus a library +>Fearless concurrency +>Financial markets are random +>Green threads +>How to choose a broker? +>Investment business is a scam +>Message passing +>Mutex +>Null references: the billion dollar mistake +>Ownership in Rust +>Stick to your portfolio strategy +>Strings are a complicated data structure +>The Stack and the Heap +>The borrow checker +>Use small Hashable items with diffable data sources +>When to prefer PUT over POST HTTP method? +>Zero-cost abstractions in Rust +>§How to invest in the stock markets? + +# Sort by unknown order. +1$ zk list -q --sort unknown +2>zk: error: incorrect criteria: unknown: unknown sorting term +2> try created, modified, path, title, random or word-count + +# Sort by title (default ascending). +$ zk list -qf\{{title}} --sort title +>Buy low, sell high +>Channel +>Compound interests make you rich +>Concurrency in Rust +>Dangling pointers +>Data race error +>Diversify your portfolio +>Do not communicate by sharing memory; instead, share memory by communicating +>Don't speculate +>Errors should be handled differently in an application versus a library +>Fearless concurrency +>Financial markets are random +>Green threads +>How to choose a broker? +>Investment business is a scam +>Message passing +>Mutex +>Null references: the billion dollar mistake +>Ownership in Rust +>Stick to your portfolio strategy +>Strings are a complicated data structure +>The Stack and the Heap +>The borrow checker +>Use small Hashable items with diffable data sources +>When to prefer PUT over POST HTTP method? +>Zero-cost abstractions in Rust +>§How to invest in the stock markets? + +# Sort by title (shortcut). +$ zk list -qf\{{title}} -st -n4 +>Buy low, sell high +>Channel +>Compound interests make you rich +>Concurrency in Rust + +# Sort by title descending. +$ zk list -qf\{{title}} --sort title- +>§How to invest in the stock markets? +>Zero-cost abstractions in Rust +>When to prefer PUT over POST HTTP method? +>Use small Hashable items with diffable data sources +>The borrow checker +>The Stack and the Heap +>Strings are a complicated data structure +>Stick to your portfolio strategy +>Ownership in Rust +>Null references: the billion dollar mistake +>Mutex +>Message passing +>Investment business is a scam +>How to choose a broker? +>Green threads +>Financial markets are random +>Fearless concurrency +>Errors should be handled differently in an application versus a library +>Don't speculate +>Do not communicate by sharing memory; instead, share memory by communicating +>Diversify your portfolio +>Data race error +>Dangling pointers +>Concurrency in Rust +>Compound interests make you rich +>Channel +>Buy low, sell high + +# Sort by path (default ascending). +$ zk list -qfpath -n4 --sort path +>18is.md +>2cl7.md +>3403.md +>3cut.md + +# Sort by path (shortcut). +$ zk list -qfpath -n4 -sp +>18is.md +>2cl7.md +>3403.md +>3cut.md + +# Sort by path descending. +$ zk list -qfpath -n4 --sort path- +>zbon.md +>wtz9.md +>uxjt.md +>uok6.md + +# Sort by word count (default ascending). +$ zk list -qf"\{{word-count}} \{{title}}" -n4 --sort word-count +>21 Channel +>37 Do not communicate by sharing memory; instead, share memory by communicating +>37 Ownership in Rust +>44 Fearless concurrency + +# Sort by word count (shortcut). +$ zk list -qf"\{{word-count}} \{{title}}" -n4 -swc +>21 Channel +>37 Do not communicate by sharing memory; instead, share memory by communicating +>37 Ownership in Rust +>44 Fearless concurrency + +# Sort by word count descending. +$ zk list -qf"\{{word-count}} \{{title}}" -n4 --sort word-count- +>196 The Stack and the Heap +>124 Green threads +>120 Stick to your portfolio strategy +>116 Compound interests make you rich + +# Sort by creation date (default descending). +$ zk list -qf\{{title}} -n4 --sort created +>Zero-cost abstractions in Rust +>Use small Hashable items with diffable data sources +>Buy low, sell high +>Stick to your portfolio strategy + +# Sort by creation date (shortcut). +$ zk list -qf\{{title}} -n4 -sc +>Zero-cost abstractions in Rust +>Use small Hashable items with diffable data sources +>Buy low, sell high +>Stick to your portfolio strategy + +# Sort by creation date ascending. +$ zk list -qf\{{title}} -n4 --sort created+ +>When to prefer PUT over POST HTTP method? +>§How to invest in the stock markets? +>Fearless concurrency +>Data race error + +# Sort by modification date (default descending). +$ zk list -qf\{{title}} -n4 --sort modified +>Zero-cost abstractions in Rust +>Use small Hashable items with diffable data sources +>Buy low, sell high +>Stick to your portfolio strategy + +# Sort by modification date (shortcut). +$ zk list -qf\{{title}} -n4 -sm +>Zero-cost abstractions in Rust +>Use small Hashable items with diffable data sources +>Buy low, sell high +>Stick to your portfolio strategy + +# Sort by modification date ascending. +$ zk list -qf\{{title}} -n4 --sort modified+ +>§How to invest in the stock markets? +>Fearless concurrency +>Data race error +>Dangling pointers + +# Sort by random order. +# For practical purpose, checks only that the command doesn't error out. +$ zk list -q --sort random > /dev/null + +# Sort by multiple orders. +$ zk list -qf"\{{word-count}} \{{title}}" --sort title-,word-count +>21 Channel +>37 Ownership in Rust +>37 Do not communicate by sharing memory; instead, share memory by communicating +>44 Financial markets are random +>44 Fearless concurrency +>49 Use small Hashable items with diffable data sources +>50 Dangling pointers +>53 Message passing +>60 Zero-cost abstractions in Rust +>66 When to prefer PUT over POST HTTP method? +>67 Errors should be handled differently in an application versus a library +>71 §How to invest in the stock markets? +>76 Mutex +>80 The borrow checker +>80 Data race error +>81 Concurrency in Rust +>95 Strings are a complicated data structure +>98 How to choose a broker? +>98 Diversify your portfolio +>103 Buy low, sell high +>106 Investment business is a scam +>107 Don't speculate +>109 Null references: the billion dollar mistake +>116 Compound interests make you rich +>120 Stick to your portfolio strategy +>124 Green threads +>196 The Stack and the Heap + +# Sort by multiple orders (shortcut) +$ zk list -qf"\{{word-count}} \{{title}}" -st-,wc +>21 Channel +>37 Ownership in Rust +>37 Do not communicate by sharing memory; instead, share memory by communicating +>44 Financial markets are random +>44 Fearless concurrency +>49 Use small Hashable items with diffable data sources +>50 Dangling pointers +>53 Message passing +>60 Zero-cost abstractions in Rust +>66 When to prefer PUT over POST HTTP method? +>67 Errors should be handled differently in an application versus a library +>71 §How to invest in the stock markets? +>76 Mutex +>80 The borrow checker +>80 Data race error +>81 Concurrency in Rust +>95 Strings are a complicated data structure +>98 How to choose a broker? +>98 Diversify your portfolio +>103 Buy low, sell high +>106 Investment business is a scam +>107 Don't speculate +>109 Null references: the billion dollar mistake +>116 Compound interests make you rich +>120 Stick to your portfolio strategy +>124 Green threads +>196 The Stack and the Heap + diff --git a/tests/cmd-list.tesh b/tests/cmd-list.tesh new file mode 100644 index 0000000..e71b6f3 --- /dev/null +++ b/tests/cmd-list.tesh @@ -0,0 +1,96 @@ +$ cd full-sample + +# Print help for `zk list` +$ zk list --help +>Usage: zk list [ ...] +> +>List notes matching the given criteria. +> +>Arguments: +> [ ...] Find notes matching the given path, including its descendants. +> +>Flags: +> -h, --help Show context-sensitive help. +> --notebook-dir=PATH Turn off notebook auto-discovery and set manually +> the notebook where commands are run. +> -W, --working-dir=PATH Run as if zk was started in instead of the +> current working directory. +> --no-input Never prompt or ask for confirmation. +> +>Formatting +> -f, --format=TEMPLATE Pretty print the list using a custom template or one +> of the predefined formats: oneline, short, medium, +> long, full, json, jsonl. +> --header=STRING Arbitrary text printed at the start of the list. +> --footer="\\n" Arbitrary text printed at the end of the list. +> -d, --delimiter="\n" Print notes delimited by the given separator. +> -0, --delimiter0 Print notes delimited by ASCII NUL characters. This +> is useful when used in conjunction with `xargs -0`. +> -P, --no-pager Do not pipe output into a pager. +> -q, --quiet Do not print the total number of notes found. +> +>Filtering +> -i, --interactive Select notes interactively with fzf. +> -n, --limit=COUNT Limit the number of notes found. +> -m, --match=QUERY Terms to search for in the notes. +> -e, --exact-match Search for exact occurrences of the --match +> argument (case insensitive). +> -x, --exclude=PATH,... Ignore notes matching the given path, including +> its descendants. +> -t, --tag=TAG,... Find notes tagged with the given tags. +> --mention=PATH,... Find notes mentioning the title of the given +> ones. +> --mentioned-by=PATH,... Find notes whose title is mentioned in the +> given ones. +> -l, --link-to=PATH,... Find notes which are linking to the given ones. +> --no-link-to=PATH,... Find notes which are not linking to the given +> notes. +> -L, --linked-by=PATH,... Find notes which are linked by the given ones. +> --no-linked-by=PATH,... Find notes which are not linked by the given +> ones. +> --orphan Find notes which are not linked by any other +> note. +> --related=PATH,... Find notes which might be related to the given +> ones. +> --max-distance=COUNT Maximum distance between two linked notes. +> -r, --recursive Follow links recursively. +> --created=DATE +> --created-before=DATE Find notes created before the given date. +> --created-after=DATE Find notes created after the given date. +> --modified=DATE Find notes modified on the given date. +> --modified-before=DATE Find notes modified before the given date. +> --modified-after=DATE Find notes modified after the given date. +> +>Sorting +> -s, --sort=TERM,... Order the notes by the given criterion. + +# List all notes. +$ zk list -qf"\{{path}} \{{title}}" +>uxjt.md Buy low, sell high +>fwsj.md Channel +>smdc.md Compound interests make you rich +>g7qa.md Concurrency in Rust +>3cut.md Dangling pointers +>3403.md Data race error +>aqfd.md Diversify your portfolio +>ref/7fto.md Do not communicate by sharing memory; instead, share memory by communicating +>pywo.md Don't speculate +>inbox/akwm.md Errors should be handled differently in an application versus a library +>2cl7.md Fearless concurrency +>fa2k.md Financial markets are random +>inbox/my59.md Green threads +>k9bm.md How to choose a broker? +>4yib.md Investment business is a scam +>4oma.md Message passing +>inbox/er4k.md Mutex +>ref/eg7k.md Null references: the billion dollar mistake +>88el.md Ownership in Rust +>uok6.md Stick to your portfolio strategy +>oumc.md Strings are a complicated data structure +>tdrj.md The Stack and the Heap +>hkvy.md The borrow checker +>wtz9.md Use small Hashable items with diffable data sources +>inbox/dld4.md When to prefer PUT over POST HTTP method? +>zbon.md Zero-cost abstractions in Rust +>18is.md §How to invest in the stock markets? + diff --git a/tests/cmd-new-template.tesh b/tests/cmd-new-template.tesh new file mode 100644 index 0000000..6d96122 --- /dev/null +++ b/tests/cmd-new-template.tesh @@ -0,0 +1,18 @@ +$ cd new + +$ mkdir "a dir" + +# Test Handlebars template variables. +$ echo "Piped content" | zk new --group handlebars --title "Note title" --date "January 2nd" --dry-run "a dir" +>id: {{match "[a-z0-9]{4}"}} +>title: Note title +>content: Piped content +> +>dir: a dir +>extra: {"key":"value","visibility":"public"} +>now: 02-01 +>env: {{working-dir}} +>filename: note-title.md +>filename-stem: note-title +2>{{working-dir}}/a dir/note-title.md + diff --git a/tests/cmd-new.tesh b/tests/cmd-new.tesh new file mode 100644 index 0000000..c4db404 --- /dev/null +++ b/tests/cmd-new.tesh @@ -0,0 +1,103 @@ +$ cd new + +# Print help for `zk new` +$ zk new --help +>Usage: zk new [] +> +>Create a new note in the given notebook directory. +> +>Arguments: +> [] Directory in which to create the note. +> +>Flags: +> -h, --help Show context-sensitive help. +> --notebook-dir=PATH Turn off notebook auto-discovery and set manually +> the notebook where commands are run. +> -W, --working-dir=PATH Run as if zk was started in instead of the +> current working directory. +> --no-input Never prompt or ask for confirmation. +> +> -t, --title=TITLE Title of the new note. +> --date=DATE Set the current date. +> -g, --group=NAME Name of the config group this note belongs to. +> Takes precedence over the config of the +> directory. +> --extra=KEY=VALUE,... Extra variables passed to the templates. +> --template=PATH Custom template used to render the note. +> -p, --print-path Print the path of the created note instead of +> editing it. +> -n, --dry-run Don't actually create the note. Instead, prints +> its content on stdout and the generated path on +> stderr. + +# Default note title. +$ zk new --print-path +>{{working-dir}}/untitled.md + +$ cat untitled.md +># Untitled +> +> + +# Provide a custom title. +$ zk new --title "Custom title" --print-path +>{{working-dir}}/custom-title.md + +$ cat custom-title.md +># Custom title +> +> + +# Provide a custom title (short flag). +$ zk new -t "Another custom title" -p +>{{working-dir}}/another-custom-title.md + +# Opens the editor after creating a new note. +$ EDITOR="echo 'edit'" zk new --title "Edit" +>edit {{working-dir}}/edit.md + +# Prints the path of newly created note instead of editing it. +$ EDITOR="echo 'edit'" zk new --title "Print path" --print-path +>{{working-dir}}/print-path.md + +# Set explicitely today's date. +$ zk new --group date --date "January 2nd" --dry-run +2>{{working-dir}}/02-01.md +$ zk new --group date --date "December 24th" --dry-run +2>{{working-dir}}/24-12.md + +# Dry run doesn't write the note. +$ zk new --dry-run --title "Dry run" +># Dry run +> +> +2>{{working-dir}}/dry-run.md + +1$ cat dry-run.md +2>cat: dry-run.md: No such file or directory + +# Dry run (short flag). +$ zk new -n --title "Dry run" +># Dry run +> +> +2>{{working-dir}}/dry-run.md + +# Pipe content in a new note. +$ echo "Content of the note" | EDITOR=cat zk new --title "Piped note" +># Piped note +> +>Content of the note +> + +# Existing notes are not overwritten, but can be edited. +$ zk new --force-input n --title "Piped note" +>? piped-note.md already exists, do you want to edit this note instead? (y/N) + +# Check that the content was not overwritten +$ cat piped-note.md +># Piped note +> +>Content of the note +> + diff --git a/tests/cmd-tag-list-format.tesh b/tests/cmd-tag-list-format.tesh new file mode 100644 index 0000000..f1ad0ec --- /dev/null +++ b/tests/cmd-tag-list-format.tesh @@ -0,0 +1,174 @@ +$ cd tags + +# Default format is `full`. +$ zk tag list +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) +2> +2>Found 13 tags + +# Full format (+long flag). +$ zk tag list --format full +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) +2> +2>Found 13 tags + +# Name format. +$ zk tag list -fname +>biography +>biology +>book +>dystopia +>feminism +>fiction +>history +>non-fiction +>philosophy +>physics +>romance +>science +>science-fiction +2> +2>Found 13 tags + +# JSON format. +$ zk tag list -fjson +>[{"id":7,"kind":"tag","name":"biography","noteCount":1},{"id":8,"kind":"tag","name":"biology","noteCount":2},{"id":14,"kind":"tag","name":"book","noteCount":12},{"id":13,"kind":"tag","name":"dystopia","noteCount":2},{"id":9,"kind":"tag","name":"feminism","noteCount":1},{"id":10,"kind":"tag","name":"fiction","noteCount":6},{"id":6,"kind":"tag","name":"history","noteCount":2},{"id":2,"kind":"tag","name":"non-fiction","noteCount":6},{"id":5,"kind":"tag","name":"philosophy","noteCount":3},{"id":3,"kind":"tag","name":"physics","noteCount":1},{"id":11,"kind":"tag","name":"romance","noteCount":3},{"id":1,"kind":"tag","name":"science","noteCount":3},{"id":12,"kind":"tag","name":"science-fiction","noteCount":1}] +2> +2>Found 13 tags + +# JSON Lines format. +$ zk tag list -fjsonl +>{"id":7,"kind":"tag","name":"biography","noteCount":1} +>{"id":8,"kind":"tag","name":"biology","noteCount":2} +>{"id":14,"kind":"tag","name":"book","noteCount":12} +>{"id":13,"kind":"tag","name":"dystopia","noteCount":2} +>{"id":9,"kind":"tag","name":"feminism","noteCount":1} +>{"id":10,"kind":"tag","name":"fiction","noteCount":6} +>{"id":6,"kind":"tag","name":"history","noteCount":2} +>{"id":2,"kind":"tag","name":"non-fiction","noteCount":6} +>{"id":5,"kind":"tag","name":"philosophy","noteCount":3} +>{"id":3,"kind":"tag","name":"physics","noteCount":1} +>{"id":11,"kind":"tag","name":"romance","noteCount":3} +>{"id":1,"kind":"tag","name":"science","noteCount":3} +>{"id":12,"kind":"tag","name":"science-fiction","noteCount":1} +2> +2>Found 13 tags + +# Custom format. +$ zk tag list -f"name: \{{name}}, count: \{{note-count}}, kind: \{{kind}}" +>name: biography, count: 1, kind: tag +>name: biology, count: 2, kind: tag +>name: book, count: 12, kind: tag +>name: dystopia, count: 2, kind: tag +>name: feminism, count: 1, kind: tag +>name: fiction, count: 6, kind: tag +>name: history, count: 2, kind: tag +>name: non-fiction, count: 6, kind: tag +>name: philosophy, count: 3, kind: tag +>name: physics, count: 1, kind: tag +>name: romance, count: 3, kind: tag +>name: science, count: 3, kind: tag +>name: science-fiction, count: 1, kind: tag +2> +2>Found 13 tags + +# Header. +$ zk tag list -qfname --header "HEADER" +>HEADERbiography +>biology +>book +>dystopia +>feminism +>fiction +>history +>non-fiction +>philosophy +>physics +>romance +>science +>science-fiction + +# Footer. +$ zk tag list -qfname --footer "FOOTER\n" +>biography +>biology +>book +>dystopia +>feminism +>fiction +>history +>non-fiction +>philosophy +>physics +>romance +>science +>science-fictionFOOTER + +# Delimiter. +$ zk tag list -qfname --delimiter ";" +>biography;biology;book;dystopia;feminism;fiction;history;non-fiction;philosophy;physics;romance;science;science-fiction + +# Delimiter (short flag). +$ zk tag list -qfname -d, +>biography,biology,book,dystopia,feminism,fiction,history,non-fiction,philosophy,physics,romance,science,science-fiction + +# Can't mix --delimiter0 and --delimiter +1$ zk tag list --delimiter0 --delimiter "," +2>zk: error: --delimiter and --delimiter0 can't be used together + +# Can't mix --delimiter0 and --header +1$ zk tag list --delimiter0 --header "-" +2>zk: error: --footer and --delimiter0 can't be used together + +# Can't mix --delimiter0 and --footer +1$ zk tag list --delimiter0 --footer "-" +2>zk: error: --footer and --delimiter0 can't be used together + +# Can't mix --format json and --header +1$ zk tag list --format json --header "-" +2>zk: error: --header can't be used with JSON format + +# Can't mix --format json and --footer +1$ zk tag list --format json --footer "-" +2>zk: error: --footer can't be used with JSON format + +# Can't mix --format json and --delimiter +1$ zk tag list --format json --delimiter "-" +2>zk: error: --delimiter can't be used with JSON format + +# Can't mix --format jsonl and --header +1$ zk tag list --format jsonl --header "-" +2>zk: error: --header can't be used with JSON format + +# Can't mix --format jsonl and --footer +1$ zk tag list --format jsonl --footer "-" +2>zk: error: --footer can't be used with JSON format + +# Can't mix --format jsonl and --delimiter +1$ zk tag list --format jsonl --delimiter "-" +2>zk: error: --delimiter can't be used with JSON format + diff --git a/tests/cmd-tag-list-sort.tesh b/tests/cmd-tag-list-sort.tesh new file mode 100644 index 0000000..7337698 --- /dev/null +++ b/tests/cmd-tag-list-sort.tesh @@ -0,0 +1,151 @@ +$ cd tags + +# Default sort order is by name. +$ zk tag list +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) +2> +2>Found 13 tags + +# Sort by name ascending (+ long flag). +$ zk tag list --sort name +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) +2> +2>Found 13 tags + +# Sort by name descending. +$ zk tag list -sname- +>science-fiction (1) +>science (3) +>romance (3) +>physics (1) +>philosophy (3) +>non-fiction (6) +>history (2) +>fiction (6) +>feminism (1) +>dystopia (2) +>book (12) +>biology (2) +>biography (1) +2> +2>Found 13 tags + +# Sort by note count ascending. +$ zk tag list -snote-count+ +>biography (1) +>feminism (1) +>physics (1) +>science-fiction (1) +>biology (2) +>dystopia (2) +>history (2) +>philosophy (3) +>romance (3) +>science (3) +>fiction (6) +>non-fiction (6) +>book (12) +2> +2>Found 13 tags + +# Sort by note count descending. +$ zk tag list -snote-count- +>book (12) +>fiction (6) +>non-fiction (6) +>philosophy (3) +>romance (3) +>science (3) +>biology (2) +>dystopia (2) +>history (2) +>biography (1) +>feminism (1) +>physics (1) +>science-fiction (1) +2> +2>Found 13 tags + +# Name shortcut. +$ zk tag list -sn +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) +2> +2>Found 13 tags + +# Note count shortcut. +$ zk tag list -snc +>book (12) +>fiction (6) +>non-fiction (6) +>philosophy (3) +>romance (3) +>science (3) +>biology (2) +>dystopia (2) +>history (2) +>biography (1) +>feminism (1) +>physics (1) +>science-fiction (1) +2> +2>Found 13 tags + +# Sort by several terms. +$ zk tag list -sn-,nc +>book (12) +>non-fiction (6) +>fiction (6) +>science (3) +>romance (3) +>philosophy (3) +>history (2) +>dystopia (2) +>biology (2) +>science-fiction (1) +>physics (1) +>feminism (1) +>biography (1) +2> +2>Found 13 tags + +# Unknown sort order. +1$ zk tag list -sfoobar +2>zk: error: foobar: unknown sorting term +2> try name or note-count + diff --git a/tests/cmd-tag-list.tesh b/tests/cmd-tag-list.tesh new file mode 100644 index 0000000..2a6909f --- /dev/null +++ b/tests/cmd-tag-list.tesh @@ -0,0 +1,116 @@ +$ cd tags + +# Print help for `zk tag list` +$ zk tag list --help +>Usage: zk tag list +> +>List all the note tags. +> +>Flags: +> -h, --help Show context-sensitive help. +> --notebook-dir=PATH Turn off notebook auto-discovery and set manually +> the notebook where commands are run. +> -W, --working-dir=PATH Run as if zk was started in instead of the +> current working directory. +> --no-input Never prompt or ask for confirmation. +> +>Formatting +> -f, --format=TEMPLATE Pretty print the list using a custom template or one +> of the predefined formats: name, full, json, jsonl. +> --header=STRING Arbitrary text printed at the start of the list. +> --footer="\\n" Arbitrary text printed at the end of the list. +> -d, --delimiter="\n" Print tags delimited by the given separator. +> -0, --delimiter0 Print tags delimited by ASCII NUL characters. This is +> useful when used in conjunction with `xargs -0`. +> -P, --no-pager Do not pipe output into a pager. +> -q, --quiet Do not print the total number of tags found. +> +>Sorting +> -s, --sort=TERM,... Order the tags by the given criterion. + +# List all tags. +$ zk tag list +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) +2> +2>Found 13 tags + +# Quiet mode. +$ zk tag list --quiet +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) + +# Quiet mode (short). +$ zk tag list -q +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) + +# Remove some tags. +$ rm the* +$ zk tag list +>book (6) +>dystopia (2) +>fiction (5) +>non-fiction (1) +>physics (1) +>romance (2) +>science (1) +>science-fiction (1) +2> +2>Found 8 tags + +# Add new tags. +$ echo "#tag1 #tag2 #science" > ulysses.md +$ zk tag list +>book (5) +>dystopia (2) +>fiction (4) +>non-fiction (1) +>physics (1) +>romance (2) +>science (2) +>science-fiction (1) +>tag1 (1) +>tag2 (1) +2> +2>Found 10 tags + +# Remove all tags. +$ rm * +$ zk tag list +2> +2>Found 0 tag + diff --git a/tests/cmd-tag.tesh b/tests/cmd-tag.tesh new file mode 100644 index 0000000..4f62c61 --- /dev/null +++ b/tests/cmd-tag.tesh @@ -0,0 +1,37 @@ +$ cd tags + +# Print help for `zk tag`. +$ zk tag --help +>Usage: zk tag +> +>Manage the note tags. +> +>Commands: +> tag list List all the note tags. +> +>Flags: +> -h, --help Show context-sensitive help. +> --notebook-dir=PATH Turn off notebook auto-discovery and set manually +> the notebook where commands are run. +> -W, --working-dir=PATH Run as if zk was started in instead of the +> current working directory. +> --no-input Never prompt or ask for confirmation. + +# The default command is `tag list`. +$ zk tag +>biography (1) +>biology (2) +>book (12) +>dystopia (2) +>feminism (1) +>fiction (6) +>history (2) +>non-fiction (6) +>philosophy (3) +>physics (1) +>romance (3) +>science (3) +>science-fiction (1) +2> +2>Found 13 tags + diff --git a/tests/config-alias.tesh b/tests/config-alias.tesh new file mode 100644 index 0000000..052e392 --- /dev/null +++ b/tests/config-alias.tesh @@ -0,0 +1,38 @@ +$ cd blank + +# Setup note fixtures. +$ mkdir "red planet" +$ touch "without-title.md" +$ echo "# Yellow sun" > "yellow-sun.md" +$ touch "red planet/blue moon.md" + +# Alias to override the default flags of a command. +$ echo "[alias] list = 'zk list --quiet -fpath \$@'" > .zk/config.toml +$ zk list -n2 --sort path- +>yellow-sun.md +>without-title.md + +# Shortcut for a native command. +$ echo "[alias] ls = 'zk list \$@'" > .zk/config.toml +$ zk ls --quiet -fpath +>red planet/blue moon.md +>without-title.md +>yellow-sun.md + +# Use $* +$ echo "[note] filename = '\{{slug title}}'\n [alias] nt = 'zk new --dry-run --title \"\$*\"'" > .zk/config.toml +$ zk nt Hello world +2>{{working-dir}}/hello-world.md + +# Use the `ZK_NOTEBOOK_DIR` env variable. +$ echo "[alias] nbdir = 'echo \$ZK_NOTEBOOK_DIR'" > .zk/config.toml +$ zk nbdir +>{{working-dir}} + +# Test the "xargs formula" +$ echo "[alias] xargs = 'zk list --quiet --format path --delimiter0 \$@ | xargs -0 ls -s1'" > .zk/config.toml +$ zk xargs +>0 red planet/blue moon.md +>0 without-title.md +>8 yellow-sun.md + diff --git a/tests/config-extra.tesh b/tests/config-extra.tesh new file mode 100644 index 0000000..f6d1fd5 --- /dev/null +++ b/tests/config-extra.tesh @@ -0,0 +1,30 @@ +$ cd extra + +# Test usage of `extra` in templates. +$ zk new --dry-run --title "Test" +># Test +> +>Visibility: public +>Color: red +>Extra: {"color":"red","visibility":"public"} +2>{{working-dir}}/public-test.md + +# Overridden extra in groups. +$ zk new journal --dry-run --title "Test" +># Test +> +>Visibility: private +>Color: red +>Extra: {"color":"red","visibility":"private"} +2>{{working-dir}}/journal/private-test.md + +# Overridden extra on the CLI. +$ zk new journal --dry-run --title "Test" --extra visibility=protected,show-header=1 +># Test +>Behold, the mighty dynamic header! +> +>Visibility: protected +>Color: red +>Extra: {"color":"red","show-header":"1","visibility":"protected"} +2>{{working-dir}}/journal/protected-test.md + diff --git a/tests/config-filter.tesh b/tests/config-filter.tesh new file mode 100644 index 0000000..ddefe79 --- /dev/null +++ b/tests/config-filter.tesh @@ -0,0 +1,27 @@ +$ cd blank + +$ touch banana.md +$ touch orange.md +$ mkdir dir +$ touch dir/orange.md +$ touch dir/apple.md +$ touch dir/pear.md + +# Use a custom filter with `zk list`. +$ echo "[filter] recents = '--sort created- --limit 2'" > .zk/config.toml +$ zk list -qfpath recents +>dir/pear.md +>dir/apple.md + +# Filter named after a directory to override the default filtering options. +$ echo "[filter] dir = 'dir --sort path-'" > .zk/config.toml +$ zk list -qfpath dir +>dir/pear.md +>dir/orange.md +>dir/apple.md + +# Nested filters. +$ echo "nested = 'dir --limit 2'" >> .zk/config.toml +$ zk list -qfpath nested +>dir/pear.md +>dir/orange.md diff --git a/tests/config-format-markdown-link.tesh b/tests/config-format-markdown-link.tesh new file mode 100644 index 0000000..8ada606 --- /dev/null +++ b/tests/config-format-markdown-link.tesh @@ -0,0 +1,62 @@ +$ cd blank + +# Setup note fixtures. +$ mkdir "red planet" +$ touch "without-title.md" +$ echo "---\ncolor: yellow\n---\n# Yellow sun" > "yellow-sun.md" +$ echo "# Blue moon" > "red planet/blue moon.md" + +# Default link format is `markdown`, without extension. +$ zk list -qflink +>[](without-title) +>[Blue moon](red%20planet/blue%20moon) +>[Yellow sun](yellow-sun) + +# Use `wiki` link format. +$ echo "[format.markdown] link-format = 'wiki'" > .zk/config.toml +$ zk list -qflink +>[[without-title]] +>[[red planet/blue moon]] +>[[yellow-sun]] + +# Use a custom link format. +# {{json .}} will print the whole template context. +$ echo "[format.markdown] link-format = '\{{json .}}'" > .zk/config.toml +$ zk list -qflink +>{"filename":"without-title","path":"without-title","absPath":"{{working-dir}}/without-title","relPath":"without-title","title":"","metadata":{}} +>{"filename":"blue moon","path":"red planet/blue moon","absPath":"{{working-dir}}/red planet/blue moon","relPath":"red planet/blue moon","title":"Blue moon","metadata":{}} +>{"filename":"yellow-sun","path":"yellow-sun","absPath":"{{working-dir}}/yellow-sun","relPath":"yellow-sun","title":"Yellow sun","metadata":{"color":"yellow"}} + +# Paths are relative to the current directory. +$ zk list -qflink -W "red planet" +>{"filename":"without-title","path":"without-title","absPath":"{{working-dir}}/without-title","relPath":"../without-title","title":"","metadata":{}} +>{"filename":"blue moon","path":"red planet/blue moon","absPath":"{{working-dir}}/red planet/blue moon","relPath":"blue moon","title":"Blue moon","metadata":{}} +>{"filename":"yellow-sun","path":"yellow-sun","absPath":"{{working-dir}}/yellow-sun","relPath":"../yellow-sun","title":"Yellow sun","metadata":{"color":"yellow"}} + +# Don't drop the extension. +$ echo "link-drop-extension = false" >> .zk/config.toml +$ zk list -qflink +>{"filename":"without-title.md","path":"without-title.md","absPath":"{{working-dir}}/without-title.md","relPath":"without-title.md","title":"","metadata":{}} +>{"filename":"blue moon.md","path":"red planet/blue moon.md","absPath":"{{working-dir}}/red planet/blue moon.md","relPath":"red planet/blue moon.md","title":"Blue moon","metadata":{}} +>{"filename":"yellow-sun.md","path":"yellow-sun.md","absPath":"{{working-dir}}/yellow-sun.md","relPath":"yellow-sun.md","title":"Yellow sun","metadata":{"color":"yellow"}} + +# Encode paths. +$ echo "link-encode-path = true" >> .zk/config.toml +$ zk list -qflink +>{"filename":"without-title.md","path":"without-title.md","absPath":"{{working-dir}}/without-title.md","relPath":"without-title.md","title":"","metadata":{}} +>{"filename":"blue%20moon.md","path":"red%20planet/blue%20moon.md","absPath":"{{working-dir}}/red%20planet/blue%20moon.md","relPath":"red%20planet/blue%20moon.md","title":"Blue moon","metadata":{}} +>{"filename":"yellow-sun.md","path":"yellow-sun.md","absPath":"{{working-dir}}/yellow-sun.md","relPath":"yellow-sun.md","title":"Yellow sun","metadata":{"color":"yellow"}} + +# Test individual template variables. +$ echo "[format.markdown] link-format = '\{{filename}} \{{title}} \{{json metadata}}'" > .zk/config.toml +$ zk list -qflink +>without-title {} +>blue moon Blue moon {} +>yellow-sun Yellow sun {"color":"yellow"} + +$ echo "[format.markdown] link-format = '\{{path}} \{{rel-path}} \{{abs-path}}'" > .zk/config.toml +$ zk list -qflink -W red\ planet +>without-title ../without-title {{working-dir}}/without-title +>red planet/blue moon blue moon {{working-dir}}/red planet/blue moon +>yellow-sun ../yellow-sun {{working-dir}}/yellow-sun + diff --git a/tests/config-format-markdown-tags.tesh b/tests/config-format-markdown-tags.tesh new file mode 100644 index 0000000..ed10ed8 --- /dev/null +++ b/tests/config-format-markdown-tags.tesh @@ -0,0 +1,43 @@ +$ cd blank + +$ echo "#hashtag\n#multi-word tag#\n:colon-tag:" > note.md + +# By default, only hashtags are enabled. +$ echo "" > .zk/config.toml +$ zk tag list +>hashtag (1) +>multi-word (1) +2> +2>Found 2 tags + +# Disable hashtags. +$ echo "[format.markdown] hashtags = false" > .zk/config.toml +$ zk index -fq +$ zk tag list +2> +2>Found 0 tag + +# Enable colon tags. +$ echo "[format.markdown] hashtags = false\n colon-tags = true" > .zk/config.toml +$ zk index -fq +$ zk tag list +>colon-tag (1) +2> +2>Found 1 tag + +# Enable Bear multi-word tags. +$ echo "[format.markdown] multiword-tags = true" > .zk/config.toml +$ zk index -fq +$ zk tag list +>hashtag (1) +>multi-word tag (1) +2> +2>Found 2 tags + +# Bear multi-word tags require hashtags to be enabled +$ echo "[format.markdown] hashtags = false\n multiword-tags = true" > .zk/config.toml +$ zk index -fq +$ zk tag list +2> +2>Found 0 tag + diff --git a/tests/config-group-paths.tesh b/tests/config-group-paths.tesh new file mode 100644 index 0000000..7d9c360 --- /dev/null +++ b/tests/config-group-paths.tesh @@ -0,0 +1,29 @@ +$ cd group-paths + +# No group. +$ zk new --title "Orange" --dry-run +2>{{working-dir}}/orange.md + +# Implicit group. +$ zk new implicit --title "Green" --dry-run +2>{{working-dir}}/implicit/implicit-green.md + +# Implicit group in subdirectory. +$ zk new dir/implicit\ subdir --title "Blue" --dry-run +2>{{working-dir}}/dir/implicit subdir/implicit-subdir-blue.md + +# Explicit paths. +$ zk new daily --title "Red" --dry-run +2>{{working-dir}}/daily/journal-red.md +$ zk new weekly --title "Yellow" --dry-run +2>{{working-dir}}/weekly/journal-yellow.md + +# Explicit paths with globs. +$ zk new journal/a --title "Black" --dry-run +2>{{working-dir}}/journal/a/journal-black.md +$ zk new journal/b --title "White" --dry-run +2>{{working-dir}}/journal/b/journal-white.md + +# Won't work in the root. +$ zk new journal --title "Purple" --dry-run +2>{{working-dir}}/journal/purple.md diff --git a/tests/config-group.tesh b/tests/config-group.tesh new file mode 100644 index 0000000..1fb5384 --- /dev/null +++ b/tests/config-group.tesh @@ -0,0 +1,23 @@ +$ cd group + +# Default group. +$ zk new --title "Red" --dry-run +># Red +> +>Default content +2>{{working-dir}}/red.md + +# Group associated with a path. +$ zk new journal --title "Green" --date "January 2nd" --dry-run +># Journal: Green +> +>What did you do today? +2>{{working-dir}}/journal/02-01.md + +# Overridden group from the CLI. +$ zk new --group journal --title "Blue" --date "January 2nd" --dry-run +># Journal: Blue +> +>What did you do today? +2>{{working-dir}}/02-01.md + diff --git a/tests/config-note-default-title.tesh b/tests/config-note-default-title.tesh new file mode 100644 index 0000000..b4ac1ef --- /dev/null +++ b/tests/config-note-default-title.tesh @@ -0,0 +1,13 @@ +$ cd blank + +$ echo "[note]\n filename = '\{{title}}'" > .zk/config.toml + +# The default title is Untitled. +$ zk new --dry-run +2>{{working-dir}}/Untitled.md + +# Set a custom default title. +$ echo "default-title = 'Sans titre'" >> .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/Sans titre.md + diff --git a/tests/config-note-filename.tesh b/tests/config-note-filename.tesh new file mode 100644 index 0000000..6304126 --- /dev/null +++ b/tests/config-note-filename.tesh @@ -0,0 +1,26 @@ +$ cd blank + +# The default filename is a random ID of 4 lowercase alphanumeric characters, with .md extension. +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-z0-9]{4}"}}.md + +# Set a custom filename. +$ echo "[note]\n filename = '\{{slug title}} - \{{date now \"%m-%d\"}}'" > .zk/config.toml +$ zk new --title "A new note" --date "January 5th" --dry-run +2>{{working-dir}}/a-new-note - 01-05.md + +# Set a custom extension. +$ echo "extension = 'markdown'" >> .zk/config.toml +$ zk new --title "A new note" --date "January 5th" --dry-run +2>{{working-dir}}/a-new-note - 01-05.markdown + +# Test the filename Handlebars variables. +$ mkdir "a dir" +$ echo "[note]\n filename = '\{{title}},\{{content}},\{{date now \"%m-%d\"}},\{{json extra}}'" > .zk/config.toml +$ echo "Piped content" | zk new --title "A new note" --date "January 5th" --extra key=value --dry-run +2>{{working-dir}}/A new note,Piped content +2>,01-05,{"key":"value"}.md +$ echo "[note]\n filename = '\{{id}},\{{dir}},\{{json extra}},\{{env.ZK_NOTEBOOK_DIR}}'" > .zk/config.toml +$ echo "Piped content" | zk new --title "A new note" --date "January 5th" --dry-run "a dir" +2>{{working-dir}}/a dir/{{match "[a-z0-9]{4}"}},a dir,{},{{working-dir}}.md + diff --git a/tests/config-note-id.tesh b/tests/config-note-id.tesh new file mode 100644 index 0000000..f6b1749 --- /dev/null +++ b/tests/config-note-id.tesh @@ -0,0 +1,50 @@ +$ cd blank + +# The default ID generation uses 4 lowercase alphanumeric characters. +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-z0-9]{4}"}}.md + +# Custom ID length. +$ echo "[note] id-length = 100" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-z0-9]{100}"}}.md + +# Uppercase. +$ echo "[note] id-length = 100\n id-case = 'upper'" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[A-Z0-9]{100}"}}.md + +# Lowercase. +$ echo "[note] id-length = 100\n id-case = 'lower'" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-z0-9]{100}"}}.md + +# Mixed case. +$ echo "[note] id-length = 100\n id-case = 'mixed'" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-zA-Z0-9]{100}"}}.md + +# Letters charset. +$ echo "[note] id-length = 100\n id-charset = 'letters'" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-z]{100}"}}.md + +# Numbers charset. +$ echo "[note] id-length = 100\n id-charset = 'numbers'" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[0-9]{100}"}}.md + +# Alphanumeric charset. +$ echo "[note] id-length = 100\n id-charset = 'alphanum'" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-z0-9]{100}"}}.md + +# Hexadecimal charset. +$ echo "[note] id-length = 100\n id-charset = 'hex'" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-f0-9]{100}"}}.md + +# Custom charset. +$ echo "[note] id-length = 100\n id-charset = 'abc01'" > .zk/config.toml +$ zk new --dry-run +2>{{working-dir}}/{{match "[a-c01]{100}"}}.md diff --git a/tests/config-note-ignore.tesh b/tests/config-note-ignore.tesh new file mode 100644 index 0000000..fd08ed4 --- /dev/null +++ b/tests/config-note-ignore.tesh @@ -0,0 +1,49 @@ +$ cd blank + +$ mkdir dir +$ mkdir dir/subdir +$ touch banana.md +$ touch orange.md +$ touch dir/orange.md +$ touch dir/subdir/apple.md + +# Ignore a file in the root directory. +$ echo "[note]\n ignore = ['orange.md']" > .zk/config.toml +$ zk index -v +>- added banana.md +>- added dir/orange.md +>- added dir/subdir/apple.md +>- ignored orange.md: matched ignore glob "orange.md" +> +>Indexed 3 notes in 0s +> + 3 added +> ~ 0 modified +> - 0 removed + +# Ignore with wildcards. +$ echo "[note]\n ignore = ['*rang*', 'dir/*']" > .zk/config.toml +$ zk index -v +>- unchanged banana.md +>- removed dir/orange.md +>- unchanged dir/subdir/apple.md +>- ignored dir/orange.md: matched ignore glob "dir/*" +>- ignored orange.md: matched ignore glob "*rang*" +> +>Indexed 2 notes in 0s +> + 0 added +> ~ 0 modified +> - 1 removed + +# Unignore all files. +$ echo "" > .zk/config.toml +$ zk index -v +>- unchanged banana.md +>- added dir/orange.md +>- unchanged dir/subdir/apple.md +>- added orange.md +> +>Indexed 4 notes in 0s +> + 2 added +> ~ 0 modified +> - 0 removed + diff --git a/tests/config-note-language.tesh b/tests/config-note-language.tesh new file mode 100644 index 0000000..fa6ab59 --- /dev/null +++ b/tests/config-note-language.tesh @@ -0,0 +1,15 @@ +$ cd blank + +$ echo "[note]\n filename = '\{{slug title}} - \{{date now \"%B\"}}'" > .zk/config.toml + +# The default language is `en`. +# Note the & converted to `and` in the slug. +$ zk new --title "Foo \& Bar" --date "January 2nd" --dry-run +2>{{working-dir}}/foo-and-bar - January.md + +# Set a custom language. +# Note the & converted to `et` in the slug. +$ echo "language = 'fr'" >> .zk/config.toml +$ zk new --title "Ceci \& cela" --date "January 2nd" --dry-run +2>{{working-dir}}/ceci-et-cela - January.md + diff --git a/tests/config-note-template.tesh b/tests/config-note-template.tesh new file mode 100644 index 0000000..7e21b26 --- /dev/null +++ b/tests/config-note-template.tesh @@ -0,0 +1,18 @@ +$ cd blank + +$ mkdir .zk/templates + +$ echo "# \{{title}}" > .zk/templates/custom.md + +# Set a custom template. +$ echo "[note] filename = '\{{slug title}}'\n template = 'custom.md'" > .zk/config.toml + +$ zk new --title "A new note" --dry-run +># A new note +2>{{working-dir}}/a-new-note.md + +# Template not found. +$ echo "[note] template = 'not-found'" > .zk/config.toml +1$ zk new --dry-run +2>zk: error: new note: load template file failed: cannot find template at not-found + diff --git a/tests/fixtures/blank/.zk/config.toml b/tests/fixtures/blank/.zk/config.toml new file mode 100644 index 0000000..e69de29 diff --git a/tests/fixtures/edit/.zk/config.toml b/tests/fixtures/edit/.zk/config.toml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/fixtures/edit/.zk/config.toml @@ -0,0 +1 @@ + diff --git a/tests/fixtures/edit/blue.md b/tests/fixtures/edit/blue.md new file mode 100644 index 0000000..33a56e2 --- /dev/null +++ b/tests/fixtures/edit/blue.md @@ -0,0 +1,3 @@ +# Blue + +Content of blue diff --git a/tests/fixtures/edit/green.md b/tests/fixtures/edit/green.md new file mode 100644 index 0000000..aa7a62e --- /dev/null +++ b/tests/fixtures/edit/green.md @@ -0,0 +1,3 @@ +# Green + +Content of green diff --git a/tests/fixtures/edit/purple.md b/tests/fixtures/edit/purple.md new file mode 100644 index 0000000..818b321 --- /dev/null +++ b/tests/fixtures/edit/purple.md @@ -0,0 +1,3 @@ +# Purple + +Content of purple diff --git a/tests/fixtures/edit/red.md b/tests/fixtures/edit/red.md new file mode 100644 index 0000000..4a824b4 --- /dev/null +++ b/tests/fixtures/edit/red.md @@ -0,0 +1,3 @@ +# Red + +Content of red diff --git a/tests/fixtures/edit/yellow.md b/tests/fixtures/edit/yellow.md new file mode 100644 index 0000000..d36a57f --- /dev/null +++ b/tests/fixtures/edit/yellow.md @@ -0,0 +1,3 @@ +# Yellow + +Content of yellow diff --git a/tests/fixtures/extra/.zk/config.toml b/tests/fixtures/extra/.zk/config.toml new file mode 100644 index 0000000..305fc99 --- /dev/null +++ b/tests/fixtures/extra/.zk/config.toml @@ -0,0 +1,10 @@ +[note] +template = "default.md" +filename = "{{extra.visibility}}-{{slug title}}" + +[extra] +color = "red" +visibility = "public" + +[group.journal.extra] +visibility = "private" # overrides diff --git a/tests/fixtures/extra/.zk/templates/default.md b/tests/fixtures/extra/.zk/templates/default.md new file mode 100644 index 0000000..de2cf34 --- /dev/null +++ b/tests/fixtures/extra/.zk/templates/default.md @@ -0,0 +1,8 @@ +# {{title}} +{{#if extra.show-header}} +Behold, the mighty dynamic header! +{{/if}} + +Visibility: {{extra.visibility}} +Color: {{extra.color}} +Extra: {{json extra}} diff --git a/tests/fixtures/full-sample/.zk/config.toml b/tests/fixtures/full-sample/.zk/config.toml new file mode 100644 index 0000000..c5e0473 --- /dev/null +++ b/tests/fixtures/full-sample/.zk/config.toml @@ -0,0 +1,2 @@ +[format.markdown] +colon-tags = true diff --git a/tests/fixtures/full-sample/.zk/templates/default.md b/tests/fixtures/full-sample/.zk/templates/default.md new file mode 100644 index 0000000..cb44174 --- /dev/null +++ b/tests/fixtures/full-sample/.zk/templates/default.md @@ -0,0 +1,3 @@ +# {{title}} + +{{content}} diff --git a/tests/fixtures/full-sample/18is.md b/tests/fixtures/full-sample/18is.md new file mode 100644 index 0000000..bf59648 --- /dev/null +++ b/tests/fixtures/full-sample/18is.md @@ -0,0 +1,20 @@ +# §How to invest in the stock markets? + +## How the markets work + +* [Financial markets are random](fa2k) +* [Compound interests make you rich](smdc) +* [The less you think about the market, the more money you make](uok6) +* [Investment business is a scam](4yib) + +## Good rules to follow + +* [Diversify your portfolio](aqfd) +* [Buy low, sell high](uxjt) +* [Don't speculate](pywo) + +## How to invest + +* [How to choose a broker?](k9bm) + +:finance: diff --git a/tests/fixtures/full-sample/2cl7.md b/tests/fixtures/full-sample/2cl7.md new file mode 100644 index 0000000..21d00bf --- /dev/null +++ b/tests/fixtures/full-sample/2cl7.md @@ -0,0 +1,9 @@ +# Fearless concurrency + +* A term coined by the Rust team to advocate the [ownership pattern](88el) as a way to not only solve memory bugs but also most concurrency bugs at compile time. + +## Reference + +* [Fearless Concurrency - The Rust Programming Language](https://doc.rust-lang.org/book/ch16-00-concurrency.html) + +:programming: diff --git a/tests/fixtures/full-sample/3403.md b/tests/fixtures/full-sample/3403.md new file mode 100644 index 0000000..8ebc2c5 --- /dev/null +++ b/tests/fixtures/full-sample/3403.md @@ -0,0 +1,13 @@ +# Data race error + +A *data race* is similar to a race condition and happens when: + +* Two or more pointers access the same data at the same time. +* At least one of the pointers is being used to write to the data. +* There's no synchronization mechanism to protect the data. + +*Data races* cause undefined behavior and are hard to debug. + +Rust prevents *data races* by allowing only a single mutable reference of a value per scope. + +:programming: diff --git a/tests/fixtures/full-sample/3cut.md b/tests/fixtures/full-sample/3cut.md new file mode 100644 index 0000000..7742b22 --- /dev/null +++ b/tests/fixtures/full-sample/3cut.md @@ -0,0 +1,11 @@ +--- +aliases: [dangling reference] +--- + +# Dangling pointers + +A *dangling pointer* is a reference that is kept to freed data. With C, reading it causes a *segmentation fault*. + +Rust protects against *dangling pointers* by making sure data is not freed until it goes out of scope ([Ownership in Rust](88el)). + +:programming: diff --git a/tests/fixtures/full-sample/4oma.md b/tests/fixtures/full-sample/4oma.md new file mode 100644 index 0000000..72f036a --- /dev/null +++ b/tests/fixtures/full-sample/4oma.md @@ -0,0 +1,7 @@ +# Message passing + +* A popular approach for safe concurrency is to use *message passing* instead of shared state. +* Channels are an example of a message passing implementation. +* The Go language is advocating for this approach with their slogan: "[Do not communicate by sharing memory; instead, share memory by communicating](ref/7fto)". + +:programming: diff --git a/tests/fixtures/full-sample/4yib.md b/tests/fixtures/full-sample/4yib.md new file mode 100644 index 0000000..8f4d82e --- /dev/null +++ b/tests/fixtures/full-sample/4yib.md @@ -0,0 +1,22 @@ +# Investment business is a scam + +## Don't trust financial advisers + +Don't trust anyone selling financial products, even if they are endorsed by your employer and especially if: + +- the fees are a recurring % of the portfolio ([Compound interests make you rich](smdc)) +- they are offering gifts or holidays +- urgent one-time offers needing immediate decision + +They are trying to exploit your emotions caused by the fact that [financial markets are random](fa2k). + +## Avoid managed financial products + +Avoid at all cost actively managed fund, because: + +- the recurring fees will eat your interests +- they attract more taxes + +Avoid QROPS (offshore pensions) for expats. + +:finance: diff --git a/tests/fixtures/full-sample/88el.md b/tests/fixtures/full-sample/88el.md new file mode 100644 index 0000000..94b132e --- /dev/null +++ b/tests/fixtures/full-sample/88el.md @@ -0,0 +1,7 @@ +# Ownership in Rust + +Ownership is one of Rust's most unique features and replaces efficiently a GC for memory management. + +The Ownership is a method to manage data on the Heap ([The Stack and the Heap](tdrj)). + +:programming:rust: diff --git a/tests/fixtures/full-sample/aqfd.md b/tests/fixtures/full-sample/aqfd.md new file mode 100644 index 0000000..c8c881f --- /dev/null +++ b/tests/fixtures/full-sample/aqfd.md @@ -0,0 +1,13 @@ +# Diversify your portfolio + +Diversifying a portfolio makes sure that its value is not too volatile, because [financial markets are random](fa2k). + +Buy funds representing the market as a whole (industry sectors, regions, etc.) instead of individual stocks, remembering to [buy when the prices are low](uxjt). + +Your portfolio should be a combination of: + +- A global stock market index fund to provide global exposure. +- A domestic stock index fund to represent your home‐country stock market (or the country where you plan to retire). +- A domestic bond market index fund to stabilize the value of the portfolio. + +:finance: diff --git a/tests/fixtures/full-sample/fa2k.md b/tests/fixtures/full-sample/fa2k.md new file mode 100644 index 0000000..9ad0b59 --- /dev/null +++ b/tests/fixtures/full-sample/fa2k.md @@ -0,0 +1,5 @@ +# Financial markets are random + +The markets' value is highly volatile on short term, but has a steady long term growth (> 10 years). Your best bet is to [stick to your portfolio strategy](uok6) and trust that [compound interests will make you rich](smdc). + +:finance: diff --git a/tests/fixtures/full-sample/fwsj.md b/tests/fixtures/full-sample/fwsj.md new file mode 100644 index 0000000..561eff7 --- /dev/null +++ b/tests/fixtures/full-sample/fwsj.md @@ -0,0 +1,6 @@ +# Channel + +* Channels are a great approach for safe concurrency. +* It's an implementation of the [message passing](4oma) pattern. + +:programming: diff --git a/tests/fixtures/full-sample/g7qa.md b/tests/fixtures/full-sample/g7qa.md new file mode 100644 index 0000000..321929f --- /dev/null +++ b/tests/fixtures/full-sample/g7qa.md @@ -0,0 +1,12 @@ +# Concurrency in Rust + +* Thanks to the [Ownership pattern](88el), Rust has a model of [Fearless concurrency](2cl7). +* Rust aims to have a small runtime, so it doesn't support [green threads](inbox/my59). + * Crates exist to add support for green threads if needed. + * Instead, Rust relies on the OS threads, a model called 1-1. + +* Rust offers a number of constructs for sharing data between threads: + * [Channel](fwsj) for a safe [message passing](4oma) approach. + * [Mutex](inbox/er4k) for managing shared state. + +:rust:programming: diff --git a/tests/fixtures/full-sample/hkvy.md b/tests/fixtures/full-sample/hkvy.md new file mode 100644 index 0000000..b296584 --- /dev/null +++ b/tests/fixtures/full-sample/hkvy.md @@ -0,0 +1,7 @@ +# The borrow checker + +The *borrow checker* of Rust's compiler is comparing the scope of borrowed references to the scope of the owned data to prevent dangling references. It also makes sure that the relationship between *lifetimes* of several reference match. + +In some deterministic patterns, the *borrow checker* automatically infer the lifetimes following [lifetime elision rules](t9i4). But when the *borrow checker* can't automatically infer the lifetimes, we need to help it by annotating our references with [generic lifetime annotations](554k). + +:programming:rust: diff --git a/tests/fixtures/full-sample/inbox/akwm.md b/tests/fixtures/full-sample/inbox/akwm.md new file mode 100644 index 0000000..ec27da5 --- /dev/null +++ b/tests/fixtures/full-sample/inbox/akwm.md @@ -0,0 +1,12 @@ +# Errors should be handled differently in an application versus a library + +Error handling should be approached differently depending on the context. + +* A *library* should focus on *producing* errors with meaningful context, by wrapping lower-level errors. +* An *application* mainly consumes errors, by deciding how they are formatted and presented to the user. + +## References + +* [Rust: Structuring and handling errors in 2020 - nick.groenen.me](https://nick.groenen.me/posts/rust-error-handling/) + +:programming: diff --git a/tests/fixtures/full-sample/inbox/dld4.md b/tests/fixtures/full-sample/inbox/dld4.md new file mode 100644 index 0000000..a34067f --- /dev/null +++ b/tests/fixtures/full-sample/inbox/dld4.md @@ -0,0 +1,14 @@ +--- +date: 2011-05-16 09:58:57 +keywords: [programming, http] +category: "Best practice" +--- + +# When to prefer PUT over POST HTTP method? + +`PUT` should be idempotent. This means that it's harmless to call a `PUT` request many times. On the contrary, calling `POST` requests repeatedly might change data on the server again. + +A way to see it is: + +* `PUT` = SQL `UPDATE` +* `POST` = SQL `INSERT` diff --git a/tests/fixtures/full-sample/inbox/er4k.md b/tests/fixtures/full-sample/inbox/er4k.md new file mode 100644 index 0000000..5a7d6b6 --- /dev/null +++ b/tests/fixtures/full-sample/inbox/er4k.md @@ -0,0 +1,10 @@ +# Mutex + +* Abbreviation of *mutual exclusion*. +* An approach to manage safely shared state by allowing only a single thread to access a protected value at one time. +* A mutex *guards* a protected data with a *locking system*. +* Managing mutexes is tricky, using [channels](../fwsj) is an easier alternative. + * The main risk is to create *deadlocks*. + * Thanks to its [Ownership](../88el) pattern, Rust makes sure we can't mess up when using locks. + +:programming: diff --git a/tests/fixtures/full-sample/inbox/my59.md b/tests/fixtures/full-sample/inbox/my59.md new file mode 100644 index 0000000..3bd83eb --- /dev/null +++ b/tests/fixtures/full-sample/inbox/my59.md @@ -0,0 +1,8 @@ +# Green threads + +> Many operating systems provide an API for creating new threads. This model where a language calls the operating system APIs to create threads is sometimes called 1:1, meaning one operating system thread per one language thread. + +> Many programming languages provide their own special implementation of threads. Programming language-provided threads are known as green threads, and languages that use these green threads will execute them in the context of a different number of operating system threads. For this reason, the green-threaded model is called the M:N model: there are M green threads per N operating system threads, where M and N are not necessarily the same number +> [Using Threads to Run Code Simultaneously - The Rust Programming Language](https://doc.rust-lang.org/book/ch16-01-threads.html) + +:programming: diff --git a/tests/fixtures/full-sample/k9bm.md b/tests/fixtures/full-sample/k9bm.md new file mode 100644 index 0000000..0562b5d --- /dev/null +++ b/tests/fixtures/full-sample/k9bm.md @@ -0,0 +1,13 @@ +# How to choose a broker? + +A broker will trade your portfolio for you on the markets. + +You should choose a broker that is located in a country where the government is stable and where banking regulations are solid. + +Don't trade more than once a month, since brokers charge commissions when you trade. + +On-going fees as percentage of a portfolio's assets are the real killer ([Investment business is a scam](4yib)) because [compound interests make you rich](smdc). However, commission fees on trading are okay. + +It might be worth choosing a broker in your country, for easier tax filling. + +:finance: diff --git a/tests/fixtures/full-sample/oumc.md b/tests/fixtures/full-sample/oumc.md new file mode 100644 index 0000000..86a4710 --- /dev/null +++ b/tests/fixtures/full-sample/oumc.md @@ -0,0 +1,14 @@ +# Strings are a complicated data structure + +Given the Hindi word "नमस्ते": + +1. It can be represented as a byte array of 18 bytes: + `[224, 164, 168, 224, 164, 174, 224, 164, 184, 224, 165, 141, 224, 164, 164, 224, 165, 135]` + +2. If you look at Unicode scalar values, you get an array of 6 characters: + `['न', 'म', 'स', '्', 'त', 'े']` + +3. But the fourth and sixth letters are diacritics. To get the human-readable letters, you need to look at the strings as an array of *grapheme clusters*: + `["न", "म", "स्", "ते"]` + +:programming: diff --git a/tests/fixtures/full-sample/pywo.md b/tests/fixtures/full-sample/pywo.md new file mode 100644 index 0000000..2aa548e --- /dev/null +++ b/tests/fixtures/full-sample/pywo.md @@ -0,0 +1,9 @@ +# Don't speculate + +You have more to loose by doing market timing (jumping in and out of the stocks market). Remember, [the less you think about the market, the more money you make](uok6). + +For example, from 1982 to 2005, the market averaged 10.6 percent annually, but if you missed the 10 best trading days, your return would drop to 8.1 percent, or 1.8 percent for the 50 best trading days. + +Take your money out of the stock market for a day, a week or a month and you could miss the best trading days of the decade, nobody can predict those because [financial markets are random](fa2k). + +:finance: diff --git a/tests/fixtures/full-sample/ref/7fto.md b/tests/fixtures/full-sample/ref/7fto.md new file mode 100644 index 0000000..9737147 --- /dev/null +++ b/tests/fixtures/full-sample/ref/7fto.md @@ -0,0 +1,6 @@ +# Do not communicate by sharing memory; instead, share memory by communicating + +* Advocates for the use of [message passing](4oma) instead of shared state. +* A slogan initially coined by Rob Pike ([Effective Go - Concurrency](https://golang.org/doc/effective_go.html#concurrency)). + +:programming: diff --git a/tests/fixtures/full-sample/ref/eg7k.md b/tests/fixtures/full-sample/ref/eg7k.md new file mode 100644 index 0000000..6cd8975 --- /dev/null +++ b/tests/fixtures/full-sample/ref/eg7k.md @@ -0,0 +1,7 @@ +# Null references: the billion dollar mistake + +Tony Hoare, the inventor of `null`, has this to say: + +> I call it my billion-dollar mistake. At that time, I was designing the first comprehensive type system for references in an object-oriented language. My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years. + +:programming: diff --git a/tests/fixtures/full-sample/smdc.md b/tests/fixtures/full-sample/smdc.md new file mode 100644 index 0000000..d2e0640 --- /dev/null +++ b/tests/fixtures/full-sample/smdc.md @@ -0,0 +1,21 @@ +# Compound interests make you rich + +Since the growth is exponential, time is more important than the amount of money you invest with compound interests. Start investing right now! + +This also means that small interest percentages add up to big amount. So [beware of financial products](4yib) eating your interests. + +Buy new shares with the interests to benefit from the compound interests, e.g. after a unique investment of $1,000 with a 10% interest rate: + +- without reinvesting the dividends: + - 40 yrs = $5,000 + - 50 yrs = $6,000 + +- with compound interest: + - 40 yrs = $45,000 + - 50 yrs = $117,000 + +## References + +- [These 3 Charts Show The Amazing Power Of Compound Interest](https://www.businessinsider.com/personal-finance/amazing-power-of-compound-interest-2014-7?r=DE&IR=T) + +:finance: diff --git a/tests/fixtures/full-sample/tdrj.md b/tests/fixtures/full-sample/tdrj.md new file mode 100644 index 0000000..2a40cad --- /dev/null +++ b/tests/fixtures/full-sample/tdrj.md @@ -0,0 +1,27 @@ +# The Stack and the Heap + +Both the Stack and the Heap are parts of the memory that is accessible to an app during runtime. + +## Stack + +* The Stack stores values in a last in, first out fashion. +* All values stored must have a known fixed size. + * Data with unknown or changeable size must be stored on the Heap instead. +* Are stored on the Stack: + * Arguments and local variables when calling a function. + +## Heap + +* The Heap is less organized than the Stack +* When *allocating on the Heap*, the memory allocator: + 1. Looks for an empty spot for the requested size. + 2. Marks the spot as reserved. + 3. Returns a pointer to the spot. + * The pointer is then usually stored on the Stack. When we want to access the data, we must follow the pointer to the Heap. + +## Stack vs Heap + +* *Pushing to the Stack* is faster than *allocating on the Heap* because the Stack doesn't need to find an empty spot. +* Accessing data from the Stack is also faster because we don't have to jump around in the memory and to follow pointers. + +:programming: diff --git a/tests/fixtures/full-sample/uok6.md b/tests/fixtures/full-sample/uok6.md new file mode 100644 index 0000000..12f4d6c --- /dev/null +++ b/tests/fixtures/full-sample/uok6.md @@ -0,0 +1,13 @@ +# Stick to your portfolio strategy + +Choose a portfolio strategy, such as the [Couch potato investment strategy](hdi6), and stick to it. + +Second-guessing and tweaking make your portfolio under perform. Ignore your emotions when the market fluctuates, this derails most investors. Instead, keep steady and trust that [compound interests make you rich](smdc). A good way to do that is to look at your investments performance only once a year. + +## The less you think about the market, the more money you make + +Don't listen to investment news, stock predictions or economic forecasts. + +Don't tweak your investments to adjust to world events, there's not always a logical connection between world events and the markets performance, because the [financial markets are random](fa2k). + +:finance: diff --git a/tests/fixtures/full-sample/uxjt.md b/tests/fixtures/full-sample/uxjt.md new file mode 100644 index 0000000..34062df --- /dev/null +++ b/tests/fixtures/full-sample/uxjt.md @@ -0,0 +1,9 @@ +# Buy low, sell high + +It's better to invest when the prices are low, because it will usually go up on the long term, despite the fact that [financial markets are random](fa2k). + +Don't wait until you think the stocks are at their lowest ([speculation](pywo)), instead buy some when the prices are dropping, and buy more every month if the prices continue to drop. + +Investing a constant amount of money regularly (e.g. monthly) is a simple way to make sure you buy less stocks when the prices are high, and more when they are low. [Compound interests will work for you over time](smdc). + +:finance: diff --git a/tests/fixtures/full-sample/wtz9.md b/tests/fixtures/full-sample/wtz9.md new file mode 100644 index 0000000..943f1bb --- /dev/null +++ b/tests/fixtures/full-sample/wtz9.md @@ -0,0 +1,5 @@ +# Use small `Hashable` items with diffable data sources + +If `apply()` is too slow with a diffable data source, it's probably because the items take too long to be hashed. A best practice is to hash only the properties that are actually used for display in the view. + +:programming:swift:ios: diff --git a/tests/fixtures/full-sample/zbon.md b/tests/fixtures/full-sample/zbon.md new file mode 100644 index 0000000..fa54d93 --- /dev/null +++ b/tests/fixtures/full-sample/zbon.md @@ -0,0 +1,9 @@ +# Zero-cost abstractions in Rust + +*Zero-cost abstractions* is a term touted (coined?) by Rust-enthusiasts. It means that using higher-level features such as `map`, `filter`, `iterators`, etc. has no performance downsides. They get compiled to the same code we would write by hand with a `for` loop. + +## Reference + +* [Comparing Performance: Loops vs. Iterators - The Rust Programming Language](https://doc.rust-lang.org/book/ch13-04-performance.html) + +:programming:rust: diff --git a/tests/fixtures/group-paths/.zk/config.toml b/tests/fixtures/group-paths/.zk/config.toml new file mode 100644 index 0000000..4482c3d --- /dev/null +++ b/tests/fixtures/group-paths/.zk/config.toml @@ -0,0 +1,21 @@ +[note] +filename = "{{slug title}}" + +# Path derived from the group name. +[group.implicit.note] +filename = "implicit-{{slug title}}" + +# Path derived from the group name, in a sub-directory. +[group."dir/implicit subdir".note] +filename = "implicit-subdir-{{slug title}}" + +# Group with explicit paths. +[group.journal] +paths = [ + "daily", + "weekly", + "journal/*" +] +[group.journal.note] +filename = "journal-{{slug title}}" + diff --git a/tests/fixtures/group/.zk/config.toml b/tests/fixtures/group/.zk/config.toml new file mode 100644 index 0000000..65f9274 --- /dev/null +++ b/tests/fixtures/group/.zk/config.toml @@ -0,0 +1,13 @@ +[note] +filename = "{{slug title}}" +template = "default.md" + +[extra] +content = "Default content" + +[group.journal.note] +filename = "{{date now '%d-%m'}}" +template = "journal.md" + +[group.journal.extra] +content = "What did you do today?" diff --git a/tests/fixtures/group/.zk/templates/default.md b/tests/fixtures/group/.zk/templates/default.md new file mode 100644 index 0000000..74ba06b --- /dev/null +++ b/tests/fixtures/group/.zk/templates/default.md @@ -0,0 +1,3 @@ +# {{title}} + +{{extra.content}} diff --git a/tests/fixtures/group/.zk/templates/journal.md b/tests/fixtures/group/.zk/templates/journal.md new file mode 100644 index 0000000..bd89c10 --- /dev/null +++ b/tests/fixtures/group/.zk/templates/journal.md @@ -0,0 +1,3 @@ +# Journal: {{title}} + +{{extra.content}} diff --git a/tests/fixtures/index/.zk/config.toml b/tests/fixtures/index/.zk/config.toml new file mode 100644 index 0000000..3020492 --- /dev/null +++ b/tests/fixtures/index/.zk/config.toml @@ -0,0 +1,4 @@ +[note] +ignore = [ + "carrot-ignored/*", +] diff --git a/tests/fixtures/index/banana.md b/tests/fixtures/index/banana.md new file mode 100644 index 0000000..085eb28 --- /dev/null +++ b/tests/fixtures/index/banana.md @@ -0,0 +1,3 @@ +# Banana + +Content of banana diff --git a/tests/fixtures/index/carrot-ignored/tomato.md b/tests/fixtures/index/carrot-ignored/tomato.md new file mode 100644 index 0000000..57fc0c3 --- /dev/null +++ b/tests/fixtures/index/carrot-ignored/tomato.md @@ -0,0 +1,3 @@ +# Tomato + +Content of tomato diff --git a/tests/fixtures/index/eggplant/clementine.md b/tests/fixtures/index/eggplant/clementine.md new file mode 100644 index 0000000..b6598c0 --- /dev/null +++ b/tests/fixtures/index/eggplant/clementine.md @@ -0,0 +1,3 @@ +# Clementine + +Content of clementine diff --git a/tests/fixtures/index/litchee.md b/tests/fixtures/index/litchee.md new file mode 100644 index 0000000..ac6f49e --- /dev/null +++ b/tests/fixtures/index/litchee.md @@ -0,0 +1,3 @@ +# Litchee + +Content of litchee diff --git a/tests/fixtures/issue-23/.zk/config.toml b/tests/fixtures/issue-23/.zk/config.toml new file mode 100644 index 0000000..e69de29 diff --git a/tests/fixtures/issue-23/index.md b/tests/fixtures/issue-23/index.md new file mode 100644 index 0000000..36c5e2d --- /dev/null +++ b/tests/fixtures/issue-23/index.md @@ -0,0 +1,3 @@ +# Index + +[[template]] diff --git a/tests/fixtures/issue-23/template-creation.md b/tests/fixtures/issue-23/template-creation.md new file mode 100644 index 0000000..b7a0e21 --- /dev/null +++ b/tests/fixtures/issue-23/template-creation.md @@ -0,0 +1 @@ +# Template creation diff --git a/tests/fixtures/issue-23/template.md b/tests/fixtures/issue-23/template.md new file mode 100644 index 0000000..c296a5f --- /dev/null +++ b/tests/fixtures/issue-23/template.md @@ -0,0 +1 @@ +# Template diff --git a/tests/fixtures/issue-47/.zk/config.toml b/tests/fixtures/issue-47/.zk/config.toml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/fixtures/issue-47/.zk/config.toml @@ -0,0 +1 @@ + diff --git a/tests/fixtures/issue-47/202102241246 §1 Zettelkasten.md b/tests/fixtures/issue-47/202102241246 §1 Zettelkasten.md new file mode 100644 index 0000000..52c1cc8 --- /dev/null +++ b/tests/fixtures/issue-47/202102241246 §1 Zettelkasten.md @@ -0,0 +1,5 @@ +# §1 Zettelkasten + +## Inquiétudes + +- [[202102251018 La slip-box est un phénomène récent et ne peut pas être prouvé utile]] diff --git a/tests/fixtures/issue-47/202102251018 La slip-box est un phénomène récent et ne peut pas être prouvé utile.md b/tests/fixtures/issue-47/202102251018 La slip-box est un phénomène récent et ne peut pas être prouvé utile.md new file mode 100644 index 0000000..cb8a8e4 --- /dev/null +++ b/tests/fixtures/issue-47/202102251018 La slip-box est un phénomène récent et ne peut pas être prouvé utile.md @@ -0,0 +1 @@ +# La slip-box est un phénomène récent et ne peut pas être prouvé utile diff --git a/tests/fixtures/issue-82/.zk/config.toml b/tests/fixtures/issue-82/.zk/config.toml new file mode 100644 index 0000000..98205aa --- /dev/null +++ b/tests/fixtures/issue-82/.zk/config.toml @@ -0,0 +1,6 @@ +[group.quest] +paths = ["Quests"] + +[group.quest.note] +filename = "{{slug title}}" +template = "quest.md" diff --git a/tests/fixtures/issue-82/.zk/templates/quest.md b/tests/fixtures/issue-82/.zk/templates/quest.md new file mode 100644 index 0000000..e69de29 diff --git a/tests/fixtures/issue-86/.zk/config.toml b/tests/fixtures/issue-86/.zk/config.toml new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/tests/fixtures/issue-86/.zk/config.toml @@ -0,0 +1 @@ + diff --git a/tests/fixtures/issue-86/202110031652 foo bar.md b/tests/fixtures/issue-86/202110031652 foo bar.md new file mode 100644 index 0000000..4d39683 --- /dev/null +++ b/tests/fixtures/issue-86/202110031652 foo bar.md @@ -0,0 +1,5 @@ +--- +title: 'foo bar' +--- + +Some note diff --git a/tests/fixtures/issue-86/202110031653 baz.md b/tests/fixtures/issue-86/202110031653 baz.md new file mode 100644 index 0000000..9e311fa --- /dev/null +++ b/tests/fixtures/issue-86/202110031653 baz.md @@ -0,0 +1,5 @@ +--- +title: 'baz' +--- + +[foo bar](202110031652%20foo%20bar) diff --git a/tests/fixtures/neuron/.zk/config.toml b/tests/fixtures/neuron/.zk/config.toml new file mode 100644 index 0000000..e69de29 diff --git a/tests/fixtures/neuron/a.md b/tests/fixtures/neuron/a.md new file mode 100644 index 0000000..3162e33 --- /dev/null +++ b/tests/fixtures/neuron/a.md @@ -0,0 +1,4 @@ +# A + +* [[[b]]] +* [[a]]# diff --git a/tests/fixtures/neuron/b.md b/tests/fixtures/neuron/b.md new file mode 100644 index 0000000..7acef82 --- /dev/null +++ b/tests/fixtures/neuron/b.md @@ -0,0 +1,3 @@ +# B + +[[b]]# diff --git a/tests/fixtures/neuron/c.md b/tests/fixtures/neuron/c.md new file mode 100644 index 0000000..0513aef --- /dev/null +++ b/tests/fixtures/neuron/c.md @@ -0,0 +1,3 @@ +# C + +#[[a]] diff --git a/tests/fixtures/new/.zk/config.toml b/tests/fixtures/new/.zk/config.toml new file mode 100644 index 0000000..1fdafe3 --- /dev/null +++ b/tests/fixtures/new/.zk/config.toml @@ -0,0 +1,14 @@ +[note] +template = "default.md" +filename = "{{slug title}}" + +[group.date.note] +template = "empty.md" +filename = "{{date now '%d-%m'}}" + +[group.handlebars.note] +template = "handlebars.md" + +[group.handlebars.extra] +key = "value" +visibility = "public" diff --git a/tests/fixtures/new/.zk/templates/default.md b/tests/fixtures/new/.zk/templates/default.md new file mode 100644 index 0000000..cb44174 --- /dev/null +++ b/tests/fixtures/new/.zk/templates/default.md @@ -0,0 +1,3 @@ +# {{title}} + +{{content}} diff --git a/tests/fixtures/new/.zk/templates/empty.md b/tests/fixtures/new/.zk/templates/empty.md new file mode 100644 index 0000000..e69de29 diff --git a/tests/fixtures/new/.zk/templates/handlebars.md b/tests/fixtures/new/.zk/templates/handlebars.md new file mode 100644 index 0000000..b4f21c3 --- /dev/null +++ b/tests/fixtures/new/.zk/templates/handlebars.md @@ -0,0 +1,9 @@ +id: {{id}} +title: {{title}} +content: {{content}} +dir: {{dir}} +extra: {{json extra}} +now: {{date now "%d-%m"}} +env: {{env.ZK_NOTEBOOK_DIR}} +filename: {{filename}} +filename-stem: {{filename-stem}} diff --git a/tests/fixtures/paths/.zk/config.toml b/tests/fixtures/paths/.zk/config.toml new file mode 100644 index 0000000..f469ef5 --- /dev/null +++ b/tests/fixtures/paths/.zk/config.toml @@ -0,0 +1,2 @@ +[note] +filename = "{{slug title}}" diff --git a/tests/fixtures/paths/brown/wood.md b/tests/fixtures/paths/brown/wood.md new file mode 100644 index 0000000..c9eb257 --- /dev/null +++ b/tests/fixtures/paths/brown/wood.md @@ -0,0 +1,3 @@ +# Wood + +Content of wood diff --git a/tests/fixtures/paths/paper.md b/tests/fixtures/paths/paper.md new file mode 100644 index 0000000..7471ba5 --- /dev/null +++ b/tests/fixtures/paths/paper.md @@ -0,0 +1,4 @@ +# Paper + +Content of paper + diff --git a/tests/fixtures/tags/.zk/config.toml b/tests/fixtures/tags/.zk/config.toml new file mode 100644 index 0000000..9c2f045 --- /dev/null +++ b/tests/fixtures/tags/.zk/config.toml @@ -0,0 +1,8 @@ +[note] +filename = "{{slug title}}" +template = "default.md" + +# [format.markdown] +# hashtags = false +# colon-tags = false +# multiword-tags = false diff --git a/tests/fixtures/tags/.zk/templates/default.md b/tests/fixtures/tags/.zk/templates/default.md new file mode 100644 index 0000000..cb44174 --- /dev/null +++ b/tests/fixtures/tags/.zk/templates/default.md @@ -0,0 +1,3 @@ +# {{title}} + +{{content}} diff --git a/tests/fixtures/tags/1984.md b/tests/fixtures/tags/1984.md new file mode 100644 index 0000000..fe11034 --- /dev/null +++ b/tests/fixtures/tags/1984.md @@ -0,0 +1,3 @@ +# 1984 + +#book #fiction #dystopia diff --git a/tests/fixtures/tags/a-brief-history-of-time.md b/tests/fixtures/tags/a-brief-history-of-time.md new file mode 100644 index 0000000..2c53e9e --- /dev/null +++ b/tests/fixtures/tags/a-brief-history-of-time.md @@ -0,0 +1,3 @@ +# A Brief History of Time + +#book #science #non-fiction #physics diff --git a/tests/fixtures/tags/anna-karenina.md b/tests/fixtures/tags/anna-karenina.md new file mode 100644 index 0000000..13bb7c5 --- /dev/null +++ b/tests/fixtures/tags/anna-karenina.md @@ -0,0 +1,3 @@ +# Anna Karenina + +#book #fiction #romance diff --git a/tests/fixtures/tags/brave-new-world.md b/tests/fixtures/tags/brave-new-world.md new file mode 100644 index 0000000..3055f82 --- /dev/null +++ b/tests/fixtures/tags/brave-new-world.md @@ -0,0 +1,3 @@ +# Brave New World + +#book #fiction #science-fiction #dystopia diff --git a/tests/fixtures/tags/pride-and-prejudice.md b/tests/fixtures/tags/pride-and-prejudice.md new file mode 100644 index 0000000..4d4aacc --- /dev/null +++ b/tests/fixtures/tags/pride-and-prejudice.md @@ -0,0 +1,3 @@ +# Pride and Prejudice + +#book #fiction #romance diff --git a/tests/fixtures/tags/the-art-of-war.md b/tests/fixtures/tags/the-art-of-war.md new file mode 100644 index 0000000..29a3541 --- /dev/null +++ b/tests/fixtures/tags/the-art-of-war.md @@ -0,0 +1,3 @@ +# The Art of War + +#book #non-fiction #philosophy #history diff --git a/tests/fixtures/tags/the-diary-of-a-young-girl.md b/tests/fixtures/tags/the-diary-of-a-young-girl.md new file mode 100644 index 0000000..5a88227 --- /dev/null +++ b/tests/fixtures/tags/the-diary-of-a-young-girl.md @@ -0,0 +1,3 @@ +# The Diary of a Young Girl + +#book #non-fiction #history #biography diff --git a/tests/fixtures/tags/the-great-gatsby.md b/tests/fixtures/tags/the-great-gatsby.md new file mode 100644 index 0000000..7c57951 --- /dev/null +++ b/tests/fixtures/tags/the-great-gatsby.md @@ -0,0 +1,3 @@ +# The Great Gatsby + +#book #fiction #romance diff --git a/tests/fixtures/tags/the-origin-of-species.md b/tests/fixtures/tags/the-origin-of-species.md new file mode 100644 index 0000000..afc10c0 --- /dev/null +++ b/tests/fixtures/tags/the-origin-of-species.md @@ -0,0 +1,4 @@ +# The Origin of Species + +#book #science #non-fiction #biology #philosophy + diff --git a/tests/fixtures/tags/the-second-sex.md b/tests/fixtures/tags/the-second-sex.md new file mode 100644 index 0000000..6f030c9 --- /dev/null +++ b/tests/fixtures/tags/the-second-sex.md @@ -0,0 +1,4 @@ +# The Second Sex + +#book #non-fiction #feminism #philosophy + diff --git a/tests/fixtures/tags/the-selfish-gene.md b/tests/fixtures/tags/the-selfish-gene.md new file mode 100644 index 0000000..899ff97 --- /dev/null +++ b/tests/fixtures/tags/the-selfish-gene.md @@ -0,0 +1,3 @@ +# The Selfish Gene + +#book #science #non-fiction #biology diff --git a/tests/fixtures/tags/ulysses.md b/tests/fixtures/tags/ulysses.md new file mode 100644 index 0000000..26b95e2 --- /dev/null +++ b/tests/fixtures/tags/ulysses.md @@ -0,0 +1,3 @@ +# Ulysses + +#book #fiction diff --git a/tests/fixtures/yaml-frontmatter/.zk/config.toml b/tests/fixtures/yaml-frontmatter/.zk/config.toml new file mode 100644 index 0000000..e69de29 diff --git a/tests/fixtures/yaml-frontmatter/case.md b/tests/fixtures/yaml-frontmatter/case.md new file mode 100644 index 0000000..d48503e --- /dev/null +++ b/tests/fixtures/yaml-frontmatter/case.md @@ -0,0 +1,9 @@ +--- +TiTLe: Test that keys are normalized to lowercase. +DATE: 2011-05-16 09:58:57 +tAGs: [writing, essay, practice] +COLORS: + sky: blue + sun: yellow +--- + diff --git a/tests/fixtures/yaml-frontmatter/empty.md b/tests/fixtures/yaml-frontmatter/empty.md new file mode 100644 index 0000000..ae27838 --- /dev/null +++ b/tests/fixtures/yaml-frontmatter/empty.md @@ -0,0 +1,6 @@ +--- +--- + +# Empty frontmatter + +This is a mention of structure of essay. diff --git a/tests/fixtures/yaml-frontmatter/full.md b/tests/fixtures/yaml-frontmatter/full.md new file mode 100644 index 0000000..4cdc486 --- /dev/null +++ b/tests/fixtures/yaml-frontmatter/full.md @@ -0,0 +1,10 @@ +--- +title: Improve the structure of essays by rewriting +date: 2011-05-16 09:58:57 +tags: [writing, essay, practice] +aliases: [Structure of essay, Rewrite] +colors: + sky: blue + sun: yellow +--- + diff --git a/tests/fixtures/yaml-frontmatter/keywords.md b/tests/fixtures/yaml-frontmatter/keywords.md new file mode 100644 index 0000000..a018340 --- /dev/null +++ b/tests/fixtures/yaml-frontmatter/keywords.md @@ -0,0 +1,6 @@ +--- +# `keywords` is an alias of `tags`. +keywords: [writing, essay, practice] +--- + +# Alias of tags diff --git a/tests/fixtures/yaml-frontmatter/minimal.md b/tests/fixtures/yaml-frontmatter/minimal.md new file mode 100644 index 0000000..42d6104 --- /dev/null +++ b/tests/fixtures/yaml-frontmatter/minimal.md @@ -0,0 +1,5 @@ +--- +title: "Only one metadata" +--- + +Here's a mention of rewriting. diff --git a/tests/fixtures/yaml-frontmatter/tag-list.md b/tests/fixtures/yaml-frontmatter/tag-list.md new file mode 100644 index 0000000..78eba4f --- /dev/null +++ b/tests/fixtures/yaml-frontmatter/tag-list.md @@ -0,0 +1,7 @@ +--- +title: "Tags using a full YAML list" +tags: + - writing + - essay, practice # This will be considered as a single tag. +--- + diff --git a/tests/flag-help.tesh b/tests/flag-help.tesh new file mode 100644 index 0000000..f58c2c4 --- /dev/null +++ b/tests/flag-help.tesh @@ -0,0 +1,37 @@ +# Print the main help +$ zk --help +>Usage: zk +> +>Commands: +> +>NOTEBOOK +> A notebook is a directory containing a collection of notes +> +> init Create a new notebook in the given directory. +> index Index the notes to be searchable. +> +>NOTES +> Edit or browse your notes +> +> new Create a new note in the given notebook directory. +> list List notes matching the given criteria. +> graph Produce a graph of the notes matching the given criteria. +> edit Edit notes matching the given criteria. +> tag Manage the note tags. +> +>Flags: +> -h, --help Show context-sensitive help. +> --notebook-dir=PATH Turn off notebook auto-discovery and set manually +> the notebook where commands are run. +> -W, --working-dir=PATH Run as if zk was started in instead of the +> current working directory. +> --no-input Never prompt or ask for confirmation. +> +>Run "zk --help" for more information on a command. + +# Short flags +$ zk -h | head -n1 +>Usage: zk +$ zk init -h | head -n1 +>Usage: zk init [] + diff --git a/tests/flag-notebook-dir.tesh b/tests/flag-notebook-dir.tesh new file mode 100644 index 0000000..671b1c0 --- /dev/null +++ b/tests/flag-notebook-dir.tesh @@ -0,0 +1,20 @@ +# No notebook found in the current directory. +1$ zk index -q +2>zk: error: failed to open notebook: no notebook found in {{working-dir}} or a parent directory + +# Provide the notebook directory with `--notebook-dir`. +$ zk index -q --notebook-dir paths + +# Provide the notebook directory with the `ZK_NOTEBOOK_DIR` env variable. +$ ZK_NOTEBOOK_DIR={{working-dir}}/paths zk index -q + +$ cd paths + +# Notebook found in the current directory. +$ zk index -q + +$ cd brown + +# Notebook found in a parent directory. +$ zk index -q + diff --git a/tests/flag-version.tesh b/tests/flag-version.tesh new file mode 100644 index 0000000..078f40b --- /dev/null +++ b/tests/flag-version.tesh @@ -0,0 +1,3 @@ +$ zk --version +>zk {{sh "git describe --tags | cut -c 2-"}} + diff --git a/tests/flag-working-dir.tesh b/tests/flag-working-dir.tesh new file mode 100644 index 0000000..ba290cb --- /dev/null +++ b/tests/flag-working-dir.tesh @@ -0,0 +1,27 @@ +# The notebook directory is derived from the working directory. +$ zk list -qfpath --working-dir paths +>paper.md +>brown/wood.md + +# Short flag. +$ zk list -qfpath -W paths +>paper.md +>brown/wood.md + +# The note paths and links are relative to the provided working directory +$ zk list -qf"\{{path}} \{{link}}" --working-dir paths/brown +>../paper.md [Paper](../paper) +>wood.md [Wood](wood) + +# Creating a new note in the given working directory. +$ zk new --print-path --title "Stone" --working-dir paths +>{{working-dir}}/paths/stone.md + +# Creating a new note in the given working directory. +$ zk new --print-path --title "Glass" --working-dir paths/brown +>{{working-dir}}/paths/brown/glass.md + +# Creating a new note relative to the given working directory. +$ zk new --print-path --title "Iron" --working-dir paths/brown .. +>{{working-dir}}/paths/iron.md + diff --git a/tests/issue-118.tesh b/tests/issue-118.tesh new file mode 100644 index 0000000..6efa74e --- /dev/null +++ b/tests/issue-118.tesh @@ -0,0 +1,8 @@ +# A single-character hashtag freezes the indexing step. +# https://github.com/mickael-menu/zk/issues/118 + +$ cd blank +$ echo "#A" > test.md +$ zk tag list -qfname +>A + diff --git a/tests/issue-20.tesh b/tests/issue-20.tesh new file mode 100644 index 0000000..840bbdb --- /dev/null +++ b/tests/issue-20.tesh @@ -0,0 +1,10 @@ +# Local notebook configuration should be optional. +# https://github.com/mickael-menu/zk/issues/20 + +1$ zk index -q +2>zk: error: failed to open notebook: no notebook found in {{working-dir}} or a parent directory + +$ mkdir .zk + +$ zk index -q + diff --git a/tests/issue-23.tesh b/tests/issue-23.tesh new file mode 100644 index 0000000..ee25b4d --- /dev/null +++ b/tests/issue-23.tesh @@ -0,0 +1,8 @@ +# Link hrefs are not finding the best match +# https://github.com/mickael-menu/zk/issues/23 + +$ cd issue-23 + +$ zk list -qfpath --linked-by index.md +>template.md + diff --git a/tests/issue-47.tesh b/tests/issue-47.tesh new file mode 100644 index 0000000..192937b --- /dev/null +++ b/tests/issue-47.tesh @@ -0,0 +1,11 @@ +# Links containing accents are not matching the target note +# https://github.com/mickael-menu/zk/issues/47 + +$ cd issue-47 + +$ zk list -qfpath --orphan +>202102241246 §1 Zettelkasten.md + +$ zk list -qfpath --link-to 202102251018 +>202102241246 §1 Zettelkasten.md + diff --git a/tests/issue-78.tesh b/tests/issue-78.tesh new file mode 100644 index 0000000..42f27f4 --- /dev/null +++ b/tests/issue-78.tesh @@ -0,0 +1,16 @@ +# Notes containing broken links are not indexed. +# https://github.com/mickael-menu/zk/issues/78 + +$ cd blank + +$ echo "[This is a link](my-note.md)" > index.md + +$ zk index +>Indexed 1 note in 0s +> + 1 added +> ~ 0 modified +> - 0 removed + +$ zk list -qfpath +>index.md + diff --git a/tests/issue-82.tesh b/tests/issue-82.tesh new file mode 100644 index 0000000..1586e7f --- /dev/null +++ b/tests/issue-82.tesh @@ -0,0 +1,10 @@ +# Crash when `zk new` fails. +# https://github.com/mickael-menu/zk/issues/82 +$ cd issue-82 + +$ zk new --group quest --print-path +>{{working-dir}}/untitled.md + +$ EDITOR=echo zk new --group quest +>{{working-dir}}/untitled.md + diff --git a/tests/issue-86.tesh b/tests/issue-86.tesh new file mode 100644 index 0000000..bc7fd8e --- /dev/null +++ b/tests/issue-86.tesh @@ -0,0 +1,13 @@ +# Encoded Markdown links are not properly indexed. +# https://github.com/mickael-menu/zk/issues/86 +$ cd issue-86 + +$ zk list -qfpath --link-to 202110031652 +>202110031653 baz.md + +$ zk list -qfpath --link-to "202110031652 foo bar" +>202110031653 baz.md + +$ zk list -qfpath --link-to "foo bar" +>202110031653 baz.md + diff --git a/tests/issue-89.tesh b/tests/issue-89.tesh new file mode 100644 index 0000000..a9cd75c --- /dev/null +++ b/tests/issue-89.tesh @@ -0,0 +1,17 @@ +# zk index only works in notebook directory +# https://github.com/mickael-menu/zk/issues/89 + +$ ZK_NOTEBOOK_DIR="{{working-dir}}/blank" zk index +>Indexed 0 note in 0s +> + 0 added +> ~ 0 modified +> - 0 removed + +$ touch blank/foo.md + +$ ZK_NOTEBOOK_DIR="{{working-dir}}/blank" zk index +>Indexed 1 note in 0s +> + 1 added +> ~ 0 modified +> - 0 removed + diff --git a/tests/markdown-yaml-frontmatter.tesh b/tests/markdown-yaml-frontmatter.tesh new file mode 100644 index 0000000..5516cb2 --- /dev/null +++ b/tests/markdown-yaml-frontmatter.tesh @@ -0,0 +1,49 @@ +$ cd yaml-frontmatter + +# The YAML frontmatter is available in the `metadata` Handlebars variable. +$ zk list -q --format "\{{path}}: \{{json metadata}}" +>keywords.md: {"keywords":["writing","essay","practice"]} +>empty.md: {} +>full.md: {"aliases":["Structure of essay","Rewrite"],"colors":{"sky":"blue","sun":"yellow"},"date":"2011-05-16 09:58:57","tags":["writing","essay","practice"],"title":"Improve the structure of essays by rewriting"} +>minimal.md: {"title":"Only one metadata"} +>tag-list.md: {"tags":["writing","essay, practice"],"title":"Tags using a full YAML list"} +>case.md: {"colors":{"sky":"blue","sun":"yellow"},"date":"2011-05-16 09:58:57","tags":["writing","essay","practice"],"title":"Test that keys are normalized to lowercase."} + +# Title extracted from the frontmatter. +$ zk list -q --format "\{{path}}: \{{title}}" +>keywords.md: Alias of tags +>empty.md: Empty frontmatter +>full.md: Improve the structure of essays by rewriting +>minimal.md: Only one metadata +>tag-list.md: Tags using a full YAML list +>case.md: Test that keys are normalized to lowercase. + +# Tags extracted from the frontmatter. +$ zk list -q --format "\{{path}}: \{{json tags}}" +>keywords.md: ["writing","essay","practice"] +>empty.md: [] +>full.md: ["writing","essay","practice"] +>minimal.md: [] +>tag-list.md: ["writing","essay, practice"] +>case.md: ["writing","essay","practice"] + +# Creation date extracted from the frontmatter. +$ zk list -q --format "\{{path}}: \{{date created 'full'}}" +>keywords.md: {{match '.*'}} +>empty.md: {{match '.*'}} +>full.md: Monday, May 16, 2011 +>minimal.md: {{match '.*'}} +>tag-list.md: Monday, May 16, 2011 +>case.md: Monday, May 16, 2011 + +# `--mention` uses the aliases from the frontmatter. +$ zk list -q --format "\{{path}}: \{{json snippets}}" --mention full.md +>minimal.md: ["Here's a mention of rewriting."] +>empty.md: ["This is a mention of structure of essay."] + +$ zk list -q --format "\{{path}}: \{{json snippets}}" --mentioned-by minimal.md +>full.md: ["Here's a mention of rewriting."] + +$ zk list -q --format "\{{path}}: \{{json snippets}}" --mentioned-by empty.md +>full.md: ["This is a mention of structure of essay."] + diff --git a/tests/neuron.tesh b/tests/neuron.tesh new file mode 100644 index 0000000..5d98250 --- /dev/null +++ b/tests/neuron.tesh @@ -0,0 +1,19 @@ +$ cd neuron + +# Test that [[[link]]], #[[link]] and [[link]]# are properly parsed and have +# the proper link relation. +$ zk graph -qfjson +>{ +> "notes": [ +> {{match '.*'}} +> {{match '.*'}} +> {{match '.*'}} +> ], +> "links": [ +> {"title":"a","href":"a","type":"wiki-link","isExternal":false,"rels":["down"],"snippet":"[[a]]#","snippetStart":17,"snippetEnd":23,"sourceId":1,"sourcePath":"a.md","targetId":1,"targetPath":"a.md"}, +> {"title":"b","href":"b","type":"wiki-link","isExternal":false,"rels":["down"],"snippet":"[[[b]]]","snippetStart":7,"snippetEnd":14,"sourceId":1,"sourcePath":"a.md","targetId":2,"targetPath":"b.md"}, +> {"title":"b","href":"b","type":"wiki-link","isExternal":false,"rels":["down"],"snippet":"[[b]]#","snippetStart":5,"snippetEnd":11,"sourceId":2,"sourcePath":"b.md","targetId":2,"targetPath":"b.md"}, +> {"title":"a","href":"a","type":"wiki-link","isExternal":false,"rels":["up"],"snippet":"#[[a]]","snippetStart":5,"snippetEnd":11,"sourceId":3,"sourcePath":"c.md","targetId":1,"targetPath":"a.md"} +> ] +>} +