Make the fzf preview command customizable

pull/6/head
Mickaël Menu 3 years ago
parent 1f0e536e14
commit e0c8e2fd02
No known key found for this signature in database
GPG Key ID: 53D73664CD359895

@ -28,6 +28,8 @@ type NoteFinder struct {
type NoteFinderOpts struct { type NoteFinderOpts struct {
// Indicates whether fzf is opened for every query, even if empty. // Indicates whether fzf is opened for every query, even if empty.
AlwaysFilter bool AlwaysFilter bool
// Preview command to run when selecting a note.
PreviewCmd opt.String
// When non nil, a "create new note from query" binding will be added to // When non nil, a "create new note from query" binding will be added to
// fzf to create a note in this directory. // fzf to create a note in this directory.
NewNoteDir *zk.Dir NewNoteDir *zk.Dir
@ -84,10 +86,9 @@ func (f *NoteFinder) Find(opts note.FinderOpts) ([]note.Match, error) {
} }
fzf, err := New(Opts{ fzf, err := New(Opts{
// PreviewCmd: opt.NewString("bat -p --theme Nord --color always {1}"), PreviewCmd: f.opts.PreviewCmd.OrString("cat {1}").NonEmpty(),
PreviewCmd: opt.NewString(zkBin + " list -f {{raw-content}} {1}"),
Padding: 2, Padding: 2,
Bindings: bindings, Bindings: bindings,
}) })
if err != nil { if err != nil {
return selectedMatches, err return selectedMatches, err

@ -45,6 +45,7 @@ func (cmd *Edit) Run(container *Container) error {
err = db.WithTransaction(func(tx sqlite.Transaction) error { err = db.WithTransaction(func(tx sqlite.Transaction) error {
finder := container.NoteFinder(tx, fzf.NoteFinderOpts{ finder := container.NoteFinder(tx, fzf.NoteFinderOpts{
AlwaysFilter: true, AlwaysFilter: true,
PreviewCmd: zk.Config.Fzf.Preview,
NewNoteDir: cmd.newNoteDir(zk), NewNoteDir: cmd.newNoteDir(zk),
BasePath: zk.Path, BasePath: zk.Path,
CurrentPath: wd, CurrentPath: wd,

@ -61,6 +61,7 @@ func (cmd *List) Run(container *Container) error {
err = db.WithTransaction(func(tx sqlite.Transaction) error { err = db.WithTransaction(func(tx sqlite.Transaction) error {
finder := container.NoteFinder(tx, fzf.NoteFinderOpts{ finder := container.NoteFinder(tx, fzf.NoteFinderOpts{
AlwaysFilter: false, AlwaysFilter: false,
PreviewCmd: zk.Config.Fzf.Preview,
BasePath: zk.Path, BasePath: zk.Path,
CurrentPath: wd, CurrentPath: wd,
}) })

@ -100,7 +100,7 @@ func create(
deps createDeps, deps createDeps,
) (*createdNote, error) { ) (*createdNote, error) {
context := renderContext{ context := renderContext{
Title: opts.Title.OrDefault(opts.Dir.Config.DefaultTitle), Title: opts.Title.OrString(opts.Dir.Config.DefaultTitle).Unwrap(),
Content: opts.Content.Unwrap(), Content: opts.Content.Unwrap(),
Dir: opts.Dir.Name, Dir: opts.Dir.Name,
Extra: opts.Dir.Config.Extra, Extra: opts.Dir.Config.Extra,

@ -46,7 +46,7 @@ func NewFormatter(basePath string, currentPath string, format opt.String, templa
} }
func resolveFormatTemplate(format opt.String) string { func resolveFormatTemplate(format opt.String) string {
templ, ok := formatTemplates[format.OrDefault("short")] templ, ok := formatTemplates[format.OrString("short").Unwrap()]
if !ok { if !ok {
templ = format.String() templ = format.String()
// Replace raw \n and \t by actual newlines and tabs in user format. // Replace raw \n and \t by actual newlines and tabs in user format.

@ -14,6 +14,7 @@ type Config struct {
Dirs map[string]DirConfig Dirs map[string]DirConfig
Editor opt.String Editor opt.String
Pager opt.String Pager opt.String
Fzf FzfConfig
Aliases map[string]string Aliases map[string]string
} }
@ -28,6 +29,11 @@ type DirConfig struct {
Extra map[string]string Extra map[string]string
} }
// FzfConfig holds the user configuration for running fzf.
type FzfConfig struct {
Preview opt.String
}
// ConfigOverrides holds user configuration overriden values, for example fed // ConfigOverrides holds user configuration overriden values, for example fed
// from CLI flags. // from CLI flags.
type ConfigOverrides struct { type ConfigOverrides struct {
@ -128,7 +134,10 @@ func ParseConfig(content []byte, templatesDir string) (*Config, error) {
Dirs: dirs, Dirs: dirs,
Editor: opt.NewNotEmptyString(tomlConf.Editor), Editor: opt.NewNotEmptyString(tomlConf.Editor),
Pager: opt.NewStringWithPtr(tomlConf.Pager), Pager: opt.NewStringWithPtr(tomlConf.Pager),
Aliases: aliases, Fzf: FzfConfig{
Preview: opt.NewStringWithPtr(tomlConf.Fzf.Preview),
},
Aliases: aliases,
}, nil }, nil
} }
@ -190,6 +199,7 @@ type tomlConfig struct {
Dirs map[string]tomlDirConfig `toml:"dir"` Dirs map[string]tomlDirConfig `toml:"dir"`
Editor string Editor string
Pager *string Pager *string
Fzf tomlFzfConfig
Aliases map[string]string `toml:"alias"` Aliases map[string]string `toml:"alias"`
} }
@ -209,6 +219,10 @@ type tomlIDConfig struct {
Case string Case string
} }
type tomlFzfConfig struct {
Preview *string
}
func charsetFromString(charset string) Charset { func charsetFromString(charset string) Charset {
switch charset { switch charset {
case "alphanum": case "alphanum":

@ -14,8 +14,6 @@ func TestParseDefaultConfig(t *testing.T) {
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, conf, &Config{ assert.Equal(t, conf, &Config{
Editor: opt.NullString,
Pager: opt.NullString,
DirConfig: DirConfig{ DirConfig: DirConfig{
FilenameTemplate: "{{id}}", FilenameTemplate: "{{id}}",
Extension: "md", Extension: "md",
@ -29,7 +27,12 @@ func TestParseDefaultConfig(t *testing.T) {
Lang: "en", Lang: "en",
Extra: make(map[string]string), Extra: make(map[string]string),
}, },
Dirs: make(map[string]DirConfig), Dirs: make(map[string]DirConfig),
Editor: opt.NullString,
Pager: opt.NullString,
Fzf: FzfConfig{
Preview: opt.NullString,
},
Aliases: make(map[string]string), Aliases: make(map[string]string),
}) })
} }
@ -57,6 +60,9 @@ func TestParseComplete(t *testing.T) {
length = 4 length = 4
case = "lower" case = "lower"
[fzf]
preview = "bat {1}"
[extra] [extra]
hello = "world" hello = "world"
salut = "le monde" salut = "le monde"
@ -139,6 +145,9 @@ func TestParseComplete(t *testing.T) {
}, },
Editor: opt.NewString("vim"), Editor: opt.NewString("vim"),
Pager: opt.NewString("less"), Pager: opt.NewString("less"),
Fzf: FzfConfig{
Preview: opt.NewString("bat {1}"),
},
Aliases: map[string]string{ Aliases: map[string]string{
"ls": "zk list $@", "ls": "zk list $@",
"ed": "zk edit $@", "ed": "zk edit $@",
@ -236,12 +245,20 @@ func TestParseMergesDirConfig(t *testing.T) {
}) })
} }
func TestParsePreserveEmptyPager(t *testing.T) { // Some properties like `pager` and `fzf.preview` differentiate between not
conf, err := ParseConfig([]byte(`pager = ""`), "") // being set and an empty string.
func TestParsePreservePropertiesAllowingEmptyValues(t *testing.T) {
conf, err := ParseConfig([]byte(`
pager = ""
[fzf]
preview = ""
`), "")
assert.Nil(t, err) assert.Nil(t, err)
assert.Equal(t, conf.Pager.IsNull(), false) assert.Equal(t, conf.Pager.IsNull(), false)
assert.Equal(t, conf.Pager, opt.NewString("")) assert.Equal(t, conf.Pager, opt.NewString(""))
assert.Equal(t, conf.Fzf.Preview.IsNull(), false)
assert.Equal(t, conf.Fzf.Preview, opt.NewString(""))
} }
func TestParseIDCharset(t *testing.T) { func TestParseIDCharset(t *testing.T) {

@ -41,6 +41,15 @@ func (s String) IsEmpty() bool {
return !s.IsNull() && *s.value == "" return !s.IsNull() && *s.value == ""
} }
// NonEmpty returns a null String if the String is empty.
func (s String) NonEmpty() String {
if s.IsEmpty() {
return NullString
} else {
return s
}
}
// Or returns the receiver if it is not null, otherwise the given optional // Or returns the receiver if it is not null, otherwise the given optional
// String. // String.
func (s String) Or(other String) String { func (s String) Or(other String) String {
@ -51,19 +60,23 @@ func (s String) Or(other String) String {
} }
} }
// OrDefault returns the optional String value or the given default string if // OrString returns the optional String value or the given default string if
// it is null. // it is null.
func (s String) OrDefault(def string) string { func (s String) OrString(alt string) String {
if s.IsNull() { if s.IsNull() {
return def return NewString(alt)
} else { } else {
return *s.value return s
} }
} }
// Unwrap returns the optional String value or an empty String if none is set. // Unwrap returns the optional String value or an empty String if none is set.
func (s String) Unwrap() string { func (s String) Unwrap() string {
return s.OrDefault("") if s.IsNull() {
return ""
} else {
return *s.value
}
} }
func (s String) Equal(other String) bool { func (s String) Equal(other String) bool {
@ -72,7 +85,7 @@ func (s String) Equal(other String) bool {
} }
func (s String) String() string { func (s String) String() string {
return s.OrDefault("") return s.Unwrap()
} }
func (s String) MarshalJSON() ([]byte, error) { func (s String) MarshalJSON() ([]byte, error) {

Loading…
Cancel
Save