Skip to content

Commit

Permalink
Add --no-input to hide the input section (#4210)
Browse files Browse the repository at this point in the history
Close #2890
Close #1396
 
You can't type in queries in this mode, and the only way to trigger an
fzf search is to use `search(...)` action.

  # Click header to trigger search
  fzf --header '[src] [test]' --no-input --layout reverse \
      --header-border bottom --input-border \
      --bind 'click-header:transform-search:echo ${FZF_CLICK_HEADER_WORD:1:-1}'
  • Loading branch information
junegunn authored Jan 29, 2025
1 parent 6b5d461 commit 6c0ca4a
Show file tree
Hide file tree
Showing 9 changed files with 126 additions and 23 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,13 @@ CHANGELOG
```
- `$FZF_KEY` was updated to expose the type of the click. e.g. `click`, `ctrl-click`, etc. You can use it to implement a more sophisticated behavior.
- `kill` completion for bash and zsh were updated to use this feature
- Added `--no-input` option to completely disable and hide the input section
```sh
# Click header to trigger search
fzf --header '[src] [test]' --no-input --layout reverse \
--header-border bottom --input-border \
--bind 'click-header:transform-search:echo ${FZF_CLICK_HEADER_WORD:1:-1}'
```
- Extended `{q}` placeholder to support ranges. e.g. `{q:1}`, `{q:2..}`, etc.
- Added `search(...)` and `transform-search(...)` action to trigger an fzf search with an arbitrary query string. This can be used to extend the search syntax of fzf. In the following example, fzf will use the first word of the query to trigger ripgrep search, and use the rest of the query to perform fzf search within the result.
```sh
Expand Down
5 changes: 5 additions & 0 deletions man/man1/fzf.1
Original file line number Diff line number Diff line change
Expand Up @@ -620,6 +620,11 @@ Position of the list label

.SS INPUT SECTION

.TP
.B "\-\-no\-input"
Disable and hide the input section. You can no longer type in queries. To
trigger a search, use \fBsearch\fR action.

.TP
.BI "\-\-prompt=" "STR"
Input prompt (default: '> ')
Expand Down
19 changes: 15 additions & 4 deletions src/options.go
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,7 @@ Usage: fzf [options]
(default: 0 or center)
INPUT SECTION
--no-input Disable and hide the input section
--prompt=STR Input prompt (default: '> ')
--info=STYLE Finder info style
[default|right|hidden|inline[-right][:PREFIX]]
Expand Down Expand Up @@ -538,6 +539,7 @@ type Options struct {
Scheme string
Extended bool
Phony bool
Inputless bool
Case Case
Normalize bool
Nth []Range
Expand Down Expand Up @@ -659,6 +661,7 @@ func defaultOptions() *Options {
Scheme: "", // Unknown
Extended: true,
Phony: false,
Inputless: false,
Case: CaseSmart,
Normalize: true,
Nth: make([]Range, 0),
Expand Down Expand Up @@ -2315,6 +2318,8 @@ func parseOptions(index *int, opts *Options, allArgs []string) error {
opts.Phony = false
case "--disabled", "--phony":
opts.Phony = true
case "--no-input":
opts.Inputless = true
case "--tiebreak":
str, err := nextString("sort criterion required")
if err != nil {
Expand Down Expand Up @@ -3064,6 +3069,9 @@ func noSeparatorLine(style infoStyle, separator bool) bool {
}

func (opts *Options) noSeparatorLine() bool {
if opts.Inputless {
return true
}
sep := opts.Separator == nil && !opts.InputBorderShape.Visible() || opts.Separator != nil && len(*opts.Separator) > 0
return noSeparatorLine(opts.InfoStyle, sep)
}
Expand Down Expand Up @@ -3235,7 +3243,13 @@ func postProcessOptions(opts *Options) error {

// Sets --min-height automatically
if opts.Height.size > 0 && opts.Height.percent && opts.MinHeight < 0 {
opts.MinHeight = -opts.MinHeight + 1 + borderLines(opts.BorderShape) + borderLines(opts.ListBorderShape) + borderLines(opts.InputBorderShape)
opts.MinHeight = -opts.MinHeight + borderLines(opts.BorderShape) + borderLines(opts.ListBorderShape)
if !opts.Inputless {
opts.MinHeight += 1 + borderLines(opts.InputBorderShape)
if !opts.noSeparatorLine() {
opts.MinHeight++
}
}
if len(opts.Header) > 0 {
opts.MinHeight += borderLines(opts.HeaderBorderShape) + len(opts.Header)
}
Expand All @@ -3246,9 +3260,6 @@ func postProcessOptions(opts *Options) error {
}
opts.MinHeight += borderLines(borderShape) + opts.HeaderLines
}
if !opts.noSeparatorLine() {
opts.MinHeight++
}
if len(opts.Preview.command) > 0 && (opts.Preview.position == posUp || opts.Preview.position == posDown) && opts.Preview.Visible() && opts.Preview.position == posUp {
borderShape := opts.Preview.border
if opts.Preview.border == tui.BorderLine {
Expand Down
63 changes: 49 additions & 14 deletions src/terminal.go
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ type Terminal struct {
cleanExit bool
executor *util.Executor
paused bool
inputless bool
border tui.Window
window tui.Window
inputWindow tui.Window
Expand Down Expand Up @@ -810,6 +811,9 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
if err != nil {
return nil, err
}
if opts.Inputless {
renderer.HideCursor()
}
wordRubout := "[^\\pL\\pN][\\pL\\pN]"
wordNext := "[\\pL\\pN][^\\pL\\pN]|(.$)"
if opts.FileWord {
Expand Down Expand Up @@ -887,6 +891,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox, executor *util.Executor
cleanExit: opts.ClearOnExit,
executor: executor,
paused: opts.Phony,
inputless: opts.Inputless,
cycle: opts.Cycle,
highlightLine: opts.CursorLine,
headerVisible: true,
Expand Down Expand Up @@ -1124,9 +1129,15 @@ func (t *Terminal) visibleHeaderLinesInList() int {

// Extra number of lines needed to display fzf
func (t *Terminal) extraLines() int {
extra := 1
if t.inputBorderShape.Visible() {
extra += borderLines(t.inputBorderShape)
extra := 0
if !t.inputless {
extra++
if !t.noSeparatorLine() {
extra++
}
if t.inputBorderShape.Visible() {
extra += borderLines(t.inputBorderShape)
}
}
if t.listBorderShape.Visible() {
extra += borderLines(t.listBorderShape)
Expand All @@ -1141,9 +1152,6 @@ func (t *Terminal) extraLines() int {
}
extra += t.headerLines
}
if !t.noSeparatorLine() {
extra++
}
return extra
}

Expand Down Expand Up @@ -1265,7 +1273,7 @@ func (t *Terminal) parsePrompt(prompt string) (func(), int) {
}

func (t *Terminal) noSeparatorLine() bool {
return noSeparatorLine(t.infoStyle, t.separatorLen > 0)
return t.inputless || noSeparatorLine(t.infoStyle, t.separatorLen > 0)
}

func getScrollbar(perLine int, total int, height int, offset int) (int, int) {
Expand Down Expand Up @@ -1350,7 +1358,10 @@ func (t *Terminal) Input() (bool, []rune) {
t.mutex.Lock()
defer t.mutex.Unlock()
paused := t.paused
src := t.input
var src []rune
if !t.inputless {
src = t.input
}
if t.inputOverride != nil {
paused = false
src = *t.inputOverride
Expand Down Expand Up @@ -1635,8 +1646,11 @@ func (t *Terminal) adjustMarginAndPadding() (int, int, [4]int, [4]int) {

minAreaWidth := minWidth
minAreaHeight := minHeight
if t.inputless {
minAreaHeight--
}
if t.noSeparatorLine() {
minAreaHeight -= 1
minAreaHeight--
}
if t.needPreviewWindow() {
minPreviewWidth, minPreviewHeight := t.minPreviewSize(t.activePreviewOpts)
Expand Down Expand Up @@ -1756,7 +1770,7 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
shrink := 0
hasHeaderWindow := t.hasHeaderWindow()
hasHeaderLinesWindow := t.hasHeaderLinesWindow()
hasInputWindow := t.inputBorderShape.Visible() || hasHeaderWindow || hasHeaderLinesWindow
hasInputWindow := !t.inputless && (t.inputBorderShape.Visible() || hasHeaderWindow || hasHeaderLinesWindow)
if hasInputWindow {
inputWindowHeight := 2
if t.noSeparatorLine() {
Expand Down Expand Up @@ -1873,6 +1887,9 @@ func (t *Terminal) resizeWindows(forcePreview bool, redrawBorder bool) {
switch previewOpts.position {
case posUp, posDown:
minWindowHeight := minHeight
if t.inputless {
minWindowHeight--
}
if t.noSeparatorLine() {
minWindowHeight--
}
Expand Down Expand Up @@ -2227,6 +2244,9 @@ func (t *Terminal) promptLine() int {
}

func (t *Terminal) placeCursor() {
if t.inputless {
return
}
if t.inputWindow != nil {
y := t.inputWindow.Height() - 1
if t.layout == layoutReverse {
Expand All @@ -2239,6 +2259,9 @@ func (t *Terminal) placeCursor() {
}

func (t *Terminal) printPrompt() {
if t.inputless {
return
}
w := t.window
if t.inputWindow != nil {
w = t.inputWindow
Expand Down Expand Up @@ -2266,6 +2289,9 @@ func (t *Terminal) trimMessage(message string, maxWidth int) string {
}

func (t *Terminal) printInfo() {
if t.inputless {
return
}
t.withWindow(t.inputWindow, func() { t.printInfoImpl() })
}

Expand Down Expand Up @@ -2509,7 +2535,7 @@ func (t *Terminal) headerIndent(borderShape tui.BorderShape) int {

func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShape, lines1 []string, lines2 []string) {
max := t.window.Height()
if t.inputWindow == nil && window == nil && t.headerFirst {
if !t.inputless && t.inputWindow == nil && window == nil && t.headerFirst {
max--
if !t.noSeparatorLine() {
max--
Expand Down Expand Up @@ -2539,7 +2565,7 @@ func (t *Terminal) printHeaderImpl(window tui.Window, borderShape tui.BorderShap
if needReverse && idx < len(lines1) {
line = len(lines1) - idx - 1
}
if t.inputWindow == nil && window == nil && !t.headerFirst {
if !t.inputless && t.inputWindow == nil && window == nil && !t.headerFirst {
line++
if !t.noSeparatorLine() {
line++
Expand Down Expand Up @@ -5681,7 +5707,7 @@ func (t *Terminal) Loop() error {
// Header
numLines := t.visibleHeaderLinesInList()
lineOffset := 0
if t.inputWindow == nil && !t.headerFirst {
if !t.inputless && t.inputWindow == nil && !t.headerFirst {
// offset for info line
if t.noSeparatorLine() {
lineOffset = 1
Expand Down Expand Up @@ -5829,7 +5855,13 @@ func (t *Terminal) Loop() error {
} else if !doActions(actions) {
continue
}
t.truncateQuery()
if t.inputless {
// Always just discard the change
t.input = previousInput
t.cx = len(t.input)
} else {
t.truncateQuery()
}
queryChanged = string(previousInput) != string(t.input)
if queryChanged {
t.inputOverride = nil
Expand Down Expand Up @@ -6016,6 +6048,9 @@ func (t *Terminal) vset(o int) bool {

// Number of prompt lines in the list window
func (t *Terminal) promptLines() int {
if t.inputless {
return 0
}
if t.inputWindow != nil {
return 0
}
Expand Down
1 change: 1 addition & 0 deletions src/tui/dummy.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func (r *FullscreenRenderer) Clear() {}
func (r *FullscreenRenderer) NeedScrollbarRedraw() bool { return false }
func (r *FullscreenRenderer) ShouldEmitResizeEvent() bool { return false }
func (r *FullscreenRenderer) Bell() {}
func (r *FullscreenRenderer) HideCursor() {}
func (r *FullscreenRenderer) Refresh() {}
func (r *FullscreenRenderer) Close() {}
func (r *FullscreenRenderer) Size() TermSize { return TermSize{} }
Expand Down
19 changes: 17 additions & 2 deletions src/tui/light.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,13 @@ func (r *LightRenderer) csi(code string) string {

func (r *LightRenderer) flush() {
if r.queued.Len() > 0 {
r.flushRaw("\x1b[?7l\x1b[?25l" + r.queued.String() + "\x1b[?25h\x1b[?7h")
raw := "\x1b[?7l\x1b[?25l" + r.queued.String()
if r.showCursor {
raw += "\x1b[?25h\x1b[?7h"
} else {
raw += "\x1b[?7h"
}
r.flushRaw(raw)
r.queued.Reset()
}
}
Expand Down Expand Up @@ -110,6 +116,7 @@ type LightRenderer struct {
y int
x int
maxHeightFunc func(int) int
showCursor bool

// Windows only
ttyinChannel chan byte
Expand Down Expand Up @@ -152,7 +159,8 @@ func NewLightRenderer(ttyin *os.File, theme *ColorTheme, forceBlack bool, mouse
tabstop: tabstop,
fullscreen: fullscreen,
upOneLine: false,
maxHeightFunc: maxHeightFunc}
maxHeightFunc: maxHeightFunc,
showCursor: true}
return &r, nil
}

Expand Down Expand Up @@ -759,6 +767,9 @@ func (r *LightRenderer) Close() {
} else if !r.fullscreen {
r.csi("u")
}
if !r.showCursor {
r.csi("?25h")
}
r.disableMouse()
r.flush()
r.closePlatform()
Expand Down Expand Up @@ -1214,3 +1225,7 @@ func (w *LightWindow) Erase() {
func (w *LightWindow) EraseMaybe() bool {
return false
}

func (r *LightRenderer) HideCursor() {
r.showCursor = false
}
15 changes: 13 additions & 2 deletions src/tui/tcell.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type TcellWindow struct {
borderStyle BorderStyle
uri *string
params *string
showCursor bool
}

func (w *TcellWindow) Top() int {
Expand All @@ -72,7 +73,9 @@ func (w *TcellWindow) Height() int {

func (w *TcellWindow) Refresh() {
if w.moveCursor {
_screen.ShowCursor(w.left+w.lastX, w.top+w.lastY)
if w.showCursor {
_screen.ShowCursor(w.left+w.lastX, w.top+w.lastY)
}
w.moveCursor = false
}
w.lastX = 0
Expand Down Expand Up @@ -104,6 +107,10 @@ func (r *FullscreenRenderer) Bell() {
_screen.Beep()
}

func (r *FullscreenRenderer) HideCursor() {
r.showCursor = false
}

func (r *FullscreenRenderer) PassThrough(str string) {
// No-op
// https://github.com/gdamore/tcell/pull/650#issuecomment-1806442846
Expand Down Expand Up @@ -168,6 +175,9 @@ func (r *FullscreenRenderer) getScreen() (tcell.Screen, error) {
if e != nil {
return nil, e
}
if !r.showCursor {
s.HideCursor()
}
_screen = s
}
return _screen, nil
Expand Down Expand Up @@ -590,7 +600,8 @@ func (r *FullscreenRenderer) NewWindow(top int, left int, width int, height int,
width: width,
height: height,
normal: normal,
borderStyle: borderStyle}
borderStyle: borderStyle,
showCursor: r.showCursor}
w.Erase()
return w
}
Expand Down
Loading

0 comments on commit 6c0ca4a

Please sign in to comment.