diff options
| author | Stefan Monnier | 2010-05-17 15:27:26 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2010-05-17 15:27:26 -0400 |
| commit | 5ad4bef5758fd694d209a8fb63f42bcfdb22785c (patch) | |
| tree | 813a37580e4d3a4d1585110aae6d14815c6d2ad6 | |
| parent | 16455a8509026404dcba9a1adfe389883b3ef990 (diff) | |
| download | emacs-5ad4bef5758fd694d209a8fb63f42bcfdb22785c.tar.gz emacs-5ad4bef5758fd694d209a8fb63f42bcfdb22785c.zip | |
Provide a simple generic indentation engine and use it for Prolog.
* emacs-lisp/smie.el: New file.
* progmodes/prolog.el (prolog-smie-op-levels)
(prolog-smie-indent-rules): New var.
(prolog-mode-variables): Use them to configure SMIE.
(prolog-indent-line, prolog-indent-level): Remove.
| -rw-r--r-- | etc/NEWS | 2 | ||||
| -rw-r--r-- | lisp/ChangeLog | 11 | ||||
| -rw-r--r-- | lisp/emacs-lisp/smie.el | 688 | ||||
| -rw-r--r-- | lisp/progmodes/prolog.el | 120 | ||||
| -rw-r--r-- | lisp/simple.el | 12 |
5 files changed, 769 insertions, 64 deletions
| @@ -210,6 +210,8 @@ threads simultaneously. | |||
| 210 | 210 | ||
| 211 | * New Modes and Packages in Emacs 24.1 | 211 | * New Modes and Packages in Emacs 24.1 |
| 212 | 212 | ||
| 213 | ** smie.el is a package providing a simple generic indentation engine. | ||
| 214 | |||
| 213 | ** secrets.el is an implementation of the Secret Service API, an | 215 | ** secrets.el is an implementation of the Secret Service API, an |
| 214 | interface to password managers like GNOME Keyring or KDE Wallet. The | 216 | interface to password managers like GNOME Keyring or KDE Wallet. The |
| 215 | Secret Service API requires D-Bus for communication. | 217 | Secret Service API requires D-Bus for communication. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index f6d4ce0c884..e85fa58d360 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,12 @@ | |||
| 1 | 2010-05-17 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | Provide a simple generic indentation engine and use it for Prolog. | ||
| 4 | * emacs-lisp/smie.el: New file. | ||
| 5 | * progmodes/prolog.el (prolog-smie-op-levels) | ||
| 6 | (prolog-smie-indent-rules): New var. | ||
| 7 | (prolog-mode-variables): Use them to configure SMIE. | ||
| 8 | (prolog-indent-line, prolog-indent-level): Remove. | ||
| 9 | |||
| 1 | 2010-05-17 Jay Belanger <jay.p.belanger@gmail.com> | 10 | 2010-05-17 Jay Belanger <jay.p.belanger@gmail.com> |
| 2 | 11 | ||
| 3 | * calc/calc-vec.el (math-vector-avg): Put the vector elements in | 12 | * calc/calc-vec.el (math-vector-avg): Put the vector elements in |
| @@ -6,7 +15,7 @@ | |||
| 6 | 2010-05-16 Jay Belanger <jay.p.belanger@gmail.com> | 15 | 2010-05-16 Jay Belanger <jay.p.belanger@gmail.com> |
| 7 | 16 | ||
| 8 | * calc/calc-vec.el (calc-histogram): | 17 | * calc/calc-vec.el (calc-histogram): |
| 9 | (calcFunc-histogram): Allow vectors as inputs. | 18 | (calcFunc-histogram): Allow vectors as inputs. |
| 10 | (math-vector-avg): New function. | 19 | (math-vector-avg): New function. |
| 11 | 20 | ||
| 12 | * calc/calc-ext.el (math-group-float): Have the number of digits | 21 | * calc/calc-ext.el (math-group-float): Have the number of digits |
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el new file mode 100644 index 00000000000..46c4222f3fe --- /dev/null +++ b/lisp/emacs-lisp/smie.el | |||
| @@ -0,0 +1,688 @@ | |||
| 1 | ;;; smie.el --- Simple Minded Indentation Engine | ||
| 2 | |||
| 3 | ;; Copyright (C) 2010 Free Software Foundation, Inc. | ||
| 4 | |||
| 5 | ;; Author: Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 6 | ;; Keywords: languages, lisp, internal, parsing, indentation | ||
| 7 | |||
| 8 | ;; This file is part of GNU Emacs. | ||
| 9 | |||
| 10 | ;; GNU Emacs is free software; you can redistribute it and/or modify | ||
| 11 | ;; it under the terms of the GNU General Public License as published by | ||
| 12 | ;; the Free Software Foundation, either version 3 of the License, or | ||
| 13 | ;; (at your option) any later version. | ||
| 14 | |||
| 15 | ;; GNU Emacs is distributed in the hope that it will be useful, | ||
| 16 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 17 | ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 18 | ;; GNU General Public License for more details. | ||
| 19 | |||
| 20 | ;; You should have received a copy of the GNU General Public License | ||
| 21 | ;; along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
| 22 | |||
| 23 | ;;; Commentary: | ||
| 24 | |||
| 25 | ;; While working on the SML indentation code, the idea grew that maybe | ||
| 26 | ;; I could write something generic to do the same thing, and at the | ||
| 27 | ;; end of working on the SML code, I had a pretty good idea of what it | ||
| 28 | ;; could look like. That idea grew stronger after working on | ||
| 29 | ;; LaTeX indentation. | ||
| 30 | ;; | ||
| 31 | ;; So at some point I decided to try it out, by writing a new | ||
| 32 | ;; indentation code for Coq while trying to keep most of the code | ||
| 33 | ;; "table driven", where only the tables are Coq-specific. The result | ||
| 34 | ;; (which was used for Beluga-mode as well) turned out to be based on | ||
| 35 | ;; something pretty close to an operator precedence parser. | ||
| 36 | |||
| 37 | ;; So here is another rewrite, this time following the actual principles of | ||
| 38 | ;; operator precedence grammars. Why OPG? Even though they're among the | ||
| 39 | ;; weakest kinds of parsers, these parsers have some very desirable properties | ||
| 40 | ;; for Emacs: | ||
| 41 | ;; - most importantly for indentation, they work equally well in either | ||
| 42 | ;; direction, so you can use them to parse backward from the indentation | ||
| 43 | ;; point to learn the syntactic context; | ||
| 44 | ;; - they work locally, so there's no need to keep a cache of | ||
| 45 | ;; the parser's state; | ||
| 46 | ;; - because of that locality, indentation also works just fine when earlier | ||
| 47 | ;; parts of the buffer are syntactically incorrect since the indentation | ||
| 48 | ;; looks at "as little as possible" of the buffer make an indentation | ||
| 49 | ;; decision. | ||
| 50 | ;; - they typically have no error handling and can't even detect a parsing | ||
| 51 | ;; error, so we don't have to worry about what to do in case of a syntax | ||
| 52 | ;; error because the parser just automatically does something. Better yet, | ||
| 53 | ;; we can afford to use a sloppy grammar. | ||
| 54 | |||
| 55 | ;; The development (especially the parts building the 2D precedence | ||
| 56 | ;; tables and then computing the precedence levels from it) is largely | ||
| 57 | ;; inspired from page 187-194 of "Parsing techniques" by Dick Grune | ||
| 58 | ;; and Ceriel Jacobs (BookBody.pdf available at | ||
| 59 | ;; http://www.cs.vu.nl/~dick/PTAPG.html). | ||
| 60 | ;; | ||
| 61 | ;; OTOH we had to kill many chickens, read many coffee grounds, and practiced | ||
| 62 | ;; untold numbers of black magic spells. | ||
| 63 | |||
| 64 | ;;; Code: | ||
| 65 | |||
| 66 | (eval-when-compile (require 'cl)) | ||
| 67 | |||
| 68 | ;;; Building precedence level tables from BNF specs. | ||
| 69 | |||
| 70 | (defun smie-set-prec2tab (table x y val &optional override) | ||
| 71 | (assert (and x y)) | ||
| 72 | (let* ((key (cons x y)) | ||
| 73 | (old (gethash key table))) | ||
| 74 | (if (and old (not (eq old val))) | ||
| 75 | (if (gethash key override) | ||
| 76 | ;; FIXME: The override is meant to resolve ambiguities, | ||
| 77 | ;; but it also hides real conflicts. It would be great to | ||
| 78 | ;; be able to distinguish the two cases so that overrides | ||
| 79 | ;; don't hide real conflicts. | ||
| 80 | (puthash key (gethash key override) table) | ||
| 81 | (display-warning 'smie (format "Conflict: %s %s/%s %s" x old val y))) | ||
| 82 | (puthash key val table)))) | ||
| 83 | |||
| 84 | (defun smie-precs-precedence-table (precs) | ||
| 85 | "Compute a 2D precedence table from a list of precedences. | ||
| 86 | PRECS should be a list, sorted by precedence (e.g. \"+\" will | ||
| 87 | come before \"*\"), of elements of the form \(left OP ...) | ||
| 88 | or (right OP ...) or (nonassoc OP ...) or (assoc OP ...). All operators in | ||
| 89 | one of those elements shares the same precedence level and associativity." | ||
| 90 | (let ((prec2-table (make-hash-table :test 'equal))) | ||
| 91 | (dolist (prec precs) | ||
| 92 | (dolist (op (cdr prec)) | ||
| 93 | (let ((selfrule (cdr (assq (car prec) | ||
| 94 | '((left . >) (right . <) (assoc . =)))))) | ||
| 95 | (when selfrule | ||
| 96 | (dolist (other-op (cdr prec)) | ||
| 97 | (smie-set-prec2tab prec2-table op other-op selfrule)))) | ||
| 98 | (let ((op1 '<) (op2 '>)) | ||
| 99 | (dolist (other-prec precs) | ||
| 100 | (if (eq prec other-prec) | ||
| 101 | (setq op1 '> op2 '<) | ||
| 102 | (dolist (other-op (cdr other-prec)) | ||
| 103 | (smie-set-prec2tab prec2-table op other-op op2) | ||
| 104 | (smie-set-prec2tab prec2-table other-op op op1))))))) | ||
| 105 | prec2-table)) | ||
| 106 | |||
| 107 | (defun smie-merge-prec2s (tables) | ||
| 108 | (if (null (cdr tables)) | ||
| 109 | (car tables) | ||
| 110 | (let ((prec2 (make-hash-table :test 'equal))) | ||
| 111 | (dolist (table tables) | ||
| 112 | (maphash (lambda (k v) | ||
| 113 | (smie-set-prec2tab prec2 (car k) (cdr k) v)) | ||
| 114 | table)) | ||
| 115 | prec2))) | ||
| 116 | |||
| 117 | (defun smie-bnf-precedence-table (bnf &rest precs) | ||
| 118 | (let ((nts (mapcar 'car bnf)) ;Non-terminals | ||
| 119 | (first-ops-table ()) | ||
| 120 | (last-ops-table ()) | ||
| 121 | (first-nts-table ()) | ||
| 122 | (last-nts-table ()) | ||
| 123 | (prec2 (make-hash-table :test 'equal)) | ||
| 124 | (override (smie-merge-prec2s | ||
| 125 | (mapcar 'smie-precs-precedence-table precs))) | ||
| 126 | again) | ||
| 127 | (dolist (rules bnf) | ||
| 128 | (let ((nt (car rules)) | ||
| 129 | (last-ops ()) | ||
| 130 | (first-ops ()) | ||
| 131 | (last-nts ()) | ||
| 132 | (first-nts ())) | ||
| 133 | (dolist (rhs (cdr rules)) | ||
| 134 | (assert (consp rhs)) | ||
| 135 | (if (not (member (car rhs) nts)) | ||
| 136 | (pushnew (car rhs) first-ops) | ||
| 137 | (pushnew (car rhs) first-nts) | ||
| 138 | (when (consp (cdr rhs)) | ||
| 139 | ;; If the first is not an OP we add the second (which | ||
| 140 | ;; should be an OP if BNF is an "operator grammar"). | ||
| 141 | ;; Strictly speaking, this should only be done if the | ||
| 142 | ;; first is a non-terminal which can expand to a phrase | ||
| 143 | ;; without any OP in it, but checking doesn't seem worth | ||
| 144 | ;; the trouble, and it lets the writer of the BNF | ||
| 145 | ;; be a bit more sloppy by skipping uninteresting base | ||
| 146 | ;; cases which are terminals but not OPs. | ||
| 147 | (assert (not (member (cadr rhs) nts))) | ||
| 148 | (pushnew (cadr rhs) first-ops))) | ||
| 149 | (let ((shr (reverse rhs))) | ||
| 150 | (if (not (member (car shr) nts)) | ||
| 151 | (pushnew (car shr) last-ops) | ||
| 152 | (pushnew (car shr) last-nts) | ||
| 153 | (when (consp (cdr shr)) | ||
| 154 | (assert (not (member (cadr shr) nts))) | ||
| 155 | (pushnew (cadr shr) last-ops))))) | ||
| 156 | (push (cons nt first-ops) first-ops-table) | ||
| 157 | (push (cons nt last-ops) last-ops-table) | ||
| 158 | (push (cons nt first-nts) first-nts-table) | ||
| 159 | (push (cons nt last-nts) last-nts-table))) | ||
| 160 | ;; Compute all first-ops by propagating the initial ones we have | ||
| 161 | ;; now, according to first-nts. | ||
| 162 | (setq again t) | ||
| 163 | (while (prog1 again (setq again nil)) | ||
| 164 | (dolist (first-nts first-nts-table) | ||
| 165 | (let* ((nt (pop first-nts)) | ||
| 166 | (first-ops (assoc nt first-ops-table))) | ||
| 167 | (dolist (first-nt first-nts) | ||
| 168 | (dolist (op (cdr (assoc first-nt first-ops-table))) | ||
| 169 | (unless (member op first-ops) | ||
| 170 | (setq again t) | ||
| 171 | (push op (cdr first-ops)))))))) | ||
| 172 | ;; Same thing for last-ops. | ||
| 173 | (setq again t) | ||
| 174 | (while (prog1 again (setq again nil)) | ||
| 175 | (dolist (last-nts last-nts-table) | ||
| 176 | (let* ((nt (pop last-nts)) | ||
| 177 | (last-ops (assoc nt last-ops-table))) | ||
| 178 | (dolist (last-nt last-nts) | ||
| 179 | (dolist (op (cdr (assoc last-nt last-ops-table))) | ||
| 180 | (unless (member op last-ops) | ||
| 181 | (setq again t) | ||
| 182 | (push op (cdr last-ops)))))))) | ||
| 183 | ;; Now generate the 2D precedence table. | ||
| 184 | (dolist (rules bnf) | ||
| 185 | (dolist (rhs (cdr rules)) | ||
| 186 | (while (cdr rhs) | ||
| 187 | (cond | ||
| 188 | ((member (car rhs) nts) | ||
| 189 | (dolist (last (cdr (assoc (car rhs) last-ops-table))) | ||
| 190 | (smie-set-prec2tab prec2 last (cadr rhs) '> override))) | ||
| 191 | ((member (cadr rhs) nts) | ||
| 192 | (dolist (first (cdr (assoc (cadr rhs) first-ops-table))) | ||
| 193 | (smie-set-prec2tab prec2 (car rhs) first '< override)) | ||
| 194 | (if (and (cddr rhs) (not (member (car (cddr rhs)) nts))) | ||
| 195 | (smie-set-prec2tab prec2 (car rhs) (car (cddr rhs)) | ||
| 196 | '= override))) | ||
| 197 | (t (smie-set-prec2tab prec2 (car rhs) (cadr rhs) '= override))) | ||
| 198 | (setq rhs (cdr rhs))))) | ||
| 199 | prec2)) | ||
| 200 | |||
| 201 | (defun smie-prec2-levels (prec2) | ||
| 202 | "Take a 2D precedence table and turn it into an alist of precedence levels. | ||
| 203 | PREC2 is a table as returned by `smie-precs-precedence-table' or | ||
| 204 | `smie-bnf-precedence-table'." | ||
| 205 | ;; For each operator, we create two "variables" (corresponding to | ||
| 206 | ;; the left and right precedence level), which are represented by | ||
| 207 | ;; cons cells. Those are the vary cons cells that appear in the | ||
| 208 | ;; final `table'. The value of each "variable" is kept in the `car'. | ||
| 209 | (let ((table ()) | ||
| 210 | (csts ()) | ||
| 211 | (eqs ()) | ||
| 212 | tmp x y) | ||
| 213 | ;; From `prec2' we construct a list of constraints between | ||
| 214 | ;; variables (aka "precedence levels"). These can be either | ||
| 215 | ;; equality constraints (in `eqs') or `<' constraints (in `csts'). | ||
| 216 | (maphash (lambda (k v) | ||
| 217 | (if (setq tmp (assoc (car k) table)) | ||
| 218 | (setq x (cddr tmp)) | ||
| 219 | (setq x (cons nil nil)) | ||
| 220 | (push (cons (car k) (cons nil x)) table)) | ||
| 221 | (if (setq tmp (assoc (cdr k) table)) | ||
| 222 | (setq y (cdr tmp)) | ||
| 223 | (setq y (cons nil (cons nil nil))) | ||
| 224 | (push (cons (cdr k) y) table)) | ||
| 225 | (ecase v | ||
| 226 | (= (push (cons x y) eqs)) | ||
| 227 | (< (push (cons x y) csts)) | ||
| 228 | (> (push (cons y x) csts)))) | ||
| 229 | prec2) | ||
| 230 | ;; First process the equality constraints. | ||
| 231 | (let ((eqs eqs)) | ||
| 232 | (while eqs | ||
| 233 | (let ((from (caar eqs)) | ||
| 234 | (to (cdar eqs))) | ||
| 235 | (setq eqs (cdr eqs)) | ||
| 236 | (if (eq to from) | ||
| 237 | (debug) ;Can it happen? | ||
| 238 | (dolist (other-eq eqs) | ||
| 239 | (if (eq from (cdr other-eq)) (setcdr other-eq to)) | ||
| 240 | (when (eq from (car other-eq)) | ||
| 241 | ;; This can happen because of `assoc' settings in precs | ||
| 242 | ;; or because of a rhs like ("op" foo "op"). | ||
| 243 | (setcar other-eq to))) | ||
| 244 | (dolist (cst csts) | ||
| 245 | (if (eq from (cdr cst)) (setcdr cst to)) | ||
| 246 | (if (eq from (car cst)) (setcar cst to))))))) | ||
| 247 | ;; Then eliminate trivial constraints iteratively. | ||
| 248 | (let ((i 0)) | ||
| 249 | (while csts | ||
| 250 | (let ((rhvs (mapcar 'cdr csts)) | ||
| 251 | (progress nil)) | ||
| 252 | (dolist (cst csts) | ||
| 253 | (unless (memq (car cst) rhvs) | ||
| 254 | (setq progress t) | ||
| 255 | (setcar (car cst) i) | ||
| 256 | (setq csts (delq cst csts)))) | ||
| 257 | (unless progress | ||
| 258 | (error "Can't resolve the precedence table to precedence levels"))) | ||
| 259 | (incf i)) | ||
| 260 | ;; Propagate equalities back to their source. | ||
| 261 | (dolist (eq (nreverse eqs)) | ||
| 262 | (assert (null (caar eq))) | ||
| 263 | (setcar (car eq) (cadr eq))) | ||
| 264 | ;; Finally, fill in the remaining vars (which only appeared on the | ||
| 265 | ;; right side of the < constraints). | ||
| 266 | ;; Tho leaving them at nil is not a bad choice, since it makes | ||
| 267 | ;; it clear that these don't bind at all. | ||
| 268 | ;; (dolist (x table) | ||
| 269 | ;; (unless (nth 1 x) (setf (nth 1 x) i)) | ||
| 270 | ;; (unless (nth 2 x) (setf (nth 2 x) i))) | ||
| 271 | ) | ||
| 272 | table)) | ||
| 273 | |||
| 274 | ;;; Parsing using a precedence level table. | ||
| 275 | |||
| 276 | (defvar smie-op-levels 'unset | ||
| 277 | "List of token parsing info. | ||
| 278 | Each element is of the form (TOKEN LEFT-LEVEL RIGHT-LEVEL). | ||
| 279 | Parsing is done using an operator precedence parser.") | ||
| 280 | |||
| 281 | (defun smie-backward-token () | ||
| 282 | ;; FIXME: This may be an OK default but probably needs a hook. | ||
| 283 | (buffer-substring (point) | ||
| 284 | (progn (if (zerop (skip-syntax-backward ".")) | ||
| 285 | (skip-syntax-backward "w_'")) | ||
| 286 | (point)))) | ||
| 287 | |||
| 288 | (defun smie-forward-token () | ||
| 289 | ;; FIXME: This may be an OK default but probably needs a hook. | ||
| 290 | (buffer-substring (point) | ||
| 291 | (progn (if (zerop (skip-syntax-forward ".")) | ||
| 292 | (skip-syntax-forward "w_'")) | ||
| 293 | (point)))) | ||
| 294 | |||
| 295 | (defun smie-backward-sexp (&optional halfsexp) | ||
| 296 | "Skip over one sexp. | ||
| 297 | HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the | ||
| 298 | first token we see is an operator, skip over its left-hand-side argument. | ||
| 299 | Possible return values: | ||
| 300 | (LEFT-LEVEL POS TOKEN): we couldn't skip TOKEN because its right-level | ||
| 301 | is too high. LEFT-LEVEL is the left-level of TOKEN, | ||
| 302 | POS is its start position in the buffer. | ||
| 303 | (t POS TOKEN): Same thing but for an open-paren or the beginning of buffer. | ||
| 304 | (nil POS TOKEN): we skipped over a paren-like pair. | ||
| 305 | nil: we skipped over an identifier, matched parentheses, ..." | ||
| 306 | (if (bobp) (list t (point)) | ||
| 307 | (catch 'return | ||
| 308 | (let ((levels ())) | ||
| 309 | (while | ||
| 310 | (let* ((pos (point)) | ||
| 311 | (token (progn (forward-comment (- (point-max))) | ||
| 312 | (smie-backward-token))) | ||
| 313 | (toklevels (cdr (assoc token smie-op-levels)))) | ||
| 314 | |||
| 315 | (cond | ||
| 316 | ((null toklevels) | ||
| 317 | (if (equal token "") | ||
| 318 | (condition-case err | ||
| 319 | (progn (goto-char pos) (backward-sexp 1) nil) | ||
| 320 | (scan-error (throw 'return (list t (caddr err))))))) | ||
| 321 | ((null (nth 1 toklevels)) | ||
| 322 | ;; A token like a paren-close. | ||
| 323 | (assert (nth 0 toklevels)) ;Otherwise, why mention it? | ||
| 324 | (push (nth 0 toklevels) levels)) | ||
| 325 | (t | ||
| 326 | (while (and levels (< (nth 1 toklevels) (car levels))) | ||
| 327 | (setq levels (cdr levels))) | ||
| 328 | (cond | ||
| 329 | ((null levels) | ||
| 330 | (if (and halfsexp (nth 0 toklevels)) | ||
| 331 | (push (nth 0 toklevels) levels) | ||
| 332 | (throw 'return | ||
| 333 | (prog1 (list (or (car toklevels) t) (point) token) | ||
| 334 | (goto-char pos))))) | ||
| 335 | (t | ||
| 336 | (while (and levels (= (nth 1 toklevels) (car levels))) | ||
| 337 | (setq levels (cdr levels))) | ||
| 338 | (cond | ||
| 339 | ((null levels) | ||
| 340 | (cond | ||
| 341 | ((null (nth 0 toklevels)) | ||
| 342 | (throw 'return (list nil (point) token))) | ||
| 343 | ((eq (nth 0 toklevels) (nth 1 toklevels)) | ||
| 344 | (throw 'return | ||
| 345 | (prog1 (list (or (car toklevels) t) (point) token) | ||
| 346 | (goto-char pos)))) | ||
| 347 | (t (debug)))) ;Not sure yet what to do here. | ||
| 348 | (t | ||
| 349 | (if (nth 0 toklevels) | ||
| 350 | (push (nth 0 toklevels) levels)))))))) | ||
| 351 | levels) | ||
| 352 | (setq halfsexp nil)))))) | ||
| 353 | |||
| 354 | ;; Mirror image, not used for indentation. | ||
| 355 | (defun smie-forward-sexp (&optional halfsexp) | ||
| 356 | "Skip over one sexp. | ||
| 357 | HALFSEXP if non-nil, means skip over a partial sexp if needed. I.e. if the | ||
| 358 | first token we see is an operator, skip over its left-hand-side argument. | ||
| 359 | Possible return values: | ||
| 360 | (RIGHT-LEVEL POS TOKEN): we couldn't skip TOKEN because its left-level | ||
| 361 | is too high. RIGHT-LEVEL is the right-level of TOKEN, | ||
| 362 | POS is its end position in the buffer. | ||
| 363 | (t POS TOKEN): Same thing but for an open-paren or the beginning of buffer. | ||
| 364 | (nil POS TOKEN): we skipped over a paren-like pair. | ||
| 365 | nil: we skipped over an identifier, matched parentheses, ..." | ||
| 366 | (if (eobp) (list t (point)) | ||
| 367 | (catch 'return | ||
| 368 | (let ((levels ())) | ||
| 369 | (while | ||
| 370 | (let* ((pos (point)) | ||
| 371 | (token (progn (forward-comment (point-max)) | ||
| 372 | (smie-forward-token))) | ||
| 373 | (toklevels (cdr (assoc token smie-op-levels)))) | ||
| 374 | |||
| 375 | (cond | ||
| 376 | ((null toklevels) | ||
| 377 | (if (equal token "") | ||
| 378 | (condition-case err | ||
| 379 | (progn (goto-char pos) (forward-sexp 1) nil) | ||
| 380 | (scan-error (throw 'return (list t (caddr err))))))) | ||
| 381 | ((null (nth 0 toklevels)) | ||
| 382 | ;; A token like a paren-close. | ||
| 383 | (assert (nth 1 toklevels)) ;Otherwise, why mention it? | ||
| 384 | (push (nth 1 toklevels) levels)) | ||
| 385 | (t | ||
| 386 | (while (and levels (< (nth 0 toklevels) (car levels))) | ||
| 387 | (setq levels (cdr levels))) | ||
| 388 | (cond | ||
| 389 | ((null levels) | ||
| 390 | (if (and halfsexp (nth 1 toklevels)) | ||
| 391 | (push (nth 1 toklevels) levels) | ||
| 392 | (throw 'return | ||
| 393 | (prog1 (list (or (nth 1 toklevels) t) (point) token) | ||
| 394 | (goto-char pos))))) | ||
| 395 | (t | ||
| 396 | (while (and levels (= (nth 0 toklevels) (car levels))) | ||
| 397 | (setq levels (cdr levels))) | ||
| 398 | (cond | ||
| 399 | ((null levels) | ||
| 400 | (cond | ||
| 401 | ((null (nth 1 toklevels)) | ||
| 402 | (throw 'return (list nil (point) token))) | ||
| 403 | ((eq (nth 1 toklevels) (nth 0 toklevels)) | ||
| 404 | (throw 'return | ||
| 405 | (prog1 (list (or (nth 1 toklevels) t) (point) token) | ||
| 406 | (goto-char pos)))) | ||
| 407 | (t (debug)))) ;Not sure yet what to do here. | ||
| 408 | (t | ||
| 409 | (if (nth 1 toklevels) | ||
| 410 | (push (nth 1 toklevels) levels)))))))) | ||
| 411 | levels) | ||
| 412 | (setq halfsexp nil)))))) | ||
| 413 | |||
| 414 | (defun smie-backward-sexp-command (&optional n) | ||
| 415 | "Move backward through N logical elements." | ||
| 416 | (interactive "p") | ||
| 417 | (if (< n 0) | ||
| 418 | (smie-forward-sexp-command (- n)) | ||
| 419 | (let ((forward-sexp-function nil)) | ||
| 420 | (while (> n 0) | ||
| 421 | (decf n) | ||
| 422 | (let ((pos (point)) | ||
| 423 | (res (smie-backward-sexp 'halfsexp))) | ||
| 424 | (if (and (car res) (= pos (point)) (not (bolp))) | ||
| 425 | (signal 'scan-error | ||
| 426 | (list "Containing expression ends prematurely" | ||
| 427 | (cadr res) (cadr res))) | ||
| 428 | nil)))))) | ||
| 429 | |||
| 430 | (defun smie-forward-sexp-command (&optional n) | ||
| 431 | "Move forward through N logical elements." | ||
| 432 | (interactive "p") | ||
| 433 | (if (< n 0) | ||
| 434 | (smie-backward-sexp-command (- n)) | ||
| 435 | (let ((forward-sexp-function nil)) | ||
| 436 | (while (> n 0) | ||
| 437 | (decf n) | ||
| 438 | (let ((pos (point)) | ||
| 439 | (res (smie-forward-sexp 'halfsexp))) | ||
| 440 | (if (and (car res) (= pos (point)) (not (bolp))) | ||
| 441 | (signal 'scan-error | ||
| 442 | (list "Containing expression ends prematurely" | ||
| 443 | (cadr res) (cadr res))) | ||
| 444 | nil)))))) | ||
| 445 | |||
| 446 | ;;; The indentation engine. | ||
| 447 | |||
| 448 | (defcustom smie-indent-basic 4 | ||
| 449 | "Basic amount of indentation." | ||
| 450 | :type 'integer) | ||
| 451 | |||
| 452 | (defvar smie-indent-rules 'unset | ||
| 453 | "Rules of the following form. | ||
| 454 | \(TOK OFFSET) how to indent right after TOK. | ||
| 455 | \(TOK O1 O2) how to indent right after TOK: | ||
| 456 | O1 is the default; | ||
| 457 | O2 is used if TOK is \"hanging\". | ||
| 458 | \((T1 . T2) . OFFSET) how to indent token T2 w.r.t T1. | ||
| 459 | \((t . TOK) . OFFSET) how to indent TOK with respect to its parent. | ||
| 460 | \(list-intro . TOKENS) declare TOKENS as being followed by what may look like | ||
| 461 | a funcall but is just a sequence of expressions. | ||
| 462 | \(t . OFFSET) basic indentation step. | ||
| 463 | \(args . OFFSET) indentation of arguments. | ||
| 464 | A nil offset defaults to `smie-indent-basic'.") | ||
| 465 | |||
| 466 | (defun smie-indent-hanging-p () | ||
| 467 | ;; A Hanging keyword is one that's at the end of a line except it's not at | ||
| 468 | ;; the beginning of a line. | ||
| 469 | (and (save-excursion (smie-forward-token) | ||
| 470 | (skip-chars-forward " \t") (eolp)) | ||
| 471 | (save-excursion (skip-chars-backward " \t") (not (bolp))))) | ||
| 472 | |||
| 473 | (defun smie-bolp () | ||
| 474 | (save-excursion (skip-chars-backward " \t") (bolp))) | ||
| 475 | |||
| 476 | (defun smie-indent-offset (elem) | ||
| 477 | (or (cdr (assq elem smie-indent-rules)) | ||
| 478 | (cdr (assq t smie-indent-rules)) | ||
| 479 | smie-indent-basic)) | ||
| 480 | |||
| 481 | (defun smie-indent-calculate (&optional virtual) | ||
| 482 | "Compute the indentation to use for point. | ||
| 483 | If VIRTUAL is non-nil, it means we're not trying to indent point but just | ||
| 484 | need to compute the column at which point should be indented | ||
| 485 | in order to figure out the indentation of some other (further down) point. | ||
| 486 | VIRTUAL can take two different non-nil values: | ||
| 487 | - :bolp: means that the current indentation of point can be trusted | ||
| 488 | to be good only if if it follows a line break. | ||
| 489 | - :hanging: means that the current indentation of point can be | ||
| 490 | trusted to be good except if the following token is hanging." | ||
| 491 | ;; FIXME: This has accumulated a lot of rules, some of which aren't | ||
| 492 | ;; clearly orthogonal any more, so we should probably try and | ||
| 493 | ;; restructure it somewhat. | ||
| 494 | (or | ||
| 495 | ;; Trust pre-existing indentation on other lines. | ||
| 496 | (and virtual | ||
| 497 | (if (eq virtual :hanging) (not (smie-indent-hanging-p)) (smie-bolp)) | ||
| 498 | (current-column)) | ||
| 499 | ;; Align close paren with opening paren. | ||
| 500 | (save-excursion | ||
| 501 | ;; (forward-comment (point-max)) | ||
| 502 | (when (looking-at "\\s)") | ||
| 503 | (while (not (zerop (skip-syntax-forward ")"))) | ||
| 504 | (skip-chars-forward " \t")) | ||
| 505 | (condition-case nil | ||
| 506 | (progn | ||
| 507 | (backward-sexp 1) | ||
| 508 | (smie-indent-calculate :hanging)) | ||
| 509 | (scan-error nil)))) | ||
| 510 | ;; Align closing token with the corresponding opening one. | ||
| 511 | ;; (e.g. "of" with "case", or "in" with "let"). | ||
| 512 | (save-excursion | ||
| 513 | (let* ((pos (point)) | ||
| 514 | (token (smie-forward-token)) | ||
| 515 | (toklevels (cdr (assoc token smie-op-levels)))) | ||
| 516 | (when (car toklevels) | ||
| 517 | (let ((res (smie-backward-sexp 'halfsexp)) tmp) | ||
| 518 | ;; If we didn't move at all, that means we didn't really skip | ||
| 519 | ;; what we wanted. | ||
| 520 | (when (< (point) pos) | ||
| 521 | (cond | ||
| 522 | ((eq (car res) (car toklevels)) | ||
| 523 | ;; We bumped into a same-level operator. align with it. | ||
| 524 | (goto-char (cadr res)) | ||
| 525 | ;; Don't use (smie-indent-calculate :hanging) here, because we | ||
| 526 | ;; want to jump back over a sequence of same-level ops such as | ||
| 527 | ;; a -> b -> c | ||
| 528 | ;; -> d | ||
| 529 | ;; So as to align with the earliest appropriate place. | ||
| 530 | (smie-indent-calculate :bolp)) | ||
| 531 | ((equal token (save-excursion | ||
| 532 | (forward-comment (- (point-max))) | ||
| 533 | (smie-backward-token))) | ||
| 534 | ;; in cases such as "fn x => fn y => fn z =>", | ||
| 535 | ;; jump back to the very first fn. | ||
| 536 | ;; FIXME: should we only do that for special tokens like "=>"? | ||
| 537 | (smie-indent-calculate :bolp)) | ||
| 538 | ((setq tmp (assoc (cons (caddr res) token) | ||
| 539 | smie-indent-rules)) | ||
| 540 | (goto-char (cadr res)) | ||
| 541 | (+ (cdr tmp) (smie-indent-calculate :hanging))) | ||
| 542 | (t | ||
| 543 | (+ (or (cdr (assoc (cons t token) smie-indent-rules)) 0) | ||
| 544 | (current-column))))))))) | ||
| 545 | ;; Indentation of a comment. | ||
| 546 | (and (looking-at comment-start-skip) | ||
| 547 | (save-excursion | ||
| 548 | (forward-comment (point-max)) | ||
| 549 | (skip-chars-forward " \t\r\n") | ||
| 550 | (smie-indent-calculate nil))) | ||
| 551 | ;; Indentation inside a comment. | ||
| 552 | (and (looking-at "\\*") (nth 4 (syntax-ppss)) | ||
| 553 | (let ((ppss (syntax-ppss))) | ||
| 554 | (save-excursion | ||
| 555 | (forward-line -1) | ||
| 556 | (if (<= (point) (nth 8 ppss)) | ||
| 557 | (progn (goto-char (1+ (nth 8 ppss))) (current-column)) | ||
| 558 | (skip-chars-forward " \t") | ||
| 559 | (if (looking-at "\\*") | ||
| 560 | (current-column)))))) | ||
| 561 | ;; Indentation right after a special keyword. | ||
| 562 | (save-excursion | ||
| 563 | (let* ((tok (progn (forward-comment (- (point-max))) | ||
| 564 | (smie-backward-token))) | ||
| 565 | (tokinfo (assoc tok smie-indent-rules)) | ||
| 566 | (toklevel (assoc tok smie-op-levels))) | ||
| 567 | (when (or tokinfo (and toklevel (null (cadr toklevel)))) | ||
| 568 | (if (or (smie-indent-hanging-p) | ||
| 569 | ;; If calculating the virtual indentation point, prefer | ||
| 570 | ;; looking up the virtual indentation of the alignment | ||
| 571 | ;; point as well. This is used for indentation after | ||
| 572 | ;; "fn x => fn y =>". | ||
| 573 | virtual) | ||
| 574 | (+ (smie-indent-calculate :bolp) | ||
| 575 | (or (caddr tokinfo) (cadr tokinfo) (smie-indent-offset t))) | ||
| 576 | (+ (current-column) | ||
| 577 | (or (cadr tokinfo) (smie-indent-offset t))))))) | ||
| 578 | ;; Main loop (FIXME: whatever that means!?). | ||
| 579 | (save-excursion | ||
| 580 | (let ((positions nil) | ||
| 581 | (begline nil) | ||
| 582 | arg) | ||
| 583 | (while (and (null (car (smie-backward-sexp))) | ||
| 584 | (push (point) positions) | ||
| 585 | (not (setq begline (smie-bolp))))) | ||
| 586 | (save-excursion | ||
| 587 | ;; Figure out if the atom we just skipped is an argument rather | ||
| 588 | ;; than a function. | ||
| 589 | (setq arg (or (null (car (smie-backward-sexp))) | ||
| 590 | (member (progn (forward-comment (- (point-max))) | ||
| 591 | (smie-backward-token)) | ||
| 592 | (cdr (assoc 'list-intro smie-indent-rules)))))) | ||
| 593 | (cond | ||
| 594 | ((and arg positions) | ||
| 595 | (goto-char (car positions)) | ||
| 596 | (current-column)) | ||
| 597 | ((and (null begline) (cdr positions)) | ||
| 598 | ;; We skipped some args plus the function and bumped into something. | ||
| 599 | ;; Align with the first arg. | ||
| 600 | (goto-char (cadr positions)) | ||
| 601 | (current-column)) | ||
| 602 | ((and (null begline) positions) | ||
| 603 | ;; We're the first arg. | ||
| 604 | ;; FIXME: it might not be a funcall, in which case we might be the | ||
| 605 | ;; second element. | ||
| 606 | (goto-char (car positions)) | ||
| 607 | (+ (smie-indent-offset 'args) | ||
| 608 | ;; We used to use (smie-indent-calculate :bolp), but that | ||
| 609 | ;; doesn't seem right since it might then indent args less than | ||
| 610 | ;; the function itself. | ||
| 611 | (current-column))) | ||
| 612 | ((and (null arg) (null positions)) | ||
| 613 | ;; We're the function itself. Not sure what to do here yet. | ||
| 614 | (if virtual (current-column) | ||
| 615 | (save-excursion | ||
| 616 | (let* ((pos (point)) | ||
| 617 | (tok (progn (forward-comment (- (point-max))) | ||
| 618 | (smie-backward-token))) | ||
| 619 | (toklevels (cdr (assoc tok smie-op-levels)))) | ||
| 620 | (cond | ||
| 621 | ((numberp (car toklevels)) | ||
| 622 | ;; We're right after an infix token. Let's skip over the | ||
| 623 | ;; lefthand side. | ||
| 624 | (goto-char pos) | ||
| 625 | (let (res) | ||
| 626 | (while (progn (setq res (smie-backward-sexp 'halfsexp)) | ||
| 627 | (and (not (smie-bolp)) | ||
| 628 | (equal (car res) (car toklevels))))) | ||
| 629 | ;; We should be right after a token of equal or | ||
| 630 | ;; higher precedence. | ||
| 631 | (cond | ||
| 632 | ((and (consp res) (memq (car res) '(t nil))) | ||
| 633 | ;; The token of higher-precedence is like an open-paren. | ||
| 634 | ;; Sample case for t: foo { bar, \n[TAB] baz }. | ||
| 635 | ;; Sample case for nil: match ... with \n[TAB] | toto ... | ||
| 636 | ;; (goto-char (cadr res)) | ||
| 637 | (smie-indent-calculate :hanging)) | ||
| 638 | ((and (consp res) (<= (car res) (car toklevels))) | ||
| 639 | ;; We stopped at a token of equal or higher precedence | ||
| 640 | ;; because we found a place with which to align. | ||
| 641 | (current-column)) | ||
| 642 | ))) | ||
| 643 | ;; For other cases.... hmm... we'll see when we get there. | ||
| 644 | ))))) | ||
| 645 | ((null positions) | ||
| 646 | (smie-backward-token) | ||
| 647 | (+ (smie-indent-offset 'args) (smie-indent-calculate :bolp))) | ||
| 648 | ((car (smie-backward-sexp)) | ||
| 649 | ;; No arg stands on its own line, but the function does: | ||
| 650 | (if (cdr positions) | ||
| 651 | (progn | ||
| 652 | (goto-char (cadr positions)) | ||
| 653 | (current-column)) | ||
| 654 | (goto-char (car positions)) | ||
| 655 | (+ (current-column) (smie-indent-offset 'args)))) | ||
| 656 | (t | ||
| 657 | ;; We've skipped to a previous arg on its own line: align. | ||
| 658 | (goto-char (car positions)) | ||
| 659 | (current-column))))))) | ||
| 660 | |||
| 661 | (defun smie-indent-line () | ||
| 662 | "Indent current line using the SMIE indentation engine." | ||
| 663 | (interactive) | ||
| 664 | (let* ((savep (point)) | ||
| 665 | (indent (condition-case nil | ||
| 666 | (save-excursion | ||
| 667 | (forward-line 0) | ||
| 668 | (skip-chars-forward " \t") | ||
| 669 | (if (>= (point) savep) (setq savep nil)) | ||
| 670 | (or (smie-indent-calculate) 0)) | ||
| 671 | (error 0)))) | ||
| 672 | (if (not (numberp indent)) | ||
| 673 | ;; If something funny is used (e.g. `noindent'), return it. | ||
| 674 | indent | ||
| 675 | (if (< indent 0) (setq indent 0)) ;Just in case. | ||
| 676 | (if savep | ||
| 677 | (save-excursion (indent-line-to indent)) | ||
| 678 | (indent-line-to indent))))) | ||
| 679 | |||
| 680 | ;;;###autoload | ||
| 681 | (defun smie-setup (op-levels indent-rules) | ||
| 682 | (set (make-local-variable 'smie-indent-rules) indent-rules) | ||
| 683 | (set (make-local-variable 'smie-op-levels) op-levels) | ||
| 684 | (set (make-local-variable 'indent-line-function) 'smie-indent-line)) | ||
| 685 | |||
| 686 | |||
| 687 | (provide 'smie) | ||
| 688 | ;;; smie.el ends here | ||
diff --git a/lisp/progmodes/prolog.el b/lisp/progmodes/prolog.el index 5bca3502af9..891f3610f96 100644 --- a/lisp/progmodes/prolog.el +++ b/lisp/progmodes/prolog.el | |||
| @@ -98,6 +98,61 @@ When nil, send actual operating system end of file." | |||
| 98 | (defvar prolog-mode-abbrev-table nil) | 98 | (defvar prolog-mode-abbrev-table nil) |
| 99 | (define-abbrev-table 'prolog-mode-abbrev-table ()) | 99 | (define-abbrev-table 'prolog-mode-abbrev-table ()) |
| 100 | 100 | ||
| 101 | (defconst prolog-smie-op-levels | ||
| 102 | ;; Rather than construct the operator levels table from the BNF, | ||
| 103 | ;; we directly provide the operator precedences from GNU Prolog's | ||
| 104 | ;; manual. The only problem is that GNU Prolog's manual uses | ||
| 105 | ;; precedence levels in the opposite sense (higher numbers bind less | ||
| 106 | ;; tightly) than SMIE, so we use negative numbers. | ||
| 107 | '(("." -10000 -10000) | ||
| 108 | (":-" -1200 -1200) | ||
| 109 | ("-->" -1200 -1200) | ||
| 110 | (";" -1100 -1100) | ||
| 111 | ("->" -1050 -1050) | ||
| 112 | ("," -1000 -1000) | ||
| 113 | ("\\+" -900 -900) | ||
| 114 | ("=" -700 -700) | ||
| 115 | ("\\=" -700 -700) | ||
| 116 | ("=.." -700 -700) | ||
| 117 | ("==" -700 -700) | ||
| 118 | ("\\==" -700 -700) | ||
| 119 | ("@<" -700 -700) | ||
| 120 | ("@=<" -700 -700) | ||
| 121 | ("@>" -700 -700) | ||
| 122 | ("@>=" -700 -700) | ||
| 123 | ("is" -700 -700) | ||
| 124 | ("=:=" -700 -700) | ||
| 125 | ("=\\=" -700 -700) | ||
| 126 | ("<" -700 -700) | ||
| 127 | ("=<" -700 -700) | ||
| 128 | (">" -700 -700) | ||
| 129 | (">=" -700 -700) | ||
| 130 | (":" -600 -600) | ||
| 131 | ("+" -500 -500) | ||
| 132 | ("-" -500 -500) | ||
| 133 | ("/\\" -500 -500) | ||
| 134 | ("\\/" -500 -500) | ||
| 135 | ("*" -400 -400) | ||
| 136 | ("/" -400 -400) | ||
| 137 | ("//" -400 -400) | ||
| 138 | ("rem" -400 -400) | ||
| 139 | ("mod" -400 -400) | ||
| 140 | ("<<" -400 -400) | ||
| 141 | (">>" -400 -400) | ||
| 142 | ("**" -200 -200) | ||
| 143 | ("^" -200 -200) | ||
| 144 | ;; Prefix | ||
| 145 | ;; ("+" 200 200) | ||
| 146 | ;; ("-" 200 200) | ||
| 147 | ;; ("\\" 200 200) | ||
| 148 | ) | ||
| 149 | "Precedence levels of infix operators.") | ||
| 150 | |||
| 151 | (defconst prolog-smie-indent-rules | ||
| 152 | '((":-") | ||
| 153 | ("->")) | ||
| 154 | "Prolog indentation rules.") | ||
| 155 | |||
| 101 | (defun prolog-mode-variables () | 156 | (defun prolog-mode-variables () |
| 102 | (make-local-variable 'paragraph-separate) | 157 | (make-local-variable 'paragraph-separate) |
| 103 | (setq paragraph-separate (concat "%%\\|$\\|" page-delimiter)) ;'%%..' | 158 | (setq paragraph-separate (concat "%%\\|$\\|" page-delimiter)) ;'%%..' |
| @@ -105,8 +160,10 @@ When nil, send actual operating system end of file." | |||
| 105 | (setq paragraph-ignore-fill-prefix t) | 160 | (setq paragraph-ignore-fill-prefix t) |
| 106 | (make-local-variable 'imenu-generic-expression) | 161 | (make-local-variable 'imenu-generic-expression) |
| 107 | (setq imenu-generic-expression '((nil "^\\sw+" 0))) | 162 | (setq imenu-generic-expression '((nil "^\\sw+" 0))) |
| 108 | (make-local-variable 'indent-line-function) | 163 | (smie-setup prolog-smie-op-levels prolog-smie-indent-rules) |
| 109 | (setq indent-line-function 'prolog-indent-line) | 164 | (set (make-local-variable 'forward-sexp-function) |
| 165 | 'smie-forward-sexp-command) | ||
| 166 | (set (make-local-variable 'smie-indent-basic) prolog-indent-width) | ||
| 110 | (make-local-variable 'comment-start) | 167 | (make-local-variable 'comment-start) |
| 111 | (setq comment-start "%") | 168 | (setq comment-start "%") |
| 112 | (make-local-variable 'comment-start-skip) | 169 | (make-local-variable 'comment-start-skip) |
| @@ -149,65 +206,6 @@ if that value is non-nil." | |||
| 149 | nil nil nil | 206 | nil nil nil |
| 150 | beginning-of-line))) | 207 | beginning-of-line))) |
| 151 | 208 | ||
| 152 | (defun prolog-indent-line () | ||
| 153 | "Indent current line as Prolog code. | ||
| 154 | With argument, indent any additional lines of the same clause | ||
| 155 | rigidly along with this one (not yet)." | ||
| 156 | (interactive "p") | ||
| 157 | (let ((indent (prolog-indent-level)) | ||
| 158 | (pos (- (point-max) (point)))) | ||
| 159 | (beginning-of-line) | ||
| 160 | (indent-line-to indent) | ||
| 161 | (if (> (- (point-max) pos) (point)) | ||
| 162 | (goto-char (- (point-max) pos))))) | ||
| 163 | |||
| 164 | (defun prolog-indent-level () | ||
| 165 | "Compute Prolog indentation level." | ||
| 166 | (save-excursion | ||
| 167 | (beginning-of-line) | ||
| 168 | (skip-chars-forward " \t") | ||
| 169 | (cond | ||
| 170 | ((looking-at "%%%") 0) ;Large comment starts | ||
| 171 | ((looking-at "%[^%]") comment-column) ;Small comment starts | ||
| 172 | ((bobp) 0) ;Beginning of buffer | ||
| 173 | (t | ||
| 174 | (let ((empty t) ind more less) | ||
| 175 | (if (looking-at ")") | ||
| 176 | (setq less t) ;Find close | ||
| 177 | (setq less nil)) | ||
| 178 | ;; See previous indentation | ||
| 179 | (while empty | ||
| 180 | (forward-line -1) | ||
| 181 | (beginning-of-line) | ||
| 182 | (if (bobp) | ||
| 183 | (setq empty nil) | ||
| 184 | (skip-chars-forward " \t") | ||
| 185 | (if (not (or (looking-at "%[^%]") (looking-at "\n"))) | ||
| 186 | (setq empty nil)))) | ||
| 187 | (if (bobp) | ||
| 188 | (setq ind 0) ;Beginning of buffer | ||
| 189 | (setq ind (current-column))) ;Beginning of clause | ||
| 190 | ;; See its beginning | ||
| 191 | (if (looking-at "%%[^%]") | ||
| 192 | ind | ||
| 193 | ;; Real prolog code | ||
| 194 | (if (looking-at "(") | ||
| 195 | (setq more t) ;Find open | ||
| 196 | (setq more nil)) | ||
| 197 | ;; See its tail | ||
| 198 | (end-of-prolog-clause) | ||
| 199 | (or (bobp) (forward-char -1)) | ||
| 200 | (cond ((looking-at "[,(;>]") | ||
| 201 | (if (and more (looking-at "[^,]")) | ||
| 202 | (+ ind prolog-indent-width) ;More indentation | ||
| 203 | (max tab-width ind))) ;Same indentation | ||
| 204 | ((looking-at "-") tab-width) ;TAB | ||
| 205 | ((or less (looking-at "[^.]")) | ||
| 206 | (max (- ind prolog-indent-width) 0)) ;Less indentation | ||
| 207 | (t 0)) ;No indentation | ||
| 208 | ))) | ||
| 209 | ))) | ||
| 210 | |||
| 211 | (defun end-of-prolog-clause () | 209 | (defun end-of-prolog-clause () |
| 212 | "Go to end of clause in this line." | 210 | "Go to end of clause in this line." |
| 213 | (beginning-of-line 1) | 211 | (beginning-of-line 1) |
diff --git a/lisp/simple.el b/lisp/simple.el index f0c38093d86..48e1148ae6b 100644 --- a/lisp/simple.el +++ b/lisp/simple.el | |||
| @@ -2077,7 +2077,11 @@ to `shell-command-history'." | |||
| 2077 | 2077 | ||
| 2078 | Like `shell-command' but if COMMAND doesn't end in ampersand, adds `&' | 2078 | Like `shell-command' but if COMMAND doesn't end in ampersand, adds `&' |
| 2079 | surrounded by whitespace and executes the command asynchronously. | 2079 | surrounded by whitespace and executes the command asynchronously. |
| 2080 | The output appears in the buffer `*Async Shell Command*'." | 2080 | The output appears in the buffer `*Async Shell Command*'. |
| 2081 | |||
| 2082 | In Elisp, you will often be better served by calling `start-process' | ||
| 2083 | directly, since it offers more control and does not impose the use of a | ||
| 2084 | shell (with its need to quote arguments)." | ||
| 2081 | (interactive | 2085 | (interactive |
| 2082 | (list | 2086 | (list |
| 2083 | (read-shell-command "Async shell command: " nil nil | 2087 | (read-shell-command "Async shell command: " nil nil |
| @@ -2138,7 +2142,11 @@ If the optional third argument ERROR-BUFFER is non-nil, it is a buffer | |||
| 2138 | or buffer name to which to direct the command's standard error output. | 2142 | or buffer name to which to direct the command's standard error output. |
| 2139 | If it is nil, error output is mingled with regular output. | 2143 | If it is nil, error output is mingled with regular output. |
| 2140 | In an interactive call, the variable `shell-command-default-error-buffer' | 2144 | In an interactive call, the variable `shell-command-default-error-buffer' |
| 2141 | specifies the value of ERROR-BUFFER." | 2145 | specifies the value of ERROR-BUFFER. |
| 2146 | |||
| 2147 | In Elisp, you will often be better served by calling `call-process' or | ||
| 2148 | `start-process' directly, since it offers more control and does not impose | ||
| 2149 | the use of a shell (with its need to quote arguments)." | ||
| 2142 | 2150 | ||
| 2143 | (interactive | 2151 | (interactive |
| 2144 | (list | 2152 | (list |