diff options
Diffstat (limited to 'lisp/progmodes/sh-script.el')
| -rw-r--r-- | lisp/progmodes/sh-script.el | 104 |
1 files changed, 52 insertions, 52 deletions
diff --git a/lisp/progmodes/sh-script.el b/lisp/progmodes/sh-script.el index 9041bd50259..d41a81e38a6 100644 --- a/lisp/progmodes/sh-script.el +++ b/lisp/progmodes/sh-script.el | |||
| @@ -939,7 +939,6 @@ See `sh-feature'.") | |||
| 939 | ;; These are used for the syntax table stuff (derived from cperl-mode). | 939 | ;; These are used for the syntax table stuff (derived from cperl-mode). |
| 940 | ;; Note: parse-sexp-lookup-properties must be set to t for it to work. | 940 | ;; Note: parse-sexp-lookup-properties must be set to t for it to work. |
| 941 | (defconst sh-st-punc (string-to-syntax ".")) | 941 | (defconst sh-st-punc (string-to-syntax ".")) |
| 942 | (defconst sh-st-symbol (string-to-syntax "_")) | ||
| 943 | (defconst sh-here-doc-syntax (string-to-syntax "|")) ;; generic string | 942 | (defconst sh-here-doc-syntax (string-to-syntax "|")) ;; generic string |
| 944 | 943 | ||
| 945 | (defconst sh-escaped-line-re | 944 | (defconst sh-escaped-line-re |
| @@ -957,7 +956,7 @@ See `sh-feature'.") | |||
| 957 | (defvar sh-here-doc-re sh-here-doc-open-re) | 956 | (defvar sh-here-doc-re sh-here-doc-open-re) |
| 958 | (make-variable-buffer-local 'sh-here-doc-re) | 957 | (make-variable-buffer-local 'sh-here-doc-re) |
| 959 | 958 | ||
| 960 | (defun sh-font-lock-close-heredoc (bol eof indented) | 959 | (defun sh-font-lock-close-heredoc (bol eof indented eol) |
| 961 | "Determine the syntax of the \\n after an EOF. | 960 | "Determine the syntax of the \\n after an EOF. |
| 962 | If non-nil INDENTED indicates that the EOF was indented." | 961 | If non-nil INDENTED indicates that the EOF was indented." |
| 963 | (let* ((eof-re (if eof (regexp-quote eof) "")) | 962 | (let* ((eof-re (if eof (regexp-quote eof) "")) |
| @@ -971,6 +970,8 @@ If non-nil INDENTED indicates that the EOF was indented." | |||
| 971 | (ere (concat "^" (if indented "[ \t]*") eof-re "\n")) | 970 | (ere (concat "^" (if indented "[ \t]*") eof-re "\n")) |
| 972 | (start (save-excursion | 971 | (start (save-excursion |
| 973 | (goto-char bol) | 972 | (goto-char bol) |
| 973 | ;; FIXME: will incorrectly find a <<EOF embedded inside | ||
| 974 | ;; the heredoc. | ||
| 974 | (re-search-backward (concat sre "\\|" ere) nil t)))) | 975 | (re-search-backward (concat sre "\\|" ere) nil t)))) |
| 975 | ;; If subgroup 1 matched, we found an open-heredoc, otherwise we first | 976 | ;; If subgroup 1 matched, we found an open-heredoc, otherwise we first |
| 976 | ;; found a close-heredoc which makes the current close-heredoc inoperant. | 977 | ;; found a close-heredoc which makes the current close-heredoc inoperant. |
| @@ -990,7 +991,7 @@ If non-nil INDENTED indicates that the EOF was indented." | |||
| 990 | (sh-in-comment-or-string (point))))) | 991 | (sh-in-comment-or-string (point))))) |
| 991 | ;; No <<EOF2 found after our <<. | 992 | ;; No <<EOF2 found after our <<. |
| 992 | (= (point) start))) | 993 | (= (point) start))) |
| 993 | sh-here-doc-syntax) | 994 | (put-text-property eol (1+ eol) 'syntax-table sh-here-doc-syntax)) |
| 994 | ((not (or start (save-excursion (re-search-forward sre nil t)))) | 995 | ((not (or start (save-excursion (re-search-forward sre nil t)))) |
| 995 | ;; There's no <<EOF either before or after us, | 996 | ;; There's no <<EOF either before or after us, |
| 996 | ;; so we should remove ourselves from font-lock's keywords. | 997 | ;; so we should remove ourselves from font-lock's keywords. |
| @@ -1000,7 +1001,7 @@ If non-nil INDENTED indicates that the EOF was indented." | |||
| 1000 | (regexp-opt sh-here-doc-markers t) "\\(\n\\)")) | 1001 | (regexp-opt sh-here-doc-markers t) "\\(\n\\)")) |
| 1001 | nil)))) | 1002 | nil)))) |
| 1002 | 1003 | ||
| 1003 | (defun sh-font-lock-open-heredoc (start string) | 1004 | (defun sh-font-lock-open-heredoc (start string eol) |
| 1004 | "Determine the syntax of the \\n after a <<EOF. | 1005 | "Determine the syntax of the \\n after a <<EOF. |
| 1005 | START is the position of <<. | 1006 | START is the position of <<. |
| 1006 | STRING is the actual word used as delimiter (e.g. \"EOF\"). | 1007 | STRING is the actual word used as delimiter (e.g. \"EOF\"). |
| @@ -1030,13 +1031,8 @@ Point is at the beginning of the next line." | |||
| 1030 | ;; Don't bother fixing it now, but place a multiline property so | 1031 | ;; Don't bother fixing it now, but place a multiline property so |
| 1031 | ;; that when jit-lock-context-* refontifies the rest of the | 1032 | ;; that when jit-lock-context-* refontifies the rest of the |
| 1032 | ;; buffer, it also refontifies the current line with it. | 1033 | ;; buffer, it also refontifies the current line with it. |
| 1033 | (put-text-property start (point) 'font-lock-multiline t))) | 1034 | (put-text-property start (point) 'syntax-multiline t))) |
| 1034 | sh-here-doc-syntax)) | 1035 | (put-text-property eol (1+ eol) 'syntax-table sh-here-doc-syntax))) |
| 1035 | |||
| 1036 | (defun sh-font-lock-here-doc (limit) | ||
| 1037 | "Search for a heredoc marker." | ||
| 1038 | ;; This looks silly, but it's because `sh-here-doc-re' keeps changing. | ||
| 1039 | (re-search-forward sh-here-doc-re limit t)) | ||
| 1040 | 1036 | ||
| 1041 | (defun sh-font-lock-quoted-subshell (limit) | 1037 | (defun sh-font-lock-quoted-subshell (limit) |
| 1042 | "Search for a subshell embedded in a string. | 1038 | "Search for a subshell embedded in a string. |
| @@ -1045,9 +1041,7 @@ subshells can nest." | |||
| 1045 | ;; FIXME: This can (and often does) match multiple lines, yet it makes no | 1041 | ;; FIXME: This can (and often does) match multiple lines, yet it makes no |
| 1046 | ;; effort to handle multiline cases correctly, so it ends up being | 1042 | ;; effort to handle multiline cases correctly, so it ends up being |
| 1047 | ;; rather flakey. | 1043 | ;; rather flakey. |
| 1048 | (when (and (re-search-forward "\"\\(?:\\(?:.\\|\n\\)*?[^\\]\\(?:\\\\\\\\\\)*\\)??\\(\\$(\\|`\\)" limit t) | 1044 | (when (eq ?\" (nth 3 (syntax-ppss))) ; Check we matched an opening quote. |
| 1049 | ;; Make sure the " we matched is an opening quote. | ||
| 1050 | (eq ?\" (nth 3 (syntax-ppss)))) | ||
| 1051 | ;; bingo we have a $( or a ` inside a "" | 1045 | ;; bingo we have a $( or a ` inside a "" |
| 1052 | (let ((char (char-after (point))) | 1046 | (let ((char (char-after (point))) |
| 1053 | ;; `state' can be: double-quote, backquote, code. | 1047 | ;; `state' can be: double-quote, backquote, code. |
| @@ -1082,8 +1076,7 @@ subshells can nest." | |||
| 1082 | (double-quote nil) | 1076 | (double-quote nil) |
| 1083 | (t (setq state (pop states))))) | 1077 | (t (setq state (pop states))))) |
| 1084 | (t (error "Internal error in sh-font-lock-quoted-subshell"))) | 1078 | (t (error "Internal error in sh-font-lock-quoted-subshell"))) |
| 1085 | (forward-char 1))) | 1079 | (forward-char 1))))) |
| 1086 | t)) | ||
| 1087 | 1080 | ||
| 1088 | 1081 | ||
| 1089 | (defun sh-is-quoted-p (pos) | 1082 | (defun sh-is-quoted-p (pos) |
| @@ -1122,7 +1115,7 @@ subshells can nest." | |||
| 1122 | (when (progn (backward-char 2) | 1115 | (when (progn (backward-char 2) |
| 1123 | (if (> start (line-end-position)) | 1116 | (if (> start (line-end-position)) |
| 1124 | (put-text-property (point) (1+ start) | 1117 | (put-text-property (point) (1+ start) |
| 1125 | 'font-lock-multiline t)) | 1118 | 'syntax-multiline t)) |
| 1126 | ;; FIXME: The `in' may just be a random argument to | 1119 | ;; FIXME: The `in' may just be a random argument to |
| 1127 | ;; a normal command rather than the real `in' keyword. | 1120 | ;; a normal command rather than the real `in' keyword. |
| 1128 | ;; I.e. we should look back to try and find the | 1121 | ;; I.e. we should look back to try and find the |
| @@ -1136,40 +1129,44 @@ subshells can nest." | |||
| 1136 | sh-st-punc | 1129 | sh-st-punc |
| 1137 | nil)) | 1130 | nil)) |
| 1138 | 1131 | ||
| 1139 | (defun sh-font-lock-flush-syntax-ppss-cache (limit) | 1132 | (defun sh-syntax-propertize-function (start end) |
| 1140 | ;; This should probably be a standard function provided by font-lock.el | 1133 | (goto-char start) |
| 1141 | ;; (or syntax.el). | 1134 | (while (prog1 |
| 1142 | (syntax-ppss-flush-cache (point)) | 1135 | (re-search-forward sh-here-doc-re end 'move) |
| 1143 | (goto-char limit) | 1136 | (save-excursion |
| 1144 | nil) | 1137 | (save-match-data |
| 1145 | 1138 | (funcall | |
| 1146 | (defconst sh-font-lock-syntactic-keywords | 1139 | (syntax-propertize-rules |
| 1147 | ;; A `#' begins a comment when it is unquoted and at the beginning of a | 1140 | ;; A `#' begins a comment when it is unquoted and at the |
| 1148 | ;; word. In the shell, words are separated by metacharacters. | 1141 | ;; beginning of a word. In the shell, words are separated by |
| 1149 | ;; The list of special chars is taken from the single-unix spec | 1142 | ;; metacharacters. The list of special chars is taken from |
| 1150 | ;; of the shell command language (under `quoting') but with `$' removed. | 1143 | ;; the single-unix spec of the shell command language (under |
| 1151 | `(("[^|&;<>()`\\\"' \t\n]\\(#+\\)" 1 ,sh-st-symbol) | 1144 | ;; `quoting') but with `$' removed. |
| 1152 | ;; In a '...' the backslash is not escaping. | 1145 | ("[^|&;<>()`\\\"' \t\n]\\(#+\\)" (1 "_")) |
| 1153 | ("\\(\\\\\\)'" (1 (sh-font-lock-backslash-quote))) | 1146 | ;; In a '...' the backslash is not escaping. |
| 1154 | ;; The previous rule uses syntax-ppss, but the subsequent rules may | 1147 | ("\\(\\\\\\)'" (1 (sh-font-lock-backslash-quote))) |
| 1155 | ;; change the syntax, so we have to tell syntax-ppss that the states it | 1148 | ;; Make sure $@ and $? are correctly recognized as sexps. |
| 1156 | ;; has just computed will need to be recomputed. | 1149 | ("\\$\\([?@]\\)" (1 "_")) |
| 1157 | (sh-font-lock-flush-syntax-ppss-cache) | 1150 | ;; Distinguish the special close-paren in `case'. |
| 1158 | ;; Make sure $@ and $? are correctly recognized as sexps. | 1151 | (")" (0 (sh-font-lock-paren (match-beginning 0)))) |
| 1159 | ("\\$\\([?@]\\)" 1 ,sh-st-symbol) | 1152 | ;; Highlight (possibly nested) subshells inside "" quoted |
| 1160 | ;; Find HEREDOC starters and add a corresponding rule for the ender. | 1153 | ;; regions correctly. |
| 1161 | (sh-font-lock-here-doc | 1154 | ("\"\\(?:\\(?:.\\|\n\\)*?[^\\]\\(?:\\\\\\\\\\)*\\)??\\(\\$(\\|`\\)" |
| 1162 | (2 (sh-font-lock-open-heredoc | 1155 | (1 (ignore |
| 1163 | (match-beginning 0) (match-string 1)) nil t) | 1156 | ;; Save excursion because we want to also apply other |
| 1164 | (5 (sh-font-lock-close-heredoc | 1157 | ;; syntax-propertize rules within the affected region. |
| 1165 | (match-beginning 0) (match-string 4) | 1158 | (save-excursion |
| 1166 | (and (match-beginning 3) (/= (match-beginning 3) (match-end 3)))) | 1159 | (sh-font-lock-quoted-subshell end)))))) |
| 1167 | nil t)) | 1160 | (prog1 start (setq start (point))) (point))))) |
| 1168 | ;; Distinguish the special close-paren in `case'. | 1161 | (if (match-beginning 2) |
| 1169 | (")" 0 (sh-font-lock-paren (match-beginning 0))) | 1162 | ;; FIXME: actually, once we see an heredoc opener, we should just |
| 1170 | ;; highlight (possibly nested) subshells inside "" quoted regions correctly. | 1163 | ;; search for its ender without propertizing anything in it. |
| 1171 | ;; This should be at the very end because it uses syntax-ppss. | 1164 | (sh-font-lock-open-heredoc |
| 1172 | (sh-font-lock-quoted-subshell))) | 1165 | (match-beginning 0) (match-string 1) (match-beginning 2)) |
| 1166 | (sh-font-lock-close-heredoc | ||
| 1167 | (match-beginning 0) (match-string 4) | ||
| 1168 | (and (match-beginning 3) (/= (match-beginning 3) (match-end 3))) | ||
| 1169 | (match-beginning 5))))) | ||
| 1173 | 1170 | ||
| 1174 | (defun sh-font-lock-syntactic-face-function (state) | 1171 | (defun sh-font-lock-syntactic-face-function (state) |
| 1175 | (let ((q (nth 3 state))) | 1172 | (let ((q (nth 3 state))) |
| @@ -1553,9 +1550,12 @@ with your script for an edit-interpret-debug cycle." | |||
| 1553 | sh-font-lock-keywords-1 sh-font-lock-keywords-2) | 1550 | sh-font-lock-keywords-1 sh-font-lock-keywords-2) |
| 1554 | nil nil | 1551 | nil nil |
| 1555 | ((?/ . "w") (?~ . "w") (?. . "w") (?- . "w") (?_ . "w")) nil | 1552 | ((?/ . "w") (?~ . "w") (?. . "w") (?- . "w") (?_ . "w")) nil |
| 1556 | (font-lock-syntactic-keywords . sh-font-lock-syntactic-keywords) | ||
| 1557 | (font-lock-syntactic-face-function | 1553 | (font-lock-syntactic-face-function |
| 1558 | . sh-font-lock-syntactic-face-function))) | 1554 | . sh-font-lock-syntactic-face-function))) |
| 1555 | (set (make-local-variable 'syntax-propertize-function) | ||
| 1556 | #'sh-syntax-propertize-function) | ||
| 1557 | (add-hook 'syntax-propertize-extend-region-functions | ||
| 1558 | #'syntax-propertize-multiline 'append 'local) | ||
| 1559 | (set (make-local-variable 'skeleton-pair-alist) '((?` _ ?`))) | 1559 | (set (make-local-variable 'skeleton-pair-alist) '((?` _ ?`))) |
| 1560 | (set (make-local-variable 'skeleton-pair-filter-function) 'sh-quoted-p) | 1560 | (set (make-local-variable 'skeleton-pair-filter-function) 'sh-quoted-p) |
| 1561 | (set (make-local-variable 'skeleton-further-elements) | 1561 | (set (make-local-variable 'skeleton-further-elements) |