aboutsummaryrefslogtreecommitdiff
path: root/generic/proof-shell.el
diff options
context:
space:
mode:
Diffstat (limited to 'generic/proof-shell.el')
-rw-r--r--generic/proof-shell.el1901
1 files changed, 1901 insertions, 0 deletions
diff --git a/generic/proof-shell.el b/generic/proof-shell.el
new file mode 100644
index 00000000..3f2e2e6a
--- /dev/null
+++ b/generic/proof-shell.el
@@ -0,0 +1,1901 @@
+;; proof-shell.el Proof General shell mode.
+;;
+;; Copyright (C) 1994-2002 LFCS Edinburgh.
+;; Authors: David Aspinall, Yves Bertot, Healfdene Goguen,
+;; Thomas Kleymann and Dilip Sequeira
+;; License: GPL (GNU GENERAL PUBLIC LICENSE)
+;;
+;; $Id$
+;;
+
+(require 'proof-menu)
+(require 'span)
+(require 'pg-goals) ; associated output
+(require 'pg-response) ; buffers for goals/response
+
+;; Nuke some byte compiler warnings.
+
+(eval-when-compile
+ (require 'comint)
+ (require 'font-lock))
+
+
+;; FIXME:
+;; Autoloads for proof-script (added to nuke warnings,
+;; maybe should be 'official' exported functions in proof.el)
+;; This helps see interface between proof-script / proof-shell.
+;; FIXME 2: We can probably assume that proof-script is always
+;; loaded before proof-shell, so just put a require on
+;; proof-script here.
+(eval-and-compile
+ (mapcar (lambda (f)
+ (autoload f "proof-script"))
+ '(proof-goto-end-of-locked
+ proof-insert-pbp-command
+ proof-detach-queue
+ proof-locked-end
+ proof-set-queue-endpoints
+ proof-script-clear-queue-spans
+ proof-file-to-buffer
+ proof-register-possibly-new-processed-file
+ proof-restart-buffers)))
+
+;; FIXME:
+;; Some variables from proof-shell are also used, in particular,
+;; the menus. These should probably be moved out to proof-menu.
+
+;; ============================================================
+;;
+;; Internal variables used by proof shell
+;;
+
+(defvar proof-marker nil
+ "Marker in proof shell buffer pointing to previous command input.")
+
+(defvar proof-action-list nil
+ "A list of
+
+ (SPAN COMMAND ACTION)
+
+triples, which is a queue of things to do.
+See the functions `proof-start-queue' and `proof-exec-loop'.")
+
+(defvar proof-shell-silent nil
+ "A flag, non-nil if PG thinks the prover is silent.")
+
+;; not implemented
+;;(defvar proof-step-counter nil
+;; "Contains a proof step counter, which counts `outputful' steps.")
+
+
+;; We keep a record of the last output from the proof system and a
+;; flag indicating its type, as well as a previous ("delayed") to use
+;; when the end of the queue is reached or an error or interrupt
+;; occurs.
+
+;; A raw record of the last prompt from the proof system
+(defvar proof-shell-last-prompt nil
+ "A record of the last prompt seen from the proof system.
+This is the string matched by `proof-shell-annotated-prompt-regexp'.")
+
+;; A raw record of the last output from the proof system
+(defvar proof-shell-last-output nil
+ "A record of the last string seen from the proof system.")
+
+;; A flag indicating the type of thing proof-shell-last-output
+(defvar proof-shell-last-output-kind nil
+ "A symbol denoting the type of the last output string from the proof system.
+Specifically:
+
+ 'interrupt An interrupt message
+ 'error An error message
+ 'abort A proof abort message
+ 'loopback A command sent from the PA to be inserted into the script
+ 'response A response message
+ 'goals A goals (proof state) display
+ 'systemspecific Something specific to a particular system,
+ -- see `proof-shell-process-output-system-specific'
+
+The output corresponding to this will be in proof-shell-last-output.
+
+See also `proof-shell-proof-completed' for further information about
+the proof process output, when ends of proofs are spotted.
+
+This variable can be used for instance specific functions which want
+to examine proof-shell-last-output.")
+
+(defvar proof-shell-delayed-output nil
+ "A copy of proof-shell-last-output held back for processing at end of queue.")
+
+(defvar proof-shell-delayed-output-kind nil
+ "A copy of proof-shell-last-output-lind held back for processing at end of queue.")
+
+
+
+;;
+;; Implementing the process lock
+;;
+;; da: In fact, there is little need for a lock. Since Emacs Lisp
+;; code is single-threaded, a loop parsing process output cannot get
+;; pre-empted by the user trying to send more input to the process,
+;; or by the process filter trying to deal with more output.
+;; (Moreover, we can tell when the process is busy because the
+;; queue is non-empty).
+;;
+;;
+
+;;
+;; We have two functions:
+;;
+;; proof-shell-ready-prover
+;; starts proof shell, gives error if it's busy.
+;;
+;; proof-activate-scripting (in proof-script.el)
+;; calls proof-shell-ready-prover, and turns on scripting minor
+;; mode for current (scripting) buffer.
+;;
+;; Also, a new enabler predicate:
+;;
+;; proof-shell-available
+;; returns non-nil if a proof shell is active and not locked.
+;;
+;; Maybe proof-shell-ready-prover doesn't need to start the shell?
+;;
+
+;;;###autoload
+(defun proof-shell-ready-prover (&optional queuemode)
+ "Make sure the proof assistant is ready for a command.
+If QUEUEMODE is set, succeed if the proof shell is busy but
+has mode QUEUEMODE, which is a symbol or list of symbols.
+Otherwise, if the shell is busy, give an error.
+No change to current buffer or point."
+ (proof-shell-start)
+ (unless (or (not proof-shell-busy)
+ (eq queuemode proof-shell-busy)
+ (member proof-shell-busy queuemode))
+ (error "Proof Process Busy!")))
+
+;;;###autoload
+(defun proof-shell-live-buffer ()
+ "Return buffer of active proof assistant, or nil if none running."
+ (and proof-shell-buffer
+ (buffer-live-p proof-shell-buffer)
+ (comint-check-proc proof-shell-buffer)))
+
+;;;###autoload
+(defun proof-shell-available-p ()
+ "Returns non-nil if there is a proof shell active and available.
+No error messages. Useful as menu or toolbar enabler."
+ (and (proof-shell-live-buffer)
+ (not proof-shell-busy)))
+
+(defun proof-grab-lock (&optional queuemode)
+ "Grab the proof shell lock, starting the proof assistant if need be.
+Runs `proof-state-change-hook' to notify state change.
+Clears the `proof-shell-error-or-interrupt-seen' flag.
+If QUEUEMODE is supplied, set the lock to that value."
+ (proof-shell-ready-prover queuemode)
+ (setq proof-shell-error-or-interrupt-seen nil)
+ (setq proof-shell-busy (or queuemode t))
+ (run-hooks 'proof-state-change-hook))
+
+(defun proof-release-lock (&optional err-or-int)
+ "Release the proof shell lock, with error or interrupt flag ERR-OR-INT.
+Clear `proof-shell-busy', and set `proof-shell-error-or-interrupt-seen'
+to err-or-int."
+ (setq proof-shell-error-or-interrupt-seen err-or-int)
+ (setq proof-shell-busy nil))
+
+
+
+;;
+;; Starting and stopping the proof shell
+;;
+
+(defun proof-shell-start ()
+ "Initialise a shell-like buffer for a proof assistant.
+
+Also generates goal and response buffers.
+Does nothing if proof assistant is already running."
+ (interactive)
+ (unless (proof-shell-live-buffer)
+
+ ;; This should configure the mode-setting variables
+ ;; proof-mode-for-<blah> so we can set the modes below.
+ ;; <blah>=shell,goals,response. We also need to set
+ ;; proof-prog-name to start the program!
+ (run-hooks 'proof-pre-shell-start-hook)
+
+ ;; Clear some state [ fixme: should clear more? ]
+ (setq proof-included-files-list nil)
+
+ ;; Added 05/99 by Patrick L.
+ (let ((name (buffer-file-name (current-buffer))))
+ ;; FIXME : we check that the buffer corresponds to a file,
+ ;; but we do not check that it is in coq- or isa-mode
+ (if (and name proof-prog-name-guess proof-guess-command-line)
+ (setq proof-prog-name
+ (apply proof-guess-command-line (list name)))))
+
+ (if proof-prog-name-ask
+ (save-excursion
+ (setq proof-prog-name (read-shell-command "Run process: "
+ proof-prog-name))))
+ (let
+ ;; PG 3.1: Buffer names are now based simply on proof assistant
+ ;; name, not process name which was a bit lowlevel and sometimes
+ ;; ugly (coqtop, hol.unquote).
+ ((proc (downcase proof-assistant)))
+
+ (message "Starting process: %s" proof-prog-name)
+
+ ;; Starting the inferior process (asynchronous)
+ (let ((prog-name-list
+ (proof-string-to-list
+ ;; Cut in proof-rsh-command if it's non-nil and
+ ;; non whitespace. FIXME: whitespace at start
+ ;; of this string is nasty.
+ (if (and proof-rsh-command
+ (not (string-match "^[ \t]*$" proof-rsh-command)))
+ (concat proof-rsh-command " " proof-prog-name)
+ proof-prog-name)
+ ;; Split on spaces: FIXME: maybe should be whitespace.
+ " "))
+
+ (process-connection-type
+ proof-shell-process-connection-type)
+
+ ;; PG 3.5: adjust the LANG variable to remove UTF-8
+ ;; encoding that may be there. This fix is targeted at RH
+ ;; 8 which has glibc 2.2, unicode encoding by default.
+ ;; FIXME: unfortunately this fix doesn't work; it's
+ ;; not enough to alter process-environment to effect
+ ;; a locale change. In bash, LANG=x <prog> works though.
+ (process-environment
+ (if (not proof-shell-wakeup-char) ;; if specials not used,
+ process-environment ;; leave it alone
+ (if (getenv "LANG")
+ (setenv
+ "LANG"
+ (replace-in-string (getenv "LANG")
+ "\\.UTF-8" "")))
+ process-environment)))
+
+ ;; An improvement here might be to catch failure of
+ ;; make-comint and then kill off the buffer. Then we
+ ;; could add back code above for multiple shells <2> <3>, etc.
+ ;; Seems hardly worth it.
+ (apply 'make-comint (append (list proc (car prog-name-list) nil)
+ (cdr prog-name-list))))
+
+ (setq proof-shell-buffer (get-buffer (concat "*" proc "*")))
+
+ (unless (proof-shell-live-buffer)
+ ;; Give error now if shell buffer isn't live
+ ;; Solves problem of make-comint succeeding but process
+ ;; exiting immediately.
+ ;; Might still be problems here if sentinels are set.
+ (setq proof-shell-buffer nil)
+ (error "Starting process: %s..failed" proof-prog-name))
+
+ ;; FIXME: patch to go in here to clean this up
+ ;; Create the associated buffers and set buffer variables
+ (let ((goals (concat "*" proc "-goals*"))
+ (resp (concat "*" proc "-response*"))
+ (trace (concat "*" proc "-trace*"))
+ (thms (concat "*" proc "-thms*")))
+ (setq proof-goals-buffer (get-buffer-create goals))
+ (setq proof-response-buffer (get-buffer-create resp))
+ (if proof-shell-trace-output-regexp
+ (setq proof-trace-buffer (get-buffer-create trace)))
+ (if proof-shell-thms-output-regexp
+ (setq proof-thms-buffer (get-buffer-create thms)))
+ ;; Set the special-display-regexps now we have the buffer names
+ (setq proof-shell-special-display-regexp
+ (proof-regexp-alt goals resp trace thms))
+ (proof-multiple-frames-enable))
+
+ (save-excursion
+ (set-buffer proof-shell-buffer)
+
+ ;; clear output from previous sessions.
+ (erase-buffer)
+
+ ;; Disable multi-byte characters in GNU Emacs.
+ ;; We noticed that for LEGO, it otherwise converts annotations
+ ;; to characters with (non-ASCII) code around 3000 which screws
+ ;; up our conventions that annotations lie between 128 and 256.
+ ;;
+ (and (fboundp 'toggle-enable-multibyte-characters)
+ (toggle-enable-multibyte-characters -1))
+
+ ;; Initialise shell mode
+ ;; Q: should this be done every time the process is started?
+ ;; A: yes, it does the process initialization, which is a bit
+ ;; odd (would expect it to be done here, maybe).
+ (funcall proof-mode-for-shell)
+
+ ;; Check to see that the process is still going.
+ ;; Otherwise the sentinel will have killed off the
+ ;; other buffers and there's no point initialising
+ ;; them.
+ (if (proof-shell-live-buffer)
+ (progn
+ ;; Set mode for response buffer
+ (set-buffer proof-response-buffer)
+ (funcall proof-mode-for-response)
+ ;; Set mode for trace buffer
+ (proof-with-current-buffer-if-exists proof-trace-buffer
+ (funcall proof-mode-for-response))
+ ;; Set mode for goals buffer
+ (set-buffer proof-goals-buffer)
+ (and (fboundp 'toggle-enable-multibyte-characters)
+ (toggle-enable-multibyte-characters -1))
+ (funcall proof-mode-for-goals))
+ ;;
+ ;; If the process died, switch to the buffer to
+ ;; display the error messages to the user.
+ (switch-to-buffer proof-shell-buffer)
+ (error "%s process exited!" proc)))
+
+ (message "Starting %s process... done." proc))))
+
+
+;;
+;; Indicator and fake minor mode for active scripting buffer
+;;
+
+(defcustom proof-shell-active-scripting-indicator
+ (if proof-running-on-XEmacs
+ (cons (make-extent nil nil) " Scripting ")
+ " Scripting")
+ "Modeline indicator for active scripting buffer.
+If first component is extent it will automatically follow the colour
+of the queue region."
+ :type 'sexp
+ :group 'proof-general-internals)
+
+(cond
+ (proof-running-on-XEmacs
+ (if (extentp (car proof-shell-active-scripting-indicator))
+ (set-extent-properties
+ (car proof-shell-active-scripting-indicator)
+ '(face proof-locked-face)))))
+
+(unless
+ (assq 'proof-active-buffer-fake-minor-mode minor-mode-alist)
+ (setq minor-mode-alist
+ (append minor-mode-alist
+ (list
+ (list
+ 'proof-active-buffer-fake-minor-mode
+ proof-shell-active-scripting-indicator)))))
+
+
+;;
+;; Shutting down proof shell and associated buffers
+;;
+
+;; Hooks here are handy for liaising with prover config stuff.
+
+(defvar proof-shell-kill-function-hooks nil
+ "Functions run from proof-shell-kill-function.")
+
+(defun proof-shell-kill-function ()
+ "Function run when a proof-shell buffer is killed.
+Attempt to shut down the proof process nicely and
+clear up all the locked regions and state variables.
+Value for `kill-buffer-hook' in shell buffer.
+Also called by `proof-shell-bail-out' if the process is
+exited by hand (or exits by itself)."
+ (let* ((alive (comint-check-proc (current-buffer)))
+ (proc (get-buffer-process (current-buffer)))
+ (bufname (buffer-name)))
+ (message "%s, cleaning up and exiting..." bufname)
+ (let ((inhibit-quit t) ; disable C-g for now
+ timeout-id)
+ (sit-for 0) ; redisplay [does it work?]
+ (if alive ; process still there
+ (progn
+ (catch 'exited
+ (set-process-sentinel proc
+ (lambda (p m) (throw 'exited t)))
+ ;; First, turn off scripting in any active scripting
+ ;; buffer. (This helps support persistent sessions with
+ ;; Isabelle, for example, by making sure that no file is
+ ;; partly processed when exiting, and registering completed
+ ;; files).
+ (proof-deactivate-scripting-auto)
+ ;; FIXME: if the shell is busy now, we should wait
+ ;; for a while (in case deactivate causes processing)
+ ;; and the send an interrupt.
+
+ ;; Second, we try to shut down the proof process
+ ;; politely. Do this before deleting other buffers,
+ ;; etc, so that any closing down processing works okay.
+ (if proof-shell-quit-cmd
+ (comint-send-string proc
+ (concat proof-shell-quit-cmd "\n"))
+ (comint-send-eof))
+ ;; Wait a while for it to die before killing
+ ;; it off more rudely. In XEmacs, accept-process-output
+ ;; or sit-for will run process sentinels if a process
+ ;; changes state.
+ ;; In FSF I've no idea how to get the process sentinel
+ ;; to run outside the top-level loop.
+ ;; So put an ugly timeout and busy wait here instead
+ ;; of simply (accept-process-output nil 10).
+ (setq timeout-id
+ (add-timeout
+ proof-shell-quit-timeout
+ (lambda (&rest args)
+ (if (comint-check-proc (current-buffer))
+ (kill-process (get-buffer-process
+ (current-buffer))))
+ (throw 'exited t)) nil))
+ (while (comint-check-proc (current-buffer))
+ ;; Perhaps XEmacs hangs too, lets try both wait forms.
+ (accept-process-output nil 1)
+ (sit-for 1)))
+ ;; Disable timeout and sentinel in case one or
+ ;; other hasn't signalled yet, but we're here anyway.
+ (disable-timeout timeout-id)
+ ;; FIXME: this was added to fix 'No catch for exited tag'
+ ;; problem, but it's done later below anyway?
+ (set-process-sentinel proc nil)))
+ (if (comint-check-proc (current-buffer))
+ (proof-debug
+ "Error in proof-shell-kill-function: process still lives!"))
+ ;; For FSF Emacs, proc may be nil if killed already.
+ (if proc (set-process-sentinel proc nil))
+ ;; Restart all scripting buffers
+ (proof-script-remove-all-spans-and-deactivate)
+ ;; Clear state
+ (proof-shell-clear-state)
+ ;; Run hooks
+ (run-hooks 'proof-shell-kill-function-hooks)
+ ;; Kill buffers associated with shell buffer
+ (let ((proof-shell-buffer nil)) ;; fool kill buffer hooks
+ (dolist (buf '(proof-goals-buffer proof-response-buffer
+ proof-trace-buffer))
+ (if (buffer-live-p (eval buf))
+ (progn
+ (kill-buffer (eval buf))
+ (set buf nil)))))
+ (message "%s exited." bufname))))
+
+(defun proof-shell-clear-state ()
+ "Clear internal state of proof shell."
+ (setq proof-action-list nil
+ proof-included-files-list nil
+ proof-shell-busy nil
+ proof-shell-proof-completed nil
+ proof-nesting-depth 0
+ proof-shell-error-or-interrupt-seen nil
+ proof-shell-silent nil
+ proof-shell-last-output nil
+ proof-shell-last-output-kind nil
+ proof-shell-last-prompt nil
+ proof-shell-delayed-output nil
+ proof-shell-delayed-output-kind nil))
+
+(defun proof-shell-exit ()
+ "Query the user and exit the proof process.
+
+This simply kills the `proof-shell-buffer' relying on the hook function
+`proof-shell-kill-function' to do the hard work."
+ (interactive)
+ (if (buffer-live-p proof-shell-buffer)
+ (if (yes-or-no-p (format "Exit %s process? " proof-assistant))
+ (progn (kill-buffer proof-shell-buffer)
+ (setq proof-shell-buffer nil))
+ (error "No proof shell buffer to kill!"))))
+
+(defun proof-shell-bail-out (process event)
+ "Value for the process sentinel for the proof assistant process.
+If the proof assistant dies, run proof-shell-kill-function to
+cleanup and remove the associated buffers. The shell buffer is
+left around so the user may discover what killed the process."
+ (message "Process %s %s, shutting down scripting..." process event)
+ (proof-shell-kill-function)
+ (message "Process %s %s, shutting down scripting...done." process event))
+
+(defun proof-shell-restart ()
+ "Clear script buffers and send `proof-shell-restart-cmd'.
+All locked regions are cleared and the active scripting buffer
+deactivated.
+
+If the proof shell is busy, an interrupt is sent with
+`proof-interrupt-process' and we wait until the process is ready.
+
+The restart command should re-synchronize Proof General with the proof
+assistant, without actually exiting and restarting the proof assistant
+process.
+
+It is up to the proof assistant how much context is cleared: for
+example, theories already loaded may be \"cached\" in some way,
+so that loading them the next time round only performs a re-linking
+operation, not full re-processing. (One way of caching is via
+object files, used by Lego and Coq)."
+ (interactive)
+ (if proof-shell-busy
+ (progn
+ (proof-interrupt-process)
+ (proof-shell-wait)))
+ (if (not (proof-shell-live-buffer))
+ ;; If shell not running, start one now.
+ ;; (Behaviour suggested by Robert Schneck)
+ (proof-shell-start)
+ ;; Otherwise, clear all context for running prover
+ (proof-script-remove-all-spans-and-deactivate)
+ (proof-shell-clear-state)
+ (if (and (buffer-live-p proof-shell-buffer)
+ proof-shell-restart-cmd)
+ (proof-shell-invisible-command
+ proof-shell-restart-cmd))))
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Response buffer processing
+;;
+
+(defvar proof-shell-no-response-display nil
+ "A setting to disable displays in the response buffer.")
+
+(defvar proof-shell-urgent-message-marker nil
+ "Marker in proof shell buffer pointing to end of last urgent message.")
+
+(defvar proof-shell-urgent-message-scanner nil
+ "Marker in proof shell buffer pointing to scan start for urgent messages.")
+
+
+(defun proof-shell-handle-output (start-regexp append-face)
+ "Displays output from process in `proof-response-buffer'.
+The output is taken from `proof-shell-last-output' and begins
+the first match for START-REGEXP.
+If START-REGEXP is nil, begin from the start of the output for
+this command.
+This is a subroutine of `proof-shell-handle-error'."
+ (let (start end string)
+ (save-excursion
+ (set-buffer proof-shell-buffer)
+ (goto-char (point-max))
+ (setq end (re-search-backward
+ ;;end-regexp was always proof-shell-annotated-prompt-regexp
+ proof-shell-annotated-prompt-regexp))
+ (goto-char (marker-position proof-marker))
+ (setq start (if start-regexp
+ (- (re-search-forward start-regexp)
+ (length (match-string 0)))
+ (point)))
+ (setq string (buffer-substring start end))
+ ;; FIXME: if the shell buffer is x-symbol minor mode,
+ ;; this string can contain X-Symbol characters, which
+ ;; is not suitable for processing with proof-fontify-region.
+ (unless pg-use-specials-for-fontify
+ (setq string
+ (pg-assoc-strip-subterm-markup string)))
+ ;; Erase if need be, and erase next time round too.
+ (proof-shell-maybe-erase-response t nil)
+ (pg-response-display-with-face string append-face))))
+
+ ;; We used to fetch the output from proof-shell-buffer. I'm not sure what
+ ;; difference it makes, except that it's difficult to find the actual
+ ;; output over there and that job has already been done in
+ ;; proof-shell-filter. -stef
+ ;; da: Not quite, unfortunately: proof-shell-last-output had
+ ;; special characters stripped.
+ ;; This breaks Isabelle, for example, because special
+ ;; characters have been stripped from proof-shell-last-output,
+ ;; but start-regexp may contain them.
+ ;; For now, test _not_ removing specials (see proof-shell-process-output)
+; ;; stef's version:
+; (let ((string proof-shell-last-output))
+; ;; Strip off start-regexp --- if it matches
+; ;; FIXME: if it doesn't we shouldn't be called, but something
+; ;; odd happens here now, so add a safety check.
+; (if (and start-regexp (string-match start-regexp string))
+; (setq string (substring string (match-beginning 0))))
+; ;; FIXME: if the shell buffer is x-symbol minor mode,
+; ;; this string can contain X-Symbol characters, which
+; ;; is not suitable for processing with proof-fontify-region.
+; (unless pg-use-specials-for-fontify
+; (setq string
+; (pg-assoc-strip-subterm-markup string)))
+; ;; Erase if need be, and erase next time round too.
+; (proof-shell-maybe-erase-response t nil)
+; (pg-response-display-with-face string append-face)))
+
+
+(defun proof-shell-handle-delayed-output ()
+ "Display delayed output.
+This function handles the cases of proof-shell-delayed-output-kind which
+are not dealt with eagerly during script processing, namely
+'abort, 'response, 'goals outputs."
+ ;; NB: this function is important even when called with an empty
+ ;; delayed output, since it serves to clear buffers.
+
+ ;; FIXME: there's a display anomaly here with Isar/shrink mode which
+ ;; is tricky to find. Error message causes an empty delayed output
+ ;; for goals buffer to split main window in two rather than
+ ;; shrinking to fit. Running through the debugger the right
+ ;; thing happens (display in a correctly sized window). Somewhere
+ ;; there is a spurious match not protected too: C-c C-n gives
+ (cond
+ ;; Response buffer output
+ ((eq proof-shell-delayed-output-kind 'abort)
+ ;; "Aborted." why??
+ (pg-response-display proof-shell-delayed-output))
+ ((eq proof-shell-delayed-output-kind 'response)
+ (unless proof-shell-no-response-display
+ (pg-response-display proof-shell-delayed-output)))
+ ;; Goals buffer output
+ ((eq proof-shell-delayed-output-kind 'goals)
+ (pg-goals-display proof-shell-delayed-output))
+ ;; Ignore other cases
+ )
+ (run-hooks 'proof-shell-handle-delayed-output-hook))
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Processing error output
+;;
+
+(defvar proof-shell-ignore-errors nil
+ "If non-nil, be quiet about errors from the prover.
+An internal setting used in `proof-shell-invisible-cmd-get-result'.")
+
+;; FIXME: combine next two functions?
+
+(defun proof-shell-handle-error (cmd)
+ "React on an error message triggered by the prover.
+We first flush unprocessed goals to the goals buffer.
+The error message is displayed in the response buffer.
+Then we call `proof-shell-error-or-interrupt-action', which see."
+ ;; [FIXME: Why not flush goals also for interrupts?]
+ ;; Flush goals or response buffer (from some last successful proof step)
+ (unless proof-shell-ignore-errors ;; quiet
+ (save-excursion
+ (proof-shell-handle-delayed-output))
+ (proof-shell-handle-output
+ (if proof-shell-truncate-before-error proof-shell-error-regexp)
+ 'proof-error-face)
+ (proof-display-and-keep-buffer proof-response-buffer))
+ (proof-shell-error-or-interrupt-action 'error))
+
+(defun proof-shell-handle-interrupt ()
+ "React on an interrupt message from the prover.
+Runs `proof-shell-error-or-interrupt-action'."
+ (unless proof-shell-ignore-errors ;; quiet
+ (proof-shell-maybe-erase-response t t t) ; force cleaned now & next
+ (proof-shell-handle-output
+ (if proof-shell-truncate-before-error proof-shell-interrupt-regexp)
+ 'proof-error-face)
+; (proof-display-and-keep-buffer proof-response-buffer)
+ (proof-warning
+ "Interrupt: script management may be in an inconsistent state
+ (but it's probably okay)"))
+ (proof-shell-error-or-interrupt-action 'interrupt))
+
+(defun proof-shell-error-or-interrupt-action (&optional err-or-int)
+ "General action when an error or interrupt message appears from prover.
+A subroutine for `proof-shell-handle-interrupt' and `proof-shell-handle-error'.
+
+We sound a beep, clear queue spans and `proof-action-list', and set the flag
+`proof-shell-error-or-interrupt-seen' to the ERR-OR-INT argument.
+Then we call `proof-shell-handle-error-or-interrupt-hook'."
+ (save-excursion ;; for safety.
+ (unless proof-shell-ignore-errors ;; quiet
+ (beep))
+ (proof-script-clear-queue-spans)
+ (setq proof-action-list nil)
+ (proof-release-lock err-or-int)
+ ;; Make sure that prover is outputting data now.
+ ;; FIXME: put something here!
+ ;; New: this is called for interrupts too.
+ (run-hooks 'proof-shell-handle-error-or-interrupt-hook)))
+
+(defun proof-goals-pos (span maparg)
+ "Given a span, return the start of it if corresponds to a goal, nil otherwise."
+ (and (eq 'goal (car (span-property span 'proof-top-element)))
+ (span-start span)))
+
+(defun proof-pbp-focus-on-first-goal ()
+ "If the `proof-goals-buffer' contains goals, bring the first one into view.
+This is a hook function for proof-shell-handle-delayed-output-hook."
+ (and proof-running-on-XEmacs ;; FIXME: map-extents exists on Emacs21
+ (fboundp 'map-extents) ;; but with different typing
+ (let
+ ((pos (map-extents 'proof-goals-pos proof-goals-buffer
+ nil nil nil nil 'proof-top-element)))
+ (and pos (set-window-point
+ (get-buffer-window proof-goals-buffer t) pos)))))
+
+
+(defsubst proof-shell-string-match-safe (regexp string)
+ "Like string-match except returns nil if REGEXP is nil."
+ (and regexp (string-match regexp string)))
+
+
+(defun proof-shell-process-output (cmd string)
+ "Process shell output (resulting from CMD) by matching on STRING.
+CMD is the first part of the `proof-action-list' that lead to this
+output. The result of this function is a pair (SYMBOL NEWSTRING).
+
+Here is where we recognizes interrupts, abortions of proofs, errors,
+completions of proofs, and proof step hints (proof by pointing results).
+They are checked for in this order, using
+
+ `proof-shell-interrupt-regexp'
+ `proof-shell-error-regexp'
+ `proof-shell-abort-goal-regexp'
+ `proof-shell-proof-completed-regexp'
+ `proof-shell-result-start'
+
+All other output from the proof engine will be reported to the user in
+the response buffer by setting `proof-shell-delayed-output' to a cons
+cell of ('insert . TEXT) where TEXT is the text string to be inserted.
+
+Order of testing is: interrupt, abort, error, completion.
+
+To extend this function, set `proof-shell-process-output-system-specific'.
+
+The \"aborted\" case is intended for killing off an open proof during
+retraction. Typically it matches the message caused by a
+`proof-kill-goal-command'. It simply inserts the word \"Aborted\" into
+the response buffer. So it is expected to be the result of a
+retraction, rather than the indication that one should be made.
+
+This function sets `proof-shell-last-output' and `proof-shell-last-output-kind',
+which see."
+ ;; Keep a record of the last message from the prover
+ (setq proof-shell-last-output string)
+ (or
+ ;; First check for error, interrupt, abort, proof completed
+ (cond
+ ((proof-shell-string-match-safe proof-shell-interrupt-regexp string)
+ (setq proof-shell-last-output-kind 'interrupt))
+
+ ((proof-shell-string-match-safe proof-shell-error-regexp string)
+ ;; FIXME: is the next setting correct or even needed?
+ ;; da: removed in pre3.5 test after Stefan's change to
+ ;; simplify proof-shell-handle-output.
+ ;;(setq proof-shell-last-output
+ ;; (pg-assoc-strip-subterm-markup
+ ;; (substring string (match-beginning 0))))
+ (setq proof-shell-last-output-kind 'error))
+
+ ((proof-shell-string-match-safe proof-shell-abort-goal-regexp string)
+ (proof-clean-buffer proof-goals-buffer)
+ (setq proof-shell-last-output-kind 'abort))
+
+ ((proof-shell-string-match-safe proof-shell-proof-completed-regexp string)
+ ;; In case no goals display
+ (proof-clean-buffer proof-goals-buffer)
+ ;; counter of commands since proof complete.
+ (setq proof-shell-proof-completed 0)
+ ;; But! We carry on matching below for goals output, so that
+ ;; provers may include proof completed message as part of
+ ;; goals message (Isabelle, HOL) or not (LEGO, Coq).
+ nil))
+
+ ;; Check for remaining things
+ (cond
+ ((proof-shell-string-match-safe proof-shell-start-goals-regexp string)
+ (let ((start (match-end 0))
+ end)
+ ;; Find the last goal string in the output
+ (while (string-match proof-shell-start-goals-regexp string start)
+ (setq start (match-end 0)))
+ ;; Convention: provers with special characters appearing in
+ ;; proof-start-goals-regexp don't include the match in their
+ ;; goals output. Others do.
+ ;; (Improvement to examine proof-start-goals-regexp suggested
+ ;; for Coq by Robert Schneck because Coq has specials but
+ ;; doesn't markup goals output specially).
+ (unless (and
+ pg-subterm-first-special-char
+ (not (string-equal
+ proof-shell-start-goals-regexp
+ (pg-assoc-strip-subterm-markup
+ proof-shell-start-goals-regexp))))
+ (setq start (match-beginning 0)))
+ (setq end (if proof-shell-end-goals-regexp
+ (string-match proof-shell-end-goals-regexp string start)
+ (length string)))
+ (setq proof-shell-last-output (substring string start end))
+ (setq proof-shell-last-output-kind 'goals)))
+
+ ;; Test for a proof by pointing command hint
+ ((proof-shell-string-match-safe proof-shell-result-start string)
+ (let (start end)
+ (setq start (+ 1 (match-end 0)))
+ (string-match proof-shell-result-end string)
+ (setq end (- (match-beginning 0) 1))
+ ;; Only record the loopback command in the last output message
+ (setq proof-shell-last-output (substring string start end)))
+ (setq proof-shell-last-output-kind 'loopback))
+
+ ;; Hook to tailor proof-shell-process-output to a specific proof
+ ;; system, in the case that all the above matches fail.
+ ((and proof-shell-process-output-system-specific
+ (funcall (car proof-shell-process-output-system-specific)
+ cmd string))
+ (setq proof-shell-last-output-kind 'systemspecific)
+ (funcall (cdr proof-shell-process-output-system-specific)
+ cmd string))
+
+ ;; Finally, any other output will appear as a response.
+ (t
+ (setq proof-shell-last-output-kind 'response)))))
+
+
+;;
+;; Low-level commands for shell communication
+;;
+
+(defvar proof-shell-insert-space-fudge
+ (cond
+ ((string-match "21.*XEmacs" emacs-version) " ")
+ (proof-running-on-XEmacs "")
+ (t " "))
+ "String to insert after setting proof marker to prevent it moving.
+Allows for a difference between different versions of comint across
+different Emacs versions.")
+
+(defun proof-shell-insert (string action)
+ "Insert STRING at the end of the proof shell, call `comint-send-input'.
+
+First call `proof-shell-insert-hook'. The argument ACTION may be
+examined by the hook to determine how to process the STRING variable.
+
+Then strip STRING of carriage returns before inserting it and updating
+`proof-marker' to point to the end of the newly inserted text.
+
+Do not use this function directly, or output will be lost. It is only
+used in `proof-append-alist' when we start processing a queue, and in
+`proof-shell-exec-loop', to process the next item."
+ (save-excursion
+ (set-buffer proof-shell-buffer)
+ (goto-char (point-max))
+
+ ;; See docstring for this hook: it allows munging of `string'
+ ;; amongst other hacks.
+ (run-hooks 'proof-shell-insert-hook)
+
+ ;; Now we replace CRs from string with spaces. This is done
+ ;; in case CRs in the input strip produce spurious prompts.
+
+ (if proof-shell-strip-crs-from-input
+ (setq string (subst-char-in-string ?\n ?\ string)))
+
+ (insert string)
+
+ ;; Advance the proof-marker, if synchronization has been gained.
+ ;; A null marker position indicates that synchronization is not
+ ;; yet gained. (NB: Any output received before syncrhonization is
+ ;; gained is ignored!)
+ (unless (null (marker-position proof-marker))
+ (set-marker proof-marker (point)))
+
+ ;; FIXME: consider as possible improvement.
+ ;; (set-marker proof-shell-urgent-message-marker (point))
+ ;; (set-marker proof-shell-urgent-message-scanner (point))
+
+ ;; FIXME da: this space fudge is actually a visible hack:
+ ;; the response string begins with a space and a newline.
+ ;; It was needed to work around differences in Emacs versions.
+ (insert proof-shell-insert-space-fudge)
+ (comint-send-input)))
+
+;; OLD BUGGY CODE here
+;; Left in as a warning of a race condition.
+;; It seems that comint-send-input can lead to the
+;; output filter running before it returns, so that
+;; the set-marker call below is executed too late.
+;; The result is that the filter deals with
+;; the previous portion of output instead of the
+;; most recent one!
+;;
+;; xemacs and FSF emacs have different semantics for what happens when
+;; shell input is sent next to a marker
+;; the following code accommodates both definitions
+; (let ((inserted (point)))
+; (comint-send-input)
+; (set-marker proof-marker inserted))))
+
+
+;; ============================================================
+;;
+;; Code for manipulating proof queue
+;;
+
+
+(defun proof-shell-command-queue-item (cmd callback)
+ "Return the proof queue entry needed to run CMD with callback CALLBACK."
+ (list nil cmd callback))
+
+
+(defun proof-shell-set-silent (span)
+ "Callback for `proof-shell-start-silent'.
+Very simple function but it's important to give it a name to help
+track what happens in the proof queue."
+ (setq proof-shell-silent t))
+
+(defun proof-shell-start-silent-item ()
+ "Return proof queue entry for starting silent mode."
+ (proof-shell-command-queue-item
+ proof-shell-start-silent-cmd
+ 'proof-shell-set-silent))
+
+(defun proof-shell-clear-silent (span)
+ "Callback for `proof-shell-stop-silent'.
+Very simple function but it's important to give it a name to help
+track what happens in the proof queue."
+ (setq proof-shell-silent nil))
+
+(defun proof-shell-stop-silent-item ()
+ "Return proof queue entry for stopping silent mode."
+ (proof-shell-command-queue-item
+ proof-shell-stop-silent-cmd
+ 'proof-shell-clear-silent))
+
+;; FIXME: could be macro for efficiency improvement in avoiding calculating num
+(defun proof-shell-should-be-silent (num)
+ "Return non-nil if we must switch to silent mode, adding NUM entries to queue."
+ (if proof-shell-start-silent-cmd
+ (or proof-shell-silent ; already
+ ;; NB: there is some question here over counting the
+ ;; proof-action-list, since it could itself contain
+ ;; silent-on/off commands which should be ignored for
+ ;; counting, really... also makes cutting lists for advanced
+ ;; queue processing more tricky.
+ (>= (+ num (length proof-action-list))
+ proof-shell-silent-threshold))))
+
+
+(defun proof-append-alist (alist &optional queuemode)
+ "Chop off the vacuous prefix of the command queue ALIST and queue it.
+For each `proof-no-command' item at the head of the list, invoke its
+callback and remove it from the list.
+
+Append the result onto `proof-action-list', and if the proof
+shell isn't already busy, grab the lock with QUEUEMODE and
+start processing the queue.
+
+If the proof shell is busy when this function is called,
+then QUEUEMODE must match the mode of the queue currently
+being processed."
+ (let (item)
+ ;; FIXME: may be wrong time to invoke callbacks for no-op commands,
+ ;; if the queue is not empty.
+ (while (and alist (string=
+ (nth 1 (setq item (car alist)))
+ proof-no-command))
+ (funcall (nth 2 item) (car item))
+ (setq alist (cdr alist)))
+ (if alist
+ (if proof-action-list
+ (progn
+ ;; internal check: correct queuemode in force if busy
+ ;; (should have proof-action-list<>nil -> busy)
+ (and proof-shell-busy queuemode
+ (unless (eq proof-shell-busy queuemode)
+ (proof-debug "proof-append-alist: wrong queuemode detected for busy shell")
+ (assert (eq proof-shell-busy queuemode))))
+ ;; See if we should make prover quieten down
+ (if (proof-shell-should-be-silent (length alist))
+ ;; Make it ASAP, which is just after the current
+ ;; command (head of queue).
+ (setq proof-action-list
+ (cons (car proof-action-list)
+ (cons (proof-shell-start-silent-item)
+ (cdr proof-action-list)))))
+ ;; append to the current queue
+ (setq proof-action-list
+ (nconc proof-action-list alist)))
+ ;; start processing a new queue
+ (progn
+ (proof-grab-lock queuemode)
+ (setq proof-shell-last-output-kind nil)
+ (if (proof-shell-should-be-silent (length alist))
+ ;;
+ (progn
+ (setq proof-action-list
+ (list (proof-shell-start-silent-item)))
+ (setq item (car proof-action-list))))
+ (setq proof-action-list
+ (nconc proof-action-list alist))
+ ;; Really start things going here
+ (proof-shell-insert (nth 1 item) (nth 2 item)))))))
+
+;;;###autoload
+(defun proof-start-queue (start end alist)
+ "Begin processing a queue of commands in ALIST.
+If START is non-nil, START and END are buffer positions in the
+active scripting buffer for the queue region.
+
+This function calls `proof-append-alist'."
+ (if start
+ (proof-set-queue-endpoints start end))
+ (proof-append-alist alist))
+
+;;;###autoload
+(defun proof-extend-queue (end alist)
+ "Extend the current queue with commands in ALIST, queue end END.
+To make sense, the commands should correspond to processing actions
+for processing a region from (buffer-queue-or-locked-end) to END.
+The queue mode is set to 'advancing"
+ (proof-set-queue-endpoints (proof-unprocessed-begin) end)
+ (proof-append-alist alist 'advancing))
+
+
+
+
+(defun proof-shell-exec-loop ()
+ "Process the `proof-action-list'.
+
+`proof-action-list' contains a list of (SPAN COMMAND ACTION) triples.
+
+If this function is called with a non-empty proof-action-list, the
+head of the list is the previously executed command which succeeded.
+We execute (ACTION SPAN) on the first item, then (ACTION SPAN) on any
+following items which have `proof-no-command' as their cmd components.
+If a there is a next command after that, send it to the process. If
+the action list becomes empty, unlock the process and remove the queue
+region.
+
+The return value is non-nil if the action list is now empty."
+ ;; The loop looks like: Execute the
+ ;; command, and if it's successful, do action on span. If the
+ ;; command's not successful, we bounce the rest of the queue and do
+ ;; some error processing.
+
+ (unless (not proof-action-list) ; exit immediately if finished.
+ (save-excursion
+ ;; Switch to active scripting buffer if there is one.
+ (if proof-script-buffer
+ (set-buffer proof-script-buffer))
+ (let ((item (car proof-action-list)))
+ ;; Do (action span) on first item in list
+ (funcall (nth 2 item) (car item))
+ (setq proof-action-list (cdr proof-action-list))
+ ;; Process following items in list with the form
+ ;; ("COMMENT" cmd) by calling (cmd "COMMENT")
+ (while (and proof-action-list
+ (string=
+ (nth 1 (setq item (car proof-action-list)))
+ proof-no-command))
+ ;; Do (action span) on comments
+ (funcall (nth 2 item) (car item))
+ (setq proof-action-list (cdr proof-action-list)))
+ ;; If action list is empty or has a single element,
+ ;; we want to make sure prover is being noisy.
+ (if (and proof-shell-silent
+ (or (null proof-action-list) ; possible?
+ (null (cdr proof-action-list))))
+ (progn
+ ;; Stick the quieten command onto the queue
+ (setq proof-action-list
+ (cons (proof-shell-stop-silent-item)
+ proof-action-list))
+ (setq item (car proof-action-list))))
+ ;; If action list is empty now, release the process lock
+ (if (null proof-action-list)
+ (progn (proof-release-lock)
+ (proof-detach-queue)
+ ;; indicate finished
+ t)
+ ;; Otherwise, send the next command to the process.
+ (proof-shell-insert (nth 1 item) (nth 2 item))
+ ;; indicate not finished
+ nil)))))
+
+(defun proof-shell-insert-loopback-cmd (cmd)
+ "Insert command sequence triggered by the proof process
+at the end of locked region (after inserting a newline and indenting).
+Assume proof-script-buffer is active."
+ (unless (string-match "^\\s-*$" cmd) ; FIXME: assumes cmd is single line
+ (save-excursion
+ (set-buffer proof-script-buffer)
+ (let (span)
+ (proof-goto-end-of-locked)
+ ;; Fix 16.11.99. This attempts to indent current line which can
+ ;; be read-only.
+ ;; (newline-and-indent)
+ (let ((proof-one-command-per-line t)) ; because pbp several commands
+ (proof-script-new-command-advance))
+ (insert cmd)
+ ;; Fix 16.11.99. Comment in todo suggested old code below
+ ;; assumed the pbp command would succeed, but it seems fine?
+ ;; But this action belongs in the proof script code.
+ ;; NB: difference between ordinary commands and pbp is that
+ ;; pbp can return *several* commands, that are treated as
+ ;; a unit, i.e. sent to the proof assistant together.
+ ;; FIXME da: this seems very similar to proof-insert-pbp-command
+ ;; in proof-script.el. Should be unified, I suspect.
+ (setq span (make-span (proof-locked-end) (point)))
+ (set-span-property span 'type 'pbp)
+ (set-span-property span 'cmd cmd)
+ (proof-set-queue-endpoints (proof-locked-end) (point))
+ (setq proof-action-list
+ (cons (car proof-action-list)
+ (cons (list span cmd 'proof-done-advancing)
+ (cdr proof-action-list))))))))
+
+;; da: first note of this sentence is false!
+;; ******** NB **********
+;; While we're using pty communication, this code is OK, since all
+;; eager annotations are one line long, and we get input a line at a
+;; time. If we go over to piped communication, it will break.
+
+(defun proof-shell-message (str)
+ "Output STR in minibuffer."
+ ;; %s is used below to escape characters special to
+ ;; 'format' which could appear in STR.
+ (message "%s" (concat "[" proof-assistant "] " str)))
+
+(defun proof-shell-process-urgent-message (message)
+ "Analyse urgent MESSAGE for various cases.
+Cases are: included file, retracted file, cleared response buffer,
+variable setting or dependency list.
+If none of these apply, display MESSAGE.
+
+MESSAGE should be a string annotated with
+`proof-shell-eager-annotation-start', `proof-shell-eager-annotation-end'."
+ (cond
+ ;; CASE processing file: the prover is reading a file directly
+ ;;
+ ;; FIXME da: this interface is quite restrictive: might be
+ ;; useful for one message to name several files, or include
+ ;; an instruction to purge the included files list, rather
+ ;; than erasing everything and re-adding it.
+ ;; Contrast retraction interface: there we compute whole
+ ;; new list.
+ ;; (Come to think of it, maybe we could unify the two
+ ;; cases: automatically find removed files and added files
+ ;; between two versions of proof-included-files-list)
+ ((and proof-shell-process-file
+ (string-match (car proof-shell-process-file) message))
+ (let
+ ((file (funcall (cdr proof-shell-process-file) message)))
+ ;; Special hack: empty string indicates current scripting buffer
+ ;; (not used anywhere presently?)
+ ;; (if (and proof-script-buffer (string= file ""))
+ ;; (setq file (buffer-file-name proof-script-buffer)))
+ ;; YES! It *was* used by LEGO.
+ ;; Now we avoid this in favour of altering the processed
+ ;; files list when the current scripting buffer changes,
+ ;; inside Proof General. Attempt to harmonize behaviour
+ ;; with Isabelle. Seems wrong to add "example.l" to
+ ;; list of processed files if it's only partly processed?
+ ;; (On the other hand, for lego, it may have declared a
+ ;; module heading, which is probably Lego's standard
+ ;; for what a processed file actually is).
+ (if (and file (not (string= file "")))
+ (proof-register-possibly-new-processed-file file))))
+
+ ;; CASE retract: the prover is retracting across files
+ ((and proof-shell-retract-files-regexp
+ (string-match proof-shell-retract-files-regexp message))
+ (let ((current-included proof-included-files-list))
+ (setq proof-included-files-list
+ (funcall proof-shell-compute-new-files-list message))
+ (let
+ ;; Previously active scripting buffer
+ ((scrbuf proof-script-buffer))
+ ;; NB: we assume that no new buffers are *added* by
+ ;; the proof-shell-compute-new-files-list
+ (proof-restart-buffers
+ (proof-files-to-buffers
+ (set-difference current-included
+ proof-included-files-list)))
+ (cond
+ ;; Do nothing if there was no active scripting buffer
+ ((not scrbuf))
+ ;; Do nothing if active scripting buffer hasn't changed
+ ;; (NB: it might have been nuked)
+ ((eq scrbuf proof-script-buffer))
+ ;; FIXME da: I've forgotten the next condition was needed?
+ ;;
+ ;; In fact, it breaks the case that the current scripting
+ ;; buffer should be deactivated if the prover retracts it.
+ ;; When scripting begins again in the buffer, other
+ ;; files may have to be re-read which may not happen unless
+ ;; scripting is properly de-activated.
+ ;;
+ ;; Otherwise, active scripting buffer has been retracted.
+ ;; Add it back!! Why? Presumably because code likes to
+ ;; have an active scripting buffer??
+ (t
+ ;; FIXME da: want to test disabling currently active scripting
+ ;; buffer. Unfortunately this doesn't work with current
+ ;; use of proof-script-buffer-list: always have to have
+ ;; *some* scripting buffer active. ARGHH!
+ ;; FIXME da: test not having this add-back. Then
+ ;; scripting buffer may change wrongly and randomly
+ ;; to some other buffer, without running change functions.
+ ;;
+ ;; FIXME da: test setting this to nil, scary!
+ (setq proof-script-buffer nil)
+ ;;(setq proof-script-buffer-list
+ ;; (cons scrbuf proof-script-buffer-list))
+ ;; (save-excursion
+ ;; (set-buffer scrbuf)
+ ;; (proof-init-segmentation)))))
+ )))
+ ))
+
+ ;; CASE clear response: prover asks PG to clear response buffer
+ ((and proof-shell-clear-response-regexp
+ (string-match proof-shell-clear-response-regexp message)
+ proof-response-buffer)
+ ;; Erase response buffer and possibly its windows.
+ (proof-shell-maybe-erase-response nil t t))
+
+ ;; CASE clear goals: prover asks PG to clear goals buffer
+ ((and proof-shell-clear-goals-regexp
+ (string-match proof-shell-clear-goals-regexp message)
+ proof-goals-buffer)
+ ;; Erase goals buffer but and possibly its windows
+ (proof-clean-buffer proof-goals-buffer))
+
+ ;; CASE variable setting: prover asks PG to set some variable
+ ;; NB: no safety protection whatsoever here, we use blind faith
+ ;; that the prover will not send malicious elisp!!
+ ((and proof-shell-set-elisp-variable-regexp
+ (string-match proof-shell-set-elisp-variable-regexp message))
+ (let
+ ((variable (match-string 1 message))
+ (expr (match-string 2 message)))
+ (condition-case nil
+ ;; Easiest way to do this seems to be to dump the lisp
+ ;; string into another buffer -- no direct way to eval
+ ;; from a string?
+ (with-temp-buffer
+ (insert expr)
+ (set (intern variable) (eval-last-sexp t)))
+ (t (proof-debug
+ (concat
+ "lisp error when obeying proof-shell-set-elisp-variable: \n"
+ "setting `" variable "'\n to: \n"
+ expr "\n"))))))
+
+ ;; CASE PGIP message from proof assistant.
+ ((and proof-shell-match-pgip-cmd
+ (string-match proof-shell-match-pgip-cmd message))
+ (require 'pg-xml)
+ (require 'pg-pgip)
+ (unless (string-match (match-string 0)
+ proof-shell-eager-annotation-start)
+ ;; Assume that eager annotation regexps are _not_ part of PGIP
+ ;; message, and strip them. This allows hybrid PGIP/non PGIP
+ ;; communication, with PGIP embedded in urgent messages.
+ (setq message
+ (substring
+ message
+ (progn
+ (string-match proof-shell-eager-annotation-start message)
+ (match-end 0))
+ (string-match proof-shell-eager-annotation-end message))))
+ (let
+ ((parsed-pgip (pg-xml-parse-string message)))
+ (pg-pgip-process-packet parsed-pgip)))
+
+ ;; CASE theorem dependency: prover lists thms used in last proof
+ ((and proof-shell-theorem-dependency-list-regexp
+ (string-match proof-shell-theorem-dependency-list-regexp message))
+ (let ((names (match-string 1 message))
+ (deps (match-string 2 message)))
+ (setq proof-last-theorem-dependencies
+ (cons
+ (split-string names
+ proof-shell-theorem-dependency-list-split)
+ (split-string deps
+ proof-shell-theorem-dependency-list-split)))))
+
+ ;; CASE tracing output: output in the tracing buffer instead
+ ;; of the response buffer
+ ((and proof-shell-trace-output-regexp
+ (string-match proof-shell-trace-output-regexp message))
+ (proof-trace-buffer-display
+ (if pg-use-specials-for-fontify
+ message
+ (pg-assoc-strip-subterm-markup message)))
+ (proof-display-and-keep-buffer proof-trace-buffer)
+ ;; Force redisplay in case in a fast loop which keeps Emacs
+ ;; fully-occupied processing prover output
+ (and (fboundp 'redisplay-frame)
+ ;; XEmacs fn
+ (redisplay-frame))
+ ;; If user quits during tracing output, send an interrupt
+ ;; to the prover. Helps when Emacs is "choking".
+ (if (and quit-flag proof-action-list)
+ (proof-interrupt-process)))
+
+ (t
+ ;; We're about to display a message. Clear the response buffer
+ ;; if necessary, but don't clear it the next time.
+ ;; Don't bother remove the window for the response buffer
+ ;; because we're about to put a message in it.
+ (proof-shell-maybe-erase-response nil nil)
+ (let ((stripped (pg-assoc-strip-subterm-markup message)))
+ ;; Display first chunk of output in minibuffer.
+ ;; Maybe this should be configurable, it can get noisy.
+ (proof-shell-message
+ (substring stripped 0 (or (string-match "\n" stripped)
+ (min (length stripped) 75))))
+ (pg-response-display-with-face
+ (if pg-use-specials-for-fontify
+ message
+ stripped)
+ 'proof-eager-annotation-face)))))
+
+(defun proof-shell-process-urgent-messages ()
+ "Scan the shell buffer for urgent messages.
+Scanning starts from `proof-shell-urgent-message-scanner' and handles
+strings between regexps eager-annotation-start and eager-annotation-end.
+
+Note that we must search the buffer rather than the chunk of output
+being filtered process because we have no guarantees about where
+chunks are broken: it may be in the middle of an annotation.
+
+This is a subroutine of `proof-shell-filter'."
+ (let ((pt (point)) (end t) lastend start)
+ (goto-char (marker-position proof-shell-urgent-message-scanner))
+ (while (and end
+ (re-search-forward proof-shell-eager-annotation-start
+ nil 'end))
+ (setq start (match-beginning 0))
+ (if (setq end
+ (re-search-forward proof-shell-eager-annotation-end nil t))
+ ;; Process the text including annotations (stripped if specials)
+ (save-excursion
+ (setq lastend end)
+ (proof-shell-process-urgent-message
+ (buffer-substring start end)))))
+ ;; Set the marker to the (character after) the end of the last
+ ;; message found, if any. Must take care to keep the marker
+ ;; behind the process marker otherwise no output is seen!
+ ;; (insert-before-markers in comint)
+ ;; FIXME: maybe we don't need to be as careful as these three checks?
+ (if lastend
+ (set-marker
+ proof-shell-urgent-message-marker
+ (min lastend
+ (1- (process-mark (get-buffer-process (current-buffer)))))))
+ ;; Now an optimization to avoid searching the same bit of text
+ ;; over and over. But it requires that we know the maximum
+ ;; possible length of an annotation to avoid missing them.
+ (if end
+ ;; If the search for the starting annotation was unsuccessful,
+ ;; set the scanner marker to the limit of the last search for
+ ;; the starting annotation, less the maximal length of the
+ ;; annotation.
+ (set-marker
+ proof-shell-urgent-message-scanner
+ (min
+ ;; NB: possible fix here not included: a test to be sure we
+ ;; don't go back before the start of the command! This
+ ;; fixes a minor problem which is possible duplication
+ ;; of urgent messages which are less than
+ ;; proof-shell-eager-annotation-start-length characters.
+ ;; But if proof-general is configured properly, there
+ ;; should never be any such messages!
+ ;; (max
+ ;; (marker-position proof-marker)
+ (- (point) proof-shell-eager-annotation-start-length)
+ (1- (process-mark (get-buffer-process (current-buffer))))))
+ ;; Otherwise, the search for the ending annotation was
+ ;; unsuccessful, so we set the scanner marker to the start of
+ ;; the annotation found.
+ (set-marker
+ proof-shell-urgent-message-scanner
+ (min
+ start
+ (1- (process-mark (get-buffer-process (current-buffer)))))))
+ (goto-char pt)))
+
+;; NOTE da: proof-shell-filter does *not* update the proof-marker,
+;; that's done in proof-shell-insert. Previous docstring below was
+;; wrong. The one case where this function updates proof-marker is
+;; the first time through the loop to synchronize.
+(defun proof-shell-filter (str)
+ "Filter for the proof assistant shell-process.
+A function for `comint-output-filter-functions'.
+
+Deal with output and issue new input from the queue.
+
+Handle urgent messages first. As many as possible are processed,
+using the function `proof-shell-process-urgent-messages'.
+
+Otherwise wait until an annotated prompt appears in the input.
+If `proof-shell-wakeup-char' is set, wait until we see that in the
+output chunk STR. This optimizes the filter a little bit.
+
+If a prompt is seen, run `proof-shell-process-output' on the output
+between the new prompt and the last input (position of `proof-marker')
+or the last urgent message (position of
+`proof-shell-urgent-message-marker'), whichever is later.
+For example, in this case:
+
+ PROMPT> INPUT
+ OUTPUT-1
+ URGENT-MESSAGE
+ OUTPUT-2
+ PROMPT>
+
+`proof-marker' is set after INPUT by `proof-shell-insert' and
+`proof-shell-urgent-message-marker' is set after URGENT-MESSAGE.
+Only OUTPUT-2 will be processed. For this reason, error
+messages and interrupt messages should *not* be considered
+urgent messages.
+
+Output is processed using the function
+`proof-shell-filter-process-output'.
+
+The first time that a prompt is seen, `proof-marker' is
+initialised to the end of the prompt. This should
+correspond with initializing the process. The
+ordinary output before the first prompt is ignored (urgent messages,
+however, are always processed; hence their name)."
+ (save-excursion
+ ;; Strip CRs.
+ (if proof-shell-strip-crs-from-output
+ (progn
+ (setq str (replace-regexp-in-string "\r+$" "" str))
+ ;; Do the same thing in the buffer via comint's function
+ ;; (sometimes put on comint-output-filter-functions too).
+ (comint-strip-ctrl-m)))
+
+ ;; Process urgent messages.
+ (and proof-shell-eager-annotation-start
+ (proof-shell-process-urgent-messages))
+
+ ;; FIXME da: some optimization possible here by customizing filter
+ ;; according to whether proof-shell-wakeup-char, etc, are non-nil.
+ ;; Could make proof-shell-filter into a macro to do this.
+ ;; On the other hand: it's not clear that wakeup-char is really
+ ;; needed, as matching the prompt may be efficient enough anyway.
+
+ (if ;; Some proof systems can be hacked to have annotated prompts;
+ ;; for these we set proof-shell-wakeup-char to the annotation
+ ;; special, and look for it in the output before doing anything.
+ (if proof-shell-wakeup-char
+ ;; FIXME: this match doesn't work in emacs-mule, darn.
+ ;; (string-match (char-to-string proof-shell-wakeup-char) str))
+ ;; FIXME: this match doesn't work in FSF emacs 20.5, darn.
+ ;; (find proof-shell-wakeup-char str)
+ ;; FIXME: [3.1] temporarily, use both tests!
+ (or
+ (string-match (char-to-string proof-shell-wakeup-char) str)
+ (find proof-shell-wakeup-char str))
+ ;; Others systems rely on a standard top-level (e.g. SML) whose
+ ;; prompts may be difficult or impossible to hack.
+ ;; For those we must search in the buffer for the prompt.
+ t)
+ (if (null (marker-position proof-marker))
+ ;; Initialisation of proof-marker:
+ ;; Set marker to after the first prompt in the
+ ;; output buffer if one can be found now.
+ ;; FIXME da: we'd rather do this initialization outside
+ ;; of the filter function for better efficiency!
+ (progn
+ (goto-char (point-min))
+ (if (re-search-forward proof-shell-annotated-prompt-regexp nil t)
+ (progn
+ (set-marker proof-marker (point))
+ ;; The first time a prompt is seen we ignore any
+ ;; output that occured before it, assuming that
+ ;; corresponds to uninteresting startup messages.
+ ;; We process the
+ ;; action list to remove the first item if need
+ ;; be (proof-shell-init-cmd sent if
+ ;; proof-shell-config-done).
+ (if proof-action-list
+ (proof-shell-filter-process-output "")))))
+ ;; Now we're looking for the end of the piece of output
+ ;; which will be processed.
+
+ ;; The blasphemous situation that the proof-action-list
+ ;; is empty is now quietly ignored so that users can
+ ;; type in the shell buffer without being screamed at.
+ ;; Also allows the process to output something for
+ ;; some other reason (perhaps it's just being chatty),
+ ;; although that could break the synchronization.
+ ;; Note that any "unexpected" output like this gets
+ ;; ignored.
+ (if proof-action-list
+ (let ((urgnt (marker-position
+ proof-shell-urgent-message-marker))
+ string startpos)
+ ;; Ignore any urgent messages that have already been
+ ;; dealt with. This loses in the case mentioned above.
+ ;; A more general way of doing this would be
+ ;; to filter out or delete the urgent messages which
+ ;; have been processed already.
+ (setq startpos (goto-char (marker-position proof-marker)))
+ (if (and urgnt
+ (< startpos urgnt))
+ (setq startpos (goto-char urgnt))
+ ;; Otherwise, skip possibly a (fudge) space and new line
+ (if (eq (char-after startpos) ?\ )
+ (setq startpos (goto-char (+ 2 startpos)))
+ (setq startpos (goto-char (1+ startpos)))))
+ ;; Find next prompt.
+ ;; The process might have sent us several things with
+ ;; prompts in-between, so we have to loop. -stef
+ (while (re-search-forward
+ proof-shell-annotated-prompt-regexp nil t)
+ (progn
+ (setq proof-shell-last-prompt
+ (buffer-substring (match-beginning 0) (match-end 0)))
+ ;; NB: decoding x-symbols here is perhaps a bit
+ ;; expensive; moreover it leads to problems
+ ;; processing special characters as annotations
+ ;; later on. So no fontify or decode.
+ ;; (proof-fontify-region startpos (point))
+ (setq string (buffer-substring startpos (match-beginning 0)))
+ ;; We are positioned right after a prompt output by the
+ ;; process. If there's anything ahead, it's also output
+ ;; from the process. Insert a newline to be sure that
+ ;; it won't look like input text sent to the process
+ ;; and so that "^" anchoring works right when matching
+ ;; process' output. -stef
+ (unless (eolp) (newline))
+ ;; Process output string.
+ (if (and (not proof-shell-strip-crs-from-input)
+ (equal string "") (not (eobp)))
+ ;; If there was no actual content apart from the
+ ;; prompt and if there's more output ahead to
+ ;; process, let's assume that this prompt was just
+ ;; a spurious result of having sent newlines in
+ ;; the input.
+ ;; This is fundamentally ambiguous because we can't
+ ;; tell the difference between such spurious prompts
+ ;; and actual empty output: if a multiline command
+ ;; returns no output, a human would have to type a
+ ;; silly command and wait for an answer to tell if
+ ;; the process was done or was still busy (short of
+ ;; counting prompts, of course).
+ ;; But we will call proof-shell-filter-process-output
+ ;; at least once, which is as good as the old code.
+ ;; We may call it too many times (with an empty
+ ;; string) because of those spurious prompts but
+ ;; it hopefully shouldn't lead to any disastrous
+ ;; effect other than displaying an empty response
+ ;; and discarding the actual non-empty one.
+ nil
+ (proof-shell-filter-process-output string))
+ (setq startpos (set-marker proof-marker (point))))))
+ ;; If proof-action-list is empty, make sure the process lock
+ ;; is not held! This should solve continual "proof shell busy"
+ ;; error messages which sometimes occur during development,
+ ;; at least.
+ (if proof-shell-busy
+ (progn
+ (proof-debug
+ "proof-shell-filter found empty action list yet proof shell busy.")
+ (proof-release-lock))))))))
+
+
+
+(defun proof-shell-filter-process-output (string)
+ "Subroutine of `proof-shell-filter' to process output STRING.
+
+Appropriate action is taken depending on what
+`proof-shell-process-output' returns: maybe handle an interrupt, an
+error, or deal with ordinary output which is a candidate for the goal
+or response buffer. Ordinary output is only displayed when the proof
+action list becomes empty, to avoid a confusing rapidly changing
+output.
+
+After processing the current output, the last step undertaken
+by the filter is to send the next command from the queue."
+ ;; If we don't strip \n from input, we may get spurious prompts.
+ ;; Ignore the corresponding empty-string.
+ (let
+ ;; Some functions may care which command invoked them
+ ((cmd (nth 1 (car proof-action-list))))
+ (save-excursion
+ ;;
+ (proof-shell-process-output cmd string)
+ ;; da: Added this next line to redisplay, for proof-toolbar
+ ;; FIXME: should do this for all frames displaying the script
+ ;; buffer!
+ ;; ODDITY: has strange effect on highlighting, leave it.
+ ;; (redisplay-frame (window-buffer t)
+ (cond
+ ((eq proof-shell-last-output-kind 'error)
+ (proof-shell-handle-error cmd))
+ ((eq proof-shell-last-output-kind 'interrupt)
+ (proof-shell-handle-interrupt))
+ ((eq proof-shell-last-output-kind 'loopback)
+ (proof-shell-insert-loopback-cmd proof-shell-last-output)
+ (proof-shell-exec-loop))
+ ;; Otherwise, it's something that we should delay
+ ;; handling: we don't act on it unless all the commands
+ ;; in the queue region have been processed.
+ ;; (e.g. goals/response message)
+ (t
+ (setq proof-shell-delayed-output-kind proof-shell-last-output-kind)
+ (setq proof-shell-delayed-output proof-shell-last-output)
+ (if (proof-shell-exec-loop)
+ (proof-shell-handle-delayed-output)))))))
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Utility functions
+;;
+(defun proof-shell-dont-show-annotations (&optional buffer)
+ "Set display values of annotations in BUFFER to be invisible.
+
+Annotations are characters 128-255."
+ (interactive)
+ (with-current-buffer (or buffer (current-buffer))
+ (let ((disp (make-display-table))
+ (i 128))
+ (while (< i 256)
+ (aset disp i [])
+ (incf i))
+ (cond ((fboundp 'add-spec-to-specifier)
+ (add-spec-to-specifier current-display-table disp (current-buffer)))
+ ((boundp 'buffer-display-table)
+ (setq buffer-display-table disp))))))
+
+(defun proof-shell-show-annotations ()
+ "Remove display table specifier from current buffer.
+This function is for testing purposes only, to reveal 8-bit characters
+in the shell buffer. Use proof-shell-dont-show-annotations to turn
+them off again.
+XEmacs only."
+ (interactive)
+ (remove-specifier current-display-table (current-buffer)))
+
+
+
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; proof-shell-invisible-command: for user-level commands.
+;;
+
+;;;###autoload
+(defun proof-shell-wait (&optional timeout)
+ "Busy wait for `proof-shell-busy' to become nil, or for TIMEOUT seconds.
+Needed between sequences of commands to maintain synchronization,
+because Proof General does not allow for the action list to be extended
+in some cases. May be called by `proof-shell-invisible-command'."
+ (while proof-shell-busy
+ (accept-process-output nil timeout)
+ (sit-for 0)))
+
+
+(defun proof-done-invisible (span)
+ "Callback for proof-shell-invisible-command.
+Calls proof-state-change-hook."
+ (run-hooks 'proof-state-change-hook))
+
+; new code to experiment with after 3.2
+;(defun proof-done-invisible (&optional span)
+; "Callback for proof-shell-invisible-command.
+;Calls proof-state-change-hook."
+; (run-hooks 'proof-state-change-hook)
+; (remove-hook 'proof-shell-handle-error-or-interrupt-hook
+; 'proof-shell-invisible-hook-fn))
+;; Seems to be hard to write this stuff without a temporary variable
+;; (or higher-order functions, sob).
+;(defun proof-shell-invisible-hook-fn ()
+; "Temporary function holding hook for proof-shell-invisible-command.")
+
+;(defmacro proof-shell-invisible-failure-msg (errormsg)
+; "Construct a value for `proof-shell-handle-error-or-interrupt-hook'.
+;Give error message ERRORMSG, then remove self from queue."
+; `(lambda ()
+; (proof-done-invisible)
+; (error ,(eval errormsg))))
+
+;(defmacro proof-shell-invisible-failure-fn (fn)
+; "Construct a value for `proof-shell-handle-error-or-interrupt-hook'.
+;Call function fn, then remove self from queue."
+; `(lambda ()
+; (proof-done-invisible)
+; (,(eval fn))))
+;
+; extra arg ERRORMSGFN to proof-shell-invisible-command:
+;
+;If ERRORMSGFN is non-nil, if the command leads to an error or interrupt
+;in the proof assistant, we will give an error. If ERRORMSGFN
+;is a string, (error ERRORMSGFN) is called; if ERRORMSGFN is a function,
+;it is called directly. If ERRORMSGFN is not a string or function,
+;we will give standard error messages for interrupts and errors."
+;
+; Other (sensible) possibility is to call
+; proof-shell-handle-error-or-interrupt-hook with span as argument.
+
+;;;###autoload
+(defun proof-shell-invisible-command (cmd &optional wait)
+ "Send CMD to the proof process.
+CMD may be a string or a string-yielding function.
+Automatically add proof-terminal-char if necessary, examining
+proof-shell-no-auto-terminate-commands.
+By default, let the command be processed asynchronously.
+But if optional WAIT command is non-nil, wait for processing to finish
+before and after sending the command.
+If WAIT is an integer, wait for that many seconds afterwards."
+ (unless (stringp cmd)
+ (setq cmd (eval cmd)))
+ (unless (or (null proof-terminal-char)
+ (not proof-shell-auto-terminate-commands)
+ (string-match (concat
+ (regexp-quote
+ (char-to-string proof-terminal-char))
+ "[ \t]*$") cmd))
+ (setq cmd (concat cmd (char-to-string proof-terminal-char))))
+ (if wait (proof-shell-wait))
+ (proof-shell-ready-prover) ; start proof assistant; set vars.
+ (proof-start-queue nil nil
+ (list (proof-shell-command-queue-item
+ cmd 'proof-done-invisible)))
+ (if wait (proof-shell-wait (if (numberp wait) wait))))
+
+(defun proof-shell-invisible-cmd-get-result (cmd &optional noerror)
+ "Execute CMD and return result as a string.
+This expects CMD to print something to the response buffer.
+The output in the response buffer is disabled, and the result
+\(contents of `proof-shell-last-output') is returned as a
+string instead.
+
+Errors are not supressed and will result in a display as
+usual, unless NOERROR is non-nil."
+ (setq proof-shell-no-response-display t)
+ (setq proof-shell-ignore-errors noerror)
+ (unwind-protect
+ (proof-shell-invisible-command cmd 'waitforit)
+ (setq proof-shell-no-response-display nil)
+ (setq proof-shell-ignore-errors nil))
+ proof-shell-last-output)
+
+
+
+
+
+;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
+;;
+;; Proof General shell mode definition
+;;
+
+(eval-and-compile ; to define vars
+;;; NB: autoload tag below doesn't work for d-d-m, autoload is in proof.el
+;;;###autoload
+(define-derived-mode proof-shell-mode comint-mode
+ "proof-shell" "Proof General shell mode class for proof assistant processes"
+
+ (setq proof-buffer-type 'shell)
+
+ ;; Clear state
+ (proof-shell-clear-state)
+
+ (make-local-variable 'proof-shell-insert-hook)
+
+ ;; Efficiency: don't keep undo history
+ (buffer-disable-undo)
+
+ ;; comint customisation. comint-prompt-regexp is used by
+ ;; comint-get-old-input, comint-skip-prompt, comint-bol, backward
+ ;; matching input, etc.
+ (if proof-shell-prompt-pattern
+ (setq comint-prompt-regexp proof-shell-prompt-pattern))
+
+ ;; An article by Helen Lowe in UITP'96 suggests that the user should
+ ;; not see all output produced by the proof process.
+ (remove-hook 'comint-output-filter-functions
+ 'comint-postoutput-scroll-to-bottom 'local)
+
+ (add-hook 'comint-output-filter-functions 'proof-shell-filter nil 'local)
+ (setq comint-get-old-input (function (lambda () "")))
+
+ ;; FIXME: this is a work-around for a nasty GNU Emacs 21.2
+ ;; bug which HANGS Emacs sometimes if special characters
+ ;; are hidden. (e.g. try M-x column-number-mode)
+ (unless proof-running-on-Emacs21
+ (proof-shell-dont-show-annotations))
+
+ ;; Proof marker is initialised in filter to first prompt found
+ (setq proof-marker (make-marker))
+ ;; Urgent message marker records end position of last urgent
+ ;; message seen.
+ (setq proof-shell-urgent-message-marker (make-marker))
+ ;; Urgent message scan marker records starting position to
+ ;; scan for urgent messages from
+ (setq proof-shell-urgent-message-scanner (make-marker))
+ (set-marker proof-shell-urgent-message-scanner (point-min))
+
+ ;; easy-menu-add must be in the mode function for XEmacs.
+ (easy-menu-add proof-shell-mode-menu proof-shell-mode-map)
+
+ ;; [ Should already be in proof-goals-buffer, really.]
+
+ ;; FIXME da: before entering proof assistant specific code,
+ ;; we'd do well to check that process is actually up and
+ ;; running now. If not, call the process sentinel function
+ ;; to display the buffer, and give an error.
+ ;; (Problem to fix is that process can die before sentinel is set:
+ ;; it ought to be set just here, perhaps: but setting hook here
+ ;; had no effect for some odd reason).
+ ;; What actually happens: an obscure infinite loop somewhere
+ ;; that can lead to "lisp nesting exceeded" somewhere, when
+ ;; shell startup fails. Ugly, but low priority to fix.
+ ))
+
+(easy-menu-define proof-shell-mode-menu
+ proof-shell-mode-map
+ "Menu used in Proof General shell mode."
+ proof-aux-menu)
+
+
+;;
+;; Sanity checks on important settings
+;;
+
+(defconst proof-shell-important-settings
+ '(proof-shell-annotated-prompt-regexp ; crucial
+ ))
+
+
+(defun proof-shell-config-done ()
+ "Initialise the specific prover after the child has been configured.
+Every derived shell mode should call this function at the end of
+processing."
+ (save-excursion
+ (set-buffer proof-shell-buffer)
+
+ ;; Give warnings if some crucial settings haven't been made
+ (dolist (sym proof-shell-important-settings)
+ (proof-warn-if-unset "proof-shell-config-done" sym))
+
+ ;; We do not use font-lock here, it's a waste of cycles.
+ ;; (proof-font-lock-configure-defaults nil)
+
+ (let ((proc (get-buffer-process proof-shell-buffer)))
+ ;; Add the kill buffer function and process sentinel
+ (make-local-hook 'kill-buffer-hook)
+ (add-hook 'kill-buffer-hook 'proof-shell-kill-function t t)
+ (set-process-sentinel proc 'proof-shell-bail-out)
+
+ ;; Pre-sync initialization command. This is necessary
+ ;; for proof assistants which change their output modes
+ ;; only after some initializations.
+ (if proof-shell-pre-sync-init-cmd
+ (proof-shell-insert proof-shell-pre-sync-init-cmd 'init-cmd))
+
+ ;; Flush pending output from startup (it gets hidden from the user)
+ ;; while waiting for the prompt to appear
+ (while (and (process-live-p proc)
+ (null (marker-position proof-marker)))
+ (accept-process-output proc 1))
+
+ (if (process-live-p proc)
+ (progn
+ ;; Send main intitialization command and wait for it to be
+ ;; processed. Also ensure that proof-action-list is initialised.
+ (setq proof-action-list nil)
+ (if proof-shell-init-cmd
+ (proof-shell-invisible-command proof-shell-init-cmd t))
+
+ ;; Configure for x-symbol
+ (proof-x-symbol-shell-config))))))
+
+
+(provide 'proof-shell)
+;; proof-shell.el ends here.