https://github.com/kastiglione updated https://github.com/llvm/llvm-project/pull/128571
>From 57638e91c97486ad7739f9658fe88f7fb4d61fb2 Mon Sep 17 00:00:00 2001 From: Dave Lee <davelee....@gmail.com> Date: Mon, 24 Feb 2025 12:48:17 -0800 Subject: [PATCH 1/5] [lldb] Add fzf_history command to examples --- lldb/examples/python/fzf_history.py | 99 +++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 lldb/examples/python/fzf_history.py diff --git a/lldb/examples/python/fzf_history.py b/lldb/examples/python/fzf_history.py new file mode 100644 index 0000000000000..4647a3532b0df --- /dev/null +++ b/lldb/examples/python/fzf_history.py @@ -0,0 +1,99 @@ +import os +import re +import sys +import subprocess + +import lldb + + +@lldb.command() +def fzf_history(debugger, cmdstr, ctx, result, _): + if sys.platform != 'darwin': + result.SetError("fzf_history supports macOS only") + return + + # Capture the current pasteboard contents to restore after overwriting. + paste_snapshot = subprocess.run("pbpaste", text=True, capture_output=True).stdout + + # On enter, copy the selected history entry into the pasteboard. + fzf_command = ( + "fzf", + "--no-sort", + f"--query={cmdstr}", + "--bind=enter:execute-silent(echo -n {} | pbcopy)+close", + ) + + history_file = os.path.expanduser("~/.lldb/lldb-widehistory") + if not os.path.exists(history_file): + result.SetError("history file does not exist") + return + + history_commands = _load_history(history_file) + fzf_input = "\n".join(history_commands) + completed = subprocess.run(fzf_command, input=fzf_input, text=True) + # 130 is used for CTRL-C or ESC. + if completed.returncode not in (0, 130): + result.SetError(f"fzf failed: {completed.stderr}") + return + + # Get the user's selected history entry. + selected_command = subprocess.run("pbpaste", text=True, capture_output=True).stdout + if selected_command == paste_snapshot: + # Nothing was selected, no cleanup needed. + return + + _handle_command(debugger, selected_command) + + # Restore the pasteboard's contents. + subprocess.run("pbcopy", input=paste_snapshot, text=True) + + +def _handle_command(debugger, command): + """Try pasting the command, and failing that, run it directly.""" + if not command: + return + + # Use applescript to paste the selected result into lldb's console. + paste_command = ( + "osascript", + "-e", + 'tell application "System Events" to keystroke "v" using command down', + ) + completed = subprocess.run(paste_command, capture_output=True) + + if completed.returncode != 0: + # The above applescript requires the "control your computer" permission. + # Settings > Private & Security > Accessibility + # If not enabled, fallback to running the command. + debugger.HandleCommand(command) + + +def _load_history(history_file): + """Load, decode, and parse an lldb history file.""" + with open(history_file) as f: + history_contents = f.read() + + history_decoded = re.sub(r"\\0([0-7][0-7])", _decode_char, history_contents) + history_lines = history_decoded.splitlines() + + # Skip the header line (_HiStOrY_V2_) + del history_lines[0] + # Reverse to show latest first. + history_lines.reverse() + + history_commands = [] + history_seen = set() + for line in history_lines: + line = line.strip() + # Skip empty lines, single character commands, and duplicates. + if line and len(line) > 1 and line not in history_seen: + history_commands.append(line) + history_seen.add(line) + + return history_commands + + +def _decode_char(match): + """Decode octal strings ('\0NN') into a single character string.""" + code = int(match.group(1), base=8) + return chr(code) >From d1106bc7165d8a62a1805ec09afdf62e5b7f09ff Mon Sep 17 00:00:00 2001 From: Dave Lee <davelee....@gmail.com> Date: Mon, 24 Feb 2025 12:56:35 -0800 Subject: [PATCH 2/5] Fix code formatting --- lldb/examples/python/fzf_history.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/examples/python/fzf_history.py b/lldb/examples/python/fzf_history.py index 4647a3532b0df..b683078465985 100644 --- a/lldb/examples/python/fzf_history.py +++ b/lldb/examples/python/fzf_history.py @@ -8,7 +8,7 @@ @lldb.command() def fzf_history(debugger, cmdstr, ctx, result, _): - if sys.platform != 'darwin': + if sys.platform != "darwin": result.SetError("fzf_history supports macOS only") return >From 7fb2bfc015e1550dde6f3d54e932e8bc6ccbe0f7 Mon Sep 17 00:00:00 2001 From: Dave Lee <davelee....@gmail.com> Date: Mon, 24 Feb 2025 12:59:08 -0800 Subject: [PATCH 3/5] Add docstring for fzf_history --- lldb/examples/python/fzf_history.py | 1 + 1 file changed, 1 insertion(+) diff --git a/lldb/examples/python/fzf_history.py b/lldb/examples/python/fzf_history.py index b683078465985..569abe54dc76f 100644 --- a/lldb/examples/python/fzf_history.py +++ b/lldb/examples/python/fzf_history.py @@ -8,6 +8,7 @@ @lldb.command() def fzf_history(debugger, cmdstr, ctx, result, _): + """Use fzf to search and select from lldb command history.""" if sys.platform != "darwin": result.SetError("fzf_history supports macOS only") return >From eff33674255e41d18d8943e74a2a142261525fc0 Mon Sep 17 00:00:00 2001 From: Dave Lee <davelee....@gmail.com> Date: Mon, 24 Feb 2025 14:35:16 -0800 Subject: [PATCH 4/5] Run featureless fzf when no copy and paste is available --- lldb/examples/python/fzf_history.py | 27 ++++++++++++++------------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/lldb/examples/python/fzf_history.py b/lldb/examples/python/fzf_history.py index 569abe54dc76f..8dfd916dc5d16 100644 --- a/lldb/examples/python/fzf_history.py +++ b/lldb/examples/python/fzf_history.py @@ -9,8 +9,17 @@ @lldb.command() def fzf_history(debugger, cmdstr, ctx, result, _): """Use fzf to search and select from lldb command history.""" + history_file = os.path.expanduser("~/.lldb/lldb-widehistory") + if not os.path.exists(history_file): + result.SetError("history file does not exist") + return + history = _load_history(history_file) + if sys.platform != "darwin": - result.SetError("fzf_history supports macOS only") + # The ability to integrate fzf's result into lldb uses copy and paste. + # In absense of copy and paste, do the basics and forgo features. + fzf_command = ("fzf", "--no-sort", f"--query={query}") + subprocess.run(fzf_command, input=history) return # Capture the current pasteboard contents to restore after overwriting. @@ -23,18 +32,10 @@ def fzf_history(debugger, cmdstr, ctx, result, _): f"--query={cmdstr}", "--bind=enter:execute-silent(echo -n {} | pbcopy)+close", ) - - history_file = os.path.expanduser("~/.lldb/lldb-widehistory") - if not os.path.exists(history_file): - result.SetError("history file does not exist") - return - - history_commands = _load_history(history_file) - fzf_input = "\n".join(history_commands) - completed = subprocess.run(fzf_command, input=fzf_input, text=True) + completed = subprocess.run(fzf_command, input=history, text=True) # 130 is used for CTRL-C or ESC. if completed.returncode not in (0, 130): - result.SetError(f"fzf failed: {completed.stderr}") + result.SetError("fzf failed") return # Get the user's selected history entry. @@ -70,7 +71,7 @@ def _handle_command(debugger, command): def _load_history(history_file): - """Load, decode, and parse an lldb history file.""" + """Load, decode, parse, and prepare an lldb history file for fzf.""" with open(history_file) as f: history_contents = f.read() @@ -91,7 +92,7 @@ def _load_history(history_file): history_commands.append(line) history_seen.add(line) - return history_commands + return "\n".join(history_commands) def _decode_char(match): >From fcdf670623e89a6d6adff50a9b667cdb1d042fa1 Mon Sep 17 00:00:00 2001 From: Dave Lee <davelee....@gmail.com> Date: Mon, 24 Feb 2025 14:41:10 -0800 Subject: [PATCH 5/5] Fix basic fzf invocation --- lldb/examples/python/fzf_history.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lldb/examples/python/fzf_history.py b/lldb/examples/python/fzf_history.py index 8dfd916dc5d16..62dde6ecf7357 100644 --- a/lldb/examples/python/fzf_history.py +++ b/lldb/examples/python/fzf_history.py @@ -19,7 +19,7 @@ def fzf_history(debugger, cmdstr, ctx, result, _): # The ability to integrate fzf's result into lldb uses copy and paste. # In absense of copy and paste, do the basics and forgo features. fzf_command = ("fzf", "--no-sort", f"--query={query}") - subprocess.run(fzf_command, input=history) + subprocess.run(fzf_command, input=history, text=True) return # Capture the current pasteboard contents to restore after overwriting. _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits