Skip to content

Commit e0dca57

Browse files
committed
Add completion at point suppport for the comint buffer
1 parent 70131b5 commit e0dca57

File tree

2 files changed

+106
-27
lines changed

2 files changed

+106
-27
lines changed

gdb-mi.el

Lines changed: 38 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,7 @@ This can also be set to t, which means that all debug components are active."
230230
gdb--context-disassemble ;; Data: BufferData
231231
gdb--context-persist-thread
232232
gdb--context-get-data ;; Data: Result name string
233+
gdb--context-get-console-data
233234
gdb--context-ignore-errors
234235
)
235236
"List of implemented token contexts.
@@ -505,6 +506,17 @@ ARGS-TO-COMMAND are passed to `gdb--command', after the context."
505506
(while (not gdb--data) (accept-process-output (gdb--session-process session) 0.5))
506507
(when (stringp gdb--data) gdb--data)))
507508

509+
(defun gdb--get-console-data (command &rest args-to-command)
510+
"Synchronously retrieve output from command. Each line will turn into a string in a list.
511+
ARGS-TO-COMMAND are passed to `gdb--command', after the context."
512+
(gdb--with-valid-session
513+
(setq gdb--data nil
514+
gdb--omit-console-output 'to-data)
515+
(apply 'gdb--command command 'gdb--context-get-console-data args-to-command)
516+
(while (or (not gdb--data) (user-ptrp gdb--data))
517+
(accept-process-output (gdb--session-process session) 0.5))
518+
(when (listp gdb--data) gdb--data)))
519+
508520

