# HG changeset patch # User Stefan Monnier # Date 1288380028 14400 # Node ID a9904c1962db38a3d717ee3ea039ec5c7428f45d # Parent d66d04803828dca16937d0c20aa867f9a5fb2756 SMIE: change indent rules format, improve smie-setup. * lisp/emacs-lisp/smie.el (smie-precs-precedence-table) (smie-merge-prec2s, smie-bnf-precedence-table, smie-prec2-levels): Mark them pure so the tables gets built at compile time. (smie-bnf-precedence-table): Store the closer-alist in the table. (smie-prec2-levels): Preserve the closer-alist. (smie-blink-matching-open): Be more forgiving in case of indentation. (smie-hanging-p): Rename from smie-indent--hanging-p. (smie-bolp): Rename from smie-indent--bolp. (smie--parent, smie--after): New dynamic vars. (smie-parent-p, smie-next-p, smie-prev-p): New funs. (smie-indent-rules): Remove. (smie-indent--offset-rule): Remove fun. (smie-rules-function): New var. (smie-indent--rule): New fun. (smie-indent--offset, smie-indent-keyword, smie-indent-after-keyword) (smie-indent-exps): Use it. (smie-setup): Setup paren blinking; add keyword args for token functions; extract closer-alist from op-levels. (smie-indent-debug-log): Remove var. (smie-indent-debug): Remove fun. * lisp/progmodes/prolog.el (prolog-smie-indent-rules): Remove. (prolog-smie-rules): New fun to replace it. (prolog-mode-variables): Simplify. * lisp/progmodes/octave-mod.el (octave-smie-closer-alist): Remove, now that it's setup automatically. (octave-smie-indent-rules): Remove. (octave-smie-rules): New fun to replace it. (octave-mode): Simplify. diff -r d66d04803828 -r a9904c1962db etc/NEWS --- a/etc/NEWS Fri Oct 29 13:51:15 2010 +0000 +++ b/etc/NEWS Fri Oct 29 15:20:28 2010 -0400 @@ -587,6 +587,8 @@ * Incompatible Lisp Changes in Emacs 24.1 +** Remove obsolete name `e' (use `float-e' instead). + ** A backquote not followed by a space is now always treated as new-style. ** Test for special mode-class was moved from view-file to view-buffer. diff -r d66d04803828 -r a9904c1962db lisp/ChangeLog --- a/lisp/ChangeLog Fri Oct 29 13:51:15 2010 +0000 +++ b/lisp/ChangeLog Fri Oct 29 15:20:28 2010 -0400 @@ -1,3 +1,35 @@ +2010-10-29 Stefan Monnier + + SMIE: change indent rules format, improve smie-setup. + * emacs-lisp/smie.el (smie-precs-precedence-table) + (smie-merge-prec2s, smie-bnf-precedence-table, smie-prec2-levels): + Mark them pure so the tables gets built at compile time. + (smie-bnf-precedence-table): Store the closer-alist in the table. + (smie-prec2-levels): Preserve the closer-alist. + (smie-blink-matching-open): Be more forgiving in case of indentation. + (smie-hanging-p): Rename from smie-indent--hanging-p. + (smie-bolp): Rename from smie-indent--bolp. + (smie--parent, smie--after): New dynamic vars. + (smie-parent-p, smie-next-p, smie-prev-p): New funs. + (smie-indent-rules): Remove. + (smie-indent--offset-rule): Remove fun. + (smie-rules-function): New var. + (smie-indent--rule): New fun. + (smie-indent--offset, smie-indent-keyword, smie-indent-after-keyword) + (smie-indent-exps): Use it. + (smie-setup): Setup paren blinking; add keyword args for token + functions; extract closer-alist from op-levels. + (smie-indent-debug-log): Remove var. + (smie-indent-debug): Remove fun. + * progmodes/prolog.el (prolog-smie-indent-rules): Remove. + (prolog-smie-rules): New fun to replace it. + (prolog-mode-variables): Simplify. + * progmodes/octave-mod.el (octave-smie-closer-alist): Remove, now that + it's setup automatically. + (octave-smie-indent-rules): Remove. + (octave-smie-rules): New fun to replace it. + (octave-mode): Simplify. + 2010-10-29 Glenn Morris * files.el (temporary-file-directory): Remove (already defined in C). diff -r d66d04803828 -r a9904c1962db lisp/emacs-lisp/smie.el --- a/lisp/emacs-lisp/smie.el Fri Oct 29 13:51:15 2010 +0000 +++ b/lisp/emacs-lisp/smie.el Fri Oct 29 15:20:28 2010 -0400 @@ -109,6 +109,7 @@ (display-warning 'smie (format "Conflict: %s %s/%s %s" x old val y))) (puthash key val table)))) +(put 'smie-precs-precedence-table 'pure t) (defun smie-precs-precedence-table (precs) "Compute a 2D precedence table from a list of precedences. PRECS should be a list, sorted by precedence (e.g. \"+\" will @@ -132,6 +133,7 @@ (smie-set-prec2tab prec2-table other-op op op1))))))) prec2-table)) +(put 'smie-merge-prec2s 'pure t) (defun smie-merge-prec2s (&rest tables) (if (null (cdr tables)) (car tables) @@ -147,6 +149,7 @@ table)) prec2))) +(put 'smie-bnf-precedence-table 'pure t) (defun smie-bnf-precedence-table (bnf &rest precs) (let ((nts (mapcar 'car bnf)) ;Non-terminals (first-ops-table ()) @@ -233,6 +236,7 @@ ;; Keep track of which tokens are openers/closer, so they can get a nil ;; precedence in smie-prec2-levels. (puthash :smie-open/close-alist (smie-bnf-classify bnf) prec2) + (puthash :smie-closer-alist (smie-bnf-closer-alist bnf) prec2) prec2)) ;; (defun smie-prec2-closer-alist (prec2 include-inners) @@ -377,6 +381,7 @@ (append names (list (car names))) " < "))) +(put 'smie-prec2-levels 'pure t) (defun smie-prec2-levels (prec2) ;; FIXME: Rather than only return an alist of precedence levels, we should ;; also extract other useful data from it: @@ -479,6 +484,8 @@ (eq 'closer (cdr (assoc (car x) classification-table)))) (setf (nth 2 x) i) (incf i))))) ;See other (incf i) above. + (let ((ca (gethash :smie-closer-alist prec2))) + (when ca (push (cons :smie-closer-alist ca) table))) table)) ;;; Parsing using a precedence level table. @@ -803,14 +810,22 @@ (defun smie-blink-matching-open () "Blink the matching opener when applicable. This uses SMIE's tables and is expected to be placed on `post-self-insert-hook'." + (let ((pos (point)) ;Position after the close token. + token) (when (and blink-matching-paren smie-closer-alist ; Optimization. - (eq (char-before) last-command-event) ; Sanity check. + (or (eq (char-before) last-command-event) ;; Sanity check. + (save-excursion + (or (progn (skip-chars-backward " \t") + (setq pos (point)) + (eq (char-before) last-command-event)) + (progn (skip-chars-backward " \n\t") + (setq pos (point)) + (eq (char-before) last-command-event))))) (memq last-command-event smie-blink-matching-triggers) (not (nth 8 (syntax-ppss)))) (save-excursion - (let ((pos (point)) - (token (funcall smie-backward-token-function))) + (setq token (funcall smie-backward-token-function)) (when (and (eq (point) (1- pos)) (= 1 (length token)) (not (rassoc token smie-closer-alist))) @@ -818,17 +833,20 @@ ;; closers (e.g. ?\; in Octave mode), so go back to the ;; previous token. (setq pos (point)) - (setq token (save-excursion - (funcall smie-backward-token-function)))) + (setq token (funcall smie-backward-token-function))) (when (rassoc token smie-closer-alist) ;; We're after a close token. Let's still make sure we ;; didn't skip a comment to find that token. (funcall smie-forward-token-function) (when (and (save-excursion - ;; Trigger can be SPC, or reindent. - (skip-chars-forward " \n\t") + ;; Skip the trigger char, if applicable. + (if (eq (char-after) last-command-event) + (forward-char 1)) + (if (eq ?\n last-command-event) + ;; Skip any auto-indentation, if applicable. + (skip-chars-forward " \t")) (>= (point) pos)) - ;; If token ends with a trigger char, so don't blink for + ;; If token ends with a trigger char, don't blink for ;; anything else than this trigger char, lest we'd blink ;; both when inserting the trigger char and when ;; inserting a subsequent trigger char like SPC. @@ -850,34 +868,25 @@ "Basic amount of indentation." :type 'integer) -(defvar smie-indent-rules 'unset - ;; TODO: For SML, we need more rule formats, so as to handle - ;; structure Foo = - ;; Bar (toto) - ;; and - ;; structure Foo = - ;; struct ... end - ;; I.e. the indentation after "=" depends on the parent ("structure") - ;; as well as on the following token ("struct"). - "Rules of the following form. -\((:before . TOK) . OFFSET-RULES) how to indent TOK itself. -\(TOK . OFFSET-RULES) how to indent right after TOK. -\(list-intro . TOKENS) declare TOKENS as being followed by what may look like - a funcall but is just a sequence of expressions. -\(t . OFFSET) basic indentation step. -\(args . OFFSET) indentation of arguments. -\((T1 . T2) OFFSET) like ((:before . T2) (:parent T1 OFFSET)). +(defvar smie-rules-function 'ignore + "Function providing the indentation rules. +It takes two arguments METHOD and ARG where the meaning of ARG +and the expected return value depends on METHOD. +METHOD can be: +- :after, in which case ARG is a token and the function should return the + OFFSET to use for indentation after ARG. +- :before, in which case ARG is a token and the function should return the + OFFSET to use to indent ARG itself. +- :elem, in which case the function should return either: + - the offset to use to indent function arguments (ARG = `arg') + - the basic indentation step (ARG = `basic'). +- :list-intro, in which case ARG is a token and the function should return + non-nil if TOKEN is followed by a list of expressions (not separated by any + token) rather than an expression. -OFFSET-RULES is a list of elements which can each either be: - -\(:hanging . OFFSET-RULES) if TOK is hanging, use OFFSET-RULES. -\(:parent PARENT . OFFSET-RULES) if TOK's parent is PARENT, use OFFSET-RULES. -\(:next TOKEN . OFFSET-RULES) if TOK is followed by TOKEN, use OFFSET-RULES. -\(:prev TOKEN . OFFSET-RULES) if TOK is preceded by TOKEN, use -\(:bolp . OFFSET-RULES) If TOK is first on a line, use OFFSET-RULES. -OFFSET the offset to use. - -PARENT can be either the name of the parent or a list of such names. +When ARG is a token, the function is called with point just before that token. +A return value of nil always means to fallback on the default behavior, so the +function should return nil for arguments it does not expect. OFFSET can be of the form: `point' align with the token. @@ -886,91 +895,69 @@ \(+ OFFSETS...) use the sum of OFFSETS. VARIABLE use the value of VARIABLE as offset. -The precise meaning of `point' depends on various details: it can -either mean the position of the token we're indenting, or the -position of its parent, or the position right after its parent. +This function will often use some of the following functions designed +specifically for it: +`smie-bolp', `smie-hanging-p', `smie-parent-p', `smie-next-p', `smie-prev-p'.") -A nil offset for indentation after an opening token defaults -to `smie-indent-basic'.") - -(defun smie-indent--hanging-p () - ;; A hanging keyword is one that's at the end of a line except it's not at - ;; the beginning of a line. - (and (save-excursion +(defun smie-hanging-p () + "Return non-nil if the current token is \"hanging\". +A hanging keyword is one that's at the end of a line except it's not at +the beginning of a line." + (and (not (smie-bolp)) + (save-excursion (when (zerop (length (funcall smie-forward-token-function))) ;; Could be an open-paren. (forward-char 1)) (skip-chars-forward " \t") - (eolp)) - (not (smie-indent--bolp)))) + (eolp)))) -(defun smie-indent--bolp () +(defun smie-bolp () + "Return non-nil if the current token is the first on the line." (save-excursion (skip-chars-backward " \t") (bolp))) +(defvar smie--parent) (defvar smie--after) ;Dynamically scoped. + +(defun smie-parent-p (&rest parents) + "Return non-nil if the current token's parent is among PARENTS. +Only meaningful when called from within `smie-rules-function'." + (member (nth 2 (or smie--parent + (save-excursion + (let* ((pos (point)) + (tok (funcall smie-forward-token-function))) + (unless (cadr (assoc tok smie-op-levels)) + (goto-char pos)) + (setq smie--parent + (smie-backward-sexp 'halfsexp)))))) + parents)) + +(defun smie-next-p (&rest tokens) + "Return non-nil if the next token is among TOKENS. +Only meaningful when called from within `smie-rules-function'." + (let ((next + (save-excursion + (unless smie--after + (smie-indent-forward-token) (setq smie--after (point))) + (goto-char smie--after) + (smie-indent-forward-token)))) + (member (car next) tokens))) + +(defun smie-prev-p (&rest tokens) + "Return non-nil if the previous token is among TOKENS." + (let ((prev (save-excursion + (smie-indent-backward-token)))) + (member (car prev) tokens))) + + (defun smie-indent--offset (elem) - (or (cdr (assq elem smie-indent-rules)) - (cdr (assq t smie-indent-rules)) + (or (funcall smie-rules-function :elem elem) + (if (not (eq elem 'basic)) + (funcall smie-rules-function :elem 'basic)) smie-indent-basic)) -(defvar smie-indent-debug-log) - -(defun smie-indent--offset-rule (tokinfo &optional after parent) - "Apply the OFFSET-RULES in TOKINFO. -Point is expected to be right in front of the token corresponding to TOKINFO. -If computing the indentation after the token, then AFTER is the position -after the token, otherwise it should be nil. -PARENT if non-nil should be the parent info returned by `smie-backward-sexp'." - (let ((rules (cdr tokinfo)) - next prev - offset) - (while (consp rules) - (let ((rule (pop rules))) - (cond - ((not (consp rule)) (setq offset rule)) - ((eq (car rule) '+) (setq offset rule)) - ((eq (car rule) :hanging) - (when (smie-indent--hanging-p) - (setq rules (cdr rule)))) - ((eq (car rule) :bolp) - (when (smie-indent--bolp) - (setq rules (cdr rule)))) - ((eq (car rule) :eolp) - (unless after - (error "Can't use :eolp in :before indentation rules")) - (when (> after (line-end-position)) - (setq rules (cdr rule)))) - ((eq (car rule) :prev) - (unless prev - (save-excursion - (setq prev (smie-indent-backward-token)))) - (when (equal (car prev) (cadr rule)) - (setq rules (cddr rule)))) - ((eq (car rule) :next) - (unless next - (unless after - (error "Can't use :next in :before indentation rules")) - (save-excursion - (goto-char after) - (setq next (smie-indent-forward-token)))) - (when (equal (car next) (cadr rule)) - (setq rules (cddr rule)))) - ((eq (car rule) :parent) - (unless parent - (save-excursion - (if after (goto-char after)) - (setq parent (smie-backward-sexp 'halfsexp)))) - (when (if (listp (cadr rule)) - (member (nth 2 parent) (cadr rule)) - (equal (nth 2 parent) (cadr rule))) - (setq rules (cddr rule)))) - (t (error "Unknown rule %s for indentation of %s" - rule (car tokinfo)))))) - ;; If `offset' is not set yet, use `rules' to handle the case where - ;; the tokinfo uses the old-style ((PARENT . TOK). OFFSET). - (unless offset (setq offset rules)) - (when (boundp 'smie-indent-debug-log) - (push (list (point) offset tokinfo) smie-indent-debug-log)) - offset)) +(defun smie-indent--rule (kind token &optional after parent) + (let ((smie--parent parent) + (smie--after after)) + (funcall smie-rules-function kind token))) (defun smie-indent--column (offset &optional base parent virtual-point) "Compute the actual column to use for a given OFFSET. @@ -1012,6 +999,9 @@ (if (consp parent) (goto-char (cadr parent))) (smie-indent-virtual)) ((eq offset nil) nil) + ;; FIXME: would be good to get rid of this since smie-rules-function + ;; can usually do the lookup trivially, but in cases where + ;; smie-rules-function returns (+ point VAR) it's not nearly as trivial. ((and (symbolp offset) (boundp 'offset)) (smie-indent--column (symbol-value offset) base parent virtual-point)) (t (error "Unknown indentation offset %s" offset)))) @@ -1046,11 +1036,11 @@ need to compute the column at which point should be indented in order to figure out the indentation of some other (further down) point." ;; Trust pre-existing indentation on other lines. - (if (smie-indent--bolp) (current-column) (smie-indent-calculate))) + (if (smie-bolp) (current-column) (smie-indent-calculate))) (defun smie-indent-fixindent () ;; Obey the `fixindent' special comment. - (and (smie-indent--bolp) + (and (smie-bolp) (save-excursion (comment-normalize-vars) (re-search-forward (concat comment-start-skip @@ -1090,43 +1080,31 @@ (save-excursion (goto-char pos) ;; Different cases: - ;; - smie-indent--bolp: "indent according to others". + ;; - smie-bolp: "indent according to others". ;; - common hanging: "indent according to others". ;; - SML-let hanging: "indent like parent". ;; - if-after-else: "indent-like parent". ;; - middle-of-line: "trust current position". (cond ((null (cdr toklevels)) nil) ;Not a keyword. - ((smie-indent--bolp) + ((smie-bolp) ;; For an open-paren-like thingy at BOL, always indent only ;; based on other rules (typically smie-indent-after-keyword). nil) (t ;; We're only ever here for virtual-indent, which is why ;; we can use (current-column) as answer for `point'. - (let* ((tokinfo (or (assoc (cons :before token) - smie-indent-rules) + (let* ((offset (or (smie-indent--rule :before token) ;; By default use point unless we're hanging. - `((:before . ,token) (:hanging nil) point))) - ;; (after (prog1 (point) (goto-char pos))) - (offset (smie-indent--offset-rule tokinfo))) + (unless (smie-hanging-p) 'point)))) (smie-indent--column offset))))) ;; FIXME: This still looks too much like black magic!! - ;; FIXME: Rather than a bunch of rules like (PARENT . TOKEN), we - ;; want a single rule for TOKEN with different cases for each PARENT. (let* ((parent (smie-backward-sexp 'halfsexp)) - (tokinfo - (or (assoc (cons (caddr parent) token) - smie-indent-rules) - (assoc (cons :before token) smie-indent-rules) - ;; Default rule. - `((:before . ,token) - ;; (:parent open 0) - point))) (offset (save-excursion (goto-char pos) - (smie-indent--offset-rule tokinfo nil parent)))) + (or (smie-indent--rule :before token nil parent) + 'point)))) ;; Different behaviors: ;; - align with parent. ;; - parent + offset. @@ -1151,10 +1129,10 @@ nil) ((eq (car parent) (car toklevels)) ;; We bumped into a same-level operator. align with it. - (if (and (smie-indent--bolp) (/= (point) pos) + (if (and (smie-bolp) (/= (point) pos) (save-excursion (goto-char (goto-char (cadr parent))) - (not (smie-indent--bolp))) + (not (smie-bolp))) ;; Check the offset of `token' rather then its parent ;; because its parent may have used a special rule. E.g. ;; function foo; @@ -1190,8 +1168,8 @@ ;; -> d ;; So as to align with the earliest appropriate place. (smie-indent-virtual))) - (tokinfo - (if (and (= (point) pos) (smie-indent--bolp) + (t + (if (and (= (point) pos) (smie-bolp) (or (eq offset 'point) (and (consp offset) (memq 'point offset)))) ;; Since we started at BOL, we're not computing a virtual @@ -1209,7 +1187,7 @@ ;; Don't do it for virtual indentations. We should normally never be "in ;; front of a comment" when doing virtual-indentation anyway. And if we are ;; (as can happen in octave-mode), moving forward can lead to inf-loops. - (and (smie-indent--bolp) + (and (smie-bolp) (let ((pos (point))) (save-excursion (beginning-of-line) @@ -1254,27 +1232,18 @@ (save-excursion (let* ((pos (point)) (toklevel (smie-indent-backward-token)) - (tok (car toklevel)) - (tokinfo (assoc tok smie-indent-rules))) - ;; Set some default indent rules. - (if (and toklevel (null (cadr toklevel)) (null tokinfo)) - (setq tokinfo (list (car toklevel)))) - ;; (if (and tokinfo (null toklevel)) - ;; (error "Token %S has indent rule but has no parsing info" tok)) + (tok (car toklevel))) (when toklevel - (unless tokinfo - ;; The default indentation after a keyword/operator is 0 for - ;; infix and t for prefix. - ;; Using the BNF syntax, we could come up with better - ;; defaults, but we only have the precedence levels here. - (setq tokinfo (list tok 'default-rule - (if (cadr toklevel) 0 (smie-indent--offset t))))) (let ((offset - (or (smie-indent--offset-rule tokinfo pos) - (smie-indent--offset t)))) - (let ((before (point))) + (or (smie-indent--rule :after tok pos) + ;; The default indentation after a keyword/operator is + ;; 0 for infix and t for prefix. + (if (or (null (cadr toklevel)) + (rassoc tok smie-closer-alist)) + (smie-indent--offset 'basic) 0))) + (before (point))) (goto-char pos) - (smie-indent--column offset before))))))) + (smie-indent--column offset before)))))) (defun smie-indent-exps () ;; Indentation of sequences of simple expressions without @@ -1297,13 +1266,14 @@ arg) (while (and (null (car (smie-backward-sexp))) (push (point) positions) - (not (smie-indent--bolp)))) + (not (smie-bolp)))) (save-excursion ;; Figure out if the atom we just skipped is an argument rather ;; than a function. - (setq arg (or (null (car (smie-backward-sexp))) - (member (funcall smie-backward-token-function) - (cdr (assoc 'list-intro smie-indent-rules)))))) + (setq arg + (or (null (car (smie-backward-sexp))) + (funcall smie-rules-function :list-intro + (funcall smie-backward-token-function))))) (cond ((null positions) ;; We're the first expression of the list. In that case, the @@ -1362,18 +1332,51 @@ (save-excursion (indent-line-to indent)) (indent-line-to indent))))) -(defun smie-indent-debug () - "Show the rules used to compute indentation of current line." - (interactive) - (let ((smie-indent-debug-log '())) - (smie-indent-calculate) - ;; FIXME: please improve! - (message "%S" smie-indent-debug-log))) - -(defun smie-setup (op-levels indent-rules) - (set (make-local-variable 'smie-indent-rules) indent-rules) +(defun smie-setup (op-levels rules-function &rest keywords) + "Setup SMIE navigation and indentation. +OP-LEVELS is a grammar table generated by `smie-prec2-levels'. +RULES-FUNCTION is a set of indentation rules for use on `smie-rules-function'. +KEYWORDS are additional arguments, which can use the following keywords: +- :forward-token FUN +- :backward-token FUN" + (set (make-local-variable 'smie-rules-function) rules-function) (set (make-local-variable 'smie-op-levels) op-levels) - (set (make-local-variable 'indent-line-function) 'smie-indent-line)) + (set (make-local-variable 'indent-line-function) 'smie-indent-line) + (set (make-local-variable 'forward-sexp-function) + 'smie-forward-sexp-command) + (while keywords + (let ((k (pop keywords)) + (v (pop keywords))) + (case k + (:forward-token + (set (make-local-variable 'smie-forward-token-function) v)) + (:backward-token + (set (make-local-variable 'smie-backward-token-function) v)) + (t (message "smie-setup: ignoring unknown keyword %s" k))))) + (let ((ca (cdr (assq :smie-closer-alist op-levels)))) + (when ca + (set (make-local-variable 'smie-closer-alist) ca) + ;; Only needed for interactive calls to blink-matching-open. + (set (make-local-variable 'blink-matching-check-function) + #'smie-blink-matching-check) + (add-hook 'post-self-insert-hook + #'smie-blink-matching-open 'append 'local) + (set (make-local-variable 'smie-blink-matching-triggers) + (append smie-blink-matching-triggers + ;; Rather than wait for SPC to blink, try to blink as + ;; soon as we type the last char of a block ender. + (let ((closers (sort (mapcar #'cdr smie-closer-alist) + #'string-lessp)) + (triggers ()) + closer) + (while (setq closer (pop closers)) + (unless (and closers + ;; FIXME: this eliminates prefixes of other + ;; closers, but we should probably elimnate + ;; prefixes of other keywords as well. + (string-prefix-p closer (car closers))) + (push (aref closer (1- (length closer))) triggers))) + (delete-dups triggers))))))) (provide 'smie) diff -r d66d04803828 -r a9904c1962db lisp/progmodes/octave-mod.el --- a/lisp/progmodes/octave-mod.el Fri Oct 29 13:51:15 2010 +0000 +++ b/lisp/progmodes/octave-mod.el Fri Oct 29 15:20:28 2010 -0400 @@ -446,9 +446,6 @@ ;; (fundesc (atom "=" atom)) )) -(defconst octave-smie-closer-alist - (smie-bnf-closer-alist octave-smie-bnf-table)) - (defconst octave-smie-op-levels (smie-prec2-levels (smie-merge-prec2s @@ -521,15 +518,18 @@ (t (smie-default-forward-token)))) -(defconst octave-smie-indent-rules - '((";" - (:parent ("function" "if" "while" "else" "elseif" "for" "otherwise" - "case" "try" "catch" "unwind_protect" "unwind_protect_cleanup") - ;; FIXME: don't hardcode 2. - (+ parent octave-block-offset)) - ;; (:parent "switch" 4) ;For (invalid) code between switch and case. - 0) - ((:before . "case") octave-block-offset))) +(defun octave-smie-rules (kind token) + (pcase (cons kind token) + (`(:elem . basic) octave-block-offset) + (`(:before . "case") octave-block-offset) + (`(:after . ";") + (if (smie-parent-p "function" "if" "while" "else" "elseif" "for" + "otherwise" "case" "try" "catch" "unwind_protect" + "unwind_protect_cleanup") + '(+ parent octave-block-offset) + ;; For (invalid) code between switch and case. + ;; (if (smie-parent-p "switch") 4) + 0)))) (defvar electric-indent-chars) @@ -619,32 +619,15 @@ including a reproducible test case and send the message." (setq local-abbrev-table octave-abbrev-table) - (smie-setup octave-smie-op-levels octave-smie-indent-rules) + (smie-setup octave-smie-op-levels #'octave-smie-rules + :forward-token #'octave-smie-forward-token + :backward-token #'octave-smie-backward-token) (set (make-local-variable 'smie-indent-basic) 'octave-block-offset) - (set (make-local-variable 'smie-backward-token-function) - 'octave-smie-backward-token) - (set (make-local-variable 'smie-forward-token-function) - 'octave-smie-forward-token) - (set (make-local-variable 'forward-sexp-function) - 'smie-forward-sexp-command) - (set (make-local-variable 'smie-closer-alist) octave-smie-closer-alist) - ;; Only needed for interactive calls to blink-matching-open. - (set (make-local-variable 'blink-matching-check-function) - #'smie-blink-matching-check) - (when octave-blink-matching-block - (add-hook 'post-self-insert-hook #'smie-blink-matching-open 'append 'local) (set (make-local-variable 'smie-blink-matching-triggers) - (append smie-blink-matching-triggers '(\;) - ;; Rather than wait for SPC or ; to blink, try to blink as - ;; soon as we type the last char of a block ender. - ;; But strip ?d from this list so that we don't blink twice - ;; when the user writes "endif" (once at "end" and another - ;; time at "endif"). - (delq ?d (delete-dups - (mapcar (lambda (kw) - (aref (cdr kw) (1- (length (cdr kw))))) - smie-closer-alist)))))) + (cons ?\; smie-blink-matching-triggers)) + (unless octave-blink-matching-block + (remove-hook 'post-self-insert-hook #'smie-blink-matching-open 'local)) (set (make-local-variable 'electric-indent-chars) (cons ?\; electric-indent-chars)) diff -r d66d04803828 -r a9904c1962db lisp/progmodes/prolog.el --- a/lisp/progmodes/prolog.el Fri Oct 29 13:51:15 2010 +0000 +++ b/lisp/progmodes/prolog.el Fri Oct 29 15:20:28 2010 -0400 @@ -173,10 +173,11 @@ ) "Precedence levels of infix operators.") -(defconst prolog-smie-indent-rules - '((":-") - ("->")) - "Prolog indentation rules.") +(defun prolog-smie-rules (kind token) + (pcase (cons kind token) + (`(:elem . basic) prolog-indent-width) + (`(:after . ".") 0) ;; To work around smie-closer-alist. + (`(:after . ,(or `":-" `"->")) prolog-indent-width))) (defun prolog-mode-variables () (make-local-variable 'paragraph-separate) @@ -185,19 +186,17 @@ (setq paragraph-ignore-fill-prefix t) (make-local-variable 'imenu-generic-expression) (setq imenu-generic-expression '((nil "^\\sw+" 0))) - (smie-setup prolog-smie-op-levels prolog-smie-indent-rules) - (set (make-local-variable 'smie-forward-token-function) - #'prolog-smie-forward-token) - (set (make-local-variable 'smie-backward-token-function) - #'prolog-smie-backward-token) - (set (make-local-variable 'forward-sexp-function) - 'smie-forward-sexp-command) - (set (make-local-variable 'smie-indent-basic) prolog-indent-width) + + ;; Setup SMIE. + (smie-setup prolog-smie-op-levels #'prolog-smie-rules + :forward-token #'prolog-smie-forward-token + :backward-token #'prolog-smie-backward-token) (set (make-local-variable 'smie-blink-matching-triggers) '(?.)) (set (make-local-variable 'smie-closer-alist) '((t . "."))) (add-hook 'post-self-insert-hook #'smie-blink-matching-open 'append 'local) ;; There's no real closer in Prolog anyway. (set (make-local-variable 'smie-blink-matching-inners) t) + (make-local-variable 'comment-start) (setq comment-start "%") (make-local-variable 'comment-start-skip)