diff options
| author | Stefan Monnier | 2010-08-30 22:34:52 +0200 |
|---|---|---|
| committer | Stefan Monnier | 2010-08-30 22:34:52 +0200 |
| commit | e17b68ed837cc835c46b4e518d05810a73997ac5 (patch) | |
| tree | 72a9fb443a06e264878b9955b529317e1efee50c /lisp | |
| parent | 42b6a73bc70429b7997fa18986a72341f98840f8 (diff) | |
| download | emacs-e17b68ed837cc835c46b4e518d05810a73997ac5.tar.gz emacs-e17b68ed837cc835c46b4e518d05810a73997ac5.zip | |
Use SMIE for octave-mode.
* test/indent/octave.m: New file.
* lisp/progmodes/octave-mod.el (octave-font-lock-keywords): Use regexp-opt.
(octave-mode-map): Remove special bindings for forward/backward-block
and octave-backward-up-block. Use smie-close-block.
(octave-continuation-marker-regexp): New var.
(octave-continuation-regexp): Use it.
(octave-operator-table, octave-smie-op-levels)
(octave-operator-regexp, octave-smie-indent-rules): New vars.
(octave-smie-backward-token, octave-smie-forward-token): New funs.
(octave-mode): Use SMIE.
(octave-close-block): Delete.
Diffstat (limited to 'lisp')
| -rw-r--r-- | lisp/ChangeLog | 13 | ||||
| -rw-r--r-- | lisp/progmodes/octave-mod.el | 193 |
2 files changed, 170 insertions, 36 deletions
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 65ec210f8ef..8e9c9a7b251 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,3 +1,16 @@ | |||
| 1 | 2010-08-30 Stefan Monnier <monnier@iro.umontreal.ca> | ||
| 2 | |||
| 3 | * progmodes/octave-mod.el (octave-font-lock-keywords): Use regexp-opt. | ||
| 4 | (octave-mode-map): Remove special bindings for forward/backward-block | ||
| 5 | and octave-backward-up-block. Use smie-close-block. | ||
| 6 | (octave-continuation-marker-regexp): New var. | ||
| 7 | (octave-continuation-regexp): Use it. | ||
| 8 | (octave-operator-table, octave-smie-op-levels) | ||
| 9 | (octave-operator-regexp, octave-smie-indent-rules): New vars. | ||
| 10 | (octave-smie-backward-token, octave-smie-forward-token): New funs. | ||
| 11 | (octave-mode): Use SMIE. | ||
| 12 | (octave-close-block): Delete. | ||
| 13 | |||
| 1 | 2010-08-30 Eli Zaretskii <eliz@gnu.org> | 14 | 2010-08-30 Eli Zaretskii <eliz@gnu.org> |
| 2 | 15 | ||
| 3 | * menu-bar.el (menu-bar-edit-menu) <"Paste">: Check selection in | 16 | * menu-bar.el (menu-bar-edit-menu) <"Paste">: Check selection in |
diff --git a/lisp/progmodes/octave-mod.el b/lisp/progmodes/octave-mod.el index 11d86ecbde4..bc007180678 100644 --- a/lisp/progmodes/octave-mod.el +++ b/lisp/progmodes/octave-mod.el | |||
| @@ -161,8 +161,8 @@ parenthetical grouping.") | |||
| 161 | (list | 161 | (list |
| 162 | ;; Fontify all builtin keywords. | 162 | ;; Fontify all builtin keywords. |
| 163 | (cons (concat "\\<\\(" | 163 | (cons (concat "\\<\\(" |
| 164 | (mapconcat 'identity octave-reserved-words "\\|") | 164 | (regexp-opt (append octave-reserved-words |
| 165 | (mapconcat 'identity octave-text-functions "\\|") | 165 | octave-text-functions)) |
| 166 | "\\)\\>") | 166 | "\\)\\>") |
| 167 | 'font-lock-keyword-face) | 167 | 'font-lock-keyword-face) |
| 168 | ;; Fontify all builtin operators. | 168 | ;; Fontify all builtin operators. |
| @@ -223,13 +223,10 @@ parenthetical grouping.") | |||
| 223 | (define-key map "\C-c\C-n" 'octave-next-code-line) | 223 | (define-key map "\C-c\C-n" 'octave-next-code-line) |
| 224 | (define-key map "\C-c\C-a" 'octave-beginning-of-line) | 224 | (define-key map "\C-c\C-a" 'octave-beginning-of-line) |
| 225 | (define-key map "\C-c\C-e" 'octave-end-of-line) | 225 | (define-key map "\C-c\C-e" 'octave-end-of-line) |
| 226 | (define-key map "\C-c\M-\C-n" 'octave-forward-block) | ||
| 227 | (define-key map "\C-c\M-\C-p" 'octave-backward-block) | ||
| 228 | (define-key map "\C-c\M-\C-u" 'octave-backward-up-block) | ||
| 229 | (define-key map "\C-c\M-\C-d" 'octave-down-block) | 226 | (define-key map "\C-c\M-\C-d" 'octave-down-block) |
| 230 | (define-key map "\C-c\M-\C-h" 'octave-mark-block) | 227 | (define-key map "\C-c\M-\C-h" 'octave-mark-block) |
| 231 | (define-key map "\C-c]" 'octave-close-block) | 228 | (define-key map "\C-c]" 'smie-close-block) |
| 232 | (define-key map "\C-c/" 'octave-close-block) | 229 | (define-key map "\C-c/" 'smie-close-block) |
| 233 | (define-key map "\C-c\C-f" 'octave-insert-defun) | 230 | (define-key map "\C-c\C-f" 'octave-insert-defun) |
| 234 | (define-key map "\C-c\C-h" 'octave-help) | 231 | (define-key map "\C-c\C-h" 'octave-help) |
| 235 | (define-key map "\C-c\C-il" 'octave-send-line) | 232 | (define-key map "\C-c\C-il" 'octave-send-line) |
| @@ -261,12 +258,9 @@ parenthetical grouping.") | |||
| 261 | ["End of Continuation" octave-end-of-line t] | 258 | ["End of Continuation" octave-end-of-line t] |
| 262 | ["Split Line at Point" octave-indent-new-comment-line t]) | 259 | ["Split Line at Point" octave-indent-new-comment-line t]) |
| 263 | ("Blocks" | 260 | ("Blocks" |
| 264 | ["Next Block" octave-forward-block t] | ||
| 265 | ["Previous Block" octave-backward-block t] | ||
| 266 | ["Down Block" octave-down-block t] | 261 | ["Down Block" octave-down-block t] |
| 267 | ["Up Block" octave-backward-up-block t] | ||
| 268 | ["Mark Block" octave-mark-block t] | 262 | ["Mark Block" octave-mark-block t] |
| 269 | ["Close Block" octave-close-block t]) | 263 | ["Close Block" smie-close-block t]) |
| 270 | ("Functions" | 264 | ("Functions" |
| 271 | ["Indent Function" octave-indent-defun t] | 265 | ["Indent Function" octave-indent-defun t] |
| 272 | ["Insert Function" octave-insert-defun t]) | 266 | ["Insert Function" octave-insert-defun t]) |
| @@ -386,8 +380,11 @@ end keywords as associated values.") | |||
| 386 | "Extra indentation applied to Octave continuation lines." | 380 | "Extra indentation applied to Octave continuation lines." |
| 387 | :type 'integer | 381 | :type 'integer |
| 388 | :group 'octave) | 382 | :group 'octave) |
| 383 | (eval-and-compile | ||
| 384 | (defconst octave-continuation-marker-regexp "\\\\\\|\\.\\.\\.")) | ||
| 389 | (defvar octave-continuation-regexp | 385 | (defvar octave-continuation-regexp |
| 390 | "[^#%\n]*\\(\\\\\\|\\.\\.\\.\\)\\s-*\\(\\s<.*\\)?$") | 386 | (concat "[^#%\n]*\\(" octave-continuation-marker-regexp |
| 387 | "\\)\\s-*\\(\\s<.*\\)?$")) | ||
| 391 | (defcustom octave-continuation-string "\\" | 388 | (defcustom octave-continuation-string "\\" |
| 392 | "Character string used for Octave continuation lines. Normally \\." | 389 | "Character string used for Octave continuation lines. Normally \\." |
| 393 | :type 'string | 390 | :type 'string |
| @@ -425,6 +422,143 @@ Non-nil means always go to the next Octave code line after sending." | |||
| 425 | :group 'octave) | 422 | :group 'octave) |
| 426 | 423 | ||
| 427 | 424 | ||
| 425 | ;;; SMIE indentation | ||
| 426 | |||
| 427 | (require 'smie) | ||
| 428 | |||
| 429 | (defconst octave-operator-table | ||
| 430 | '((assoc ";" "\n") (assoc ",") ; The doc claims they have equal precedence!? | ||
| 431 | (right "=" "+=" "-=" "*=" "/=") | ||
| 432 | (assoc "&&") (assoc "||") ; The doc claims they have equal precedence!? | ||
| 433 | (assoc "&") (assoc "|") ; The doc claims they have equal precedence!? | ||
| 434 | (nonassoc "<" "<=" "==" ">=" ">" "!=" "~=") | ||
| 435 | (nonassoc ":") ;No idea what this is. | ||
| 436 | (assoc "+" "-") | ||
| 437 | (assoc "*" "/" "\\" ".\\" ".*" "./") | ||
| 438 | (nonassoc "'" ".'") | ||
| 439 | (nonassoc "++" "--" "!" "~") ;And unary "+" and "-". | ||
| 440 | (right "^" "**" ".^" ".**") | ||
| 441 | ;; It's not really an operator, but for indentation purposes it | ||
| 442 | ;; could be convenient to treat it as one. | ||
| 443 | (assoc "..."))) | ||
| 444 | |||
| 445 | (defconst octave-smie-op-levels | ||
| 446 | (smie-prec2-levels | ||
| 447 | (smie-merge-prec2s | ||
| 448 | (smie-bnf-precedence-table | ||
| 449 | '((atom) | ||
| 450 | ;; We can't distinguish the first element in a sequence with | ||
| 451 | ;; precedence grammars, so we can't distinguish the condition | ||
| 452 | ;; if the `if' from the subsequent body, for example. | ||
| 453 | ;; This has to be done later in the indentation rules. | ||
| 454 | (exp (exp "\n" exp) | ||
| 455 | ;; We need to mention at least one of the operators in this part | ||
| 456 | ;; of the grammar: if the BNF and the operator table have | ||
| 457 | ;; no overlap, SMIE can't know how they relate. | ||
| 458 | (exp ";" exp) | ||
| 459 | ("try" exp "catch" exp "end_try_catch") | ||
| 460 | ("try" exp "catch" exp "end") | ||
| 461 | ("unwind_protect" exp | ||
| 462 | "unwind_protect_cleanup" exp "end_unwind_protect") | ||
| 463 | ("unwind_protect" exp "unwind_protect_cleanup" exp "end") | ||
| 464 | ("for" exp "endfor") | ||
| 465 | ("for" exp "end") | ||
| 466 | ("do" exp "until" atom) | ||
| 467 | ("while" exp "endwhile") | ||
| 468 | ("while" exp "end") | ||
| 469 | ("if" exp "endif") | ||
| 470 | ("if" exp "else" exp "endif") | ||
| 471 | ("if" exp "elseif" exp "else" exp "endif") | ||
| 472 | ("if" exp "elseif" exp "elseif" exp "else" exp "endif") | ||
| 473 | ("if" exp "elseif" exp "elseif" exp "else" exp "end") | ||
| 474 | ("switch" exp "case" exp "endswitch") | ||
| 475 | ("switch" exp "case" exp "otherwise" exp "endswitch") | ||
| 476 | ("switch" exp "case" exp "case" exp "otherwise" exp "endswitch") | ||
| 477 | ("switch" exp "case" exp "case" exp "otherwise" exp "end") | ||
| 478 | ("function" exp "endfunction") | ||
| 479 | ("function" exp "end")) | ||
| 480 | ;; (fundesc (atom "=" atom)) | ||
| 481 | ) | ||
| 482 | '((assoc "\n" ";"))) | ||
| 483 | |||
| 484 | (smie-precs-precedence-table | ||
| 485 | (append octave-operator-table | ||
| 486 | '((nonassoc " -dummy- "))) ;Bogus anchor at the end. | ||
| 487 | )))) | ||
| 488 | |||
| 489 | ;; Tokenizing needs to be refined so that ";;" is treated as two | ||
| 490 | ;; tokens and also so as to recognize the \n separator (and | ||
| 491 | ;; corresponding continuation lines). | ||
| 492 | |||
| 493 | (defconst octave-operator-regexp | ||
| 494 | (regexp-opt (apply 'append (mapcar 'cdr octave-operator-table)))) | ||
| 495 | |||
| 496 | (defun octave-smie-backward-token () | ||
| 497 | (let ((pos (point))) | ||
| 498 | (forward-comment (- (point))) | ||
| 499 | (cond | ||
| 500 | ((and (not (eq (char-before) ?\;)) ;Coalesce ";" and "\n". | ||
| 501 | (> pos (line-end-position)) | ||
| 502 | (if (looking-back octave-continuation-marker-regexp (- (point) 3)) | ||
| 503 | (progn | ||
| 504 | (goto-char (match-beginning 0)) | ||
| 505 | (forward-comment (- (point))) | ||
| 506 | nil) | ||
| 507 | t) | ||
| 508 | ;; Ignore it if it's within parentheses. | ||
| 509 | (let ((ppss (syntax-ppss))) | ||
| 510 | (not (and (nth 1 ppss) | ||
| 511 | (eq ?\( (char-after (nth 1 ppss))))))) | ||
| 512 | (skip-chars-forward " \t") | ||
| 513 | ;; Why bother distinguishing \n and ;? | ||
| 514 | ";") ;;"\n" | ||
| 515 | ((and (looking-back octave-operator-regexp (- (point) 3) 'greedy) | ||
| 516 | ;; Don't mistake a string quote for a transpose. | ||
| 517 | (not (looking-back "\\s\"" (1- (point))))) | ||
| 518 | (goto-char (match-beginning 0)) | ||
| 519 | (match-string-no-properties 0)) | ||
| 520 | (t | ||
| 521 | (smie-default-backward-token))))) | ||
| 522 | |||
| 523 | (defun octave-smie-forward-token () | ||
| 524 | (skip-chars-forward " \t") | ||
| 525 | (when (looking-at (eval-when-compile | ||
| 526 | (concat "\\(" octave-continuation-marker-regexp | ||
| 527 | "\\)[ \t]*\\($\\|[%#]\\)"))) | ||
| 528 | (goto-char (match-end 1)) | ||
| 529 | (forward-comment 1)) | ||
| 530 | (cond | ||
| 531 | ((and (looking-at "$\\|[%#]") | ||
| 532 | ;; Ignore it if it's within parentheses. | ||
| 533 | (prog1 (let ((ppss (syntax-ppss))) | ||
| 534 | (not (and (nth 1 ppss) | ||
| 535 | (eq ?\( (char-after (nth 1 ppss)))))) | ||
| 536 | (forward-comment (point-max)))) | ||
| 537 | ;; Why bother distinguishing \n and ;? | ||
| 538 | ";") ;;"\n" | ||
| 539 | ((looking-at ";[ \t]*\\($\\|[%#]\\)") | ||
| 540 | ;; Combine the ; with the subsequent \n. | ||
| 541 | (goto-char (match-beginning 1)) | ||
| 542 | (forward-comment 1) | ||
| 543 | ";") | ||
| 544 | ((and (looking-at octave-operator-regexp) | ||
| 545 | ;; Don't mistake a string quote for a transpose. | ||
| 546 | (not (looking-at "\\s\""))) | ||
| 547 | (goto-char (match-end 0)) | ||
| 548 | (match-string-no-properties 0)) | ||
| 549 | (t | ||
| 550 | (smie-default-forward-token)))) | ||
| 551 | |||
| 552 | (defconst octave-smie-indent-rules | ||
| 553 | '((";" | ||
| 554 | (:parent ("function" "if" "while" "else" "elseif" "for" "otherwise" | ||
| 555 | "case" "try" "catch" "unwind_protect" "unwind_protect_cleanup") | ||
| 556 | ;; FIXME: don't hardcode 2. | ||
| 557 | (+ parent octave-block-offset)) | ||
| 558 | ;; (:parent "switch" 4) ;For (invalid) code between switch and case. | ||
| 559 | 0) | ||
| 560 | ((:before . "case") octave-block-offset))) | ||
| 561 | |||
| 428 | ;;;###autoload | 562 | ;;;###autoload |
| 429 | (define-derived-mode octave-mode prog-mode "Octave" | 563 | (define-derived-mode octave-mode prog-mode "Octave" |
| 430 | "Major mode for editing Octave code. | 564 | "Major mode for editing Octave code. |
| @@ -511,7 +645,17 @@ already added. You just need to add a description of the problem, | |||
| 511 | including a reproducible test case and send the message." | 645 | including a reproducible test case and send the message." |
| 512 | (setq local-abbrev-table octave-abbrev-table) | 646 | (setq local-abbrev-table octave-abbrev-table) |
| 513 | 647 | ||
| 514 | (set (make-local-variable 'indent-line-function) 'octave-indent-line) | 648 | (smie-setup octave-smie-op-levels octave-smie-indent-rules) |
| 649 | (set (make-local-variable 'smie-indent-basic) 'octave-block-offset) | ||
| 650 | (set (make-local-variable 'smie-backward-token-function) | ||
| 651 | 'octave-smie-backward-token) | ||
| 652 | (set (make-local-variable 'smie-forward-token-function) | ||
| 653 | 'octave-smie-forward-token) | ||
| 654 | (set (make-local-variable 'forward-sexp-function) | ||
| 655 | 'smie-forward-sexp-command) | ||
| 656 | (set (make-local-variable 'smie-closer-alist) | ||
| 657 | (mapcar (lambda (elem) (cons (car elem) (car (last elem)))) | ||
| 658 | octave-block-match-alist)) | ||
| 515 | 659 | ||
| 516 | (set (make-local-variable 'comment-start) octave-comment-start) | 660 | (set (make-local-variable 'comment-start) octave-comment-start) |
| 517 | (set (make-local-variable 'comment-end) "") | 661 | (set (make-local-variable 'comment-end) "") |
| @@ -924,29 +1068,6 @@ The block marked is the one that contains point or follows point." | |||
| 924 | (goto-char pos) | 1068 | (goto-char pos) |
| 925 | (message "No block to mark found")))) | 1069 | (message "No block to mark found")))) |
| 926 | 1070 | ||
| 927 | (defun octave-close-block () | ||
| 928 | "Close the current Octave block on a separate line. | ||
| 929 | An error is signaled if no block to close is found." | ||
| 930 | (interactive) | ||
| 931 | (let (bb-keyword) | ||
| 932 | (condition-case nil | ||
| 933 | (progn | ||
| 934 | (save-excursion | ||
| 935 | (octave-backward-up-block 1) | ||
| 936 | (setq bb-keyword (buffer-substring-no-properties | ||
| 937 | (match-beginning 1) (match-end 1)))) | ||
| 938 | (if (save-excursion | ||
| 939 | (beginning-of-line) | ||
| 940 | (looking-at "^\\s-*$")) | ||
| 941 | (indent-according-to-mode) | ||
| 942 | (octave-reindent-then-newline-and-indent)) | ||
| 943 | (insert (car (reverse | ||
| 944 | (assoc bb-keyword | ||
| 945 | octave-block-match-alist)))) | ||
| 946 | (octave-reindent-then-newline-and-indent) | ||
| 947 | t) | ||
| 948 | (error (message "No block to close found"))))) | ||
| 949 | |||
| 950 | (defun octave-blink-matching-block-open () | 1071 | (defun octave-blink-matching-block-open () |
| 951 | "Blink the matching Octave begin block keyword. | 1072 | "Blink the matching Octave begin block keyword. |
| 952 | If point is right after an Octave else or end type block keyword, move | 1073 | If point is right after an Octave else or end type block keyword, move |