- using the Sphinx docs framework.
- restructured docs into directories to create some high level organisation.
- initialised as a zk notebook for quick editing and zk specific workflow enhancements.
- docs development, local build steps and requirements to be documented in subsequent PR.
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Jurica Bacurin <jurica@bacurin.de>
Ran tests against the PR, all pass.
Fallback wiki link resolution by matching on title or path
Add new template variables when generating Markdown links
Add a {{substring}} template helper
- label:I searched the existing discussions for help
required:true
- type:textarea
id:help
attributes:
label:How can we help you?
validations:
required:true
- type:markdown
attributes:
value:|
:warning:Unfortunately, my time is limited and I can't offer reliable user support. I might answer if you catch me on a slow day, or hopefully someone else will.
:warning:Unfortunately, my time is limited and I can't offer reliable user support. I might answer if you catch me on a slow day, or hopefully someone else will.
- type:checkboxes
id:checks
attributes:
label:If you need help, open a discussion
options:
- label:I will [create a new discussion](https://github.com/zk-org/zk/discussions/new?category=help) instead of an issue.
stale-issue-message:'This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs in the next 5 days.'
close-issue-message:'This issue was closed because it has been stalled for 5 days with no activity.'
All notable changes to this project will be documented in this file.
<!--## Unreleased-->
## Unreleased
## Added
* Path in .zk/config.toml for the default note template now accepts UNIX "~/paths" (by @WhyNotHugo)
## Fixed
* LSP ignores magnet links as links to notes (by @billymosis)
* Compilation robustness for Alpine package builds (by @nmeum)
## 0.14.1
### Fixed
* Fixed parsing large notes @khimaros in https://github.com/zk-org/zk/pull/339
* fix day range parsing (zk-org/zk#382) by @tjex in https://github.com/zk-org/zk/pull/384
* accept tripple dash file URIs as valid links by @tjex in https://github.com/zk-org/zk/pull/391
* fix(lsp): fix trigger completion of zk LSP by @Rahlir in https://github.com/zk-org/zk/pull/397
* fix(lsp): ignore diagnostic check within code blocks by @Rahlir in https://github.com/zk-org/zk/pull/399
* allow notebook as hidden dir by @tjex in https://github.com/zk-org/zk/pull/402
## 0.14.0
### Added
* New [`tool.shell`](docs/tool-shell.md) configuration key to set a custom shell (contributed by [@lsvmello](https://github.com/zk-org/zk/pull/302)).
* New [`notebook.dir`](docs/config-notebook.md) configuration key to set the default notebook (contributed by [@lsvmello](https://github.com/zk-org/zk/pull/304)).
### Changed
* The `note.ignore` configuration property was renamed to `note.exclude`, to be more consistent with the CLI flags.
### Fixed
* Fixed LSP positions using UTF-16 offsets (contributed by [@wrvsrx](https://github.com/zk-org/zk/pull/317)).
## 0.13.0
### Added
* LSP:
* `zk.new` now returns the created note's content in its output (`content`), and has two new options:
* `dryRun` will prevent `zk.new` from creating the note on the file system.
* `insertContentAtLocation` can be used to insert the created note's content into an arbitrary location.
* A new `zk.link` command to insert a link to a given note (contributed by [@psanker](https://github.com/zk-org/zk/pull/284)).
## 0.12.0
### Added
* LSP: Support for external URLs with `documentLink`.
* New `{{date}}` template helper to obtain a date object from natural language (contributed by [@zalegrala](https://github.com/zk-org/zk/pull/262)).
```
Get a relative date using natural language:
{{date "next week"}}
Format a date returned by `get-date`:
{{format-date (date "monday") "timestamp"}}
```
* `zk list` now support multiple `--match`/`-m` flags, which allows to search for several tokens appearing in any order in the notes (contributed by [@rktjmp](https://github.com/zk-org/zk/pull/268)).
### Changed
* **Breaking change:** The `{{date}}` template helper was renamed to `{{format-date}}`. You might need to update your configuration and templates.
### Fixed
* [#243](https://github.com/zk-org/zk/issues/243) LSP: Fixed finding backlink references for notes in a folder.
* [#254](https://github.com/zk-org/zk/issues/254) Fixed SQL error when pairing `--link-to` and `--linked-by`.
## 0.11.1
### Changed
* `zk new` now requires the `--interactive`/`-i` flag to read the note body from a pipe or standard input. [See rational](https://github.com/zk-org/zk/pull/242#issuecomment-1182602001).
### Fixed
* [#244](https://github.com/zk-org/zk/issues/244) Fixed `zk new` waiting for `Ctrl-D` to proceed (contributed by [@pkazmier](https://github.com/zk-org/zk/pull/242)).
## 0.11.0
### Added
* Use regular expressions when searching for notes with `--match`.
```sh
# Find notes containing emails.
$ zk list --match-strategy re --match ".+@.+"
$ zk list -Mr -m ".+@.+"
```
### Changed
* The flags `--exact-match`/`-e` are deprecated in favor of `--match-strategy exact`/`-Me`.
### Deprecated
* The LSP server does not support resolving a wiki link to a note title anymore.
* For example, `[[Planet]]` can match a note with filename `i4w0 Planet.md` but not `i4w0.md` with a Markdown title `Planet` anymore.
* This "smart" fallback resolution based on note titles was too fragile and not supported by the `zk` CLI.
### Fixed
* [#233](https://github.com/zk-org/zk/issues/233) Hide index progress in non-interactive shells.
* [#235](https://github.com/zk-org/zk/issues/235) Fix LSP link recognition with unicode (contributed by [@zkbpkp](https://github.com/zk-org/zk/issues/235)).
* [#236](https://github.com/zk-org/zk/issues/236) Fix updating links after creating a new note.
* [#239](https://github.com/zk-org/zk/discussions/239) Support standard input via shell redirection with `zk new`.
## 0.10.1
### Changed
* Removed the dependency on `libicu`.
### Fixed
* Indexed links are now automatically updated when adding a new note, if it is a better match than the previous link target.
## 0.10.0
### Added
* New `--date` flag for `zk new` to set the current date manually.
* New `--id` flag for `zk new` to skip ID generation and use a provided value (contributed by [@skbolton](https://github.com/zk-org/zk/pull/183)).
* [#144](https://github.com/zk-org/zk/issues/144) LSP auto-completion of YAML frontmatter tags.
* [zk-nvim#26](https://github.com/zk-org/zk-nvim/issues/26) The LSP server doesn't use `additionalTextEdits` anymore to remove the trigger characters when completing links.
* You can customize the default behavior with the [`use-additional-text-edits` configuration key](docs/config-lsp.md).
* [#163](https://github.com/zk-org/zk/issues/163) Use the `ZK_SHELL` environment variable to override the shell for `zk` only.
* [#173](https://github.com/zk-org/zk/issues/173) Support for double star globbing in `note.ignore` config option.
* [#137](https://github.com/zk-org/zk/issues/137) Customize the `fzf` options used by `zk`'s interactive modes with the [`fzf-options`](docs/tool-fzf.md) config option (contributed by [@Nelyah](https://github.com/zk-org/zk/pull/154)).
* [#168](https://github.com/zk-org/zk/discussions/168) Customize the `fzf` key binding to create new notes with the [`fzf-bind-new`](docs/tool-fzf.md) config option.
### Changed
* The default `fzf` key binding to create a new note with `zk edit --interactive` was changed to `Ctrl-E`, to avoid conflict with the default `Ctrl-N` binding.
### Fixed
* [#126](https://github.com/zk-org/zk/issues/126) Embedded image links shown as not found.
* [#152](https://github.com/zk-org/zk/issues/152) Incorrect timezone for natural dates.
* [#170](https://github.com/zk-org/zk/issues/170) Broken wiki links in subdirectories.
* [#185](https://github.com/zk-org/zk/issues/185) Don't parse a Markdown table header as a colon tag.
## 0.9.0
### Added
* New LSP commands:
* [`zk.list`](docs/editors-integration.md#zklist) to search for notes.
* [`zk.tag.list`](docs/editors-integration.md#zktaglist) to retrieve the list of tags.
* `--debug` mode which prints a stacktrace on `SIGINT`.
### Fixed
* [#111](https://github.com/zk-org/zk/issues/111) Filenames take precedence over folders when matching a sub-path with wiki links.
* [#118](https://github.com/zk-org/zk/issues/118) Fix infinite loop when parsing a single-character hashtag.
* [#121](https://github.com/zk-org/zk/issues/121) Take into account the `--no-input` flag with `zk init`.
* [#120](https://github.com/zk-org/zk/discussions/120) Support RFC 3339 dates with the time flags (e.g. `--created-before`).
## 0.8.0
### Added
* New `zk graph --format json` command which produces a JSON graph of the notes matching the given criteria.
* New template variables `filename` and `filename-stem` when formatting notes (e.g. with `zk list --format`) and for the [`fzf-line`](docs/tool-fzf.md) config key.
* Customize how LSP completion items appear in your editor when auto-completing links with the [`[lsp.completion]` configuration section](docs/config-lsp.md).
```toml
[lsp.completion]
# Show the note title in the completion pop-up, or fallback on its path if empty.
note-label = "{{title-or-path}}"
# Filter out the completion pop-up using the note title or its path.
note-filter-text = "{{title}} {{path}}"
# Show the note filename without extension as detail.
note-detail = "{{filename-stem}}"
```
* New `--dry-run` flag for `zk new` which prints out the path and content of the generated note instead of saving it to the file system.
* New `--verbose` flag for `zk index` which prints detailed information about the indexing process.
* You can now filter through the [YAML frontmatter](docs/note-frontmatter.md) with `zk list --interactive`.
### Fixed
* [#89](https://github.com/zk-org/zk/issues/89) Calling `zk index` from outside the notebook (contributed by [@adamreese](https://github.com/zk-org/zk/pull/90)).
* [#98](https://github.com/zk-org/zk/issues/98) Index wiki links using partial paths for `--linked-by` and `--link-to`.
* [#98](https://github.com/zk-org/zk/issues/98) Ignore spaces around the pipe in wiki links for LSP diagnostics.
## 0.7.0
### Added
* List the tags found in your notebook with `zk tag list`.
* Many options are available to customize the output, including JSON serialization. See `zk tag list --help`.
* Support for LSP references to browse the backlinks of the current note, if the caret is not over a link.
* New template variables are available when [generating custom Markdown links with `link-format`](docs/note-format.md).
* `filename`, `path`, `abs-path` and `rel-path` for many path flavors.
* `metadata` to use information (e.g. `id`) from the YAML frontmatter.
* The LSP server is now matching wiki links to any part of a note's path or its title.
* Given the note `book/z5mj Information Graphics.md` with the title "Book Review of Information Graphics", the following wiki links would work from a note located under `journal/2020-09-25.md`:
```markdown
[[../book/z5mj]]
[[book/z5mj]]
[[z5mj]]
[[book review information]]
[[Information Graphics]]
```
* Use the `{{abs-path}}` template variable when [formatting notes](docs/template-format.md) to print the absolute path to the note (contributed by [@pstuifzand](https://github.com/zk-org/zk/pull/60)).
* A new `{{substring s index length}}` template helper extracts a portion of a given string, e.g.:
* `{{substring 'A full quote' 2 4}}` outputs `full`
* `{{substring 'A full quote' -5 5}` outputs `quote`
### Fixed
* UTF-8 handling in the LSP server.
* [#78](https://github.com/zk-org/zk/issues/78) Do not exclude notes containing broken links from the index.
* Allow setting the `--working-dir` and `--notebook-dir` flags before the `zk` subcommand when using aliases, e.g. `zk -W ~/notes my-alias`.
* [#86](https://github.com/zk-org/zk/issues/86) Index encoded Markdown links.
## 0.6.0
### Added
* Use JSON formats with `zk list` for easy post-processing:
* `--format json` prints a plain JSON array.
* `--format jsonl` prints one JSON note object per line, according to [JSON Lines](https://jsonlines.org/).
* The new `{{json}}` template helper serializes any template context variable into a valid JSON value, e.g.:
* `{{json title}}` prints with quotes `"An interesting note"`
* `{{json .}}` serializes the full template context as a JSON object.
* Use `--header` and `--footer` options with `zk list` to print arbitrary text at the start or end of the list.
* Support for LSP references to browse the backlinks of the link under the caret (contributed by [@pstuifzand](https://github.com/zk-org/zk/pull/58)).
* New [`note.ignore`](docs/config-note.md) configuration option to ignore files matching the given path globs when indexing notes.
```yaml
[note]
ignore = [
"log-*.md"
"drafts/*"
]
```
### Fixed
* [#16](https://github.com/zk-org/zk/issues/16) Links with section anchors, e.g. `[[filename#section]]`.
* Unicode support in wiki links. If you use accents or ideograms, please run `zk index --force` after upgrading to fix your index.
## 0.5.0
### Added
* [Editor integration through LSP](https://github.com/zk-org/zk/issues/22):
* New code actions to create a note using the current selection as title.
* Custom commands to [run `new` and `index` from your editor](docs/editors-integration.md#custom-commands).
* Diagnostics to [report dead links or wiki link titles](docs/config-lsp.md).
* Auto-complete only the path of a Markdown link by typing `[custom title]((`.
* Customize the format of `fzf`'s lines [with your own template](docs/tool-fzf.md).
* Automatically index the notebook when saving a note with an LSP-enabled editor.
* This ensures that tags and notes auto-completion lists are up-to-date.
### Fixed
* Creating a new note from `fzf` in a directory containing spaces.
* Fix completion with Neovim's built-in LSP client (contributed by [@cormacrelf](https://github.com/zk-org/zk/pull/39)).
## 0.4.0
@ -10,18 +287,18 @@ All notable changes to this project will be documented in this file.
* Interactive wizard for the `zk init` command.
* An experimental Language Server for LSP-compatible editors:
* Auto-complete Markdown links with `[[` (setup wiki-links in the [note formats configuration](docs/note-format.md))
* Auto-complete Markdown links with `[[` (setup wikilinks in the [note formats configuration](docs/note-format.md))
* Auto-complete [hashtags and colon-separated tags](docs/tags.md).
* Preview the content of a note when hovering a link.
* Navigate in your notes by following internal links.
* [And more to come...](https://github.com/mickael-menu/zk/issues/22)
* [And more to come...](https://github.com/zk-org/zk/issues/22)
* See [the documentation](docs/editors-integration.md) for configuration samples.
* Pair `--match` with `--exact-match` / `-e` to search for (case insensitive) exact occurrences in your notes.
* This can be useful when looking for terms including special characters, such as `[[name]]`.
* Generating links to notes.
* Use the `{{link}}` template variable when [formatting notes](docs/template-format.md) to print a link to the note, relative to the working directory.
* Use the `{{format-link path title}}` template helper to render a custom link.
* Customize the link format from the [note formats settings](docs/note-format.md). You can for example choose regular Markdown links, Wiki-links or a custom format.
* Customize the link format from the [note formats settings](docs/note-format.md). You can for example choose regular Markdown links, wiki links or a custom format.
### Changed
@ -59,7 +336,7 @@ All notable changes to this project will be documented in this file.
### Fixed
* [#4](https://github.com/mickael-menu/zk/issues/4) Terminal borked when piping content with Vim
* [#4](https://github.com/zk-org/zk/issues/4) Terminal borked when piping content with Vim
## 0.2.1
@ -92,3 +369,4 @@ All notable changes to this project will be documented in this file.
* Renamed `--linking-to` filtering option to `--link-to`.
* Multiple `--extra` variables are now separated by `,` instead of `;`.
- `CGO_ENABLED=1` enables CGO, which is required by the `mattn/go-sqlite3` dependency.
- `GOARCH=arm64` is only required for Apple Silicon chips.
- `-tags "fts5"` enables the FTS option with `mattn/go-sqlite3`, which handles much of the magic behind `zk`'s `--match` filtering option.
- ``-ldflags "-X=main.Version=`git describe --tags --match v[0-9]* 2> /dev/null` -X=main.Build=`git rev-parse --short HEAD`"`` will automatically set `zk`'s build and version numbers using the latest Git tag and commit SHA.
### Automated tests
The project is vetted with two different kind of automated tests: unit tests and end-to-end tests.
#### Unit tests
Unit tests are using the standard [Go testing library](https://pkg.go.dev/testing). To execute them, use the command `make test`.
They are ideal for testing parsing output or individual API edge cases and minutiae.
#### End-to-end tests
Most of `zk`'s functionality is tested with functional tests ran with [`tesh`](https://github.com/mickael-menu/tesh), which you can execute with `make tesh` (or `make teshb`, to debug whitespaces changes).
When addressing a GitHub issue, it's a good idea to begin by creating a `tesh` file in `tests/issue-XXX.tesh`. If a starting notebook state is required, it can be added under `tests/fixtures`.
If you modify the output of `zk`, you may disrupt some `tesh` files. You can use `make tesh-update` to automatically update them with the correct output.
### CI workflows
Several GitHub action workflows are executed when pull requests are merged or releases are created.
- `.github/workflows/build.yml` checks that the project can be built and the tests still pass.
- `.github/workflows/codeql.yml` runs static analysis to vet code quality.
- `.github/workflows/gh-pages.yml` deploy the documentation files to GitHub Pages.
- `.github/workflows/release.yml` submits a new version to Homebrew when a Git version tag is created.
- `.github/workflows/triage.yml` automatically tags old issues and PRs as staled.
## Releasing a new version
When `zk` is ready to be released, you can update the `CHANGELOG.md` ([for example](https://github.com/zk-org/zk/commit/ea4457ad671aa85a6b15747460c6f2c9ad61bf73)) and create a new Git version tag (for example `v0.13.0`). Make sure you follow the [Semantic Versioning](https://semver.org) scheme.
Then, create [a new GitHub release](https://github.com/zk-org/zk/releases) with a copy of the latest `CHANGELOG.md` entries and the binaries for all supported platforms.
Binaries can be created automatically using `make dist-linux` and `make dist-macos`.
Unfortunately, `make dist-macos` must be run manually on both an Apple Silicon and Intel chips. The Linux builds are created using Docker and [these custom images](https://github.com/zk-org/zk-xcompile), which are hosted via [ghcr.io within zk-org](https://github.com/orgs/zk-org/packages/container/package/zk-xcompile).
This process is convoluted because `zk` requires CGO with `mattn/go-sqlite3`, which prevents using Go's native cross-compilation. Transitioning to a CGO-free SQLite driver such as [cznic/sqlite](https://gitlab.com/cznic/sqlite) could simplify the distribution process significantly.
## Documentation
TODO: add documentation steps for Sphinx docs, after it's all working.
<p>Looking for a quick usage example? <ahref="docs/getting-started.md">Let's get started</a>.</p>
</div>
## Description
`zk` is a command-line tool helping you to maintain a plain text [Zettelkasten](https://zettelkasten.de/introduction/) or [personal wiki](https://en.wikipedia.org/wiki/Personal_wiki).
Looking for a [quick usage example?](https://zk-org.github.io/zk/tips/getting-started.html)
Or want to see it in action? Checkout [Shivan's](https://github.com/shivan-s)
video, [_Note-taking System ALL Programmers Should Consider_](https://www.youtube.com/watch?v=UzhZb7e4l4Y).
### Highlights
* [Creating notes from templates](docs/note-creation.md)
* [Advanced search and filtering capabilities](docs/note-filtering.md) including [tags](docs/tags.md), links and mentions
* [Integration with your favorite editors](docs/editors-integration.md):
* [`zk.nvim`](https://github.com/megalithic/zk.nvim) for Neovim 0.5+, maintained by [Seth Messer](https://github.com/megalithic)
* [`zk-vscode`](https://github.com/mickael-menu/zk-vscode) for Visual Studio Code
* [Future-proof, thanks to Markdown](docs/future-proof.md)
* [Creating notes from templates](https://zk-org.github.io/zk/notes/note-creation.html)
* [Advanced search and filtering capabilities](https://zk-org.github.io/zk/notes/note-filtering.html) including [tags](https://zk-org.github.io/zk/notes/tags.html), links and mentions
* [Integration with your favorite editors](https://zk-org.github.io/zk/tips/editors-integration.html):
[See the changelog](CHANGELOG.md) for the list of upcoming features waiting to be released.
### What `zk` is not
* A note editor.
* A tool to serve your notes on the web – for this, you may be interested in [Neuron](docs/neuron.md) or [Gollum](https://github.com/gollum/gollum).
* A tool to serve your notes on the web – for this, you may be interested in [Neuron](docs/tips/neuron.md) or [Gollum](https://github.com/gollum/gollum).
## Install
[Check out the latest release](https://github.com/mickael-menu/zk/releases) for pre-built binaries for macOS and Linux (`zk` was not tested on Windows).
### Build from scratch
[Check out the latest release](https://github.com/zk-org/zk/releases) for pre-built binaries for macOS and Linux (`zk` was not tested on Windows).
Make sure you have a working [Go installation](https://golang.org/), then clone the repository:
`zk` was designed with automation in mind and strive to be [a good Unix citizen](https://en.wikipedia.org/wiki/Unix_philosophy). As such, it offers a number of ways to interface with other programs:
* write [command aliases](config-alias.md) or [named filters](config-filter.md) for repeated complex commands
* [call `zk` from other programs](external-call.md)
* [send notes for processing by other programs](external-processing.md)
* [create a note with initial content](note-creation.md) from a standard input pipe
If you find out that `zk` does not behave as expected or could communicate better with other programs, [please post an issue](https://github.com/mickael-menu/zk/issues).
* modifying a [template](template.md)'s output dynamically depending on the value of an extra variable
## Static extra variables
You can declare static extra variables in the [configuration file](config.md)'s `[extra]` section. Each [note group](config-group.md) can have its own `[extra]` section, which may override values from the root section.
```toml
[extra]
visibility = "public"
author = "Mickaël"
[group.journal.extra]
visibility = "private" # overrides
```
## Dynamic extra variables
Maybe more useful, you can provide additional extra variables dynamically to `zk new` from the command-line with `--extra`. Multiple variables can be separated by a comma `,`.
```sh
$ zk new --extra author=Thomas
$ zk new --extra show-header=1,author=Thomas
```
## Using extra variables in templates
After declaring extra variables, you can expand them inside the [template used when creating new notes](template-creation.md), using the usual [Handlebars syntax](template.md).
A *group* is a named [configuration section](config.md) used to override [note creation rules](config-note.md) for specific directories. This allows you to use your [notebook](notebook.md) very differently depending on the type of note created. For a practical example, take a look at [maintaining a daily journal](daily-journal.md).
## Declaring a new group
To add a new group to your configuration file, declare a new `[group.<name>]` section. It takes a single optional property `paths`, which is the list of directories belonging to this group.
```toml
[group.journal]
paths = [
"journal/daily",
"journal/weekly"
]
```
You can also use [glob patterns](https://en.wikipedia.org/wiki/Glob_\(programming\)) in `paths`.
```toml
[group.journal]
paths = ["journal/*"]
```
If you omit `paths`, the directory named after the group will be inferred. Note the double quotes when using spaces or slashes for subdirectories.
```toml
# This will automatically apply to the `citations/web` directory
[group."citations/web"]
```
## Overriding note configuration and extra variables
You can override the global [note configuration](config-note.md) and [extra user variables](config-extra.md) for a given group.
```toml
[group.journal.note]
filename = "{{date now}}"
template = "journal.md"
[group.journal.extra]
author = "Mickaël"
```
## Choose a group dynamically
If you prefer to keep multiple groups in a single directory, you can specify which group to use when creating a new note explicitly.
A command alias is a custom `zk` command which can run another `zk` command or an external program.
A command alias is a custom `zk` command which can run another `zk` command or
an external program.
Declaring your own aliases is a great way to make your experience with `zk` easier and more familiar. With aliases, `zk` becomes a hub capable of launching all the programs you need to manage your [notebook](notebook.md).
Declaring your own aliases is a great way to make your experience with `zk`
easier and more familiar. With aliases, `zk` becomes a hub capable of launching
all the programs you need to manage your [notebook](../notes/notebook.md).
## Configuring aliases
Command aliases are declared in your [configuration file](config.md), under the `[alias]` section. They are executed with `$SHELL -c`, which allows you to:
Command aliases are declared in your [configuration file](config.md), under the
`[alias]` section. They are executed with [your default shell](tool-shell.md),
which allows you to:
* expand arguments with `$@` or `$*`
* expand environment variables
* run several commands with `&&`
* pipe several commands with `|`
- expand arguments with `$@` or `$*`
- [it is recommended to wrap `$@` in quotes](https://github.com/zk-org/zk/issues/316#issuecomment-1543564168)
- expand environment variables
- run several commands with `&&`
- pipe several commands with `|`
An alias can call other aliases but cannot call itself. This enables you to override the default options of native commands, for example:
An alias can call other aliases but cannot call itself. This enables you to
override the default options of native commands, for example:
```toml
[alias]
edit = "zk edit --interactive $@"
edit = 'zk edit --interactive "$@"'
```
When running an alias, the `ZK_NOTEBOOK_DIR` environment variable is set to the absolute path of the current notebook. You can use it to run commands working no matter the location of the working directory.
When running an alias, the `ZK_NOTEBOOK_DIR` environment variable is set to the
absolute path of the current notebook. You can use it to run commands working no
matter the location of the working directory.
```toml
journal = 'zk new "$ZK_NOTEBOOK_DIR/journal"'
```
If you need to surround the path with quotes, make sure you use double quotes, otherwise environment variables will not be expanded.
If you need to surround the path with quotes, make sure you use double quotes,
otherwise environment variables will not be expanded.
### `xargs` formula
Calling an external program with a list of note paths using `xargs` is such a common use case that we can extract a reusable alias pattern.
Calling an external program with a list of note paths using `xargs` is such a
common use case that we can extract a reusable alias pattern.
```toml
alias = "zk list --quiet --format path --delimiter0 $@ | xargs -0 <EXTERNALCOMMAND>"
```
Find more details about these options in [Send notes for processing by other programs](external-processing.md).
Find more details about these options in
[Send notes for processing by other programs](../tips/external-processing.md).
## Collection of useful aliases
@ -52,7 +64,8 @@ n = "zk new $@"
### Edit the last modified note
Suffixing the `modified` sort criterion with `-` orders the notes by *descendent* modification date.
Suffixing the `modified` sort criterion with `-` orders the notes by
### Edit the notes created during the last two weeks
This command uses `--interactive` to let the user select which notes to actually edit among the recent ones. Note the use of human friendly language for `--created-after`'s argument.
This command uses `--interactive` to let the user select which notes to actually
edit among the recent ones. Note the use of human friendly language for
`--created-after`'s argument.
In this case, additional arguments do not necessarily make sense, so we omit the trailing `$@`.
In this case, additional arguments do not necessarily make sense, so we omit the
Use this alias to send a list of space-separated file paths matching the given [filtering criteria](note-filtering.md) to another program. See [send notes for processing by other programs](external-processing.md) for more details.
Use this alias to send a list of space-separated file paths matching the given
[filtering criteria](../notes/note-filtering.md) to another program. See
[send notes for processing by other programs](../tips/external-processing.md) for more
Increasing serendipity while using your notebook is important to spark new ideas. The `random` sort criterion is the key to this alias.
Increasing serendipity while using your notebook is important to spark new
ideas. The `random` sort criterion is the key to this alias.
```toml
lucky = "zk list --quiet --format full --sort random --limit 1"
@ -114,7 +136,9 @@ lucky = "zk list --quiet --format full --sort random --limit 1"
### Create a note from a free title
If you often create notes with `zk new --title "An interesting concept"`, you will like this alias. Using `"$*"`, you do not need to quote the arguments anymore.
If you often create notes with `zk new --title "An interesting concept"`, you
will like this alias. Using `"$*"`, you do not need to quote the arguments
anymore.
```toml
nt = 'zk new --title "$*"'
@ -126,7 +150,8 @@ No more forgotten quotes!
### Create a note and save its path into the clipboard (macOS)
Build upon the previous alias, but instead of editing the created note it will copy the created note's path into the macOS clipboard.
Build upon the previous alias, but instead of editing the created note it will
copy the created note's path into the macOS clipboard.
### Print and sort the word count of selected notes
This will list the notes and their word count sorted by increasing word count. It is useful to spot flimsy notes that you could flesh out.
This will list the notes and their word count sorted by increasing word count.
It is useful to spot flimsy notes that you could flesh out.
```toml
wc = "zk list --format '{{word-count}}\t{{title}}' --sort word-count $@"
@ -161,9 +187,12 @@ bl = "zk list --link-to $@"
### Locate unlinked mentions in a note
This alias can help you look for potential new links to establish, by listing every note whose title is mentioned in the note you are working on but which are not already linked to it.
This alias can help you look for potential new links to establish, by listing
every note whose title is mentioned in the note you are working on but which are
not already linked to it.
Note that we are using a single argument `$1` which is repeated for both options.
Note that we are using a single argument `$1` which is repeated for both
options.
```toml
unlinked-mentions = "zk list --mentioned-by $1 --no-linked-by $1"
This alias does not call `zk` at all! This shows how you can use `zk` as a hub for everything related to your notes.
This alias does not call `zk` at all! This shows how you can use `zk` as a hub
for everything related to your notes.
```toml
save = 'git add . && git commit -m "$*"'
@ -189,9 +219,12 @@ Usage: `zk save Expand the note on command aliases`
### Copy/backup selected notes
A more complex example backing up the notes matching the given filtering criteria in a target directory. It creates intermediate directories if needed.
A more complex example backing up the notes matching the given filtering
criteria in a target directory. It creates intermediate directories if needed.
`$1` and `${@:2}` are used to split the arguments between the first one which will be the destination directory, and the remaining arguments which will be used as filtering options.
`$1` and `${@:2}` are used to split the arguments between the first one which
will be the destination directory, and the remaining arguments which will be
A named filter is a set of [note filtering options](note-filtering.md) used frequently together, declared in the [configuration file](config.md).
A named filter is a set of [note filtering options](../notes/note-filtering.md)
used frequently together, declared in the [configuration file](config.md).
For example, if you use regularly the following command to list your most recent notes:
For example, if you use regularly the following command to list your most recent
notes:
```sh
$ zk list --sort created- --created-after "last two weeks"
```
You can create a new named filter in the configuration file to avoid repeating yourself.
You can create a new named filter in the configuration file to avoid repeating
yourself.
```toml
[filter]
recents = "--sort created- --created-after 'last two weeks'"
```
Then, you can use the name as an argument of `zk list`, with any additional option.
Then, you can use the name as an argument of `zk list`, with any additional
option.
```sh
$ zk list recents --limit 10
```
Named filters are similar to [command aliases](config-alias.md), as they simplify frequent commands. However, named filters can be used with any command accepting filtering options.
Named filters are similar to [command aliases](config-alias.md), as they
simplify frequent commands. However, named filters can be used with any command
In filtering commands, named filters take precedence over path arguments. As a nice side effect, this means you can customize the default filtering options for a directory by naming a filter after it.
In filtering commands, named filters take precedence over path arguments. As a
nice side effect, this means you can customize the default filtering options for
a directory by naming a filter after it.
For example, by default `zk` sorts notes by their titles. However, if you keep daily notes under a `journal/` directory, you may want to sort them by creation date instead. You can use the following named filter for this:
For example, by default `zk` sorts notes by their titles. However, if you keep
daily notes under a `journal/` directory, you may want to sort them by creation
date instead. You can use the following named filter for this:
```
[filter]
journal = "--sort created journal"
```
Named filters cannot call themselves recursively, so by adding the `journal` argument to the filter, we are actually selecting the `journal/` directory. This means that the following commands are equivalent:
Named filters cannot call themselves recursively, so by adding the `journal`
argument to the filter, we are actually selecting the `journal/` directory. This
The `[note]` section from the [configuration file](config.md) is used to set the [note creation rules](note-creation.md). The following properties are customizable:
The `[note]` section from the [configuration file](config.md) is used to set the [note creation rules](../notes/note-creation.md). The following properties are customizable:
* `language` (string)
* Two-letters code of the language used when writing notes, e.g. `en`.
@ -8,14 +8,16 @@ The `[note]` section from the [configuration file](config.md) is used to set the
* `default-title` (string)
* The default title used for new notes when no `--title` option is provided.
* `filename` (string)
* [Template](template.md) used to generate the note filename, without its file extension.
* [Template](../notes/template.md) used to generate the note filename, without its file extension.
* `extension` (string)
* File extension for the generated note. By default, `md` (Markdown) is used.
* `template` (string)
* Path to the [template](template.md) used to generate the note content.
* Path to the [template](../notes/template.md) used to generate the note content.
* Either an absolute path, or relative to `.zk/templates/`.
* `exclude` (list of strings)
* List of [path globs](https://en.wikipedia.org/wiki/Glob_\(programming\)) excluded during note indexing.
* `id-charset` (string)
* Characters set used to [generate random IDs](note-id.md).
* Characters set used to [generate random IDs](../notes/note-id.md).
* You can use:
* `letters` for characters from `a` to `z`
* `numbers` for characters from `0` to `9`
@ -33,8 +35,8 @@ The `[note]` section from the [configuration file](config.md) is used to set the
Here are some common filename patterns you may want to use:
* `{{id}}`– e.g. `i2hn8.md`
* Just a [random ID](note-id.md), simple and elegant.
* To use [Neuron](neuron.md)'s ID format, set:
* Just a [random ID](../notes/note-id.md), simple and elegant.
* To use [Neuron](../tips/neuron.md)'s ID format, set:
```toml
[note]
id-charset = "hex"
@ -42,14 +44,14 @@ Here are some common filename patterns you may want to use:
id-case = "lower"
```
* `{{slug title}}`– e.g. `an-interesting-concept.md`
* A [slugified](template.md) version of the title given with `--title`.
* A [slugified](../notes/template.md) version of the title given with `--title`.
* Readable and practical for web servers, but fragile in case of renaming.
* `{{id}}-{{slug title}}`– e.g. `i2hn8-an-interesting-concept.md`
* The best of both worlds? Readable but if you link only with the prefix ID, you can rename without breaking links.
* `{{date now 'timestamp'}}` – e.g. `200911172034.md`
* `{{format-date now 'timestamp'}}` – e.g. `200911172034.md`
* Verbose, but sortable by creation date and stable.
* `{{date now 'timestamp'}} {{title}}` – e.g. `200911172034 An interesting concept.md`
* `{{format-date now 'timestamp'}} {{title}}` – e.g. `200911172034 An interesting concept.md`
* The format of [The Archive](https://zettelkasten.de/the-archive/) and [sirupsen's zk](https://github.com/sirupsen/zk).
* `{{date now '%Y-%m-%d'}}` – e.g. `2009-11-17.md`
* `{{format-date now '%Y-%m-%d'}}` – e.g. `2009-11-17.md`
* Sortable, human-friendly format for a daily journal.
* i.e. [Maintaining a daily journal](daily-journal.md).
* i.e. [Maintaining a daily journal](../tips/daily-journal.md).
Each [notebook](notebook.md) contains a configuration file used to customize your experience with `zk`. This file is located at `.zk/config.toml` and uses the [TOML format](https://github.com/toml-lang/toml). It is composed of several optional sections:
Each [notebook](../notes/notebook.md) contains a configuration file used to customize your experience with `zk`. This file is located at `.zk/config.toml` and uses the [TOML format](https://github.com/toml-lang/toml). It is composed of several optional sections:
* `[notebook]` configures the [default notebook](config-notebook.md)
* `[note]` sets the [note creation rules](config-note.md)
* `[extra]` contains free [user variables](config-extra.md) which can be expanded in templates
* `[group]` defines [note groups](config-group.md) with custom rules
* `[format]` configures the [note format settings](note-format.md), such as Markdown options.
* `[format]` configures the [note format settings](../notes/note-format.md), such as Markdown options
* `[tool]` customizes interaction with external programs such as:
* [your default editor](tool-editor.md)
* [your default shell](tool-shell.md)
* [your default pager](tool-pager.md)
* [`fzf`](tool-fzf.md)
* `[lsp]` setups the [Language Server Protocol settings](config-lsp.md) for [editors integration](../tips/editors-integration.md)
* `[filter]` declares your [named filters](config-filter.md)
* `[alias]` holds your [command aliases](config-alias.md)
@ -24,6 +27,10 @@ Notebook configuration files will inherit the settings defined in the global con
Here's an example of a complete configuration file:
Let's assume you want to write daily notes named like `2021-02-16.md` in a `journal/daily` sub-directory. This common use case is a good fit for creating a [note group](config-group.md) overriding the default [note creation](note-creation.md) settings.
First, create a `group` entry in the [configuration file](config.md) to set the note settings for this directory. Refer to the [template syntax reference](template.md) to understand how to use the `{{date}}` helper.
```toml
[group.daily]
# Directories listed here will automatically use this group when creating notes.
paths = ["journal/daily"]
[group.daily.note]
# %Y-%m-%d is actually the default format, so you could use {{date now}} instead.
filename = "{{date now '%Y-%m-%d'}}"
extension = "md"
template = "daily.md"
```
Next, create a template file under `.zk/templates/daily.md` to render the note content. Here we used the date again to generate a title like "February 16, 2021".
```markdown
# {{date now "long"}}
What did I do today?
```
We are now ready to write today's note! We don't need to set `--title` since the note's title is entirely generated by the template.
```sh
$ zk new journal/daily
```
That is a bit of a mouthful for a command called every day. Would it not be better to just write `zk daily`? We can, by defining a [command alias](config-alias.md) in the [configuration file](config.md).
```toml
[alias]
daily = 'zk new --no-input "$ZK_NOTEBOOK_DIR/journal/daily"'
```
Let's unpack this alias:
* `zk new` will refuse to overwrite notes. If you already created today's note, it will instead ask you if you wish to edit it. Using `--no-input` skips the prompt and edit the existing note right away.
* `$ZK_NOTEBOOK_DIR` is set to the absolute path of the current [notebook](notebook.md) when running an alias. Using it allows you to run `zk daily` no matter where you are in the notebook folder hierarchy.
* We need to use double quotes around `$ZK_NOTEBOOK_DIR`, otherwise it will not be expanded.
There are several extensions available to integrate `zk` in your favorite editor:
* [`zk.nvim`](https://github.com/megalithic/zk.nvim) for Neovim 0.5+, maintained by [Seth Messer](https://github.com/megalithic)
* [`zk-vscode`](https://github.com/mickael-menu/zk-vscode) for Visual Studio Code
## Language Server Protocol
`zk` ships with a [Language Server](https://microsoft.github.io/language-server-protocol/overviews/lsp/overview/) to provide basic support for any LSP-compatible editor. The currently supported features are:
* Auto-complete Markdown links with `[[` (setup wiki-links in the [note formats configuration](note-format.md))
* Auto-complete [hashtags and colon-separated tags](tags.md).
* Preview the content of a note when hovering a link.
* Navigate in your notes by following internal links.
* [And more to come...](https://github.com/mickael-menu/zk/issues/22)
To start the Language Server, use the `zk lsp` command. Refer to the following sections for editor-specific examples. [Feel free to share the configuration for your editor](https://github.com/mickael-menu/zk/issues/22).
### Vim and Neovim
#### Vim and Neovim 0.4
With [`coc.nvim`](https://github.com/neoclide/coc.nvim), run `:CocConfig` and add the following in the settings file:
```jsonc
{
// Important, otherwise link completion containing spaces and other special characters won't work.
"suggest.invalidInsertCharacters": [],
"languageserver": {
"zk": {
"command": "zk",
"args": ["lsp"],
"trace.server": "messages",
"filetypes": ["markdown"]
},
}
}
```
#### Neovim 0.5 built-in LSP client
Using [`nvim-lspconfig`](https://github.com/neovim/nvim-lspconfig):
-- Add keybindings here, see https://github.com/neovim/nvim-lspconfig#keybindings-and-completion
end })
```
### Sublime Text
Install the [Sublime LSP](https://github.com/sublimelsp/LSP) package, then run the **Preferences: LSP Settings** command. Add the following to the settings file:
`zk` is designed to be future-proof and rely on simple [plain text formats](note-format.md) such as Markdown.
The shape of your [notebook](notebook.md) is entirely up to you, making `zk` flexible enough to be used in a variety of contexts. However, `zk` shines in a Zettelkasten-style notebook with many small interlinked notes.
Create a [notebook](notebook.md) to host your notes. You are free to organize your notebook as you want, adding subdirectories if needed.
```sh
$ zk init my-notes
Initialized a notebook in my-notes
$ cd my-notes
```
## Create your first notes
Now you are ready to write your very first note. Pick a subject, [create a new note](note-creation.md) and write on!
```sh
$ zk new --title "An interesting concept"
```
You can customize your experience using [custom templates](template.md) to generate many kind of notes.
<divalign="center"><imgalt="Create a note"width="85%"src="assets/media/new1.svg"/></div>
If you are not sure whether a note already exists for a particular subject, the "search or create" mode might be more appropriate than `zk new`. It is inspired by [Notational Velocity](https://notational.net/) and enables searching for an existing note or creating a new one in a single action.
From `zk`'s interactive edit screen, press `Ctrl-N` to create a new note using the current search query as title.
<divalign="center"><imgalt="Create a note"width="85%"src="assets/media/new2.svg"/></div>
## List existing notes
After some time, hopefully you will have enough notes to be lost in it. Use `zk`'s powerful [filtering capabilities](note-filtering.md) to find the notes you need.
```sh
$ zk list --tag "recipe" --match "pizza -pineapple"
```
<divalign="center"><imgalt="Format the list output"width="85%"src="assets/media/list.svg"/></div>
Sort the results however you need with `--sort`.
<divalign="center"><imgalt="Format the list output"width="85%"src="assets/media/list-sort.svg"/></div>
`--format` and `--delimiter` offer some versatile formatting options to customize the output.
<divalign="center"><imgalt="Format the list output"width="85%"src="assets/media/list-format.svg"/></div>
`zk` is aware of the links you set between your notes. You can use the linking options to find the backlinks or outbound links of a note. It even supports listing indirect links thanks to `--recursive`.
<divalign="center"><imgalt="Format the list output"width="85%"src="assets/media/list-link.svg"/></div>
`zk` supports an interactive mode powered by [`fzf`](https://github.com/junegunn/fzf) to further filter notes manually.
<divalign="center"><imgalt="Format the list output"width="85%"src="assets/media/list-interactive.svg"/></div>
## Edit existing notes
To edit notes with your default editor, use `zk edit`. It supports the same [filtering options](note-filtering.md) as `zk list`.
You can add a new note to a [notebook](notebook.md) using `zk new --title "An interesting concept" [<directory>]`.
`zk` automatically generates a filename and initial content according to rules set in your [configuration file](config.md). These settings can be customized per [group of notes](config-group.md) in your notebook, as illustrated in [Maintaining a daily journal](daily-journal.md).
By default, `zk new` will start [your editor](tool-editor.md) after creating the note. You can choose instead to print the absolute path to the note with `--print-path`, which is more useful for [automation](automation.md).
## Search or create with a single command
If you are not sure whether a note already exists for a particular subject, the "search or create" mode might be more appropriate than `zk new`. It is inspired by [Notational Velocity](https://notational.net/) and enables searching for an existing note or creating a new one in a single action.
This option is available when running `zk edit --interactive`, which spawns [`fzf`](tool-fzf.md) to filter selected notes. From `fzf`, press `Ctrl-N` to create a new note using the current search query as title.
## Create a note with initial content
Initial content can be fed to the template through a standard input pipe, which will be expandable with the `{{content}}` [template variable](template-creation.md).
For example, to use the content of the macOS clipboard as the initial content you can run:
A few commands are built upon `zk`'s powerful note filtering capabilities, such as `edit` and `list`. They accept any option described here. You may also declare [named filters](config-filter.md) in the [configuration file](config.md) for the same set of options you use frequently.
## Filter by path
All filtering commands take for unique positional argument a list of paths. When set, only the notes matching the given paths will be returned.
You can use it to find all the notes in a directory.
```sh
$ zk list journal/daily journal/weekly
```
Or specific notes.
```sh
$ zk edit 200911172034-an-interesting-concept.md
```
It works fine with only a path prefix as well. This is useful when you have a [note ID](note-id.md) prefix, but not the full file path.
```sh
$ zk edit 200911172034
```
These rules apply to all the following options, when they expect a `<path>` parameter.
```sh
$ zk list --link-to 200911172034
```
You can also use a nested `zk` command to pre-filter paths to feed to an option with a `<path>` argument. [See the `inline` command alias example](config-alias.md) for more explanation.
```sh
# List the notes which have at least one link pointing to them (i.e. not orphans).
$ zk list --exclude "`zk inline --orphan`"
# List the notes which are linked by at least one note from the journal/ directory.
$ zk list --linked-by "`zk inline journal`"
```
## Search the title or body
Use `--match <query>` (or `-m`) to search through the title and body of notes.
The search is powered by a [full-text search](https://en.wikipedia.org/wiki/Full-text_search) database enabling near-instant results. Queries are not case-sensitive and terms are tokenized, which means that searching for `create` will also match `created` and `creating`.
A syntax similar to Google Search is available for advanced search queries.
### Combining terms
By default, the search engine will find the notes containing all the terms in the query, in any order.
```
"tesla edison"
```
If you want to find the notes containing any or both of the terms, put `OR` (all caps) or a pipe `|` between them.
```
"tesla OR edison"
"tesla | edison"
```
Search for an exact phrase by surrounding it with double quotes. In this case, you will need to single quote the full query if you do not want to escape the double quotes.
```
'tesla "alternating current"'
```
To construct more complex queries, you can group sub-queries with parentheses.
```
"current (tesla OR edison)"
```
Finally, you can filter out results by excluding a term with `NOT` (all caps) or a `-` prefix.
```
"tesla NOT car"
"tesla -car"
```
### Search in specific fields
If you want to search only in the title or body of notes, prefix a query with `title:` or `body:`.
```
"title: tesla"
"body: (tesla OR edison)"
```
### Prefix terms
Match any term beginning with the given prefix with a wildcard `*`.
```
"edi*"
```
Prefixing a query with `^` will match notes whose title or body start with the following term.
```
"title: ^journal"
```
### Search for special characters
If you need to find patterns containing special characters, such as an `email@addre.ss` or a `[[wiki-link]]`, use the `--exact-match` / `-e` option. The search will be case-insensitive.
```
$ zk list --exact-match --match "[[link]]"
$ zk list -em "[[link]]"
```
## Filter by tags
You can filter your notes by their [tags](tags.md) using `--tags` (or `-t`).
Find the notes having several tags by separating them with a comma.
```sh
$ zk list --tag "history, europe"
```
To match notes having either or both tags, use a pipe `|` or `OR` (all caps).
```sh
$ zk list --tag "inbox OR todo"
```
If you want to exclude notes having a particular tag instead, prefix it with `-` or `NOT` (all caps).
```sh
$ zk list --tag "NOT done"
```
Your shell might give you some trouble using the `-` prefix. You can quote it and add an extra space as a workaround, e.g. `--tag " -done"`.
Finally, you can use glob patterns to match multiple tags. This is particularly useful if you use a separator (e.g. `/`) to group multiple tags under a parent tag.
```sh
$ zk list --tag "year/201*"
```
## Filter by creation or modification date
To find notes created or modified on a specific day, use `--created <date>` and `--modified <date>`. They accept a human-friendly date for argument.
```
--created yesterday
--created "last tuesday"
--modified "Feb 3"
```
You can filter by range instead, using `--created-before`, `--created-after`, `--modified-before` and `--modified-after`.
You can use the following options to explore the web of links spanning your [notebook](notebook.md).
`--linked-by <path>` (or `-L`) finds the notes linked by the given one, while `--link-to <path>` (or `-l`) searches the notes having a link to it (also known as *backlinks*).
```
--linked-by 200911172034
--link-to 200911172034
```
These options stop at the first level by default. But you can explore the whole web by adding the `--recursive` (or `-r`) option to find all the notes leading to (or from) a given note. If you feel overwhelmed, limit the distance between two notes with `--max-distance <count>`.
Finally, it can be useful to see which notes have no links pointing to them at all. You can use the `--orphan` option for this.
## Find related notes
Part of writing a great notebook is to establish links between related notes. The `--related <path>` option can help by listing results having a linked note in common, but not yet connected to the note.
```
--related 200911172034
```
## Locate mentions of other notes
Another great way to look for potential new links is to find every mention of other notes in the note you are currently working on.
```
--mentioned-by 200911172034
```
This option will find every note whose title is mentioned in the given note. To refer to a note using several names, you can use the [YAML frontmatter](note-frontmatter.md) to declare additional aliases. For example, a note titled "Artificial Intelligence" might have for aliases "AI" and "robot". This method is compatible with [Obsidian](https://publish.obsidian.md/help/How+to/Add+aliases+to+note).
```
---
title: Artificial Intelligence
aliases: [AI, robot]
---
```
Alternatively, find every note mentioning the given note with `--mention`.
```
--mention 200911172034
```
To find only unlinked mentions, pair the `--mentioned-by` and `--mentions` options with `--no-linked-by` (resp. `--no-link-to`) to remove notes which are already linked from the results.
To prevent certain notes from polluting the results, you can explicitly exclude them with `--exclude <path>` (or `-x`). This is particularly useful when you have a whole directory of notes to be ignored.
```
-x journal
```
## Limit the number of results
If you are only interested into the first few notes, limit the number of results with `--limit <count>` (or `-n`).
```
--limit 20
```
Using `-n1` is particularly common when you are expecting only a single result.
## Interactive filtering
A common search flow is to reduce the search scope using `zk`'s filtering options, before selecting manually the notes to process among them. This is especially useful with `zk edit` to avoid opening many unwanted notes with your editor.
Use `--interactive` (or `-i`) to select filtered notes manually. The interactive selection is handled by [`fzf`](tool-fzf.md) which brings a powerful fuzzy matching search into the mix.
## Sort the results
After finding matching notes, it might be useful to sort them before processing. The `--sort <criteria>` (or `-s`) option is made for that.
You can add a `+` (ascending) or `-` (descending) suffix to a sort criterion to customize the order. Each criterion has a sensible intrinsic order by default.
To keep your notebooks [future-proof](future-proof.md), `zk` uses a simple plain text format for your notes. Only Markdown is supported at the moment, but more formats may be added in the future.
## Markdown
You can set up some features of `zk`'s Markdown parser from your [configuration file](config.md), under the `[format.markdown]` section.
### Customizing the Markdown links generated by `zk`
By default, `zk` will generate regular Markdown links for internal links. If you prefer to use `[[Wiki Links]]` instead, set the `link-format` setting to `wiki`. If you want to override completely the link format, you can also set `link-format` to a [custom template](template.md). Two variables `path` and `title` are available in the template, for example to generate a wiki-link with a title:
Each note is uniquely identified by its path relative to the [notebook](notebook.md)'s root. However, in some cases it is more convenient to refer to a "note ID", which is the unique part of its filename. For example, the note ID of the file `200911172034 An interesting concept.md` is `200911172034`. You could have several notes named "An interesting concept", but only one with the ID `200911172034`.
The purpose of using a unique identifier in your note filenames is to create stable links between your notes, which will not break even if you change the title of the linked note. [See this reference for more information](https://zettelkasten.de/introduction/#the-unique-identifier).
There are several flavors of note IDs and `zk` supports most of them. You can set it up in the [note configuration](config-note.md).
## Random ID
A random ID enables short and memorable unique identifiers. By default, `zk` is configured to generate random IDs of four alphanumeric characters. I found this to be the sweet spot between an easily memorable and usable ID and enough candidates. This default setting can generate 1 679 616 unique IDs.
## Timestamp
Another common ID is a timestamp in the `YYYYMMDDHHMM` shape. This is less readable than a short random ID, but has the added advantage of being sortable by creation date. However, I find this not so useful in practice.
## Sequential IDs
Sequential (incremented) IDs are currently not supported by `zk`. They get ugly very quickly when deleting outdated notes and have an irregular shape.
A *notebook* is a directory containing a collection of notes managed by `zk`. Notebooks cannot be nested, but you are free to organize your notes in subdirectories.
To create a new notebook, simply run `zk init [<directory>]`.
Most `zk` commands are operating "Git-style" on the notebook containing the current working directory (or one of its parents). However, you can explicitly set which notebook to use with `--notebook-dir` or the `ZK_NOTEBOOK_DIR` environment variable. Setting `ZK_NOTEBOOK_DIR` in your shell configuration (e.g. `~/.profile`) can be used to define a default notebook which `zk` commands will use when the working directory is not in another notebook.
## Anatomy of a notebook
Similarly to Git, a notebook is identified by the presence of a `.zk` directory at its root. This directory contains the only `zk`-specific files in your notebook:
* `.zk/config.toml` is the user [configuration file](config.md)
* `.zk/templates/` contains [user templates](template.md) used when [creating new notes](note-creation.md)
* `.zk/notebook.db` is the SQLite database enabling [powerful search features](note-filtering.md).
Markdown being a simple format, it does not offer any way to attach additional metadata to a note. The community came up with a solution by inserting a YAML header at the top of each note to contain its metadata. This method is widely supported among Zettelkasten softwares, including `zk`.
Markdown being a simple format, it does not offer any way to attach additional
metadata to a note. The community came up with a solution by inserting a YAML
header at the top of each note to contain its metadata. This method is widely
supported among Zettelkasten softwares, including `zk`.
| `title` | Title of the note – takes precedence over the first heading |
| `date` | Creation date – takes precedence over the file date |
| `tags` | List of tags attached to this note |
| `keywords` | Alias for `tags` |
| `aliases` | Alternative titles for this note, used by `--mention` |
All metadata are indexed and can be printed in `zk list` output, using the template variable `{{metadata.<key>}}`, e.g. `{{metadata.description}}`. The keys are normalized to lower case.
All metadata are indexed and can be printed in `zk list` output, using the
template variable `{{metadata.<key>}}`, e.g. `{{metadata.description}}`. The
`zk` uses the [Handlebars template syntax](https://handlebarsjs.com/guide) for its templates. The list of variables available depends of the running command:
* [Template context when creating notes](template-creation.md) (i.e. `zk new`)
* [Template context when formatting a note](template-format.md) (i.e. `zk list --format <template>`)
## Additional helpers
Besides the default Handlebars helpers, `zk` ships with additional helpers which you might find useful. They are available to all templates.
### Format Link helper
The `{{format-link}}` helper renders an internal link to another note, according to the user preferences set in the [note formats configuration](note-format.md).
The `{{date}}` helper formats the given date for display.
Template contexts usually provide a `now` variable which can be used to print the current date.
The default format output by `{{date <variable>}}` looks like `2009-11-17`, but you can choose a different format by providing a second argument, e.g. `{{date now "medium"}}`.
| `timestamp` | 200911172034 | Useful for sortable filenames |
| `timestamp-unix` | 1258490098 | Number of seconds since January 1, 1970 |
| `elapsed` | 12 years ago | Time elapsed since then in human-friendly format |
If none of the provided formats suit you, you can use a custom format using `strftime`-style placeholders, e.g. `{{date now "%m-%d-%Y"}}`. See `man strftime` for a list of placeholders.
### Slug helper
The `{{slug}}` helper generates a URL friendly version of a text. For example, `{{slug "This will be slugified!"}}` becomes `this-will-be-slugified`.
This is mostly useful to generate a safe filename containing the title passed to `zk new --title "An interesting note"`. With the [`filename`](config-note.md) template `{{slug title}}`, it becomes `an-interesting-note.md`.
### Prepend helper
The `{{prepend}}` helper adds a prefix to every line of the given text or block. You can use it to generate a Markdown quote, for example:
```
{{prepend "> " "A quote"}}
{{#prepend "> "}}
A multiline
quote.
{{/prepend}}
```
### Shell helper
The `{{sh}}` helper will call the given shell command and insert its output in the template. Your imagination is the limit!
```
Get today's events from your calendar:
{{sh "icalBuddy -b '* ' -nc eventsToday"}}
Insert a random quote:
{{prepend '> ' (sh 'fortune')}}
Download today's weather:
{{sh 'curl http://wttr.in/?0'}}
```
When used as a block helper, the block content will be passed to the command through a standard input pipe.
```
Will output "HELLO, WORLD!":
{{#sh "tr '[a-z]' '[A-Z]'"}}
Hello, world!
{{/sh}}
```
### Style helper
The `{{style}}` helper is mostly useful when formatting content for the command-line. See the [styling rules](style.md) for more information.
| `created` | string | No | Find notes created on the given date |
| `createdBefore` | string | No | Find notes created before the given date |
| `createdAfter` | string | No | Find notes created after the given date |
| `modified` | string | No | Find notes modified on the given date |
| `modifiedBefore` | string | No | Find notes modified before the given date |
| `modifiedAfter` | string | No | Find notes modified after the given date |
| `sort` | string array | No | Order the notes by the given criterion |
1. As the output of this command might be very verbose and put a heavy load on the LSP client, you need to explicitly set which note fields you want to receive with the `select` option. The following fields are available: `filename`, `filenameStem`, `path`, `absPath`, `title`, `lead`, `body`, `snippets`, `rawContent`, `wordCount`, `tags`, `metadata`, `created`, `modified` and `checksum`.
</details>
`zk.list` returns the found notes as a JSON array.
#### `zk.tag.list`
This LSP command calls `zk tag list` to return the list of tags in a notebook.
It takes two arguments:
1. A path to any file or directory in the notebook, to locate it.
2. <details><summary>(Optional) A dictionary of additional options (click to expand)</summary>
A great way to expand `zk` feature set is to explore a wealth of command-line tools available. You can use `zk`'s powerful [searching and filtering](note-filtering.md) capabilities to select notes before delegating further processing to other programs.
A great way to expand `zk` feature set is to explore a wealth of command-line
tools available. You can use `zk`'s powerful
[searching and filtering](../notes/note-filtering.md) capabilities to select notes before
delegating further processing to other programs.
## Process file paths
Many programs expect file paths for input. You can interface with such program using the `path` list format and a space delimiter.
Many programs expect file paths for input. You can interface with such program
using the `path` list format and a space delimiter.
```sh
$ zk list --format path --delimiter " "
```
If the file paths can contain spaces, you may want to quote manually the paths, using the `{{path}}` [template variable](template-format.md) instead:
If the file paths can contain spaces, you may want to quote manually the paths,
using the `{{path}}` [template variable](../notes/template-format.md) instead:
```sh
$ zk list --format "'{{path}}'" --delimiter " "
```
As always, this is such a useful [command alias](config-alias.md) to have:
As always, this is such a useful [command alias](../config/config-alias.md) to have:
Some programs – such as `xargs`– work better when file paths are separated by the ASCII NUL character (`\0`). In this case, you can use the `--delimiter0` (or `-0`) option.
Some programs – such as `xargs`– work better when file paths are separated by
the ASCII NUL character (`\0`). In this case, you can use the `--delimiter0` (or
`-0`) option.
For example, this command prints the full Git history of the notes:
Some `zk` options such as `--exclude` also take file paths for parameters. Let's increase their flexibility by nesting `zk` calls. In this case, the delimiter will be `,`.
Some `zk` options such as `--exclude` also take file paths for parameters. Let's
increase their flexibility by nesting `zk` calls. In this case, the delimiter
will be `,`.
For example, this command lists the notes which are linked by at least one other note – so the notes which are *not* orphans.
For example, this command lists the notes which are linked by at least one other
note – so the notes which are _not_ orphans.
```sh
$ zk list --exclude "`zk list -q -f path -d "," --orphan`"
```
And this one finds the notes which are linked by at least one note in `journal/`.
And this one finds the notes which are linked by at least one note in
`journal/`.
```sh
$ zk list --linked-by "`zk list -q -f path -d "," journal`"
@ -48,11 +59,14 @@ $ zk list --linked-by "`zk list -q -f path -d "," journal`"
## Process the content of a note
If you want to directly transform the content instead, you may use the `raw-content` template variable, which will print the full content of the note file.
If you want to directly transform the content instead, you may use the
`raw-content` template variable, which will print the full content of the note
file.
In this particular case, we usually want to process only one note at a time. You can make sure that `zk list` will print only the first note from the result with `--limit 1` (or `-n1`).
In this particular case, we usually want to process only one note at a time. You
can make sure that `zk list` will print only the first note from the result with
While there is some overlap with `zk`'s features, both tools are actually useful when paired together:
* `zk` has powerful [filtering](note-filtering.md) and [note generation](note-creation.md) capabilities
* `zk` has powerful [filtering](../notes/note-filtering.md) and [note generation](../notes/note-creation.md) capabilities
* Neuron shines with its static website generation
Close integration with Neuron was thought through from the start when designing `zk`. For example, Neuron's [Folgezettel](https://neuron.zettel.page/folgezettel.html) syntax is supported: `[[[link]]]`, `#[[link]]` and `[[link]]#`.
<!-- TODO: They automatically add a `from` or `to` link relation when used. -->
But you can make your [notebook](notebook.md) even more tightly integrated with Neuron by:
But you can make your [notebook](../notes/notebook.md) even more tightly integrated with Neuron by:
* using the [same settings as Neuron](https://neuron.zettel.page/id.html) to generate the [note IDs](note-id.md) in the [note configuration](config-note.md)
* using the [same settings as Neuron](https://neuron.zettel.page/id.html) to generate the [note IDs](../notes/note-id.md) in the [note configuration](../config/config-note.md)
```toml
[note]
filename = "{{id}}"
@ -21,9 +21,13 @@ But you can make your [notebook](notebook.md) even more tightly integrated with
id-length = 8
id-case = "lower"
```
* adding [command aliases](config-alias.md) for your frequently used `neuron` commands
* adding [command aliases](../config/config-alias.md) for your frequently used `neuron` commands
```toml
[alias]
serve = "neuron gen -wS"
gen = "neuron gen -o public"
```
## Emanote
Emanote is neuron's successor. For Emanote-specific configuration, see https://emanote.srid.ca/start/resources/zk.
Tending to your notes does not only mean writing. You need to keep your [notebook](notebook.md) in great shape to make good use of it. For many maintenance tasks, `zk` can help!
Tending to your notes does not only mean writing. You need to keep your
[notebook](../notes/notebook.md) in great shape to make good use of it. For many
maintenance tasks, `zk` can help!
## Find related notes
To surf your notebook with ease, make sure to link all related notes together. You can list notes which could be good candidates for a new link with the `--related` [filtering option](note-filtering.md).
To surf your notebook with ease, make sure to link all related notes together.
You can list notes which could be good candidates for a new link with the
This returns notes which are not connected to the given note, but with at least one linked note in common.
This returns notes which are not connected to the given note, but with at least
one linked note in common.
## Find flimsy notes
To find flimsy notes needing to be fleshed out, you can list the first few notes with the smallest word count from your notebook with the following command:
To find flimsy notes needing to be fleshed out, you can list the first few notes
with the smallest word count from your notebook with the following command:
```sh
$ zk list --format '{{word-count}}\t{{title}}' --sort word-count --limit 20
[`fzf`](https://github.com/junegunn/fzf) is an awesome and versatile fuzzy finder powering `zk`'s [interactive filtering mode](note-filtering.md).
Besides the standard [`fzf` configuration options](https://github.com/junegunn/fzf) documented on its website, `zk` offers additional options you can set in the `[tool]` [configuration section](config.md).
If you wish to customize more of `fzf` behavior, [please post a feature request](https://github.com/mickael-menu/zk/issues).
## Preview command
You can customize the command used to preview a note with `fzf-preview`. The special placeholder `{-1}` will be expanded to the note file path.
By default, `zk` uses `cat` for preview, which is a bit boring. A much better option would be to use [`bat`](https://github.com/sharkdp/bat) which supports syntax highlighting.
```toml
[tool]
fzf-preview = "bat -p --color always {-1}"
```
Or, if you prefer to preview more metadata, you can use a nested `zk` command.
```toml
[tool]
fzf-preview = "zk list --quiet --format full --limit 1 {-1}"
When `zk`'s output exceeds a certain limit, it is automatically paginated by your system pager. By default, `less` is used but you may set up your own pager in the [configuration file](config.md) or environment variables. In order of precedence, `zk` will use:
1. `ZK_PAGER` environment variable
2. `pager` configuration property
```toml
[tool]
pager = "less -FIRX"
```
3. `PAGER` environment variable
## Disable the pager
If you need to disable paging, you can either:
* use `--no-pager`
* set the `pager` configuration property to an empty string `""`