diff --git a/CHANGELOG.md b/CHANGELOG.md index 96a9945..b5a8519 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,16 @@ CHANGELOG 0.31.0 ------ +- Added support for an alternative preview window layout that is activated + when the size of the preview window is smaller than a certain threshold. + ```sh + # If the width of the preview window is smaller than 50 columns, + # it will be displayed above the search window. + fzf --preview 'cat {}' --preview-window 'right,50%,border-left,<50(up,30%,border-bottom)' + + # Or you can just hide it like so + fzf --preview 'cat {}' --preview-window '<50(hidden)' + ``` - Use SGR mouse mode to support larger terminals - Bug fixes and improvements diff --git a/man/man1/fzf.1 b/man/man1/fzf.1 index d4c0de1..098c374 100644 --- a/man/man1/fzf.1 +++ b/man/man1/fzf.1 @@ -21,7 +21,7 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. .. -.TH fzf 1 "Apr 2022" "fzf 0.30.0" "fzf - a command-line fuzzy finder" +.TH fzf 1 "Jul 2022" "fzf 0.31.0" "fzf - a command-line fuzzy finder" .SH NAME fzf - a command-line fuzzy finder @@ -470,7 +470,7 @@ e.g. done'\fR .RE .TP -.BI "--preview-window=" "[POSITION][,SIZE[%]][,border-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default]" +.BI "--preview-window=" "[POSITION][,SIZE[%]][,border-BORDER_OPT][,[no]wrap][,[no]follow][,[no]cycle][,[no]hidden][,+SCROLL[OFFSETS][/DENOM]][,~HEADER_LINES][,default][, 0 { + opts.threshold = atoi(match[2]) + alternative = match[3] + continue + } + token := match[1] switch token { case "": case "default": @@ -1233,6 +1244,12 @@ func parsePreviewWindow(opts *previewOpts, input string) { } } } + if len(alternative) > 0 { + alternativeOpts := *opts + opts.alternative = &alternativeOpts + opts.alternative.alternative = nil + parsePreviewWindow(opts.alternative, alternative) + } } func parseMargin(opt string, margin string) [4]sizeSpec { diff --git a/src/terminal.go b/src/terminal.go index 3c13b37..96bb641 100644 --- a/src/terminal.go +++ b/src/terminal.go @@ -819,12 +819,15 @@ func (t *Terminal) resizeWindows() { } if t.window != nil { t.window.Close() + t.window = nil } if t.pborder != nil { t.pborder.Close() + t.pborder = nil } if t.pwindow != nil { t.pwindow.Close() + t.pwindow = nil } // Reset preview version so that full redraw occurs t.previewed.version = 0 @@ -869,76 +872,97 @@ func (t *Terminal) resizeWindows() { width = screenWidth - marginInt[1] - marginInt[3] height = screenHeight - marginInt[0] - marginInt[2] + // Set up preview window noBorder := tui.MakeBorderStyle(tui.BorderNone, t.unicode) if previewVisible { - createPreviewWindow := func(y int, x int, w int, h int) { - pwidth := w - pheight := h - var previewBorder tui.BorderStyle - if t.previewOpts.border == tui.BorderNone { - previewBorder = tui.MakeTransparentBorder() - } else { - previewBorder = tui.MakeBorderStyle(t.previewOpts.border, t.unicode) + var resizePreviewWindows func(previewOpts previewOpts) + resizePreviewWindows = func(previewOpts previewOpts) { + if previewOpts.hidden { + return } - t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder) - switch t.previewOpts.border { - case tui.BorderSharp, tui.BorderRounded: - pwidth -= 4 - pheight -= 2 - x += 2 - y += 1 - case tui.BorderLeft: - pwidth -= 2 - x += 2 - case tui.BorderRight: - pwidth -= 2 - case tui.BorderTop: - pheight -= 1 - y += 1 - case tui.BorderBottom: - pheight -= 1 - case tui.BorderHorizontal: - pheight -= 2 - y += 1 - case tui.BorderVertical: - pwidth -= 4 - x += 2 + hasThreshold := previewOpts.threshold > 0 && previewOpts.alternative != nil + createPreviewWindow := func(y int, x int, w int, h int) { + pwidth := w + pheight := h + var previewBorder tui.BorderStyle + if previewOpts.border == tui.BorderNone { + previewBorder = tui.MakeTransparentBorder() + } else { + previewBorder = tui.MakeBorderStyle(previewOpts.border, t.unicode) + } + t.pborder = t.tui.NewWindow(y, x, w, h, true, previewBorder) + switch previewOpts.border { + case tui.BorderSharp, tui.BorderRounded: + pwidth -= 4 + pheight -= 2 + x += 2 + y += 1 + case tui.BorderLeft: + pwidth -= 2 + x += 2 + case tui.BorderRight: + pwidth -= 2 + case tui.BorderTop: + pheight -= 1 + y += 1 + case tui.BorderBottom: + pheight -= 1 + case tui.BorderHorizontal: + pheight -= 2 + y += 1 + case tui.BorderVertical: + pwidth -= 4 + x += 2 + } + t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder) + } + verticalPad := 2 + minPreviewHeight := 3 + switch previewOpts.border { + case tui.BorderNone, tui.BorderVertical, tui.BorderLeft, tui.BorderRight: + verticalPad = 0 + minPreviewHeight = 1 + case tui.BorderTop, tui.BorderBottom: + verticalPad = 1 + minPreviewHeight = 2 + } + switch previewOpts.position { + case posUp, posDown: + pheight := calculateSize(height, previewOpts.size, minHeight, minPreviewHeight, verticalPad) + if hasThreshold && pheight < previewOpts.threshold { + resizePreviewWindows(*previewOpts.alternative) + return + } + if previewOpts.position == posUp { + t.window = t.tui.NewWindow( + marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder) + createPreviewWindow(marginInt[0], marginInt[3], width, pheight) + } else { + t.window = t.tui.NewWindow( + marginInt[0], marginInt[3], width, height-pheight, false, noBorder) + createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight) + } + case posLeft, posRight: + pwidth := calculateSize(width, previewOpts.size, minWidth, 5, 4) + if hasThreshold && pwidth < previewOpts.threshold { + fmt.Println("Alternative", (*previewOpts.alternative).position == posDown) + resizePreviewWindows(*previewOpts.alternative) + return + } + if previewOpts.position == posLeft { + t.window = t.tui.NewWindow( + marginInt[0], marginInt[3]+pwidth, width-pwidth, height, false, noBorder) + createPreviewWindow(marginInt[0], marginInt[3], pwidth, height) + } else { + t.window = t.tui.NewWindow( + marginInt[0], marginInt[3], width-pwidth, height, false, noBorder) + createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height) + } } - t.pwindow = t.tui.NewWindow(y, x, pwidth, pheight, true, noBorder) } - verticalPad := 2 - minPreviewHeight := 3 - switch t.previewOpts.border { - case tui.BorderNone, tui.BorderVertical, tui.BorderLeft, tui.BorderRight: - verticalPad = 0 - minPreviewHeight = 1 - case tui.BorderTop, tui.BorderBottom: - verticalPad = 1 - minPreviewHeight = 2 - } - switch t.previewOpts.position { - case posUp: - pheight := calculateSize(height, t.previewOpts.size, minHeight, minPreviewHeight, verticalPad) - t.window = t.tui.NewWindow( - marginInt[0]+pheight, marginInt[3], width, height-pheight, false, noBorder) - createPreviewWindow(marginInt[0], marginInt[3], width, pheight) - case posDown: - pheight := calculateSize(height, t.previewOpts.size, minHeight, minPreviewHeight, verticalPad) - t.window = t.tui.NewWindow( - marginInt[0], marginInt[3], width, height-pheight, false, noBorder) - createPreviewWindow(marginInt[0]+height-pheight, marginInt[3], width, pheight) - case posLeft: - pwidth := calculateSize(width, t.previewOpts.size, minWidth, 5, 4) - t.window = t.tui.NewWindow( - marginInt[0], marginInt[3]+pwidth, width-pwidth, height, false, noBorder) - createPreviewWindow(marginInt[0], marginInt[3], pwidth, height) - case posRight: - pwidth := calculateSize(width, t.previewOpts.size, minWidth, 5, 4) - t.window = t.tui.NewWindow( - marginInt[0], marginInt[3], width-pwidth, height, false, noBorder) - createPreviewWindow(marginInt[0], marginInt[3]+width-pwidth, pwidth, height) - } - } else { + resizePreviewWindows(t.previewOpts) + } + if t.window == nil { t.window = t.tui.NewWindow( marginInt[0], marginInt[3],