From 66d55fd89349b38e61ba2180ea8e7d8e5656c878 Mon Sep 17 00:00:00 2001 From: Junegunn Choi Date: Sun, 25 Sep 2016 02:02:00 +0900 Subject: [PATCH] Make preview windows scrollable Close #669 You can use your mouse or binadble preview-up and preview-down actions to scroll the content of the preview window. fzf --preview 'highlight -O ansi {}' --bind alt-j:preview-down,alt-k:preview-up --- src/options.go | 4 +++ src/terminal.go | 72 ++++++++++++++++++++++++++++++++++++++++++------- 2 files changed, 67 insertions(+), 9 deletions(-) diff --git a/src/options.go b/src/options.go index 6ff71c0f..3b412f83 100644 --- a/src/options.go +++ b/src/options.go @@ -663,6 +663,10 @@ func parseKeymap(keymap map[int]actionType, execmap map[int]string, str string) keymap[key] = actTogglePreview case "toggle-sort": keymap[key] = actToggleSort + case "preview-up": + keymap[key] = actPreviewUp + case "preview-down": + keymap[key] = actPreviewDown default: if isExecuteAction(actLower) { var offset int diff --git a/src/terminal.go b/src/terminal.go index 0e9436a7..9bb92629 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -28,6 +28,13 @@ const ( jumpAcceptEnabled ) +type previewer struct { + text string + lines int + offset int + enabled bool +} + // Terminal represents terminal input/output type Terminal struct { initDelay time.Duration @@ -68,8 +75,7 @@ type Terminal struct { selected map[int32]selectedItem reqBox *util.EventBox preview previewOpts - previewing bool - previewTxt string + previewer previewer previewBox *util.EventBox eventBox *util.EventBox mutex sync.Mutex @@ -119,6 +125,7 @@ const ( reqPrintQuery reqPreviewEnqueue reqPreviewDisplay + reqPreviewRefresh reqQuit ) @@ -165,6 +172,8 @@ const ( actPrintQuery actToggleSort actTogglePreview + actPreviewUp + actPreviewDown actPreviousHistory actNextHistory actExecute @@ -275,8 +284,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal { selected: make(map[int32]selectedItem), reqBox: util.NewEventBox(), preview: opts.Preview, - previewing: previewBox != nil && !opts.Preview.hidden, - previewTxt: "", + previewer: previewer{"", 0, 0, previewBox != nil && !opts.Preview.hidden}, previewBox: previewBox, eventBox: eventBox, mutex: sync.Mutex{}, @@ -772,9 +780,35 @@ func (t *Terminal) printHighlighted(result *Result, bold bool, col1 int, col2 in } } +func numLinesMax(str string, max int) int { + lines := 0 + for lines < max { + idx := strings.Index(str, "\n") + if idx < 0 { + break + } + str = str[idx+1:] + lines++ + } + return lines +} + func (t *Terminal) printPreview() { t.pwindow.Erase() - extractColor(t.previewTxt, nil, func(str string, ansi *ansiState) bool { + skip := t.previewer.offset + extractColor(t.previewer.text, nil, func(str string, ansi *ansiState) bool { + if skip > 0 { + newlines := numLinesMax(str, skip) + if skip <= newlines { + for i := 0; i < skip; i++ { + str = str[strings.Index(str, "\n")+1:] + } + skip = 0 + } else { + skip -= newlines + return true + } + } if ansi != nil && ansi.colored() { return t.pwindow.CFill(str, ansi.fg, ansi.bg, ansi.bold) } @@ -891,7 +925,7 @@ func (t *Terminal) hasPreviewWindow() bool { } func (t *Terminal) isPreviewEnabled() bool { - return t.previewBox != nil && t.previewing + return t.previewBox != nil && t.previewer.enabled } func (t *Terminal) current() string { @@ -1033,7 +1067,11 @@ func (t *Terminal) Loop() { } exit(exitNoMatch) case reqPreviewDisplay: - t.previewTxt = value.(string) + t.previewer.text = value.(string) + t.previewer.lines = strings.Count(t.previewer.text, "\n") + t.previewer.offset = 0 + t.printPreview() + case reqPreviewRefresh: t.printPreview() case reqPrintQuery: C.Close() @@ -1118,10 +1156,10 @@ func (t *Terminal) Loop() { return false case actTogglePreview: if t.hasPreviewWindow() { - t.previewing = !t.previewing + t.previewer.enabled = !t.previewer.enabled t.resizeWindows() cnt := t.merger.Length() - if t.previewing && cnt > 0 && cnt > t.cy { + if t.previewer.enabled && cnt > 0 && cnt > t.cy { t.previewBox.Set(reqPreviewEnqueue, previewRequest{true, t.current()}) } req(reqList, reqInfo) @@ -1131,6 +1169,18 @@ func (t *Terminal) Loop() { t.eventBox.Set(EvtSearchNew, t.sort) t.mutex.Unlock() return false + case actPreviewUp: + if t.isPreviewEnabled() { + t.previewer.offset = util.Constrain( + t.previewer.offset-1, 0, t.previewer.lines-t.pwindow.Height) + req(reqPreviewRefresh) + } + case actPreviewDown: + if t.isPreviewEnabled() { + t.previewer.offset = util.Constrain( + t.previewer.offset+1, 0, t.previewer.lines-t.pwindow.Height) + req(reqPreviewRefresh) + } case actBeginningOfLine: t.cx = 0 case actBackwardChar: @@ -1299,6 +1349,10 @@ func (t *Terminal) Loop() { } t.vmove(me.S) req(reqList) + } else if t.isPreviewEnabled() && t.pwindow.Enclose(my, mx) { + t.previewer.offset = util.Constrain( + t.previewer.offset-me.S, 0, t.previewer.lines-t.pwindow.Height) + req(reqPreviewRefresh) } } else if t.window.Enclose(my, mx) { mx -= t.window.Left