Skip to content

Commit 57638e9

Browse files
committed
[lldb] Add fzf_history command to examples
1 parent b335d5a commit 57638e9

File tree

1 file changed

+99
-0
lines changed

1 file changed

+99
-0
lines changed
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
import os
2+
import re
3+
import sys
4+
import subprocess
5+
6+
import lldb
7+
8+
9+
@lldb.command()
10+
def fzf_history(debugger, cmdstr, ctx, result, _):
11+
if sys.platform != 'darwin':
12+
result.SetError("fzf_history supports macOS only")
13+
return
14+
15+
# Capture the current pasteboard contents to restore after overwriting.
16+
paste_snapshot = subprocess.run("pbpaste", text=True, capture_output=True).stdout
17+
18+
# On enter, copy the selected history entry into the pasteboard.
19+
fzf_command = (
20+
"fzf",
21+
"--no-sort",
22+
f"--query={cmdstr}",
23+
"--bind=enter:execute-silent(echo -n {} | pbcopy)+close",
24+
)
25+
26+
history_file = os.path.expanduser("~/.lldb/lldb-widehistory")
27+
if not os.path.exists(history_file):
28+
result.SetError("history file does not exist")
29+
return
30+
31+
history_commands = _load_history(history_file)
32+
fzf_input = "\n".join(history_commands)
33+
completed = subprocess.run(fzf_command, input=fzf_input, text=True)
34+
# 130 is used for CTRL-C or ESC.
35+
if completed.returncode not in (0, 130):
36+
result.SetError(f"fzf failed: {completed.stderr}")
37+
return
38+
39+
# Get the user's selected history entry.
40+
selected_command = subprocess.run("pbpaste", text=True, capture_output=True).stdout
41+
if selected_command == paste_snapshot:
42+
# Nothing was selected, no cleanup needed.
43+
return
44+
45+
_handle_command(debugger, selected_command)
46+
47+
# Restore the pasteboard's contents.
48+
subprocess.run("pbcopy", input=paste_snapshot, text=True)
49+
50+
51+
def _handle_command(debugger, command):
52+
"""Try pasting the command, and failing that, run it directly."""
53+
if not command:
54+
return
55+
56+
# Use applescript to paste the selected result into lldb's console.
57+
paste_command = (
58+
"osascript",
59+
"-e",
60+
'tell application "System Events" to keystroke "v" using command down',
61+
)
62+
completed = subprocess.run(paste_command, capture_output=True)
63+
64+
if completed.returncode != 0:
65+
# The above applescript requires the "control your computer" permission.
66+
# Settings > Private & Security > Accessibility
67+
# If not enabled, fallback to running the command.
68+
debugger.HandleCommand(command)
69+
70+
71+
def _load_history(history_file):
72+
"""Load, decode, and parse an lldb history file."""
73+
with open(history_file) as f:
74+
history_contents = f.read()
75+
76+
history_decoded = re.sub(r"\\0([0-7][0-7])", _decode_char, history_contents)
77+
history_lines = history_decoded.splitlines()
78+
79+
# Skip the header line (_HiStOrY_V2_)
80+
del history_lines[0]
81+
# Reverse to show latest first.
82+
history_lines.reverse()
83+
84+
history_commands = []
85+
history_seen = set()
86+
for line in history_lines:
87+
line = line.strip()
88+
# Skip empty lines, single character commands, and duplicates.
89+
if line and len(line) > 1 and line not in history_seen:
90+
history_commands.append(line)
91+
history_seen.add(line)
92+
93+
return history_commands
94+
95+
96+
def _decode_char(match):
97+
"""Decode octal strings ('\0NN') into a single character string."""
98+
code = int(match.group(1), base=8)
99+
return chr(code)

0 commit comments

Comments
 (0)