Skip to content

Commit 0602e05

Browse files
committed
make control-r reverse search style configurable
Allow the old control-r incremental search to be recovered via a config file setting. In case control-r is bound to traditional incremental search, add alt-r bindings for fzf search so that it is always available. The "fzf" setting for control_r in myclirc remains a bit of a lie, because we still fall back to reverse_isearch if fzf is not installed. But it could be nice to emit a warning in that case. This is intended to address the discussion comment at * #1265 (comment)
1 parent 9379f4e commit 0602e05

4 files changed

Lines changed: 47 additions & 27 deletions

File tree

changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
Upcoming Release (TBD)
22
======================
33

4+
Features
5+
--------
6+
* Make control-r reverse search style configurable.
7+
8+
49
Internal
510
--------
611

mycli/key_bindings.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,8 +143,18 @@ def _(event):
143143

144144
@kb.add("c-r", filter=emacs_mode)
145145
def _(event):
146-
"""Search history using fzf or default reverse incremental search."""
146+
"""Search history using fzf or reverse incremental search."""
147147
_logger.debug("Detected <C-r> key.")
148+
mode = mycli.config.get('keys', {}).get('control_r', 'auto')
149+
if mode == 'reverse_isearch':
150+
search_history(event, incremental=True)
151+
else:
152+
search_history(event)
153+
154+
@kb.add("escape", "r", filter=emacs_mode)
155+
def _(event):
156+
"""Search history using fzf when available."""
157+
_logger.debug("Detected <alt-r> key.")
148158
search_history(event)
149159

150160
@kb.add("enter", filter=completion_is_selected)

mycli/myclirc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,10 @@ enable_pager = True
102102
# Choose a specific pager
103103
pager = 'less'
104104

105+
[keys]
106+
# possible values: auto, fzf, reverse_isearch
107+
control_r = auto
108+
105109
# Custom colors for the completion menu, toolbar, etc.
106110
[colors]
107111
completion-menu.completion.current = 'bg:#ffffff #000000'

mycli/packages/toolkit/fzf.py

Lines changed: 27 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,36 +20,37 @@ def is_available(self) -> bool:
2020
return self.executable is not None
2121

2222

23-
def search_history(event: KeyPressEvent):
23+
def search_history(event: KeyPressEvent, incremental: bool = False) -> None:
2424
buffer = event.current_buffer
2525
history = buffer.history
2626

2727
fzf = Fzf()
2828

29-
if fzf.is_available() and isinstance(history, FileHistoryWithTimestamp):
30-
history_items_with_timestamp = history.load_history_with_timestamp()
31-
32-
formatted_history_items = []
33-
original_history_items = []
34-
seen = {}
35-
for item, timestamp in history_items_with_timestamp:
36-
formatted_item = re.sub(r'\s+', ' ', item)
37-
timestamp = timestamp.split(".")[0] if "." in timestamp else timestamp
38-
if formatted_item in seen:
39-
continue
40-
seen[formatted_item] = True
41-
formatted_history_items.append(f"{timestamp} {formatted_item}")
42-
original_history_items.append(item)
43-
44-
result = fzf.prompt(
45-
formatted_history_items,
46-
fzf_options="--scheme=history --tiebreak=index --preview-window=down:wrap --preview=\"printf '%s' {}\"",
47-
)
48-
49-
if result:
50-
selected_index = formatted_history_items.index(result[0])
51-
buffer.text = original_history_items[selected_index]
52-
buffer.cursor_position = len(buffer.text)
53-
else:
29+
if incremental or not fzf.is_available() or not isinstance(history, FileHistoryWithTimestamp):
5430
# Fallback to default reverse incremental search
5531
search.start_search(direction=search.SearchDirection.BACKWARD)
32+
return
33+
34+
history_items_with_timestamp = history.load_history_with_timestamp()
35+
36+
formatted_history_items = []
37+
original_history_items = []
38+
seen = {}
39+
for item, timestamp in history_items_with_timestamp:
40+
formatted_item = re.sub(r'\s+', ' ', item)
41+
timestamp = timestamp.split(".")[0] if "." in timestamp else timestamp
42+
if formatted_item in seen:
43+
continue
44+
seen[formatted_item] = True
45+
formatted_history_items.append(f"{timestamp} {formatted_item}")
46+
original_history_items.append(item)
47+
48+
result = fzf.prompt(
49+
formatted_history_items,
50+
fzf_options="--scheme=history --tiebreak=index --preview-window=down:wrap --preview=\"printf '%s' {}\"",
51+
)
52+
53+
if result:
54+
selected_index = formatted_history_items.index(result[0])
55+
buffer.text = original_history_items[selected_index]
56+
buffer.cursor_position = len(buffer.text)

0 commit comments

Comments
 (0)