aboutsummaryrefslogtreecommitdiffhomepage
path: root/generic/proof-indent.el
blob: ec580165b204b07d844672a9d11e17481e784b7c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
;; proof-indent.el Generic Indentation for Proof Assistants
;; Copyright (C) 1997, 1998 LFCS Edinburgh
;; Authors: Healfdene Goguen, Thomas Kleymann and Dilip Sequeira
;; Maintainer:  Proof General maintainer <proofgen@dcs.ed.ac.uk>
;;
;; $Id$
;;

(require 'proof)			; loader
(require 'proof-script)			; indent code is for script editing

;; This is quite different from sml-mode, but borrows some bits of
;; code.  It's quite a lot less general, but works with nested
;; comments.

;; parse-to-point: If from is nil, parsing starts from either
;; proof-locked-end if we're in the proof-script-buffer or the
;; beginning of the buffer. Otherwise state must contain a valid
;; triple.

(defun proof-parse-to-point (&optional from state)
  (let ((cmt-level 0) (stack (list (list nil 0)))
	(end (point)) instring c forward-amount
	(cmt-end-regexp (regexp-quote proof-comment-end))
	(cmt-start-regexp (regexp-quote proof-comment-start)))
    (save-excursion
      (if (null from)
	  (goto-char (point-min))
	(goto-char from)
	(setq instring (car state)
	      cmt-level (nth 1 state)
	      stack (nth 2 state)))
      (while (< (point) end)
	(setq c (char-after (point)))
	(setq forward-amount 1)   ; may be subject to dynamic scoping!
	(cond 
	 ;; strings
	 ((and instring (proof-looking-at proof-string-end-regexp))
	  (setq forward-amount (length (match-string 0)))
	  (setq instring nil))
	 (instring)
	 ((proof-looking-at proof-string-start-regexp)
	  (setq forward-amount (length (match-string 0)))
	  (setq instring t))

	 ;; comments
	 ((proof-looking-at cmt-start-regexp)
	  (setq forward-amount (length (match-string 0)))
	  (incf cmt-level))
	 ((proof-looking-at cmt-end-regexp)
	  (setq forward-amount (length (match-string 0)))
	  (decf cmt-level))
	 ((> cmt-level 0))

	 ;; parentheses
	 ((proof-looking-at "\\s(")
	  (setq stack (cons (list c (point)) stack)))
	 ((proof-looking-at "\\s)")
	  (setq stack (cdr stack)))
	 
	 ;; basic indentation for commands
	 ((proof-looking-at proof-indent-commands-regexp)
	  (setq stack (cons (list proof-terminal-char (point)) stack)))
	 ((and (eq c proof-terminal-char)
	       (eq (car (car stack)) proof-terminal-char))
	  (setq stack (cdr stack)))

	 ;; prover specific plugin
	 (proof-parse-indent
	  (setq stack (funcall proof-parse-indent c stack))))

	(forward-char forward-amount))
      (list instring cmt-level stack))))

;;;###autoload      
(defun proof-indent-line ()
  "Indent current line of proof script, if indentation enabled."
  (interactive)
  (unless (not (proof-ass script-indent))
    (if (< (point) (proof-locked-end))
	(if (< (current-column) (current-indentation))
	    (skip-chars-forward "\t "))
      (save-excursion
	(beginning-of-line)
	(let* ((state (proof-parse-to-point))
	       (beg (point))
	       (indent (cond 
			((car state) 1)
			((> (nth 1 state) 0) 1)
			(t (funcall proof-stack-to-indent (nth 2 state))))))
	  (skip-chars-forward "\t ")
	  (if (not (eq (current-indentation) indent))
	      (progn (delete-region beg (point))
		     (indent-to indent)))))
      (skip-chars-forward "\t "))))

;;;###autoload      
(defun proof-indent-region (start end)
  (interactive "r")
  (if (< (point) (proof-locked-end))
      (error "can't indent locked region!"))
  (save-excursion
    (goto-char start)
    (beginning-of-line)
    (let* ((beg (point))
	   (state (proof-parse-to-point))
	   indent)
      ;; End of region changes with new indentation
      (while (< (point) end)
	(setq indent
	      (cond ((car state) 1)
		    ((> (nth 1 state) 0) 1)
		    (t (funcall proof-stack-to-indent (nth 2 state)))))
	(skip-chars-forward "\t ")
	(let ((diff (- (current-indentation) indent)))
	  (if (not (eq diff 0))
	      (progn
		(delete-region beg (point))
		(indent-to indent)
		(setq end (- end diff)))))
	(end-of-line)
	(if (< (point) (point-max)) (forward-char))
	(setq state (proof-parse-to-point beg state)
	      beg (point))))))

(provide 'proof-indent)