From 9108f6347e5e93b0bb6a66f0c2a26f924803a0ef Mon Sep 17 00:00:00 2001 From: khimaros Date: Tue, 21 Nov 2023 16:07:55 -0800 Subject: [PATCH] pass fzf query or cmd match to editor environment --- docs/tool-editor.md | 34 +++++++++++++++++++ internal/adapter/editor/editor.go | 6 ++-- internal/adapter/editor/editor_test.go | 10 +++--- internal/adapter/fzf/fzf.go | 5 ++- internal/adapter/fzf/note_filter.go | 4 +++ .../adapter/handlebars/handlebars_test.go | 1 + internal/cli/cmd/edit.go | 7 +++- internal/cli/cmd/new.go | 2 +- internal/cli/container.go | 4 +-- 9 files changed, 61 insertions(+), 12 deletions(-) diff --git a/docs/tool-editor.md b/docs/tool-editor.md index 90b23c2..99fb55b 100644 --- a/docs/tool-editor.md +++ b/docs/tool-editor.md @@ -12,3 +12,37 @@ You can customize which editor to use either from the [configuration file](confi ``` 3. `VISUAL` environment variable 4. `EDITOR` environment variable + +When invoking the editor, `zk` will provide the following environment to the editor: + +`ZK_QUERY`: the query interactively provided to `fzf` or otherwise the value passed with the `-m` flag + +## Advanced editor usage + +It is also possible to create a custom script for your editor, for example to jump to a specific instance of a search term. + +Consider the following script: + +```bash +#!/bin/bash + +set -eou pipefail + +grep -nEv '^[[:space:]]*$' "$1" \ + | fzf \ + --tiebreak=begin \ + --exact \ + --tabstop=4 \ + --height=100% \ + --layout=reverse \ + --no-hscroll \ + --color=hl:-1,hl+:-1 \ + --preview-window=wrap \ + --delimiter=':' \ + --with-nth=2.. \ + --query="${ZK_QUERY}" \ + | sed 's/:.*$//' \ + | xargs -o -I {} vim +{} "$1" +``` + +This script could then be configured as the `editor` in `.zk/config.yaml` to open a second `fzf` instance prepopulated with the query which was previously entered into `zk`. diff --git a/internal/adapter/editor/editor.go b/internal/adapter/editor/editor.go index f02058b..dc55e44 100644 --- a/internal/adapter/editor/editor.go +++ b/internal/adapter/editor/editor.go @@ -15,11 +15,12 @@ import ( // Editor represents an external editor able to edit the notes. type Editor struct { editor string + query string } // NewEditor creates a new Editor from the given editor user setting or the // matching environment variables. -func NewEditor(editor opt.String) (*Editor, error) { +func NewEditor(editor opt.String, query string) (*Editor, error) { editor = osutil.GetOptEnv("ZK_EDITOR"). Or(editor). Or(osutil.GetOptEnv("VISUAL")). @@ -29,7 +30,7 @@ func NewEditor(editor opt.String) (*Editor, error) { return nil, fmt.Errorf("no editor set in config") } - return &Editor{editor.Unwrap()}, nil + return &Editor{editor.Unwrap(), query}, nil } // Open launches the editor with the notes at given paths. @@ -38,6 +39,7 @@ func (e *Editor) Open(paths ...string) error { // initial note content to `zk new`. Without this, Vim doesn't work // properly in this case. // See https://github.com/zk-org/zk/issues/4 + os.Setenv("ZK_QUERY", e.query) cmd := executil.CommandFromString(e.editor + " " + shellquote.Join(paths...) + " 0 { + query = cmd.Match[0] + } + + editor, err := container.NewNoteEditor(notebook, query) if err != nil { return err } diff --git a/internal/cli/cmd/new.go b/internal/cli/cmd/new.go index bc672b8..8379698 100644 --- a/internal/cli/cmd/new.go +++ b/internal/cli/cmd/new.go @@ -96,7 +96,7 @@ func (cmd *New) Run(container *cli.Container) error { fmt.Printf("%+v\n", path) return nil } else { - editor, err := container.NewNoteEditor(notebook) + editor, err := container.NewNoteEditor(notebook, "") if err != nil { return err } diff --git a/internal/cli/container.go b/internal/cli/container.go index 8e65910..627452e 100644 --- a/internal/cli/container.go +++ b/internal/cli/container.go @@ -236,8 +236,8 @@ func (c *Container) NewNoteFilter(opts fzf.NoteFilterOpts) *fzf.NoteFilter { return fzf.NewNoteFilter(opts, c.FS, c.Terminal, c.TemplateLoader) } -func (c *Container) NewNoteEditor(notebook *core.Notebook) (*editor.Editor, error) { - return editor.NewEditor(notebook.Config.Tool.Editor) +func (c *Container) NewNoteEditor(notebook *core.Notebook, query string) (*editor.Editor, error) { + return editor.NewEditor(notebook.Config.Tool.Editor, query) } // Paginate creates an auto-closing io.Writer which will be automatically