summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunegunn Choi <junegunn.c@gmail.com>2021-01-03 00:00:40 +0900
committerJunegunn Choi <junegunn.c@gmail.com>2021-01-03 00:15:00 +0900
commitd779ff7e6dcf068fbcf743bed45127c3b857ec92 (patch)
treee50d90a35c8a59841eaad89af9c5718ab2663237
parentfd8858f8c93e38d50f00cd21430e21d89e2f9399 (diff)
Make search toggleable
- `--phony` renamed to `--disabled` for consistency - `--no-phony` is now `--enabled` - Added `enable-search`, `disable-search`, and `toggle-search` actions for `--bind` - Added `--color` options: `query` and `disabled` Close #2303
-rw-r--r--CHANGELOG.md9
-rw-r--r--README-VIM.md30
-rw-r--r--doc/fzf.txt36
-rw-r--r--man/man1/fzf-tmux.12
-rw-r--r--man/man1/fzf.114
-rw-r--r--src/core.go8
-rw-r--r--src/options.go16
-rw-r--r--src/terminal.go31
-rw-r--r--src/tui/tui.go9
-rwxr-xr-xtest/test_go.rb26
10 files changed, 132 insertions, 49 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5e650af9..69bab6a0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,7 @@
CHANGELOG
=========
-0.24.5
+0.25.0
------
- Text attributes set in `--color` are not reset when fzf sees another
`--color` option for the same element. This allows you to put custom text
@@ -23,6 +23,13 @@ CHANGELOG
# Write "regular" if you want to clear the attributes
fzf --color hl:176:regular,hl+:177:regular
```
+- Renamed `--phony` to `--disabled`
+- You can dynamically enable and disable the search functionality using the
+ new `enable-search`, `disable-search`, and `toggle-search` actions
+- You can assign a different color to the query string for when search is disabled
+ ```sh
+ fzf --color query:#ffffff,disabled:#999999 --bind space:toggle-search
+ ```
- Added `last` action to move the cursor to the last match
- The opposite action `top` is renamed to `first`, but `top` is still
recognized as a synonym for backward compatibility
diff --git a/README-VIM.md b/README-VIM.md
index ea588bbe..058dfaf1 100644
--- a/README-VIM.md
+++ b/README-VIM.md
@@ -171,19 +171,23 @@ list:
- `element` is an fzf element to apply a color to:
- | Element | Description |
- | --- | --- |
- | `fg` / `bg` / `hl` | Item (foreground / background / highlight) |
- | `fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight) |
- | `hl` / `hl+` | Highlighted substrings (normal / current) |
- | `gutter` | Background of the gutter on the left |
- | `pointer` | Pointer to the current line (`>`) |
- | `marker` | Multi-select marker (`>`) |
- | `border` | Border around the window (`--border` and `--preview`) |
- | `header` | Header (`--header` or `--header-lines`) |
- | `info` | Info line (match counters) |
- | `spinner` | Streaming input indicator |
- | `prompt` | Prompt before query (`> `) |
+ | Element | Description |
+ | --- | --- |
+ | `fg` / `bg` / `hl` | Item (foreground / background / highlight) |
+ | `fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight) |
+ | `preview-fg` / `preview-bg` | Preview window text and background |
+ | `hl` / `hl+` | Highlighted substrings (normal / current) |
+ | `gutter` | Background of the gutter on the left |
+ | `pointer` | Pointer to the current line (`>`) |
+ | `marker` | Multi-select marker (`>`) |
+ | `border` | Border around the window (`--border` and `--preview`) |
+ | `header` | Header (`--header` or `--header-lines`) |
+ | `info` | Info line (match counters) |
+ | `spinner` | Streaming input indicator |
+ | `query` | Query string |
+ | `disabled` | Query string when search is disabled |
+ | `prompt` | Prompt before query (`> `) |
+ | `pointer` | Pointer to the current line (`>`) |
- `component` specifies the component (`fg` / `bg`) from which to extract the
color when considering each of the following highlight groups
diff --git a/doc/fzf.txt b/doc/fzf.txt
index f50a35ba..c8888962 100644
--- a/doc/fzf.txt
+++ b/doc/fzf.txt
@@ -1,4 +1,4 @@
-fzf.txt fzf Last change: December 31 2020
+fzf.txt fzf Last change: January 2 2021
FZF - TABLE OF CONTENTS *fzf* *fzf-toc*
==============================================================================
@@ -200,21 +200,25 @@ list:
<
- `element` is an fzf element to apply a color to:
- ----------------------+------------------------------------------------------
- Element | Description ~
- ----------------------+------------------------------------------------------
- `fg` / `bg` / `hl` | Item (foreground / background / highlight)
- `fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight)
- `hl` / `hl+` | Highlighted substrings (normal / current)
- `gutter` | Background of the gutter on the left
- `pointer` | Pointer to the current line ( `>` )
- `marker` | Multi-select marker ( `>` )
- `border` | Border around the window ( `--border` and `--preview` )
- `header` | Header ( `--header` or `--header-lines` )
- `info` | Info line (match counters)
- `spinner` | Streaming input indicator
- `prompt` | Prompt before query ( `> ` )
- ----------------------+------------------------------------------------------
+ ----------------------------+------------------------------------------------------
+ Element | Description ~
+ ----------------------------+------------------------------------------------------
+ `fg` / `bg` / `hl` | Item (foreground / background / highlight)
+ `fg+` / `bg+` / `hl+` | Current item (foreground / background / highlight)
+ `preview-fg` / `preview-bg` | Preview window text and background
+ `hl` / `hl+` | Highlighted substrings (normal / current)
+ `gutter` | Background of the gutter on the left
+ `pointer` | Pointer to the current line ( `>` )
+ `marker` | Multi-select marker ( `>` )
+ `border` | Border around the window ( `--border` and `--preview` )
+ `header` | Header ( `--header` or `--header-lines` )
+ `info` | Info line (match counters)
+ `spinner` | Streaming input indicator
+ `query` | Query string
+ `disabled` | Query string when search is disabled
+ `prompt` | Prompt before query ( `> ` )
+ `pointer` | Pointer to the current line ( `>` )
+ ----------------------------+------------------------------------------------------
- `component` specifies the component (`fg` / `bg`) from which to extract the
color when considering each of the following highlight groups
- `group1 [, group2, ...]` is a list of highlight groups that are searched (in
diff --git a/man/man1/fzf-tmux.1 b/man/man1/fzf-tmux.1
index f33fafa7..904fda34 100644
--- a/man/man1/fzf-tmux.1
+++ b/man/man1/fzf-tmux.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-tmux 1 "Dec 2020" "fzf 0.24.4" "fzf-tmux - open fzf in tmux split pane"
+.TH fzf-tmux 1 "Jan 2021" "fzf 0.25.0" "fzf-tmux - open fzf in tmux split pane"
.SH NAME
fzf-tmux - open fzf in tmux split pane
diff --git a/man/man1/fzf.1 b/man/man1/fzf.1
index e976a5a2..5fff2e1c 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 "Dec 2020" "fzf 0.24.5" "fzf - a command-line fuzzy finder"
+.TH fzf 1 "Jan 2021" "fzf 0.25.0" "fzf - a command-line fuzzy finder"
.SH NAME
fzf - a command-line fuzzy finder
@@ -71,9 +71,10 @@ Transform the presentation of each line using field index expressions
.BI "-d, --delimiter=" "STR"
Field delimiter regex for \fB--nth\fR and \fB--with-nth\fR (default: AWK-style)
.TP
-.BI "--phony"
+.BI "--disabled"
Do not perform search. With this option, fzf becomes a simple selector
-interface rather than a "fuzzy finder".
+interface rather than a "fuzzy finder". You can later enable the search using
+\fBenable-search\fR or `\fBtoggle-search\R action.
.SS Search result
.TP
.B "+s, --no-sort"
@@ -323,6 +324,8 @@ color mappings.
\fBbg+ \fRBackground (current line)
\fBgutter \fRGutter on the left (defaults to \fBbg+\fR)
\fBhl+ \fRHighlighted substrings (current line)
+ \fBquery \fRQuery string
+ \fBdisabled \fRQuery string when search is disabled
\fBinfo \fRInfo line (match counters)
\fBborder \fRBorder around the window (\fB--border\fR and \fB--preview\fR)
\fBprompt \fRPrompt
@@ -780,7 +783,9 @@ A key or an event can be bound to one or more of the following actions.
\fBdelete-char\fR \fIdel\fR
\fBdelete-char/eof\fR \fIctrl-d\fR (same as \fBdelete-char\fR except aborts fzf if query is empty)
\fBdeselect-all\fR (deselect all matches)
+ \fBdisable-search\fR (disable search functionality)
\fBdown\fR \fIctrl-j ctrl-n down\fR
+ \fBenable-search\fR (enable search functionality)
\fBend-of-line\fR \fIctrl-e end\fR
\fBexecute(...)\fR (see below for the details)
\fBexecute-silent(...)\fR (see below for the details)
@@ -820,6 +825,7 @@ A key or an event can be bound to one or more of the following actions.
\fBtoggle-out\fR (\fB--layout=reverse*\fR ? \fBtoggle+down\fR : \fBtoggle+up\fR)
\fBtoggle-preview\fR
\fBtoggle-preview-wrap\fR
+ \fBtoggle-search\fR (toggle search functionality)
\fBtoggle-sort\fR
\fBtoggle+up\fR \fIbtab (shift-tab)\fR
\fBunix-line-discard\fR \fIctrl-u\fR
@@ -902,7 +908,7 @@ e.g.
INITIAL_QUERY="foobar"
FZF_DEFAULT_COMMAND="$RG_PREFIX '$INITIAL_QUERY'" \\
fzf --bind "change:reload:$RG_PREFIX {q} || true" \\
- --ansi --phony --query "$INITIAL_QUERY"\fR
+ --ansi --disabled --query "$INITIAL_QUERY"\fR
.SS PREVIEW BINDING
diff --git a/src/core.go b/src/core.go
index ef470a80..1c009c69 100644
--- a/src/core.go
+++ b/src/core.go
@@ -237,14 +237,16 @@ func Run(opts *Options, version string, revision string) {
go reader.restart(command)
}
eventBox.Watch(EvtReadNew)
+ query := []rune{}
for {
delay := true
ticks++
input := func() []rune {
- if opts.Phony {
- return []rune{}
+ paused, input := terminal.Input()
+ if !paused {
+ query = input
}
- return []rune(terminal.Input())
+ return query
}
eventBox.Wait(func(events *util.Events) {
if _, fin := (*events)[EvtReadFin]; fin {
diff --git a/src/options.go b/src/options.go
index 691934ed..12c09556 100644
--- a/src/options.go
+++ b/src/options.go
@@ -33,7 +33,7 @@ const usage = `usage: fzf [options]
-d, --delimiter=STR Field delimiter regex (default: AWK-style)
+s, --no-sort Do not sort the result
--tac Reverse the order of the input
- --phony Do not perform search
+ --disabled Do not perform search
--tiebreak=CRI[,..] Comma-separated list of sort criteria to apply
when the scores are tied [length|begin|end|index]
(default: length)
@@ -682,8 +682,10 @@ func parseTheme(defaultTheme *tui.ColorTheme, str string) *tui.ColorTheme {
}
}
switch components[0] {
- case "input":
+ case "query", "input":
mergeAttr(&theme.Input)
+ case "disabled":
+ mergeAttr(&theme.Disabled)
case "fg":
mergeAttr(&theme.Fg)
case "bg":
@@ -875,6 +877,8 @@ func parseKeymap(keymap map[tui.Event][]action, str string) {
appendAction(actToggleOut)
case "toggle-all":
appendAction(actToggleAll)
+ case "toggle-search":
+ appendAction(actToggleSearch)
case "select-all":
appendAction(actSelectAll)
case "deselect-all":
@@ -923,6 +927,10 @@ func parseKeymap(keymap map[tui.Event][]action, str string) {
appendAction(actPreviewHalfPageUp)
case "preview-half-page-down":
appendAction(actPreviewHalfPageDown)
+ case "enable-search":
+ appendAction(actEnableSearch)
+ case "disable-search":
+ appendAction(actDisableSearch)
default:
t := isExecuteAction(specLower)
if t == actIgnore {
@@ -1199,9 +1207,9 @@ func parseOptions(opts *Options, allArgs []string) {
}
case "--no-expect":
opts.Expect = make(map[tui.Event]string)
- case "--no-phony":
+ case "--enabled", "--no-phony":
opts.Phony = false
- case "--phony":
+ case "--disabled", "--phony":
opts.Phony = true
case "--tiebreak":
opts.Criteria = parseTiebreak(nextString(allArgs, &i, "sort criterion required"))
diff --git a/src/terminal.go b/src/terminal.go
index e630db4e..48011628 100644
--- a/src/terminal.go
+++ b/src/terminal.go
@@ -125,6 +125,7 @@ type Terminal struct {
unicode bool
borderShape tui.BorderShape
cleanExit bool
+ paused bool
border tui.Window
window tui.Window
pborder tui.Window
@@ -233,6 +234,7 @@ const (
actSelectAll
actDeselectAll
actToggle
+ actToggleSearch
actToggleAll
actToggleDown
actToggleUp
@@ -270,6 +272,8 @@ const (
actFirst
actLast
actReload
+ actDisableSearch
+ actEnableSearch
)
type placeholderFlags struct {
@@ -488,6 +492,7 @@ func NewTerminal(opts *Options, eventBox *util.EventBox) *Terminal {
unicode: opts.Unicode,
borderShape: opts.BorderShape,
cleanExit: opts.ClearOnExit,
+ paused: opts.Phony,
strong: strongAttr,
cycle: opts.Cycle,
header: header,
@@ -563,10 +568,10 @@ func (t *Terminal) noInfoLine() bool {
}
// Input returns current query string
-func (t *Terminal) Input() []rune {
+func (t *Terminal) Input() (bool, []rune) {
t.mutex.Lock()
defer t.mutex.Unlock()
- return copySlice(t.input)
+ return t.paused, copySlice(t.input)
}
// UpdateCount updates the count information
@@ -925,8 +930,12 @@ func (t *Terminal) printPrompt() {
t.prompt()
before, after := t.updatePromptOffset()
- t.window.CPrint(tui.ColInput, string(before))
- t.window.CPrint(tui.ColInput, string(after))
+ color := tui.ColInput
+ if t.paused {
+ color = tui.ColDisabled
+ }
+ t.window.CPrint(color, string(before))
+ t.window.CPrint(color, string(after))
}
func (t *Terminal) trimMessage(message string, maxWidth int) string {
@@ -1880,7 +1889,8 @@ func (t *Terminal) Loop() {
version++
// We don't display preview window if no match
if items[0] != nil {
- command := t.replacePlaceholder(commandTemplate, false, string(t.Input()), items)
+ _, query := t.Input()
+ command := t.replacePlaceholder(commandTemplate, false, string(query), items)
initialOffset := 0
cmd := util.ExecCommand(command, true)
if pwindow != nil {
@@ -2465,6 +2475,17 @@ func (t *Terminal) Loop() {
t.input = trimQuery(t.history.next())
t.cx = len(t.input)
}
+ case actToggleSearch:
+ t.paused = !t.paused
+ changed = !t.paused
+ req(reqPrompt)
+ case actEnableSearch:
+ t.paused = false
+ changed = true
+ req(reqPrompt)
+ case actDisableSearch:
+ t.paused = true
+ req(reqPrompt)
case actSigStop:
p, err := os.FindProcess(os.Getpid())
if err == nil {
diff --git a/src/tui/tui.go b/src/tui/tui.go
index cc9c7f67..eb09da40 100644
--- a/src/tui/tui.go
+++ b/src/tui/tui.go
@@ -250,6 +250,7 @@ func (p ColorPair) MergeNonDefault(other ColorPair) ColorPair {
type ColorTheme struct {
Colored bool
Input ColorAttr
+ Disabled ColorAttr
Fg ColorAttr
Bg ColorAttr
PreviewFg ColorAttr
@@ -421,6 +422,7 @@ var (
ColPrompt ColorPair
ColNormal ColorPair
ColInput ColorPair
+ ColDisabled ColorPair
ColMatch ColorPair
ColCursor ColorPair
ColCursorEmpty ColorPair
@@ -443,6 +445,7 @@ func EmptyTheme() *ColorTheme {
return &ColorTheme{
Colored: true,
Input: ColorAttr{colUndefined, AttrUndefined},
+ Disabled: ColorAttr{colUndefined, AttrUndefined},
Fg: ColorAttr{colUndefined, AttrUndefined},
Bg: ColorAttr{colUndefined, AttrUndefined},
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
@@ -465,6 +468,7 @@ func NoColorTheme() *ColorTheme {
return &ColorTheme{
Colored: false,
Input: ColorAttr{colDefault, AttrRegular},
+ Disabled: ColorAttr{colDefault, AttrRegular},
Fg: ColorAttr{colDefault, AttrRegular},
Bg: ColorAttr{colDefault, AttrRegular},
PreviewFg: ColorAttr{colDefault, AttrRegular},
@@ -492,6 +496,7 @@ func init() {
Default16 = &ColorTheme{
Colored: true,
Input: ColorAttr{colDefault, AttrUndefined},
+ Disabled: ColorAttr{colUndefined, AttrUndefined},
Fg: ColorAttr{colDefault, AttrUndefined},
Bg: ColorAttr{colDefault, AttrUndefined},
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
@@ -511,6 +516,7 @@ func init() {
Dark256 = &ColorTheme{
Colored: true,
Input: ColorAttr{colDefault, AttrUndefined},
+ Disabled: ColorAttr{colUndefined, AttrUndefined},
Fg: ColorAttr{colDefault, AttrUndefined},
Bg: ColorAttr{colDefault, AttrUndefined},
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
@@ -530,6 +536,7 @@ func init() {
Light256 = &ColorTheme{
Colored: true,
Input: ColorAttr{colDefault, AttrUndefined},
+ Disabled: ColorAttr{colUndefined, AttrUndefined},
Fg: ColorAttr{colDefault, AttrUndefined},
Bg: ColorAttr{colDefault, AttrUndefined},
PreviewFg: ColorAttr{colUndefined, AttrUndefined},
@@ -564,6 +571,7 @@ func initTheme(theme *ColorTheme, baseTheme *ColorTheme, forceBlack bool) {
return c
}
theme.Input = o(baseTheme.Input, theme.Input)
+ theme.Disabled = o(theme.Input, o(baseTheme.Disabled, theme.Disabled))
theme.Fg = o(baseTheme.Fg, theme.Fg)
theme.Bg = o(baseTheme.Bg, theme.Bg)
theme.PreviewFg = o(theme.Fg, o(baseTheme.PreviewFg, theme.PreviewFg))
@@ -597,6 +605,7 @@ func initPalette(theme *ColorTheme) {
ColPrompt = pair(theme.Prompt, theme.Bg)
ColNormal = pair(theme.Fg, theme.Bg)
ColInput = pair(theme.Input, theme.Bg)
+ ColDisabled = pair(theme.Disabled, theme.Bg)
ColMatch = pair(theme.Match, theme.Bg)
ColCursor = pair(theme.Cursor, theme.Gutter)
ColCursorEmpty = pair(blank, theme.Gutter)
diff --git a/test/test_go.rb b/test/test_go.rb
index f1456751..aa28e1ce 100755
--- a/test/test_go.rb
+++ b/test/test_go.rb
@@ -1658,13 +1658,35 @@ class TestGoFZF < TestBase
tmux.until { |lines| assert_includes lines[1], ' + green ' }
end
- def test_phony
- tmux.send_keys %(seq 1000 | #{FZF} --query 333 --phony --preview 'echo {} {q}'), :Enter
+ def test_disabled
+ tmux.send_keys %(seq 1000 | #{FZF} --query 333 --disabled --bind a:enable-search,b:disable-search,c:toggle-search --preview 'echo {} {q}'), :Enter
tmux.until { |lines| assert_equal 1000, lines.match_count }
tmux.until { |lines| assert_includes lines[1], ' 1 333 ' }
tmux.send_keys 'foo'
tmux.until { |lines| assert_equal 1000, lines.match_count }
tmux.until { |lines| assert_includes lines[1], ' 1 333foo ' }
+
+ # Already disabled, no change
+ tmux.send_keys 'b'
+ tmux.until { |lines| assert_equal 1000, lines.match_count }
+
+ # Enable search
+ tmux.send_keys 'a'
+ tmux.until { |lines| assert_equal 0, lines.match_count }
+ tmux.send_keys :BSpace, :BSpace, :BSpace
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' 333 333 ' }
+
+ # Toggle search -> disabled again, but retains the previous result
+ tmux.send_keys 'c'
+ tmux.send_keys 'foo'
+ tmux.until { |lines| assert_includes lines[1], ' 333 333foo ' }
+ tmux.until { |lines| assert_equal 1, lines.match_count }
+
+ # Enabled, no match
+ tmux.send_keys 'c'
+ tmux.until { |lines| assert_equal 0, lines.match_count }
+ tmux.until { |lines| assert_includes lines[1], ' 333foo ' }
end
def test_reload