Customize `fzf` options and key bindings (#154)

pull/196/head
Nelyah 2 years ago committed by GitHub
parent 525047fab9
commit 94e8a0d437
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -13,6 +13,13 @@ All notable changes to this project will be documented in this file.
* 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)).
* [#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.
### Changed
* The default `fzf` key binding to create a new note with `zk edit --interactive` was changed to `Ctrl-E`, to avoid conflict with the default `Ctrl-N` binding.
### Fixed

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 60 KiB

After

Width:  |  Height:  |  Size: 60 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 21 KiB

After

Width:  |  Height:  |  Size: 21 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 91 KiB

After

Width:  |  Height:  |  Size: 91 KiB

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 166 KiB

After

Width:  |  Height:  |  Size: 166 KiB

@ -27,7 +27,7 @@ You can customize your experience using [custom templates](template.md) to gener
If you are not sure whether a note already exists for a particular subject, the "search or create" mode might be more appropriate than `zk new`. It is inspired by [Notational Velocity](https://notational.net/) and enables searching for an existing note or creating a new one in a single action.
From `zk`'s interactive edit screen, press `Ctrl-N` to create a new note using the current search query as title.
From `zk`'s interactive edit screen, press `Ctrl-E` to create a new note using the current search query as title.
<div align="center"><img alt="Create a note" width="85%" src="assets/media/new2.svg"/></div>

@ -10,7 +10,7 @@ By default, `zk new` will start [your editor](tool-editor.md) after creating the
If you are not sure whether a note already exists for a particular subject, the "search or create" mode might be more appropriate than `zk new`. It is inspired by [Notational Velocity](https://notational.net/) and enables searching for an existing note or creating a new one in a single action.
This option is available when running `zk edit --interactive`, which spawns [`fzf`](tool-fzf.md) to filter selected notes. From `fzf`, press `Ctrl-N` to create a new note using the current search query as title.
This option is available when running `zk edit --interactive`, which spawns [`fzf`](tool-fzf.md) to filter selected notes. From `fzf`, press `Ctrl-E` to create a new note using the current search query as title.
## Create a note with initial content

@ -60,3 +60,33 @@ The following variables are available in the line template.
| `checksum` | string | SHA-256 checksum of the note file |
1. YAML keys are normalized to lower case.
## `fzf` options
You can override the default `fzf` options used by `zk` with `fzf-options`. Look at `man fzf` for the list of available options.
```toml
[tool]
fzf-options = "--height 40% --border"
```
Note that this overrides all the default options used by `zk`, you might want to keep some of them:
* `--tiebreak begin` Prefer matches located at the beginning of the line
* `--exact` Look for exact matches instead of fuzzy ones by default
* `--tabstop 4` Length of tab characters
* `--height 100%` Height of the list relative to the terminal window
* `--layout reverse` Display the input field at the top
* `--no-hscroll` Make sure the path and titles are always visible
* `--color hl:-1,hl+:-1` Don't highlight search terms
* `--preview-window wrap` Enable line wrapping in the preview window
## Key bindings
When running `fzf` with `zk edit --interactive`, you can [create a new note with the `Ctrl-E` key binding](note-creation.md#search-or-create-with-a-single-command). This binding is customizable with `fzf-bind-new`. You can also disable it by setting it to an empty string (`""`).
```toml
[tool]
fzf-bind-new = "Ctrl-C"
```

@ -8,6 +8,7 @@ import (
"strings"
"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"
@ -26,6 +27,8 @@ var (
type Opts struct {
// Preview command executed by fzf when hovering a line.
PreviewCmd opt.String
// Optionally provide additional arguments, taken from the config `fzf-options` property.
Options opt.String
// Amount of space between two non-empty fields.
Padding int
// Delimiter used by fzf between fields.
@ -72,21 +75,18 @@ func New(opts Opts) (*Fzf, error) {
opts.Delimiter = "\x01"
}
// Hard-coded fzf options that are required by zk.
args := []string{
"--delimiter", opts.Delimiter,
"--tiebreak", "begin",
"--ansi",
"--exact",
"--tabstop", "4",
"--height", "100%",
"--layout", "reverse",
//"--info", "inline",
// Make sure the path and titles are always visible
"--no-hscroll",
// Don't highlight search terms
"--color", "hl:-1,hl+:-1",
"--preview-window", "wrap",
"--delimiter", opts.Delimiter,
}
// Additional options.
additionalArgs, err := shellquote.Split(opts.Options.String())
if err != nil {
return nil, errors.Wrapf(err, "can't split the fzf-options: %s", opts.Options.String())
}
args = append(args, additionalArgs...)
header := ""
binds := []string{}

@ -4,6 +4,7 @@ import (
"fmt"
"os"
"path/filepath"
"strings"
"time"
"github.com/mickael-menu/zk/internal/adapter/term"
@ -32,6 +33,10 @@ type NoteFilterOpts struct {
AlwaysFilter bool
// Format for a single line, taken from the config `fzf-line` property.
LineTemplate opt.String
// Optionally provide additional arguments, taken from the config `fzf-options` property.
FzfOptions opt.String
// Key binding for the new action.
NewBinding opt.String
// Preview command to run when selecting a note.
PreviewCmd opt.String
// When non null, a "create new note from query" binding will be added to
@ -88,16 +93,20 @@ func (f *NoteFilter) Apply(notes []core.ContextualNote) ([]core.ContextualNote,
suffix = " in " + dir.Name + "/"
}
bindings = append(bindings, Binding{
Keys: "Ctrl-N",
Description: "create a note with the query as title" + suffix,
Action: fmt.Sprintf(`abort+execute("%s" new "%s" --title {q} < /dev/tty > /dev/tty)`, zkBin, dir.Path),
})
newBinding := f.opts.NewBinding.OrString("Ctrl-E").String()
if newBinding != "" {
bindings = append(bindings, Binding{
Keys: newBinding,
Description: "create a note with the query as title" + suffix,
Action: fmt.Sprintf(`abort+execute("%s" new "%s" --title {q} < /dev/tty > /dev/tty)`, zkBin, dir.Path),
})
}
}
previewCmd := f.opts.PreviewCmd.OrString("cat {-1}").Unwrap()
fzf, err := New(Opts{
Options: f.opts.FzfOptions.OrString(defaultOptions),
PreviewCmd: opt.NewNotEmptyString(previewCmd),
Padding: 2,
Bindings: bindings,
@ -158,6 +167,18 @@ func (f *NoteFilter) Apply(notes []core.ContextualNote) ([]core.ContextualNote,
var defaultLineTemplate = `{{style "title" title-or-path}} {{style "understate" body}} {{style "understate" (json metadata)}}`
// defaultOptions are the default fzf options used when filtering notes.
var defaultOptions = strings.Join([]string{
"--tiebreak begin", // Prefer matches located at the beginning of the line
"--exact", // Look for exact matches instead of fuzzy ones by default
"--tabstop 4", // Length of tab characters
"--height 100%", // Height of the list relative to the terminal window
"--layout reverse", // Display the input field at the top
"--no-hscroll", // Make sure the path and titles are always visible
"--color hl:-1,hl+:-1", // Don't highlight search terms
"--preview-window wrap", // Enable line wrapping in the preview window
}, " ")
type lineRenderContext struct {
Filename string
FilenameStem string `handlebars:"filename-stem"`

@ -206,6 +206,8 @@ func (c *Container) CurrentNotebook() (*core.Notebook, error) {
func (c *Container) NewNoteFilter(opts fzf.NoteFilterOpts) *fzf.NoteFilter {
opts.PreviewCmd = c.Config.Tool.FzfPreview
opts.LineTemplate = c.Config.Tool.FzfLine
opts.FzfOptions = c.Config.Tool.FzfOptions
opts.NewBinding = c.Config.Tool.FzfBindNew
return fzf.NewNoteFilter(opts, c.FS, c.Terminal, c.TemplateLoader)
}

@ -151,6 +151,8 @@ type ToolConfig struct {
Pager opt.String
FzfPreview opt.String
FzfLine opt.String
FzfOptions opt.String
FzfBindNew opt.String
}
// LSPConfig holds the Language Server Protocol configuration.
@ -362,6 +364,12 @@ func ParseConfig(content []byte, path string, parentConfig Config) (Config, erro
if tool.FzfLine != nil {
config.Tool.FzfLine = opt.NewNotEmptyString(*tool.FzfLine)
}
if tool.FzfOptions != nil {
config.Tool.FzfOptions = opt.NewNotEmptyString(*tool.FzfOptions)
}
if tool.FzfBindNew != nil {
config.Tool.FzfBindNew = opt.NewStringWithPtr(tool.FzfBindNew)
}
// LSP completion
lspCompl := tomlConf.LSP.Completion
@ -506,6 +514,8 @@ type tomlToolConfig struct {
Pager *string
FzfPreview *string `toml:"fzf-preview"`
FzfLine *string `toml:"fzf-line"`
FzfOptions *string `toml:"fzf-options"`
FzfBindNew *string `toml:"fzf-bind-new"`
}
type tomlLSPConfig struct {

@ -89,6 +89,8 @@ func TestParseComplete(t *testing.T) {
pager = "less"
fzf-preview = "bat {1}"
fzf-line = "{{title}}"
fzf-options = "--border --height 40%"
fzf-bind-new = "Ctrl-C"
[extra]
hello = "world"
@ -229,6 +231,8 @@ func TestParseComplete(t *testing.T) {
Pager: opt.NewString("less"),
FzfPreview: opt.NewString("bat {1}"),
FzfLine: opt.NewString("{{title}}"),
FzfOptions: opt.NewString("--border --height 40%"),
FzfBindNew: opt.NewString("Ctrl-C"),
},
LSP: LSPConfig{
Completion: LSPCompletionConfig{

Loading…
Cancel
Save