aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorStefan Monnier2010-08-30 22:34:52 +0200
committerStefan Monnier2010-08-30 22:34:52 +0200
commite17b68ed837cc835c46b4e518d05810a73997ac5 (patch)
tree72a9fb443a06e264878b9955b529317e1efee50c /lisp
parent42b6a73bc70429b7997fa18986a72341f98840f8 (diff)
downloademacs-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/ChangeLog13
-rw-r--r--lisp/progmodes/octave-mod.el193
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 @@
12010-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
12010-08-30 Eli Zaretskii <eliz@gnu.org> 142010-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,
511including a reproducible test case and send the message." 645including 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.
929An 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.
952If point is right after an Octave else or end type block keyword, move 1073If point is right after an Octave else or end type block keyword, move