remove GDS
[bpt/guile.git] / emacs / gds-scheme.el
diff --git a/emacs/gds-scheme.el b/emacs/gds-scheme.el
deleted file mode 100755 (executable)
index 326d152..0000000
+++ /dev/null
@@ -1,540 +0,0 @@
-;;; gds-scheme.el -- GDS function for Scheme mode buffers
-
-;;;; Copyright (C) 2005 Neil Jerram
-;;;;
-;;;; This library is free software; you can redistribute it and/or
-;;;; modify it under the terms of the GNU Lesser General Public
-;;;; License as published by the Free Software Foundation; either
-;;;; version 3 of the License, or (at your option) any later version.
-;;;; 
-;;;; This library is distributed in the hope that it will be useful,
-;;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
-;;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-;;;; Lesser General Public License for more details.
-;;;; 
-;;;; You should have received a copy of the GNU Lesser General Public
-;;;; License along with this library; if not, write to the Free
-;;;; Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
-;;;; 02111-1307 USA
-
-(require 'comint)
-(require 'scheme)
-(require 'derived)
-(require 'pp)
-
-;;;; Maintaining an association between a Guile client process and a
-;;;; set of Scheme mode buffers.
-
-(defcustom gds-auto-create-utility-client t
-  "Whether to automatically create a utility Guile client, and
-associate the current buffer with it, if there are no existing Guile
-clients available to GDS when the user does something that requires a
-running Guile client."
-  :type 'boolean
-  :group 'gds)
-
-(defcustom gds-auto-associate-single-client t
-  "Whether to automatically associate the current buffer with an
-existing Guile client, if there is only only client known to GDS when
-the user does something that requires a running Guile client, and the
-current buffer is not already associated with a Guile client."
-  :type 'boolean
-  :group 'gds)
-
-(defcustom gds-auto-associate-last-client t
-  "Whether to automatically associate the current buffer with the
-Guile client that most recently caused that buffer to be displayed,
-when the user does something that requires a running Guile client and
-the current buffer is not already associated with a Guile client."
-  :type 'boolean
-  :group 'gds)
-
-(defvar gds-last-touched-by nil
-  "For each Scheme mode buffer, this records the GDS client that most
-recently `touched' that buffer in the sense of using it to display
-source code, for example for the source code relevant to a debugger
-stack frame.")
-(make-variable-buffer-local 'gds-last-touched-by)
-
-(defun gds-auto-associate-buffer ()
-  "Automatically associate the current buffer with a Guile client, if
-possible."
-  (let* ((num-clients (length gds-client-info))
-        (client
-         (or
-          ;; If there are no clients yet, and
-          ;; `gds-auto-create-utility-client' allows us to create one
-          ;; automatically, do that.
-          (and (= num-clients 0)
-               gds-auto-create-utility-client
-               (gds-start-utility-guile))
-          ;; Otherwise, if there is a single existing client, and
-          ;; `gds-auto-associate-single-client' allows us to use it
-          ;; for automatic association, do that.
-          (and (= num-clients 1)
-               gds-auto-associate-single-client
-               (caar gds-client-info))
-          ;; Otherwise, if the current buffer was displayed because
-          ;; of a Guile client trapping somewhere in its code, and
-          ;; `gds-auto-associate-last-client' allows us to associate
-          ;; with that client, do so.
-          (and gds-auto-associate-last-client
-               gds-last-touched-by))))
-    (if client
-       (gds-associate-buffer client))))         
-
-(defun gds-associate-buffer (client)
-  "Associate the current buffer with the Guile process CLIENT.
-This means that operations in this buffer that require a running Guile
-process - such as evaluation, help, completion and setting traps -
-will be sent to the Guile process whose name or connection number is
-CLIENT."
-  (interactive (list (gds-choose-client)))
-  ;; If this buffer is already associated, dissociate from its
-  ;; existing client first.
-  (if gds-client (gds-dissociate-buffer))
-  ;; Store the client number in the buffer-local variable gds-client.
-  (setq gds-client client)
-  ;; Add this buffer to the list of buffers associated with the
-  ;; client.
-  (gds-client-put client 'associated-buffers
-                 (cons (current-buffer)
-                       (gds-client-get client 'associated-buffers))))
-
-(defun gds-dissociate-buffer ()
-  "Dissociate the current buffer from any specific Guile process."
-  (interactive)
-  (if gds-client
-      (progn
-        ;; Remove this buffer from the list of buffers associated with
-        ;; the current client.
-       (gds-client-put gds-client 'associated-buffers
-                       (delq (current-buffer)
-                             (gds-client-get gds-client 'associated-buffers)))
-        ;; Reset the buffer-local variable gds-client.
-        (setq gds-client nil)
-        ;; Clear any process status indication from the modeline.
-        (setq mode-line-process nil)
-        (force-mode-line-update))))
-
-(defun gds-show-client-status (client status-string)
-  "Show a client's status in the modeline of all its associated
-buffers."
-  (let ((buffers (gds-client-get client 'associated-buffers)))
-    (while buffers
-      (if (buffer-live-p (car buffers))
-          (with-current-buffer (car buffers)
-            (setq mode-line-process status-string)
-            (force-mode-line-update)))
-      (setq buffers (cdr buffers)))))
-
-(defcustom gds-running-text ":running"
-  "*Mode line text used to show that a Guile process is \"running\".
-\"Running\" means that the process cannot currently accept any input
-from the GDS frontend in Emacs, because all of its threads are busy
-running code that GDS cannot easily interrupt."
-  :type 'string
-  :group 'gds)
-
-(defcustom gds-ready-text ":ready"
-  "*Mode line text used to show that a Guile process is \"ready\".
-\"Ready\" means that the process is ready to interact with the GDS
-frontend in Emacs, because at least one of its threads is waiting for
-GDS input."
-  :type 'string
-  :group 'gds)
-
-(defcustom gds-debug-text ":debug"
-  "*Mode line text used to show that a Guile process is \"debugging\".
-\"Debugging\" means that the process is using the GDS frontend in
-Emacs to display an error or trap so that the user can debug it."
-  :type 'string
-  :group 'gds)
-
-(defun gds-choose-client ()
-  "Ask the user to choose a GDS client process from a list."
-  (let ((table '())
-        (default nil))
-    ;; Prepare a table containing all current clients.
-    (mapcar (lambda (client-info)
-               (setq table (cons (cons (cadr (memq 'name client-info))
-                                      (car client-info))
-                                table)))
-             gds-client-info)
-    ;; Add an entry to allow the user to ask for a new process.
-    (setq table (cons (cons "Start a new Guile process" nil) table))
-    ;; Work out a good default.  If the buffer has a good value in
-    ;; gds-last-touched-by, we use that; otherwise default to starting
-    ;; a new process.
-    (setq default (or (and gds-last-touched-by
-                           (gds-client-get gds-last-touched-by 'name))
-                      (caar table)))
-    ;; Read using this table.
-    (let* ((name (completing-read "Choose a Guile process: "
-                                  table
-                                  nil
-                                  t     ; REQUIRE-MATCH
-                                  nil   ; INITIAL-INPUT
-                                  nil   ; HIST
-                                  default))
-           ;; Convert name to a client number.
-           (client (cdr (assoc name table))))
-      ;; If the user asked to start a new Guile process, do that now.
-      (or client (setq client (gds-start-utility-guile)))
-      ;; Return the chosen client ID.
-      client)))
-
-(defvar gds-last-utility-number 0
-  "Number of the last started Guile utility process.")
-
-(defun gds-start-utility-guile ()
-  "Start a new utility Guile process."
-  (setq gds-last-utility-number (+ gds-last-utility-number 1))
-  (let* ((procname (format "gds-util[%d]" gds-last-utility-number))
-         (code (format "(begin
-                          %s
-                          (use-modules (ice-9 gds-client))
-                          (run-utility))"
-                      (if gds-scheme-directory
-                          (concat "(set! %load-path (cons "
-                                  (format "%S" gds-scheme-directory)
-                                  " %load-path))")
-                        "")))
-         (proc (start-process procname
-                              (get-buffer-create procname)
-                              gds-guile-program
-                              "-q"
-                              "--debug"
-                              "-c"
-                              code)))
-    ;; Note that this process can be killed automatically on Emacs
-    ;; exit.
-    (process-kill-without-query proc)
-    ;; Set up a process filter to catch the new client's number.
-    (set-process-filter proc
-                        (lambda (proc string)
-                          (if (process-buffer proc)
-                              (with-current-buffer (process-buffer proc)
-                                (insert string)
-                               (or gds-client
-                                   (save-excursion
-                                     (goto-char (point-min))
-                                     (setq gds-client
-                                           (condition-case nil
-                                               (read (current-buffer))
-                                             (error nil)))))))))
-    ;; Accept output from the new process until we have its number.
-    (while (not (with-current-buffer (process-buffer proc) gds-client))
-      (accept-process-output proc))
-    ;; Return the new process's client number.
-    (with-current-buffer (process-buffer proc) gds-client)))
-
-;;;; Evaluating code.
-
-;; The following commands send code for evaluation through the GDS TCP
-;; connection, receive the result and any output generated through the
-;; same connection, and display the result and output to the user.
-;;
-;; For each buffer where evaluations can be requested, GDS uses the
-;; buffer-local variable `gds-client' to track which GDS client
-;; program should receive and handle that buffer's evaluations.
-
-(defun gds-module-name (start end)
-  "Determine and return the name of the module that governs the
-specified region.  The module name is returned as a list of symbols."
-  (interactive "r")                    ; why not?
-  (save-excursion
-    (goto-char start)
-    (let (module-name)
-      (while (and (not module-name)
-                 (beginning-of-defun-raw 1))
-       (if (looking-at "(define-module ")
-           (setq module-name
-                 (progn
-                   (goto-char (match-end 0))
-                   (read (current-buffer))))))
-      module-name)))
-
-(defcustom gds-emacs-buffer-port-name-prefix "Emacs buffer: "
-  "Prefix used when telling Guile the name of the port from which a
-chunk of Scheme code (to be evaluated) comes.  GDS uses this prefix,
-followed by the buffer name, in two cases: when the buffer concerned
-is not associated with a file, or if the buffer has been modified
-since last saving to its file.  In the case where the buffer is
-identical to a saved file, GDS uses the file name as the port name."
-  :type '(string)
-  :group 'gds)
-
-(defun gds-port-name (start end)
-  "Return port name for the specified region of the current buffer.
-The name will be used by Guile as the port name when evaluating that
-region's code."
-  (or (and (not (buffer-modified-p))
-          buffer-file-name)
-      (concat gds-emacs-buffer-port-name-prefix (buffer-name))))
-
-(defun gds-line-and-column (pos)
-  "Return 0-based line and column number at POS."
-  (let (line column)
-    (save-excursion
-      (goto-char pos)
-      (setq column (current-column))
-      (beginning-of-line)
-      (setq line (count-lines (point-min) (point))))
-    (cons line column)))
-
-(defun gds-eval-region (start end &optional debugp)
-  "Evaluate the current region.  If invoked with `C-u' prefix (or, in
-a program, with optional DEBUGP arg non-nil), pause and pop up the
-stack at the start of the evaluation, so that the user can single-step
-through the code."
-  (interactive "r\nP")
-  (or gds-client
-      (gds-auto-associate-buffer)
-      (call-interactively 'gds-associate-buffer))
-  (let ((module (gds-module-name start end))
-       (port-name (gds-port-name start end))
-       (lc (gds-line-and-column start)))
-    (let ((code (buffer-substring-no-properties start end)))
-      (gds-send (format "eval (region . %S) %s %S %d %d %S %s"
-                       (gds-abbreviated code)
-                       (if module (prin1-to-string module) "#f")
-                       port-name (car lc) (cdr lc)
-                       code
-                       (if debugp '(debug) '(none)))
-               gds-client))))
-
-(defun gds-eval-expression (expr &optional correlator debugp)
-  "Evaluate the supplied EXPR (a string).  If invoked with `C-u'
-prefix (or, in a program, with optional DEBUGP arg non-nil), pause and
-pop up the stack at the start of the evaluation, so that the user can
-single-step through the code."
-  (interactive "sEvaluate expression: \ni\nP")
-  (or gds-client
-      (gds-auto-associate-buffer)
-      (call-interactively 'gds-associate-buffer))
-  (set-text-properties 0 (length expr) nil expr)
-  (gds-send (format "eval (%S . %S) #f \"Emacs expression\" 0 0 %S %s"
-                   (or correlator 'expression)
-                   (gds-abbreviated expr)
-                   expr
-                   (if debugp '(debug) '(none)))
-           gds-client))
-
-(defconst gds-abbreviated-length 35)
-
-(defun gds-abbreviated (code)
-  (let ((nlpos (string-match (regexp-quote "\n") code)))
-    (while nlpos
-      (setq code
-           (if (= nlpos (- (length code) 1))
-               (substring code 0 nlpos)
-             (concat (substring code 0 nlpos)
-                     "\\n"
-                     (substring code (+ nlpos 1)))))
-      (setq nlpos (string-match (regexp-quote "\n") code))))
-  (if (> (length code) gds-abbreviated-length)
-      (concat (substring code 0 (- gds-abbreviated-length 3)) "...")
-    code))
-
-(defun gds-eval-defun (&optional debugp)
-  "Evaluate the defun (top-level form) at point.  If invoked with
-`C-u' prefix (or, in a program, with optional DEBUGP arg non-nil),
-pause and pop up the stack at the start of the evaluation, so that the
-user can single-step through the code."
-  (interactive "P")
-  (save-excursion
-   (end-of-defun)
-   (let ((end (point)))
-     (beginning-of-defun)
-     (gds-eval-region (point) end debugp))))
-
-(defun gds-eval-last-sexp (&optional debugp)
-  "Evaluate the sexp before point.  If invoked with `C-u' prefix (or,
-in a program, with optional DEBUGP arg non-nil), pause and pop up the
-stack at the start of the evaluation, so that the user can single-step
-through the code."
-  (interactive "P")
-  (gds-eval-region (save-excursion (backward-sexp) (point)) (point) debugp))
-
-;;;; Help.
-
-;; Help is implemented as a special case of evaluation, identified by
-;; the evaluation correlator 'help.
-
-(defun gds-help-symbol (sym)
-  "Get help for SYM (a Scheme symbol)."
-  (interactive
-   (let ((sym (thing-at-point 'symbol))
-        (enable-recursive-minibuffers t)
-        val)
-     (setq val (read-from-minibuffer
-               (if sym
-                   (format "Describe Guile symbol (default %s): " sym)
-                 "Describe Guile symbol: ")))
-     (list (if (zerop (length val)) sym val))))
-  (gds-eval-expression (format "(help %s)" sym) 'help))
-
-(defun gds-apropos (regex)
-  "List Guile symbols matching REGEX."
-  (interactive
-   (let ((sym (thing-at-point 'symbol))
-        (enable-recursive-minibuffers t)
-        val)
-     (setq val (read-from-minibuffer
-               (if sym
-                   (format "Guile apropos (regexp, default \"%s\"): " sym)
-                 "Guile apropos (regexp): ")))
-     (list (if (zerop (length val)) sym val))))
-  (set-text-properties 0 (length regex) nil regex)
-  (gds-eval-expression (format "(apropos %S)" regex) 'apropos))
-
-;;;; Displaying results of help and eval.
-
-(defun gds-display-results (client correlator stack-available results)
-  (let* ((helpp+bufname (cond ((eq (car correlator) 'help)
-                               '(t . "*Guile Help*"))
-                              ((eq (car correlator) 'apropos)
-                               '(t . "*Guile Apropos*"))
-                              (t
-                               '(nil . "*Guile Evaluation*"))))
-         (helpp (car helpp+bufname)))
-    (let ((buf (get-buffer-create (cdr helpp+bufname))))
-      (save-selected-window
-       (save-excursion
-         (set-buffer buf)
-         (gds-dissociate-buffer)
-         (erase-buffer)
-         (scheme-mode)
-         (insert (cdr correlator) "\n\n")
-         (while results
-           (insert (car results))
-           (or (bolp) (insert "\\\n"))
-           (if helpp
-               nil
-             (if (cadr results)
-                 (mapcar (function (lambda (value)
-                                     (insert " => " value "\n")))
-                         (cadr results))
-               (insert " => no (or unspecified) value\n"))
-             (insert "\n"))
-           (setq results (cddr results)))
-         (if stack-available
-             (let ((beg (point))
-                   (map (make-sparse-keymap)))
-               (define-key map [mouse-1] 'gds-show-last-stack)
-               (define-key map "\C-m" 'gds-show-last-stack)
-               (insert "[click here (or RET) to show error stack]")
-               (add-text-properties beg (point)
-                                    (list 'keymap map
-                                          'mouse-face 'highlight))
-               (insert "\n")
-               (add-text-properties (1- (point)) (point)
-                                    (list 'keymap map))))
-         (goto-char (point-min))
-         (gds-associate-buffer client))
-       (pop-to-buffer buf)
-       (run-hooks 'temp-buffer-show-hook)))))
-
-(defun gds-show-last-stack ()
-  "Show stack of the most recent error."
-  (interactive)
-  (or gds-client
-      (gds-auto-associate-buffer)
-      (call-interactively 'gds-associate-buffer))
-  (gds-send "debug-lazy-trap-context" gds-client))
-
-;;;; Completion.
-
-(defvar gds-completion-results nil)
-
-(defun gds-complete-symbol ()
-  "Complete the Guile symbol before point.  Returns `t' if anything
-interesting happened, `nil' if not."
-  (interactive)
-  (or gds-client
-      (gds-auto-associate-buffer)
-      (call-interactively 'gds-associate-buffer))
-  (let* ((chars (- (point) (save-excursion
-                            (while (let ((syntax (char-syntax (char-before (point)))))
-                                     (or (eq syntax ?w) (eq syntax ?_)))
-                              (forward-char -1))
-                            (point)))))
-    (if (zerop chars)
-       nil
-      (setq gds-completion-results nil)
-      (gds-send (format "complete %s"
-                       (prin1-to-string
-                        (buffer-substring-no-properties (- (point) chars)
-                                                        (point))))
-                gds-client)
-      (while (null gds-completion-results)
-       (accept-process-output gds-debug-server 0 200))
-      (cond ((eq gds-completion-results 'error)
-             (error "Internal error - please report the contents of the *Guile Evaluation* window"))
-           ((eq gds-completion-results t)
-            nil)
-           ((stringp gds-completion-results)
-            (if (<= (length gds-completion-results) chars)
-                nil
-              (insert (substring gds-completion-results chars))
-              (message "Sole completion")
-              t))
-           ((= (length gds-completion-results) 1)
-            (if (<= (length (car gds-completion-results)) chars)
-                nil
-              (insert (substring (car gds-completion-results) chars))
-              t))
-           (t
-            (with-output-to-temp-buffer "*Completions*"
-              (display-completion-list gds-completion-results))
-            t)))))
-
-;;;; Dispatcher for non-debug protocol.
-
-(defun gds-nondebug-protocol (client proc args)
-  (cond (;; (eval-results ...) - Results of evaluation.
-         (eq proc 'eval-results)
-         (gds-display-results client (car args) (cadr args) (cddr args))
-         ;; If these results indicate an error, set
-         ;; gds-completion-results to non-nil in case the error arose
-         ;; when trying to do a completion.
-         (if (eq (caar args) 'error)
-             (setq gds-completion-results 'error)))
-
-        (;; (completion-result ...) - Available completions.
-         (eq proc 'completion-result)
-         (setq gds-completion-results (or (car args) t)))
-
-       (;; (note ...) - For debugging only.
-        (eq proc 'note))
-
-        (;; (trace ...) - Tracing.
-         (eq proc 'trace)
-         (with-current-buffer (get-buffer-create "*GDS Trace*")
-           (save-excursion
-             (goto-char (point-max))
-             (or (bolp) (insert "\n"))
-             (insert "[client " (number-to-string client) "] " (car args) "\n"))))
-
-        (t
-         ;; Unexpected.
-         (error "Bad protocol: %S" form))))
-  
-;;;; Scheme mode keymap items.
-
-(define-key scheme-mode-map "\M-\C-x" 'gds-eval-defun)
-(define-key scheme-mode-map "\C-x\C-e" 'gds-eval-last-sexp)
-(define-key scheme-mode-map "\C-c\C-e" 'gds-eval-expression)
-(define-key scheme-mode-map "\C-c\C-r" 'gds-eval-region)
-(define-key scheme-mode-map "\C-hg" 'gds-help-symbol)
-(define-key scheme-mode-map "\C-h\C-g" 'gds-apropos)
-(define-key scheme-mode-map "\C-hG" 'gds-apropos)
-(define-key scheme-mode-map "\C-hS" 'gds-show-last-stack)
-(define-key scheme-mode-map "\e\t" 'gds-complete-symbol)
-
-;;;; The end!
-
-(provide 'gds-scheme)
-
-;;; gds-scheme.el ends here.