3.5.3 Getting Started with GDS

To enable the use of GDS in your own Emacs sessions, simply add

(require 'gds)

somewhere in your .emacs file. This will cause Emacs to load the
GDS Emacs Lisp code when starting up, and to start the inferior GDS
server process so that it is ready and waiting for any Guile programs
that want to use GDS.

The Scheme side of GDS is installed automatically by Guile. The Emacs
Lisp side, however, is not. You will have to grab
gds-server.el, gds-scheme.el, and gds.el from
Guile's source distribution, and make sure they end up in Emacs' load
path.

(If GDS's Scheme code is not installed in one of the locations in
Guile's load path, you may find that the server process fails to start.
When this happens you will see an error message from Emacs:

error in process filter: Wrong type argument: listp, Backtrace:

and the gds-debug buffer will contain a Scheme backtrace ending
with the message:

no code for module (ice-9 gds-server)

The solution for this is to customize the Emacs variable
gds-scheme-directory so that it specifies where the GDS Scheme
code is installed. Then either restart Emacs or type M-x
gds-run-debug-server to try starting the GDS server process again.)

For evaluations, help and completion from Scheme code buffers that you
are working on, this is all you need. The first time you do any of
these things, GDS will automatically start a new Guile client program as
an Emacs subprocess. This Guile program does nothing but wait for and
act on instructions from GDS, and we refer to it as a utility
Guile client. Over time this utility client will accumulate the code
that you ask it to evaluate, and you can also tell it to load complete
files or modules by sending it load or use-modules
expressions.

When you want to use GDS to work on an independent Guile
application, you need to add something to that application's Scheme code
to cause it to connect to and interact with GDS at the right times. The
following subsections describe the ways of doing this.

3.5.3.1 Invoking GDS when an Exception Occurs

One option is to use GDS to catch and display any exceptions that
are thrown by the application's code. If you already have a
lazy-catch or with-throw-handler around the area of code
that you want to monitor, you just need to add the following to the
handler code:

(gds-debug-trap (throw->trap-context key args))

where key and args are the first and rest arguments that
Guile passes to the handler. (In other words, they assume the handler
signature (lambda (key . args) ...).) With Guile 1.8 or
later, you can also do this with a catch, by adding this same
code to the catch's pre-unwind handler.

If you don't already have any of these, insert a whole
with-throw-handler expression (or lazy-catch if your Guile
is pre-1.8) around the code of interest like this:

Either way, you will need to use the (ice-9 gds-client) and
(ice-9 debugging traps) modules.

Two special cases of this are the lazy-catch that the Guile REPL code
uses to catch exceptions in user code, and the lazy-catch inside the
stack-catch utility procedure that is provided by the
(ice-9 stack-catch) module. Both of these use a handler called
lazy-handler-dispatch (defined in boot-9.scm), which you
can hook into such that it calls GDS to display the stack when an
exception occurs. To do this, use the on-lazy-handler-dispatch
procedure as follows.

After this the program will use GDS to display the stack whenever it
hits an exception that is protected by a lazy-catch using
lazy-handler-dispatch.

3.5.3.2 Accepting GDS Instructions at Any Time

In addition to setting an exception handler as described above, a
Guile program can in principle set itself up to accept new
instructions from GDS at any time, not just when it has stopped at an
exception. This would allow the GDS user to evaluate code in the
context of the running program, without having to wait for the program
to stop first.

(use-modules (ice-9 gds-client))
(gds-accept-input #t)

gds-accept-input causes the calling program to loop processing
instructions from GDS, until GDS sends the continue instruction.
This blocks the thread that calls it, however, so it will normally be
more practical for the program to set up a dedicated GDS thread and call
gds-accept-input from that thread.

For select-driven applications, an alternative approach would be
for the GDS client code to provide an API which allowed the application
to

discover the file descriptors (or Scheme ports) that are used for
receiving instruction from the GDS front end, so that it could include
these in its select call

call the GDS instruction handler when select indicated data
available for reading on those descriptors/ports.

This approach is not yet implemented, though.

3.5.3.3 Utility Guile Implementation

The “utility” Guile client mentioned above is a simple combination
of the mechanisms that we have just described. In fact the code for
the utility Guile client is essentially just this:

The named-module-use! line ensures that the client can process
help and apropos expressions, to implement lookups in
Guile's online help. The #f parameter to
gds-accept-input means that the continue instruction
will not cause the instruction loop to exit, which makes sense here
because the utility client has nothing to do except to process GDS
instructions.

The utility client does not use on-lazy-handler-dispatch at its
top level, because it has its own mechanism for catching and reporting
exceptions in the code that it is asked to evaluate. This mechanism
summarizes the exception and gives the user a button they can click to
see the full stack, so the end result is very similar to what
on-lazy-handler-dispatch provides. Deep inside
gds-accept-input, in the part that handles evaluating
expressions from Emacs, the GDS client code uses
throw->trap-context and gds-debug-trap to implement
this.