From 6f3b987ebbf8eeabd054c967e673899d3da203dc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gerd=20M=C3=B6llmann?= Date: Wed, 18 Oct 2023 09:24:45 +0200 Subject: [PATCH] Gud LLDB completions * etc/emacs_lldb.py: Remove xcomplete. * lisp/progmodes/gud.el: Implement lldb command completions. --- etc/emacs_lldb.py | 30 --------------- lisp/progmodes/gud.el | 87 ++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 85 insertions(+), 32 deletions(-) diff --git a/etc/emacs_lldb.py b/etc/emacs_lldb.py index f2c7a7987c7..fa8d95d7b5b 100644 --- a/etc/emacs_lldb.py +++ b/etc/emacs_lldb.py @@ -203,35 +203,6 @@ def xdebug_print(debugger, command, result, internal_dict): """Print Lisp_Objects using safe_debug_print()""" debugger.HandleCommand(f"expr safe_debug_print({command})") -# According to SBCommanInterpreter.cpp, the return value of -# HandleCompletions is as follows: -# -# Index 1 to the end contain all the completions. -# -# At index 0: -# -# If all completions have a common prefix, this is the shortest -# completion, with the common prefix removed from it. -# -# If it is the completion for a whole word, a space is added at the -# end. -# -# So, the prefix is what could be added to make the command partially -# complete. -# -# If there is no common prefix, index 0 has an empty string "". - -def xcomplete(debugger, command, result, internal_dict): - """Print completions for COMMAND.""" - interpreter = debugger.GetCommandInterpreter() - string_list = lldb.SBStringList() - interpreter.HandleCompletion(command, len(command), len(command), - -1, string_list) - list = "" - for i in range(string_list.GetSize()): - list += '"' + string_list.GetStringAtIndex(i) + '" ' - result.AppendMessage("(" + list + ")") - ######################################################################## # Formatters @@ -336,7 +307,6 @@ def enable_type_category(debugger, category): def __lldb_init_module(debugger, internal_dict): define_command(debugger, xbacktrace) define_command(debugger, xdebug_print) - define_command(debugger, xcomplete) define_type_summary(debugger, "Lisp_Object", type_summary_Lisp_Object) define_type_synthetic(debugger, "Lisp_Object", Lisp_Object_Provider) enable_type_category(debugger, "Emacs") diff --git a/lisp/progmodes/gud.el b/lisp/progmodes/gud.el index ea5a3580629..a9c1c25a505 100644 --- a/lisp/progmodes/gud.el +++ b/lisp/progmodes/gud.el @@ -3850,7 +3850,7 @@ gud-tooltip-tips ;; 'gud-lldb-history' and 'gud-gud-lldb-command-name' are required -;; because gud-symbol uses their values if they are present. Their +;; because 'gud-symbol' uses their values if they are present. Their ;; names are deduced from the minor-mode name. (defvar gud-lldb-history nil) @@ -3859,7 +3859,7 @@ gud-gud-lldb-command-name :type 'string) (defun gud-lldb-marker-filter (string) - "Deduce interesting stuff from output STRING." + "Deduce interesting stuff from process output STRING." (cond (;; Process 72668 stopped ;; * thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1 ;; frame #0: ...) at emacs.c:1310:9 [opt] @@ -3879,6 +3879,83 @@ gud-lldb-marker-filter (setq gud-overlay-arrow-position nil))) string) +;; According to SBCommanInterpreter.cpp, the return value of +;; HandleCompletions is as follows: +;; +;; Index 1 to the end contain all the completions. +;; +;; At index 0: +;; +;; If all completions have a common prefix, this is the shortest +;; completion, with the common prefix removed from it. +;; +;; If it is the completion for a whole word, a space is added at the +;; end. +;; +;; So, the prefix is what could be added to make the command partially +;; complete. +;; +;; If there is no common prefix, index 0 has an empty string "". + +(defun gud-lldb-fetch-completions () + "Return the data to complete the LLDB command before point." + (let* ((process (get-buffer-process gud-comint-buffer)) + (start (process-mark process)) + (end (point)) + (to-complete (buffer-substring-no-properties start end)) + (output-buffer (get-buffer-create "*lldb-completions*"))) + ;; Send the completion command with output to our buffer + (with-current-buffer output-buffer + (erase-buffer)) + (comint-redirect-send-command-to-process + (format "script --language python -- gud_complete('%s')" + to-complete) + output-buffer process nil t) + ;; Wait for output + (unwind-protect + (while (not comint-redirect-completed) + (accept-process-output process)) + (comint-redirect-cleanup)) + ;; Process the completion output. + (with-current-buffer output-buffer + (goto-char (point-min)) + (when (search-forward "gud-completions:" nil t) + (read (current-buffer)))))) + +(defun gud-lldb-completions (_context _command) + "Completion table for LLDB commands." + (gud-gdb-completions-1 (gud-lldb-fetch-completions))) + +(defun gud-lldb-completion-at-point () + "Return the data to complete the LLDB command before point." + (let* ((end (point)) + (line-start (comint-line-beginning-position)) + (start (save-excursion + (skip-chars-backward "^ " line-start) + (point)))) + (list (copy-marker start t) end + (completion-table-dynamic + (apply-partially #'gud-lldb-completions + (buffer-substring line-start start)))))) + +(defvar gud-lldb-def-python-completion-function + (concat + "script --language python -- " + "def gud_complete(c): " + "ci = lldb.debugger.GetCommandInterpreter(); " + "sl = lldb.SBStringList(); " + "ci.HandleCompletion(c, len(c), len(c),-1, sl); " + "print('gud-completions: ('); " + "[print(f'\"{sl.GetStringAtIndex(i)}\" ') " + " for i in range(sl.GetSize())]; " + "print(')')") + "LLDB command to define a Python function for completion. +Must be a single line.") + +(defun gud-lldb-initialize () + "Initialize the LLDB process as needed for this debug session." + (gud-basic-call gud-lldb-def-python-completion-function)) + ;;;###autoload (defun lldb (command-line) "Run lldb passing it COMMAND-LINE as arguments. @@ -3979,11 +4056,17 @@ lldb nil "Run the program.") + (add-hook 'completion-at-point-functions + #'gud-lldb-completion-at-point + nil 'local) + (keymap-local-set "" #'completion-at-point) + (gud-set-repeat-map-property 'gud-gdb-repeat-map) (setq comint-prompt-regexp (rx line-start "(lldb)" (0+ blank))) (setq paragraph-start comint-prompt-regexp) (setq gud-running nil) (setq gud-filter-pending-text nil) + (gud-lldb-initialize) (run-hooks 'lldb-mode-hook)) (provide 'gud) -- 2.42.0