509521
;; ------------------------------------------------------------------------------------------
510522
;; Files
@@ -1098,9 +1110,11 @@ HAS-CHILDREN should be t when this node has children."
10981110
(define-derived-mode gdb-comint-mode comint-mode "GDB Comint"
10991111
"Major mode for interacting with GDB."
11001112
(setq-local comint-input-sender #'gdb--comint-sender)
1101-
(setq-local comint-preoutput-filter-functions '(gdb--output-filter)))
1113+
(setq-local comint-preoutput-filter-functions '(gdb--output-filter))
1114+
(setq-local completion-at-point-functions '(gdb--comint-completion-at-point)))
11021115

11031116
(gdb--simple-get-buffer gdb--comint ignore "Comint" t
1117+
(setq gdb--omit-console-output nil)
11041118
(gdb-comint-mode)
11051119
(let ((process-connection-type nil))
11061120
(make-comint-in-buffer "GDB" buffer "gdb" nil "-i=mi"
@@ -1199,6 +1213,18 @@ stopped thread before running the command. If FORCE-STOPPED is
11991213
(when (and stopped-thread (not (eq force-stopped 'no-resume)))
12001214
(gdb--command "-exec-continue" nil stopped-thread)))))
12011215

1216+
(defun gdb--comint-completion-at-point ()
1217+
(let* ((real-beg (comint-line-beginning-position)) (end (point-max))
1218+
(str (buffer-substring-no-properties real-beg end)))
1219+
(unless (= real-beg end)
1220+
(setq beg (string-match " [^ ]+" str)
1221+
beg (or (and beg (+ real-beg 1 beg)) real-beg))
1222+
(list beg end
1223+
(completion-table-dynamic (lambda (_)
1224+
(let ((raw-list (gdb--get-console-data (concat "complete " str))))
1225+
(cl-loop for item in raw-list
1226+
collect (substring item (- beg real-beg))))))))))
1227+
12021228

12031229
;; ------------------------------------------------------------------------------------------
12041230
;; Infer from point
@@ -2107,10 +2133,6 @@ it from the list."
21072133
(defun gdb--persist-thread ()
21082134
(gdb--with-valid-session (setf (gdb--session-persist-thread session) t)))
21092135

2110-
(defun gdb--set-data (result) (setq gdb--data (or result 'no-data)))
2111-
2112-
(defun gdb--finalize-user-command () (setq gdb--omit-console-output t))
2113-
21142136
;; ------------------------------------------------------------------------------------------
21152137
;; Global minor mode
21162138
(define-minor-mode gdb-keys-mode
@@ -2637,27 +2659,26 @@ If ARG is `dprintf' create a dprintf breakpoint instead."
26372659
(defun gdb-create-session ()
26382660
"Create GDB session. This will not associate any target with it."
26392661
(interactive)
2640-
(let* ((session (make-gdb--session))
2641-
(frame (gdb--create-frame session)))
2642-
(push session gdb--sessions)
2662+
(let ((gdb--session (make-gdb--session)))
2663+
(push gdb--session gdb--sessions)
2664+
(gdb--create-frame gdb--session)
26432665

2644-
(with-selected-frame frame ;; NOTE(nox): In order to have a session available
2645-
;; NOTE(nox): Create essential buffers
2646-
(gdb--comint-get-buffer session)
2647-
(gdb--inferior-io-get-buffer session)
2666+
;; NOTE(nox): Create essential buffers
2667+
(gdb--comint-get-buffer gdb--session)
2668+
(gdb--inferior-io-get-buffer gdb--session)
26482669

2649-
;; NOTE(nox): Essential settings
2650-
(gdb--command "-gdb-set mi-async on")
2651-
(gdb--command "-gdb-set non-stop on"))
2670+
;; NOTE(nox): Essential settings
2671+
(gdb--command "-gdb-set mi-async on")
2672+
(gdb--command "-gdb-set non-stop on")
26522673

2653-
(gdb-setup-windows session)
2674+
(gdb-setup-windows gdb--session)
26542675
(when gdb-enable-global-keybindings
26552676
(gdb-keys-mode))
26562677

26572678
(add-hook 'delete-frame-functions #'gdb--handle-delete-frame)
26582679
(add-hook 'window-configuration-change-hook #'gdb--rename-frame)
26592680

2660-
session))
2681+
gdb--session))
26612682

26622683
;;;###autoload
26632684
(defun gdb-executable ()

gdb-module.c

Lines changed: 68 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -52,16 +52,18 @@ u32 plugin_is_GPL_compatible;
5252
W(Cdr, cdr) \
5353
W(VecFunc, vector) \
5454
W(ListFunc, list) \
55-
W(DeleteProcess, delete-process) \
55+
W(Set, set) \
5656
W(Eval, eval) \
57+
W(Eq, eq) \
58+
W(DeleteProcess, delete-process) \
5759
\
5860
W(GdbCmd, gdb--command) \
5961
W(ExtractContext, gdb--extract-context) \
60-
W(SetData, gdb--set-data) \
6162
W(Error, error) \
6263
W(LogError, gdb--log-error) \
6364
\
64-
W(FinalizeUserCmd, gdb--finalize-user-command) \
65+
W(GdbData, gdb--data) \
66+
W(ConsoleOutputToData, to-data) \
6567
W(OmitConsoleOutput, gdb--omit-console-output) \
6668
\
6769
W(SwitchToThread, gdb--switch-to-thread) \
@@ -254,6 +256,14 @@ static inline emacs_value internFuncall(emacs_env *Env, char *Func, u32 NumArgs,
254256
return Result;
255257
}
256258

259+
static inline bool isNil(emacs_env *Env, emacs_value Thing) {
260+
return !Env->is_not_nil(Env, Thing);
261+
}
262+
263+
static inline bool isNotNil(emacs_env *Env, emacs_value Thing) {
264+
return Env->is_not_nil(Env, Thing);
265+
}
266+
257267
static void breakpointChange(emacs_env *Env, mi_result *Breakpoint) {
258268
#define breakpointVariablesWriter(W) W(Number, number), \
259269
W(Type, type), \
@@ -652,7 +662,7 @@ static void logError(emacs_env *Env, mi_result *Result, char **PrintString, char
652662
if(Message) {
653663
bufPrintf(*PrintString, "%s\n(gdb) ", Result->variant.cstring);
654664
funcall(Env, LogError, 1, (emacs_value[]){getEmacsString(Env, Message)});
655-
funcall(Env, FinalizeUserCmd, 0, 0);
665+
funcall(Env, Set, 2, (emacs_value[]){OmitConsoleOutput, T});
656666
}
657667
}
658668

@@ -748,13 +758,35 @@ static void handleMiOobRecord(emacs_env *Env, mi_oob_record *Record, char **Prin
748758
mi_stream_record *StreamRecord = Record->variant.stream_record;
749759
switch(StreamRecord->kind) {
750760
case GDBWIRE_MI_CONSOLE: {
751-
if(!Env->is_not_nil(Env, funcall(Env, Eval, 1, (emacs_value[]){OmitConsoleOutput}))) {
761+
emacs_value Omit = funcall(Env, Eval, 1, (emacs_value[]){OmitConsoleOutput});
762+
if(isNil(Env, funcall(Env, Eval, 1, (emacs_value[]){OmitConsoleOutput}))) {
752763
bufPrintf(*PrintString, "%s", StreamRecord->cstring);
753764
}
765+
else if(funcall(Env, Eq, 2, (emacs_value[]){Omit, ConsoleOutputToData})) {
766+
emacs_value *Array = 0;
767+
768+
emacs_value UserPtr = funcall(Env, Eval, 1, (emacs_value[]){GdbData});
769+
bool UserPtrExists = isNotNil(Env, UserPtr);
770+
if(UserPtrExists) {
771+
Array = Env->get_user_ptr(Env, UserPtr);
772+
}
773+
774+
if(StreamRecord->cstring) {
775+
// NOTE(nox): Remove newlines
776+
StreamRecord->cstring[strlen(StreamRecord->cstring) - 1] = 0;
777+
}
778+
bufPush(Array, getEmacsString(Env, StreamRecord->cstring));
779+
if(UserPtrExists) {
780+
Env->set_user_ptr(Env, UserPtr, Array);
781+
}
782+
else {
783+
UserPtr = Env->make_user_ptr(Env, 0, Array);
784+
funcall(Env, Set, 2, (emacs_value[]){GdbData, UserPtr});
785+
}
786+
}
754787
} break;
755788

756789
case GDBWIRE_MI_TARGET: {
757-
// TODO(nox): If we are outputting to another tty, will we ever receive this?
758790
bufPrintf(*PrintString, "Target: %s", StreamRecord->cstring);
759791
} break;
760792

@@ -786,6 +818,7 @@ typedef struct token_context {
786818
Context_Disassemble,
787819
Context_PersistThread,
788820
Context_GetData,
821+
Context_GetConsoleData,
789822
Context_IgnoreErrors,
790823

791824
Context_Size,
@@ -901,7 +934,21 @@ static void handleMiResultRecord(emacs_env *Env, mi_result_record *Record, char
901934
char *String = getResultString(Result, Key);
902935
free(Key);
903936

904-
funcall(Env, SetData, 1, (emacs_value[]){getEmacsString(Env, String)});
937+
funcall(Env, Set, 2, (emacs_value[]){GdbData, getEmacsString(Env, String)});
938+
} break;
939+
940+
case Context_GetConsoleData: {
941+
emacs_value UserPtr = funcall(Env, Eval, 1, (emacs_value[]){GdbData});
942+
if(isNotNil(Env, UserPtr)) {
943+
emacs_value *Array = Env->get_user_ptr(Env, UserPtr);
944+
emacs_value List = funcall(Env, ListFunc, bufLen(Array), Array);
945+
bufFree(Array);
946+
funcall(Env, Set, 2, (emacs_value[]){GdbData, List});
947+
} else {
948+
funcall(Env, Set, 2, (emacs_value[]){GdbData, T});
949+
}
950+
951+
funcall(Env, Set, 2, (emacs_value[]){OmitConsoleOutput, T});
905952
} break;
906953

907954
ignoreDefaultCase();
@@ -914,8 +961,19 @@ static void handleMiResultRecord(emacs_env *Env, mi_result_record *Record, char
914961
ignoreCase(Context_IgnoreErrors);
915962

916963
case Context_GetData: {
964+
emacs_value UserPtr = funcall(Env, Eval, 1, (emacs_value[]){GdbData});
965+
if(isNotNil(Env, UserPtr)) {
966+
emacs_value *Array = Env->get_user_ptr(Env, UserPtr);
967+
bufFree(Array);
968+
}
969+
funcall(Env, Set, 2, (emacs_value[]){GdbData, Error});
970+
funcall(Env, Set, 2, (emacs_value[]){OmitConsoleOutput, T});
971+
logError(Env, Result, PrintString, "msg");
972+
} break;
973+
974+
case Context_GetConsoleData: {
975+
funcall(Env, Set, 2, (emacs_value[]){GdbData, Error});
917976
logError(Env, Result, PrintString, "msg");
918-
funcall(Env, SetData, 1, &Error);
919977
} break;
920978

921979
default: { logError(Env, Result, PrintString, "msg"); } break;
@@ -963,9 +1021,9 @@ static emacs_value handleGdbMiOutput(emacs_env *Env, ptrdiff_t NumberOfArgs,
9631021
} break;
9641022

9651023
case GDBWIRE_MI_OUTPUT_PROMPT: {
966-
if(!Env->is_not_nil(Env, funcall(Env, Eval, 1, (emacs_value[]){OmitConsoleOutput}))) {
1024+
if(isNil(Env, funcall(Env, Eval, 1, (emacs_value[]){OmitConsoleOutput}))) {
9671025
bufPrintf(PrintString, "(gdb) ");
968-
funcall(Env, FinalizeUserCmd, 0, 0);
1026+
funcall(Env, Set, 2, (emacs_value[]){OmitConsoleOutput, T});
9691027
}
9701028
} break;
9711029
}

0 commit comments

Comments
 (0)