Compare commits

...

65 Commits

Author SHA1 Message Date
Sören Tempel 00a4361d20
Determine fixture path using the current working directory (#422) 3 days ago
Tillman Jex 578894f45b
release zk v0.14.1 (#417) 3 weeks ago
Tillman Jex e21519a1b4
readme: exit maintenance mode, add logo, contributing (#416) 3 weeks ago
Tillman Jex cfa74a7f0c
update Makefile (go 1.21 and alpine), update contributing.md (#412) 3 weeks ago
Tillman Jex 8e2add0606
raise sqlite version for musl build compatibility (#414) 4 weeks ago
guangwu bf5cad60dc
chore: pkg imported more than once (#410)
Signed-off-by: guoguangwu <guoguangwug@gmail.com>
Co-authored-by: tjex <tjex@tjex.net>
1 month ago
Alexis Praga c3f26ca12b
Doc: how to edit today's daily note (#407)
documentation daily note tutorial extra detail
2 months ago
Tillman Jex 0973f9929d
allow notebook as hidden dir (#402) 2 months ago
dependabot[bot] 45b68121ce
Bump actions/configure-pages from 4 to 5 (#398)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tillman Jex <tjex@tjex.net>
2 months ago
Tadeas Uhlir c9d4734d3c
fix(lsp): ignore diagnostic check within code blocks (#399)
Co-authored-by: tjex <tjex@tjex.net>
2 months ago
Tadeas Uhlir 05c50a70d5
fix(lsp): fix trigger completion of zk LSP (#397) 3 months ago
Tillman Jex b10d51dbc2
accept tripple dash file URIs as valid links (#391)
Co-authored-by: Jurica Bacurin <jurica@bacurin.de>
3 months ago
Tillman Jex 56f4e650ea
git: ignore delve debug files (#396) 3 months ago
Sumit Sahrawat 6a06ded3c4
Fix hyperlink from `README.md` to `docs/getting-started.md` (#395) 3 months ago
Kyle Huggins 1471c6be2c
Update documentation to restore GitHub Pages functionality (#387) 5 months ago
Tillman Jex d4e542b70c
tesh test case for yaml dates without time stamp (#385) 5 months ago
Tillman Jex 537c7f7554
fix day range parsing (zk-org/zk#382) (#384) 5 months ago
Michael McDonagh 55d5487d24
Fix broken links (#381) 5 months ago
dependabot[bot] f7079be6c0
Bump actions/stale from 7 to 9 (#365)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tillman Jex <tjex@tjex.net>
5 months ago
dependabot[bot] a1f2a701af
Bump github/codeql-action from 2 to 3 (#367)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Tillman Jex <tjex@tjex.net>
5 months ago
dependabot[bot] 70a9afb9f5
Bump actions/setup-go from 4 to 5 (#363)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
5 months ago
Michael McDonagh 0eaf26483f
Remove references to old repo (#373)
Finalise transfer from old repo (github.com/mickael-menu/zk) to new (github.com/zk-org/zk)

Co-authored-by: tjex <tjex@tjex.net>
5 months ago
Julio Lopez 5a2333d0af
test: add TestFormatDateHelperElapsed (#359)
improve and extend test coverage in handlebars_test.go, which deals with time and date formatting.
5 months ago
Mickaël Menu e3e52dfe69
Add `CONTRIBUTING.md` (#378) 5 months ago
Julio Lopez 87f3680a9b
chore(ci): use Go 1.21 (#360)
Co-authored-by: Jurica Bacurin <jurica@bacurin.de>
5 months ago
dependabot[bot] f120f9546c
Bump golang.org/x/crypto from 0.0.0-20220525230936-793ad666bf5e to 0.17.0 (#368)
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.
5 months ago
Tillman Jex 5bb1c0ba89
Maintenance mode callout fix (#377) 5 months ago
Tillman Jex 1e28fe4b92
notification of maintenance mode (#376)
update readme to communicate maintenance mode due to project handover
5 months ago
Michael McDonagh 50fb638dd9
Update the arch repo link (#372) 5 months ago
Michael McDonagh 7ba9df6526
Relative output needs relative input (#374) 6 months ago
Julio Lopez be1249d7a6
Use 'go-version-file' option in build workflow (#355) 7 months ago
Julio Lopez 228c96fcea
Address io/ioutil deprecation (#354) 7 months ago
dependabot[bot] 1fd1298c00
Bump actions/checkout from 3 to 4 (#344)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
9 months ago
khimaros 0b4db9ade6
Fix parsing large notes (#339) 10 months ago
Mickaël Menu 072fae2f6c
Fix `{{date}}` helper test (#324) 1 year ago
Mickaël Menu b71a74eabc Release zk 0.14.0 1 year ago
Mickaël Menu 1ec777de7e Update documentation of config alias 1 year ago
Mickaël Menu 75205fe099
Rename `note.ignore` config property to `note.exclude` (#322) 1 year ago
wrvsrx 6252e51595
Fix LSP positions using UTF-16 offsets (#317) 1 year ago
Leonardo Mello e26ac5133e
Add `notebook` configuration to set default notebook path (#304) 1 year ago
Leonardo Mello a8d1db4c57
Add `tool.shell` configuration key (#302) 1 year ago
dependabot[bot] ba611e1c1e
Bump actions/setup-go from 3 to 4 (#299) 1 year ago
Mickaël Menu 39bcb8069f
Bump go-sqlite3 (#296) 1 year ago
dependabot[bot] 89ff022593
Bump golang.org/x/text from 0.3.7 to 0.3.8 (#292) 1 year ago
Mickaël Menu ea4457ad67 Release zk 0.13.0 1 year ago
Cyril Dutrieux 6401a4e1f6
Add "title" to the Command in code actions (#288) 1 year ago
Patrick Anker f7d4db07d6
Add `zk.link` LSP command (#284) 1 year ago
Leiser Fernández Gallo 150c82fb22
Fix emanote URL (#283) 1 year ago
Matthias Vogelgesang 279f9ef3cd
Add `zk-spaced` to list of related projects (#281) 1 year ago
dependabot[bot] 6506198743
Bump actions/stale from 6 to 7 (#277) 2 years ago
Mickaël Menu ae3a86dbfa
Add new options for LSP command `zk.new` (#276) 2 years ago
Mickaël Menu d79da8933a Release zk 0.12.0 2 years ago
Mickaël Menu 15d4cfc921
Rename the `{{date}}` helper to `{{format-date}}` (#274) 2 years ago
Oliver Marriott 142b636342
Support multiple `--match` flags (#268) 2 years ago
Oliver Marriott 9d88245102
Fix `--working-dir=` and `--notebook-dir=` options parsing (#267) 2 years ago
Zach Leslie 404ef9d6f5
Add the `get-date` template helper (#262) 2 years ago
Mickaël Menu c21c4fc21f
LSP: Add support for external URLs with `documentLink` (#261) 2 years ago
dependabot[bot] cdf4f8e0c1
Bump actions/stale from 5 to 6 (#258) 2 years ago
Mickaël Menu 1745097256
Fix error when pairing `--link-to` and `--linked-by` (#255) 2 years ago
Sridhar Ratnakumar 9faec3628a
neuron.md: Add link to docs for Emanote (#247) 2 years ago
Kristof Lünenschloß 814a5d7c07
Link to mickael-menu/zk-nvim instead of megalithic/zk.nvim (#249) 2 years ago
bibor ab1d8fd0bd
LSP: Fix double use of `notebook.RelPath` (#246) 2 years ago
Mickaël Menu 61b9c0f5d7
LSP: Fix finding backlink references for notes in a folder (#245) 2 years ago
Mickaël Menu 78c40eeecf Release zk 0.11.1 2 years ago
Pete Kazmier a6e522562e
Add explicit flag to read from standard input (#242) 2 years ago

@ -0,0 +1,19 @@
title: "[Help] "
body:
- type: checkboxes
id: checks
attributes:
label: Verify
options:
- 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.

@ -0,0 +1,14 @@
body:
- type: checkboxes
id: checks
attributes:
label: Verify
options:
- label: I searched the existing discussions for similar ideas
required: true
- type: textarea
id: help
attributes:
label: Share your idea or feature request
validations:
required: true

@ -0,0 +1,65 @@
name: Bug report
description: File a bug report to help improve zk.
body:
- type: markdown
attributes:
value: |
Thank you for filing a bug report!
- type: checkboxes
id: checks
attributes:
label: Check if applicable
description: |
:warning: My time is limited and if I don't plan on fixing the reported bug myself, I might close this issue. No hard feelings.
:heart: But if you would like to contribute a fix yourself, **I'll be happy to guide you through the codebase and review a pull request**.
options:
- label: I have searched the existing issues (**required**)
required: true
- label: I'm willing to help fix the problem and contribute a pull request
- type: textarea
id: bug-description
attributes:
label: Describe the bug
description: Also tell me, what did you expect to happen?
placeholder: A clear and concise description of what the bug is.
validations:
required: true
- type: textarea
id: bug-steps
attributes:
label: How to reproduce?
description: |
Step by step explanation to reproduce the issue.
If you can, drag and drop:
- a zipped sample notebook
- screenshots or a screencast showing the issue
placeholder: |
1. Add a note with the content "..."
2. Run `zk edit --interactive`
3. See error
...
validations:
required: true
- type: textarea
id: vim-config
attributes:
label: zk configuration
description: |
Paste the minimal `zk` configuration file (`.zk/config.toml`) reproducing the issue.
render: toml
validations:
required: true
- type: textarea
id: bug-environment
attributes:
label: Environment
description: |
Run the following shell commands and paste the result here:
```
zk --version && echo "system: `uname -srmo`"
```
placeholder: |
zk 0.13.0
system: Darwin 22.5.0 arm64
render: bash

@ -0,0 +1,10 @@
name: Feature request
description: Suggest an idea for this project.
body:
- type: checkboxes
id: checks
attributes:
label: If you have an idea, open a discussion
options:
- label: I will [create a new discussion](https://github.com/zk-org/zk/discussions/new?category=ideas) instead of an issue.

@ -0,0 +1,13 @@
name: User support
description: You need help?
body:
- 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.
- 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.

@ -11,14 +11,14 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
lfs: 'true'
- name: Set up Go
uses: actions/setup-go@v3
uses: actions/setup-go@v5
with:
go-version: 1.18
go-version-file: 'go.mod'
- name: Install dependencies
run: |

@ -26,15 +26,15 @@ jobs:
steps:
- name: Checkout repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Initialize CodeQL
uses: github/codeql-action/init@v2
uses: github/codeql-action/init@v3
with:
languages: ${{ matrix.language }}
- name: Autobuild
uses: github/codeql-action/autobuild@v2
uses: github/codeql-action/autobuild@v3
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v2
uses: github/codeql-action/analyze@v3

@ -0,0 +1,43 @@
name: Deploy to GitHub Pages
on:
release:
types:
- "published"
permissions:
contents: read
pages: write
id-token: write
concurrency:
group: "pages"
cancel-in-progress: false
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Pages
uses: actions/configure-pages@v5
- name: Fix anchor tag in README
run: ex -s -c '%s/docs\/getting-started\.md/docs\/getting-started/|x' README.md
- name: Build with Jekyll
uses: actions/jekyll-build-pages@v1
with:
source: ./
destination: ./_site
- name: Upload artifact
uses: actions/upload-pages-artifact@v3
deploy:
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
needs: build
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4

@ -11,7 +11,7 @@ jobs:
runs-on: macos-latest
steps:
- name: Checkout repo
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Update Homebrew formula
uses: dawidd6/action-homebrew-bump-formula@v3
with:

@ -16,7 +16,7 @@ jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v5
- uses: actions/stale@v9
with:
days-before-stale: 30

3
.gitignore vendored

@ -11,6 +11,9 @@
# Output of the go coverage tool, specifically when used with LiteIDE
*.out
# Delve debug files
*__debug_bin*
# Dependency directories (remove the comment below to include it)
# vendor/

@ -2,7 +2,79 @@
All notable changes to this project will be documented in this file.
<!--## Unreleased-->
## Unreleased
## 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
@ -27,10 +99,10 @@ All notable changes to this project will be documented in this file.
### Fixed
* [#233](https://github.com/mickael-menu/zk/issues/233) Hide index progress in non-interactive shells.
* [#235](https://github.com/mickael-menu/zk/issues/235) Fix LSP link recognition with unicode (contributed by [@zkbpkp](https://github.com/mickael-menu/zk/issues/235)).
* [#236](https://github.com/mickael-menu/zk/issues/236) Fix updating links after creating a new note.
* [#239](https://github.com/mickael-menu/zk/discussions/239) Support standard input via shell redirection with `zk new`.
* [#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
@ -49,15 +121,15 @@ 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.
* New `--id` flag for `zk new` to skip ID generation and use a provided value (contributed by [@skbolton](https://github.com/mickael-menu/zk/pull/183)).
* [#144](https://github.com/mickael-menu/zk/issues/144) LSP auto-completion of YAML frontmatter tags.
* [zk-nvim#26](https://github.com/mickael-menu/zk-nvim/issues/26) The LSP server doesn't use `additionalTextEdits` anymore to remove the trigger characters when completing links.
* 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/mickael-menu/zk/issues/163) Use the `ZK_SHELL` environment variable to override the shell for `zk` only.
* [#173](https://github.com/mickael-menu/zk/issues/173) Support for double star globbing in `note.ignore` config option.
* [#137](https://github.com/mickael-menu/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/mickael-menu/zk/pull/154)).
* [#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/mickael-menu/zk/discussions/168) Customize the `fzf` key binding to create new notes with the [`fzf-bind-new`](docs/tool-fzf.md) config option.
* [#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
@ -65,10 +137,10 @@ All notable changes to this project will be documented in this file.
### Fixed
* [#126](https://github.com/mickael-menu/zk/issues/126) Embedded image links shown as not found.
* [#152](https://github.com/mickael-menu/zk/issues/152) Incorrect timezone for natural dates.
* [#170](https://github.com/mickael-menu/zk/issues/170) Broken wiki links in subdirectories.
* [#185](https://github.com/mickael-menu/zk/issues/185) Don't parse a Markdown table header as a colon tag.
* [#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
@ -82,10 +154,10 @@ All notable changes to this project will be documented in this file.
### Fixed
* [#111](https://github.com/mickael-menu/zk/issues/111) Filenames take precedence over folders when matching a sub-path with wiki links.
* [#118](https://github.com/mickael-menu/zk/issues/118) Fix infinite loop when parsing a single-character hashtag.
* [#121](https://github.com/mickael-menu/zk/issues/121) Take into account the `--no-input` flag with `zk init`.
* [#120](https://github.com/mickael-menu/zk/discussions/120) Support RFC 3339 dates with the time flags (e.g. `--created-before`).
* [#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
@ -110,9 +182,9 @@ All notable changes to this project will be documented in this file.
### Fixed
* [#89](https://github.com/mickael-menu/zk/issues/89) Calling `zk index` from outside the notebook (contributed by [@adamreese](https://github.com/mickael-menu/zk/pull/90)).
* [#98](https://github.com/mickael-menu/zk/issues/98) Index wiki links using partial paths for `--linked-by` and `--link-to`.
* [#98](https://github.com/mickael-menu/zk/issues/98) Ignore spaces around the pipe in wiki links for LSP diagnostics.
* [#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
@ -134,7 +206,7 @@ All notable changes to this project will be documented in this file.
[[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/mickael-menu/zk/pull/60)).
* 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`
@ -142,9 +214,9 @@ All notable changes to this project will be documented in this file.
### Fixed
* UTF-8 handling in the LSP server.
* [#78](https://github.com/mickael-menu/zk/issues/78) Do not exclude notes containing broken links from the index.
* [#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/mickael-menu/zk/issues/86) Index encoded Markdown links.
* [#86](https://github.com/zk-org/zk/issues/86) Index encoded Markdown links.
## 0.6.0
@ -158,7 +230,7 @@ All notable changes to this project will be documented in this file.
* `{{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/mickael-menu/zk/pull/58)).
* 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]
@ -170,7 +242,7 @@ All notable changes to this project will be documented in this file.
### Fixed
* [#16](https://github.com/mickael-menu/zk/issues/16) Links with section anchors, e.g. `[[filename#section]]`.
* [#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.
@ -178,7 +250,7 @@ All notable changes to this project will be documented in this file.
### Added
* [Editor integration through LSP](https://github.com/mickael-menu/zk/issues/22):
* [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).
@ -197,7 +269,7 @@ All notable changes to this project will be documented in this file.
### 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/mickael-menu/zk/pull/39)).
* Fix completion with Neovim's built-in LSP client (contributed by [@cormacrelf](https://github.com/zk-org/zk/pull/39)).
## 0.4.0
@ -210,7 +282,7 @@ All notable changes to this project will be documented in this file.
* 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]]`.
@ -255,7 +327,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

@ -0,0 +1,62 @@
# Contributing to `zk`
## Understanding the codebase
### Building the project
It is recommended to use the `Makefile` for compiling the project, as the `go` command requires a few parameters.
```shell
make build
```
This will be expanded to the following command:
```shell
CGO_ENABLED=1 GOARCH=arm64 go build -tags "fts5" -ldflags "-X=main.Version=`git describe --tags --match v[0-9]* 2> /dev/null` -X=main.Build=`git rev-parse --short HEAD`"
```
- `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.

@ -22,6 +22,9 @@ teshb: build
tesh-update: build
PATH=".:$(shell pwd):$(PATH)" tesh -u tests tests/fixtures
alpine:
$(call alpine,build)
# Produce a release bundle for all platforms.
dist: dist-macos dist-linux
rm -f zk
@ -31,10 +34,31 @@ dist-macos:
rm -f zk && make && zip -r "zk-${VERSION}-macos-`uname -m`.zip" zk
# Produce a release bundle for Linux.
dist-linux:
rm -f zk && docker run --platform linux/amd64 --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk mickaelmenu/zk-xcompile:linux-i386 /bin/bash -c 'make' && tar -zcvf "zk-${VERSION}-linux-i386.tar.gz" zk
rm -f zk && docker run --platform linux/amd64 --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk mickaelmenu/zk-xcompile:linux-amd64 /bin/bash -c 'make' && tar -zcvf "zk-${VERSION}-linux-amd64.tar.gz" zk
rm -f zk && docker run --platform linux/amd64 --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk mickaelmenu/zk-xcompile:linux-arm64 /bin/bash -c 'make' && tar -zcvf "zk-${VERSION}-linux-arm64.tar.gz" zk
dist-linux: dist-linux-amd64 dist-linux-arm64 dist-linux-i386 dist-alpine-amd64 dist-alpine-arm64 dist-alpine-i386
dist-linux-amd64:
rm -f zk \
&& docker run --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk ghcr.io/zk-org/zk-xcompile:linux-amd64 /bin/bash -c 'make' \
&& tar -zcvf "zk-${VERSION}-linux-amd64.tar.gz" zk
dist-linux-arm64:
rm -f zk \
&& docker run --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk ghcr.io/zk-org/zk-xcompile:linux-arm64 /bin/bash -c 'make' \
&& tar -zcvf "zk-${VERSION}-linux-arm64.tar.gz" zk
dist-linux-i386:
rm -f zk \
&& docker run --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk ghcr.io/zk-org/zk-xcompile:linux-i386 /bin/bash -c 'make' \
&& tar -zcvf "zk-${VERSION}-linux-i386.tar.gz" zk
dist-alpine-amd64:
rm -f zk \
&& docker run --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk ghcr.io/zk-org/zk-xcompile:alpine-amd64 /bin/bash -c 'make alpine' \
&& tar -zcvf "zk-${VERSION}-alpine-amd64.tar.gz" zk
dist-alpine-arm64:
rm -f zk \
&& docker run --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk ghcr.io/zk-org/zk-xcompile:alpine-arm64 /bin/bash -c 'make alpine' \
&& tar -zcvf "zk-${VERSION}-alpine-arm64.tar.gz" zk
dist-alpine-i386:
rm -f zk \
&& docker run --rm -v "${PWD}":/usr/src/zk -w /usr/src/zk ghcr.io/zk-org/zk-xcompile:alpine-i386 /bin/bash -c 'make alpine' \
&& tar -zcvf "zk-${VERSION}-alpine-i386.tar.gz" zk
# Clean build products.
clean:
@ -55,3 +79,8 @@ define go
$(ENV_PREFIX) go $(1) -tags "fts5" -ldflags "-X=main.Version=$(VERSION) -X=main.Build=$(BUILD)" $(2)
endef
# Alpine (musl) requires statically linked libs. This should be compatible for
# Void linux and other musl based distros aswell.
define alpine
$(ENV_PREFIX) go $(1) -tags "fts5" -ldflags "-extldflags=-static -X=main.Version=$(VERSION) -X=main.Build=$(BUILD)" $(2)
endef

@ -1,10 +1,12 @@
<div align="center">
<h1>zk</h1>
<img alt="zk logo" width="20%" src="./docs/assets/media/zk-black-modern.png" />
<h4>A plain text note-taking assistant</h4>
<img alt="Screencast" width="95%" src="docs/assets/media/screencast.svg"/>
<p>Looking for a quick usage example? <a href="docs/getting-started.md">Let's get started</a>.</p>
</div>
Looking for a quick usage example? [Let's get started](docs/getting-started.md).
## 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).
@ -15,8 +17,8 @@
* [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):
* [Any LSP-compatible editor](docs/editors-integration.md)
* [`zk-nvim`](https://github.com/mickael-menu/zk-nvim) for Neovim 0.5+
* [`zk-vscode`](https://github.com/mickael-menu/zk-vscode) for Visual Studio Code
* [`zk-nvim`](https://github.com/zk-org/zk-nvim) for Neovim 0.8+
* [`zk-vscode`](https://github.com/zk-org/zk-vscode) for Visual Studio Code
* (*unmaintained*) [`zk.nvim`](https://github.com/megalithic/zk.nvim) for Neovim 0.5+ by [Seth Messer](https://github.com/megalithic)
* [Interactive browser](docs/tool-fzf.md), powered by `fzf`
* [Git-style command aliases](docs/config-alias.md) and [named filters](docs/config-filter.md)
@ -37,7 +39,7 @@
## 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).
[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).
### Homebrew
@ -62,7 +64,7 @@ nix-env -iA zk
### Arch Linux
You can install [the zk package](https://archlinux.org/packages/community/x86_64/zk/) from the official repos.
You can install [the zk package](https://archlinux.org/packages/extra/x86_64/zk/) from the official repos.
```sh
sudo pacman -S zk
@ -70,28 +72,29 @@ sudo pacman -S zk
### Build from scratch
Make sure you have a working [Go 1.18+ installation](https://golang.org/), then clone the repository:
Make sure you have a working [Go 1.21+ installation](https://golang.org/), then clone the repository:
```sh
$ git clone https://github.com/mickael-menu/zk.git
$ git clone https://github.com/zk-org/zk.git
$ cd zk
```
#### On macOS
#### On macOS / Linux
```
$ make
$ ./zk -h
```
#### On Linux
## Contributing
```
$ make
$ ./zk -h
```
We warmly welcome issues, PRs and [discussions](https://github.com/zk-org/zk/discussions).
Here you can read [some useful info for contributing to `zk`](./CONTRIBUTING.md).
## Related projects
* [Neuron](https://github.com/srid/neuron) a great tool to publish a Zettelkasten on the web
* [Emanote](https://emanote.srid.ca/) an improved successor to Neuron
* [sirupsen's zk](https://github.com/sirupsen/zk) a collection of scripts with a similar purpose
* [zk-spaced](https://github.com/matze/zk-spaced) spaced repetition plugin for zk

@ -0,0 +1,24 @@
title: "zk"
permalink: /:title
defaults:
- scope:
path: "README.md"
values:
title: "zk"
- scope:
path: "" # all
values:
render_with_liquid: false
exclude:
- ".github/"
- ".gitignore"
- "CHANGELOG.md"
- "CONTRIBUTING.md"
- "LICENSE"
- "Makefile"
- "go.mod"
- "go.sum"
- "internal/"
- "main.go"
- "tests/"

@ -1,2 +0,0 @@
permalink: /:title
theme: jekyll-theme-modernist

@ -1,57 +0,0 @@
<!doctype html>
<html lang="{{ site.lang | default: "en-US" }}">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
{% seo %}
<link rel="stylesheet" href="{{ '/assets/css/style.css?v=' | append: site.github.build_revision | relative_url }}">
<script src="{{ '/assets/js/scale.fix.js' | relative_url }}"></script>
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<!--[if lt IE 9]>
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
<![endif]-->
</head>
<body>
<div class="wrapper">
<header {% unless site.description or site.github.project_tagline %} class="without-description" {% endunless %}>
<h1><a href="https://mickael-menu.github.io/zk/">{{ site.title | default: site.github.repository_name }}</a></h1>
{% if site.description or site.github.project_tagline %}
<p>{{ site.description | default: site.github.project_tagline }}</p>
{% endif %}
<p class="view"><a href="{{ site.github.repository_url }}">View the Project on GitHub <small>{{ github_name }}</small></a></p>
<ul>
{% if site.show_downloads %}
<li><a href="{{ site.github.zip_url }}">Download <strong>ZIP File</strong></a></li>
<li><a href="{{ site.github.tar_url }}">Download <strong>TAR Ball</strong></a></li>
{% endif %}
<li><a href="{{ site.github.repository_url }}">View On <strong>GitHub</strong></a></li>
</ul>
</header>
<section>
{{ content }}
</section>
</div>
<footer>
{% if site.github.is_project_page %}
<p>Project maintained by <a href="{{ site.github.owner_url }}">{{ site.github.owner_name }}</a></p>
{% endif %}
</footer>
<!--[if !IE]><script>fixScale(document);</script><![endif]-->
{% if site.google_analytics %}
<script>
(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');
ga('create', '{{ site.google_analytics }}', 'auto');
ga('send', 'pageview');
</script>
{% endif %}
</body>
</html>

@ -1,9 +0,0 @@
---
---
@import "{{ site.theme }}";
code, pre {
font-size: inherit;
}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 40 KiB

After

Width:  |  Height:  |  Size: 40 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 29 KiB

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 167 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.9 KiB

@ -7,4 +7,4 @@
* [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).
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/zk-org/zk/issues).

@ -6,9 +6,10 @@ Declaring your own aliases is a great way to make your experience with `zk` easi
## 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 `$*`
* [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 `|`
@ -17,7 +18,7 @@ An alias can call other aliases but cannot call itself. This enables you to over
```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.

@ -34,7 +34,7 @@ You can override the global [note configuration](config-note.md) and [extra user
```toml
[group.journal.note]
filename = "{{date now}}"
filename = "{{format-date now}}"
template = "journal.md"
[group.journal.extra]

@ -14,8 +14,8 @@ The `[note]` section from the [configuration file](config.md) is used to set the
* `template` (string)
* Path to the [template](template.md) used to generate the note content.
* Either an absolute path, or relative to `.zk/templates/`.
* `ignore` (list of strings)
* List of [path globs](https://en.wikipedia.org/wiki/Glob_\(programming\)) ignored during note indexing.
* `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).
* You can use:
@ -48,10 +48,10 @@ Here are some common filename patterns you may want to use:
* 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).

@ -0,0 +1,15 @@
# Notebook configuration
The `[notebook]` section from the [configuration file](config.md) is used to set the default notebook directory.
If the path starts with `~` it will be replaced with the user home directory (`$HOME`). This property also supports environment variables.
```toml
[notebook]
dir = "~/notebook" # same as "$HOME/notebook"
```
The following properties are customizable:
* `dir` (string)
* Path of the default notebook.
* Only available in the global config file (`~/.config/zk/config.toml`).

@ -2,12 +2,14 @@
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:
* `[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
* `[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](editors-integration.md)
@ -25,6 +27,10 @@ Notebook configuration files will inherit the settings defined in the global con
Here's an example of a complete configuration file:
```toml
# NOTEBOOK SETTINGS
[notebook]
dir = "~/notebook"
# NOTE SETTINGS
[note]
@ -63,11 +69,11 @@ author = "Mickaël"
# GROUP OVERRIDES
[dir.journal]
[group.journal]
paths = ["journal/weekly", "journal/daily"]
[dir.journal.note]
filename = "{{date now}}"
[group.journal.note]
filename = "{{format-date now}}"
# MARKDOWN SETTINGS
@ -84,6 +90,9 @@ colon-tags = true
# Default editor used to open notes.
editor = "nvim"
# Default shell used by aliases and commands.
shell = "/bin/bash"
# Pager used to scroll through long output.
pager = "less -FIRX"
@ -114,4 +123,4 @@ lucky = "zk list --quiet --format full --sort random --limit 1"
wiki-title = "hint"
# Warn for dead links between notes.
dead-link = "error"
```
```

@ -2,7 +2,7 @@
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.
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 `{{format-date}}` helper.
```toml
[group.daily]
@ -10,8 +10,8 @@ First, create a `group` entry in the [configuration file](config.md) to set the
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'}}"
# %Y-%m-%d is actually the default format, so you could use {{format-date now}} instead.
filename = "{{format-date now '%Y-%m-%d'}}"
extension = "md"
template = "daily.md"
```
@ -19,7 +19,7 @@ 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"}}
# {{format-date now "long"}}
What did I do today?
```
@ -43,3 +43,7 @@ Let's unpack this alias:
* `$ZK_NOTEBOOK_DIR` is set to the absolute path of the current [notebook](notebook.md) when running an alias. Using it allows you to run `zk daily` no matter where you are in the notebook folder hierarchy.
* We need to use double quotes around `$ZK_NOTEBOOK_DIR`, otherwise it will not be expanded.
If you want to edit today's note, simply use this alias:
```sh
$ zk daily
```

@ -2,8 +2,8 @@
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
* [`zk-nvim`](https://github.com/zk-org/zk-nvim) for Neovim 0.5+
* [`zk-vscode`](https://github.com/zk-org/zk-vscode) for Visual Studio Code
## Language Server Protocol
@ -15,13 +15,13 @@ There are several extensions available to integrate `zk` in your favorite editor
* Navigate in your notes by following internal links.
* Create a new note using the current selection as title.
* Diagnostics for dead links and wiki-links titles.
* [And more to come...](https://github.com/mickael-menu/zk/issues/22)
* [And more to come...](https://github.com/zk-org/zk/issues/22)
You can configure some of these features in your notebook's [configuration file](config-lsp.md).
### Editor LSP configurations
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).
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/zk-org/zk/issues/22).
#### Vim and Neovim
@ -150,19 +150,21 @@ This LSP command calls `zk new` to create a new note. It can be useful to quickl
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>
| Key | Type | Description |
|------------------------|----------------------|-------------------------------------------------------------------------------------------|
| `title` | string | Title of the new note |
| `content` | string | Initial content of the note |
| `dir` | string | Parent directory, relative to the root of the notebook |
| `group` | string | [Note configuration group](config-group.md) |
| `template` | string | [Custom template used to render the note](template-creation.md) |
| `extra` | dictionary | A dictionary of extra variables to expand in the template |
| `date` | string | A date of creation for the note in natural language, e.g. "tomorrow" |
| `edit` | boolean | When true, the editor will open the newly created note (**not supported by all editors**) |
| `insertLinkAtLocation` | location<sup>1</sup> | A location in another note where a link to the new note will be inserted |
The `location` type is an [LSP Location object](https://microsoft.github.io/language-server-protocol/specification#location), for example:
| Key | Type | Description |
|---------------------------|----------------------|----------------------------------------------------------------------------------------------------------------------|
| `title` | string | Title of the new note |
| `content` | string | Initial content of the note |
| `dir` | string | Parent directory, relative to the root of the notebook |
| `group` | string | [Note configuration group](config-group.md) |
| `template` | string | [Custom template used to render the note](template-creation.md) |
| `extra` | dictionary | A dictionary of extra variables to expand in the template |
| `date` | string | A date of creation for the note in natural language, e.g. "tomorrow" |
| `edit` | boolean | When true, the editor will open the newly created note (**not supported by all editors**) |
| `dryRun` | boolean | When true, `zk` will not actually create the note on the file system, but will return its generated content and path |
| `insertLinkAtLocation` | location<sup>1</sup> | A location in another note where a link to the new note will be inserted |
| `insertContentAtLocation` | location<sup>1</sup> | A location in another note where the content of the new note will be inserted |
1. The `location` type is an [LSP Location object](https://microsoft.github.io/language-server-protocol/specification#location), for example:
```json
{
@ -175,7 +177,22 @@ This LSP command calls `zk new` to create a new note. It can be useful to quickl
```
</details>
`zk.new` returns a dictionary with the key `path` containing the absolute path to the newly created file.
`zk.new` returns a dictionary with two properties:
* `path` containing the absolute path to the created note.
* `content` containing the raw content of the created note.
#### `zk.link`
This LSP command allows editors to tap into the note linking mechanism. It takes three arguments:
1. A `path` to any file in the notebook that will be linked to
2. An LSP `location` object that points to where the link will be inserted
3. An optional title of the link. If `title` is not provided, the title of the note will be inserted instead
`zk.link` returns a JSON object with the path to the linked note, if the linking was successful.
**Note**: This command is _not_ exposed in the command line. This command is targeted at editor / plugin authors to extend zk functionality.
#### `zk.list`
@ -184,30 +201,31 @@ This LSP command calls `zk list` to search a notebook. It takes two arguments:
1. A path to any file or directory in the notebook, to locate it.
2. <details><summary>A dictionary of additional options (click to expand)</summary>
| Key | Type | Required? | Description |
|------------------|--------------|-----------|-------------------------------------------------------------------------|
| `select` | string array | Yes | List of note fields to return<sup>1</sup> |
| `hrefs` | string array | No | Find notes matching the given path, including its descendants |
| `limit` | integer | No | Limit the number of notes found |
| `match` | string | No | Terms to search for in the notes |
| `exactMatch` | boolean | No | Search for exact occurrences of the `match` argument (case insensitive) |
| `excludeHrefs` | string array | No | Ignore notes matching the given path, including its descendants |
| `tags` | string array | No | Find notes tagged with the given tags |
| `mention` | string array | No | Find notes mentioning the title of the given ones |
| `mentionedBy` | string array | No | Find notes whose title is mentioned in the given ones |
| `linkTo` | string array | No | Find notes which are linking to the given ones |
| `linkedBy` | string array | No | Find notes which are linked by the given ones |
| `orphan` | boolean | No | Find notes which are not linked by any other note |
| `related` | string array | No | Find notes which might be related to the given ones |
| `maxDistance` | integer | No | Maximum distance between two linked notes |
| `recursive` | boolean | No | Follow links recursively |
| `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 |
| Key | Type | Required? | Description |
| ------------------ | -------------- | ----------- | ------------------------------------------------------------------------- |
| `select` | string array | Yes | List of note fields to return<sup>1</sup> |
| `hrefs` | string array | No | Find notes matching the given path, including its descendants |
| `limit` | integer | No | Limit the number of notes found |
| `match` | string array | No | Terms to search for in the notes |
| `exactMatch` | boolean | No | (deprecated: use `matchStrategy`) Search for exact occurrences of the `match` argument (case insensitive) |
| `matchStrategy` | string | No | Specify match strategy, which may be "fts" (default), "exact" or "re" |
| `excludeHrefs` | string array | No | Ignore notes matching the given path, including its descendants |
| `tags` | string array | No | Find notes tagged with the given tags |
| `mention` | string array | No | Find notes mentioning the title of the given ones |
| `mentionedBy` | string array | No | Find notes whose title is mentioned in the given ones |
| `linkTo` | string array | No | Find notes which are linking to the given ones |
| `linkedBy` | string array | No | Find notes which are linked by the given ones |
| `orphan` | boolean | No | Find notes which are not linked by any other note |
| `related` | string array | No | Find notes which might be related to the given ones |
| `maxDistance` | integer | No | Maximum distance between two linked notes |
| `recursive` | boolean | No | Follow links recursively |
| `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`.

@ -27,3 +27,7 @@ But you can make your [notebook](notebook.md) even more tightly integrated with
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.

@ -14,11 +14,17 @@ This option is available when running `zk edit --interactive`, which spawns [`fz
## 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).
Initial content can be fed to the template through standard input using `zk new --interactive`, 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:
```sh
$ pbpaste | zk new
$ pbpaste | zk new --interactive
```
Alternatively, you can use the content of a file:
```sh
$ zk new --interactive < file.txt
```

@ -58,6 +58,21 @@ Change the currently used strategy with `--match-strategy <strategy>` (or `-M`).
list = "zk list --match-strategy re $@"
```
The `--match` option may be given multiple times, where each argument will be combined with a boolean AND.
For example,
```sh
$ zk list --tag "recipe" --match "pizza -pineapple" --match "mushrooms"
```
Is equivalent to,
```sh
$ zk list --tag "recipe" --match "(pizza -pineapple) AND (mushrooms)"
```
### Full-text search (`fts`)
The default match strategy 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`.

@ -6,6 +6,8 @@ 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.
If the [default notebook](config-notebook.md) is set it will be used as `ZK_NOTEBOOK_DIR`, unless this environment variable is not already set.
## 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:

@ -9,7 +9,7 @@ The following variables are available in the templates used when [creating new n
| `content` | string | Any text piped through the standard input |
| `dir` | string | Parent directory in the notebook |
| `extra.<key>` | string | [Additional variables](config-extra.md) provided through the config file or `--extra` |
| `now` | date | Current date and time, useful when paired with [`{{date now}}`](template.md) |
| `now` | date | Current date and time, useful when paired with [`{{format-date now}}`](template.md) |
| `env` | map | Dictionary of case-sensitive environment variables, e.g. `{{env.PATH}}`. |
These additional variables are available only to the note content template, once the filename is generated.

@ -36,15 +36,27 @@ The `{{concat s1 s2}}` helper concatenates two strings together. For example `{{
* The `{{substring s index length}}` helper extracts a portion of the given string. For example:
* `{{substring 'A full quote' 2 4}}` outputs `full`
* `{{substring 'A full quote' -5 5}` outputs `quote`
* `{{substring 'A full quote' -5 5}}` outputs `quote`
### Date helper
### Date helpers
The `{{date}}` helper formats the given date for display.
#### Date from natural string helper
You can get a date object from a natural human date (e.g. `tomorrow`, `2 weeks ago`, `2022-03-24`) using the `{{date}}` helper. It is most useful when paired with the `{{format-date}}` helper.
```
{{date "tomorrow"}}
{{format-date (date "last week") "timestamp"}}
```
#### Date formatting helper
The `{{format-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"}}`.
The default format output by `{{format-date <variable>}}` looks like `2009-11-17`, but you can choose a different format by providing a second argument, e.g. `{{format-date now "medium"}}`.
| Format | Output | Notes |
|------------------|----------------------------|--------------------------------------------------|
@ -58,7 +70,7 @@ The default format output by `{{date <variable>}}` looks like `2009-11-17`, but
| `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.
If none of the provided formats suit you, you can use a custom format using `strftime`-style placeholders, e.g. `{{format-date now "%m-%d-%Y"}}`. See `man strftime` for a list of placeholders.
### Slug helper

@ -4,7 +4,7 @@
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).
If you wish to customize more of `fzf` behavior, [please post a feature request](https://github.com/zk-org/zk/issues).
## Preview command

@ -0,0 +1,14 @@
# Setting your default shell
This is *currently* not supported on Windows (that defaults always to `cmd`).
You can customize which shell to use to run aliases and commands either from the [configuration file](config.md) or environment variables. In order of precedence, `zk` will use:
1. `ZK_SHELL` environment variable
2. `shell` configuration property
```toml
[tool]
shell = "/bin/bash"
```
3. `SHELL` environment variable
4. `sh` as fallback

@ -1,8 +1,6 @@
module github.com/mickael-menu/zk
module github.com/zk-org/zk
go 1.18
replace github.com/tliron/glsp => github.com/mickael-menu/glsp v0.1.1
go 1.21
require (
github.com/AlecAivazis/survey/v2 v2.3.4
@ -10,16 +8,16 @@ require (
github.com/aymerick/raymond v2.0.2+incompatible
github.com/bmatcuk/doublestar/v4 v4.0.2
github.com/fatih/color v1.13.0
github.com/go-testfixtures/testfixtures/v3 v3.6.2
github.com/go-testfixtures/testfixtures/v3 v3.6.1
github.com/google/go-cmp v0.5.8
github.com/gosimple/slug v1.12.0
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51
github.com/lestrrat-go/strftime v1.0.6
github.com/mattn/go-isatty v0.0.14
github.com/mattn/go-sqlite3 v2.0.3+incompatible
github.com/mickael-menu/pretty v0.2.3
github.com/mattn/go-sqlite3 v1.14.22
github.com/mvdan/xurls v1.1.0
github.com/pelletier/go-toml v1.9.5
github.com/pkg/errors v0.9.1
github.com/relvacode/iso8601 v1.1.0
github.com/rvflash/elapsed v0.2.0
github.com/schollz/progressbar/v3 v3.8.6
@ -28,6 +26,7 @@ require (
github.com/tliron/kutil v0.1.59
github.com/yuin/goldmark v1.4.12
github.com/yuin/goldmark-meta v1.1.0
github.com/zk-org/pretty v0.2.4
gopkg.in/djherbis/times.v1 v1.3.0
)
@ -41,16 +40,15 @@ require (
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d // indirect
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db // indirect
github.com/petermattis/goid v0.0.0-20220526132513-07eaf5d0b9f4 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/rivo/uniseg v0.2.0 // indirect
github.com/rogpeppe/go-internal v1.8.1 // indirect
github.com/rogpeppe/go-internal v1.9.0 // indirect
github.com/sasha-s/go-deadlock v0.3.1 // indirect
github.com/sourcegraph/jsonrpc2 v0.1.0 // indirect
github.com/zchee/color/v2 v2.0.6 // indirect
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 // indirect
golang.org/x/text v0.3.7 // indirect
golang.org/x/crypto v0.17.0 // indirect
golang.org/x/sys v0.15.0 // indirect
golang.org/x/term v0.15.0 // indirect
golang.org/x/text v0.14.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

159
go.sum

@ -10,20 +10,29 @@ github.com/aymerick/raymond v2.0.2+incompatible h1:VEp3GpgdAnv9B2GFyTvqgcKvY+mfK
github.com/aymerick/raymond v2.0.2+incompatible/go.mod h1:osfaiScAUVup+UC9Nfq76eWqDhXlp+4UYaA8uhTBO6g=
github.com/bmatcuk/doublestar/v4 v4.0.2 h1:X0krlUVAVmtr2cRoTqR8aDMrDqnB36ht8wpWTiQ3jsA=
github.com/bmatcuk/doublestar/v4 v4.0.2/go.mod h1:xBQ8jztBU6kakFMg+8WGxn0c6z1fTSPVIjEY1Wr7jzc=
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/coreos/go-systemd v0.0.0-20190719114852-fd7a80b32e1f/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7DoTY=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/creack/pty v1.1.17/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/creack/pty v1.1.18 h1:n56/Zwd5o6whRC5PMGretI4IdRLlmBXYNjScPaBgsbY=
github.com/creack/pty v1.1.18/go.mod h1:MOBLtS5ELjhRRrroQr9kyvTxUAFNvYEK993ew/Vr4O4=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/denisenkom/go-mssqldb v0.12.0 h1:VtrkII767ttSPNRfFekePK3sctr+joXgO58stqQbtUA=
github.com/denisenkom/go-mssqldb v0.10.0 h1:QykgLZBorFE95+gO3u9esLd0BmbvpWp0/waNNZfHBM8=
github.com/denisenkom/go-mssqldb v0.10.0/go.mod h1:xbL0rPBG9cCiLr28tMa8zpbdarY27NDyej4t/EjAShU=
github.com/fatih/color v1.13.0 h1:8LOYc1KYPPmyKMuN8QV2DNRWNbLo6LZ0iLs8+mlH53w=
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-testfixtures/testfixtures/v3 v3.6.2 h1:xfcTCkQlyDmNF+DtpGvxOnUk8aj4aenOwcKO0valf9o=
github.com/go-testfixtures/testfixtures/v3 v3.6.2/go.mod h1:iok8G2W/yEGHD4R9PDFRr+7PmAKZCKlr36D+HDND5Mo=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
github.com/go-testfixtures/testfixtures/v3 v3.6.1 h1:n4Fv95Exp0D05G6l6CAZv22Ck1EJK0pa0TfPqE4ncSs=
github.com/go-testfixtures/testfixtures/v3 v3.6.1/go.mod h1:Bsb2MoHAfHnNsPpSwAjtOs102mqDuM+1u3nE2OCi0N0=
github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe h1:lXe2qZdvpiX5WZkZR4hgp4KJVfY3nMkvmwbVkpv1rVY=
github.com/golang-sql/sqlexp v0.0.0-20170517235910-f1bb20e5a188 h1:+eHOFJl1BaXrQxKX+T06f78590z4qA2ZzBTqahsKSE4=
github.com/golang-sql/civil v0.0.0-20190719163853-cb61b32ac6fe/go.mod h1:8vg3r2VgvsThLBIFL93Qb5yWzgyZWhEmBwUJWevAkK0=
github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/gorilla/websocket v1.4.1/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
@ -35,23 +44,59 @@ github.com/gosimple/unidecode v1.0.1 h1:hZzFTMMqSswvf0LBJZCZgThIZrpDHFXux9KeGmn6
github.com/gosimple/unidecode v1.0.1/go.mod h1:CP0Cr1Y1kogOtx0bJblKzsVWrqYaqfNOnHzpgWw4Awc=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec h1:qv2VnGeEQHchGaZ/u7lxST/RaJw+cv273q79D81Xbog=
github.com/hinshun/vt10x v0.0.0-20220119200601-820417d04eec/go.mod h1:Q48J4R4DvxnHolD5P8pOtXigYlRuPLGl6moFx3ulM68=
github.com/jackc/chunkreader v1.0.0 h1:4s39bBR8ByfqH+DKm8rQA3E1LHZWB9XWcrz8fqaZbe0=
github.com/jackc/chunkreader v1.0.0/go.mod h1:RT6O25fNZIuasFJRyZ4R/Y2BbhasbmZXF9QQ7T3kePo=
github.com/jackc/chunkreader/v2 v2.0.0/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/chunkreader/v2 v2.0.1 h1:i+RDz65UE+mmpjTfyz0MoVTnzeYxroil2G82ki7MGG8=
github.com/jackc/pgconn v1.12.1 h1:rsDFzIpRk7xT4B8FufgpCCeyjdNpKyghZeSefViE5W8=
github.com/jackc/chunkreader/v2 v2.0.1/go.mod h1:odVSm741yZoC3dpHEUXIqA9tQRhFrgOHwnPIn9lDKlk=
github.com/jackc/pgconn v0.0.0-20190420214824-7e0022ef6ba3/go.mod h1:jkELnwuX+w9qN5YIfX0fl88Ehu4XC3keFuOJJk9pcnA=
github.com/jackc/pgconn v0.0.0-20190824142844-760dd75542eb/go.mod h1:lLjNuW/+OfW9/pnVKPazfWOgNfH2aPem8YQ7ilXGvJE=
github.com/jackc/pgconn v0.0.0-20190831204454-2fabfa3c18b7/go.mod h1:ZJKsE/KZfsUgOEh9hBm+xYTstcNHg7UPMVJqRfQxq4s=
github.com/jackc/pgconn v1.5.0 h1:oFSOilzIZkyg787M1fEmyMfOUUvwj0daqYMfaWwNL4o=
github.com/jackc/pgconn v1.5.0/go.mod h1:QeD3lBfpTFe8WUnPZWN5KY/mB8FGMIYRdd8P8Jr0fAI=
github.com/jackc/pgio v1.0.0 h1:g12B9UwVnzGhueNavwioyEEpAmqMe1E/BN9ES+8ovkE=
github.com/jackc/pgio v1.0.0/go.mod h1:oP+2QK2wFfUWgr+gxjoBH9KGBb31Eio69xUb0w5bYf8=
github.com/jackc/pgmock v0.0.0-20190831213851-13a1b77aafa2/go.mod h1:fGZlG77KXmcq05nJLRkk0+p82V8B8Dw8KN2/V9c/OAE=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgproto3/v2 v2.3.0 h1:brH0pCGBDkBW07HWlN/oSBXrmo3WB0UvZd1pIuDcL8Y=
github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b h1:C8S2+VttkHFdOOCXJe+YGfa4vHYwlt4Zx+IVXQ97jYg=
github.com/jackc/pgtype v1.11.0 h1:u4uiGPz/1hryuXzyaBhSk6dnIyyG2683olG2OV+UUgs=
github.com/jackc/pgx/v4 v4.16.1 h1:JzTglcal01DrghUqt+PmzWsZx/Yh7SC/CTQmSBMTd0Y=
github.com/joho/godotenv v1.4.0 h1:3l4+N6zfMWnkbPEXKng2o2/MR5mSwTrBih4ZEkkz1lg=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgproto3 v1.1.0 h1:FYYE4yRw+AgI8wXIinMlNjBbp/UitDJwfj5LqqewP1A=
github.com/jackc/pgproto3 v1.1.0/go.mod h1:eR5FA3leWg7p9aeAqi37XOTgTIbkABlvcPB3E5rlc78=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190420180111-c116219b62db/go.mod h1:bhq50y+xrl9n5mRYyCBFKkpRVTLYJVWeCc+mEAI3yXA=
github.com/jackc/pgproto3/v2 v2.0.0-alpha1.0.20190609003834-432c2951c711/go.mod h1:uH0AWtUmuShn0bcesswc4aBTWGvw0cAxIJp+6OB//Wg=
github.com/jackc/pgproto3/v2 v2.0.0-rc3/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.0-rc3.0.20190831210041-4c03ce451f29/go.mod h1:ryONWYqW6dqSg1Lw6vXNMXoBJhpzvWKnT95C46ckYeM=
github.com/jackc/pgproto3/v2 v2.0.1 h1:Rdjp4NFjwHnEslx2b66FfCI2S0LhO4itac3hXz6WX9M=
github.com/jackc/pgproto3/v2 v2.0.1/go.mod h1:WfJCnwN3HIg9Ish/j3sgWXnAfK8A9Y0bwXYU5xKaEdA=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8 h1:Q3tB+ExeflWUW7AFcAhXqk40s9mnNYLk1nOkKNZ5GnU=
github.com/jackc/pgservicefile v0.0.0-20200307190119-3430c5407db8/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E=
github.com/jackc/pgtype v0.0.0-20190421001408-4ed0de4755e0/go.mod h1:hdSHsc1V01CGwFsrv11mJRHWJ6aifDLfdV3aVjFF0zg=
github.com/jackc/pgtype v0.0.0-20190824184912-ab885b375b90/go.mod h1:KcahbBH1nCMSo2DXpzsoWOAfFkdEtEJpPbVLq8eE+mc=
github.com/jackc/pgtype v0.0.0-20190828014616-a8802b16cc59/go.mod h1:MWlu30kVJrUS8lot6TQqcg7mtthZ9T0EoIBFiJcmcyw=
github.com/jackc/pgtype v1.3.0 h1:l8JvKrby3RI7Kg3bYEeU9TA4vqC38QDpFCfcrC7KuN0=
github.com/jackc/pgtype v1.3.0/go.mod h1:b0JqxHvPmljG+HQ5IsvQ0yqeSi4nGcDTVjFoiLDb0Ik=
github.com/jackc/pgx v3.6.2+incompatible h1:2zP5OD7kiyR3xzRYMhOcXVvkDZsImVXfj+yIyTQf3/o=
github.com/jackc/pgx v3.6.2+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I=
github.com/jackc/pgx/v4 v4.0.0-20190420224344-cc3461e65d96/go.mod h1:mdxmSJJuR08CZQyj1PVQBHy9XOp5p8/SHH6a0psbY9Y=
github.com/jackc/pgx/v4 v4.0.0-20190421002000-1b8f0016e912/go.mod h1:no/Y67Jkk/9WuGR0JG/JseM9irFbnEPbuWV2EELPNuM=
github.com/jackc/pgx/v4 v4.0.0-pre1.0.20190824185557-6972a5742186/go.mod h1:X+GQnOEnf1dqHGpw7JmHqHc1NxDoalibchSk9/RWuDc=
github.com/jackc/pgx/v4 v4.6.0 h1:Fh0O9GdlG4gYpjpwOqjdEodJUQM9jzN3Hdv7PN0xmm0=
github.com/jackc/pgx/v4 v4.6.0/go.mod h1:vPh43ZzxijXUVJ+t/EmXBtFmbFVO72cuneCT9oAlxAg=
github.com/jackc/puddle v0.0.0-20190413234325-e4ced69a3a2b/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v0.0.0-20190608224051-11cab39313c9/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/jackc/puddle v1.1.0/go.mod h1:m4B5Dj62Y0fbyuIc15OsIqK0+JU8nkqQjsgx7dvjSWk=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/konsorten/go-windows-terminal-sequences v1.0.2/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/pty v1.1.8/go.mod h1:O1sed60cT9XZ5uDucP5qwvh+TE3NnUj51EiZO/lmSfw=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
@ -59,26 +104,33 @@ github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc h1:RKf14vYWi2t
github.com/lestrrat-go/envload v0.0.0-20180220234015-a3eb8ddeffcc/go.mod h1:kopuH9ugFRkIXf3YoqHKyrJ9YfUFsckUU9S7B+XP+is=
github.com/lestrrat-go/strftime v1.0.6 h1:CFGsDEt1pOpFNU+TJB0nhz9jl+K0hZSLE205AhTIGQQ=
github.com/lestrrat-go/strftime v1.0.6/go.mod h1:f7jQKgV5nnJpYgdEasS+/y7EsTb8ykN2z68n3TtcTaw=
github.com/lib/pq v1.10.5 h1:J+gdV2cUmX7ZqL2B0lFcW0m+egaHC2V3lpO8nWxyYiQ=
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.1.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
github.com/lib/pq v1.10.2 h1:AqzbZs4ZoCBp+GtejcpCpcxM3zlSMx29dXbUSeVtJb8=
github.com/lib/pq v1.10.2/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o=
github.com/mattn/go-colorable v0.1.1/go.mod h1:FuOcm+DKB9mbwrcAfNl7/TZVBZ6rcnceauSikq3lYCQ=
github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE=
github.com/mattn/go-colorable v0.1.9/go.mod h1:u6P/XSegPjTcexA+o6vUJrdnUu04hMope9wVRipJSqc=
github.com/mattn/go-colorable v0.1.12 h1:jF+Du6AlPIjs2BiUiQlKOX0rt3SujHxPnksPKZbaA40=
github.com/mattn/go-colorable v0.1.12/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
github.com/mattn/go-isatty v0.0.5/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.7/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s=
github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-runewidth v0.0.13 h1:lTGmDsbAYt5DmK6OnoV7EuIF1wEIFAcxld6ypU4OSgU=
github.com/mattn/go-runewidth v0.0.13/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
github.com/mattn/go-sqlite3 v2.0.3+incompatible h1:gXHsfypPkaMZrKbD5209QV9jbUTJKjyR5WD3HYQSd+U=
github.com/mattn/go-sqlite3 v2.0.3+incompatible/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
github.com/mattn/go-sqlite3 v1.14.7/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU=
github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y=
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d h1:5PJl274Y63IEHC+7izoQE9x6ikvDFZS2mDVS3drnohI=
github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
github.com/mickael-menu/glsp v0.1.1 h1:OW7meY/k5/mdZ5F4ds8H2ugq4rXARGRFp9vb+wzpP7k=
github.com/mickael-menu/glsp v0.1.1/go.mod h1:JkdOZOy+1znsGY8oa1zwT00kBsiNgL5QbcrW5JiPrIM=
github.com/mickael-menu/pretty v0.2.3 h1:AXi5WcBuWxwQV6iY/GhmCFpaoboQO2SLtzfujrn7dv0=
github.com/mickael-menu/pretty v0.2.3/go.mod h1:gupeWUSWoo3KX7BItIuouLgTqQLlmRylpaPdIK6IqLk=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ=
github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw=
github.com/mvdan/xurls v1.1.0 h1:OpuDelGQ1R1ueQ6sSryzi6P+1RtBpfQHM8fJwlE45ww=
@ -88,7 +140,7 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
github.com/petermattis/goid v0.0.0-20180202154549-b0b1615b78e5/go.mod h1:jvVRKCrJTQWu0XVbaOlby/2lO20uSCHEMzzplHXte1o=
github.com/petermattis/goid v0.0.0-20220526132513-07eaf5d0b9f4 h1:COozsq2xbSoZ6kt+/iHGF7eQqiUZr2uxQoAe4OzNkhE=
github.com/petermattis/goid v0.0.0-20220526132513-07eaf5d0b9f4/go.mod h1:pxMtw7cyUw6B2bRH0ZBANSPg+AoSud1I1iyJHI69jH4=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@ -98,19 +150,31 @@ github.com/relvacode/iso8601 v1.1.0/go.mod h1:FlNp+jz+TXpyRqgmM7tnzHHzBnz776kmAH
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
github.com/rogpeppe/go-internal v1.9.0 h1:73kH8U+JUqXU8lRuOHeVHaa/SZPifC7BkcraZVejAe8=
github.com/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rs/xid v1.2.1/go.mod h1:+uKXf+4Djp6Md1KODXJxgGQPKngRmWyn10oCKFzNHOQ=
github.com/rs/zerolog v1.13.0/go.mod h1:YbFCdg8HfsridGWAh22vktObvhZbQsZXe4/zB0OKkWU=
github.com/rs/zerolog v1.15.0/go.mod h1:xYTKnLHcpfU2225ny5qZjxnj9NvkumZYjJHlAThCjNc=
github.com/rvflash/elapsed v0.2.0 h1:zpMX24KJzo8jJaCI/6690Hb8tCEe5xtjAAjEgba0cns=
github.com/rvflash/elapsed v0.2.0/go.mod h1:sgjohdXO66LHVgIEQpO92eQjDWyZ5twX1ow122ixFGY=
github.com/sasha-s/go-deadlock v0.3.1 h1:sqv7fDNShgjcaxkO0JNcOAlr8B9+cV5Ey/OB71efZx0=
github.com/sasha-s/go-deadlock v0.3.1/go.mod h1:F73l+cr82YSh10GxyRI6qZiCgK64VaZjwesgfQ1/iLM=
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
github.com/schollz/progressbar/v3 v3.8.6 h1:QruMUdzZ1TbEP++S1m73OqRJk20ON11m6Wqv4EoGg8c=
github.com/schollz/progressbar/v3 v3.8.6/go.mod h1:W5IEwbJecncFGBvuEh4A7HT1nZZ6WNIL2i3qbnI0WKY=
github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4=
github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sourcegraph/jsonrpc2 v0.1.0 h1:ohJHjZ+PcaLxDUjqk2NC3tIGsVa5bXThe1ZheSXOjuk=
github.com/sourcegraph/jsonrpc2 v0.1.0/go.mod h1:ZafdZgk/axhT1cvZAPOhw+95nz2I/Ra5qMlU4gTRwIo=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.2.0/go.mod h1:qt09Ya8vawLte6SNmTgCsAVtYtaKzEcn8ATUoHMkEqE=
github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
@ -118,6 +182,8 @@ github.com/tj/assert v0.0.0-20190920132354-ee03d75cd160 h1:NSWpaDaurcAJY7PkL8Xt0
github.com/tj/assert v0.0.0-20190920132354-ee03d75cd160/go.mod h1:mZ9/Rh9oLWpLLDRpvE+3b7gP/C2YyLFYxNmcLnPTMe0=
github.com/tj/go-naturaldate v1.3.0 h1:OgJIPkR/Jk4bFMBLbxZ8w+QUxwjqSvzd9x+yXocY4RI=
github.com/tj/go-naturaldate v1.3.0/go.mod h1:rpUbjivDKiS1BlfMGc2qUKNZ/yxgthOfmytQs8d8hKk=
github.com/tliron/glsp v0.1.1 h1:GNNgUX9p1Q9MoPQooJoZ0+WaLL03EkhcKZUYJAtiNqs=
github.com/tliron/glsp v0.1.1/go.mod h1:RVyVKeY3U+Nlc3DRklUiaegNsQyjzNTEool6YWh1v7g=
github.com/tliron/kutil v0.1.59 h1:ReZ/o2EB0TsoTsmGIFNRUnbLyHvuFmSI5TKO8VZgnFk=
github.com/tliron/kutil v0.1.59/go.mod h1:jzWwDRumthKR8qHIquhHrErveSzZeFImNacoKfEjYkM=
github.com/yuin/goldmark v1.4.12 h1:6hffw6vALvEDqJ19dOJvJKOoAOKe4NDaTqvd2sktGN0=
@ -126,12 +192,39 @@ github.com/yuin/goldmark-meta v1.1.0 h1:pWw+JLHGZe8Rk0EGsMVssiNb/AaPMHfSRszZeUei
github.com/yuin/goldmark-meta v1.1.0/go.mod h1:U4spWENafuA7Zyg+Lj5RqK/MF+ovMYtBvXi1lBb2VP0=
github.com/zchee/color/v2 v2.0.6 h1:+mD95jTXou3Bi8+ZWn3SOEDts36SNROILd9JId7VI9A=
github.com/zchee/color/v2 v2.0.6/go.mod h1:mtte+U+f1/0xODbqR9J+TfcTjd86MMv6KNmpnC8MiXk=
github.com/zenazn/goji v0.9.0/go.mod h1:7S9M489iMyHBNxwZnk9/EHS098H4/F6TATF2mIxtB1Q=
github.com/zk-org/pretty v0.2.4 h1:pxf2E61IDO1I9cSNVoESQqK/y129Xophlp6XOH59130=
github.com/zk-org/pretty v0.2.4/go.mod h1:GIPC7TRqGw0VDdumZQ6JP21n0xCsXBd+rnVHeyEjN10=
go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0=
go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
go.uber.org/zap v1.10.0/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190411191339-88737f569e3a/go.mod h1:WFFai1msRO1wXaEeE5yQxYXgSfI8pQAWXbQop6sCtWE=
golang.org/x/crypto v0.0.0-20190820162420-60c769a6c586/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
golang.org/x/crypto v0.0.0-20200323165209-0ec3e9974c59/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM=
golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.17.0 h1:r8bRNjWL3GshPW3gkd+RpvzWrZAwPS49OmTGZ/uhM4k=
golang.org/x/crypto v0.17.0/go.mod h1:gCAAfMLgwOJRpTjQ2zCCt2OcSfYMTeZVSRtQlPC7Nq4=
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190403152447-81d4e9dc473e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190614084037-d442b75600c5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190826190057-c7b8b68b1456/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@ -140,18 +233,27 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467 h1:CBpWXWQpIRjzmkkA+M7q9Fqnwd2mZr3AFqexg8YTfoM=
golang.org/x/term v0.0.0-20220526004731-065cf7ba2467/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.15.0 h1:y/Oo/a/q3IXu26lQgl04j/gjuBDOBlx7X6Om1j2CPW4=
golang.org/x/term v0.15.0/go.mod h1:BDl952bC7+uMoWR75FIrCDx79TPU9oHkTZ9yRbYOrX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190425163242-31fd60d6bfdc/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
golang.org/x/tools v0.0.0-20190823170909-c4a336ef6a2f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
golang.org/x/xerrors v0.0.0-20190410155217-1f06c39b4373/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190513163551-3ee3066db522/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
@ -159,6 +261,7 @@ gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EV
gopkg.in/djherbis/times.v1 v1.3.0 h1:uxMS4iMtH6Pwsxog094W0FYldiNnfY/xba00vq6C2+o=
gopkg.in/djherbis/times.v1 v1.3.0/go.mod h1:AQlg6unIsrsCEdQYhTzERy542dz6SFdQFZFv6mUY0P8=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/inconshreveable/log15.v2 v2.0.0-20180818164646-67afb5ed74ec/go.mod h1:aPpfJ7XW+gOuirDoZ8gHhLh3kZ1B08FtV2bbmy7Jv3s=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=

@ -6,10 +6,10 @@ import (
"strings"
"github.com/kballard/go-shellquote"
"github.com/mickael-menu/zk/internal/util/errors"
executil "github.com/mickael-menu/zk/internal/util/exec"
"github.com/mickael-menu/zk/internal/util/opt"
osutil "github.com/mickael-menu/zk/internal/util/os"
"github.com/zk-org/zk/internal/util/errors"
executil "github.com/zk-org/zk/internal/util/exec"
"github.com/zk-org/zk/internal/util/opt"
osutil "github.com/zk-org/zk/internal/util/os"
)
// Editor represents an external editor able to edit the notes.
@ -37,7 +37,7 @@ func (e *Editor) Open(paths ...string) error {
// /dev/tty is restored as stdin, in case the user used a pipe to feed
// initial note content to `zk new`. Without this, Vim doesn't work
// properly in this case.
// See https://github.com/mickael-menu/zk/issues/4
// See https://github.com/zk-org/zk/issues/4
cmd := executil.CommandFromString(e.editor + " " + shellquote.Join(paths...) + " </dev/tty")
cmd.Stdin = os.Stdin
cmd.Stdout = os.Stdout

@ -4,8 +4,8 @@ import (
"os"
"testing"
"github.com/mickael-menu/zk/internal/util/opt"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/util/opt"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestEditorUsesZkEditorFirst(t *testing.T) {

@ -1,12 +1,11 @@
package fs
import (
"io/ioutil"
"os"
"path/filepath"
"strings"
"github.com/mickael-menu/zk/internal/util"
"github.com/zk-org/zk/internal/util"
)
// FileStorage implements the port core.FileStorage.
@ -114,7 +113,7 @@ func (fs *FileStorage) IsDescendantOf(dir string, path string) (bool, error) {
}
func (fs *FileStorage) Read(path string) ([]byte, error) {
return ioutil.ReadFile(path)
return os.ReadFile(path)
}
func (fs *FileStorage) Write(path string, content []byte) error {

@ -9,9 +9,9 @@ import (
"sync"
"github.com/kballard/go-shellquote"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/opt"
stringsutil "github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/opt"
stringsutil "github.com/zk-org/zk/internal/util/strings"
)
// ErrCancelled is returned when the user cancelled fzf.

@ -7,10 +7,10 @@ import (
"strings"
"time"
"github.com/mickael-menu/zk/internal/adapter/term"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/opt"
stringsutil "github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/adapter/term"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/opt"
stringsutil "github.com/zk-org/zk/internal/util/strings"
)
// NoteFilter uses fzf to filter interactively a set of notes.

@ -6,22 +6,23 @@ import (
"path/filepath"
"github.com/aymerick/raymond"
"github.com/mickael-menu/zk/internal/adapter/handlebars/helpers"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/paths"
"github.com/zk-org/zk/internal/adapter/handlebars/helpers"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/paths"
)
func Init(supportsUTF8 bool, logger util.Logger) {
helpers.RegisterConcat()
helpers.RegisterSubstring()
helpers.RegisterDate(logger)
helpers.RegisterFormatDate(logger)
helpers.RegisterJoin()
helpers.RegisterJSON(logger)
helpers.RegisterList(supportsUTF8)
helpers.RegisterPrepend(logger)
helpers.RegisterShell(logger)
helpers.RegisterSubstring()
}
// Template renders a parsed handlebars template.

@ -7,12 +7,12 @@ import (
"testing"
"time"
"github.com/mickael-menu/zk/internal/adapter/handlebars/helpers"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/fixtures"
"github.com/mickael-menu/zk/internal/util/paths"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/adapter/handlebars/helpers"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/fixtures"
"github.com/zk-org/zk/internal/util/paths"
"github.com/zk-org/zk/internal/util/test/assert"
)
func init() {
@ -226,19 +226,131 @@ func TestSlugHelper(t *testing.T) {
)
}
func TestFormatDateHelper(t *testing.T) {
context := map[string]interface{}{"now": time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)}
testString(t, "{{format-date now}}", context, "2009-11-17")
testString(t, "{{format-date now 'short'}}", context, "11/17/2009")
testString(t, "{{format-date now 'medium'}}", context, "Nov 17, 2009")
testString(t, "{{format-date now 'long'}}", context, "November 17, 2009")
testString(t, "{{format-date now 'full'}}", context, "Tuesday, November 17, 2009")
testString(t, "{{format-date now 'year'}}", context, "2009")
testString(t, "{{format-date now 'time'}}", context, "20:34")
testString(t, "{{format-date now 'timestamp'}}", context, "200911172034")
testString(t, "{{format-date now 'timestamp-unix'}}", context, "1258490098")
testString(t, "{{format-date now 'cust: %Y-%m'}}", context, "cust: 2009-11")
}
func TestFormatDateHelperElapsedYear(t *testing.T) {
year := time.Now().UTC().Year() - 14
context := map[string]interface{}{"now": time.Date(year, 11, 17, 20, 34, 58, 651387237, time.UTC)}
testString(t, "{{format-date now 'elapsed'}}", context, "14 years ago")
}
func TestFormatDateHelperElapsedViaTimeMultiplication(t *testing.T) {
// test for time being provided in via multiplications on seconds, minutes
// and hours, as expected by github.com/rvflash/elapsed
cases := []struct {
elapsed time.Duration
want string
}{
{
elapsed: -12 * time.Second,
want: "not yet",
},
{
elapsed: time.Second,
want: "just now",
},
{
elapsed: 59 * time.Second,
want: "just now",
},
{
elapsed: 60 * time.Second,
want: "1 minute ago",
},
{
elapsed: 1 * time.Minute,
want: "1 minute ago",
},
{
elapsed: 2 * time.Minute,
want: "2 minutes ago",
},
{
elapsed: 62 * time.Minute,
want: "1 hour ago",
},
{
elapsed: time.Hour,
want: "1 hour ago",
},
{
elapsed: 2 * time.Hour,
want: "2 hours ago",
},
{
elapsed: 24 * time.Hour,
want: "yesterday",
},
{
elapsed: 4 * 24 * time.Hour,
want: "4 days ago",
},
{
elapsed: 7 * 24 * time.Hour,
want: "1 week ago",
},
{
elapsed: 8 * 24 * time.Hour,
want: "2 weeks ago",
},
{
elapsed: 18 * 24 * time.Hour,
want: "3 weeks ago",
},
{
elapsed: 30 * 24 * time.Hour,
want: "1 month ago",
},
{
elapsed: 31 * 24 * time.Hour,
want: "2 months ago",
},
{
elapsed: 60 * 24 * time.Hour,
want: "2 months ago",
},
{
elapsed: 61 * 24 * time.Hour,
want: "3 months ago",
},
{
elapsed: 330 * 24 * time.Hour,
want: "11 months ago",
},
{
elapsed: 331 * 24 * time.Hour,
want: "1 year ago",
},
{
elapsed: 366 * 24 * time.Hour,
want: "2 years ago",
},
}
for i, tc := range cases {
t.Run(fmt.Sprintf("%d_%s", i, tc.want), func(t *testing.T) {
templateContext := map[string]interface{}{"now": time.Now().Add(-tc.elapsed)}
testString(t, "{{format-date now 'elapsed'}}", templateContext, tc.want)
})
}
}
func TestDateHelper(t *testing.T) {
context := map[string]interface{}{"now": time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)}
testString(t, "{{date now}}", context, "2009-11-17")
testString(t, "{{date now 'short'}}", context, "11/17/2009")
testString(t, "{{date now 'medium'}}", context, "Nov 17, 2009")
testString(t, "{{date now 'long'}}", context, "November 17, 2009")
testString(t, "{{date now 'full'}}", context, "Tuesday, November 17, 2009")
testString(t, "{{date now 'year'}}", context, "2009")
testString(t, "{{date now 'time'}}", context, "20:34")
testString(t, "{{date now 'timestamp'}}", context, "200911172034")
testString(t, "{{date now 'timestamp-unix'}}", context, "1258490098")
testString(t, "{{date now 'cust: %Y-%m'}}", context, "cust: 2009-11")
testString(t, "{{date now 'elapsed'}}", context, "13 years ago")
testString(t, "{{format-date (date \"2009-11-17T20:34:58\") 'timestamp'}}", context, "200911172034")
}
func TestShellHelper(t *testing.T) {

@ -1,24 +1,51 @@
package helpers
import (
"os"
"time"
"github.com/aymerick/raymond"
"github.com/lestrrat-go/strftime"
"github.com/mickael-menu/zk/internal/util"
"github.com/zk-org/zk/internal/util"
dateutil "github.com/zk-org/zk/internal/util/date"
"github.com/pkg/errors"
"github.com/rvflash/elapsed"
)
// RegisterDate registers the {{date}} template helpers which format a given date.
// RegisterDate registers the {{date}} template helper to use the `naturaldate` package to generate time.Time based on language strings.
// This can be used in combination with the `format-date` helper to generate dates in the user's language.
// {{format-date (date "last week") "timestamp"}}
func RegisterDate(logger util.Logger) {
raymond.RegisterHelper("date", func(arg1 interface{}, arg2 interface{}) time.Time {
var t time.Time
switch date := arg1.(type) {
case string:
t, err := dateutil.TimeFromNatural(date)
if err != nil {
logger.Err(errors.Wrap(err, "the {{date}} template helper failed to parse the date"))
}
return t
case time.Time:
logger.Println("the {{date}} template helper was renamed to {{format-date}}, please update your configuration")
os.Exit(1)
return t
default:
logger.Println("the {{date}} template helper expects a natural human date as a string for its only argument")
return t
}
})
}
// RegisterFormatDate registers the {{format-date}} template helpers which format a given date.
//
// It supports various styles: short, medium, long, full, year, time,
// timestamp, timestamp-unix or a custom strftime format.
//
// {{date now}} -> 2009-11-17
// {{date now "medium"}} -> Nov 17, 2009
// {{date now "%Y-%m"}} -> 2009-11
func RegisterDate(logger util.Logger) {
raymond.RegisterHelper("date", func(date time.Time, arg interface{}) string {
// {{format-date now}} -> 2009-11-17
// {{format-date now "medium"}} -> Nov 17, 2009
// {{format-date now "%Y-%m"}} -> 2009-11
func RegisterFormatDate(logger util.Logger) {
raymond.RegisterHelper("format-date", func(date time.Time, arg interface{}) string {
format := "%Y-%m-%d"
if arg, ok := arg.(string); ok {
@ -31,7 +58,7 @@ func RegisterDate(logger util.Logger) {
} else {
res, err := strftime.Format(format, date, strftime.WithUnixSeconds('s'))
if err != nil {
logger.Printf("the {{date}} template helper failed to format the date: %v", err)
logger.Printf("the {{format-date}} template helper failed to format the date: %v", err)
return ""
}
return res

@ -4,8 +4,8 @@ import (
"encoding/json"
"github.com/aymerick/raymond"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
)
// RegisterJSON registers a {{json}} template helper which serializes its

@ -1,8 +1,8 @@
package helpers
import (
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
)
// NewLinkHelper creates a new template helper to generate an internal link

@ -2,8 +2,8 @@ package helpers
import (
"github.com/aymerick/raymond"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/strings"
)
// RegisterPrepend registers a {{prepend}} template helper which prepend a

@ -4,8 +4,8 @@ import (
"strings"
"github.com/aymerick/raymond"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/exec"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/exec"
)
// RegisterShell registers the {{sh}} template helper, which runs shell commands.

@ -3,7 +3,7 @@ package helpers
import (
"github.com/aymerick/raymond"
"github.com/gosimple/slug"
"github.com/mickael-menu/zk/internal/util"
"github.com/zk-org/zk/internal/util"
)
// NewSlugHelper creates a new template helper to slugify text.

@ -4,8 +4,8 @@ import (
"strings"
"github.com/aymerick/raymond"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
)
// NewStyleHelper creates a new template helper which stylizes the text input

@ -3,7 +3,7 @@ package lsp
import (
"fmt"
"github.com/mickael-menu/zk/internal/core"
"github.com/zk-org/zk/internal/core"
)
const cmdIndex = "zk.index"

@ -0,0 +1,64 @@
package lsp
import (
"fmt"
"path/filepath"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/errors"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
const cmdLink = "zk.link"
type cmdLinkOpts struct {
Path *string `json:"path"`
Location *protocol.Location `json:"location"`
Title *string `json:"title"`
}
func executeCommandLink(notebook *core.Notebook, documents *documentStore, context *glsp.Context, args []interface{}) (interface{}, error) {
var opts cmdLinkOpts
if len(args) > 1 {
arg, ok := args[1].(map[string]interface{})
if !ok {
return nil, fmt.Errorf("%s expects a dictionary of options as second argument, got: %v", cmdLink, args[1])
}
err := unmarshalJSON(arg, &opts)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse %s args, got: %v", cmdLink, arg)
}
}
if opts.Path == nil {
return nil, errors.New("'path' not provided")
}
note, err := notebook.FindByHref(*opts.Path, false)
if err != nil {
return nil, err
}
if note == nil {
return nil, errors.New("Requested note to link to not found!")
}
info := &linkInfo{
note: note,
location: opts.Location,
title: opts.Title,
}
err = linkNote(notebook, documents, context, info)
if err != nil {
return nil, err
}
return map[string]interface{}{
"path": filepath.Join(notebook.Path, note.Path),
}, nil
}

@ -5,11 +5,11 @@ import (
"path/filepath"
"time"
"github.com/mickael-menu/zk/internal/cli"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
strutil "github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
strutil "github.com/zk-org/zk/internal/util/strings"
)
const cmdList = "zk.list"

@ -4,10 +4,10 @@ import (
"fmt"
"path/filepath"
"github.com/mickael-menu/zk/internal/core"
dateutil "github.com/mickael-menu/zk/internal/util/date"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/opt"
"github.com/zk-org/zk/internal/core"
dateutil "github.com/zk-org/zk/internal/util/date"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/opt"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
@ -15,15 +15,17 @@ import (
const cmdNew = "zk.new"
type cmdNewOpts struct {
Title string `json:"title"`
Content string `json:"content"`
Dir string `json:"dir"`
Group string `json:"group"`
Template string `json:"template"`
Extra map[string]string `json:"extra"`
Date string `json:"date"`
Edit jsonBoolean `json:"edit"`
InsertLinkAtLocation *protocol.Location `json:"insertLinkAtLocation"`
Title string `json:"title"`
Content string `json:"content"`
Dir string `json:"dir"`
Group string `json:"group"`
Template string `json:"template"`
Extra map[string]string `json:"extra"`
Date string `json:"date"`
Edit jsonBoolean `json:"edit"`
DryRun jsonBoolean `json:"dryRun"`
InsertLinkAtLocation *protocol.Location `json:"insertLinkAtLocation"`
InsertContentAtLocation *protocol.Location `json:"insertContentAtLocation"`
}
func executeCommandNew(notebook *core.Notebook, documents *documentStore, context *glsp.Context, args []interface{}) (interface{}, error) {
@ -51,6 +53,7 @@ func executeCommandNew(notebook *core.Notebook, documents *documentStore, contex
Group: opt.NewNotEmptyString(opts.Group),
Template: opt.NewNotEmptyString(opts.Template),
Extra: opts.Extra,
DryRun: bool(opts.DryRun),
Date: date,
})
if err != nil {
@ -69,47 +72,41 @@ func executeCommandNew(notebook *core.Notebook, documents *documentStore, contex
return nil, errors.New("zk.new could not generate a new note")
}
if opts.InsertLinkAtLocation != nil {
doc, ok := documents.Get(opts.InsertLinkAtLocation.URI)
if !ok {
return nil, fmt.Errorf("can't insert link in %s", opts.InsertLinkAtLocation.URI)
}
linkFormatter, err := notebook.NewLinkFormatter()
if err != nil {
return nil, err
}
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
}
link, err := linkFormatter(linkFormatterContext)
if err != nil {
return nil, err
}
if opts.InsertContentAtLocation != nil {
go context.Call(protocol.ServerWorkspaceApplyEdit, protocol.ApplyWorkspaceEditParams{
Edit: protocol.WorkspaceEdit{
Changes: map[string][]protocol.TextEdit{
opts.InsertLinkAtLocation.URI: {{Range: opts.InsertLinkAtLocation.Range, NewText: link}},
opts.InsertContentAtLocation.URI: {{Range: opts.InsertContentAtLocation.Range, NewText: note.RawContent}},
},
},
}, nil)
}
if !opts.DryRun && opts.InsertLinkAtLocation != nil {
minNote := note.AsMinimalNote()
info := &linkInfo{
note: &minNote,
location: opts.InsertLinkAtLocation,
title: &opts.Title,
}
err := linkNote(notebook, documents, context, info)
if err != nil {
return nil, err
}
}
absPath := filepath.Join(notebook.Path, note.Path)
if opts.Edit {
if !opts.DryRun && opts.Edit {
go context.Call(protocol.ServerWindowShowDocument, protocol.ShowDocumentParams{
URI: pathToURI(absPath),
TakeFocus: boolPtr(true),
}, nil)
}
return map[string]interface{}{"path": absPath}, nil
return map[string]interface{}{
"path": absPath,
"content": note.RawContent,
}, nil
}

@ -3,9 +3,9 @@ package lsp
import (
"fmt"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
)
const cmdTagList = "zk.tag.list"

@ -3,8 +3,8 @@ package lsp
import (
"path/filepath"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/paths"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/paths"
)
// completionTemplates holds templates to render the various elements of an LSP

@ -2,15 +2,17 @@ package lsp
import (
"net/url"
"path/filepath"
"regexp"
"strings"
"unicode/utf16"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
strutil "github.com/mickael-menu/zk/internal/util/strings"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
strutil "github.com/zk-org/zk/internal/util/strings"
)
// documentStore holds opened documents.
@ -130,34 +132,46 @@ func (d *document) GetLines() []string {
// LookBehind returns the n characters before the given position, on the same line.
func (d *document) LookBehind(pos protocol.Position, length int) string {
line, ok := d.GetLine(int(pos.Line))
utf16Bytes := utf16.Encode([]rune(line))
if !ok {
return ""
}
charIdx := int(pos.Character)
if length > charIdx {
return line[0:charIdx]
return string(utf16.Decode(utf16Bytes[0:charIdx]))
}
return line[(charIdx - length):charIdx]
return string(utf16.Decode(utf16Bytes[(charIdx - length):charIdx]))
}
// LookForward returns the n characters after the given position, on the same line.
func (d *document) LookForward(pos protocol.Position, length int) string {
line, ok := d.GetLine(int(pos.Line))
utf16Bytes := utf16.Encode([]rune(line))
if !ok {
return ""
}
lineLength := len(line)
lineLength := len(utf16Bytes)
charIdx := int(pos.Character)
if lineLength <= charIdx+length {
return line[charIdx:]
return string(utf16.Decode(utf16Bytes[charIdx:]))
}
return line[charIdx:(charIdx + length)]
return string(utf16.Decode(utf16Bytes[charIdx:(charIdx + length)]))
}
var wikiLinkRegex = regexp.MustCompile(`\[?\[\[(.+?)(?: *\| *(.+?))?\]\]`)
var markdownLinkRegex = regexp.MustCompile(`\[([^\]]+?[^\\])\]\((.+?[^\\])\)`)
// LinkFromRoot returns a Link to this document from the root of the given
// notebook.
func (d *document) LinkFromRoot(nb *core.Notebook) (*documentLink, error) {
href, err := nb.RelPath(d.Path)
if err != nil {
return nil, err
}
return &documentLink{
Href: href,
RelativeToDir: nb.Path,
}, nil
}
// DocumentLinkAt returns the internal or external link found in the document
// at the given position.
@ -176,6 +190,66 @@ func (d *document) DocumentLinkAt(pos protocol.Position) (*documentLink, error)
return nil, nil
}
// Recursive function to check whether a link is within inline code.
func linkWithinInlineCode(strBuffer string, linkStart, linkEnd int, insideInline bool) bool {
if backtickId := strings.Index(strBuffer, "`"); backtickId >= 0 && backtickId < linkEnd {
return linkWithinInlineCode(strBuffer[backtickId+1:],
linkStart-backtickId-1, linkEnd-backtickId-1, !insideInline)
} else {
return insideInline
}
}
var wikiLinkRegex = regexp.MustCompile(`\[?\[\[(.+?)(?: *\| *(.+?))?\]\]`)
var markdownLinkRegex = regexp.MustCompile(`\[([^\]]+?[^\\])\]\((.+?[^\\])\)`)
var fileURIregex = regexp.MustCompile(`file:///`)
var fencedStartRegex = regexp.MustCompile(`^(` + "```" + `|~~~).*`)
var fencedEndRegex = regexp.MustCompile(`^(` + "```" + `|~~~)\s*`)
var indentedRegex = regexp.MustCompile(`^(\s{4}|\t).+`)
var insideInline = false
var insideFenced = false
var insideIndented = false
var currentCodeBlockStart = -1
// check whether the current line in document is within a fenced or indented
// code block
func isLineWithinCodeBlock(lines []string, lineIndex int, line string) bool {
// if line is already within code fences or indented code block
if insideFenced {
if fencedEndRegex.FindStringIndex(line) != nil &&
lines[currentCodeBlockStart][:3] == line[:3] {
// Fenced code block ends with this line
insideFenced = false
currentCodeBlockStart = -1
}
return true
} else if insideIndented {
if indentedRegex.FindStringIndex(line) == nil && len(line) > 0 {
// Indeted code block ends with this line
insideIndented = false
currentCodeBlockStart = -1
} else {
return true
}
} else {
// Check whether the current line is the start of a code fence or
// indented code block
if fencedStartRegex.FindStringIndex(line) != nil {
insideFenced = true
currentCodeBlockStart = lineIndex
return true
} else if indentedRegex.FindStringIndex(line) != nil &&
(lineIndex > 0 && len(lines[lineIndex-1]) == 0 || lineIndex == 0) {
insideIndented = true
currentCodeBlockStart = lineIndex
return true
}
}
return false
}
// DocumentLinks returns all the internal and external links found in the
// document.
func (d *document) DocumentLinks() ([]documentLink, error) {
@ -184,6 +258,10 @@ func (d *document) DocumentLinks() ([]documentLink, error) {
lines := d.GetLines()
for lineIndex, line := range lines {
if isLineWithinCodeBlock(lines, lineIndex, line) {
continue
}
appendLink := func(href string, start, end int, hasTitle bool, isWikiLink bool) {
if href == "" {
return
@ -194,7 +272,8 @@ func (d *document) DocumentLinks() ([]documentLink, error) {
end = strutil.ByteIndexToRuneIndex(line, end)
links = append(links, documentLink{
Href: href,
Href: href,
RelativeToDir: filepath.Dir(d.Path),
Range: protocol.Range{
Start: protocol.Position{
Line: protocol.UInteger(lineIndex),
@ -210,25 +289,51 @@ func (d *document) DocumentLinks() ([]documentLink, error) {
})
}
// extract link paths from [title](path) patterns
// note: match[0:1] is the entire match, match[2:3] is the contents of
// brackets, match[4:5] is contents of parentheses
for _, match := range markdownLinkRegex.FindAllStringSubmatchIndex(line, -1) {
// Ignore embedded image, e.g. ![title](href.png)
// Ignore when inside backticks: `[title](file)`
if linkWithinInlineCode(line, match[0], match[1], insideInline) {
continue
}
// Ignore embedded images ![title](file.png)
if match[0] > 0 && line[match[0]-1] == '!' {
continue
}
// ignore tripple dash file URIs [title](file:///foo.go)
if match[5]-match[4] >= 8 {
linkURL := line[match[4]:match[5]]
fileURIresult := linkURL[:8]
if fileURIregex.MatchString(fileURIresult) {
continue
}
}
href := line[match[4]:match[5]]
// Valid Markdown links are percent-encoded.
// Decode the href if it's percent-encoded
if decodedHref, err := url.PathUnescape(href); err == nil {
href = decodedHref
}
appendLink(href, match[0], match[1], false, false)
}
for _, match := range wikiLinkRegex.FindAllStringSubmatchIndex(line, -1) {
// Ignore when inside backticks: `[[filename]]`
if linkWithinInlineCode(line, match[0], match[1], insideInline) {
continue
}
href := line[match[2]:match[3]]
hasTitle := match[4] != -1
appendLink(href, match[0], match[1], hasTitle, true)
}
if strings.Count(line, "`")%2 == 1 {
insideInline = !insideInline
}
}
return links, nil
@ -240,13 +345,16 @@ func (d *document) IsTagPosition(position protocol.Position, noteContentParser c
lineIdx := int(position.Line)
charIdx := int(position.Character)
line := lines[lineIdx]
// https://github.com/mickael-menu/zk/issues/144#issuecomment-1006108485
// https://github.com/zk-org/zk/issues/144#issuecomment-1006108485
line = line[:charIdx] + "ZK_PLACEHOLDER" + line[charIdx:]
lines[lineIdx] = line
targetWord := strutil.WordAt(line, charIdx)
if targetWord == "" {
return false
}
if string(targetWord[0]) == "#" {
targetWord = targetWord[1:]
}
content := strings.Join(lines, "\n")
note, err := noteContentParser.ParseNoteContent(content)
@ -257,8 +365,9 @@ func (d *document) IsTagPosition(position protocol.Position, noteContentParser c
}
type documentLink struct {
Href string
Range protocol.Range
Href string
RelativeToDir string
Range protocol.Range
// HasTitle indicates whether this link has a title information. For
// example [[filename]] doesn't but [[filename|title]] does.
HasTitle bool

@ -3,16 +3,16 @@ package lsp
import (
"encoding/json"
"fmt"
"io/ioutil"
"os"
"path/filepath"
"strings"
"time"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/opt"
strutil "github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/opt"
strutil "github.com/zk-org/zk/internal/util/strings"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
glspserv "github.com/tliron/glsp/server"
@ -209,7 +209,7 @@ func NewServer(opts ServerOpts) *Server {
handler.CompletionItemResolve = func(context *glsp.Context, params *protocol.CompletionItem) (*protocol.CompletionItem, error) {
if path, ok := params.Data.(string); ok {
content, err := ioutil.ReadFile(path)
content, err := os.ReadFile(path)
if err != nil {
return params, err
}
@ -238,7 +238,7 @@ func NewServer(opts ServerOpts) *Server {
return nil, err
}
target, err := server.noteForLink(*link, doc, notebook)
target, err := server.noteForLink(*link, notebook)
if err != nil || target == nil {
return nil, err
}
@ -250,7 +250,7 @@ func NewServer(opts ServerOpts) *Server {
}
path = fs.Canonical(path)
contents, err := ioutil.ReadFile(path)
contents, err := os.ReadFile(path)
if err != nil {
return nil, err
}
@ -281,15 +281,24 @@ func NewServer(opts ServerOpts) *Server {
documentLinks := []protocol.DocumentLink{}
for _, link := range links {
target, err := server.noteForLink(link, doc, notebook)
if target == nil || err != nil {
continue
var target string
if strutil.IsURL(link.Href) {
// External link
target = link.Href
} else {
// Internal note link
targetNote, err := server.noteForLink(link, notebook)
if targetNote != nil && err == nil {
target = targetNote.URI
}
}
documentLinks = append(documentLinks, protocol.DocumentLink{
Range: link.Range,
Target: &target.URI,
})
if target != "" {
documentLinks = append(documentLinks, protocol.DocumentLink{
Range: link.Range,
Target: &target,
})
}
}
return documentLinks, err
@ -311,7 +320,7 @@ func NewServer(opts ServerOpts) *Server {
return nil, err
}
target, err := server.noteForLink(*link, doc, notebook)
target, err := server.noteForLink(*link, notebook)
if link == nil || target == nil || err != nil {
return nil, err
}
@ -360,6 +369,13 @@ func NewServer(opts ServerOpts) *Server {
}
return executeCommandNew(nb, server.documents, context, params.Arguments)
case cmdLink:
nb, err := openNotebook()
if err != nil {
return nil, err
}
return executeCommandLink(nb, server.documents, context, params.Arguments)
case cmdList:
nb, err := openNotebook()
if err != nil {
@ -412,6 +428,7 @@ func NewServer(opts ServerOpts) *Server {
Title: actionTitle,
Kind: stringPtr(protocol.CodeActionKindRefactor),
Command: &protocol.Command{
Title: actionTitle,
Command: cmdNew,
Arguments: []interface{}{wd, jsonOpts},
},
@ -442,25 +459,19 @@ func NewServer(opts ServerOpts) *Server {
return nil, err
}
if link == nil {
href, err := notebook.RelPath(doc.Path)
link, err = doc.LinkFromRoot(notebook)
if err != nil {
return nil, err
}
link = &documentLink{Href: href}
}
target, err := server.noteForLink(*link, doc, notebook)
target, err := server.noteForLink(*link, notebook)
if link == nil || target == nil || err != nil {
return nil, err
}
p, err := notebook.RelPath(target.Path)
if err != nil {
return nil, err
}
opts := core.NoteFindOpts{
LinkTo: &core.LinkFilter{Hrefs: []string{p}},
LinkTo: &core.LinkFilter{Hrefs: []string{target.Path}},
}
notes, err := notebook.FindNotes(opts)
@ -510,14 +521,14 @@ func (s *Server) notebookOf(doc *document) (*core.Notebook, error) {
return s.notebooks.Open(doc.Path)
}
// noteForLink returns the LSP documentUri for the note targeted by the given link.
// noteForLink returns the Note object for the note targeted by the given link.
//
// Match by order of precedence:
// 1. Prefix of relative path
// 2. Find any occurrence of the href in a note path (substring)
// 3. Match the href as a term in the note titles
func (s *Server) noteForLink(link documentLink, doc *document, notebook *core.Notebook) (*Note, error) {
note, err := s.noteForHref(link.Href, doc, notebook)
func (s *Server) noteForLink(link documentLink, notebook *core.Notebook) (*Note, error) {
note, err := s.noteForHref(link.Href, link.RelativeToDir, notebook)
if note == nil && err == nil && link.IsWikiLink {
// Try to find a partial href match.
note, err = notebook.FindByHref(link.Href, true)
@ -530,13 +541,17 @@ func (s *Server) noteForLink(link documentLink, doc *document, notebook *core.No
return &Note{*note, pathToURI(joined_path)}, nil
}
// noteForHref returns the LSP documentUri for the note targeted by the given HREF.
func (s *Server) noteForHref(href string, doc *document, notebook *core.Notebook) (*core.MinimalNote, error) {
// noteForHref returns the Note object for the note targeted by the given HREF
// relative to relativeToDir.
func (s *Server) noteForHref(href string, relativeToDir string, notebook *core.Notebook) (*core.MinimalNote, error) {
if strutil.IsURL(href) {
return nil, nil
}
path := filepath.Clean(filepath.Join(filepath.Dir(doc.Path), href))
path := href
if relativeToDir != "" {
path = filepath.Clean(filepath.Join(relativeToDir, path))
}
path, err := filepath.Rel(notebook.Path, path)
if err != nil {
return nil, errors.Wrapf(err, "failed to resolve href: %s", href)
@ -588,7 +603,7 @@ func (s *Server) refreshDiagnosticsOfDocument(doc *document, notify glsp.NotifyF
if strutil.IsURL(link.Href) {
continue
}
target, err := s.noteForLink(link, doc, notebook)
target, err := s.noteForLink(link, notebook)
if err != nil {
s.logger.Err(err)
continue
@ -628,10 +643,16 @@ 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, notebook.Parser) {
return nil, nil
currentWord := doc.WordAt(position)
if strings.HasPrefix(doc.LookBehind(position, len(currentWord)+2), "[[") {
return s.buildLinkCompletionList(notebook, doc, position)
}
if doc.IsTagPosition(position, notebook.Parser) {
return s.buildTagCompletionList(notebook, doc.WordAt(position))
}
return s.buildTagCompletionList(notebook, doc.WordAt(position))
return nil, nil
}
// buildTriggerCompletionList builds the completion item response for a
@ -789,12 +810,18 @@ func (s *Server) newCompletionItem(notebook *core.Notebook, note core.MinimalNot
if s.useAdditionalTextEditsWithNotebook(notebook) {
addTextEdits := []protocol.TextEdit{}
startOffset := -2
if doc.LookBehind(pos, 2) != "[[" {
currentWord := doc.WordAt(pos)
startOffset = -2 - len(currentWord)
}
// Some LSP clients (e.g. VSCode) don't support deleting the trigger
// characters with the main TextEdit. So let's add an additional
// TextEdit for that.
addTextEdits = append(addTextEdits, protocol.TextEdit{
NewText: "",
Range: rangeFromPosition(pos, -2, 0),
Range: rangeFromPosition(pos, startOffset, 0),
})
item.AdditionalTextEdits = addTextEdits
@ -821,7 +848,12 @@ func (s *Server) newTextEditForLink(notebook *core.Notebook, note core.MinimalNo
// Overwrite [[ trigger directly if the additional text edits are disabled.
startOffset := 0
if !s.useAdditionalTextEditsWithNotebook(notebook) {
startOffset = -2
if doc.LookBehind(pos, 2) == "[[" {
startOffset = -2
} else {
currentWord := doc.WordAt(pos)
startOffset = -2 - len(currentWord)
}
}
// Some LSP clients (e.g. VSCode) auto-pair brackets, so we need to

@ -3,10 +3,14 @@ package lsp
import (
"fmt"
"net/url"
"path/filepath"
"runtime"
"strings"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/errors"
"github.com/tliron/glsp"
protocol "github.com/tliron/glsp/protocol_3_16"
)
func pathToURI(path string) string {
@ -56,3 +60,59 @@ func (b *jsonBoolean) UnmarshalJSON(data []byte) error {
}
return nil
}
type linkInfo struct {
note *core.MinimalNote
location *protocol.Location
title *string
}
func linkNote(notebook *core.Notebook, documents *documentStore, context *glsp.Context, info *linkInfo) error {
if info.location == nil {
return errors.New("'location' not provided")
}
// Get current document to edit
doc, ok := documents.Get(info.location.URI)
if !ok {
return fmt.Errorf("Cannot insert link in '%s'", info.location.URI)
}
formatter, err := notebook.NewLinkFormatter()
if err != nil {
return err
}
path := core.NotebookPath{
Path: info.note.Path,
BasePath: notebook.Path,
WorkingDir: filepath.Dir(doc.Path),
}
var title *string
title = info.title
if title == nil {
title = &info.note.Title
}
formatterContext, err := core.NewLinkFormatterContext(path, *title, info.note.Metadata)
if err != nil {
return err
}
link, err := formatter(formatterContext)
if err != nil {
return err
}
go context.Call(protocol.ServerWorkspaceApplyEdit, protocol.ApplyWorkspaceEditParams{
Edit: protocol.WorkspaceEdit{
Changes: map[string][]protocol.TextEdit{
info.location.URI: {{Range: info.location.Range, NewText: link}},
},
},
}, nil)
return nil
}

@ -6,7 +6,6 @@ import (
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
gast "github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"
"github.com/yuin/goldmark/text"
"github.com/yuin/goldmark/util"
@ -14,7 +13,7 @@ import (
// Tags represents a list of inline tags in a Markdown document.
type Tags struct {
gast.BaseInline
ast.BaseInline
// Tags in this list.
Tags []string
}
@ -22,13 +21,13 @@ type Tags struct {
func (n *Tags) Dump(source []byte, level int) {
m := map[string]string{}
m["Tags"] = strings.Join(n.Tags, ", ")
gast.DumpHelper(n, source, level, m, nil)
ast.DumpHelper(n, source, level, m, nil)
}
// KindTags is a NodeKind of the Tags node.
var KindTags = gast.NewNodeKind("Tags")
var KindTags = ast.NewNodeKind("Tags")
func (n *Tags) Kind() gast.NodeKind {
func (n *Tags) Kind() ast.NodeKind {
return KindTags
}
@ -168,7 +167,7 @@ func (p *hashtagParser) Parse(parent ast.Node, block text.Reader, pc parser.Cont
block.Advance(endPos)
return &Tags{
BaseInline: gast.BaseInline{},
BaseInline: ast.BaseInline{},
Tags: []string{tag},
}
}
@ -248,7 +247,7 @@ func (p *colontagParser) Parse(parent ast.Node, block text.Reader, pc parser.Con
block.Advance(endPos)
return &Tags{
BaseInline: gast.BaseInline{},
BaseInline: ast.BaseInline{},
Tags: tags,
}
}
@ -267,7 +266,7 @@ func isValidTag(tag string) bool {
}
// Prevent Markdown table syntax to be parsed a a colon tag, e.g. |:---:|
// https://github.com/mickael-menu/zk/issues/185
// https://github.com/zk-org/zk/issues/185
for _, c := range tag {
if c != '-' {
return true

@ -3,7 +3,7 @@ package extensions
import (
"strings"
"github.com/mickael-menu/zk/internal/core"
"github.com/zk-org/zk/internal/core"
"github.com/yuin/goldmark"
"github.com/yuin/goldmark/ast"
"github.com/yuin/goldmark/parser"

@ -7,12 +7,12 @@ import (
"regexp"
"strings"
"github.com/mickael-menu/zk/internal/adapter/markdown/extensions"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/opt"
strutil "github.com/mickael-menu/zk/internal/util/strings"
"github.com/mickael-menu/zk/internal/util/yaml"
"github.com/zk-org/zk/internal/adapter/markdown/extensions"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/opt"
strutil "github.com/zk-org/zk/internal/util/strings"
"github.com/zk-org/zk/internal/util/yaml"
"github.com/mvdan/xurls"
"github.com/yuin/goldmark"
meta "github.com/yuin/goldmark-meta"

@ -3,10 +3,10 @@ package markdown
import (
"testing"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/opt"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/opt"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestParseTitle(t *testing.T) {
@ -190,7 +190,7 @@ func TestParseHashtags(t *testing.T) {
test("#multi word# end", []string{"multi"})
// Single character
// See https://github.com/mickael-menu/zk/issues/118
// See https://github.com/zk-org/zk/issues/118
test("#a", []string{"a"})
}
@ -570,7 +570,7 @@ A link can have [one relation](one "rel-1") or [several relations](several "rel-
})
// Markdown links are decoded, but not WikiLinks.
// i.e. https://github.com/mickael-menu/zk/issues/86
// i.e. https://github.com/zk-org/zk/issues/86
test("[foo%20bar](202110031652%20foo%20bar)", []core.Link{
{
Title: "foo%20bar",

@ -5,9 +5,9 @@ import (
"fmt"
"strings"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
)
// CollectionDAO persists collections (e.g. tags) in the SQLite database.

@ -3,9 +3,9 @@ package sqlite
import (
"testing"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestCollectionDAOFindOrCreate(t *testing.T) {

@ -6,8 +6,8 @@ import (
"regexp"
sqlite "github.com/mattn/go-sqlite3"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/errors"
)
func init() {
@ -214,7 +214,7 @@ func (db *DB) migrate() error {
{ // 7
SQL: []string{},
// https://github.com/mickael-menu/zk/issues/170#issuecomment-1107848441
// https://github.com/zk-org/zk/issues/170#issuecomment-1107848441
NeedsReindexing: true,
},
}

@ -3,8 +3,8 @@ package sqlite
import (
"testing"
"github.com/mickael-menu/zk/internal/util/fixtures"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/util/fixtures"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestOpen(t *testing.T) {

@ -4,8 +4,8 @@ import (
"database/sql"
"fmt"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
)
// LinkDAO persists links in the SQLite database.

@ -4,9 +4,9 @@ import (
"fmt"
"testing"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/test/assert"
)
func testLinkDAO(t *testing.T, callback func(tx Transaction, dao *LinkDAO)) {

@ -3,7 +3,7 @@ package sqlite
import (
"database/sql"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/errors"
)
// Known metadata keys.

@ -3,7 +3,7 @@ package sqlite
import (
"testing"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestMetadataDAOGetUnknown(t *testing.T) {

@ -8,13 +8,12 @@ import (
"strings"
"time"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/fts5"
"github.com/mickael-menu/zk/internal/util/opt"
"github.com/mickael-menu/zk/internal/util/paths"
strutil "github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/fts5"
"github.com/zk-org/zk/internal/util/paths"
strutil "github.com/zk-org/zk/internal/util/strings"
)
// NoteDAO persists notes in the SQLite database.
@ -75,7 +74,7 @@ func NewNoteDAO(tx Transaction, logger util.Logger) *NoteDAO {
SELECT id FROM notes
WHERE path REGEXP ?
-- To find the best match possible, we sort by path length.
-- See https://github.com/mickael-menu/zk/issues/23
-- See https://github.com/zk-org/zk/issues/23
ORDER BY LENGTH(path) ASC
`),
@ -421,9 +420,7 @@ func (d *NoteDAO) expandMentionsIntoMatch(opts core.NoteFindOpts) (core.NoteFind
}
// Expand the mention queries in the match predicate.
match := opts.Match.String()
match += " " + strings.Join(mentionQueries, " OR ")
opts.Match = opt.NewString(match)
opts.Match = append(opts.Match, " ("+strings.Join(mentionQueries, " OR ")+") ")
return opts, nil
}
@ -448,7 +445,7 @@ func (d *NoteDAO) findRows(opts core.NoteFindOpts, selection noteSelection) (*sq
transitiveClosure := false
maxDistance := 0
setupLinkFilter := func(hrefs []string, direction int, negate, recursive bool) error {
setupLinkFilter := func(tableAlias string, hrefs []string, direction int, negate, recursive bool) error {
ids, err := d.findIdsByHrefs(hrefs, true /* allowPartialHrefs */)
if err != nil {
return err
@ -463,27 +460,29 @@ func (d *NoteDAO) findRows(opts core.NoteFindOpts, selection noteSelection) (*sq
if recursive {
transitiveClosure = true
linksSrc = "transitive_closure"
additionalOrderTerms = append(additionalOrderTerms, tableAlias+".distance")
}
if !negate {
if direction != 0 {
snippetCol = "GROUP_CONCAT(REPLACE(l.snippet, l.title, '<zk:match>' || l.title || '</zk:match>'), '\x01')"
snippetCol = fmt.Sprintf("GROUP_CONCAT(REPLACE(%s.snippet, %[1]s.title, '<zk:match>' || %[1]s.title || '</zk:match>'), '\x01')", tableAlias)
}
joinOns := make([]string, 0)
if direction <= 0 {
joinOns = append(joinOns, fmt.Sprintf(
"(n.id = l.target_id AND l.source_id IN %s)", idsList,
"(n.id = %[1]s.target_id AND %[1]s.source_id IN %[2]s)", tableAlias, idsList,
))
}
if direction >= 0 {
joinOns = append(joinOns, fmt.Sprintf(
"(n.id = l.source_id AND l.target_id IN %s)", idsList,
"(n.id = %[1]s.source_id AND %[1]s.target_id IN %[2]s)", tableAlias, idsList,
))
}
joinClauses = append(joinClauses, fmt.Sprintf(
"LEFT JOIN %s l ON %s",
"LEFT JOIN %[2]s %[1]s ON %[3]s",
tableAlias,
linksSrc,
strings.Join(joinOns, " OR "),
))
@ -517,20 +516,26 @@ func (d *NoteDAO) findRows(opts core.NoteFindOpts, selection noteSelection) (*sq
return nil
}
if !opts.Match.IsNull() {
if 0 < len(opts.Match) {
switch opts.MatchStrategy {
case core.MatchStrategyExact:
whereExprs = append(whereExprs, `n.raw_content LIKE '%' || ? || '%' ESCAPE '\'`)
args = append(args, escapeLikeTerm(opts.Match.String(), '\\'))
for _, match := range opts.Match {
whereExprs = append(whereExprs, `n.raw_content LIKE '%' || ? || '%' ESCAPE '\'`)
args = append(args, escapeLikeTerm(match, '\\'))
}
case core.MatchStrategyFts:
snippetCol = `snippet(fts_match.notes_fts, 2, '<zk:match>', '</zk:match>', '…', 20)`
joinClauses = append(joinClauses, "JOIN notes_fts fts_match ON n.id = fts_match.rowid")
additionalOrderTerms = append(additionalOrderTerms, `bm25(fts_match.notes_fts, 1000.0, 500.0, 1.0)`)
whereExprs = append(whereExprs, "fts_match.notes_fts MATCH ?")
args = append(args, fts5.ConvertQuery(opts.Match.String()))
for _, match := range opts.Match {
whereExprs = append(whereExprs, "fts_match.notes_fts MATCH ?")
args = append(args, fts5.ConvertQuery(match))
}
case core.MatchStrategyRe:
whereExprs = append(whereExprs, "n.raw_content REGEXP ?")
args = append(args, opts.Match.String())
for _, match := range opts.Match {
whereExprs = append(whereExprs, "n.raw_content REGEXP ?")
args = append(args, match)
}
break
}
}
@ -618,7 +623,7 @@ WHERE collection_id IN (SELECT id FROM collections t WHERE kind = '%s' AND (%s))
if opts.LinkedBy != nil {
filter := opts.LinkedBy
maxDistance = filter.MaxDistance
err := setupLinkFilter(filter.Hrefs, -1, filter.Negate, filter.Recursive)
err := setupLinkFilter("l_by", filter.Hrefs, -1, filter.Negate, filter.Recursive)
if err != nil {
return nil, err
}
@ -627,7 +632,7 @@ WHERE collection_id IN (SELECT id FROM collections t WHERE kind = '%s' AND (%s))
if opts.LinkTo != nil {
filter := opts.LinkTo
maxDistance = filter.MaxDistance
err := setupLinkFilter(filter.Hrefs, 1, filter.Negate, filter.Recursive)
err := setupLinkFilter("l_to", filter.Hrefs, 1, filter.Negate, filter.Recursive)
if err != nil {
return nil, err
}
@ -635,11 +640,11 @@ WHERE collection_id IN (SELECT id FROM collections t WHERE kind = '%s' AND (%s))
if opts.Related != nil {
maxDistance = 2
err := setupLinkFilter(opts.Related, 0, false, true)
err := setupLinkFilter("l_rel", opts.Related, 0, false, true)
if err != nil {
return nil, err
}
groupBy += " HAVING MIN(l.distance) = 2"
groupBy += " HAVING MIN(l_rel.distance) = 2"
}
if opts.Orphan {
@ -687,8 +692,6 @@ WHERE collection_id IN (SELECT id FROM collections t WHERE kind = '%s' AND (%s))
// Credit to https://inviqa.com/blog/storing-graphs-database-sql-meets-social-network
if transitiveClosure {
orderTerms = append([]string{"l.distance"}, orderTerms...)
query += `WITH RECURSIVE transitive_closure(source_id, target_id, title, snippet, distance, path) AS (
SELECT source_id, target_id, title, snippet,
1 AS distance,

@ -6,11 +6,11 @@ import (
"testing"
"time"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/opt"
"github.com/mickael-menu/zk/internal/util/paths"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/opt"
"github.com/zk-org/zk/internal/util/paths"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestNoteDAOIndexed(t *testing.T) {
@ -239,7 +239,7 @@ func TestNoteDAOFindIdsByHref(t *testing.T) {
test("test", true, []core.NoteID{6, 5, 8})
// Filename takes precedence over the rest of the path.
// See https://github.com/mickael-menu/zk/issues/111
// See https://github.com/zk-org/zk/issues/111
test("ref", true, []core.NoteID{8})
}
@ -258,7 +258,7 @@ func TestNoteDAOFindIncludingHrefs(t *testing.T) {
test("test", true, []string{"ref/test/ref.md", "ref/test/b.md", "ref/test/a.md"})
// Filename takes precedence over the rest of the path.
// See https://github.com/mickael-menu/zk/issues/111
// See https://github.com/zk-org/zk/issues/111
test("ref", true, []string{"ref/test/ref.md"})
}
@ -280,7 +280,7 @@ func TestNoteDAOFindExcludingHrefs(t *testing.T) {
"log/2021-02-04.md", "index.md", "log/2021-01-04.md"})
// Filename takes precedence over the rest of the path.
// See https://github.com/mickael-menu/zk/issues/111
// See https://github.com/zk-org/zk/issues/111
test("ref", true, []string{"ref/test/b.md", "f39c8.md", "ref/test/a.md",
"log/2021-01-03.md", "log/2021-02-04.md", "index.md", "log/2021-01-04.md"})
}
@ -312,7 +312,7 @@ func TestNoteDAOFindMinimalAll(t *testing.T) {
func TestNoteDAOFindMinimalWithFilter(t *testing.T) {
testNoteDAO(t, func(tx Transaction, dao *NoteDAO) {
notes, err := dao.FindMinimal(core.NoteFindOpts{
Match: opt.NewString("daily | index"),
Match: []string{"daily | index"},
MatchStrategy: core.MatchStrategyFts,
Sorters: []core.NoteSorter{{Field: core.NoteSortWordCount, Ascending: true}},
Limit: 3,
@ -368,7 +368,7 @@ func TestNoteDAOFindTag(t *testing.T) {
func TestNoteDAOFindMatch(t *testing.T) {
testNoteDAOFind(t,
core.NoteFindOpts{
Match: opt.NewString("daily | index"),
Match: []string{"daily | index"},
MatchStrategy: core.MatchStrategyFts,
},
[]core.ContextualNote{
@ -452,10 +452,25 @@ func TestNoteDAOFindMatch(t *testing.T) {
)
}
func TestNoteDAOFindMatchWithMultiMatch(t *testing.T) {
testNoteDAOFindPaths(t,
core.NoteFindOpts{
Match: []string{"daily | index", "second"},
MatchStrategy: core.MatchStrategyFts,
Sorters: []core.NoteSorter{
{Field: core.NoteSortPath, Ascending: false},
},
},
[]string{
"log/2021-01-04.md",
},
)
}
func TestNoteDAOFindMatchWithSort(t *testing.T) {
testNoteDAOFindPaths(t,
core.NoteFindOpts{
Match: opt.NewString("daily | index"),
Match: []string{"daily | index"},
MatchStrategy: core.MatchStrategyFts,
Sorters: []core.NoteSorter{
{Field: core.NoteSortPath, Ascending: false},
@ -474,7 +489,7 @@ func TestNoteDAOFindExactMatch(t *testing.T) {
test := func(match string, expected []string) {
testNoteDAOFindPaths(t,
core.NoteFindOpts{
Match: opt.NewString(match),
Match: []string{match},
MatchStrategy: core.MatchStrategyExact,
},
expected,

@ -5,11 +5,11 @@ import (
"regexp"
"strings"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/paths"
strutil "github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/paths"
strutil "github.com/zk-org/zk/internal/util/strings"
)
// NoteIndex persists note indexing results in the SQLite database.
@ -150,7 +150,7 @@ func (ni *NoteIndex) fixExistingLinks(dao *dao, id core.NoteID, path string) err
for _, link := range links {
// To find the best match possible, shortest paths take precedence.
// See https://github.com/mickael-menu/zk/issues/23
// See https://github.com/zk-org/zk/issues/23
if link.TargetPath != "" && len(link.TargetPath) < len(path) {
continue
}

@ -4,9 +4,9 @@ import (
"fmt"
"testing"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/test/assert"
)
// FIXME: Missing tests

@ -4,7 +4,7 @@ import (
"database/sql"
"sync"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/errors"
)
// LazyStmt is a wrapper around a sql.Stmt which will be evaluated on first use.

@ -1,4 +1,4 @@
# See https://github.com/mickael-menu/zk/issues/23
# See https://github.com/zk-org/zk/issues/23
- id: 1
path: "prefix-longest.md"
sortable_path: "prefix-longest.md"

@ -4,8 +4,8 @@ import (
"testing"
"github.com/go-testfixtures/testfixtures/v3"
"github.com/mickael-menu/zk/internal/util/opt"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/util/opt"
"github.com/zk-org/zk/internal/util/test/assert"
)
// testDB is an utility function to create a database loaded with the default fixtures.

@ -6,8 +6,8 @@ import (
"strconv"
"strings"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/errors"
)
type RowScanner interface {

@ -3,7 +3,7 @@ package sqlite
import (
"testing"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestEscapeLikeTerm(t *testing.T) {

@ -4,7 +4,7 @@ import (
"fmt"
"github.com/fatih/color"
"github.com/mickael-menu/zk/internal/core"
"github.com/zk-org/zk/internal/core"
)
// Style implements core.Styler using ANSI escape codes to be used with a terminal.

@ -4,8 +4,8 @@ import (
"testing"
"github.com/fatih/color"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/test/assert"
)
func createTerminal() *Terminal {

@ -5,10 +5,10 @@ import (
"os"
"path/filepath"
"github.com/mickael-menu/zk/internal/adapter/fzf"
"github.com/mickael-menu/zk/internal/cli"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/zk-org/zk/internal/adapter/fzf"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/errors"
)
// Edit opens notes matching a set of criteria with the user editor.

@ -5,11 +5,11 @@ import (
"fmt"
"os"
"github.com/mickael-menu/zk/internal/adapter/fzf"
"github.com/mickael-menu/zk/internal/cli"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/adapter/fzf"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/strings"
)
// Graph produces a directed graph of the notes matching a set of criteria.

@ -5,9 +5,9 @@ import (
"os"
"time"
"github.com/mickael-menu/zk/internal/cli"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/paths"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/paths"
"github.com/schollz/progressbar/v3"
)

@ -6,9 +6,9 @@ import (
"github.com/AlecAivazis/survey/v2"
"github.com/AlecAivazis/survey/v2/terminal"
"github.com/mickael-menu/zk/internal/cli"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/strings"
)
// Init creates a notebook in the given directory

@ -5,10 +5,10 @@ import (
"io"
"os"
"github.com/mickael-menu/zk/internal/adapter/fzf"
"github.com/mickael-menu/zk/internal/cli"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/adapter/fzf"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/strings"
)
// List displays notes matching a set of criteria.
@ -155,26 +155,26 @@ var defaultNoteFormats = map[string]string{
"path": `{{path}}`,
"link": `{{link}}`,
"oneline": `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})`,
"oneline": `{{style "title" title}} {{style "path" path}} ({{format-date created "elapsed"}})`,
"short": `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})
"short": `{{style "title" title}} {{style "path" path}} ({{format-date created "elapsed"}})
{{list snippets}}`,
"medium": `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
Created: {{format-date created "short"}}
{{list snippets}}`,
"long": `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
Modified: {{date modified "short"}}
Created: {{format-date created "short"}}
Modified: {{format-date modified "short"}}
{{list snippets}}`,
"full": `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
Modified: {{date modified "short"}}
Created: {{format-date created "short"}}
Modified: {{format-date modified "short"}}
Tags: {{join tags ", "}}
{{prepend " " body}}

@ -3,12 +3,12 @@ package cmd
import (
"testing"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestListFormatDefault(t *testing.T) {
cmd := List{}
assert.Equal(t, cmd.noteTemplate(), `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})
assert.Equal(t, cmd.noteTemplate(), `{{style "title" title}} {{style "path" path}} ({{format-date created "elapsed"}})
{{list snippets}}`)
}
@ -25,26 +25,26 @@ func TestListFormatPredefined(t *testing.T) {
test("path", `{{path}}`)
test("link", `{{link}}`)
test("oneline", `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})`)
test("oneline", `{{style "title" title}} {{style "path" path}} ({{format-date created "elapsed"}})`)
test("short", `{{style "title" title}} {{style "path" path}} ({{date created "elapsed"}})
test("short", `{{style "title" title}} {{style "path" path}} ({{format-date created "elapsed"}})
{{list snippets}}`)
test("medium", `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
Created: {{format-date created "short"}}
{{list snippets}}`)
test("long", `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
Modified: {{date modified "short"}}
Created: {{format-date created "short"}}
Modified: {{format-date modified "short"}}
{{list snippets}}`)
test("full", `{{style "title" title}} {{style "path" path}}
Created: {{date created "short"}}
Modified: {{date modified "short"}}
Created: {{format-date created "short"}}
Modified: {{format-date modified "short"}}
Tags: {{join tags ", "}}
{{prepend " " body}}

@ -1,9 +1,9 @@
package cmd
import (
"github.com/mickael-menu/zk/internal/adapter/lsp"
"github.com/mickael-menu/zk/internal/cli"
"github.com/mickael-menu/zk/internal/util/opt"
"github.com/zk-org/zk/internal/adapter/lsp"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/util/opt"
)
// LSP starts a server implementing the Language Server Protocol.

@ -3,28 +3,29 @@ package cmd
import (
"errors"
"fmt"
"io/ioutil"
"io"
"os"
"path/filepath"
"time"
"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"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/core"
dateutil "github.com/zk-org/zk/internal/util/date"
"github.com/zk-org/zk/internal/util/opt"
)
// New adds a new note to the notebook.
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."`
PrintPath bool `short:p help:"Print the path of the created note instead of editing it."`
DryRun bool `short:n help:"Don't actually create the note. Instead, prints its content on stdout and the generated path on stderr."`
ID string ` placeholder:ID help:"Skip id generation and use provided value."`
Directory string `arg optional default:"." help:"Directory in which to create the note."`
Interactive bool `short:i help:"Read contents from standard input."`
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."`
PrintPath bool `short:p help:"Print the path of the created note instead of editing it."`
DryRun bool `short:n help:"Don't actually create the note. Instead, prints its content on stdout and the generated path on stderr."`
ID string ` placeholder:ID help:"Skip id generation and use provided value."`
}
func (cmd *New) Run(container *cli.Container) error {
@ -33,9 +34,12 @@ func (cmd *New) Run(container *cli.Container) error {
return err
}
content, err := ioutil.ReadAll(os.Stdin)
if err != nil {
return err
var content []byte
if cmd.Interactive {
content, err = io.ReadAll(os.Stdin)
if err != nil {
return err
}
}
date := time.Now()

@ -5,10 +5,10 @@ import (
"io"
"os"
"github.com/mickael-menu/zk/internal/cli"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/cli"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/strings"
)
// Tag manages the note tags in the notebook.

@ -4,22 +4,23 @@ import (
"io"
"os"
"path/filepath"
"strings"
"github.com/mickael-menu/zk/internal/adapter/editor"
"github.com/mickael-menu/zk/internal/adapter/fs"
"github.com/mickael-menu/zk/internal/adapter/fzf"
"github.com/mickael-menu/zk/internal/adapter/handlebars"
hbhelpers "github.com/mickael-menu/zk/internal/adapter/handlebars/helpers"
"github.com/mickael-menu/zk/internal/adapter/markdown"
"github.com/mickael-menu/zk/internal/adapter/sqlite"
"github.com/mickael-menu/zk/internal/adapter/term"
"github.com/mickael-menu/zk/internal/core"
"github.com/mickael-menu/zk/internal/util"
"github.com/mickael-menu/zk/internal/util/errors"
osutil "github.com/mickael-menu/zk/internal/util/os"
"github.com/mickael-menu/zk/internal/util/pager"
"github.com/mickael-menu/zk/internal/util/paths"
"github.com/mickael-menu/zk/internal/util/rand"
"github.com/zk-org/zk/internal/adapter/editor"
"github.com/zk-org/zk/internal/adapter/fs"
"github.com/zk-org/zk/internal/adapter/fzf"
"github.com/zk-org/zk/internal/adapter/handlebars"
hbhelpers "github.com/zk-org/zk/internal/adapter/handlebars/helpers"
"github.com/zk-org/zk/internal/adapter/markdown"
"github.com/zk-org/zk/internal/adapter/sqlite"
"github.com/zk-org/zk/internal/adapter/term"
"github.com/zk-org/zk/internal/core"
"github.com/zk-org/zk/internal/util"
"github.com/zk-org/zk/internal/util/errors"
osutil "github.com/zk-org/zk/internal/util/os"
"github.com/zk-org/zk/internal/util/pager"
"github.com/zk-org/zk/internal/util/paths"
"github.com/zk-org/zk/internal/util/rand"
)
type Dirs struct {
@ -65,12 +66,32 @@ func NewContainer(version string) (*Container, error) {
return nil, wrap(err)
}
if configPath != "" {
config, err = core.OpenConfig(configPath, config, fs)
config, err = core.OpenConfig(configPath, config, fs, true)
if err != nil {
return nil, wrap(err)
}
}
// Set the default notebook if not already set
// might be overrided if --notebook-dir flag is present
if osutil.GetOptEnv("ZK_NOTEBOOK_DIR").IsNull() && !config.Notebook.Dir.IsNull() {
// Expand in case there are environment variables on the path
notebookDir := os.Expand(config.Notebook.Dir.Unwrap(), os.Getenv)
if strings.HasPrefix(notebookDir, "~") {
dirname, err := os.UserHomeDir()
if err != nil {
return nil, wrap(err)
}
notebookDir = filepath.Join(dirname, notebookDir[1:])
}
os.Setenv("ZK_NOTEBOOK_DIR", notebookDir)
}
// Set the default shell if not already set
if osutil.GetOptEnv("ZK_SHELL").IsNull() && !config.Tool.Shell.IsEmpty() {
os.Setenv("ZK_SHELL", config.Tool.Shell.Unwrap())
}
return &Container{
Version: version,
Config: config,

@ -6,11 +6,10 @@ import (
"github.com/alecthomas/kong"
"github.com/kballard/go-shellquote"
"github.com/mickael-menu/zk/internal/core"
dateutil "github.com/mickael-menu/zk/internal/util/date"
"github.com/mickael-menu/zk/internal/util/errors"
"github.com/mickael-menu/zk/internal/util/opt"
"github.com/mickael-menu/zk/internal/util/strings"
"github.com/zk-org/zk/internal/core"
dateutil "github.com/zk-org/zk/internal/util/date"
"github.com/zk-org/zk/internal/util/errors"
"github.com/zk-org/zk/internal/util/strings"
)
// Filtering holds filtering options to select notes.
@ -19,7 +18,7 @@ type Filtering struct {
Interactive bool `kong:"group='filter',short='i',help='Select notes interactively with fzf.'" json:"-"`
Limit int `kong:"group='filter',short='n',placeholder='COUNT',help='Limit the number of notes found.'" json:"limit"`
Match string `kong:"group='filter',short='m',placeholder='QUERY',help='Terms to search for in the notes.'" json:"match"`
Match []string `kong:"group='filter',short='m',placeholder='QUERY',help='Terms to search for in the notes.'" json:"match"`
MatchStrategy string `kong:"group='filter',short='M',default='fts',placeholder='STRATEGY',help='Text matching strategy among: fts, re, exact.'" json:"matchStrategy"`
Exclude []string `kong:"group='filter',short='x',placeholder='PATH',help='Ignore notes matching the given path, including its descendants.'" json:"excludeHrefs"`
Tag []string `kong:"group='filter',short='t',help='Find notes tagged with the given tags.'" json:"tags"`
@ -117,11 +116,7 @@ func (f Filtering) ExpandNamedFilters(filters map[string]string, expandedFilters
f.ModifiedAfter = parsedFilter.ModifiedAfter
}
if f.Match == "" {
f.Match = parsedFilter.Match
} else if parsedFilter.Match != "" {
f.Match = fmt.Sprintf("(%s) AND (%s)", f.Match, parsedFilter.Match)
}
f.Match = append(f.Match, parsedFilter.Match...)
if f.MatchStrategy == "" {
f.MatchStrategy = parsedFilter.MatchStrategy
}
@ -148,7 +143,8 @@ func (f Filtering) NewNoteFindOpts(notebook *core.Notebook) (core.NoteFindOpts,
return opts, fmt.Errorf("the --exact-match (-e) option is deprecated, use --match-strategy=exact (-Me) instead")
}
opts.Match = opt.NewNotEmptyString(f.Match)
opts.Match = make([]string, len(f.Match))
copy(opts.Match, f.Match)
opts.MatchStrategy, err = core.MatchStrategyFromString(f.MatchStrategy)
if err != nil {
return opts, err
@ -284,7 +280,9 @@ func parseDayRange(date string) (start time.Time, end time.Time, err error) {
return
}
start = startOfDay(day)
// we add -1 second so that the day range ends at 23:59:59
// i.e, the 'new day' begins at 00:00:00
start = startOfDay(day).Add(time.Second * -1)
end = start.AddDate(0, 0, 1)
return start, end, nil
}

@ -3,7 +3,7 @@ package cli
import (
"testing"
"github.com/mickael-menu/zk/internal/util/test/assert"
"github.com/zk-org/zk/internal/util/test/assert"
)
func TestExpandNamedFiltersNone(t *testing.T) {
@ -11,7 +11,7 @@ func TestExpandNamedFiltersNone(t *testing.T) {
Path: []string{"path1"},
Limit: 10,
Interactive: true,
Match: "match query",
Match: []string{"match query"},
Exclude: []string{"excl-path1", "excl-path2"},
Tag: []string{"tag1", "tag2"},
Mention: []string{"mention1", "mention2"},
@ -156,7 +156,7 @@ func TestExpandNamedFiltersJoinLitterals(t *testing.T) {
func TestExpandNamedFiltersJoinMatch(t *testing.T) {
f := Filtering{
Path: []string{"f1", "f2"},
Match: "(chocolate OR caramel)",
Match: []string{"(chocolate OR caramel)"},
}
res, err := f.ExpandNamedFilters(
@ -168,7 +168,7 @@ func TestExpandNamedFiltersJoinMatch(t *testing.T) {
)
assert.Nil(t, err)
assert.Equal(t, res.Match, "(((chocolate OR caramel)) AND (banana)) AND (apple)")
assert.Equal(t, res.Match, []string{"(chocolate OR caramel)", "banana", "apple"})
}
func TestExpandNamedFiltersExpandsRecursively(t *testing.T) {

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save