Rename the `{{date}}` helper to `{{format-date}}` (#274)

pull/276/head
Mickaël Menu 1 year ago committed by GitHub
parent 142b636342
commit 15d4cfc921
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -7,16 +7,20 @@ All notable changes to this project will be documented in this file.
### Added
* LSP: Support for external URLs with `documentLink`.
* New `{{get-date}}` template helper to obtain a date object from natural language.
* New `{{date}}` template helper to obtain a date object from natural language (contributed by [@zalegrala](https://github.com/mickael-menu/zk/pull/262)).
```
Get a relative date using natural language:
{{get-date "next week"}}
{{date "next week"}}
Format a date returned by `get-date`:
{{date (get-date "monday") "timestamp"}}
{{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/mickael-menu/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/mickael-menu/zk/issues/243) LSP: Fixed finding backlink references for notes in a folder.

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: 166 KiB

After

Width:  |  Height:  |  Size: 167 KiB

@ -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]

@ -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).

@ -67,7 +67,7 @@ author = "Mickaël"
paths = ["journal/weekly", "journal/daily"]
[dir.journal.note]
filename = "{{date now}}"
filename = "{{format-date now}}"
# MARKDOWN SETTINGS
@ -114,4 +114,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?
```

@ -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.

@ -38,13 +38,25 @@ The `{{concat s1 s2}}` helper concatenates two strings together. For example `{{
* `{{substring 'A full quote' 2 4}}` outputs `full`
* `{{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

@ -16,7 +16,7 @@ import (
func Init(supportsUTF8 bool, logger util.Logger) {
helpers.RegisterConcat()
helpers.RegisterDate(logger)
helpers.RegisterGetDate(logger)
helpers.RegisterFormatDate(logger)
helpers.RegisterJoin()
helpers.RegisterJSON(logger)
helpers.RegisterList(supportsUTF8)

@ -226,25 +226,25 @@ func TestSlugHelper(t *testing.T) {
)
}
func TestDateHelper(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, "{{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, "14 years ago")
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")
testString(t, "{{format-date now 'elapsed'}}", context, "14 years ago")
}
func TestGetDateHelper(t *testing.T) {
func TestDateHelper(t *testing.T) {
context := map[string]interface{}{"now": time.Date(2009, 11, 17, 20, 34, 58, 651387237, time.UTC)}
localOffsetAndTZ := time.Now().Format("-0700 MST")
testString(t, "{{get-date \"2009-11-17T20:34:58\"}}", context, "2009-11-17 20:34:58 "+localOffsetAndTZ)
testString(t, "{{date \"2009-11-17T20:34:58\"}}", context, "2009-11-17 20:34:58 "+localOffsetAndTZ)
}
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"
dateutil "github.com/mickael-menu/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

@ -1,23 +0,0 @@
package helpers
import (
"time"
"github.com/aymerick/raymond"
"github.com/mickael-menu/zk/internal/util"
dateutil "github.com/mickael-menu/zk/internal/util/date"
"github.com/pkg/errors"
)
// RegisterGetDate registers the {{getdate}} template helper to use the `naturaldate` package to generate time.Time based on language strings.
// This can be used in combination with the `date` helper to generate dates in the user's language.
// {{date (get-date "last week") "timestamp"}}
func RegisterGetDate(logger util.Logger) {
raymond.RegisterHelper("get-date", func(natural string) time.Time {
date, err := dateutil.TimeFromNatural(natural)
if err != nil {
logger.Err(errors.Wrap(err, "the {{get-date}} template helper failed to parse the date"))
}
return date
})
}

@ -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}}

@ -8,7 +8,7 @@ import (
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}}

@ -152,7 +152,7 @@ func (ns *NotebookStore) locateNotebook(path string) (string, error) {
var locate func(string) (string, error)
locate = func(currentPath string) (string, error) {
// For Windows, the root dir may end with volume name, e.g. E:\\
// For Windows, the root dir may end with volume name, e.g. E:\\
if currentPath == "/" || currentPath == filepath.VolumeName(currentPath)+"\\" || currentPath == "." {
return "", ErrNotebookNotFound(path)
}
@ -251,7 +251,7 @@ template = "default.md"
#[group."<NAME>"]
#paths = ["<DIR1>", "<DIR2>"]
#[group."<NAME>".note]
#filename = "\{{date now}}"
#filename = "\{{format-date now}}"
#[group."<NAME>".extra]
#key = "value"

@ -77,7 +77,7 @@ $ cat .zk/config.toml
>#[group."<NAME>"]
>#paths = ["<DIR1>", "<DIR2>"]
>#[group."<NAME>".note]
>#filename = "\{{date now}}"
>#filename = "\{{format-date now}}"
>#[group."<NAME>".extra]
>#key = "value"
>

@ -5,7 +5,7 @@ $ zk new --dry-run
2>{{working-dir}}/{{match "[a-z0-9]{4}"}}.md
# Set a custom filename.
$ echo "[note]\n filename = '\{{slug title}} - \{{date now \"%m-%d\"}}'" > .zk/config.toml
$ echo "[note]\n filename = '\{{slug title}} - \{{format-date now \"%m-%d\"}}'" > .zk/config.toml
$ zk new --title "A new note" --date "January 5th" --dry-run
2>{{working-dir}}/a-new-note - 01-05.md
@ -16,7 +16,7 @@ $ zk new --title "A new note" --date "January 5th" --dry-run
# Test the filename Handlebars variables.
$ mkdir "a dir"
$ echo "[note]\n filename = '\{{title}},\{{content}},\{{date now \"%m-%d\"}},\{{json extra}}'" > .zk/config.toml
$ echo "[note]\n filename = '\{{title}},\{{content}},\{{format-date now \"%m-%d\"}},\{{json extra}}'" > .zk/config.toml
$ echo "Piped content" | zk new --interactive --title "A new note" --date "January 5th" --extra key=value --dry-run
2>{{working-dir}}/A new note,Piped content
2>,01-05,{"key":"value"}.md

@ -1,6 +1,6 @@
$ cd blank
$ echo "[note]\n filename = '\{{slug title}} - \{{date now \"%B\"}}'" > .zk/config.toml
$ echo "[note]\n filename = '\{{slug title}} - \{{format-date now \"%B\"}}'" > .zk/config.toml
# The default language is `en`.
# Note the & converted to `and` in the slug.

@ -6,7 +6,7 @@ template = "default.md"
content = "Default content"
[group.journal.note]
filename = "{{date now '%d-%m'}}"
filename = "{{format-date now '%d-%m'}}"
template = "journal.md"
[group.journal.extra]

@ -4,7 +4,7 @@ filename = "{{slug title}}"
[group.date.note]
template = "empty.md"
filename = "{{date now '%d-%m'}}"
filename = "{{format-date now '%d-%m'}}"
[group.date-raw.note]
template = "empty.md"

@ -3,7 +3,7 @@ title: {{title}}
content: {{content}}
dir: {{dir}}
extra: {{json extra}}
now: {{date now "%d-%m"}}
now: {{format-date now "%d-%m"}}
env: {{env.ZK_NOTEBOOK_DIR}}
filename: {{filename}}
filename-stem: {{filename-stem}}

@ -28,7 +28,7 @@ $ zk list -q --format "\{{path}}: \{{json tags}}"
>case.md: ["writing","essay","practice"]
# Creation date extracted from the frontmatter.
$ zk list -q --format "\{{path}}: \{{date created 'full'}}"
$ zk list -q --format "\{{path}}: \{{format-date created 'full'}}"
>keywords.md: {{match '.*'}}
>empty.md: {{match '.*'}}
>full.md: Monday, May 16, 2011

Loading…
Cancel
Save