Gud LLDB completions (bug#66604)

* etc/emacs_lldb.py: Remove xcomplete.
* lisp/progmodes/gud.el: Implement lldb command completions.
* src/.lldbinit: Remove settings done in Gud.
This commit is contained in:
Gerd Möllmann 2023-10-18 09:24:45 +02:00
parent 646ecec0ec
commit 1038e48038
3 changed files with 99 additions and 37 deletions

View file

@ -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")

View file

@ -3850,7 +3850,7 @@ so they have been disabled."))
;; '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 @@ so they have been disabled."))
: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,96 @@ so they have been disabled."))
(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 (context command)
"Return the data to complete the LLDB command before point.
This is what the Python function we installed at initialzation
time returns, as a Lisp list."
(let* ((process (get-buffer-process gud-comint-buffer))
(to-complete (concat context command))
(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."
(let ((completions (gud-lldb-fetch-completions context command)))
;; If this is a cmpletion for w whole word, return a completion
;; list that contains that word only, with a space appended.
(if (string-suffix-p " " (car completions))
(list (concat (cadr completions) " "))
(cdr 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)))
(context (buffer-substring line-start start)))
(list (copy-marker start t)
end
(completion-table-dynamic
(apply-partially #'gud-lldb-completions context)))))
(defvar gud-lldb-def-python-completion-function
"
def gud_complete(s):
interpreter = lldb.debugger.GetCommandInterpreter()
string_list = lldb.SBStringList()
interpreter.HandleCompletion(s, len(s), len(s), -1, string_list)
print('gud-completions: (')
for i in range(string_list.GetSize()):
print(f'\"{string_list.GetStringAtIndex(i)}\" ')
print(')')
"
"LLDB command to define a Python function for completion.")
(defun gud-lldb-send-python (python)
(gud-basic-call "script --language python --")
(mapc #'gud-basic-call (split-string python "\n"))
(gud-basic-call "exit()"))
(defun gud-lldb-initialize ()
"Initialize the LLDB process as needed for this debug session."
(gud-lldb-send-python gud-lldb-def-python-completion-function)
(gud-basic-call "settings set stop-line-count-before 0")
(gud-basic-call "settings set stop-line-count-after 0")
(gud-basic-call "script --language python -- print('Gud initialized')"))
;;;###autoload
(defun lldb (command-line)
"Run lldb passing it COMMAND-LINE as arguments.
@ -3979,11 +4069,17 @@ the buffer in which this command was invoked."
nil
"Run the program.")
(add-hook 'completion-at-point-functions
#'gud-lldb-completion-at-point
nil 'local)
(keymap-local-set "<tab>" #'completion-at-point)
(gud-set-repeat-map-property 'gud-gdb-repeat-map)
(setq comint-prompt-regexp (rx line-start "(lldb)" (0+ blank)))
(setq comint-process-echoes t)
(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)

View file

@ -33,8 +33,4 @@ command script import emacs_lldb
# Print with children provider, depth 2.
command alias xprint frame variable -P 2
# This is for M-x lldb: don't show source lines when stopping.
settings set stop-line-count-before 0
settings set stop-line-count-after 0
# end.