Next: , Previous: GDS Architecture, Up: Using Guile in Emacs


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:

     (with-throw-handler #t
       (lambda ()
         ;; Protected code here.
         )
       (lambda (key . args)
         (gds-debug-trap (throw->trap-context key args))))

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.

     (use-modules (ice-9 gds-client)
                  (ice-9 debugging traps))
     (on-lazy-handler-dispatch gds-debug-trap)

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

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:

     (use-modules (ice-9 gds-client))
     (named-module-use! '(guile-user) '(ice-9 session))
     (gds-accept-input #f))

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.