diff options
| author | Stefan Monnier | 2010-11-07 10:45:45 -0500 |
|---|---|---|
| committer | Stefan Monnier | 2010-11-07 10:45:45 -0500 |
| commit | 674728d4e3b3eed39fd2c229eda4ac7754657102 (patch) | |
| tree | f04e2cc56e2ac3c1b3ad4fd61424c7f0e1644e60 | |
| parent | 66b167670d669ad8f98153351cea588c1000cb6a (diff) | |
| download | emacs-674728d4e3b3eed39fd2c229eda4ac7754657102.tar.gz emacs-674728d4e3b3eed39fd2c229eda4ac7754657102.zip | |
* lisp/emacs-lisp/smie.el: Simplify the smie-rules-function return values.
(smie-precs->prec2): Rename from smie-precs-precedence-table.
(smie-bnf->prec2): Rename from smie-bnf-precedence-table.
(smie-prec2->grammar): Rename from smie-prec2-levels.
(smie-grammar): Rename from smie-op-levels.
(smie-indent--hanging-p): Rename from smie-hanging-p.
(smie-rule-hanging-p): New alias.
(smie-indent--bolp): Rename from smie-bolp.
(smie-indent--hanging-p): New alias.
(smie--token): New dynamically bound variable.
(smie-indent--parent): New function.
(smie-rule-parent-p): Use it; rename from smie-parent-p.
(smie-rule-next-p): Rename from smie-next-p.
(smie-rule-prev-p): Rename from smie-prev-p.
(smie-rule-sibling-p, smie-rule-parent)
(smie-indent--separator-outdent, smie-rule-separator): New functions.
(smie-rule-separator-outdent): New var.
(smie-indent--rule): Merge with smie-indent--column.
(smie-indent-forward-token, smie-indent-backward-token):
Also recognize close parens.
(smie-indent-keyword): Don't use smie-indent--column any more.
(smie-indent-after-keyword): Ignore closers by default.
(smie-indent-line): Use with-demoted-errors.
* lisp/progmodes/octave-mod.el (octave-smie-grammar):
Rename from octave-smie-op-levels.
(octave-smie-rules): Adjust to new behavior.
* lisp/progmodes/prolog.el (prolog-smie-grammar):
Rename from prolog-smie-op-levels.
| -rw-r--r-- | lisp/ChangeLog | 31 | ||||
| -rw-r--r-- | lisp/emacs-lisp/smie.el | 457 | ||||
| -rw-r--r-- | lisp/progmodes/octave-mod.el | 29 | ||||
| -rw-r--r-- | lisp/progmodes/prolog.el | 4 |
4 files changed, 315 insertions, 206 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 0d1e07f7f5a..4c106b95c74 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,34 @@ | |||
| 1 | 2010-11-07 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * emacs-lisp/smie.el: Simplify the smie-rules-function return values. | ||
| 4 | (smie-precs->prec2): Rename from smie-precs-precedence-table. | ||
| 5 | (smie-bnf->prec2): Rename from smie-bnf-precedence-table. | ||
| 6 | (smie-prec2->grammar): Rename from smie-prec2-levels. | ||
| 7 | (smie-grammar): Rename from smie-op-levels. | ||
| 8 | (smie-indent--hanging-p): Rename from smie-hanging-p. | ||
| 9 | (smie-rule-hanging-p): New alias. | ||
| 10 | (smie-indent--bolp): Rename from smie-bolp. | ||
| 11 | (smie-indent--hanging-p): New alias. | ||
| 12 | (smie--token): New dynamically bound variable. | ||
| 13 | (smie-indent--parent): New function. | ||
| 14 | (smie-rule-parent-p): Use it; rename from smie-parent-p. | ||
| 15 | (smie-rule-next-p): Rename from smie-next-p. | ||
| 16 | (smie-rule-prev-p): Rename from smie-prev-p. | ||
| 17 | (smie-rule-sibling-p, smie-rule-parent) | ||
| 18 | (smie-indent--separator-outdent, smie-rule-separator): New functions. | ||
| 19 | (smie-rule-separator-outdent): New var. | ||
| 20 | (smie-indent--rule): Merge with smie-indent--column. | ||
| 21 | (smie-indent-forward-token, smie-indent-backward-token): | ||
| 22 | Also recognize close parens. | ||
| 23 | (smie-indent-keyword): Don't use smie-indent--column any more. | ||
| 24 | (smie-indent-after-keyword): Ignore closers by default. | ||
| 25 | (smie-indent-line): Use with-demoted-errors. | ||
| 26 | * progmodes/octave-mod.el (octave-smie-grammar): | ||
| 27 | Rename from octave-smie-op-levels. | ||
| 28 | (octave-smie-rules): Adjust to new behavior. | ||
| 29 | * progmodes/prolog.el (prolog-smie-grammar): | ||
| 30 | Rename from prolog-smie-op-levels. | ||
| 31 | |||
| 1 | 2010-11-07 Glenn Morris <rgm@gnu.org> | 32 | 2010-11-07 Glenn Morris <rgm@gnu.org> |
| 2 | 33 | ||
| 3 | * eshell/esh-util.el (subst-char-in-string) | 34 | * eshell/esh-util.el (subst-char-in-string) |
diff --git a/lisp/emacs-lisp/smie.el b/lisp/emacs-lisp/smie.el index afb2834414a..03c03126d2f 100644 --- a/lisp/emacs-lisp/smie.el +++ b/lisp/emacs-lisp/smie.el | |||
| @@ -52,9 +52,9 @@ | |||
| 52 | ;; error because the parser just automatically does something. Better yet, | 52 | ;; error because the parser just automatically does something. Better yet, |
| 53 | ;; we can afford to use a sloppy grammar. | 53 | ;; we can afford to use a sloppy grammar. |
| 54 | 54 | ||
| 55 | ;; The development (especially the parts building the 2D precedence | 55 | ;; A good background to understand the development (especially the parts |
| 56 | ;; tables and then computing the precedence levels from it) is largely | 56 | ;; building the 2D precedence tables and then computing the precedence levels |
| 57 | ;; inspired from page 187-194 of "Parsing techniques" by Dick Grune | 57 | ;; from it) can be found in pages 187-194 of "Parsing techniques" by Dick Grune |
| 58 | ;; and Ceriel Jacobs (BookBody.pdf available at | 58 | ;; and Ceriel Jacobs (BookBody.pdf available at |
| 59 | ;; http://www.cs.vu.nl/~dick/PTAPG.html). | 59 | ;; http://www.cs.vu.nl/~dick/PTAPG.html). |
| 60 | ;; | 60 | ;; |
| @@ -91,9 +91,9 @@ | |||
| 91 | ;; - a 2 dimensional precedence table (key word "prec2"), is a 2D | 91 | ;; - a 2 dimensional precedence table (key word "prec2"), is a 2D |
| 92 | ;; table recording the precedence relation (can be `<', `=', `>', or | 92 | ;; table recording the precedence relation (can be `<', `=', `>', or |
| 93 | ;; nil) between each pair of tokens. | 93 | ;; nil) between each pair of tokens. |
| 94 | ;; - a precedence-level table (key word "levels"), while is a alist | 94 | ;; - a precedence-level table (key word "grammar"), which is a alist |
| 95 | ;; giving for each token its left and right precedence level (a | 95 | ;; giving for each token its left and right precedence level (a |
| 96 | ;; number or nil). This is used in `smie-op-levels'. | 96 | ;; number or nil). This is used in `smie-grammar'. |
| 97 | ;; The prec2 tables are only intermediate data structures: the source | 97 | ;; The prec2 tables are only intermediate data structures: the source |
| 98 | ;; code normally provides a mix of BNF and precs tables, and then | 98 | ;; code normally provides a mix of BNF and precs tables, and then |
| 99 | ;; turns them into a levels table, which is what's used by the rest of | 99 | ;; turns them into a levels table, which is what's used by the rest of |
| @@ -113,8 +113,8 @@ | |||
| 113 | (display-warning 'smie (format "Conflict: %s %s/%s %s" x old val y))) | 113 | (display-warning 'smie (format "Conflict: %s %s/%s %s" x old val y))) |
| 114 | (puthash key val table)))) | 114 | (puthash key val table)))) |
| 115 | 115 | ||
| 116 | (put 'smie-precs-precedence-table 'pure t) | 116 | (put 'smie-precs->prec2 'pure t) |
| 117 | (defun smie-precs-precedence-table (precs) | 117 | (defun smie-precs->prec2 (precs) |
| 118 | "Compute a 2D precedence table from a list of precedences. | 118 | "Compute a 2D precedence table from a list of precedences. |
| 119 | PRECS should be a list, sorted by precedence (e.g. \"+\" will | 119 | PRECS should be a list, sorted by precedence (e.g. \"+\" will |
| 120 | come before \"*\"), of elements of the form \(left OP ...) | 120 | come before \"*\"), of elements of the form \(left OP ...) |
| @@ -153,8 +153,8 @@ one of those elements share the same precedence level and associativity." | |||
| 153 | table)) | 153 | table)) |
| 154 | prec2))) | 154 | prec2))) |
| 155 | 155 | ||
| 156 | (put 'smie-bnf-precedence-table 'pure t) | 156 | (put 'smie-bnf->prec2 'pure t) |
| 157 | (defun smie-bnf-precedence-table (bnf &rest precs) | 157 | (defun smie-bnf->prec2 (bnf &rest precs) |
| 158 | (let ((nts (mapcar 'car bnf)) ;Non-terminals | 158 | (let ((nts (mapcar 'car bnf)) ;Non-terminals |
| 159 | (first-ops-table ()) | 159 | (first-ops-table ()) |
| 160 | (last-ops-table ()) | 160 | (last-ops-table ()) |
| @@ -162,7 +162,7 @@ one of those elements share the same precedence level and associativity." | |||
| 162 | (last-nts-table ()) | 162 | (last-nts-table ()) |
| 163 | (prec2 (make-hash-table :test 'equal)) | 163 | (prec2 (make-hash-table :test 'equal)) |
| 164 | (override (apply 'smie-merge-prec2s | 164 | (override (apply 'smie-merge-prec2s |
| 165 | (mapcar 'smie-precs-precedence-table precs))) | 165 | (mapcar 'smie-precs->prec2 precs))) |
| 166 | again) | 166 | again) |
| 167 | (dolist (rules bnf) | 167 | (dolist (rules bnf) |
| 168 | (let ((nt (car rules)) | 168 | (let ((nt (car rules)) |
| @@ -238,7 +238,7 @@ one of those elements share the same precedence level and associativity." | |||
| 238 | (t (smie-set-prec2tab prec2 (car rhs) (cadr rhs) '= override))) | 238 | (t (smie-set-prec2tab prec2 (car rhs) (cadr rhs) '= override))) |
| 239 | (setq rhs (cdr rhs))))) | 239 | (setq rhs (cdr rhs))))) |
| 240 | ;; Keep track of which tokens are openers/closer, so they can get a nil | 240 | ;; Keep track of which tokens are openers/closer, so they can get a nil |
| 241 | ;; precedence in smie-prec2-levels. | 241 | ;; precedence in smie-prec2->grammar. |
| 242 | (puthash :smie-open/close-alist (smie-bnf-classify bnf) prec2) | 242 | (puthash :smie-open/close-alist (smie-bnf-classify bnf) prec2) |
| 243 | (puthash :smie-closer-alist (smie-bnf-closer-alist bnf) prec2) | 243 | (puthash :smie-closer-alist (smie-bnf-closer-alist bnf) prec2) |
| 244 | prec2)) | 244 | prec2)) |
| @@ -322,7 +322,7 @@ from the table, e.g. the table will not include things like (\"if\" . \"else\"). | |||
| 322 | (unless (member term nts) | 322 | (unless (member term nts) |
| 323 | (pushnew (cons (car rhs) term) alist :test #'equal))))))) | 323 | (pushnew (cons (car rhs) term) alist :test #'equal))))))) |
| 324 | (nreverse alist))) | 324 | (nreverse alist))) |
| 325 | 325 | ||
| 326 | (defun smie-bnf-classify (bnf) | 326 | (defun smie-bnf-classify (bnf) |
| 327 | "Return a table classifying terminals. | 327 | "Return a table classifying terminals. |
| 328 | Each terminal can either be an `opener', a `closer', or neither." | 328 | Each terminal can either be an `opener', a `closer', or neither." |
| @@ -367,7 +367,7 @@ CSTS is a list of pairs representing arcs in a graph." | |||
| 367 | (push (cons (car path) (cons (cdr cst) (cdr path))) | 367 | (push (cons (car path) (cons (cdr cst) (cdr path))) |
| 368 | paths)))))) | 368 | paths)))))) |
| 369 | (cons (car cycle) (nreverse (cdr cycle))))) | 369 | (cons (car cycle) (nreverse (cdr cycle))))) |
| 370 | 370 | ||
| 371 | (defun smie-debug--describe-cycle (table cycle) | 371 | (defun smie-debug--describe-cycle (table cycle) |
| 372 | (let ((names | 372 | (let ((names |
| 373 | (mapcar (lambda (val) | 373 | (mapcar (lambda (val) |
| @@ -385,17 +385,11 @@ CSTS is a list of pairs representing arcs in a graph." | |||
| 385 | (append names (list (car names))) | 385 | (append names (list (car names))) |
| 386 | " < "))) | 386 | " < "))) |
| 387 | 387 | ||
| 388 | (put 'smie-prec2-levels 'pure t) | 388 | (put 'smie-prec2->grammar 'pure t) |
| 389 | (defun smie-prec2-levels (prec2) | 389 | (defun smie-prec2->grammar (prec2) |
| 390 | ;; FIXME: Rather than only return an alist of precedence levels, we should | ||
| 391 | ;; also extract other useful data from it: | ||
| 392 | ;; - better default indentation rules (i.e. non-zero indentation after inner | ||
| 393 | ;; keywords like the "in" of "let..in..end") for smie-indent-after-keyword. | ||
| 394 | ;; Of course, maybe those things would be even better handled in the | ||
| 395 | ;; bnf->prec function. | ||
| 396 | "Take a 2D precedence table and turn it into an alist of precedence levels. | 390 | "Take a 2D precedence table and turn it into an alist of precedence levels. |
| 397 | PREC2 is a table as returned by `smie-precs-precedence-table' or | 391 | PREC2 is a table as returned by `smie-precs->prec2' or |
| 398 | `smie-bnf-precedence-table'." | 392 | `smie-bnf->prec2'." |
| 399 | ;; For each operator, we create two "variables" (corresponding to | 393 | ;; For each operator, we create two "variables" (corresponding to |
| 400 | ;; the left and right precedence level), which are represented by | 394 | ;; the left and right precedence level), which are represented by |
| 401 | ;; cons cells. Those are the very cons cells that appear in the | 395 | ;; cons cells. Those are the very cons cells that appear in the |
| @@ -494,8 +488,9 @@ PREC2 is a table as returned by `smie-precs-precedence-table' or | |||
| 494 | 488 | ||
| 495 | ;;; Parsing using a precedence level table. | 489 | ;;; Parsing using a precedence level table. |
| 496 | 490 | ||
| 497 | (defvar smie-op-levels 'unset | 491 | (defvar smie-grammar 'unset |
| 498 | "List of token parsing info. | 492 | "List of token parsing info. |
| 493 | This list is normally built by `smie-prec2->grammar'. | ||
| 499 | Each element is of the form (TOKEN LEFT-LEVEL RIGHT-LEVEL). | 494 | Each element is of the form (TOKEN LEFT-LEVEL RIGHT-LEVEL). |
| 500 | Parsing is done using an operator precedence parser. | 495 | Parsing is done using an operator precedence parser. |
| 501 | LEFT-LEVEL and RIGHT-LEVEL can be either numbers or nil, where nil | 496 | LEFT-LEVEL and RIGHT-LEVEL can be either numbers or nil, where nil |
| @@ -538,7 +533,7 @@ it should move backward to the beginning of the previous token.") | |||
| 538 | (defun smie--associative-p (toklevels) | 533 | (defun smie--associative-p (toklevels) |
| 539 | ;; in "a + b + c" we want to stop at each +, but in | 534 | ;; in "a + b + c" we want to stop at each +, but in |
| 540 | ;; "if a then b elsif c then d else c" we don't want to stop at each keyword. | 535 | ;; "if a then b elsif c then d else c" we don't want to stop at each keyword. |
| 541 | ;; To distinguish the two cases, we made smie-prec2-levels choose | 536 | ;; To distinguish the two cases, we made smie-prec2->grammar choose |
| 542 | ;; different levels for each part of "if a then b else c", so that | 537 | ;; different levels for each part of "if a then b else c", so that |
| 543 | ;; by checking if the left-level is equal to the right level, we can | 538 | ;; by checking if the left-level is equal to the right level, we can |
| 544 | ;; figure out that it's an associative operator. | 539 | ;; figure out that it's an associative operator. |
| @@ -568,7 +563,7 @@ Possible return values: | |||
| 568 | (while | 563 | (while |
| 569 | (let* ((pos (point)) | 564 | (let* ((pos (point)) |
| 570 | (token (funcall next-token)) | 565 | (token (funcall next-token)) |
| 571 | (toklevels (cdr (assoc token smie-op-levels)))) | 566 | (toklevels (cdr (assoc token smie-grammar)))) |
| 572 | (cond | 567 | (cond |
| 573 | ((null toklevels) | 568 | ((null toklevels) |
| 574 | (when (zerop (length token)) | 569 | (when (zerop (length token)) |
| @@ -710,7 +705,7 @@ Possible return values: | |||
| 710 | (string (cdr (syntax-after (point)))) | 705 | (string (cdr (syntax-after (point)))) |
| 711 | (let* ((open (funcall smie-forward-token-function)) | 706 | (let* ((open (funcall smie-forward-token-function)) |
| 712 | (closer (cdr (assoc open smie-closer-alist))) | 707 | (closer (cdr (assoc open smie-closer-alist))) |
| 713 | (levels (list (assoc open smie-op-levels))) | 708 | (levels (list (assoc open smie-grammar))) |
| 714 | (seen '()) | 709 | (seen '()) |
| 715 | (found '())) | 710 | (found '())) |
| 716 | (cond | 711 | (cond |
| @@ -722,13 +717,11 @@ Possible return values: | |||
| 722 | ((or (equal levels '(nil)) (nth 1 (car levels))) | 717 | ((or (equal levels '(nil)) (nth 1 (car levels))) |
| 723 | (error "Doesn't look like a block")) | 718 | (error "Doesn't look like a block")) |
| 724 | (t | 719 | (t |
| 725 | ;; FIXME: With grammars like Octave's, every closer ("end", | 720 | ;; Now that smie-setup automatically sets smie-closer-alist |
| 726 | ;; "endif", "endwhile", ...) has the same level, so we'd need | 721 | ;; from the BNF, this is not really needed any more. |
| 727 | ;; to look at the BNF or at least at the 2D prec-table, in | ||
| 728 | ;; order to find the right closer for a given opener. | ||
| 729 | (while levels | 722 | (while levels |
| 730 | (let ((level (pop levels))) | 723 | (let ((level (pop levels))) |
| 731 | (dolist (other smie-op-levels) | 724 | (dolist (other smie-grammar) |
| 732 | (when (and (eq (nth 2 level) (nth 1 other)) | 725 | (when (and (eq (nth 2 level) (nth 1 other)) |
| 733 | (not (memq other seen))) | 726 | (not (memq other seen))) |
| 734 | (push other seen) | 727 | (push other seen) |
| @@ -763,7 +756,7 @@ This command assumes point is not in a string or comment." | |||
| 763 | (while | 756 | (while |
| 764 | (let* ((pos (point)) | 757 | (let* ((pos (point)) |
| 765 | (token (funcall next-token)) | 758 | (token (funcall next-token)) |
| 766 | (levels (assoc token smie-op-levels))) | 759 | (levels (assoc token smie-grammar))) |
| 767 | (cond | 760 | (cond |
| 768 | ((zerop (length token)) | 761 | ((zerop (length token)) |
| 769 | (if (if (< inc 0) (looking-back "\\s(\\|\\s)" (1- (point))) | 762 | (if (if (< inc 0) (looking-back "\\s(\\|\\s)" (1- (point))) |
| @@ -817,8 +810,8 @@ If non-nil, it will blink not only for \"begin..end\" but also for \"if...else\" | |||
| 817 | This uses SMIE's tables and is expected to be placed on `post-self-insert-hook'." | 810 | This uses SMIE's tables and is expected to be placed on `post-self-insert-hook'." |
| 818 | (let ((pos (point)) ;Position after the close token. | 811 | (let ((pos (point)) ;Position after the close token. |
| 819 | token) | 812 | token) |
| 820 | (when (and blink-matching-paren | 813 | (when (and blink-matching-paren |
| 821 | smie-closer-alist ; Optimization. | 814 | smie-closer-alist ; Optimization. |
| 822 | (or (eq (char-before) last-command-event) ;; Sanity check. | 815 | (or (eq (char-before) last-command-event) ;; Sanity check. |
| 823 | (save-excursion | 816 | (save-excursion |
| 824 | (or (progn (skip-chars-backward " \t") | 817 | (or (progn (skip-chars-backward " \t") |
| @@ -827,9 +820,9 @@ This uses SMIE's tables and is expected to be placed on `post-self-insert-hook'. | |||
| 827 | (progn (skip-chars-backward " \n\t") | 820 | (progn (skip-chars-backward " \n\t") |
| 828 | (setq pos (point)) | 821 | (setq pos (point)) |
| 829 | (eq (char-before) last-command-event))))) | 822 | (eq (char-before) last-command-event))))) |
| 830 | (memq last-command-event smie-blink-matching-triggers) | 823 | (memq last-command-event smie-blink-matching-triggers) |
| 831 | (not (nth 8 (syntax-ppss)))) | 824 | (not (nth 8 (syntax-ppss)))) |
| 832 | (save-excursion | 825 | (save-excursion |
| 833 | (setq token (funcall smie-backward-token-function)) | 826 | (setq token (funcall smie-backward-token-function)) |
| 834 | (when (and (eq (point) (1- pos)) | 827 | (when (and (eq (point) (1- pos)) |
| 835 | (= 1 (length token)) | 828 | (= 1 (length token)) |
| @@ -859,7 +852,7 @@ This uses SMIE's tables and is expected to be placed on `post-self-insert-hook'. | |||
| 859 | (not (memq (char-before) | 852 | (not (memq (char-before) |
| 860 | smie-blink-matching-triggers))) | 853 | smie-blink-matching-triggers))) |
| 861 | (or smie-blink-matching-inners | 854 | (or smie-blink-matching-inners |
| 862 | (null (nth 2 (assoc token smie-op-levels))))) | 855 | (null (nth 2 (assoc token smie-grammar))))) |
| 863 | ;; The major mode might set blink-matching-check-function | 856 | ;; The major mode might set blink-matching-check-function |
| 864 | ;; buffer-locally so that interactive calls to | 857 | ;; buffer-locally so that interactive calls to |
| 865 | ;; blink-matching-open work right, but let's not presume | 858 | ;; blink-matching-open work right, but let's not presume |
| @@ -894,49 +887,58 @@ When ARG is a token, the function is called with point just before that token. | |||
| 894 | A return value of nil always means to fallback on the default behavior, so the | 887 | A return value of nil always means to fallback on the default behavior, so the |
| 895 | function should return nil for arguments it does not expect. | 888 | function should return nil for arguments it does not expect. |
| 896 | 889 | ||
| 897 | OFFSET can be of the form: | 890 | OFFSET can be: |
| 898 | `point' align with the token. | 891 | nil use the default indentation rule. |
| 899 | `parent' align with the parent. | 892 | `(column . COLUMN) indent to column COLUMN. |
| 900 | NUMBER offset by NUMBER. | 893 | NUMBER offset by NUMBER, relative to a base token |
| 901 | \(+ OFFSETS...) use the sum of OFFSETS. | 894 | which is the current token for :after and |
| 902 | VARIABLE use the value of VARIABLE as offset. | 895 | its parent for :before. |
| 903 | 896 | ||
| 904 | This function will often use some of the following functions designed | 897 | The functions whose name starts with \"smie-rule-\" are helper functions |
| 905 | specifically for it: | 898 | designed specifically for use in this function.") |
| 906 | `smie-bolp', `smie-hanging-p', `smie-parent-p', `smie-next-p', `smie-prev-p'.") | ||
| 907 | 899 | ||
| 908 | (defun smie-hanging-p () | 900 | (defalias 'smie-rule-hanging-p 'smie-indent--hanging-p) |
| 901 | (defun smie-indent--hanging-p () | ||
| 909 | "Return non-nil if the current token is \"hanging\". | 902 | "Return non-nil if the current token is \"hanging\". |
| 910 | A hanging keyword is one that's at the end of a line except it's not at | 903 | A hanging keyword is one that's at the end of a line except it's not at |
| 911 | the beginning of a line." | 904 | the beginning of a line." |
| 912 | (and (not (smie-bolp)) | 905 | (and (not (smie-indent--bolp)) |
| 913 | (save-excursion | 906 | (save-excursion |
| 914 | (when (zerop (length (funcall smie-forward-token-function))) | 907 | (<= (line-end-position) |
| 915 | ;; Could be an open-paren. | 908 | (progn |
| 916 | (forward-char 1)) | 909 | (when (zerop (length (funcall smie-forward-token-function))) |
| 917 | (skip-chars-forward " \t") | 910 | ;; Could be an open-paren. |
| 918 | (eolp)))) | 911 | (forward-char 1)) |
| 912 | (skip-chars-forward " \t") | ||
| 913 | (or (eolp) | ||
| 914 | (and (looking-at comment-start-skip) | ||
| 915 | (forward-comment (point-max)))) | ||
| 916 | (point)))))) | ||
| 919 | 917 | ||
| 920 | (defun smie-bolp () | 918 | (defalias 'smie-rule-bolp 'smie-indent--bolp) |
| 919 | (defun smie-indent--bolp () | ||
| 921 | "Return non-nil if the current token is the first on the line." | 920 | "Return non-nil if the current token is the first on the line." |
| 922 | (save-excursion (skip-chars-backward " \t") (bolp))) | 921 | (save-excursion (skip-chars-backward " \t") (bolp))) |
| 923 | 922 | ||
| 924 | (defvar smie--parent) (defvar smie--after) ;Dynamically scoped. | 923 | ;; Dynamically scoped. |
| 924 | (defvar smie--parent) (defvar smie--after) (defvar smie--token) | ||
| 925 | 925 | ||
| 926 | (defun smie-parent-p (&rest parents) | 926 | (defun smie-indent--parent () |
| 927 | (or smie--parent | ||
| 928 | (save-excursion | ||
| 929 | (let* ((pos (point)) | ||
| 930 | (tok (funcall smie-forward-token-function))) | ||
| 931 | (unless (cadr (assoc tok smie-grammar)) | ||
| 932 | (goto-char pos)) | ||
| 933 | (setq smie--parent | ||
| 934 | (smie-backward-sexp 'halfsexp)))))) | ||
| 935 | |||
| 936 | (defun smie-rule-parent-p (&rest parents) | ||
| 927 | "Return non-nil if the current token's parent is among PARENTS. | 937 | "Return non-nil if the current token's parent is among PARENTS. |
| 928 | Only meaningful when called from within `smie-rules-function'." | 938 | Only meaningful when called from within `smie-rules-function'." |
| 929 | (member (nth 2 (or smie--parent | 939 | (member (nth 2 (smie-indent--parent)) parents)) |
| 930 | (save-excursion | 940 | |
| 931 | (let* ((pos (point)) | 941 | (defun smie-rule-next-p (&rest tokens) |
| 932 | (tok (funcall smie-forward-token-function))) | ||
| 933 | (unless (cadr (assoc tok smie-op-levels)) | ||
| 934 | (goto-char pos)) | ||
| 935 | (setq smie--parent | ||
| 936 | (smie-backward-sexp 'halfsexp)))))) | ||
| 937 | parents)) | ||
| 938 | |||
| 939 | (defun smie-next-p (&rest tokens) | ||
| 940 | "Return non-nil if the next token is among TOKENS. | 942 | "Return non-nil if the next token is among TOKENS. |
| 941 | Only meaningful when called from within `smie-rules-function'." | 943 | Only meaningful when called from within `smie-rules-function'." |
| 942 | (let ((next | 944 | (let ((next |
| @@ -947,12 +949,104 @@ Only meaningful when called from within `smie-rules-function'." | |||
| 947 | (smie-indent-forward-token)))) | 949 | (smie-indent-forward-token)))) |
| 948 | (member (car next) tokens))) | 950 | (member (car next) tokens))) |
| 949 | 951 | ||
| 950 | (defun smie-prev-p (&rest tokens) | 952 | (defun smie-rule-prev-p (&rest tokens) |
| 951 | "Return non-nil if the previous token is among TOKENS." | 953 | "Return non-nil if the previous token is among TOKENS." |
| 952 | (let ((prev (save-excursion | 954 | (let ((prev (save-excursion |
| 953 | (smie-indent-backward-token)))) | 955 | (smie-indent-backward-token)))) |
| 954 | (member (car prev) tokens))) | 956 | (member (car prev) tokens))) |
| 955 | 957 | ||
| 958 | (defun smie-rule-sibling-p () | ||
| 959 | "Return non-nil if the parent is actually a sibling. | ||
| 960 | Only meaningful when called from within `smie-rules-function'." | ||
| 961 | (eq (car (smie-indent--parent)) | ||
| 962 | (cadr (assoc smie--token smie-grammar)))) | ||
| 963 | |||
| 964 | (defun smie-rule-parent (&optional offset) | ||
| 965 | "Align with parent. | ||
| 966 | If non-nil, OFFSET should be an integer giving an additional offset to apply. | ||
| 967 | Only meaningful when called from within `smie-rules-function'." | ||
| 968 | (save-excursion | ||
| 969 | (goto-char (cadr (smie-indent--parent))) | ||
| 970 | (cons 'column | ||
| 971 | (+ (or offset 0) | ||
| 972 | (if (smie-indent--hanging-p) | ||
| 973 | (smie-indent-virtual) (current-column)))))) | ||
| 974 | |||
| 975 | (defvar smie-rule-separator-outdent 2) | ||
| 976 | |||
| 977 | (defun smie-indent--separator-outdent () | ||
| 978 | ;; FIXME: Here we actually have several reasonable behaviors. | ||
| 979 | ;; E.g. for a parent token of "FOO" and a separator ";" we may want to: | ||
| 980 | ;; 1- left-align ; with FOO. | ||
| 981 | ;; 2- right-align ; with FOO. | ||
| 982 | ;; 3- align content after ; with content after FOO. | ||
| 983 | ;; 4- align content plus add/remove spaces so as to align ; with FOO. | ||
| 984 | ;; Currently, we try to align the contents (option 3) which actually behaves | ||
| 985 | ;; just like option 2 (if the number of spaces after FOO and ; is equal). | ||
| 986 | (let ((afterpos (save-excursion | ||
| 987 | (let ((tok (funcall smie-forward-token-function))) | ||
| 988 | (unless tok | ||
| 989 | (with-demoted-errors | ||
| 990 | (error "smie-rule-separator: can't skip token %s" | ||
| 991 | smie--token)))) | ||
| 992 | (skip-chars-forward " ") | ||
| 993 | (unless (eolp) (point))))) | ||
| 994 | (or (and afterpos | ||
| 995 | ;; This should always be true, unless | ||
| 996 | ;; smie-forward-token-function skipped a \n. | ||
| 997 | (< afterpos (line-end-position)) | ||
| 998 | (- afterpos (point))) | ||
| 999 | smie-rule-separator-outdent))) | ||
| 1000 | |||
| 1001 | (defun smie-rule-separator (method) | ||
| 1002 | "Indent current token as a \"separator\". | ||
| 1003 | By \"separator\", we mean here a token whose sole purpose is to separate | ||
| 1004 | various elements within some enclosing syntactic construct, and which does | ||
| 1005 | not have any semantic significance in itself (i.e. it would typically no exist | ||
| 1006 | as a node in an abstract syntax tree). | ||
| 1007 | Such a token is expected to have an associative syntax and be closely tied | ||
| 1008 | to its syntactic parent. Typical examples are \",\" in lists of arguments | ||
| 1009 | \(enclosed inside parentheses), or \";\" in sequences of instructions (enclosed | ||
| 1010 | in a {..} or begin..end block). | ||
| 1011 | METHOD should be the method name that was passed to `smie-rules-function'. | ||
| 1012 | Only meaningful when called from within `smie-rules-function'." | ||
| 1013 | ;; FIXME: The code below works OK for cases where the separators | ||
| 1014 | ;; are placed consistently always at beginning or always at the end, | ||
| 1015 | ;; but not if some are at the beginning and others are at the end. | ||
| 1016 | ;; I.e. it gets confused in cases such as: | ||
| 1017 | ;; ( a | ||
| 1018 | ;; , a, | ||
| 1019 | ;; b | ||
| 1020 | ;; , c, | ||
| 1021 | ;; d | ||
| 1022 | ;; ) | ||
| 1023 | ;; | ||
| 1024 | ;; Assuming token is associative, the default rule for associative | ||
| 1025 | ;; tokens (which assumes an infix operator) works fine for many cases. | ||
| 1026 | ;; We mostly need to take care of the case where token is at beginning of | ||
| 1027 | ;; line, in which case we want to align it with its enclosing parent. | ||
| 1028 | (cond | ||
| 1029 | ((and (eq method :before) (smie-rule-bolp) (not (smie-rule-sibling-p))) | ||
| 1030 | ;; FIXME: Rather than consult the number of spaces, we could *set* the | ||
| 1031 | ;; number of spaces so as to align the separator with the close-paren | ||
| 1032 | ;; while aligning the content with the rest. | ||
| 1033 | (let ((parent-col | ||
| 1034 | (save-excursion | ||
| 1035 | (goto-char (cadr smie--parent)) | ||
| 1036 | (if (smie-indent--hanging-p) | ||
| 1037 | (smie-indent-virtual) (current-column)))) | ||
| 1038 | (parent-pos-col ;FIXME: we knew this when computing smie--parent. | ||
| 1039 | (save-excursion | ||
| 1040 | (goto-char (cadr smie--parent)) | ||
| 1041 | (smie-indent-forward-token) | ||
| 1042 | (forward-comment (point-max)) | ||
| 1043 | (current-column)))) | ||
| 1044 | (cons 'column | ||
| 1045 | (max parent-col | ||
| 1046 | (min parent-pos-col | ||
| 1047 | (- parent-pos-col (smie-indent--separator-outdent))))))) | ||
| 1048 | ((and (eq method :after) (smie-indent--bolp)) | ||
| 1049 | (smie-indent--separator-outdent)))) | ||
| 956 | 1050 | ||
| 957 | (defun smie-indent--offset (elem) | 1051 | (defun smie-indent--offset (elem) |
| 958 | (or (funcall smie-rules-function :elem elem) | 1052 | (or (funcall smie-rules-function :elem elem) |
| @@ -960,76 +1054,60 @@ Only meaningful when called from within `smie-rules-function'." | |||
| 960 | (funcall smie-rules-function :elem 'basic)) | 1054 | (funcall smie-rules-function :elem 'basic)) |
| 961 | smie-indent-basic)) | 1055 | smie-indent-basic)) |
| 962 | 1056 | ||
| 963 | (defun smie-indent--rule (kind token &optional after parent) | 1057 | (defun smie-indent--rule (method token |
| 964 | (let ((smie--parent parent) | 1058 | ;; FIXME: Too many parameters. |
| 965 | (smie--after after)) | 1059 | &optional after parent base-pos) |
| 966 | (funcall smie-rules-function kind token))) | 1060 | "Compute indentation column according to `indent-rule-functions'. |
| 967 | 1061 | METHOD and TOKEN are passed to `indent-rule-functions'. | |
| 968 | (defun smie-indent--column (offset &optional base parent virtual-point) | 1062 | AFTER is the position after TOKEN, if known. |
| 969 | "Compute the actual column to use for a given OFFSET. | 1063 | PARENT is the parent info returned by `smie-backward-sexp', if known. |
| 970 | BASE is the base position to use, and PARENT is the parent info, if any. | 1064 | BASE-POS is the position relative to which offsets should be applied." |
| 971 | If VIRTUAL-POINT is non-nil, then `point' is virtual." | 1065 | ;; This is currently called in 3 cases: |
| 972 | (cond | 1066 | ;; - :before opener, where rest=nil but base-pos could as well be parent. |
| 973 | ((eq (car-safe offset) '+) | 1067 | ;; - :before other, where |
| 974 | (apply '+ (mapcar (lambda (offset) (smie-indent--column offset nil parent)) | 1068 | ;; ; after=nil |
| 975 | (cdr offset)))) | 1069 | ;; ; parent is set |
| 976 | ((integerp offset) | 1070 | ;; ; base-pos=parent |
| 977 | (+ offset | 1071 | ;; - :after tok, where |
| 978 | (case base | 1072 | ;; ; after is set; parent=nil; base-pos=point; |
| 979 | ((nil) 0) | 1073 | (save-excursion |
| 980 | (parent (goto-char (cadr parent)) | 1074 | (let ((offset |
| 981 | (smie-indent-virtual)) | 1075 | (let ((smie--parent parent) |
| 982 | (t | 1076 | (smie--token token) |
| 983 | (goto-char base) | 1077 | (smie--after after)) |
| 984 | ;; For indentation after "(let" in SML-mode, we end up accumulating | 1078 | (funcall smie-rules-function method token)))) |
| 985 | ;; the offset of "(" and the offset of "let", so we use `min' to try | 1079 | (cond |
| 986 | ;; and get it right either way. | 1080 | ((not offset) nil) |
| 987 | (min (smie-indent-virtual) (current-column)))))) | 1081 | ((eq (car-safe offset) 'column) (cdr offset)) |
| 988 | ((eq offset 'point) | 1082 | ((integerp offset) |
| 989 | ;; In indent-keyword, if we're indenting `then' wrt `if', we want to use | 1083 | (+ offset |
| 990 | ;; indent-virtual rather than use just current-column, so that we can | 1084 | (if (null base-pos) 0 |
| 991 | ;; apply the (:before . "if") rule which does the "else if" dance in SML. | 1085 | (goto-char base-pos) |
| 992 | ;; But in other cases, we do not want to use indent-virtual | 1086 | (if (smie-indent--hanging-p) |
| 993 | ;; (e.g. indentation of "*" w.r.t "+", or ";" wrt "("). We could just | 1087 | (smie-indent-virtual) (current-column))))) |
| 994 | ;; always use indent-virtual and then have indent-rules say explicitly | 1088 | (t (error "Unknown indentation offset %s" offset)))))) |
| 995 | ;; to use `point' after things like "(" or "+" when they're not at EOL, | ||
| 996 | ;; but you'd end up with lots of those rules. | ||
| 997 | ;; So we use a heuristic here, which is that we only use virtual if | ||
| 998 | ;; the parent is tightly linked to the child token (they're part of | ||
| 999 | ;; the same BNF rule). | ||
| 1000 | (if (and virtual-point (null (car parent))) ;Black magic :-( | ||
| 1001 | (smie-indent-virtual) (current-column))) | ||
| 1002 | ((eq offset 'parent) | ||
| 1003 | (unless parent | ||
| 1004 | (setq parent (or (smie-backward-sexp 'halfsexp) :notfound))) | ||
| 1005 | (if (consp parent) (goto-char (cadr parent))) | ||
| 1006 | (smie-indent-virtual)) | ||
| 1007 | ((eq offset nil) nil) | ||
| 1008 | ;; FIXME: would be good to get rid of this since smie-rules-function | ||
| 1009 | ;; can usually do the lookup trivially, but in cases where | ||
| 1010 | ;; smie-rules-function returns (+ point VAR) it's not nearly as trivial. | ||
| 1011 | ((and (symbolp offset) (boundp 'offset)) | ||
| 1012 | (smie-indent--column (symbol-value offset) base parent virtual-point)) | ||
| 1013 | (t (error "Unknown indentation offset %s" offset)))) | ||
| 1014 | 1089 | ||
| 1015 | (defun smie-indent-forward-token () | 1090 | (defun smie-indent-forward-token () |
| 1016 | "Skip token forward and return it, along with its levels." | 1091 | "Skip token forward and return it, along with its levels." |
| 1017 | (let ((tok (funcall smie-forward-token-function))) | 1092 | (let ((tok (funcall smie-forward-token-function))) |
| 1018 | (cond | 1093 | (cond |
| 1019 | ((< 0 (length tok)) (assoc tok smie-op-levels)) | 1094 | ((< 0 (length tok)) (assoc tok smie-grammar)) |
| 1020 | ((looking-at "\\s(") | 1095 | ((looking-at "\\s(\\|\\s)\\(\\)") |
| 1021 | (forward-char 1) | 1096 | (forward-char 1) |
| 1022 | (list (buffer-substring (1- (point)) (point)) nil 0))))) | 1097 | (cons (buffer-substring (1- (point)) (point)) |
| 1098 | (if (match-end 1) '(0 nil) '(nil 0))))))) | ||
| 1023 | 1099 | ||
| 1024 | (defun smie-indent-backward-token () | 1100 | (defun smie-indent-backward-token () |
| 1025 | "Skip token backward and return it, along with its levels." | 1101 | "Skip token backward and return it, along with its levels." |
| 1026 | (let ((tok (funcall smie-backward-token-function))) | 1102 | (let ((tok (funcall smie-backward-token-function)) |
| 1103 | class) | ||
| 1027 | (cond | 1104 | (cond |
| 1028 | ((< 0 (length tok)) (assoc tok smie-op-levels)) | 1105 | ((< 0 (length tok)) (assoc tok smie-grammar)) |
| 1029 | ;; 4 == Open paren syntax. | 1106 | ;; 4 == open paren syntax, 5 == close. |
| 1030 | ((eq 4 (syntax-class (syntax-after (1- (point))))) | 1107 | ((memq (setq class (syntax-class (syntax-after (1- (point))))) '(4 5)) |
| 1031 | (forward-char -1) | 1108 | (forward-char -1) |
| 1032 | (list (buffer-substring (point) (1+ (point))) nil 0))))) | 1109 | (cons (buffer-substring (point) (1+ (point))) |
| 1110 | (if (eq class 4) '(nil 0) '(0 nil))))))) | ||
| 1033 | 1111 | ||
| 1034 | (defun smie-indent-virtual () | 1112 | (defun smie-indent-virtual () |
| 1035 | ;; We used to take an optional arg (with value :not-hanging) to specify that | 1113 | ;; We used to take an optional arg (with value :not-hanging) to specify that |
| @@ -1042,11 +1120,11 @@ This is used when we're not trying to indent point but just | |||
| 1042 | need to compute the column at which point should be indented | 1120 | need to compute the column at which point should be indented |
| 1043 | in order to figure out the indentation of some other (further down) point." | 1121 | in order to figure out the indentation of some other (further down) point." |
| 1044 | ;; Trust pre-existing indentation on other lines. | 1122 | ;; Trust pre-existing indentation on other lines. |
| 1045 | (if (smie-bolp) (current-column) (smie-indent-calculate))) | 1123 | (if (smie-indent--bolp) (current-column) (smie-indent-calculate))) |
| 1046 | 1124 | ||
| 1047 | (defun smie-indent-fixindent () | 1125 | (defun smie-indent-fixindent () |
| 1048 | ;; Obey the `fixindent' special comment. | 1126 | ;; Obey the `fixindent' special comment. |
| 1049 | (and (smie-bolp) | 1127 | (and (smie-indent--bolp) |
| 1050 | (save-excursion | 1128 | (save-excursion |
| 1051 | (comment-normalize-vars) | 1129 | (comment-normalize-vars) |
| 1052 | (re-search-forward (concat comment-start-skip | 1130 | (re-search-forward (concat comment-start-skip |
| @@ -1086,31 +1164,25 @@ in order to figure out the indentation of some other (further down) point." | |||
| 1086 | (save-excursion | 1164 | (save-excursion |
| 1087 | (goto-char pos) | 1165 | (goto-char pos) |
| 1088 | ;; Different cases: | 1166 | ;; Different cases: |
| 1089 | ;; - smie-bolp: "indent according to others". | 1167 | ;; - smie-indent--bolp: "indent according to others". |
| 1090 | ;; - common hanging: "indent according to others". | 1168 | ;; - common hanging: "indent according to others". |
| 1091 | ;; - SML-let hanging: "indent like parent". | 1169 | ;; - SML-let hanging: "indent like parent". |
| 1092 | ;; - if-after-else: "indent-like parent". | 1170 | ;; - if-after-else: "indent-like parent". |
| 1093 | ;; - middle-of-line: "trust current position". | 1171 | ;; - middle-of-line: "trust current position". |
| 1094 | (cond | 1172 | (cond |
| 1095 | ((null (cdr toklevels)) nil) ;Not a keyword. | 1173 | ((null (cdr toklevels)) nil) ;Not a keyword. |
| 1096 | ((smie-bolp) | 1174 | ((smie-indent--bolp) |
| 1097 | ;; For an open-paren-like thingy at BOL, always indent only | 1175 | ;; For an open-paren-like thingy at BOL, always indent only |
| 1098 | ;; based on other rules (typically smie-indent-after-keyword). | 1176 | ;; based on other rules (typically smie-indent-after-keyword). |
| 1099 | nil) | 1177 | nil) |
| 1178 | ;; We're only ever here for virtual-indent. | ||
| 1179 | ((smie-indent--rule :before token)) | ||
| 1100 | (t | 1180 | (t |
| 1101 | ;; We're only ever here for virtual-indent, which is why | 1181 | ;; By default use point unless we're hanging. |
| 1102 | ;; we can use (current-column) as answer for `point'. | 1182 | (unless (smie-indent--hanging-p) (current-column))))) |
| 1103 | (let* ((offset (or (smie-indent--rule :before token) | ||
| 1104 | ;; By default use point unless we're hanging. | ||
| 1105 | (unless (smie-hanging-p) 'point)))) | ||
| 1106 | (smie-indent--column offset))))) | ||
| 1107 | 1183 | ||
| 1108 | ;; FIXME: This still looks too much like black magic!! | 1184 | ;; FIXME: This still looks too much like black magic!! |
| 1109 | (let* ((parent (smie-backward-sexp 'halfsexp)) | 1185 | (let* ((parent (smie-backward-sexp 'halfsexp))) |
| 1110 | (offset (save-excursion | ||
| 1111 | (goto-char pos) | ||
| 1112 | (or (smie-indent--rule :before token nil parent) | ||
| 1113 | 'point)))) | ||
| 1114 | ;; Different behaviors: | 1186 | ;; Different behaviors: |
| 1115 | ;; - align with parent. | 1187 | ;; - align with parent. |
| 1116 | ;; - parent + offset. | 1188 | ;; - parent + offset. |
| @@ -1133,21 +1205,15 @@ in order to figure out the indentation of some other (further down) point." | |||
| 1133 | ;; maybe when an infix or close-paren is at the beginning | 1205 | ;; maybe when an infix or close-paren is at the beginning |
| 1134 | ;; of a buffer. | 1206 | ;; of a buffer. |
| 1135 | nil) | 1207 | nil) |
| 1208 | ((save-excursion | ||
| 1209 | (goto-char pos) | ||
| 1210 | (smie-indent--rule :before token nil parent (cadr parent)))) | ||
| 1136 | ((eq (car parent) (car toklevels)) | 1211 | ((eq (car parent) (car toklevels)) |
| 1137 | ;; We bumped into a same-level operator. align with it. | 1212 | ;; We bumped into a same-level operator; align with it. |
| 1138 | (if (and (smie-bolp) (/= (point) pos) | 1213 | (if (and (smie-indent--bolp) (/= (point) pos) |
| 1139 | (save-excursion | 1214 | (save-excursion |
| 1140 | (goto-char (goto-char (cadr parent))) | 1215 | (goto-char (goto-char (cadr parent))) |
| 1141 | (not (smie-bolp))) | 1216 | (not (smie-indent--bolp)))) |
| 1142 | ;; Check the offset of `token' rather then its parent | ||
| 1143 | ;; because its parent may have used a special rule. E.g. | ||
| 1144 | ;; function foo; | ||
| 1145 | ;; line2; | ||
| 1146 | ;; line3; | ||
| 1147 | ;; The ; on the first line had a special rule, but when | ||
| 1148 | ;; indenting line3, we don't care about it and want to | ||
| 1149 | ;; align with line2. | ||
| 1150 | (memq offset '(point nil))) | ||
| 1151 | ;; If the parent is at EOL and its children are indented like | 1217 | ;; If the parent is at EOL and its children are indented like |
| 1152 | ;; itself, then we can just obey the indentation chosen for the | 1218 | ;; itself, then we can just obey the indentation chosen for the |
| 1153 | ;; child. | 1219 | ;; child. |
| @@ -1175,25 +1241,33 @@ in order to figure out the indentation of some other (further down) point." | |||
| 1175 | ;; So as to align with the earliest appropriate place. | 1241 | ;; So as to align with the earliest appropriate place. |
| 1176 | (smie-indent-virtual))) | 1242 | (smie-indent-virtual))) |
| 1177 | (t | 1243 | (t |
| 1178 | (if (and (= (point) pos) (smie-bolp) | 1244 | (if (and (= (point) pos) (smie-indent--bolp)) |
| 1179 | (or (eq offset 'point) | ||
| 1180 | (and (consp offset) (memq 'point offset)))) | ||
| 1181 | ;; Since we started at BOL, we're not computing a virtual | 1245 | ;; Since we started at BOL, we're not computing a virtual |
| 1182 | ;; indentation, and we're still at the starting point, so | 1246 | ;; indentation, and we're still at the starting point, so |
| 1183 | ;; we can't use `current-column' which would cause | 1247 | ;; we can't use `current-column' which would cause |
| 1184 | ;; indentation to depend on itself. | 1248 | ;; indentation to depend on itself and we can't use |
| 1249 | ;; smie-indent-virtual since that would be an inf-loop. | ||
| 1185 | nil | 1250 | nil |
| 1186 | (smie-indent--column offset 'parent parent | 1251 | ;; In indent-keyword, if we're indenting `then' wrt `if', we |
| 1187 | ;; If we're still at pos, indent-virtual | 1252 | ;; want to use indent-virtual rather than use just |
| 1188 | ;; will inf-loop. | 1253 | ;; current-column, so that we can apply the (:before . "if") |
| 1189 | (unless (= (point) pos) 'virtual)))))))))) | 1254 | ;; rule which does the "else if" dance in SML. But in other |
| 1255 | ;; cases, we do not want to use indent-virtual (e.g. indentation | ||
| 1256 | ;; of "*" w.r.t "+", or ";" wrt "("). We could just always use | ||
| 1257 | ;; indent-virtual and then have indent-rules say explicitly to | ||
| 1258 | ;; use `point' after things like "(" or "+" when they're not at | ||
| 1259 | ;; EOL, but you'd end up with lots of those rules. | ||
| 1260 | ;; So we use a heuristic here, which is that we only use virtual | ||
| 1261 | ;; if the parent is tightly linked to the child token (they're | ||
| 1262 | ;; part of the same BNF rule). | ||
| 1263 | (if (car parent) (current-column) (smie-indent-virtual)))))))))) | ||
| 1190 | 1264 | ||
| 1191 | (defun smie-indent-comment () | 1265 | (defun smie-indent-comment () |
| 1192 | "Compute indentation of a comment." | 1266 | "Compute indentation of a comment." |
| 1193 | ;; Don't do it for virtual indentations. We should normally never be "in | 1267 | ;; Don't do it for virtual indentations. We should normally never be "in |
| 1194 | ;; front of a comment" when doing virtual-indentation anyway. And if we are | 1268 | ;; front of a comment" when doing virtual-indentation anyway. And if we are |
| 1195 | ;; (as can happen in octave-mode), moving forward can lead to inf-loops. | 1269 | ;; (as can happen in octave-mode), moving forward can lead to inf-loops. |
| 1196 | (and (smie-bolp) | 1270 | (and (smie-indent--bolp) |
| 1197 | (let ((pos (point))) | 1271 | (let ((pos (point))) |
| 1198 | (save-excursion | 1272 | (save-excursion |
| 1199 | (beginning-of-line) | 1273 | (beginning-of-line) |
| @@ -1239,17 +1313,17 @@ in order to figure out the indentation of some other (further down) point." | |||
| 1239 | (let* ((pos (point)) | 1313 | (let* ((pos (point)) |
| 1240 | (toklevel (smie-indent-backward-token)) | 1314 | (toklevel (smie-indent-backward-token)) |
| 1241 | (tok (car toklevel))) | 1315 | (tok (car toklevel))) |
| 1242 | (when toklevel | 1316 | (cond |
| 1243 | (let ((offset | 1317 | ((null toklevel) nil) |
| 1244 | (or (smie-indent--rule :after tok pos) | 1318 | ((smie-indent--rule :after tok pos nil (point))) |
| 1245 | ;; The default indentation after a keyword/operator is | 1319 | ;; The default indentation after a keyword/operator is |
| 1246 | ;; 0 for infix and t for prefix. | 1320 | ;; 0 for infix, t for prefix, and use another rule |
| 1247 | (if (or (null (cadr toklevel)) | 1321 | ;; for postfix. |
| 1248 | (rassoc tok smie-closer-alist)) | 1322 | ((null (nth 2 toklevel)) nil) ;A closer. |
| 1249 | (smie-indent--offset 'basic) 0))) | 1323 | ((or (null (nth 1 toklevel)) ;An opener. |
| 1250 | (before (point))) | 1324 | (rassoc tok smie-closer-alist)) ;An inner. |
| 1251 | (goto-char pos) | 1325 | (+ (smie-indent-virtual) (smie-indent--offset 'basic))) ; |
| 1252 | (smie-indent--column offset before)))))) | 1326 | (t (smie-indent-virtual)))))) ;An infix. |
| 1253 | 1327 | ||
| 1254 | (defun smie-indent-exps () | 1328 | (defun smie-indent-exps () |
| 1255 | ;; Indentation of sequences of simple expressions without | 1329 | ;; Indentation of sequences of simple expressions without |
| @@ -1272,7 +1346,7 @@ in order to figure out the indentation of some other (further down) point." | |||
| 1272 | arg) | 1346 | arg) |
| 1273 | (while (and (null (car (smie-backward-sexp))) | 1347 | (while (and (null (car (smie-backward-sexp))) |
| 1274 | (push (point) positions) | 1348 | (push (point) positions) |
| 1275 | (not (smie-bolp)))) | 1349 | (not (smie-indent--bolp)))) |
| 1276 | (save-excursion | 1350 | (save-excursion |
| 1277 | ;; Figure out if the atom we just skipped is an argument rather | 1351 | ;; Figure out if the atom we just skipped is an argument rather |
| 1278 | ;; than a function. | 1352 | ;; than a function. |
| @@ -1298,7 +1372,6 @@ in order to figure out the indentation of some other (further down) point." | |||
| 1298 | (positions | 1372 | (positions |
| 1299 | ;; We're the first arg. | 1373 | ;; We're the first arg. |
| 1300 | (goto-char (car positions)) | 1374 | (goto-char (car positions)) |
| 1301 | ;; FIXME: Use smie-indent--column. | ||
| 1302 | (+ (smie-indent--offset 'args) | 1375 | (+ (smie-indent--offset 'args) |
| 1303 | ;; We used to use (smie-indent-virtual), but that | 1376 | ;; We used to use (smie-indent-virtual), but that |
| 1304 | ;; doesn't seem right since it might then indent args less than | 1377 | ;; doesn't seem right since it might then indent args less than |
| @@ -1307,9 +1380,9 @@ in order to figure out the indentation of some other (further down) point." | |||
| 1307 | 1380 | ||
| 1308 | (defvar smie-indent-functions | 1381 | (defvar smie-indent-functions |
| 1309 | '(smie-indent-fixindent smie-indent-bob smie-indent-close | 1382 | '(smie-indent-fixindent smie-indent-bob smie-indent-close |
| 1310 | smie-indent-comment smie-indent-comment-continue smie-indent-comment-close | 1383 | smie-indent-comment smie-indent-comment-continue smie-indent-comment-close |
| 1311 | smie-indent-comment-inside smie-indent-keyword smie-indent-after-keyword | 1384 | smie-indent-comment-inside smie-indent-keyword smie-indent-after-keyword |
| 1312 | smie-indent-exps) | 1385 | smie-indent-exps) |
| 1313 | "Functions to compute the indentation. | 1386 | "Functions to compute the indentation. |
| 1314 | Each function is called with no argument, shouldn't move point, and should | 1387 | Each function is called with no argument, shouldn't move point, and should |
| 1315 | return either nil if it has no opinion, or an integer representing the column | 1388 | return either nil if it has no opinion, or an integer representing the column |
| @@ -1323,13 +1396,13 @@ to which that point should be aligned, if we were to reindent it.") | |||
| 1323 | "Indent current line using the SMIE indentation engine." | 1396 | "Indent current line using the SMIE indentation engine." |
| 1324 | (interactive) | 1397 | (interactive) |
| 1325 | (let* ((savep (point)) | 1398 | (let* ((savep (point)) |
| 1326 | (indent (condition-case-no-debug nil | 1399 | (indent (or (with-demoted-errors |
| 1327 | (save-excursion | 1400 | (save-excursion |
| 1328 | (forward-line 0) | 1401 | (forward-line 0) |
| 1329 | (skip-chars-forward " \t") | 1402 | (skip-chars-forward " \t") |
| 1330 | (if (>= (point) savep) (setq savep nil)) | 1403 | (if (>= (point) savep) (setq savep nil)) |
| 1331 | (or (smie-indent-calculate) 0)) | 1404 | (or (smie-indent-calculate) 0))) |
| 1332 | (error 0)))) | 1405 | 0))) |
| 1333 | (if (not (numberp indent)) | 1406 | (if (not (numberp indent)) |
| 1334 | ;; If something funny is used (e.g. `noindent'), return it. | 1407 | ;; If something funny is used (e.g. `noindent'), return it. |
| 1335 | indent | 1408 | indent |
| @@ -1338,15 +1411,15 @@ to which that point should be aligned, if we were to reindent it.") | |||
| 1338 | (save-excursion (indent-line-to indent)) | 1411 | (save-excursion (indent-line-to indent)) |
| 1339 | (indent-line-to indent))))) | 1412 | (indent-line-to indent))))) |
| 1340 | 1413 | ||
| 1341 | (defun smie-setup (op-levels rules-function &rest keywords) | 1414 | (defun smie-setup (grammar rules-function &rest keywords) |
| 1342 | "Setup SMIE navigation and indentation. | 1415 | "Setup SMIE navigation and indentation. |
| 1343 | OP-LEVELS is a grammar table generated by `smie-prec2-levels'. | 1416 | GRAMMAR is a grammar table generated by `smie-prec2->grammar'. |
| 1344 | RULES-FUNCTION is a set of indentation rules for use on `smie-rules-function'. | 1417 | RULES-FUNCTION is a set of indentation rules for use on `smie-rules-function'. |
| 1345 | KEYWORDS are additional arguments, which can use the following keywords: | 1418 | KEYWORDS are additional arguments, which can use the following keywords: |
| 1346 | - :forward-token FUN | 1419 | - :forward-token FUN |
| 1347 | - :backward-token FUN" | 1420 | - :backward-token FUN" |
| 1348 | (set (make-local-variable 'smie-rules-function) rules-function) | 1421 | (set (make-local-variable 'smie-rules-function) rules-function) |
| 1349 | (set (make-local-variable 'smie-op-levels) op-levels) | 1422 | (set (make-local-variable 'smie-grammar) grammar) |
| 1350 | (set (make-local-variable 'indent-line-function) 'smie-indent-line) | 1423 | (set (make-local-variable 'indent-line-function) 'smie-indent-line) |
| 1351 | (set (make-local-variable 'forward-sexp-function) | 1424 | (set (make-local-variable 'forward-sexp-function) |
| 1352 | 'smie-forward-sexp-command) | 1425 | 'smie-forward-sexp-command) |
| @@ -1359,7 +1432,7 @@ KEYWORDS are additional arguments, which can use the following keywords: | |||
| 1359 | (:backward-token | 1432 | (:backward-token |
| 1360 | (set (make-local-variable 'smie-backward-token-function) v)) | 1433 | (set (make-local-variable 'smie-backward-token-function) v)) |
| 1361 | (t (message "smie-setup: ignoring unknown keyword %s" k))))) | 1434 | (t (message "smie-setup: ignoring unknown keyword %s" k))))) |
| 1362 | (let ((ca (cdr (assq :smie-closer-alist op-levels)))) | 1435 | (let ((ca (cdr (assq :smie-closer-alist grammar)))) |
| 1363 | (when ca | 1436 | (when ca |
| 1364 | (set (make-local-variable 'smie-closer-alist) ca) | 1437 | (set (make-local-variable 'smie-closer-alist) ca) |
| 1365 | ;; Only needed for interactive calls to blink-matching-open. | 1438 | ;; Only needed for interactive calls to blink-matching-open. |
diff --git a/lisp/progmodes/octave-mod.el b/lisp/progmodes/octave-mod.el index fdd5e867b7b..2402540bfb6 100644 --- a/lisp/progmodes/octave-mod.el +++ b/lisp/progmodes/octave-mod.el | |||
| @@ -446,14 +446,13 @@ Non-nil means always go to the next Octave code line after sending." | |||
| 446 | ;; (fundesc (atom "=" atom)) | 446 | ;; (fundesc (atom "=" atom)) |
| 447 | )) | 447 | )) |
| 448 | 448 | ||
| 449 | (defconst octave-smie-op-levels | 449 | (defconst octave-smie-grammar |
| 450 | (smie-prec2-levels | 450 | (smie-prec2->grammar |
| 451 | (smie-merge-prec2s | 451 | (smie-merge-prec2s |
| 452 | (smie-bnf-precedence-table | 452 | (smie-bnf->prec2 octave-smie-bnf-table |
| 453 | octave-smie-bnf-table | 453 | '((assoc "\n" ";"))) |
| 454 | '((assoc "\n" ";"))) | ||
| 455 | 454 | ||
| 456 | (smie-precs-precedence-table octave-operator-table)))) | 455 | (smie-precs->prec2 octave-operator-table)))) |
| 457 | 456 | ||
| 458 | ;; Tokenizing needs to be refined so that ";;" is treated as two | 457 | ;; Tokenizing needs to be refined so that ";;" is treated as two |
| 459 | ;; tokens and also so as to recognize the \n separator (and | 458 | ;; tokens and also so as to recognize the \n separator (and |
| @@ -520,13 +519,19 @@ Non-nil means always go to the next Octave code line after sending." | |||
| 520 | 519 | ||
| 521 | (defun octave-smie-rules (kind token) | 520 | (defun octave-smie-rules (kind token) |
| 522 | (pcase (cons kind token) | 521 | (pcase (cons kind token) |
| 522 | ;; We could set smie-indent-basic instead, but that would have two | ||
| 523 | ;; disadvantages: | ||
| 524 | ;; - changes to octave-block-offset wouldn't take effect immediately. | ||
| 525 | ;; - edebug wouldn't show the use of this variable. | ||
| 523 | (`(:elem . basic) octave-block-offset) | 526 | (`(:elem . basic) octave-block-offset) |
| 524 | (`(:before . "case") octave-block-offset) | 527 | ;; Since "case" is in the same BNF rules as switch..end, SMIE by default |
| 528 | ;; aligns it with "switch". | ||
| 529 | (`(:before . "case") (if (not (smie-rule-sibling-p)) octave-block-offset)) | ||
| 525 | (`(:after . ";") | 530 | (`(:after . ";") |
| 526 | (if (smie-parent-p "function" "if" "while" "else" "elseif" "for" | 531 | (if (smie-rule-parent-p "function" "if" "while" "else" "elseif" "for" |
| 527 | "otherwise" "case" "try" "catch" "unwind_protect" | 532 | "otherwise" "case" "try" "catch" "unwind_protect" |
| 528 | "unwind_protect_cleanup") | 533 | "unwind_protect_cleanup") |
| 529 | '(+ parent octave-block-offset) | 534 | (smie-rule-parent octave-block-offset) |
| 530 | ;; For (invalid) code between switch and case. | 535 | ;; For (invalid) code between switch and case. |
| 531 | ;; (if (smie-parent-p "switch") 4) | 536 | ;; (if (smie-parent-p "switch") 4) |
| 532 | 0)))) | 537 | 0)))) |
| @@ -619,7 +624,7 @@ already added. You just need to add a description of the problem, | |||
| 619 | including a reproducible test case and send the message." | 624 | including a reproducible test case and send the message." |
| 620 | (setq local-abbrev-table octave-abbrev-table) | 625 | (setq local-abbrev-table octave-abbrev-table) |
| 621 | 626 | ||
| 622 | (smie-setup octave-smie-op-levels #'octave-smie-rules | 627 | (smie-setup octave-smie-grammar #'octave-smie-rules |
| 623 | :forward-token #'octave-smie-forward-token | 628 | :forward-token #'octave-smie-forward-token |
| 624 | :backward-token #'octave-smie-backward-token) | 629 | :backward-token #'octave-smie-backward-token) |
| 625 | (set (make-local-variable 'smie-indent-basic) 'octave-block-offset) | 630 | (set (make-local-variable 'smie-indent-basic) 'octave-block-offset) |
diff --git a/lisp/progmodes/prolog.el b/lisp/progmodes/prolog.el index dd17c4b6086..f2f80d0d81d 100644 --- a/lisp/progmodes/prolog.el +++ b/lisp/progmodes/prolog.el | |||
| @@ -123,7 +123,7 @@ When nil, send actual operating system end of file." | |||
| 123 | ((not (zerop (skip-syntax-backward "."))))) | 123 | ((not (zerop (skip-syntax-backward "."))))) |
| 124 | (point)))) | 124 | (point)))) |
| 125 | 125 | ||
| 126 | (defconst prolog-smie-op-levels | 126 | (defconst prolog-smie-grammar |
| 127 | ;; Rather than construct the operator levels table from the BNF, | 127 | ;; Rather than construct the operator levels table from the BNF, |
| 128 | ;; we directly provide the operator precedences from GNU Prolog's | 128 | ;; we directly provide the operator precedences from GNU Prolog's |
| 129 | ;; manual (7.14.10 op/3). The only problem is that GNU Prolog's | 129 | ;; manual (7.14.10 op/3). The only problem is that GNU Prolog's |
| @@ -188,7 +188,7 @@ When nil, send actual operating system end of file." | |||
| 188 | (setq imenu-generic-expression '((nil "^\\sw+" 0))) | 188 | (setq imenu-generic-expression '((nil "^\\sw+" 0))) |
| 189 | 189 | ||
| 190 | ;; Setup SMIE. | 190 | ;; Setup SMIE. |
| 191 | (smie-setup prolog-smie-op-levels #'prolog-smie-rules | 191 | (smie-setup prolog-smie-grammar #'prolog-smie-rules |
| 192 | :forward-token #'prolog-smie-forward-token | 192 | :forward-token #'prolog-smie-forward-token |
| 193 | :backward-token #'prolog-smie-backward-token) | 193 | :backward-token #'prolog-smie-backward-token) |
| 194 | (set (make-local-variable 'smie-blink-matching-triggers) '(?.)) | 194 | (set (make-local-variable 'smie-blink-matching-triggers) '(?.)) |