diff options
| author | Stefan Monnier | 2012-05-11 10:24:50 -0400 |
|---|---|---|
| committer | Stefan Monnier | 2012-05-11 10:24:50 -0400 |
| commit | ff46c759ddf01935f111660d982ec03d83406d24 (patch) | |
| tree | 91abf4834c71e8f05a967af59aa3aa3a3a579f79 | |
| parent | dee6c9a34ff9f8ca764465937b6d2621cbb36318 (diff) | |
| download | emacs-ff46c759ddf01935f111660d982ec03d83406d24.tar.gz emacs-ff46c759ddf01935f111660d982ec03d83406d24.zip | |
* lisp/progmodes/sh-script.el: Use post-self-insert-hook&electric-pair-mode.
Provide SMIE-based indentation (not enabled by default yet).
(sh-mode-map): Don't bind electric keys.
Use electric-pair-mode instead of skeleton-pair.
(sh-assignment-regexp): Fit within 80 columns.
(sh-indent-supported): Specify actual shell name instead of boolean.
(sh--maybe-here-document): New fun, from sh-maybe-here-document.
(sh-maybe-here-document): Use it. Make obsolete.
(sh-electric-here-document-mode) New minor mode.
(sh-mode): Use it. Don't set sh-indent-supported-here here.
(sh-smie-sh-grammar, sh-smie--sh-operators, sh-smie--sh-operators-re)
(sh-smie--sh-operators-back-re, sh-indent-after-continuation)
(sh-smie-rc-grammar, sh-use-smie): New vars.
(sh-smie--keyword-p, sh-smie--newline-semi-p, sh-smie--sh-keyword-p)
(sh-smie-sh-forward-token, sh-smie--looking-back-at-continuation-p)
(sh-smie-sh-backward-token, sh-smie--continuation-start-indent)
(sh-smie-sh-rules, sh-smie-rc-rules, sh-smie--sh-keyword-in-p)
(sh-smie--rc-after-special-arg-p, sh-smie-rc-backward-token)
(sh-smie-sh-rules, sh-smie--rc-newline-semi-p): New functions.
(sh-set-shell): Use smie-setup if requested.
| -rw-r--r-- | etc/NEWS | 5 | ||||
| -rw-r--r-- | lisp/ChangeLog | 21 | ||||
| -rw-r--r-- | lisp/progmodes/sh-script.el | 548 |
3 files changed, 512 insertions, 62 deletions
| @@ -90,6 +90,11 @@ character when doing minibuffer filename prompts. | |||
| 90 | 90 | ||
| 91 | * Changes in Specialized Modes and Packages in Emacs 24.2 | 91 | * Changes in Specialized Modes and Packages in Emacs 24.2 |
| 92 | 92 | ||
| 93 | ** `sh-script' | ||
| 94 | *** Pairing of parens/quotes uses electric-pair-mode instead of skeleton-pair. | ||
| 95 | *** `sh-electric-here-document-mode' now controls auto-insertion of here-docs. | ||
| 96 | *** `sh-use-smie' lets you choose a new indentation and navigation code. | ||
| 97 | |||
| 93 | ** reStructuredText mode | 98 | ** reStructuredText mode |
| 94 | 99 | ||
| 95 | *** Major merge with upstream development. | 100 | *** Major merge with upstream development. |
diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 17d0fcb6427..a70257b2a83 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog | |||
| @@ -1,5 +1,26 @@ | |||
| 1 | 2012-05-11 Stefan Monnier <monnier@iro.umontreal.ca> | 1 | 2012-05-11 Stefan Monnier <monnier@iro.umontreal.ca> |
| 2 | 2 | ||
| 3 | * progmodes/sh-script.el: Use post-self-insert-hook&electric-pair-mode. | ||
| 4 | Provide SMIE-based indentation (not enabled by default yet). | ||
| 5 | (sh-mode-map): Don't bind electric keys. | ||
| 6 | Use electric-pair-mode instead of skeleton-pair. | ||
| 7 | (sh-assignment-regexp): Fit within 80 columns. | ||
| 8 | (sh-indent-supported): Specify actual shell name instead of boolean. | ||
| 9 | (sh--maybe-here-document): New fun, from sh-maybe-here-document. | ||
| 10 | (sh-maybe-here-document): Use it. Make obsolete. | ||
| 11 | (sh-electric-here-document-mode) New minor mode. | ||
| 12 | (sh-mode): Use it. Don't set sh-indent-supported-here here. | ||
| 13 | (sh-smie-sh-grammar, sh-smie--sh-operators, sh-smie--sh-operators-re) | ||
| 14 | (sh-smie--sh-operators-back-re, sh-indent-after-continuation) | ||
| 15 | (sh-smie-rc-grammar, sh-use-smie): New vars. | ||
| 16 | (sh-smie--keyword-p, sh-smie--newline-semi-p, sh-smie--sh-keyword-p) | ||
| 17 | (sh-smie-sh-forward-token, sh-smie--looking-back-at-continuation-p) | ||
| 18 | (sh-smie-sh-backward-token, sh-smie--continuation-start-indent) | ||
| 19 | (sh-smie-sh-rules, sh-smie-rc-rules, sh-smie--sh-keyword-in-p) | ||
| 20 | (sh-smie--rc-after-special-arg-p, sh-smie-rc-backward-token) | ||
| 21 | (sh-smie-sh-rules, sh-smie--rc-newline-semi-p): New functions. | ||
| 22 | (sh-set-shell): Use smie-setup if requested. | ||
| 23 | |||
| 3 | * term.el (term-set-escape-char): Properly set term-escape-char. | 24 | * term.el (term-set-escape-char): Properly set term-escape-char. |
| 4 | See http://stackoverflow.com/questions/10524656. | 25 | See http://stackoverflow.com/questions/10524656. |
| 5 | 26 | ||
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index f60ce185bc7..a07ecfcb3a4 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el | |||
| @@ -326,7 +326,9 @@ shell it really is." | |||
| 326 | 326 | ||
| 327 | (defcustom sh-imenu-generic-expression | 327 | (defcustom sh-imenu-generic-expression |
| 328 | `((sh | 328 | `((sh |
| 329 | . ((nil "^\\s-*\\(function\\s-+\\)?\\([[:alpha:]_][[:alnum:]_]+\\)\\s-*()" 2)))) | 329 | . ((nil |
| 330 | "^\\s-*\\(function\\s-+\\)?\\([[:alpha:]_][[:alnum:]_]+\\)\\s-*()" | ||
| 331 | 2)))) | ||
| 330 | "Alist of regular expressions for recognizing shell function definitions. | 332 | "Alist of regular expressions for recognizing shell function definitions. |
| 331 | See `sh-feature' and `imenu-generic-expression'." | 333 | See `sh-feature' and `imenu-generic-expression'." |
| 332 | :type '(alist :key-type (symbol :tag "Shell") | 334 | :type '(alist :key-type (symbol :tag "Shell") |
| @@ -460,14 +462,6 @@ This is buffer-local in every such buffer.") | |||
| 460 | (define-key map "\C-c+" 'sh-add) | 462 | (define-key map "\C-c+" 'sh-add) |
| 461 | (define-key map "\C-\M-x" 'sh-execute-region) | 463 | (define-key map "\C-\M-x" 'sh-execute-region) |
| 462 | (define-key map "\C-c\C-x" 'executable-interpret) | 464 | (define-key map "\C-c\C-x" 'executable-interpret) |
| 463 | ;; FIXME: Use post-self-insert-hook. | ||
| 464 | (define-key map "<" 'sh-maybe-here-document) | ||
| 465 | (define-key map "(" 'skeleton-pair-insert-maybe) | ||
| 466 | (define-key map "{" 'skeleton-pair-insert-maybe) | ||
| 467 | (define-key map "[" 'skeleton-pair-insert-maybe) | ||
| 468 | (define-key map "'" 'skeleton-pair-insert-maybe) | ||
| 469 | (define-key map "`" 'skeleton-pair-insert-maybe) | ||
| 470 | (define-key map "\"" 'skeleton-pair-insert-maybe) | ||
| 471 | 465 | ||
| 472 | (define-key map [remap complete-tag] 'comint-dynamic-complete) | 466 | (define-key map [remap complete-tag] 'comint-dynamic-complete) |
| 473 | (define-key map [remap delete-backward-char] | 467 | (define-key map [remap delete-backward-char] |
| @@ -478,10 +472,10 @@ This is buffer-local in every such buffer.") | |||
| 478 | (define-key map [menu-bar sh-script] (cons "Sh-Script" menu-map)) | 472 | (define-key map [menu-bar sh-script] (cons "Sh-Script" menu-map)) |
| 479 | (define-key menu-map [sh-learn-buffer-indent] | 473 | (define-key menu-map [sh-learn-buffer-indent] |
| 480 | '(menu-item "Learn buffer indentation" sh-learn-buffer-indent | 474 | '(menu-item "Learn buffer indentation" sh-learn-buffer-indent |
| 481 | :help "Learn how to indent the buffer the way it currently is.")) | 475 | :help "Learn how to indent the buffer the way it currently is.")) |
| 482 | (define-key menu-map [sh-learn-line-indent] | 476 | (define-key menu-map [sh-learn-line-indent] |
| 483 | '(menu-item "Learn line indentation" sh-learn-line-indent | 477 | '(menu-item "Learn line indentation" sh-learn-line-indent |
| 484 | :help "Learn how to indent a line as it currently is indented")) | 478 | :help "Learn how to indent a line as it currently is indented")) |
| 485 | (define-key menu-map [sh-show-indent] | 479 | (define-key menu-map [sh-show-indent] |
| 486 | '(menu-item "Show indentation" sh-show-indent | 480 | '(menu-item "Show indentation" sh-show-indent |
| 487 | :help "Show the how the current line would be indented")) | 481 | :help "Show the how the current line would be indented")) |
| @@ -491,13 +485,9 @@ This is buffer-local in every such buffer.") | |||
| 491 | 485 | ||
| 492 | (define-key menu-map [sh-pair] | 486 | (define-key menu-map [sh-pair] |
| 493 | '(menu-item "Insert braces and quotes in pairs" | 487 | '(menu-item "Insert braces and quotes in pairs" |
| 494 | (lambda () | 488 | electric-pair-mode |
| 495 | (interactive) | 489 | :button (:toggle . (bound-and-true-p electric-pair-mode)) |
| 496 | (require 'skeleton) | 490 | :help "Inserting a brace or quote automatically inserts the matching pair")) |
| 497 | (setq skeleton-pair (not skeleton-pair))) | ||
| 498 | :button (:toggle . (and (boundp 'skeleton-pair) | ||
| 499 | skeleton-pair)) | ||
| 500 | :help "Inserting a brace or quote automatically inserts the matching pair")) | ||
| 501 | 491 | ||
| 502 | (define-key menu-map [sh-s0] '("--")) | 492 | (define-key menu-map [sh-s0] '("--")) |
| 503 | ;; Insert | 493 | ;; Insert |
| @@ -506,7 +496,7 @@ This is buffer-local in every such buffer.") | |||
| 506 | :help "Insert a function definition")) | 496 | :help "Insert a function definition")) |
| 507 | (define-key menu-map [sh-add] | 497 | (define-key menu-map [sh-add] |
| 508 | '(menu-item "Addition..." sh-add | 498 | '(menu-item "Addition..." sh-add |
| 509 | :help "Insert an addition of VAR and prefix DELTA for Bourne (type) shell")) | 499 | :help "Insert an addition of VAR and prefix DELTA for Bourne (type) shell")) |
| 510 | (define-key menu-map [sh-until] | 500 | (define-key menu-map [sh-until] |
| 511 | '(menu-item "Until Loop" sh-until | 501 | '(menu-item "Until Loop" sh-until |
| 512 | :help "Insert an until loop")) | 502 | :help "Insert an until loop")) |
| @@ -537,16 +527,16 @@ This is buffer-local in every such buffer.") | |||
| 537 | (define-key menu-map [sh-s1] '("--")) | 527 | (define-key menu-map [sh-s1] '("--")) |
| 538 | (define-key menu-map [sh-exec] | 528 | (define-key menu-map [sh-exec] |
| 539 | '(menu-item "Execute region" sh-execute-region | 529 | '(menu-item "Execute region" sh-execute-region |
| 540 | :help "Pass optional header and region to a subshell for noninteractive execution")) | 530 | :help "Pass optional header and region to a subshell for noninteractive execution")) |
| 541 | (define-key menu-map [sh-exec-interpret] | 531 | (define-key menu-map [sh-exec-interpret] |
| 542 | '(menu-item "Execute script..." executable-interpret | 532 | '(menu-item "Execute script..." executable-interpret |
| 543 | :help "Run script with user-specified args, and collect output in a buffer")) | 533 | :help "Run script with user-specified args, and collect output in a buffer")) |
| 544 | (define-key menu-map [sh-set-shell] | 534 | (define-key menu-map [sh-set-shell] |
| 545 | '(menu-item "Set shell type..." sh-set-shell | 535 | '(menu-item "Set shell type..." sh-set-shell |
| 546 | :help "Set this buffer's shell to SHELL (a string)")) | 536 | :help "Set this buffer's shell to SHELL (a string)")) |
| 547 | (define-key menu-map [sh-backslash-region] | 537 | (define-key menu-map [sh-backslash-region] |
| 548 | '(menu-item "Backslash region" sh-backslash-region | 538 | '(menu-item "Backslash region" sh-backslash-region |
| 549 | :help "Insert, align, or delete end-of-line backslashes on the lines in the region.")) | 539 | :help "Insert, align, or delete end-of-line backslashes on the lines in the region.")) |
| 550 | map) | 540 | map) |
| 551 | "Keymap used in Shell-Script mode.") | 541 | "Keymap used in Shell-Script mode.") |
| 552 | 542 | ||
| @@ -564,9 +554,10 @@ This is buffer-local in every such buffer.") | |||
| 564 | :group 'sh-script) | 554 | :group 'sh-script) |
| 565 | 555 | ||
| 566 | (defcustom sh-assignment-regexp | 556 | (defcustom sh-assignment-regexp |
| 567 | '((csh . "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?[ \t]*[-+*/%^]?=") | 557 | `((csh . "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?[ \t]*[-+*/%^]?=") |
| 568 | ;; actually spaces are only supported in let/(( ... )) | 558 | ;; actually spaces are only supported in let/(( ... )) |
| 569 | (ksh88 . "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?[ \t]*\\([-+*/%&|~^]\\|<<\\|>>\\)?=") | 559 | (ksh88 . ,(concat "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?" |
| 560 | "[ \t]*\\(?:[-+*/%&|~^]\\|<<\\|>>\\)?=")) | ||
| 570 | (bash . "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?\\+?=") | 561 | (bash . "\\<\\([[:alnum:]_]+\\)\\(\\[.+\\]\\)?\\+?=") |
| 571 | (rc . "\\<\\([[:alnum:]_*]+\\)[ \t]*=") | 562 | (rc . "\\<\\([[:alnum:]_*]+\\)[ \t]*=") |
| 572 | (sh . "\\<\\([[:alnum:]_]+\\)=")) | 563 | (sh . "\\<\\([[:alnum:]_]+\\)=")) |
| @@ -1379,10 +1370,10 @@ punctuation characters like '-'." | |||
| 1379 | 1370 | ||
| 1380 | 1371 | ||
| 1381 | (defconst sh-indent-supported | 1372 | (defconst sh-indent-supported |
| 1382 | '((sh . t) | 1373 | '((sh . sh) |
| 1383 | (csh . nil) | 1374 | (csh . nil) |
| 1384 | (rc . t)) | 1375 | (rc . rc)) |
| 1385 | "Shell types that shell indenting can do something with.") | 1376 | "Indentation rule set to use for each shell type.") |
| 1386 | 1377 | ||
| 1387 | (defvar sh-indent-supported-here nil | 1378 | (defvar sh-indent-supported-here nil |
| 1388 | "Non-nil if we support indentation for the current buffer's shell type.") | 1379 | "Non-nil if we support indentation for the current buffer's shell type.") |
| @@ -1464,9 +1455,8 @@ buffer indents as it currently is indented. | |||
| 1464 | \\[sh-set-shell] Set this buffer's shell, and maybe its magic number. | 1455 | \\[sh-set-shell] Set this buffer's shell, and maybe its magic number. |
| 1465 | \\[sh-execute-region] Have optional header and region be executed in a subshell. | 1456 | \\[sh-execute-region] Have optional header and region be executed in a subshell. |
| 1466 | 1457 | ||
| 1467 | \\[sh-maybe-here-document] Without prefix, following an unquoted < inserts here document. | 1458 | `sh-electric-here-document-mode' controls whether insertion of two |
| 1468 | \{, (, [, ', \", ` | 1459 | unquoted < insert a here document. |
| 1469 | Unless quoted with \\, insert the pairs {}, (), [], or '', \"\", ``. | ||
| 1470 | 1460 | ||
| 1471 | If you generally program a shell different from your login shell you can | 1461 | If you generally program a shell different from your login shell you can |
| 1472 | set `sh-shell-file' accordingly. If your shell's file name doesn't correctly | 1462 | set `sh-shell-file' accordingly. If your shell's file name doesn't correctly |
| @@ -1503,13 +1493,13 @@ with your script for an edit-interpret-debug cycle." | |||
| 1503 | #'sh-syntax-propertize-function) | 1493 | #'sh-syntax-propertize-function) |
| 1504 | (add-hook 'syntax-propertize-extend-region-functions | 1494 | (add-hook 'syntax-propertize-extend-region-functions |
| 1505 | #'syntax-propertize-multiline 'append 'local) | 1495 | #'syntax-propertize-multiline 'append 'local) |
| 1496 | (sh-electric-here-document-mode 1) | ||
| 1506 | (set (make-local-variable 'skeleton-pair-alist) '((?` _ ?`))) | 1497 | (set (make-local-variable 'skeleton-pair-alist) '((?` _ ?`))) |
| 1507 | (set (make-local-variable 'skeleton-pair-filter-function) 'sh-quoted-p) | 1498 | (set (make-local-variable 'skeleton-pair-filter-function) 'sh-quoted-p) |
| 1508 | (set (make-local-variable 'skeleton-further-elements) | 1499 | (set (make-local-variable 'skeleton-further-elements) |
| 1509 | '((< '(- (min sh-indentation (current-column)))))) | 1500 | '((< '(- (min sh-indentation (current-column)))))) |
| 1510 | (set (make-local-variable 'skeleton-filter-function) 'sh-feature) | 1501 | (set (make-local-variable 'skeleton-filter-function) 'sh-feature) |
| 1511 | (set (make-local-variable 'skeleton-newline-indent-rigidly) t) | 1502 | (set (make-local-variable 'skeleton-newline-indent-rigidly) t) |
| 1512 | (set (make-local-variable 'sh-indent-supported-here) nil) | ||
| 1513 | (set (make-local-variable 'defun-prompt-regexp) | 1503 | (set (make-local-variable 'defun-prompt-regexp) |
| 1514 | (concat "^\\(function[ \t]\\|[[:alnum:]]+[ \t]+()[ \t]+\\)")) | 1504 | (concat "^\\(function[ \t]\\|[[:alnum:]]+[ \t]+()[ \t]+\\)")) |
| 1515 | ;; Parse or insert magic number for exec, and set all variables depending | 1505 | ;; Parse or insert magic number for exec, and set all variables depending |
| @@ -1519,23 +1509,15 @@ with your script for an edit-interpret-debug cycle." | |||
| 1519 | (goto-char (point-min)) | 1509 | (goto-char (point-min)) |
| 1520 | (looking-at "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)")) | 1510 | (looking-at "#![ \t]?\\([^ \t\n]*/bin/env[ \t]\\)?\\([^ \t\n]+\\)")) |
| 1521 | (match-string 2)) | 1511 | (match-string 2)) |
| 1522 | ((not buffer-file-name) | 1512 | ((not buffer-file-name) sh-shell-file) |
| 1523 | sh-shell-file) | ||
| 1524 | ;; Checks that use `buffer-file-name' follow. | 1513 | ;; Checks that use `buffer-file-name' follow. |
| 1525 | ((string-match "\\.m?spec\\'" buffer-file-name) | 1514 | ((string-match "\\.m?spec\\'" buffer-file-name) "rpm") |
| 1526 | "rpm") | 1515 | ((string-match "[.]sh\\>" buffer-file-name) "sh") |
| 1527 | ((string-match "[.]sh\\>" buffer-file-name) | 1516 | ((string-match "[.]bash\\>" buffer-file-name) "bash") |
| 1528 | "sh") | 1517 | ((string-match "[.]ksh\\>" buffer-file-name) "ksh") |
| 1529 | ((string-match "[.]bash\\>" buffer-file-name) | 1518 | ((string-match "[.]csh\\>" buffer-file-name) "csh") |
| 1530 | "bash") | 1519 | ((equal (file-name-nondirectory buffer-file-name) ".profile") "sh") |
| 1531 | ((string-match "[.]ksh\\>" buffer-file-name) | 1520 | (t sh-shell-file)) |
| 1532 | "ksh") | ||
| 1533 | ((string-match "[.]csh\\>" buffer-file-name) | ||
| 1534 | "csh") | ||
| 1535 | ((equal (file-name-nondirectory buffer-file-name) ".profile") | ||
| 1536 | "sh") | ||
| 1537 | (t | ||
| 1538 | sh-shell-file)) | ||
| 1539 | nil nil)) | 1521 | nil nil)) |
| 1540 | 1522 | ||
| 1541 | ;;;###autoload | 1523 | ;;;###autoload |
| @@ -1578,6 +1560,426 @@ This adds rules for comments and assignments." | |||
| 1578 | "Function to get better fontification including keywords and builtins." | 1560 | "Function to get better fontification including keywords and builtins." |
| 1579 | (sh-font-lock-keywords-1 t)) | 1561 | (sh-font-lock-keywords-1 t)) |
| 1580 | 1562 | ||
| 1563 | ;;; Indentation and navigation with SMIE. | ||
| 1564 | |||
| 1565 | (require 'smie) | ||
| 1566 | |||
| 1567 | ;; The SMIE code should generally be preferred, but it currently does not obey | ||
| 1568 | ;; the various indentation custom-vars, and it misses some important features | ||
| 1569 | ;; of the old code, mostly: sh-learn-line/buffer-indent, sh-show-indent, | ||
| 1570 | ;; sh-name/save/load-style. | ||
| 1571 | (defvar sh-use-smie nil | ||
| 1572 | "Whether to use the SMIE code for navigation and indentation.") | ||
| 1573 | |||
| 1574 | (defun sh-smie--keyword-p (tok) | ||
| 1575 | "Non-nil if TOK (at which we're looking) really is a keyword." | ||
| 1576 | (let ((prev (funcall smie-backward-token-function))) | ||
| 1577 | (if (zerop (length prev)) | ||
| 1578 | (looking-back "\\s(" (1- (point))) | ||
| 1579 | (assoc prev smie-grammar)))) | ||
| 1580 | |||
| 1581 | (defun sh-smie--newline-semi-p (&optional tok) | ||
| 1582 | "Return non-nil if a newline should be treated as a semi-colon. | ||
| 1583 | Here we assume that a newline should be treated as a semi-colon unless it | ||
| 1584 | comes right after a special keyword. | ||
| 1585 | This function does not pay attention to line-continuations. | ||
| 1586 | If TOK is nil, point should be before the newline; otherwise, TOK is the token | ||
| 1587 | before the newline and in that case point should be just before the token." | ||
| 1588 | (save-excursion | ||
| 1589 | (unless tok | ||
| 1590 | (setq tok (funcall smie-backward-token-function))) | ||
| 1591 | (if (and (zerop (length tok)) | ||
| 1592 | (looking-back "\\s(" (1- (point)))) | ||
| 1593 | nil | ||
| 1594 | (not (numberp (nth 2 (assoc tok smie-grammar))))))) | ||
| 1595 | |||
| 1596 | ;;;; SMIE support for `sh'. | ||
| 1597 | |||
| 1598 | (defconst sh-smie-sh-grammar | ||
| 1599 | (smie-prec2->grammar | ||
| 1600 | (smie-bnf->prec2 | ||
| 1601 | '((exp) ;A constant, or a $var, or a sequence of them... | ||
| 1602 | (cmd ("case" exp "in" branches "esac") | ||
| 1603 | ("if" cmd "then" cmd "fi") | ||
| 1604 | ("if" cmd "then" cmd "else" cmd "fi") | ||
| 1605 | ("if" cmd "then" cmd "elif" cmd "then" cmd "fi") | ||
| 1606 | ("if" cmd "then" cmd "elif" cmd "then" cmd "else" cmd "fi") | ||
| 1607 | ("if" cmd "then" cmd "elif" cmd "then" cmd | ||
| 1608 | "elif" cmd "then" cmd "else" cmd "fi") | ||
| 1609 | ("while" cmd "do" cmd "done") | ||
| 1610 | ("until" cmd "do" cmd "done") | ||
| 1611 | ("for" exp "in" cmd "do" cmd "done") | ||
| 1612 | ("for" exp "do" cmd "done") | ||
| 1613 | ("select" exp "in" cmd "do" cmd "done") ;bash&zsh&ksh88. | ||
| 1614 | ("repeat" exp "do" cmd "done") ;zsh. | ||
| 1615 | (exp "always" exp) ;zsh. | ||
| 1616 | (cmd "|" cmd) (cmd "|&" cmd) | ||
| 1617 | (cmd "&&" cmd) (cmd "||" cmd) | ||
| 1618 | (cmd ";" cmd) (cmd "&" cmd)) | ||
| 1619 | (pattern (pattern "|" pattern)) | ||
| 1620 | (branches (branches ";;" branches) | ||
| 1621 | (branches ";&" branches) (branches ";;&" branches) ;bash. | ||
| 1622 | (pattern "case-)" cmd))) | ||
| 1623 | '((assoc ";;" ";&" ";;&")) | ||
| 1624 | '((assoc ";" "&") (assoc "&&" "||") (assoc "|" "|&"))))) | ||
| 1625 | |||
| 1626 | (defconst sh-smie--sh-operators | ||
| 1627 | (delq nil (mapcar (lambda (x) | ||
| 1628 | (setq x (car x)) | ||
| 1629 | (and (stringp x) | ||
| 1630 | (not (string-match "\\`[a-z]" x)) | ||
| 1631 | x)) | ||
| 1632 | sh-smie-sh-grammar))) | ||
| 1633 | |||
| 1634 | (defconst sh-smie--sh-operators-re (regexp-opt sh-smie--sh-operators)) | ||
| 1635 | (defconst sh-smie--sh-operators-back-re | ||
| 1636 | (concat "\\(?:^\\|[^\\]\\)\\(?:\\\\\\\\\\)*" | ||
| 1637 | "\\(" sh-smie--sh-operators-re "\\)")) | ||
| 1638 | |||
| 1639 | (defun sh-smie--sh-keyword-in-p () | ||
| 1640 | "Assuming we're looking at \"in\", return non-nil if it's a keyword. | ||
| 1641 | Does not preserve point." | ||
| 1642 | (let ((forward-sexp-function nil) | ||
| 1643 | (words nil) ;We've seen words. | ||
| 1644 | (newline nil) ;We've seen newlines after the words. | ||
| 1645 | (res nil) | ||
| 1646 | prev) | ||
| 1647 | (while (not res) | ||
| 1648 | (setq prev (funcall smie-backward-token-function)) | ||
| 1649 | (cond | ||
| 1650 | ((zerop (length prev)) | ||
| 1651 | (if newline | ||
| 1652 | (progn (assert words) (setq res 'word)) | ||
| 1653 | (setq words t) | ||
| 1654 | (condition-case nil | ||
| 1655 | (forward-sexp -1) | ||
| 1656 | (scan-error (setq res 'unknown))))) | ||
| 1657 | ((equal prev ";") | ||
| 1658 | (if words (setq newline t) | ||
| 1659 | (setq res 'keyword))) | ||
| 1660 | ((member prev '("case" "for" "select")) (setq res 'keyword)) | ||
| 1661 | ((assoc prev smie-grammar) (setq res 'word)) | ||
| 1662 | (t | ||
| 1663 | (if newline | ||
| 1664 | (progn (assert words) (setq res 'word)) | ||
| 1665 | (setq words t))))) | ||
| 1666 | (eq res 'keyword))) | ||
| 1667 | |||
| 1668 | (defun sh-smie--sh-keyword-p (tok) | ||
| 1669 | "Non-nil if TOK (at which we're looking) really is a keyword." | ||
| 1670 | (if (equal tok "in") | ||
| 1671 | (sh-smie--sh-keyword-in-p) | ||
| 1672 | (sh-smie--keyword-p tok))) | ||
| 1673 | |||
| 1674 | (defun sh-smie-sh-forward-token () | ||
| 1675 | (if (and (looking-at "[ \t]*\\(?:#\\|\\(\\s|\\)\\|$\\)") | ||
| 1676 | (save-excursion | ||
| 1677 | (skip-chars-backward " \t") | ||
| 1678 | (not (bolp)))) | ||
| 1679 | (if (and (match-end 1) (not (nth 3 (syntax-ppss)))) | ||
| 1680 | ;; Right before a here-doc. | ||
| 1681 | (let ((forward-sexp-function nil)) | ||
| 1682 | (forward-sexp 1) | ||
| 1683 | ;; Pretend the here-document is a "newline representing a | ||
| 1684 | ;; semi-colon", since the here-doc otherwise covers the newline(s). | ||
| 1685 | ";") | ||
| 1686 | (let ((semi (sh-smie--newline-semi-p))) | ||
| 1687 | (forward-line 1) | ||
| 1688 | (if semi ";" | ||
| 1689 | (sh-smie-sh-forward-token)))) | ||
| 1690 | (forward-comment (point-max)) | ||
| 1691 | (cond | ||
| 1692 | ((looking-at "\\\\\n") (forward-line 1) (sh-smie-sh-forward-token)) | ||
| 1693 | ((looking-at sh-smie--sh-operators-re) | ||
| 1694 | (goto-char (match-end 0)) | ||
| 1695 | (let ((tok (match-string-no-properties 0))) | ||
| 1696 | (if (and (memq (aref tok (1- (length tok))) '(?\; ?\& ?\|)) | ||
| 1697 | (looking-at "[ \t]*\\(?:#\\|$\\)")) | ||
| 1698 | (forward-line 1)) | ||
| 1699 | tok)) | ||
| 1700 | (t | ||
| 1701 | (let* ((pos (point)) | ||
| 1702 | (tok (smie-default-forward-token))) | ||
| 1703 | (cond | ||
| 1704 | ((equal tok ")") "case-)") | ||
| 1705 | ((and tok (string-match "\\`[a-z]" tok) | ||
| 1706 | (assoc tok smie-grammar) | ||
| 1707 | (not | ||
| 1708 | (save-excursion | ||
| 1709 | (goto-char pos) | ||
| 1710 | (sh-smie--sh-keyword-p tok)))) | ||
| 1711 | " word ") | ||
| 1712 | (t tok))))))) | ||
| 1713 | |||
| 1714 | (defun sh-smie--looking-back-at-continuation-p () | ||
| 1715 | (save-excursion | ||
| 1716 | (and (if (eq (char-before) ?\n) (progn (forward-char -1) t) (eolp)) | ||
| 1717 | (looking-back "\\(?:^\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\\\" | ||
| 1718 | (line-beginning-position))))) | ||
| 1719 | |||
| 1720 | (defun sh-smie-sh-backward-token () | ||
| 1721 | (let ((bol (line-beginning-position)) | ||
| 1722 | pos tok) | ||
| 1723 | (forward-comment (- (point))) | ||
| 1724 | (cond | ||
| 1725 | ((and (bolp) (not (bobp)) | ||
| 1726 | (equal (syntax-after (1- (point))) (string-to-syntax "|")) | ||
| 1727 | (not (nth 3 (syntax-ppss)))) | ||
| 1728 | ;; Right after a here-document. | ||
| 1729 | (let ((forward-sexp-function nil)) | ||
| 1730 | (forward-sexp -1) | ||
| 1731 | ;; Pretend the here-document is a "newline representing a | ||
| 1732 | ;; semi-colon", since the here-doc otherwise covers the newline(s). | ||
| 1733 | ";")) | ||
| 1734 | ((< (point) bol) | ||
| 1735 | (cond | ||
| 1736 | ((sh-smie--looking-back-at-continuation-p) | ||
| 1737 | (forward-char -1) | ||
| 1738 | (funcall smie-backward-token-function)) | ||
| 1739 | ((sh-smie--newline-semi-p) ";") | ||
| 1740 | (t (funcall smie-backward-token-function)))) | ||
| 1741 | ((looking-back sh-smie--sh-operators-back-re | ||
| 1742 | (line-beginning-position) 'greedy) | ||
| 1743 | (goto-char (match-beginning 1)) | ||
| 1744 | (match-string-no-properties 1)) | ||
| 1745 | (t | ||
| 1746 | (let ((tok (smie-default-backward-token))) | ||
| 1747 | (cond | ||
| 1748 | ((equal tok ")") "case-)") | ||
| 1749 | ((and tok (string-match "\\`[a-z]" tok) | ||
| 1750 | (assoc tok smie-grammar) | ||
| 1751 | (not (save-excursion (sh-smie--sh-keyword-p tok)))) | ||
| 1752 | " word ") | ||
| 1753 | (t tok))))))) | ||
| 1754 | |||
| 1755 | (defcustom sh-indent-after-continuation t | ||
| 1756 | "If non-nil, try to make sure text is indented after a line continuation." | ||
| 1757 | :type 'boolean) | ||
| 1758 | |||
| 1759 | (defun sh-smie--continuation-start-indent () | ||
| 1760 | "Return the initial indentation of a continued line. | ||
| 1761 | May return nil if the line should not be treated as continued." | ||
| 1762 | (save-excursion | ||
| 1763 | (forward-line -1) | ||
| 1764 | (unless (sh-smie--looking-back-at-continuation-p) | ||
| 1765 | (current-indentation)))) | ||
| 1766 | |||
| 1767 | (defun sh-smie-sh-rules (kind token) | ||
| 1768 | (pcase (cons kind token) | ||
| 1769 | (`(:elem . basic) sh-indentation) | ||
| 1770 | (`(:after . "case-)") (or sh-indentation smie-indent-basic)) | ||
| 1771 | ((and `(:before . ,_) | ||
| 1772 | (guard (when sh-indent-after-continuation | ||
| 1773 | (save-excursion | ||
| 1774 | (ignore-errors | ||
| 1775 | (skip-chars-backward " \t") | ||
| 1776 | (sh-smie--looking-back-at-continuation-p)))))) | ||
| 1777 | ;; After a line-continuation, make sure the rest is indented. | ||
| 1778 | (let* ((sh-indent-after-continuation nil) | ||
| 1779 | (indent (smie-indent-calculate)) | ||
| 1780 | (initial (sh-smie--continuation-start-indent))) | ||
| 1781 | (when (and (numberp indent) (numberp initial) | ||
| 1782 | (<= indent initial)) | ||
| 1783 | `(column . ,(+ initial sh-indentation))))) | ||
| 1784 | (`(:before . ,(or `"(" `"{" `"[")) | ||
| 1785 | (if (smie-rule-hanging-p) (smie-rule-parent))) | ||
| 1786 | ;; FIXME: Maybe this handling of ;; should be made into | ||
| 1787 | ;; a smie-rule-terminator function that takes the substitute ";" as arg. | ||
| 1788 | (`(:before . ,(or `";;" `";&" `";;&")) | ||
| 1789 | (if (and (smie-rule-bolp) (looking-at ";;?&?[ \t]*\\(#\\|$\\)")) | ||
| 1790 | (cons 'column (smie-indent-keyword ";")) | ||
| 1791 | (smie-rule-separator kind))) | ||
| 1792 | (`(:after . ,(or `";;" `";&" `";;&")) | ||
| 1793 | (with-demoted-errors | ||
| 1794 | (smie-backward-sexp token) | ||
| 1795 | (cons 'column | ||
| 1796 | (if (or (smie-rule-bolp) | ||
| 1797 | (save-excursion | ||
| 1798 | (and (member (funcall smie-backward-token-function) | ||
| 1799 | '("in" ";;")) | ||
| 1800 | (smie-rule-bolp)))) | ||
| 1801 | (current-column) | ||
| 1802 | (smie-indent-calculate))))) | ||
| 1803 | (`(:after . "|") (if (smie-rule-parent-p "|") nil 4)) | ||
| 1804 | )) | ||
| 1805 | |||
| 1806 | ;; (defconst sh-smie-csh-grammar | ||
| 1807 | ;; (smie-prec2->grammar | ||
| 1808 | ;; (smie-bnf->prec2 | ||
| 1809 | ;; '((exp) ;A constant, or a $var, or a sequence of them… | ||
| 1810 | ;; (elseifcmd (cmd) | ||
| 1811 | ;; (cmd "else" "else-if" exp "then" elseifcmd)) | ||
| 1812 | ;; (cmd ("switch" branches "endsw") | ||
| 1813 | ;; ("if" exp) | ||
| 1814 | ;; ("if" exp "then" cmd "endif") | ||
| 1815 | ;; ("if" exp "then" cmd "else" cmd "endif") | ||
| 1816 | ;; ("if" exp "then" elseifcmd "endif") | ||
| 1817 | ;; ;; ("if" exp "then" cmd "else" cmd "endif") | ||
| 1818 | ;; ;; ("if" exp "then" cmd "else" "if" exp "then" cmd "endif") | ||
| 1819 | ;; ;; ("if" exp "then" cmd "else" "if" exp "then" cmd | ||
| 1820 | ;; ;; "else" cmd "endif") | ||
| 1821 | ;; ;; ("if" exp "then" cmd "else" "if" exp "then" cmd | ||
| 1822 | ;; ;; "else" "if" exp "then" cmd "endif") | ||
| 1823 | ;; ("while" cmd "end") | ||
| 1824 | ;; ("foreach" cmd "end") | ||
| 1825 | ;; (cmd "|" cmd) (cmd "|&" cmd) | ||
| 1826 | ;; (cmd "&&" cmd) (cmd "||" cmd) | ||
| 1827 | ;; (cmd ";" cmd) (cmd "&" cmd)) | ||
| 1828 | ;; ;; This is a lie, but (combined with the corresponding disambiguation | ||
| 1829 | ;; ;; rule) it makes it more clear that `case' and `default' are the key | ||
| 1830 | ;; ;; separators and the `:' is a secondary tokens. | ||
| 1831 | ;; (branches (branches "case" branches) | ||
| 1832 | ;; (branches "default" branches) | ||
| 1833 | ;; (exp ":" branches))) | ||
| 1834 | ;; '((assoc "else" "then" "endif")) | ||
| 1835 | ;; '((assoc "case" "default") (nonassoc ":")) | ||
| 1836 | ;; '((assoc ";;" ";&" ";;&")) | ||
| 1837 | ;; '((assoc ";" "&") (assoc "&&" "||") (assoc "|" "|&"))))) | ||
| 1838 | |||
| 1839 | ;;;; SMIE support for `rc'. | ||
| 1840 | |||
| 1841 | (defconst sh-smie-rc-grammar | ||
| 1842 | (smie-prec2->grammar | ||
| 1843 | (smie-bnf->prec2 | ||
| 1844 | '((exp) ;A constant, or a $var, or a sequence of them... | ||
| 1845 | (cmd (cmd "case" cmd) | ||
| 1846 | ("if" exp) | ||
| 1847 | ("switch" exp) | ||
| 1848 | ("for" exp) ("while" exp) | ||
| 1849 | (cmd "|" cmd) (cmd "|&" cmd) | ||
| 1850 | (cmd "&&" cmd) (cmd "||" cmd) | ||
| 1851 | (cmd ";" cmd) (cmd "&" cmd)) | ||
| 1852 | (pattern (pattern "|" pattern)) | ||
| 1853 | (branches (branches ";;" branches) | ||
| 1854 | (branches ";&" branches) (branches ";;&" branches) ;bash. | ||
| 1855 | (pattern "case-)" cmd))) | ||
| 1856 | '((assoc ";;" ";&" ";;&")) | ||
| 1857 | '((assoc "case") (assoc ";" "&") (assoc "&&" "||") (assoc "|" "|&"))))) | ||
| 1858 | |||
| 1859 | (defun sh-smie--rc-after-special-arg-p () | ||
| 1860 | "Check if we're after the first arg of an if/while/for/... construct. | ||
| 1861 | Returns the construct's token and moves point before it, if so." | ||
| 1862 | (forward-comment (- (point))) | ||
| 1863 | (when (looking-back ")\\|\\_<not" (- (point) 3)) | ||
| 1864 | (ignore-errors | ||
| 1865 | (let ((forward-sexp-function nil)) | ||
| 1866 | (forward-sexp -1) | ||
| 1867 | (car (member (funcall smie-backward-token-function) | ||
| 1868 | '("if" "for" "switch" "while"))))))) | ||
| 1869 | |||
| 1870 | (defun sh-smie--rc-newline-semi-p () | ||
| 1871 | "Return non-nil if a newline should be treated as a semi-colon. | ||
| 1872 | Point should be before the newline." | ||
| 1873 | (save-excursion | ||
| 1874 | (let ((tok (funcall smie-backward-token-function))) | ||
| 1875 | (if (or (when (equal tok "not") (forward-word 1) t) | ||
| 1876 | (and (zerop (length tok)) (eq (char-before) ?\)))) | ||
| 1877 | (not (sh-smie--rc-after-special-arg-p)) | ||
| 1878 | (sh-smie--newline-semi-p tok))))) | ||
| 1879 | |||
| 1880 | (defun sh-smie-rc-forward-token () | ||
| 1881 | ;; FIXME: Code duplication with sh-smie-sh-forward-token. | ||
| 1882 | (if (and (looking-at "[ \t]*\\(?:#\\|\\(\\s|\\)\\|$\\)") | ||
| 1883 | (save-excursion | ||
| 1884 | (skip-chars-backward " \t") | ||
| 1885 | (not (bolp)))) | ||
| 1886 | (if (and (match-end 1) (not (nth 3 (syntax-ppss)))) | ||
| 1887 | ;; Right before a here-doc. | ||
| 1888 | (let ((forward-sexp-function nil)) | ||
| 1889 | (forward-sexp 1) | ||
| 1890 | ;; Pretend the here-document is a "newline representing a | ||
| 1891 | ;; semi-colon", since the here-doc otherwise covers the newline(s). | ||
| 1892 | ";") | ||
| 1893 | (let ((semi (sh-smie--rc-newline-semi-p))) | ||
| 1894 | (forward-line 1) | ||
| 1895 | (if semi ";" | ||
| 1896 | (sh-smie-rc-forward-token)))) | ||
| 1897 | (forward-comment (point-max)) | ||
| 1898 | (cond | ||
| 1899 | ((looking-at "\\\\\n") (forward-line 1) (sh-smie-rc-forward-token)) | ||
| 1900 | ;; ((looking-at sh-smie--rc-operators-re) | ||
| 1901 | ;; (goto-char (match-end 0)) | ||
| 1902 | ;; (let ((tok (match-string-no-properties 0))) | ||
| 1903 | ;; (if (and (memq (aref tok (1- (length tok))) '(?\; ?\& ?\|)) | ||
| 1904 | ;; (looking-at "[ \t]*\\(?:#\\|$\\)")) | ||
| 1905 | ;; (forward-line 1)) | ||
| 1906 | ;; tok)) | ||
| 1907 | (t | ||
| 1908 | (let* ((pos (point)) | ||
| 1909 | (tok (smie-default-forward-token))) | ||
| 1910 | (cond | ||
| 1911 | ;; ((equal tok ")") "case-)") | ||
| 1912 | ((and tok (string-match "\\`[a-z]" tok) | ||
| 1913 | (assoc tok smie-grammar) | ||
| 1914 | (not | ||
| 1915 | (save-excursion | ||
| 1916 | (goto-char pos) | ||
| 1917 | (sh-smie--keyword-p tok)))) | ||
| 1918 | " word ") | ||
| 1919 | (t tok))))))) | ||
| 1920 | |||
| 1921 | (defun sh-smie-rc-backward-token () | ||
| 1922 | ;; FIXME: Code duplication with sh-smie-sh-backward-token. | ||
| 1923 | (let ((bol (line-beginning-position)) | ||
| 1924 | pos tok) | ||
| 1925 | (forward-comment (- (point))) | ||
| 1926 | (cond | ||
| 1927 | ((and (bolp) (not (bobp)) | ||
| 1928 | (equal (syntax-after (1- (point))) (string-to-syntax "|")) | ||
| 1929 | (not (nth 3 (syntax-ppss)))) | ||
| 1930 | ;; Right after a here-document. | ||
| 1931 | (let ((forward-sexp-function nil)) | ||
| 1932 | (forward-sexp -1) | ||
| 1933 | ;; Pretend the here-document is a "newline representing a | ||
| 1934 | ;; semi-colon", since the here-doc otherwise covers the newline(s). | ||
| 1935 | ";")) | ||
| 1936 | ((< (point) bol) ;We skipped over a newline. | ||
| 1937 | (cond | ||
| 1938 | ;; A continued line. | ||
| 1939 | ((and (eolp) | ||
| 1940 | (looking-back "\\(?:^\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\\\" | ||
| 1941 | (line-beginning-position))) | ||
| 1942 | (forward-char -1) | ||
| 1943 | (funcall smie-backward-token-function)) | ||
| 1944 | ((sh-smie--rc-newline-semi-p) ";") | ||
| 1945 | (t (funcall smie-backward-token-function)))) | ||
| 1946 | ;; ((looking-back sh-smie--sh-operators-back-re | ||
| 1947 | ;; (line-beginning-position) 'greedy) | ||
| 1948 | ;; (goto-char (match-beginning 1)) | ||
| 1949 | ;; (match-string-no-properties 1)) | ||
| 1950 | (t | ||
| 1951 | (let ((tok (smie-default-backward-token))) | ||
| 1952 | (cond | ||
| 1953 | ;; ((equal tok ")") "case-)") | ||
| 1954 | ((and tok (string-match "\\`[a-z]" tok) | ||
| 1955 | (assoc tok smie-grammar) | ||
| 1956 | (not (save-excursion (sh-smie--keyword-p tok)))) | ||
| 1957 | " word ") | ||
| 1958 | (t tok))))))) | ||
| 1959 | |||
| 1960 | (defun sh-smie-rc-rules (kind token) | ||
| 1961 | (pcase (cons kind token) | ||
| 1962 | (`(:elem . basic) sh-indentation) | ||
| 1963 | ;; (`(:after . "case") (or sh-indentation smie-indent-basic)) | ||
| 1964 | (`(:after . ";") (if (smie-rule-parent-p "case") | ||
| 1965 | (smie-rule-parent sh-indentation))) | ||
| 1966 | (`(:before . "{") | ||
| 1967 | (save-excursion | ||
| 1968 | (when (sh-smie--rc-after-special-arg-p) | ||
| 1969 | `(column . ,(current-column))))) | ||
| 1970 | (`(:before . ,(or `"(" `"{" `"[")) | ||
| 1971 | (if (smie-rule-hanging-p) (smie-rule-parent))) | ||
| 1972 | ;; FIXME: SMIE parses "if (exp) cmd" as "(if ((exp) cmd))" so "cmd" is | ||
| 1973 | ;; treated as an arg to (exp) by default, which indents it all wrong. | ||
| 1974 | ;; To handle it right, we should extend smie-indent-exps so that the | ||
| 1975 | ;; preceding keyword can give special rules. Currently the only special | ||
| 1976 | ;; rule we have is the :list-intro hack, which we use here to align "cmd" | ||
| 1977 | ;; with "(exp)", which is rarely the right thing to do, but is better | ||
| 1978 | ;; than nothing. | ||
| 1979 | (`(:list-intro . ,(or `"for" `"if" `"while")) t) | ||
| 1980 | )) | ||
| 1981 | |||
| 1982 | ;;; End of SMIE code. | ||
| 1581 | 1983 | ||
| 1582 | (defvar sh-regexp-for-done nil | 1984 | (defvar sh-regexp-for-done nil |
| 1583 | "A buffer-local regexp to match opening keyword for done.") | 1985 | "A buffer-local regexp to match opening keyword for done.") |
| @@ -1677,19 +2079,28 @@ Calls the value of `sh-set-shell-hook' if set." | |||
| 1677 | (set-syntax-table sh-mode-syntax-table))) | 2079 | (set-syntax-table sh-mode-syntax-table))) |
| 1678 | (dolist (var (sh-feature sh-variables)) | 2080 | (dolist (var (sh-feature sh-variables)) |
| 1679 | (sh-remember-variable var)) | 2081 | (sh-remember-variable var)) |
| 1680 | (if (setq sh-indent-supported-here (sh-feature sh-indent-supported)) | 2082 | (if (set (make-local-variable 'sh-indent-supported-here) |
| 2083 | (sh-feature sh-indent-supported)) | ||
| 1681 | (progn | 2084 | (progn |
| 1682 | (message "Setting up indent for shell type %s" sh-shell) | 2085 | (message "Setting up indent for shell type %s" sh-shell) |
| 1683 | (set (make-local-variable 'parse-sexp-lookup-properties) t) | 2086 | (if sh-use-smie |
| 1684 | (set (make-local-variable 'sh-kw-alist) (sh-feature sh-kw)) | 2087 | (let ((mksym (lambda (name) |
| 1685 | (let ((regexp (sh-feature sh-kws-for-done))) | 2088 | (intern (format "sh-smie-%s-%s" |
| 1686 | (if regexp | 2089 | sh-indent-supported-here name))))) |
| 1687 | (set (make-local-variable 'sh-regexp-for-done) | 2090 | (smie-setup (symbol-value (funcall mksym "grammar")) |
| 1688 | (sh-mkword-regexpr (regexp-opt regexp t))))) | 2091 | (funcall mksym "rules") |
| 1689 | (message "setting up indent stuff") | 2092 | :forward-token (funcall mksym "forward-token") |
| 1690 | ;; sh-mode has already made indent-line-function local | 2093 | :backward-token (funcall mksym "backward-token"))) |
| 1691 | ;; but do it in case this is called before that. | 2094 | (set (make-local-variable 'parse-sexp-lookup-properties) t) |
| 1692 | (set (make-local-variable 'indent-line-function) 'sh-indent-line) | 2095 | (set (make-local-variable 'sh-kw-alist) (sh-feature sh-kw)) |
| 2096 | (let ((regexp (sh-feature sh-kws-for-done))) | ||
| 2097 | (if regexp | ||
| 2098 | (set (make-local-variable 'sh-regexp-for-done) | ||
| 2099 | (sh-mkword-regexpr (regexp-opt regexp t))))) | ||
| 2100 | (message "setting up indent stuff") | ||
| 2101 | ;; sh-mode has already made indent-line-function local | ||
| 2102 | ;; but do it in case this is called before that. | ||
| 2103 | (set (make-local-variable 'indent-line-function) 'sh-indent-line)) | ||
| 1693 | (if sh-make-vars-local | 2104 | (if sh-make-vars-local |
| 1694 | (sh-make-vars-local)) | 2105 | (sh-make-vars-local)) |
| 1695 | (message "Indentation setup for shell type %s" sh-shell)) | 2106 | (message "Indentation setup for shell type %s" sh-shell)) |
| @@ -3237,8 +3648,9 @@ overwritten if | |||
| 3237 | (defun sh-save-styles-to-buffer (buff) | 3648 | (defun sh-save-styles-to-buffer (buff) |
| 3238 | "Save all current styles in elisp to buffer BUFF. | 3649 | "Save all current styles in elisp to buffer BUFF. |
| 3239 | This is always added to the end of the buffer." | 3650 | This is always added to the end of the buffer." |
| 3240 | (interactive (list | 3651 | (interactive |
| 3241 | (read-from-minibuffer "Buffer to save styles in? " "*scratch*"))) | 3652 | (list |
| 3653 | (read-from-minibuffer "Buffer to save styles in? " "*scratch*"))) | ||
| 3242 | (with-current-buffer (get-buffer-create buff) | 3654 | (with-current-buffer (get-buffer-create buff) |
| 3243 | (goto-char (point-max)) | 3655 | (goto-char (point-max)) |
| 3244 | (insert "\n") | 3656 | (insert "\n") |
| @@ -3656,8 +4068,12 @@ option followed by a colon `:' if the option accepts an argument." | |||
| 3656 | The document is bounded by `sh-here-document-word'." | 4068 | The document is bounded by `sh-here-document-word'." |
| 3657 | (interactive "*P") | 4069 | (interactive "*P") |
| 3658 | (self-insert-command (prefix-numeric-value arg)) | 4070 | (self-insert-command (prefix-numeric-value arg)) |
| 3659 | (or arg | 4071 | (or arg (sh--maybe-here-document))) |
| 3660 | (not (looking-back "[^<]<<")) | 4072 | (make-obsolete 'sh--maybe-here-document |
| 4073 | 'sh-electric-here-document-mode "24.2") | ||
| 4074 | |||
| 4075 | (defun sh--maybe-here-document () | ||
| 4076 | (or (not (looking-back "[^<]<<")) | ||
| 3661 | (save-excursion | 4077 | (save-excursion |
| 3662 | (backward-char 2) | 4078 | (backward-char 2) |
| 3663 | (sh-quoted-p)) | 4079 | (sh-quoted-p)) |
| @@ -3678,6 +4094,12 @@ The document is bounded by `sh-here-document-word'." | |||
| 3678 | (insert ?\n tabs (replace-regexp-in-string | 4094 | (insert ?\n tabs (replace-regexp-in-string |
| 3679 | "\\`-?[ \t]*" "" delim)))))) | 4095 | "\\`-?[ \t]*" "" delim)))))) |
| 3680 | 4096 | ||
| 4097 | (define-minor-mode sh-electric-here-document-mode | ||
| 4098 | "Make << insert a here document skeleton." | ||
| 4099 | nil nil nil | ||
| 4100 | (if sh-electric-here-document-mode | ||
| 4101 | (add-hook 'post-self-insert-hook #'sh--maybe-here-document nil t) | ||
| 4102 | (remove-hook 'post-self-insert-hook #'sh--maybe-here-document t))) | ||
| 3681 | 4103 | ||
| 3682 | ;; various other commands | 4104 | ;; various other commands |
| 3683 | 4105 | ||
| @@ -3696,12 +4118,14 @@ The document is bounded by `sh-here-document-word'." | |||
| 3696 | 4118 | ||
| 3697 | 4119 | ||
| 3698 | (defun sh-beginning-of-command () | 4120 | (defun sh-beginning-of-command () |
| 4121 | ;; FIXME: Redefine using SMIE. | ||
| 3699 | "Move point to successive beginnings of commands." | 4122 | "Move point to successive beginnings of commands." |
| 3700 | (interactive) | 4123 | (interactive) |
| 3701 | (if (re-search-backward sh-beginning-of-command nil t) | 4124 | (if (re-search-backward sh-beginning-of-command nil t) |
| 3702 | (goto-char (match-beginning 2)))) | 4125 | (goto-char (match-beginning 2)))) |
| 3703 | 4126 | ||
| 3704 | (defun sh-end-of-command () | 4127 | (defun sh-end-of-command () |
| 4128 | ;; FIXME: Redefine using SMIE. | ||
| 3705 | "Move point to successive ends of commands." | 4129 | "Move point to successive ends of commands." |
| 3706 | (interactive) | 4130 | (interactive) |
| 3707 | (if (re-search-forward sh-end-of-command nil t) | 4131 | (if (re-search-forward sh-end-of-command nil t) |