From 43f0d0cacde99ba5fdcc32d774cfd8849a6af2b5 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Sat, 4 Dec 2021 11:46:15 +0900 Subject: change-preview-window to take multiple option sets separated by '|' So you can "rotate" through the different options with a single binding. fzf --preview 'cat {}' \ --bind 'ctrl-/:change-preview-window(70%|down,40%,border-horizontal|hidden|)' Close #2376 --- src/options.go | 24 ++++++++++++----------- src/terminal.go | 60 ++++++++++++++++++++++++++++++++++----------------------- 2 files changed, 49 insertions(+), 35 deletions(-) (limited to 'src') diff --git a/src/options.go b/src/options.go index 63b385cd..b3bcdeab 100644 --- a/src/options.go +++ b/src/options.go @@ -224,7 +224,7 @@ type Options struct { Filter *string ToggleSort bool Expect map[tui.Event]string - Keymap map[tui.Event][]action + Keymap map[tui.Event][]*action Preview previewOpts PrintQuery bool ReadZero bool @@ -287,7 +287,7 @@ func defaultOptions() *Options { Filter: nil, ToggleSort: false, Expect: make(map[tui.Event]string), - Keymap: make(map[tui.Event][]action), + Keymap: make(map[tui.Event][]*action), Preview: defaultPreviewOpts(""), PrintQuery: false, ReadZero: false, @@ -798,7 +798,7 @@ func init() { `(?si)[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|unbind):.+|[:+](execute(?:-multi|-silent)?|reload|preview|change-prompt|change-preview-window|change-preview|unbind)(\([^)]*\)|\[[^\]]*\]|~[^~]*~|![^!]*!|@[^@]*@|\#[^\#]*\#|\$[^\$]*\$|%[^%]*%|\^[^\^]*\^|&[^&]*&|\*[^\*]*\*|;[^;]*;|/[^/]*/|\|[^\|]*\|)`) } -func parseKeymap(keymap map[tui.Event][]action, str string) { +func parseKeymap(keymap map[tui.Event][]*action, str string) { masked := executeRegexp.ReplaceAllStringFunc(str, func(src string) string { symbol := ":" if strings.HasPrefix(src, "+") { @@ -854,7 +854,7 @@ func parseKeymap(keymap map[tui.Event][]action, str string) { idx2 := len(pair[0]) + 1 specs := strings.Split(pair[1], "+") - actions := make([]action, 0, len(specs)) + actions := make([]*action, 0, len(specs)) appendAction := func(types ...actionType) { actions = append(actions, toActions(types...)...) } @@ -1033,20 +1033,22 @@ func parseKeymap(keymap map[tui.Event][]action, str string) { if spec[offset] == ':' { if specIndex == len(specs)-1 { actionArg = spec[offset+1:] - actions = append(actions, action{t: t, a: actionArg}) + actions = append(actions, &action{t: t, a: actionArg}) } else { prevSpec = spec + "+" continue } } else { actionArg = spec[offset+1 : len(spec)-1] - actions = append(actions, action{t: t, a: actionArg}) + actions = append(actions, &action{t: t, a: actionArg}) } if t == actUnbind { parseKeyChords(actionArg, "unbind target required") } else if t == actChangePreviewWindow { opts := previewOpts{} - parsePreviewWindow(&opts, actionArg) + for _, arg := range strings.Split(actionArg, "|") { + parsePreviewWindow(&opts, arg) + } } } } @@ -1088,7 +1090,7 @@ func isExecuteAction(str string) actionType { return actIgnore } -func parseToggleSort(keymap map[tui.Event][]action, str string) { +func parseToggleSort(keymap map[tui.Event][]*action, str string) { keys := parseKeyChords(str, "key name required") if len(keys) != 1 { errorExit("multiple keys specified") @@ -1656,7 +1658,7 @@ func postProcessOptions(opts *Options) { // Extend the default key map keymap := defaultKeymap() for key, actions := range opts.Keymap { - lastChangePreviewWindow := action{t: actIgnore} + var lastChangePreviewWindow *action for _, act := range actions { switch act.t { case actToggleSort: @@ -1670,8 +1672,8 @@ func postProcessOptions(opts *Options) { // and it comes first in the list. // * change-preview-window(up,+10)+preview(sleep 3; cat {})+change-preview-window(up,+20) // -> change-preview-window(up,+20)+preview(sleep 3; cat {}) - if lastChangePreviewWindow.t == actChangePreviewWindow { - reordered := []action{lastChangePreviewWindow} + if lastChangePreviewWindow != nil { + reordered := []*action{lastChangePreviewWindow} for _, act := range actions { if act.t != actChangePreviewWindow { reordered = append(reordered, act) diff --git a/src/terminal.go b/src/terminal.go index 804e2b2e..5e89cd4c 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -135,7 +135,7 @@ type Terminal struct { toggleSort bool delimiter Delimiter expect map[tui.Event]string - keymap map[tui.Event][]action + keymap map[tui.Event][]*action pressed string printQuery bool history *History @@ -217,6 +217,7 @@ const ( reqRefresh reqReinit reqRedraw + reqFullRedraw reqClose reqPrintQuery reqPreviewEnqueue @@ -229,6 +230,7 @@ const ( type action struct { t actionType a string + c int } type actionType int @@ -340,16 +342,16 @@ type previewResult struct { spinner string } -func toActions(types ...actionType) []action { - actions := make([]action, len(types)) +func toActions(types ...actionType) []*action { + actions := make([]*action, len(types)) for idx, t := range types { - actions[idx] = action{t: t, a: ""} + actions[idx] = &action{t: t, a: ""} } return actions } -func defaultKeymap() map[tui.Event][]action { - keymap := make(map[tui.Event][]action) +func defaultKeymap() map[tui.Event][]*action { + keymap := make(map[tui.Event][]*action) add := func(e tui.EventType, a actionType) { keymap[e.AsEvent()] = toActions(a) } @@ -1778,8 +1780,10 @@ func replacePlaceholder(template string, stripAnsi bool, delimiter Delimiter, pr }) } -func (t *Terminal) redraw() { - t.tui.Clear() +func (t *Terminal) redraw(clear bool) { + if clear { + t.tui.Clear() + } t.tui.Refresh() t.printAll() } @@ -1799,7 +1803,7 @@ func (t *Terminal) executeCommand(template string, forcePlus bool, background bo t.tui.Pause(true) cmd.Run() t.tui.Resume(true, false) - t.redraw() + t.redraw(true) t.refresh() } else { t.tui.Pause(false) @@ -1944,7 +1948,7 @@ func (t *Terminal) Loop() { go func() { for { <-resizeChan - t.reqBox.Set(reqRedraw, nil) + t.reqBox.Set(reqFullRedraw, nil) } }() @@ -2194,9 +2198,11 @@ func (t *Terminal) Loop() { t.suppress = false case reqReinit: t.tui.Resume(t.fullscreen, t.sigstop) - t.redraw() + t.redraw(true) case reqRedraw: - t.redraw() + t.redraw(false) + case reqFullRedraw: + t.redraw(true) case reqClose: exit(func() int { if t.output() { @@ -2268,7 +2274,6 @@ func (t *Terminal) Loop() { if t.previewer.enabled != enabled { t.previewer.enabled = enabled // We need to immediately update t.pwindow so we don't use reqRedraw - t.tui.Clear() t.resizeWindows() req(reqPrompt, reqList, reqInfo, reqHeader) return true @@ -2310,12 +2315,12 @@ func (t *Terminal) Loop() { } } - actionsFor := func(eventType tui.EventType) []action { + actionsFor := func(eventType tui.EventType) []*action { return t.keymap[eventType.AsEvent()] } - var doAction func(action) bool - doActions := func(actions []action) bool { + var doAction func(*action) bool + doActions := func(actions []*action) bool { for _, action := range actions { if !doAction(action) { return false @@ -2323,7 +2328,7 @@ func (t *Terminal) Loop() { } return true } - doAction = func(a action) bool { + doAction = func(a *action) bool { switch a.t { case actIgnore: case actExecute, actExecuteSilent: @@ -2503,14 +2508,14 @@ func (t *Terminal) Loop() { } case actToggleIn: if t.layout != layoutDefault { - return doAction(action{t: actToggleUp}) + return doAction(&action{t: actToggleUp}) } - return doAction(action{t: actToggleDown}) + return doAction(&action{t: actToggleDown}) case actToggleOut: if t.layout != layoutDefault { - return doAction(action{t: actToggleDown}) + return doAction(&action{t: actToggleDown}) } - return doAction(action{t: actToggleUp}) + return doAction(&action{t: actToggleUp}) case actToggleDown: if t.multi > 0 && t.merger.Length() > 0 && toggle() { t.vmove(-1, true) @@ -2534,7 +2539,7 @@ func (t *Terminal) Loop() { req(reqClose) } case actClearScreen: - req(reqRedraw) + req(reqFullRedraw) case actClearQuery: t.input = []rune{} t.cx = 0 @@ -2732,7 +2737,14 @@ func (t *Terminal) Loop() { // Reset preview options and apply the additional options t.previewOpts = t.initialPreviewOpts - parsePreviewWindow(&t.previewOpts, a.a) + + // Split window options + tokens := strings.Split(a.a, "|") + parsePreviewWindow(&t.previewOpts, tokens[0]) + if len(tokens) > 1 { + a.a = strings.Join(append(tokens[1:], tokens[0]), "|") + a.c++ + } if t.previewOpts.hidden { togglePreview(false) @@ -2761,7 +2773,7 @@ func (t *Terminal) Loop() { if t.jumping == jumpDisabled { actions := t.keymap[event.Comparable()] if len(actions) == 0 && event.Type == tui.Rune { - doAction(action{t: actRune}) + doAction(&action{t: actRune}) } else if !doActions(actions) { continue } -- cgit v1.2.3