1 ;;; gds.el -- frontend for Guile development in Emacs
3 ;;;; Copyright (C) 2003 Free Software Foundation, Inc.
5 ;;;; This library is free software; you can redistribute it and/or
6 ;;;; modify it under the terms of the GNU Lesser General Public
7 ;;;; License as published by the Free Software Foundation; either
8 ;;;; version 2.1 of the License, or (at your option) any later
11 ;;;; This library is distributed in the hope that it will be useful,
12 ;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13 ;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 ;;;; Lesser General Public License for more details.
16 ;;;; You should have received a copy of the GNU Lesser General Public
17 ;;;; License along with this library; if not, write to the Free
18 ;;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
29 ;;;; Debugging (of this code!).
31 (defsubst dmessage
(msg &rest args
)
32 ;;(apply (function message) msg args)
36 ;;;; Customization group setup.
39 "Customization options for Guile Emacs frontend."
43 ;;;; Communication with the (ice-9 debugger ui-server) subprocess.
45 ;; The subprocess object.
46 (defvar gds-process nil
)
48 ;; Subprocess output goes into the `*GDS Process*' buffer, and
49 ;; is then read from there one form at a time. `gds-read-cursor' is
50 ;; the buffer position of the start of the next unread form.
51 (defvar gds-read-cursor nil
)
54 "Start (or restart, if already running) the GDS subprocess."
56 (if gds-process
(gds-shutdown))
57 (with-current-buffer (get-buffer-create "*GDS Process*")
60 (let ((process-connection-type nil
)) ; use a pipe
69 "/home/neil/Guile/cvs/guile-core/ice-9/debugger/ui-server.scm"))))
70 (setq gds-read-cursor
(point-min))
71 (set-process-filter gds-process
(function gds-filter
))
72 (set-process-sentinel gds-process
(function gds-sentinel
))
73 (set-process-coding-system gds-process
'latin-1-unix
))
75 ;; Shutdown the subprocess and cleanup all associated data.
76 (defun gds-shutdown ()
77 "Shut down the GDS subprocess."
79 ;; Do cleanup for all clients.
81 (gds-client-cleanup (caar gds-names
)))
82 ;; Reset any remaining variables.
83 (setq gds-displayed-client nil
85 ;; If the timer is running, cancel it.
87 (cancel-timer gds-timer
))
89 ;; Kill the subprocess.
90 (process-kill-without-query gds-process
)
93 (kill-process gds-process
)
94 (accept-process-output gds-process
0 200))
96 (setq gds-process nil
))
98 ;; Subprocess output filter: inserts normally into the process buffer,
99 ;; then tries to reread the output one form at a time and delegates
100 ;; processing of each form to `gds-handle-input'.
101 (defun gds-filter (proc string
)
102 (with-current-buffer (process-buffer proc
)
104 (goto-char (process-mark proc
))
105 (insert-before-markers string
))
106 (goto-char gds-read-cursor
)
107 (while (let ((form (condition-case nil
108 (read (current-buffer))
112 (gds-handle-input form
)))
114 (setq gds-read-cursor
(point)))))
116 ;; Subprocess sentinel: do nothing. (Currently just here to avoid
117 ;; inserting un-`read'able process status messages into the process
119 (defun gds-sentinel (proc event
)
122 ;; Send input to the subprocess.
123 (defun gds-send (string)
124 (process-send-string gds-process string
))
127 ;;;; Multiple application scheduling.
129 ;; At any moment one Guile application has the focus of the frontend
130 ;; code. `gds-displayed-client' holds the port number of that client.
131 ;; If there are no Guile applications wanting the focus - that is,
132 ;; ready for instructions - `gds-displayed-client' is nil.
133 (defvar gds-displayed-client nil
)
135 ;; The list of other Guile applications waiting for focus, referenced
136 ;; by their port numbers.
137 (defvar gds-waiting nil
)
139 ;; An idle timer that we use to avoid confusing any user work when
140 ;; popping up debug buffers. `gds-timer' is non-nil whenever the
141 ;; timer is running and nil whenever it is not running.
142 (defvar gds-timer nil
)
144 ;; Debug the specified client. If it already has the focus, do so
145 ;; immediately, but using the idle timer to ensure that it doesn't
146 ;; confuse any work the user may be doing. Non-structural work is
147 ;; delegated to `gds-display-state'.
148 (defun gds-debug (&optional client
)
149 (dmessage "gds-debug")
150 ;; If `client' is specified, add it to the end of `gds-waiting',
151 ;; unless that client is already the current client or it is already
152 ;; in the waiting list.
154 (not (eq client gds-displayed-client
))
155 (not (memq client gds-waiting
)))
156 (setq gds-waiting
(append gds-waiting
(list client
))))
157 ;; Now update `client' to be the next client in the list.
158 (setq client
(or gds-displayed-client
(car gds-waiting
)))
159 ;; If conditions are right, start the idle timer.
161 (or (null gds-displayed-client
)
162 (eq gds-displayed-client client
)))
163 (gds-display-state (or gds-displayed-client
164 (prog1 (car gds-waiting
)
166 (cdr gds-waiting
)))))))
168 ;; Give up focus because debugging is done for now. Display detail in
169 ;; case of no waiting clients is delegated to `gds-clear-display'.
170 (defun gds-focus-done ()
174 ;; Although debugging of this client isn't done, yield focus to the
175 ;; next waiting client.
176 (defun gds-focus-yield ()
178 (if (and (null gds-waiting
)
179 (y-or-n-p "No other clients waiting - bury *Guile* buffer? "))
181 (or (memq gds-displayed-client gds-waiting
)
182 (setq gds-waiting
(append gds-waiting
(list gds-displayed-client
))))
186 ;;;; Per-client state information.
188 ;; Alist mapping client port numbers to application names. The names
189 ;; in this list have been uniquified by `gds-uniquify'.
190 (defvar gds-names nil
)
192 ;; Return unique form of NAME.
193 (defun gds-uniquify (name)
196 (while (member maybe-unique
(mapcar (function cdr
) gds-names
))
197 (setq count
(1+ count
)
198 maybe-unique
(concat name
"<" (number-to-string count
) ">")))
201 ;; Alist mapping client port numbers to last known status.
203 ;; Status is one of the following symbols.
205 ;; `running' - application is running.
207 ;; `waiting-for-input' - application is blocked waiting for
208 ;; instruction from the frontend.
210 ;; `ready-for-input' - application is not blocked but can also
211 ;; accept asynchronous instructions from the frontend.
213 (defvar gds-statuses nil
)
215 ;; Alist mapping client port numbers to last printed outputs.
216 (defvar gds-outputs nil
)
218 ;; Alist mapping client port numbers to last known stacks.
219 (defvar gds-stacks nil
)
221 ;; Alist mapping client port numbers to module information. This
224 ;; ((4 ((guile) t sym1 sym2 ...) ((guile-user)) ((ice-9 debug) nil sym3 sym4) ...) ...)
228 ;; (assq client gds-modules)
230 ;; (4 ((guile) t sym1 sym2 ...) ((guile-user)) ((ice-9 debug) nil sym3 sym4) ...)
232 ;; The t or nil after the module name indicates whether the module is
233 ;; displayed in expanded form (that is, showing the bindings in that
236 ;; The syms are actually all strings, because some Guile symbols are
237 ;; not readable by Emacs.
238 (defvar gds-modules nil
)
241 ;;;; Handling debugging instructions.
243 ;; General dispatch function called by the subprocess filter.
244 (defun gds-handle-input (form)
245 (dmessage "Form: %S" form
)
246 (let ((client (car form
)))
247 (cond ((eq client
'*))
249 (let ((proc (cadr form
)))
251 (cond ((eq proc
'name
)
252 ;; (name ...) - Application's name.
254 (cons (cons client
(gds-uniquify (caddr form
)))
258 ;; (stack ...) - Stack at an error or breakpoint.
259 (gds-set gds-stacks client
(cddr form
)))
262 ;; (modules ...) - Application's loaded modules.
263 (gds-set gds-modules client
264 (mapcar (function list
) (cddr form
))))
267 ;; (output ...) - Last printed output.
268 (gds-set gds-outputs client
(caddr form
)))
271 ;; (status ...) - Application status indication.
272 (let ((status (caddr form
)))
273 (gds-set gds-statuses client status
)
274 (cond ((eq status
'waiting-for-input
)
276 ((or (eq status
'running
)
277 (eq status
'ready-for-input
))
278 (if (eq client gds-displayed-client
)
279 (gds-display-state client
)))
281 (error "Unexpected status: %S" status
)))))
284 ;; (module MODULE ...) - The specified module's bindings.
285 (let* ((modules (assq client gds-modules
))
286 (minfo (assoc (caddr form
) modules
)))
288 (setcdr (cdr minfo
) (cdddr form
)))))
291 ;; (closed) - Client has gone away.
292 (gds-client-cleanup client
))
294 ((eq proc
'eval-results
)
295 ;; (eval-results ...) - Results of evaluation.
296 (gds-display-results client
(cddr form
)))
300 (defun gds-display-results (client results
)
301 (let ((buf (get-buffer-create "*Guile Results*")))
306 (insert (car results
))
307 (mapcar (function (lambda (value)
308 (insert " => " value
"\n")))
311 (setq results
(cddr results
))))
312 (pop-to-buffer buf
)))
314 ;; Store latest status, stack or module list for the specified client.
315 (defmacro gds-set
(alist client val
)
316 `(let ((existing (assq ,client
,alist
)))
318 (setcdr existing
,val
)
320 (cons (cons client
,val
) ,alist
)))))
322 ;; Cleanup processing when CLIENT goes away.
323 (defun gds-client-cleanup (client)
324 (if (eq client gds-displayed-client
)
327 (delq (assq client gds-names
) gds-names
))
329 (delq (assq client gds-stacks
) gds-stacks
))
331 (delq (assq client gds-modules
) gds-modules
)))
334 ;;;; Displaying debugging information.
336 (defvar gds-client-buffer nil
)
338 (define-derived-mode gds-mode
341 "Major mode for Guile information buffers.")
343 (defun gds-set-client-buffer (&optional client
)
344 (if (and gds-client-buffer
345 (buffer-live-p gds-client-buffer
))
346 (set-buffer gds-client-buffer
)
347 (setq gds-client-buffer
(get-buffer-create "*Guile*"))
348 (set-buffer gds-client-buffer
)
350 ;; Rename to something we don't want first. Otherwise, if the
351 ;; buffer is already correctly named, we get a confusing change
352 ;; from, say, `*Guile: REPL*' to `*Guile: REPL*<2>'.
353 (rename-buffer "*Guile Fake Buffer Name*" t
)
354 (rename-buffer (if client
356 (cdr (assq client gds-names
))
359 t
) ; Rename uniquely if needed,
360 ; although it shouldn't be.
361 (force-mode-line-update t
))
363 (defun gds-clear-display ()
364 ;; Clear the client buffer.
365 (gds-set-client-buffer)
366 (let ((inhibit-read-only t
))
368 (insert "Stack:\nNo clients ready for debugging.\n")
369 (goto-char (point-min)))
370 (setq gds-displayed-stack
'no-clients
)
371 (setq gds-displayed-modules nil
)
372 (setq gds-displayed-client nil
)
375 ;; Determine whether the client display buffer is visible in the
376 ;; currently selected frame (i.e. where the user is editing).
377 (defun gds-buffer-visible-in-selected-frame-p ()
378 (let ((visible-p nil
))
379 (walk-windows (lambda (w)
380 (if (eq (window-buffer w
) gds-client-buffer
)
381 (setq visible-p t
))))
384 ;; Cached display variables for `gds-display-state'.
385 (defvar gds-displayed-stack nil
)
386 (defvar gds-displayed-modules nil
)
388 ;; Types of display areas in the *Guile* buffer.
389 (defvar gds-display-types
'("Status" "Stack" "Modules"))
390 (defvar gds-display-type-regexp
392 (substring (apply (function concat
)
393 (mapcar (lambda (type)
399 (defun gds-maybe-delete-region (type)
400 (let ((beg (save-excursion
401 (goto-char (point-min))
402 (and (re-search-forward (concat "^"
406 (match-beginning 0)))))
412 (or (and (re-search-forward gds-display-type-regexp
417 (defun gds-maybe-skip-region (type)
418 (if (looking-at (regexp-quote type
))
419 (if (re-search-forward gds-display-type-regexp nil t
2)
421 (goto-char (point-max)))))
423 (defun gds-display-state (client)
424 (dmessage "gds-display-state")
425 ;; Avoid continually popping up the last associated source buffer
426 ;; unless it really is still current.
427 (setq gds-selected-frame-source-buffer nil
)
428 (gds-set-client-buffer client
)
429 (let ((stack (cdr (assq client gds-stacks
)))
430 (modules (cdr (assq client gds-modules
)))
431 (inhibit-read-only t
)
432 (p (if (eq client gds-displayed-client
)
436 ;; Start at top of buffer.
437 (goto-char (point-min))
438 ;; Display status; too simple to be worth caching.
439 (gds-maybe-delete-region "Status")
440 (widget-insert "Status: "
441 (cdr (assq (cdr (assq client gds-statuses
))
442 '((running .
"running (cannot accept input)")
443 (waiting-for-input .
"waiting for input")
444 (ready-for-input .
"running"))))
446 (let ((output (cdr (assq client gds-outputs
))))
447 (if (> (length output
) 0)
448 (widget-insert output
"\n\n")))
450 (dmessage "insert stack")
451 (if (equal stack gds-displayed-stack
)
452 (gds-maybe-skip-region "Stack")
453 ;; Note that stack has changed.
454 (if stack
(setq stack-changed t
))
455 ;; Delete existing stack.
456 (gds-maybe-delete-region "Stack")
458 (if stack
(gds-insert-stack stack
))
459 ;; Record displayed stack.
460 (setq gds-displayed-stack stack
))
461 ;; Display module list.
462 (dmessage "insert modules")
463 (if (equal modules gds-displayed-modules
)
464 (gds-maybe-skip-region "Modules")
465 ;; Delete existing module list.
466 (gds-maybe-delete-region "Modules")
468 (if modules
(gds-insert-modules modules
))
469 ;; Record displayed list.
470 (setq gds-displayed-modules
(copy-tree modules
)))
472 (dmessage "widget-setup")
475 ;; Stack is being seen for the first time, so make sure top of
476 ;; buffer is visible.
478 (goto-char (point-min))
479 (re-search-forward "^Stack:")
480 (forward-line (+ 1 (cadr stack
))))
481 ;; Restore point from before buffer was redrawn.
483 (setq gds-displayed-client client
)
484 (dmessage "consider display")
485 (if (eq (window-buffer (selected-window)) gds-client-buffer
)
486 ;; *Guile* buffer already selected.
487 (gds-display-buffers)
488 (dmessage "Running GDS timer")
490 (run-with-idle-timer 0.5
494 (gds-display-buffers))))))
496 (defun gds-display-buffers ()
497 ;; If there's already a window showing the *Guile* buffer, use
499 (let ((window (get-buffer-window gds-client-buffer t
)))
502 (make-frame-visible (window-frame window
))
503 (raise-frame (window-frame window
))
504 (select-frame (window-frame window
))
505 (select-window window
))
506 (switch-to-buffer gds-client-buffer
)))
507 ;; If there is an associated source buffer, display it as well.
508 (if gds-selected-frame-source-buffer
509 (let ((window (display-buffer gds-selected-frame-source-buffer
)))
510 (set-window-point window
511 (overlay-start gds-selected-frame-source-overlay
))))
516 (if (gds-buffer-visible-in-selected-frame-p)
517 ;; Buffer already visible enough.
519 ;; Delete any views of the buffer in other frames - we don't want
520 ;; views all over the place.
521 (delete-windows-on gds-client-buffer
)
522 ;; Run idle timer to display the buffer as soon as user isn't in
523 ;; the middle of something else.
526 (defun gds-insert-stack (stack)
527 (let ((frames (car stack
))
529 (flags (caddr stack
))
531 (widget-insert "Stack: " (prin1-to-string flags
) "\n")
533 (gds-show-selected-frame (caddr (nth index frames
)))
535 (setq frame
(car frames
)
538 items
(cons (list 'item
539 (let ((s (cadr frame
)))
540 (put-text-property 0 1 'index i s
)
543 (setq items
(nreverse items
))
544 (apply (function widget-create
)
546 :value
(cadr (nth index items
))
547 :notify
(function gds-select-stack-frame
)
549 (widget-insert "\n")))
551 (defun gds-select-stack-frame (widget &rest ignored
)
552 (let* ((s (widget-value widget
))
553 (ind (memq 'index
(text-properties-at 0 s
))))
554 (gds-send (format "(%S debugger-command frame %d)\n"
558 ;; Overlay used to highlight the source expression corresponding to
559 ;; the selected frame.
560 (defvar gds-selected-frame-source-overlay nil
)
562 ;; Buffer containing source for the selected frame.
563 (defvar gds-selected-frame-source-buffer nil
)
565 (defun gds-show-selected-frame (source)
566 ;; Highlight the frame source, if possible.
568 (file-readable-p (car source
)))
569 (with-current-buffer (find-file-noselect (car source
))
570 (if gds-selected-frame-source-overlay
572 (setq gds-selected-frame-source-overlay
(make-overlay 0 0))
573 (overlay-put gds-selected-frame-source-overlay
'face
'highlight
))
574 ;; Move to source line. Note that Guile line numbering is
575 ;; 0-based, while Emacs numbering is 1-based.
578 (goto-line (+ (cadr source
) 1))
579 (move-to-column (caddr source
))
580 (move-overlay gds-selected-frame-source-overlay
582 (if (not (looking-at ")"))
583 (save-excursion (forward-sexp 1) (point))
584 ;; It seems that the source coordinates for
585 ;; backquoted expressions are at the end of
586 ;; the sexp rather than the beginning...
587 (save-excursion (forward-char 1)
588 (backward-sexp 1) (point)))
590 (setq gds-selected-frame-source-buffer
(current-buffer)))
591 (if gds-selected-frame-source-overlay
592 (move-overlay gds-selected-frame-source-overlay
0 0))))
594 (defcustom gds-module-filter
'(t (guile nil
) (ice-9 nil
) (oop nil
))
595 "Specification of which Guile modules the debugger should display.
596 This is a list with structure (DEFAULT EXCEPTION EXCEPTION...), where
597 DEFAULT is `t' or `nil' and each EXCEPTION has the structure (SYMBOL
598 DEFAULT EXCEPTION EXCEPTION...).
600 A Guile module name `(x y z)' is matched against this filter as
601 follows. If one of the top level EXCEPTIONs has SYMBOL `x', continue
602 by matching the rest of the module name, in this case `(y z)', against
603 that SYMBOL's DEFAULT and next level EXCEPTION list. Otherwise, if
604 the current DEFAULT is `t' display the module, and if the current
605 DEFAULT is `nil', don't display it.
607 This variable is usually set to exclude Guile system modules that are
608 not of primary interest when debugging application code."
612 (defun gds-show-module-p (name)
613 ;; Determine whether to display the NAMEd module by matching NAME
614 ;; against `gds-module-filter'.
615 (let ((default (car gds-module-filter
))
616 (exceptions (cdr gds-module-filter
)))
617 (let ((exception (assq (car name
) exceptions
)))
619 (let ((gds-module-filter (cdr exception
)))
620 (gds-show-module-p (cdr name
)))
623 (defun gds-insert-modules (modules)
624 (insert "Modules:\n")
626 (let ((minfo (car modules
)))
627 (if (gds-show-module-p (car minfo
))
628 (let ((w (widget-create 'push-button
629 :notify
(function gds-module-notify
)
633 (widget-put w
:module
(cons client
(car minfo
)))
634 (widget-insert " " (prin1-to-string (car minfo
)) "\n")
636 (let ((syms (cddr minfo
)))
638 (widget-insert " > " (car syms
) "\n")
639 (setq syms
(cdr syms
))))))))
640 (setq modules
(cdr modules
))))
642 (defun gds-module-notify (w &rest ignore
)
643 (let* ((module (widget-get w
:module
))
644 (client (car module
))
646 (modules (assq client gds-modules
))
647 (minfo (assoc name modules
)))
649 ;; Just toggle expansion state.
651 (setcar (cdr minfo
) (not (cadr minfo
)))
652 (gds-display-state client
))
653 ;; Set flag to indicate module expanded.
654 (setcdr minfo
(list t
))
655 ;; Get symlist from Guile.
656 (gds-send (format "(%S query-module %S)\n" client name
)))))
659 ;;;; Guile Debugging keymap.
661 (set-keymap-parent gds-mode-map widget-keymap
)
662 (define-key gds-mode-map
"g" (function gds-go
))
663 (define-key gds-mode-map
"b" (function gds-set-breakpoint
))
664 (define-key gds-mode-map
"q" (function gds-quit
))
665 (define-key gds-mode-map
"y" (function gds-yield
))
666 (define-key gds-mode-map
" " (function gds-next
))
667 (define-key gds-mode-map
"e" (function gds-evaluate
))
668 (define-key gds-mode-map
"i" (function gds-step-in
))
669 (define-key gds-mode-map
"o" (function gds-step-out
))
670 (define-key gds-mode-map
"t" (function gds-trace-finish
))
672 (defun gds-client-waiting ()
673 (eq (cdr (assq gds-displayed-client gds-statuses
)) 'waiting-for-input
))
677 (gds-send (format "(%S debugger-command continue)\n" gds-displayed-client
)))
681 (if (gds-client-waiting)
682 (if (y-or-n-p "Client is waiting for instruction - tell it to continue? ")
688 (if (gds-client-waiting)
694 (gds-send (format "(%S debugger-command next 1)\n" gds-displayed-client
)))
696 (defun gds-evaluate (expr)
697 (interactive "sEvaluate (in this stack frame): ")
698 (gds-send (format "(%S debugger-command evaluate %s)\n"
700 (prin1-to-string expr
))))
702 (defun gds-step-in ()
704 (gds-send (format "(%S debugger-command step 1)\n" gds-displayed-client
)))
706 (defun gds-step-out ()
708 (gds-send (format "(%S debugger-command finish)\n" gds-displayed-client
)))
710 (defun gds-trace-finish ()
712 (gds-send (format "(%S debugger-command trace-finish)\n"
713 gds-displayed-client
)))
715 (defun gds-set-breakpoint ()
717 (cond ((gds-in-source-buffer)
718 (gds-set-source-breakpoint))
720 (gds-set-stack-breakpoint))
722 (gds-set-module-breakpoint))
724 (error "No way to set a breakpoint from here"))))
726 (defun gds-in-source-buffer ()
727 ;; Not yet worked out what will be available in Scheme source
731 (defun gds-in-stack ()
732 (and (eq (current-buffer) gds-client-buffer
)
734 (and (re-search-backward "^\\(Stack\\|Modules\\):" nil t
)
735 (looking-at "Stack")))))
737 (defun gds-in-modules ()
738 (and (eq (current-buffer) gds-client-buffer
)
740 (and (re-search-backward "^\\(Stack\\|Modules\\):" nil t
)
741 (looking-at "Modules")))))
743 (defun gds-set-module-breakpoint ()
744 (let ((sym (save-excursion
746 (and (looking-at " > \\([^ \n\t]+\\)")
748 (module (save-excursion
749 (and (re-search-backward "^\\[[+---]\\] \\(([^)]+)\\)" nil t
)
752 (error "Couldn't find procedure name on current line"))
754 (error "Couldn't find module name for current line"))
757 (format "Behaviour for breakpoint at %s:%s (default debug-here): "
767 (gds-send (format "(%S set-breakpoint %s %s %s)\n"
774 ;;;; Evaluating code.
776 ;; The following commands send code for evaluation through the GDS TCP
777 ;; connection, receive the result and any output generated through the
778 ;; same connection, and display the result and output to the user.
780 ;; Where there are multiple Guile applications known to GDS, GDS by
781 ;; default sends code to the one that holds the debugging focus,
782 ;; i.e. `gds-displayed-client'. Where no application has the focus,
783 ;; or the command is invoked `C-u', GDS asks the user which
784 ;; application is intended.
786 (defun gds-read-client ()
787 (let* ((def (if gds-displayed-client
788 (cdr (assq gds-displayed-client gds-names
))))
790 (concat "Application for eval (default "
793 "Application for eval: "))
795 (completing-read prompt
796 (mapcar (function cdr
) gds-names
)
799 (let (client (names gds-names
))
800 (while (and names
(not client
))
801 (if (string-equal (cadar names
) name
)
802 (setq client
(caar names
)))
803 (setq names
(cdr names
))))))
805 (defun gds-choose-client (client)
806 (or ;; If client is an integer, it is the port number of the
808 (if (integerp client
) client
)
809 ;; Any other non-nil value indicates invocation with a prefix
810 ;; arg, which forces asking the user which application is
812 (if client
(gds-read-client))
813 ;; If ask not forced, and there is a client with the focus,
814 ;; default to that one.
816 ;; Last resort - ask the user.
819 (error "No application chosen.")))
821 (defcustom gds-default-module-name
'(guile-user)
822 "Name of the default module for GDS code evaluation, as list of symbols.
823 This module is used when there is no `define-module' form in the
824 buffer preceding the code to be evaluated."
828 (defun gds-module-name (start end
)
829 "Determine and return the name of the module that governs the
830 specified region. The module name is returned as a list of symbols."
831 (interactive "r") ; why not?
835 (while (and (not module-name
)
836 (beginning-of-defun-raw 1))
837 (if (looking-at "(define-module ")
840 (goto-char (match-end 0))
841 (read (current-buffer))))))
844 (defun gds-port-name (start end
)
845 "Return port name for the specified region of the current buffer.
846 The name will be used by Guile as the port name when evaluating that
848 (or (buffer-file-name)
849 (concat "Emacs buffer: " (buffer-name))))
851 (defun gds-eval-region (start end
&optional client
)
852 "Evaluate the current region."
854 (setq client
(gds-choose-client client
))
855 (let ((module (gds-module-name start end
))
856 (port-name (gds-port-name start end
))
860 (setq column
(current-column)) ; 0-based
862 (setq line
(count-lines (point-min) (point)))) ; 0-based
863 (gds-send (format "(%S eval %s %S %d %d %S)\n"
865 (if module
(prin1-to-string module
) "#f")
866 port-name line column
867 (buffer-substring-no-properties start end
)))))
869 (defun gds-eval-expression (expr &optional client
)
870 "Evaluate the supplied EXPR (a string)."
871 (interactive "sEvaluate expression: \nP")
872 (setq client
(gds-choose-client client
))
873 (gds-send (format "(%S eval #f \"Emacs expression\" 0 0 %S)\n"
876 (defun gds-eval-defun (&optional client
)
877 "Evaluate the defun (top-level form) at point."
883 (gds-eval-region (point) end client
))))
885 (defun gds-eval-last-sexp (&optional client
)
886 "Evaluate the sexp before point."
888 (gds-eval-region (save-excursion (backward-sexp) (point)) (point) client
))
890 (defcustom gds-source-modes
'(scheme-mode)
891 "*Used to determine if a buffer contains Scheme source code.
892 If it's loaded into a buffer that is in one of these major modes, it's
893 considered a scheme source file by `gds-load-file'."
894 :type
'(repeat function
)
897 (defvar gds-prev-load-dir
/file nil
898 "Holds the last (directory . file) pair passed to `gds-load-file'.
899 Used for determining the default for the next `gds-load-file'.")
901 (defun gds-load-file (file-name &optional client
)
902 "Load a Scheme file into the inferior Scheme process."
903 (interactive (list (car (comint-get-source "Load Scheme file: "
904 gds-prev-load-dir
/file
906 ; T because LOAD needs an
909 (comint-check-source file-name
) ; Check to see if buffer needs saved.
910 (setq gds-prev-load-dir
/file
(cons (file-name-directory file-name
)
911 (file-name-nondirectory file-name
)))
912 (setq client
(gds-choose-client client
))
913 (gds-send (format "(%S load %S)\n" client file-name
)))
915 ;; Install the process communication commands in the scheme-mode keymap.
916 (define-key scheme-mode-map
"\M-\C-x" 'gds-eval-defun
);gnu convention
917 (define-key scheme-mode-map
"\C-x\C-e" 'gds-eval-last-sexp
);gnu convention
918 (define-key scheme-mode-map
"\C-c\C-e" 'gds-eval-defun
)
919 (define-key scheme-mode-map
"\C-c\C-r" 'gds-eval-region
)
920 (define-key scheme-mode-map
"\C-c\C-l" 'gds-load-file
)
923 ;;;; Menu bar entries.
925 (defvar gds-debug-menu nil
926 "GDS debugging menu.")
929 (setq gds-debug-menu
(make-sparse-keymap "Debug"))
930 (define-key gds-debug-menu
[go]
931 '(menu-item "Go" gds-go))
932 (define-key gds-debug-menu [trace-finish]
933 '(menu-item "Trace This Frame" gds-trace-finish))
934 (define-key gds-debug-menu [step-out]
935 '(menu-item "Finish This Frame" gds-step-out))
936 (define-key gds-debug-menu [next]
937 '(menu-item "Next" gds-next))
938 (define-key gds-debug-menu [step-in]
939 '(menu-item "Single Step" gds-step-in))
940 (define-key gds-debug-menu [eval]
941 '(menu-item "Eval In This Frame..." gds-evaluate)))
943 (defvar gds-eval-menu nil
944 "GDS evaluation menu.")
947 (setq gds-eval-menu (make-sparse-keymap "Evaluate"))
948 (define-key gds-eval-menu [load-file]
949 '(menu-item "Load Scheme File" gds-load-file))
950 (define-key gds-eval-menu [defun]
951 '(menu-item "Defun At Point" gds-eval-defun))
952 (define-key gds-eval-menu [region]
953 '(menu-item "Region" gds-eval-region))
954 (define-key gds-eval-menu [last-sexp]
955 '(menu-item "Sexp Before Point" gds-eval-last-sexp))
956 (define-key gds-eval-menu [expr]
957 '(menu-item "Expression..." gds-eval-expression)))
959 (defvar gds-help-menu nil
963 (setq gds-help-menu (make-sparse-keymap "Help"))
964 (define-key gds-help-menu [apropos]
965 '(menu-item "Apropos..." gds-apropos))
966 (define-key gds-help-menu [sym-here]
967 '(menu-item "Symbol At Point" gds-help-symbol-here))
968 (define-key gds-help-menu [sym]
969 '(menu-item "Symbol..." gds-help-symbol)))
971 (defvar gds-advanced-menu nil
972 "Menu of rarely needed GDS operations.")
973 (if gds-advanced-menu
975 (setq gds-advanced-menu (make-sparse-keymap "Advanced"))
976 (define-key gds-advanced-menu [restart-gds]
977 '(menu-item "Restart IDE" gds-start :enable gds-process))
978 (define-key gds-advanced-menu [kill-gds]
979 '(menu-item "Shutdown IDE" gds-shutdown :enable gds-process))
980 (define-key gds-advanced-menu [start-gds]
981 '(menu-item "Start IDE" gds-start :enable (not gds-process))))
984 "Global menu for GDS commands.")
987 (setq gds-menu (make-sparse-keymap "Guile"))
988 (define-key gds-menu [advanced]
989 (cons "Advanced" gds-advanced-menu))
990 (define-key gds-menu [separator-1]
992 (define-key gds-menu [help]
993 `(menu-item "Help" ,gds-help-menu :enable gds-names))
994 (define-key gds-menu [eval]
995 `(menu-item "Evaluate" ,gds-eval-menu :enable gds-names))
996 (define-key gds-menu [debug]
997 `(menu-item "Debug" ,gds-debug-menu :enable (and gds-displayed-client
998 (gds-client-waiting))))
999 (setq menu-bar-final-items
1000 (cons 'guile menu-bar-final-items))
1001 (define-key global-map [menu-bar guile]
1002 (cons "Guile" gds-menu)))
1004 ;;;; Autostarting the GDS server.
1006 (defcustom gds-autostart-server t
1007 "Whether to automatically start the GDS server when `gds.el' is loaded."
1011 (if (and gds-autostart-server
1017 ;;; gds.el ends here.