diff options
Diffstat (limited to 'generic/proof-script.el')
-rw-r--r-- | generic/proof-script.el | 1423 |
1 files changed, 1423 insertions, 0 deletions
diff --git a/generic/proof-script.el b/generic/proof-script.el new file mode 100644 index 00000000..453b18db --- /dev/null +++ b/generic/proof-script.el @@ -0,0 +1,1423 @@ +;; proof-script.el Major mode for proof assistant script files. +;; +;; Copyright (C) 1994 - 1998 LFCS Edinburgh. +;; Authors: David Aspinall, Yves Bertot, Healfdene Goguen, +;; Thomas Kleymann and Dilip Sequeira +;; +;; Maintainer: Proof General maintainer <proofgen@dcs.ed.ac.uk> +;; +;; $Id$ +;; + +;; +;; Internal variables used by script mode +;; + +;; FIXME da: remove proof-terminal-string. At the moment some +;; commands need to have the terminal string, some don't. +;; We should assume commands are terminated properly at the +;; specific level. +(defvar proof-terminal-string nil + "End-of-line string for proof process.") + +(defvar proof-re-end-of-cmd nil + "Regexp matching end of command. Based on proof-terminal-string. +Set in proof-config-done.") + +(defvar proof-re-term-or-comment nil + "Regexp matching terminator, comment start, or comment end. +Set in proof-config-done.") + +(defvar proof-marker nil + "Marker in proof shell buffer pointing to previous command input.") + +(defvar proof-shell-buffer nil + "Process buffer where the proof assistant is run.") + +(defvar proof-script-buffer-list nil + "Scripting buffers with locked regions. +The first element is current and in scripting minor mode. +The cdr of the list of corresponding file names is a subset of +`proof-included-files-list'.") + +(defvar proof-pbp-buffer nil + "The goals buffer (also known as the pbp buffer).") + +(defvar proof-response-buffer nil + "The response buffer.") + +(defvar proof-shell-busy nil + "A lock indicating that the proof shell is processing. +When this is non-nil, proof-check-process-available will give +an error.") + +(deflocal proof-buffer-type nil + "Symbol indicating the type of this buffer: 'script, 'shell, or 'pbp.") + +(defvar proof-action-list nil "action list") + +(defvar proof-included-files-list nil + "List of files currently included in proof process. +Whenever a new file is being processed, it gets added to the front of +the list. When the prover retracts across file boundaries, this list +is resynchronised. It contains files in canonical truename format") + +(deflocal proof-active-buffer-fake-minor-mode nil + "An indication in the modeline that this is the *active* script buffer") + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; A few small utilities ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun proof-match-find-next-function-name (buffer) + "General next function name in BUFFER finder using match. +The regexp is assumed to be a two item list the car of which is the regexp +to use, and the cdr of which is the match position of the function +name. Moves point after the match. + +The package fume-func provides the function +`fume-match-find-next-function-name' with the same specification. +However, fume-func's version is incorrec" + ;; DO NOT USE save-excursion; we need to move point! + ;; save-excursion is called at a higher level in the func-menu + ;; package + (set-buffer buffer) + (let ((r (car fume-function-name-regexp)) + (p (cdr fume-function-name-regexp))) + (and (re-search-forward r nil t) + (cons (buffer-substring (setq p (match-beginning p)) (point)) p)))) + +(defun proof-message (str) + "Output STR in minibuffer." + (message (concat "[" proof-assistant "] " str))) + +;; append-element in tl-list +(defun proof-append-element (ls elt) + "Append ELT to last of LS if ELT is not nil. [proof.el] +This function coincides with `append-element' in the package +[tl-list.el.]" + (if elt + (append ls (list elt)) + ls)) + +(defun proof-define-keys (map kbl) + "Adds keybindings KBL in MAP. +The argument KBL is a list of tuples (k . f) where `k' is a keybinding +(vector) and `f' the designated function." + (mapcar + (lambda (kbl) + (let ((k (car kbl)) (f (cdr kbl))) + (define-key map k f))) + kbl)) + +(defun proof-string-to-list (s separator) + "Return the list of words in S separated by SEPARATOR." + (let ((end-of-word-occurence (string-match (concat separator "+") s))) + (if (not end-of-word-occurence) + (if (string= s "") + nil + (list s)) + (cons (substring s 0 end-of-word-occurence) + (proof-string-to-list + (substring s + (string-match (concat "[^" separator "]") + s end-of-word-occurence)) separator))))) + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Basic code for the locked region and the queue region ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; FIXME: da: doc below needs fixing. +(defvar proof-locked-hwm nil + "Upper limit of the locked region") + +(defvar proof-queue-loose-end nil + "Limit of the queue region that is not equal to proof-locked-hwm.") + +(defvar proof-locked-span nil + "Upper limit of the locked region") + +(defvar proof-queue-span nil + "Upper limit of the locked region") + +(make-variable-buffer-local 'proof-locked-span) +(make-variable-buffer-local 'proof-queue-span) + +(defface proof-queue-face + '((((type x) (class color) (background light)) + (:background "mistyrose")) + (((type x) (class color) (background dark)) + (:background "mediumvioletred")) + (t + (:foreground "white" :background "black"))) + "Face for commands in proof script waiting to be processed." + :group 'proof) + +(defface proof-locked-face + '((((type x) (class color) (background light)) + (:background "lavender")) + (((type x) (class color) (background dark)) + (:background "navy")) + (t + (:underline t))) + "Face for locked region of proof script (processed commands)." + :group 'proof) + +(defun proof-init-segmentation () + (setq proof-queue-loose-end nil) + (if (not proof-queue-span) + (setq proof-queue-span (make-span 1 1))) + (set-span-property proof-queue-span 'start-closed t) + (set-span-property proof-queue-span 'end-open t) + (span-read-only proof-queue-span) + + (set-span-property proof-queue-span 'face 'proof-queue-face) + + (detach-span proof-queue-span) + + (setq proof-locked-hwm nil) + (if (not proof-locked-span) + (setq proof-locked-span (make-span 1 1))) + (set-span-property proof-locked-span 'start-closed t) + (set-span-property proof-locked-span 'end-open t) + (span-read-only proof-locked-span) + + (set-span-property proof-locked-span 'face 'proof-locked-face) + + (detach-span proof-locked-span)) + +(defsubst proof-lock-unlocked () + "Make the locked region read only." + (span-read-only proof-locked-span)) + +(defsubst proof-unlock-locked () + "Make the locked region read-write." + (span-read-write proof-locked-span)) + +(defsubst proof-set-queue-endpoints (start end) + "Set the queue span to be START, END." + (set-span-endpoints proof-queue-span start end)) + +(defsubst proof-set-locked-endpoints (start end) + "Set the locked span to be START, END." + (set-span-endpoints proof-locked-span start end)) + +(defsubst proof-detach-queue () + "Remove the span for the queue region." + (and proof-queue-span (detach-span proof-queue-span))) + +(defsubst proof-detach-locked () + "Remove the span for the locked region." + (and proof-locked-span (detach-span proof-locked-span))) + +(defsubst proof-set-queue-start (start) + "Set the queue span to begin at START." + (set-span-start proof-queue-span start)) + +(defsubst proof-set-queue-end (end) + "Set the queue span to end at END." + (set-span-end proof-queue-span end)) + +(defun proof-detach-segments (&optional buffer) + "Remove locked and queue region from BUFFER. +Defaults to current buffer when BUFFER is nil." + (let ((buffer (or buffer (current-buffer)))) + (save-excursion + (proof-detach-queue) + (proof-detach-locked)))) + +(defsubst proof-set-locked-end (end) + "Set the end of the locked region to be END, sort of? FIXME. +If END is past the end of the buffer, remove the locked region. +Otherwise set the locked region to be from the start of the +buffer to END." + (if (>= (point-min) end) + (proof-detach-locked) + (set-span-endpoints proof-locked-span (point-min) end))) + +(defun proof-unprocessed-begin () + "Return end of locked region in current buffer or (point-min) otherwise." + (or + (and (member (current-buffer) proof-script-buffer-list) + proof-locked-span (span-end proof-locked-span)) + (point-min))) + +(defun proof-locked-end () + "Return end of the locked region of the current buffer. +Only call this from a scripting buffer." + (if (member (current-buffer) proof-script-buffer-list) + (proof-unprocessed-begin) + (error "bug: proof-locked-end called from wrong buffer"))) + +(defsubst proof-end-of-queue () + "Return the end of the queue region, or nil if none." + (and proof-queue-span (span-end proof-queue-span))) + +(defun proof-dont-show-annotations () + "Set display values of annotations (characters 128-255) to be invisible." + (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-mark-buffer-atomic (buffer) + "Mark BUFFER as having been processed in a single step. + +If buffer already contains a locked region, only the remainder of the +buffer is closed off atomically." + (save-excursion + (set-buffer buffer) + (let ((span (make-span (proof-unprocessed-begin) (point-max))) + cmd) + ;; compute first command of buffer + (goto-char (point-min)) + (proof-find-next-terminator) + (let ((cmd-list (member-if + (lambda (entry) (equal (car entry) 'cmd)) + (proof-segment-up-to (point))))) + (proof-init-segmentation) + (if cmd-list + (progn + (setq cmd (second (car cmd-list))) + (set-span-property span 'type 'vanilla) + (set-span-property span 'cmd cmd)) + ;; If there was no command in the buffer, atomic + ;; span becomes a comment. + (set-span-property span 'type 'comment))) + (proof-set-locked-end (point-max)) + (or (member buffer proof-script-buffer-list) + (setq proof-script-buffer-list + (append proof-script-buffer-list (list buffer))))))) + +(defun proof-file-truename (filename) + "Returns the true name of the file FILENAME or nil." + (and filename (file-exists-p filename) (file-truename filename))) + +(defun proof-register-possibly-new-processed-file (file) + "Register a possibly new FILE as having been processed by the prover." + (let* ((cfile (file-truename file)) + (buffer (proof-file-to-buffer cfile))) + (if (not (member cfile proof-included-files-list)) + (progn + (setq proof-included-files-list + (cons cfile proof-included-files-list)) + (or (equal cfile + (file-truename (buffer-file-name + (car proof-script-buffer-list)))) + (not buffer) + (proof-mark-buffer-atomic buffer)))))) + + + + +;;; begin messy COMPATIBILITY HACKING for FSFmacs. +;;; +;;; In case Emacs is not aware of the function read-shell-command, +;;; and read-shell-command-map, we duplicate some code adjusted from +;;; minibuf.el distributed with XEmacs 20.4. +;;; +;;; This code is still required as of FSF Emacs 20.2. +;;; +;;; I think bothering with this just to give completion for +;;; when proof-prog-name-ask-p=t is a big overkill! - da. +;;; +(defvar read-shell-command-map + (let ((map (make-sparse-keymap 'read-shell-command-map))) + (if (not (fboundp 'set-keymap-parents)) + (if (fboundp 'set-keymap-parent) + ;; FSF Emacs 20.2 + (set-keymap-parent map minibuffer-local-map) + ;; Earlier FSF Emacs + (setq map (append minibuffer-local-map map)) + ;; XEmacs versions? + (set-keymap-parents map minibuffer-local-map))) + (define-key map "\t" 'comint-dynamic-complete) + (define-key map "\M-\t" 'comint-dynamic-complete) + (define-key map "\M-?" 'comint-dynamic-list-completions) + map) + "Minibuffer keymap used by shell-command and related commands.") + +(or (fboundp 'read-shell-command) + (defun read-shell-command (prompt &optional initial-input history) + "Just like read-string, but uses read-shell-command-map: +\\{read-shell-command-map}" + (let ((minibuffer-completion-table nil)) + (read-from-minibuffer prompt initial-input read-shell-command-map + nil (or history + 'shell-command-history))))) + + +;;; end messy COMPATIBILITY HACKING + + +;; +;; Misc movement functions +;; + +;; FIXME da: these next two functions slightly different, why? +;; (unprocessed-begin vs proof-locked-end) +(defun proof-goto-end-of-locked-interactive () + "Jump to the end of the locked region." + (interactive) + (switch-to-buffer (car proof-script-buffer-list)) + (goto-char (proof-locked-end))) + +(defun proof-goto-end-of-locked () + "Jump to the end of the locked region." + (goto-char (proof-unprocessed-begin))) + +(defun proof-in-locked-region-p () + "Non-nil if point is in locked region. Assumes proof script buffer current." + (< (point) (proof-locked-end))) + +(defun proof-goto-end-of-locked-if-pos-not-visible-in-window () + "If the end of the locked region is not visible, jump to the end of it." + (interactive) + (let* ((proof-script-buffer (car proof-script-buffer-list)) + (pos (save-excursion + (set-buffer proof-script-buffer) + (proof-locked-end)))) + (or (pos-visible-in-window-p pos (get-buffer-window + proof-script-buffer t)) + (proof-goto-end-of-locked-interactive)))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; User Commands ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +; Script management uses two major segments: Locked, which marks text +; which has been sent to the proof assistant and cannot be altered +; without being retracted, and Queue, which contains stuff being +; queued for processing. proof-action-list contains a list of +; (span,command,action) triples. 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. +; +; when a span has been processed, we classify it as follows: +; 'goalsave - denoting a 'goalsave pair in the locked region +; a 'goalsave region has a 'name property which is the name of the goal +; 'comment - denoting a comment +; 'pbp - denoting a span created by pbp +; 'vanilla - denoting any other span. +; 'pbp & 'vanilla spans have a property 'cmd, which says what +; command they contain. + +; We don't allow commands while the queue has anything in it. So we +; do configuration by concatenating the config command on the front in +; proof-send + +;; proof-assert-until-point, and various gunk for its ;; +;; setup and callback ;; + + +(defun proof-check-atomic-sequents-lists (span cmd end) + "Check if CMD is the final command in an ACS. + +If CMD is matched by the end regexp in `proof-atomic-sequents-list', +the ACS is marked in the current buffer. If CMD does not match any, +`nil' is returned, otherwise non-nil." + ;;FIXME tms: needs implementation + nil) + +(defun proof-done-advancing (span) + "The callback function for assert-until-point." + (let ((end (span-end span)) nam gspan next cmd) + (proof-set-locked-end end) + (proof-set-queue-start end) + (setq cmd (span-property span 'cmd)) + (cond + ((eq (span-property span 'type) 'comment) + (set-span-property span 'mouse-face 'highlight)) + ((proof-check-atomic-sequents-lists span cmd end)) + ((string-match proof-save-command-regexp cmd) + ;; In coq, we have the invariant that if we've done a save and + ;; there's a top-level declaration then it must be the + ;; associated goal. (Notice that because it's a callback it + ;; must have been approved by the theorem prover.) + (if (string-match proof-save-with-hole-regexp cmd) + (setq nam (match-string 2 cmd))) + (setq gspan span) + (while (or (eq (span-property gspan 'type) 'comment) + (not (funcall proof-goal-command-p + (setq cmd (span-property gspan 'cmd))))) + (setq next (prev-span gspan 'type)) + (delete-span gspan) + (setq gspan next)) + + (if (null nam) + (if (string-match proof-goal-with-hole-regexp + (span-property gspan 'cmd)) + (setq nam (match-string 2 (span-property gspan 'cmd))) + ;; This only works for Coq, but LEGO raises an error if + ;; there's no name. + ;; FIXME: a nonsense for Isabelle. + (setq nam "Unnamed_thm"))) + + (set-span-end gspan end) + (set-span-property gspan 'mouse-face 'highlight) + (set-span-property gspan 'type 'goalsave) + (set-span-property gspan 'name nam) + + (and proof-lift-global + (funcall proof-lift-global gspan))) + (t + (set-span-property span 'mouse-face 'highlight) + (and proof-global-p + (funcall proof-global-p cmd) + proof-lift-global + (funcall proof-lift-global span)))))) + + + +;; FIXME da: Below it would probably be faster to use the primitive +;; skip-chars-forward rather than scanning character-by-character +;; with a lisp loop over the whole region. Also I'm not convinced that +;; Emacs should be better at skipping whitespace and comments than the +;; proof process itself! + +(defun proof-segment-up-to (pos &optional next-command-end) + "Create a list of (type,int,string) tuples from end of locked region to POS. +Each tuple denotes the command and the position of its terminator, +type is one of 'comment, or 'cmd. 'unclosed-comment may be consed onto +the start if the segment finishes with an unclosed comment. +If optional NEXT-COMMAND-END is non-nil, we contine past POS until +the next command end." + (save-excursion + ;; depth marks number of nested comments. + ;; quote-parity is false if we're inside ""'s. + ;; Only one of (depth > 0) and (not quote-parity) + ;; should be true at once. -- hhg + (let ((str (make-string (- (buffer-size) + (proof-unprocessed-begin) -10) ?x)) + (i 0) (depth 0) (quote-parity t) done alist c) + (proof-goto-end-of-locked) + (while (not done) + (cond + ;; Case 1. We've reached POS, not allowed to go past it, + ;; and are inside a comment + ((and (not next-command-end) (= (point) pos) (> depth 0)) + (setq done t alist (cons 'unclosed-comment alist))) + ;; Case 2. We've reached the end of the buffer while + ;; scanning inside a comment or string + ((= (point) (point-max)) + (cond + ((not quote-parity) + (message "Warning: unclosed quote")) + ((> depth 0) + (setq done t alist (cons 'unclosed-comment alist)))) + (setq done t)) + ;; Case 3. Found a comment end, not inside a string + ((and (looking-at (regexp-quote proof-comment-end)) quote-parity) + (if (= depth 0) + (progn + (message "Warning: extraneous comment end") + (setq done t)) + (setq depth (- depth 1)) + (forward-char (length proof-comment-end)) + (if (eq i 0) + (setq alist (cons (list 'comment "" (point)) alist)) + (aset str i ?\ ) + (incf i)))) + ;; Case 4. Found a comment start, not inside a string + ((and (looking-at (regexp-quote proof-comment-start)) quote-parity) + (setq depth (+ depth 1)) + (forward-char (length proof-comment-start))) + ;; Case 5. Inside a comment. + ((> depth 0) + (forward-char)) + ;; Case 6. Anything else + (t + ;; Skip whitespace before the start of a command, otherwise + ;; other characters in the accumulator string str + (setq c (char-after (point))) + (if (or (> i 0) (not (= (char-syntax c) ?\ ))) + (progn + (aset str i c) + (incf i))) + + (if (looking-at "\"") ; FIXME da: should this be more generic? + (setq quote-parity (not quote-parity))) + + (forward-char) + + ;; Found the end of a command + (if (and (= c proof-terminal-char) quote-parity) + (progn + (setq alist + (cons (list 'cmd (substring str 0 i) (point)) alist)) + (if (>= (point) pos) + (setq done t) + (setq i 0))))))) + alist))) + +(defun proof-semis-to-vanillas (semis &optional callback-fn) + "Convert a sequence of semicolon positions (returned by the above +function) to a set of vanilla extents." + (let ((ct (proof-unprocessed-begin)) span alist semi) + (while (not (null semis)) + (setq semi (car semis) + span (make-span ct (nth 2 semi)) + ct (nth 2 semi)) + (if (eq (car (car semis)) 'cmd) + (progn + (set-span-property span 'type 'vanilla) + (set-span-property span 'cmd (nth 1 semi)) + (setq alist (cons (list span (nth 1 semi) + (or callback-fn 'proof-done-advancing)) + alist))) + (set-span-property span 'type 'comment) + (setq alist (cons (list span proof-no-command 'proof-done-advancing) alist))) + (setq semis (cdr semis))) + (nreverse alist))) + +;; +;; Two commands for moving forwards in proof scripts. +;; Moving forward for a "new" command may insert spaces +;; or new lines. Moving forward for the "next" command +;; does not. +;; + +(defun proof-script-new-command-advance () + "Move point to a nice position for a new command. +Assumes that point is at the end of a command." + (interactive) + (if proof-one-command-per-line + ;; One command per line: move to next new line, + ;; creating one if at end of buffer or at the + ;; start of a blank line. (This has the pleasing + ;; effect that blank regions of the buffer are + ;; automatically extended when inserting new commands). + (cond + ((eq (forward-line) 1) + (newline)) + ((eolp) + (newline) + (forward-line -1))) + ;; Multiple commands per line: skip spaces at point, + ;; and insert the same number of spaces that were + ;; skipped in front of point (at least one). + ;; This has the pleasing effect that the spacing + ;; policy of the current line is copied: e.g. + ;; <command>; <command>; + ;; Tab columns don't work properly, however. + ;; Instead of proof-one-command-per-line we could + ;; introduce a "proof-command-separator" to improve + ;; this. + (let ((newspace (max (skip-chars-forward " \t") 1)) + (p (point))) + (insert-char ?\ newspace) + (goto-char p)))) + +(defun proof-script-next-command-advance () + "Move point to the beginning of the next command if it's nearby. +Assumes that point is at the end of a command." + (interactive) + ;; skip whitespace on this line + (skip-chars-forward " \t") + (if (and proof-one-command-per-line (eolp)) + ;; go to the next line if we have one command per line + (forward-line))) + + + +; Assert until point - We actually use this to implement the +; assert-until-point, active terminator keypress, and find-next-terminator. +; In different cases we want different things, but usually the information +; (i.e. are we inside a comment) isn't available until we've actually run +; proof-segment-up-to (point), hence all the different options when we've +; done so. + +;; FIXME da: this command doesn't behave as the doc string says when +;; inside comments. Also is unhelpful at the start of commands, and +;; in the locked region. I prefer the new version below. + +(defun proof-assert-until-point + (&optional unclosed-comment-fun ignore-proof-process-p) + "Process the region from the end of the locked-region until point. + Default action if inside a comment is just to go until the start of + the comment. If you want something different, put it inside + unclosed-comment-fun. If ignore-proof-process-p is set, no commands + will be added to the queue." + (interactive) + (let ((pt (point)) + (crowbar (or ignore-proof-process-p (proof-check-process-available))) + semis) + (save-excursion + (if (not (re-search-backward "\\S-" (proof-unprocessed-begin) t)) + (progn (goto-char pt) + (error "I don't know what I should be doing in this buffer!"))) + (setq semis (proof-segment-up-to (point)))) + (if (and unclosed-comment-fun (eq 'unclosed-comment (car semis))) + (funcall unclosed-comment-fun) + (if (eq 'unclosed-comment (car semis)) (setq semis (cdr semis))) + (if (and (not ignore-proof-process-p) (not crowbar) (null semis)) + (error "I don't know what I should be doing in this buffer!")) + (goto-char (nth 2 (car semis))) + (and (not ignore-proof-process-p) + (let ((vanillas (proof-semis-to-vanillas (nreverse semis)))) +; (if crowbar (setq vanillas (cons crowbar vanillas))) + (proof-start-queue (proof-unprocessed-begin) (point) vanillas)))))) + + +;; da: This is my alternative version of the above. +;; It works from the locked region too. +;; I find it more convenient to assert up to the current command (command +;; point is inside), and move to the next command. +;; This means proofs can be easily replayed with point at the start +;; of lines. Above function gives stupid "nothing to do error." when +;; point is on the start of line or in the locked region. + +;; FIXME: behaviour inside comments may be odd at the moment. (it +;; doesn't behave as docstring suggests, same prob as +;; proof-assert-until-point) +;; FIXME: polish the undo behaviour and quit behaviour of this +;; command (should inhibit quit somewhere or other). + +(defun proof-assert-next-command + (&optional unclosed-comment-fun ignore-proof-process-p + dont-move-forward for-new-command) + "Process until the end of the next unprocessed command after point. +If inside a comment, just to go the start of +the comment. If you want something different, put it inside +UNCLOSED-COMMENT-FUN. If IGNORE-PROOF-PROCESS-P is set, no commands +will be added to the queue. +Afterwards, move forward to near the next command afterwards, unless +DONT-MOVE-FORWARD is non-nil. If FOR-NEW-COMMAND is non-nil, +a space or newline will be inserted automatically." + (interactive) + (let ((pt (point)) + (crowbar (or ignore-proof-process-p (proof-check-process-available))) + semis) + (save-excursion + ;; CHANGE from old proof-assert-until-point: don't bother check + ;; for non-whitespace between locked region and point. + ;; CHANGE: ask proof-segment-up-to to scan until command end + ;; (which it used to do anyway, except in the case of a comment) + (setq semis (proof-segment-up-to (point) t))) + ;; old code: + ;;(if (not (re-search-backward "\\S-" (proof-unprocessed-begin) t)) + ;; (progn (goto-char pt) + ;; (error "I don't know what I should be doing in this buffer!"))) + ;; (setq semis (proof-segment-up-to (point)))) + (if (and unclosed-comment-fun (eq 'unclosed-comment (car semis))) + (funcall unclosed-comment-fun) + (if (eq 'unclosed-comment (car semis)) + ;; CHANGE: if inside a comment, do as the documentation + ;; suggests. + (setq semis nil)) + (if (and (not ignore-proof-process-p) (not crowbar) (null semis)) + (error "I don't know what I should be doing in this buffer!")) + (goto-char (nth 2 (car semis))) + (if (not ignore-proof-process-p) + (let ((vanillas (proof-semis-to-vanillas (nreverse semis)))) +; (if crowbar (setq vanillas (cons crowbar vanillas))) + (proof-start-queue (proof-unprocessed-begin) (point) vanillas))) + ;; This is done after the queuing to be polite: it means the + ;; spacing policy enforced here is not put into the locked + ;; region so the user can re-edit. + (if (not dont-move-forward) + (if for-new-command + (proof-script-new-command-advance) + (proof-script-next-command-advance)))))) + +;; insert-pbp-command - an advancing command, for use when ;; +;; PbpHyp or Pbp has executed in LEGO, and returned a ;; +;; command for us to run ;; + +(defun proof-insert-pbp-command (cmd) + (proof-check-process-available) + (let (span) + (proof-goto-end-of-locked) + (insert cmd) + (setq span (make-span (proof-locked-end) (point))) + (set-span-property span 'type 'pbp) + (set-span-property span 'cmd cmd) + (proof-start-queue (proof-unprocessed-begin) (point) + (list (list span cmd 'proof-done-advancing))))) + + +;; proof-retract-until-point and associated gunk ;; +;; most of the hard work (i.e computing the commands to do ;; +;; the retraction) is implemented in the customisation ;; +;; module (lego.el or coq.el) which is why this looks so ;; +;; straightforward ;; + + +(defun proof-done-retracting (span) + "Updates display after proof process has reset its state. See also +the documentation for `proof-retract-until-point'. It optionally +deletes the region corresponding to the proof sequence." + (let ((start (span-start span)) + (end (span-end span)) + (kill (span-property span 'delete-me))) + (proof-set-locked-end start) + (proof-set-queue-end start) + (delete-spans start end 'type) + (delete-span span) + (if kill (delete-region start end)))) + +(defun proof-setup-retract-action (start end proof-command delete-region) + (let ((span (make-span start end))) + (set-span-property span 'delete-me delete-region) + (list (list span proof-command 'proof-done-retracting)))) + +(defun proof-retract-target (target delete-region) + (let ((end (proof-locked-end)) + (start (span-start target)) + (span (proof-last-goal-or-goalsave)) + actions) + + (if (and span (not (eq (span-property span 'type) 'goalsave))) + (if (< (span-end span) (span-end target)) + (progn + (setq span target) + (while (and span (eq (span-property span 'type) 'comment)) + (setq span (next-span span 'type))) + (setq actions (proof-setup-retract-action + start end + (if (null span) proof-no-command + (funcall proof-count-undos-fn span)) + delete-region) + end start)) + + (setq actions (proof-setup-retract-action (span-start span) end + proof-kill-goal-command + delete-region) + end (span-start span)))) + + (if (> end start) + (setq actions + (nconc actions (proof-setup-retract-action + start end + (funcall proof-find-and-forget-fn target) + delete-region)))) + + (proof-start-queue (min start end) (proof-locked-end) actions))) + +;; FIXME da: I would rather that this function moved point to +;; the start of the region retracted? + +(defun proof-retract-until-point (&optional delete-region) + "Sets up the proof process for retracting until point. In + particular, it sets a flag for the filter process to call + `proof-done-retracting' after the proof process has actually + successfully reset its state. It optionally deletes the region in + the proof script corresponding to the proof command sequence. If + this function is invoked outside a locked region, the last + successfully processed command is undone." + (interactive) + (proof-check-process-available) + (let ((span (span-at (point) 'type))) + (if (null (proof-locked-end)) (error "No locked region")) + (and (null span) + (progn (proof-goto-end-of-locked) (backward-char) + (setq span (span-at (point) 'type)))) + (proof-retract-target span delete-region))) + +;; proof-try-command ;; +;; this isn't really in the spirit of script management, ;; +;; but sometimes the user wants to just try an expression ;; +;; without having to undo it in order to try something ;; +;; different. Of course you can easily lose sync by doing ;; +;; something here which changes the proof state ;; + +(defun proof-done-trying (span) + (delete-span span) + (proof-detach-queue)) + +(defun proof-try-command + (&optional unclosed-comment-fun) + + "Process the command at point, + but don't add it to the locked region. This will only happen if + the command satisfies proof-state-preserving-p. + + Default action if inside a comment is just to go until the start of + the comment. If you want something different, put it inside + unclosed-comment-fun." + (interactive) + (let ((pt (point)) semis crowbar test) + (setq crowbar (proof-check-process-available)) + (save-excursion + (if (not (re-search-backward "\\S-" (proof-locked-end) t)) + (progn (goto-char pt) + (error "I don't know what I should be doing in this buffer!"))) + (setq semis (proof-segment-up-to (point)))) + (if (and unclosed-comment-fun (eq 'unclosed-comment (car semis))) + (funcall unclosed-comment-fun) + (if (eq 'unclosed-comment (car semis)) (setq semis (cdr semis))) + (if (and (not crowbar) (null semis)) (error "I don't know what I should be doing in this buffer!")) + (setq test (car semis)) + (if (not (funcall proof-state-preserving-p (nth 1 test))) + (error "Command is not state preserving")) + (goto-char (nth 2 test)) + (let ((vanillas (proof-semis-to-vanillas (list test) + 'proof-done-trying))) +; (if crowbar (setq vanillas (cons crowbar vanillas))) + (proof-start-queue (proof-unprocessed-begin) (point) vanillas))))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; misc other user functions ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +(defun proof-undo-last-successful-command (&optional no-delete) + "Undo last successful command at end of locked region. +Unless optional NO-DELETE is set, the text is also deleted from +the proof script." + (interactive "p") + (let ((lastspan (span-at-before (proof-locked-end) 'type))) + (if lastspan + (progn + (goto-char (span-start lastspan)) + (proof-retract-until-point (not no-delete))) + (error "Nothing to undo!")))) + +(defun proof-interrupt-process () + (interactive) + (if (not (proof-shell-live-buffer)) + (error "Proof Process Not Started!")) + (if (not (member (current-buffer) proof-script-buffer-list)) + (error "Don't own process!")) + (if (not proof-shell-busy) + (error "Proof Process Not Active!")) + (save-excursion + (set-buffer proof-shell-buffer) + (comint-interrupt-subjob))) + + +(defun proof-find-next-terminator () + "Set point after next `proof-terminal-char'." + (interactive) + (let ((cmd (span-at (point) 'type))) + (if cmd (goto-char (span-end cmd)) + (and (re-search-forward "\\S-" nil t) + (proof-assert-until-point nil 'ignore-proof-process))))) + +(defun proof-goto-command-start () + "Move point to start of current command." + (interactive) + (let ((cmd (span-at (point) 'type))) + (if cmd (goto-char (span-start cmd)) ; BUG: only works for unclosed proofs. + (let ((semis (proof-segment-up-to (point) t))) + (if (eq 'unclosed-comment (car semis)) (setq semis (cdr semis))) + (if (and semis (car semis) (car (car semis))) + (progn + (goto-char (nth 2 (car (car semis)))) + (skip-chars-forward " \t\n"))))))) + +(defun proof-process-buffer () + "Process the current buffer and set point at the end of the buffer." + (interactive) + (goto-char (point-max)) + (proof-assert-until-point)) + +(defun proof-restart-buffer (buffer) + "Remove all extents in BUFFER and update `proof-script-buffer-list'." + (save-excursion + (if (buffer-live-p buffer) + (progn + (set-buffer buffer) + (setq proof-active-buffer-fake-minor-mode nil) + (delete-spans (point-min) (point-max) 'type) + (proof-detach-segments))) + (setq proof-script-buffer-list + (remove buffer proof-script-buffer-list)))) + +(defun proof-restart-buffers (bufferlist) + "Remove all extents in BUFFERLIST and update `proof-script-buffer-list'." + (mapcar 'proof-restart-buffer bufferlist)) + +;; For when things go horribly wrong +;; FIXME: this needs to politely stop the process by sending +;; an EOF or customizable command. (maybe timeout waiting for +;; it to die before killing the buffer) +;; maybe better: +;; Put a funciton to remove all extents in buffers into +;; the kill-buffer-hook for the proof shell. Then this +;; function just stops the shell nicely (see proof-stop-shell). +(defun proof-restart-script () + "Restart Proof General. +Kill off the proof assistant process and remove all markings in the +script buffers." + (interactive) + (proof-restart-buffers proof-script-buffer-list) + ;; { (equal proof-script-buffer-list nil) } + (setq proof-shell-busy nil + proof-included-files-list nil + proof-shell-proof-completed nil) + (if (buffer-live-p proof-shell-buffer) + (kill-buffer proof-shell-buffer)) + (if (buffer-live-p proof-pbp-buffer) + (kill-buffer proof-pbp-buffer)) + (and (buffer-live-p proof-response-buffer) + (kill-buffer proof-response-buffer))) + +;; For when things go not-quite-so-horribly wrong +;; FIXME: this may need work, and maybe isn't needed at +;; all (proof-retract-file when it appears may be enough). +(defun proof-restart-script-same-process () + (interactive) + (save-excursion + (if (buffer-live-p proof-script-buffer) + (progn + (set-buffer proof-script-buffer) + (setq proof-active-buffer-fake-minor-mode nil) + (delete-spans (point-min) (point-max) 'type) + (proof-detach-segments))))) + +;; A command for making things go horribly wrong - it moves the +;; end-of-locked-region marker backwards, so user had better move it +;; correctly to sync with the proof state, or things will go all +;; pear-shaped. + +(defun proof-frob-locked-end () + (interactive) + "Move the end of the locked region backwards. +Only for use by consenting adults." + (cond + ((not (member (current-buffer) proof-script-buffer-list)) + (error "Not in proof buffer")) + ((> (point) (proof-locked-end)) + (error "Can only move backwards")) + (t (proof-set-locked-end (point)) + (delete-spans (proof-locked-end) (point-max) 'type)))) + +(defvar proof-minibuffer-history nil + "History of proof commands read from the minibuffer") + +(defun proof-execute-minibuffer-cmd () + (interactive) + (let (cmd) + (proof-check-process-available 'relaxed) + (setq cmd (read-string "Command: " nil 'proof-minibuffer-history)) + (proof-invisible-command cmd 'relaxed))) + +;; da: below functions for input history simulation are quick hacks. +;; Could certainly be made more efficient. + +(defvar proof-command-history nil + "History used by proof-previous-matching-command and friends.") + +(defun proof-build-command-history () + "Construct proof-command-history from script buffer. +Based on position of point." + ;; let + ) + +(defun proof-previous-matching-command (arg) + "Search through previous commands for new command matching current input." + (interactive)) + ;;(if (not (memq last-command '(proof-previous-matching-command + ;; proof-next-matching-command))) + ;; Start a new search + + + +(defun proof-next-matching-command (arg) + "Search through following commands for new command matching current input." + (interactive "p") + (proof-previous-matching-command (- arg))) + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;;; Popup and Pulldown Menu ;;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;;; Menu commands for the underlying proof assistant + +;;; These are defcustom'd so that users may re-configure +;;; the system to their liking. +;;; Functions using the above + +(defun proof-ctxt () + "List context." + (interactive) + (proof-invisible-command (concat proof-ctxt-string proof-terminal-string))) + +(defun proof-help () + "Print help message giving syntax." + (interactive) + (proof-invisible-command (concat proof-help-string proof-terminal-string))) + +(defun proof-prf () + "List proof state." + (interactive) + (proof-invisible-command (concat proof-prf-string proof-terminal-string))) + + + +;; FIXME: da: add more general function for inserting into the +;; script buffer and the proof process together, and using +;; a choice of minibuffer prompting (hated by power users, perfect +;; for novices). +;; Add named goals. +;; TODO: +;; Add named goals. +;; Coherent policy for movement here and elsewhere based on +;; proof-one-command-per-line user option. +;; Coherent policy for sending to process after writing into +;; script buffer. Could have one without the other. +;; For example, may be more easy to edit complex goal string +;; first in the script buffer. Ditto for tactics, etc. + +(defvar proof-issue-goal-history nil + "History of goals for proof-issue-goal.") + +(defun proof-issue-goal (goal-cmd) + "Insert a goal command into the script buffer, issue it to prover." + (interactive + (if proof-goal-command + (if (stringp proof-goal-command) + (list (format proof-goal-command + (read-string "Goal: " "" + proof-issue-goal-history))) + (proof-goal-command)) + (error + "Proof General not configured for goals: set proof-goal-command."))) + (let ((proof-one-command-per-line t)) ; Goals always start at a new line + (proof-issue-new-command goal-cmd))) + +(defvar proof-issue-save-history nil + "History of theorem names for proof-issue-save.") + +(defun proof-issue-save (thmsave-cmd) + "Insert a save theorem command into the script buffer, issue it." + (interactive + (if proof-save-command + (if (stringp proof-save-command) + (list (format proof-save-command + (read-string "Save as: " "" + proof-issue-save-history))) + (proof-save-command)) + (error + "Proof General not configured for save theorem: set proof-save-command."))) + (let ((proof-one-command-per-line t)) ; Goals always start at a new line + (proof-issue-new-command thmsave-cmd))) + +(defun proof-issue-new-command (cmd) + "Insert CMD into the script buffer and issue it to the proof assistant. +If point is in the locked region, move to the end of it first. +Start up the proof assistant if necessary." + ;; FIXME: da: I think we need a (proof-script-switch-to-buffer) + ;; function (so there is some control over display). + ;; (switch-to-buffer proof-script-buffer) + (if (proof-shell-live-buffer) + (if (proof-in-locked-region-p) + (proof-goto-end-of-locked-interactive))) + (proof-script-new-command-advance) + ;; FIXME: fixup behaviour of undo here. Really want + ;; to temporarily disable undo for insertion. + ;; (buffer-disable-undo) this trashes whole undo list! + (insert cmd) + ;; FIXME: could do proof-indent-line here, but let's + ;; wait until indentation is fixed. + (proof-assert-until-point)) + + + + +;;; To be called from menu +(defun proof-info-mode () + "Call info on Proof General." + (interactive) + (info "ProofGeneral")) + +(defun proof-exit () + "Exit Proof-assistant." + (interactive) + (proof-restart-script)) + +(defvar proof-help-menu + `("Help" + [,(concat proof-assistant " web page") + (browse-url proof-www-home-page) t] + ["Proof General home page" + (browse-url proof-general-home-page) t] + ["Proof General Info" proof-info-mode t] + ) + "The Help Menu in Script Management.") + +(defvar proof-shared-menu + (proof-append-element + (append + (list + ["Display context" proof-ctxt + :active (proof-shell-live-buffer)] + ["Display proof state" proof-prf + :active (proof-shell-live-buffer)] + ["Exit proof assistant" proof-exit + :active (proof-shell-live-buffer)]) + (if proof-tags-support + (list + "----" + ["Find definition/declaration" find-tag-other-window t]) + nil)) + proof-help-menu)) + +(defvar proof-menu + (append '("Commands" + ["Toggle active terminator" proof-active-terminator-minor-mode + :active t + :style toggle + :selected proof-active-terminator-minor-mode] + "----") + (list (if (string-match "XEmacs 19.1[2-9]" emacs-version) + "--:doubleLine" "----")) + proof-shared-menu + ) + "*The menu for the proof assistant.") + +(defvar proof-shell-menu proof-shared-menu + "The menu for the Proof-assistant shell") + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Active terminator minor mode ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(deflocal proof-active-terminator-minor-mode nil + "Active terminator minor mode flag") + +(defun proof-active-terminator-minor-mode (&optional arg) + "Toggle PROOF's Active Terminator minor mode. +With arg, turn on the Active Terminator minor mode if and only if arg +is positive. + +If Active terminator mode is enabled, a terminator will process the +current command." + + (interactive "P") + +;; has this minor mode been registered as such? + (or (assq 'proof-active-terminator-minor-mode minor-mode-alist) + (setq minor-mode-alist + (append minor-mode-alist + (list '(proof-active-terminator-minor-mode + (concat " " proof-terminal-string)))))) + + (setq proof-active-terminator-minor-mode + (if (null arg) (not proof-active-terminator-minor-mode) + (> (prefix-numeric-value arg) 0))) + (if (fboundp 'redraw-modeline) + (redraw-modeline) + (force-mode-line-update))) + +(defun proof-process-active-terminator () + "Insert the proof command terminator, and assert up to it. +Fire up proof process if necessary." + (let ((mrk (point)) ins incomment) + (if (looking-at "\\s-\\|\\'\\|\\w") + (if (not (re-search-backward "\\S-" (proof-unprocessed-begin) t)) + (error "I don't know what I should be doing in this buffer!"))) + (if (not (= (char-after (point)) proof-terminal-char)) + (progn (forward-char) (insert proof-terminal-string) (setq ins t))) + (proof-assert-until-point + (function (lambda () + (setq incomment t) + (if ins (backward-delete-char 1)) + (goto-char mrk) + (insert proof-terminal-string)))) + (or incomment + (proof-script-next-command-advance)))) + +(defun proof-active-terminator () + "Insert the terminator, perhaps sending the command to the assistant. +If proof-active-terminator-minor-mode is non-nil, the command will be +sent to the assistant." + (interactive) + (if proof-active-terminator-minor-mode + (proof-process-active-terminator) + (self-insert-command 1))) + + + + + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Proof General scripting mode definition ;; +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + + +;; da: this isn't so nice if a scripting buffer should inherit +;; from another mode: e.g. for Isabelle, we would like to use +;; sml-mode. +;; FIXME: add more doc to the mode below, to give hints on +;; configuring for new assistants. +(define-derived-mode proof-mode fundamental-mode + proof-mode-name + "Proof General major mode for proof scripts. +\\{proof-mode-map} +" + (setq proof-buffer-type 'script) + + ;; Has buffer already been processed? + (and (member buffer-file-truename proof-included-files-list) + (proof-mark-buffer-atomic (current-buffer))) + + (make-local-variable 'kill-buffer-hook) + (add-hook 'kill-buffer-hook + (lambda () + (setq proof-script-buffer-list + (remove (current-buffer) proof-script-buffer-list))))) + +;; FIXME: da: could we put these into another keymap already? +;; FIXME: da: it's offensive to experience users to rebind global stuff +;; like meta-tab, this should be removed. +(defconst proof-universal-keys + (append + '(([(control c) (control c)] . proof-interrupt-process) + ([(control c) (control v)] . proof-execute-minibuffer-cmd)) + (if proof-tags-support + '(([(meta tab)] . tag-complete-symbol)) + nil)) +"List of keybindings which for the script and response buffer. +Elements of the list are tuples (k . f) +where `k' is a keybinding (vector) and `f' the designated function.") + +;; Fixed definitions in proof-mode-map, which don't depend on +;; prover configuration. +;;; INDENT HACK: font-lock only recognizes define-key at start of line +(let ((map proof-mode-map)) +(define-key map [(control c) (control e)] 'proof-find-next-terminator) +(define-key map [(control c) (control a)] 'proof-goto-command-start) +(define-key map [(control c) (control n)] 'proof-assert-next-command) +(define-key map [(control c) (return)] 'proof-assert-next-command) +(define-key map [(control c) (control t)] 'proof-try-command) +(define-key map [(control c) ?u] 'proof-retract-until-point) +(define-key map [(control c) (control u)] 'proof-undo-last-successful-command) +(define-key map [(control c) ?\'] 'proof-goto-end-of-locked-interactive) +(define-key map [(control button1)] 'proof-send-span) +(define-key map [(control c) (control b)] 'proof-process-buffer) +(define-key map [(control c) (control z)] 'proof-frob-locked-end) +(define-key map [(control c) (control p)] 'proof-prf) +(define-key map [(control c) ?c] 'proof-ctxt) +(define-key map [(control c) ?h] 'proof-help) +(define-key map [(meta p)] 'proof-previous-matching-command) +(define-key map [(meta n)] 'proof-next-matching-command) +;; FIXME da: this shouldn't need setting, because it works +;; via indent-line-function which is set below. Check this. +(define-key map [tab] 'proof-indent-line) +(proof-define-keys map proof-universal-keys)) + + + +;; the following callback is an irritating hack - there should be some +;; elegant mechanism for computing constants after the child has +;; configured. + +(defun proof-config-done () + "Finish setup of Proof General scripting mode. +Call this function in the derived mode for the proof assistant to +finish setup which depends on specific proof assistant configuration." + ;; calculate some strings and regexps for searching + (setq proof-terminal-string (char-to-string proof-terminal-char)) + + ;; FIXME: these are LEGO specific! + (setq pbp-goal-command (concat "Pbp %s" proof-terminal-string)) + (setq pbp-hyp-command (concat "PbpHyp %s" proof-terminal-string)) + + ;; FIXME da: I'm not sure we ought to add spaces here, but if + ;; we don't, there would be trouble overloading these settings + ;; to also use as regexps for finding comments. + ;; + (make-local-variable 'comment-start) + (setq comment-start (concat proof-comment-start " ")) + (make-local-variable 'comment-end) + (setq comment-end (concat " " proof-comment-end)) + (make-local-variable 'comment-start-skip) + (setq comment-start-skip + (concat (regexp-quote proof-comment-start) "+\\s_?")) + + (setq proof-re-end-of-cmd (concat "\\s_*" proof-terminal-string "\\s_*\\\'")) + (setq proof-re-term-or-comment + (concat proof-terminal-string "\\|" (regexp-quote proof-comment-start) + "\\|" (regexp-quote proof-comment-end))) + + ;; func-menu --- Jump to a goal within a buffer + (and (boundp 'fume-function-name-regexp-alist) + (defvar fume-function-name-regexp-proof + (cons proof-goal-with-hole-regexp 2)) + (push (cons major-mode 'fume-function-name-regexp-proof) + fume-function-name-regexp-alist)) + (and (boundp 'fume-find-function-name-method-alist) + (push (cons major-mode 'proof-match-find-next-function-name) + fume-find-function-name-method-alist)) + + ;; Additional key definitions which depend on configuration for + ;; specific proof assistant. + (define-key proof-mode-map + (vconcat [(control c)] (vector proof-terminal-char)) + 'proof-active-terminator-minor-mode) + + (define-key proof-mode-map (vector proof-terminal-char) + 'proof-active-terminator) + + (make-local-variable 'indent-line-function) + (setq indent-line-function 'proof-indent-line) + + ;; Toolbar + (if (featurep 'proof-toolbar) + (proof-toolbar-setup)) + + ;; Menu + (easy-menu-define proof-mode-menu + proof-mode-map + "Menu used in Proof General scripting mode." + (cons proof-mode-name + (append + (cdr proof-menu) + ;; begin UGLY COMPATIBILTY HACK + ;; older/non-existent customize doesn't have + ;; this function. + (if (fboundp 'customize-menu-create) + (list (customize-menu-create 'proof) + (customize-menu-create 'proof-internal + "Internals")) + nil) + ;; end UGLY COMPATIBILTY HACK + ))) + (easy-menu-add proof-mode-menu proof-mode-map) + + ;; For fontlock + + ;; setting font-lock-defaults explicitly is required by FSF Emacs + ;; 20.2's version of font-lock + (make-local-variable 'font-lock-defaults) + (setq font-lock-defaults '(font-lock-keywords)) + + ;; FIXME (da): zap commas support is too specific, should be enabled + ;; by each proof assistant as it likes. + (remove-hook 'font-lock-after-fontify-buffer-hook 'proof-zap-commas-buffer t) + (add-hook 'font-lock-after-fontify-buffer-hook + 'proof-zap-commas-buffer nil t) + (remove-hook 'font-lock-mode-hook 'proof-unfontify-separator t) + (add-hook 'font-lock-mode-hook 'proof-unfontify-separator nil t) + + ;; if we don't have the following, zap-commas fails to work. + ;; FIXME (da): setting this to t everywhere is too brutal. Should + ;; probably make it local. + (and (boundp 'font-lock-always-fontify-immediately) + (setq font-lock-always-fontify-immediately t)) + + (run-hooks 'proof-mode-hook)) + + + +(provide 'proof-script) +;; proof-script.el ends here. |