diff options
Diffstat (limited to '.emacs.d/lisp/lua-mode.el')
| -rw-r--r-- | .emacs.d/lisp/lua-mode.el | 991 |
1 files changed, 636 insertions, 355 deletions
diff --git a/.emacs.d/lisp/lua-mode.el b/.emacs.d/lisp/lua-mode.el index 640e490..2d6a2d5 100644 --- a/.emacs.d/lisp/lua-mode.el +++ b/.emacs.d/lisp/lua-mode.el | |||
| @@ -11,16 +11,16 @@ | |||
| 11 | ;; Paul Du Bois <pld-lua@gelatinous.com> and | 11 | ;; Paul Du Bois <pld-lua@gelatinous.com> and |
| 12 | ;; Aaron Smith <aaron-lua@gelatinous.com>. | 12 | ;; Aaron Smith <aaron-lua@gelatinous.com>. |
| 13 | ;; | 13 | ;; |
| 14 | ;; URL: http://immerrr.github.com/lua-mode | 14 | ;; URL: https://immerrr.github.io/lua-mode |
| 15 | ;; Version: 20151025 | 15 | ;; Version: 20210802 |
| 16 | ;; Package-Requires: ((emacs "24.3")) | 16 | ;; Package-Requires: ((emacs "24.3")) |
| 17 | ;; | 17 | ;; |
| 18 | ;; This file is NOT part of Emacs. | 18 | ;; This file is NOT part of Emacs. |
| 19 | ;; | 19 | ;; |
| 20 | ;; This program is free software; you can redistribute it and/or | 20 | ;; This program is free software; you can redistribute it and/or modify |
| 21 | ;; modify it under the terms of the GNU General Public License | 21 | ;; it under the terms of the GNU General Public License as published by |
| 22 | ;; as published by the Free Software Foundation; either version 2 | 22 | ;; the Free Software Foundation, either version 3 of the License, or |
| 23 | ;; of the License, or (at your option) any later version. | 23 | ;; (at your option) any later version. |
| 24 | ;; | 24 | ;; |
| 25 | ;; This program is distributed in the hope that it will be useful, | 25 | ;; This program is distributed in the hope that it will be useful, |
| 26 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of | 26 | ;; but WITHOUT ANY WARRANTY; without even the implied warranty of |
| @@ -28,15 +28,13 @@ | |||
| 28 | ;; GNU General Public License for more details. | 28 | ;; GNU General Public License for more details. |
| 29 | ;; | 29 | ;; |
| 30 | ;; You should have received a copy of the GNU General Public License | 30 | ;; You should have received a copy of the GNU General Public License |
| 31 | ;; along with this program; if not, write to the Free Software | 31 | ;; along with this program. If not, see <https://www.gnu.org/licenses/>. |
| 32 | ;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, | ||
| 33 | ;; MA 02110-1301, USA. | ||
| 34 | 32 | ||
| 35 | ;; Keywords: languages, processes, tools | 33 | ;; Keywords: languages, processes, tools |
| 36 | 34 | ||
| 37 | ;; This field is expanded to commit SHA, date & associated heads/tags during | 35 | ;; This field is expanded to commit SHA and commit date during the |
| 38 | ;; archive creation. | 36 | ;; archive creation. |
| 39 | ;; Revision: $Format:%h (%cD %d)$ | 37 | ;; Revision: $Format:%h (%cD)$ |
| 40 | ;; | 38 | ;; |
| 41 | 39 | ||
| 42 | ;;; Commentary: | 40 | ;;; Commentary: |
| @@ -53,6 +51,12 @@ | |||
| 53 | ;; - Var `lua-indent-string-contents': | 51 | ;; - Var `lua-indent-string-contents': |
| 54 | ;; set to `t` if you like to have contents of multiline strings to be | 52 | ;; set to `t` if you like to have contents of multiline strings to be |
| 55 | ;; indented like comments | 53 | ;; indented like comments |
| 54 | ;; - Var `lua-indent-nested-block-content-align': | ||
| 55 | ;; set to `nil' to stop aligning the content of nested blocks with the | ||
| 56 | ;; open parenthesis | ||
| 57 | ;; - Var `lua-indent-close-paren-align': | ||
| 58 | ;; set to `t' to align close parenthesis with the open parenthesis, | ||
| 59 | ;; rather than with the beginning of the line | ||
| 56 | ;; - Var `lua-mode-hook': | 60 | ;; - Var `lua-mode-hook': |
| 57 | ;; list of functions to execute when lua-mode is initialized | 61 | ;; list of functions to execute when lua-mode is initialized |
| 58 | ;; - Var `lua-documentation-url': | 62 | ;; - Var `lua-documentation-url': |
| @@ -115,7 +119,7 @@ | |||
| 115 | 119 | ||
| 116 | (lua-name (symbol (seq (+ (any alpha "_")) (* (any alnum "_"))))) | 120 | (lua-name (symbol (seq (+ (any alpha "_")) (* (any alnum "_"))))) |
| 117 | (lua-funcname (seq lua-name (* ws "." ws lua-name) | 121 | (lua-funcname (seq lua-name (* ws "." ws lua-name) |
| 118 | (opt ws ":" ws lua-name))) | 122 | (opt ws ":" ws lua-name))) |
| 119 | (lua-funcheader | 123 | (lua-funcheader |
| 120 | ;; Outer (seq ...) is here to shy-group the definition | 124 | ;; Outer (seq ...) is here to shy-group the definition |
| 121 | (seq (or (seq (symbol "function") ws (group-n 1 lua-funcname)) | 125 | (seq (or (seq (symbol "function") ws (group-n 1 lua-funcname)) |
| @@ -123,15 +127,26 @@ | |||
| 123 | (symbol "function"))))) | 127 | (symbol "function"))))) |
| 124 | (lua-number | 128 | (lua-number |
| 125 | (seq (or (seq (+ digit) (opt ".") (* digit)) | 129 | (seq (or (seq (+ digit) (opt ".") (* digit)) |
| 126 | (seq (* digit) (opt ".") (+ digit))) | 130 | (seq (* digit) (opt ".") (+ digit))) |
| 127 | (opt (regexp "[eE][+-]?[0-9]+")))) | 131 | (opt (regexp "[eE][+-]?[0-9]+")))) |
| 128 | (lua-assignment-op (seq "=" (or buffer-end (not (any "="))))) | 132 | (lua-assignment-op (seq "=" (or buffer-end (not (any "="))))) |
| 129 | (lua-token (or "+" "-" "*" "/" "%" "^" "#" "==" "~=" "<=" ">=" "<" | 133 | (lua-operator (or "+" "-" "*" "/" "%" "^" "#" "==" "~=" "<=" ">=" "<" |
| 130 | ">" "=" ";" ":" "," "." ".." "...")) | 134 | ">" "=" ";" ":" "," "." ".." "...")) |
| 135 | (lua-keyword-operator (symbol "and" "not" "or")) | ||
| 131 | (lua-keyword | 136 | (lua-keyword |
| 132 | (symbol "and" "break" "do" "else" "elseif" "end" "for" "function" | 137 | (symbol "break" "do" "else" "elseif" "end" "for" "function" |
| 133 | "goto" "if" "in" "local" "not" "or" "repeat" "return" | 138 | "goto" "if" "in" "local" "repeat" "return" |
| 134 | "then" "until" "while")))) | 139 | "then" "until" "while")) |
| 140 | (lua-up-to-9-variables | ||
| 141 | (seq (group-n 1 lua-name) ws | ||
| 142 | (? "," ws (group-n 2 lua-name) ws | ||
| 143 | (? "," ws (group-n 3 lua-name) ws | ||
| 144 | (? "," ws (group-n 4 lua-name) ws | ||
| 145 | (? "," ws (group-n 5 lua-name) ws | ||
| 146 | (? "," ws (group-n 6 lua-name) ws | ||
| 147 | (? "," ws (group-n 7 lua-name) ws | ||
| 148 | (? "," ws (group-n 8 lua-name) ws | ||
| 149 | (? "," ws (group-n 9 lua-name) ws)))))))))))) | ||
| 135 | 150 | ||
| 136 | (defmacro lua-rx (&rest regexps) | 151 | (defmacro lua-rx (&rest regexps) |
| 137 | (eval `(rx-let ,lua--rx-bindings | 152 | (eval `(rx-let ,lua--rx-bindings |
| @@ -185,7 +200,7 @@ element is itself expanded with `lua-rx-to-string'. " | |||
| 185 | (setq form (if (eq 1 (length form)) | 200 | (setq form (if (eq 1 (length form)) |
| 186 | (car form) | 201 | (car form) |
| 187 | (append '(or) form))) | 202 | (append '(or) form))) |
| 188 | (and (fboundp 'rx-form) ; Silence Emacs 27's byte-compiler. | 203 | (and (fboundp 'rx-form) ; Silence Emacs 27's byte-compiler. |
| 189 | (rx-form `(seq symbol-start ,form symbol-end) rx-parent))) | 204 | (rx-form `(seq symbol-start ,form symbol-end) rx-parent))) |
| 190 | 205 | ||
| 191 | (setq lua-rx-constituents (copy-sequence rx-constituents)) | 206 | (setq lua-rx-constituents (copy-sequence rx-constituents)) |
| @@ -208,14 +223,25 @@ element is itself expanded with `lua-rx-to-string'. " | |||
| 208 | (opt (regexp "[eE][+-]?[0-9]+")))) | 223 | (opt (regexp "[eE][+-]?[0-9]+")))) |
| 209 | (lua-assignment-op | 224 | (lua-assignment-op |
| 210 | :rx (seq "=" (or buffer-end (not (any "="))))) | 225 | :rx (seq "=" (or buffer-end (not (any "="))))) |
| 211 | (lua-token | 226 | (lua-operator |
| 212 | :rx (or "+" "-" "*" "/" "%" "^" "#" "==" "~=" "<=" ">=" "<" | 227 | :rx (or "+" "-" "*" "/" "%" "^" "#" "==" "~=" "<=" ">=" "<" |
| 213 | ">" "=" ";" ":" "," "." ".." "...")) | 228 | ">" "=" ";" ":" "," "." ".." "...")) |
| 229 | (lua-keyword-operator | ||
| 230 | :rx (symbol "and" "not" "or")) | ||
| 214 | (lua-keyword | 231 | (lua-keyword |
| 215 | :rx (symbol "and" "break" "do" "else" "elseif" "end" "for" "function" | 232 | :rx (symbol "break" "do" "else" "elseif" "end" "for" "function" |
| 216 | "goto" "if" "in" "local" "not" "or" "repeat" "return" | 233 | "goto" "if" "in" "local" "repeat" "return" |
| 217 | "then" "until" "while"))) | 234 | "then" "until" "while")) |
| 218 | )))) | 235 | (lua-up-to-9-variables |
| 236 | :rx (seq (group-n 1 lua-name) ws | ||
| 237 | (? "," ws (group-n 2 lua-name) ws | ||
| 238 | (? "," ws (group-n 3 lua-name) ws | ||
| 239 | (? "," ws (group-n 4 lua-name) ws | ||
| 240 | (? "," ws (group-n 5 lua-name) ws | ||
| 241 | (? "," ws (group-n 6 lua-name) ws | ||
| 242 | (? "," ws (group-n 7 lua-name) ws | ||
| 243 | (? "," ws (group-n 8 lua-name) ws | ||
| 244 | (? "," ws (group-n 9 lua-name) ws))))))))))))))) | ||
| 219 | 245 | ||
| 220 | 246 | ||
| 221 | ;; Local variables | 247 | ;; Local variables |
| @@ -241,7 +267,11 @@ element is itself expanded with `lua-rx-to-string'. " | |||
| 241 | :group 'lua) | 267 | :group 'lua) |
| 242 | 268 | ||
| 243 | (defcustom lua-default-application "lua" | 269 | (defcustom lua-default-application "lua" |
| 244 | "Default application to run in Lua process." | 270 | "Default application to run in Lua process. |
| 271 | |||
| 272 | Can be a string, where it denotes a command to be executed to | ||
| 273 | start Lua process, or a (HOST . PORT) cons, that can be used to | ||
| 274 | connect to Lua process running remotely." | ||
| 245 | :type '(choice (string) | 275 | :type '(choice (string) |
| 246 | (cons string integer)) | 276 | (cons string integer)) |
| 247 | :group 'lua) | 277 | :group 'lua) |
| @@ -279,7 +309,7 @@ Should be a list of strings." | |||
| 279 | "The active Lua process") | 309 | "The active Lua process") |
| 280 | 310 | ||
| 281 | (defvar lua-process-buffer nil | 311 | (defvar lua-process-buffer nil |
| 282 | "Buffer used for communication with the Lua process") | 312 | "Buffer used for communication with the Lua process.") |
| 283 | 313 | ||
| 284 | (defun lua--customize-set-prefix-key (prefix-key-sym prefix-key-val) | 314 | (defun lua--customize-set-prefix-key (prefix-key-sym prefix-key-val) |
| 285 | (cl-assert (eq prefix-key-sym 'lua-prefix-key)) | 315 | (cl-assert (eq prefix-key-sym 'lua-prefix-key)) |
| @@ -327,13 +357,13 @@ If the latter is nil, the keymap translates into `lua-mode-map' verbatim.") | |||
| 327 | #'lua-electric-match)) | 357 | #'lua-electric-match)) |
| 328 | lua--electric-indent-chars)) | 358 | lua--electric-indent-chars)) |
| 329 | (define-key result-map [menu-bar lua-mode] (cons "Lua" lua-mode-menu)) | 359 | (define-key result-map [menu-bar lua-mode] (cons "Lua" lua-mode-menu)) |
| 360 | (define-key result-map [remap backward-up-list] 'lua-backward-up-list) | ||
| 330 | 361 | ||
| 331 | ;; FIXME: see if the declared logic actually works | ||
| 332 | ;; handle prefix-keyed bindings: | 362 | ;; handle prefix-keyed bindings: |
| 333 | ;; * if no prefix, set prefix-map as parent, i.e. | 363 | ;; * if no prefix, set prefix-map as parent, i.e. |
| 334 | ;; if key is not defined look it up in prefix-map | 364 | ;; if key is not defined look it up in prefix-map |
| 335 | ;; * if prefix is set, bind the prefix-map to that key | 365 | ;; * if prefix is set, bind the prefix-map to that key |
| 336 | (if (boundp 'lua-prefix-key) | 366 | (if lua-prefix-key |
| 337 | (define-key result-map (vector lua-prefix-key) lua-prefix-mode-map) | 367 | (define-key result-map (vector lua-prefix-key) lua-prefix-mode-map) |
| 338 | (set-keymap-parent result-map lua-prefix-mode-map)) | 368 | (set-keymap-parent result-map lua-prefix-mode-map)) |
| 339 | result-map) | 369 | result-map) |
| @@ -372,8 +402,8 @@ If the latter is nil, the keymap translates into `lua-mode-map' verbatim.") | |||
| 372 | ;; NOTE: this doesn't traverse `compilation-search-path' when | 402 | ;; NOTE: this doesn't traverse `compilation-search-path' when |
| 373 | ;; looking for filename. | 403 | ;; looking for filename. |
| 374 | (not (file-exists-p (expand-file-name | 404 | (not (file-exists-p (expand-file-name |
| 375 | filename | 405 | filename |
| 376 | (when directory (expand-file-name directory)))))) | 406 | (when directory (expand-file-name directory)))))) |
| 377 | (setq ad-return-value (current-buffer)) | 407 | (setq ad-return-value (current-buffer)) |
| 378 | ad-do-it)) | 408 | ad-do-it)) |
| 379 | 409 | ||
| @@ -397,7 +427,24 @@ Usually, stdin:XX line number points to nowhere." | |||
| 397 | "If non-nil, contents of multiline string will be indented. | 427 | "If non-nil, contents of multiline string will be indented. |
| 398 | Otherwise leading amount of whitespace on each line is preserved." | 428 | Otherwise leading amount of whitespace on each line is preserved." |
| 399 | :group 'lua | 429 | :group 'lua |
| 400 | :type 'boolean) | 430 | :type 'boolean |
| 431 | :safe #'booleanp) | ||
| 432 | |||
| 433 | (defcustom lua-indent-nested-block-content-align t | ||
| 434 | "If non-nil, the contents of nested blocks are indented to | ||
| 435 | align with the column of the opening parenthesis, rather than | ||
| 436 | just forward by `lua-indent-level'." | ||
| 437 | :group 'lua | ||
| 438 | :type 'boolean | ||
| 439 | :safe #'booleanp) | ||
| 440 | |||
| 441 | (defcustom lua-indent-close-paren-align t | ||
| 442 | "If non-nil, close parenthesis are aligned with their open | ||
| 443 | parenthesis. If nil, close parenthesis are aligned to the | ||
| 444 | beginning of the line." | ||
| 445 | :group 'lua | ||
| 446 | :type 'boolean | ||
| 447 | :safe #'booleanp) | ||
| 401 | 448 | ||
| 402 | (defcustom lua-jump-on-traceback t | 449 | (defcustom lua-jump-on-traceback t |
| 403 | "*Jump to innermost traceback location in *lua* buffer. When this | 450 | "*Jump to innermost traceback location in *lua* buffer. When this |
| @@ -476,118 +523,38 @@ traceback location." | |||
| 476 | "offset"))))) | 523 | "offset"))))) |
| 477 | 524 | ||
| 478 | (cl-labels | 525 | (cl-labels |
| 479 | ((module-name-re (x) | 526 | ((module-name-re (x) |
| 480 | (concat "\\(?1:\\_<" | 527 | (concat "\\(?1:\\_<" |
| 481 | (if (listp x) (car x) x) | 528 | (if (listp x) (car x) x) |
| 482 | "\\_>\\)")) | 529 | "\\_>\\)")) |
| 483 | (module-members-re (x) (if (listp x) | 530 | (module-members-re (x) (if (listp x) |
| 484 | (concat "\\(?:[ \t]*\\.[ \t]*" | 531 | (concat "\\(?:[ \t]*\\.[ \t]*" |
| 485 | "\\_<\\(?2:" | 532 | "\\_<\\(?2:" |
| 486 | (regexp-opt (cdr x)) | 533 | (regexp-opt (cdr x)) |
| 487 | "\\)\\_>\\)?") | 534 | "\\)\\_>\\)?") |
| 488 | ""))) | 535 | ""))) |
| 489 | 536 | ||
| 490 | (concat | 537 | (concat |
| 491 | ;; common prefix: | 538 | ;; common prefix: |
| 492 | ;; - beginning-of-line | 539 | ;; - beginning-of-line |
| 493 | ;; - or neither of [ '.', ':' ] to exclude "foo.string.rep" | 540 | ;; - or neither of [ '.', ':' ] to exclude "foo.string.rep" |
| 494 | ;; - or concatenation operator ".." | 541 | ;; - or concatenation operator ".." |
| 495 | "\\(?:^\\|[^:. \t]\\|[.][.]\\)" | 542 | "\\(?:^\\|[^:. \t]\\|[.][.]\\)" |
| 496 | ;; optional whitespace | 543 | ;; optional whitespace |
| 497 | "[ \t]*" | 544 | "[ \t]*" |
| 498 | "\\(?:" | 545 | "\\(?:" |
| 499 | ;; any of modules/functions | 546 | ;; any of modules/functions |
| 500 | (mapconcat (lambda (x) (concat (module-name-re x) | 547 | (mapconcat (lambda (x) (concat (module-name-re x) |
| 501 | (module-members-re x))) | 548 | (module-members-re x))) |
| 502 | modules | 549 | modules |
| 503 | "\\|") | 550 | "\\|") |
| 504 | "\\)")))) | 551 | "\\)")))) |
| 505 | 552 | ||
| 506 | "A regexp that matches Lua builtin functions & variables. | 553 | "A regexp that matches Lua builtin functions & variables. |
| 507 | 554 | ||
| 508 | This is a compilation of 5.1, 5.2 and 5.3 builtins taken from the | 555 | This is a compilation of 5.1, 5.2 and 5.3 builtins taken from the |
| 509 | index of respective Lua reference manuals.") | 556 | index of respective Lua reference manuals.") |
| 510 | 557 | ||
| 511 | (eval-and-compile | ||
| 512 | (defun lua-make-delimited-matcher (elt-regexp sep-regexp end-regexp) | ||
| 513 | "Construct matcher function for `font-lock-keywords' to match a sequence. | ||
| 514 | |||
| 515 | It's supposed to match sequences with following EBNF: | ||
| 516 | |||
| 517 | ELT-REGEXP { SEP-REGEXP ELT-REGEXP } END-REGEXP | ||
| 518 | |||
| 519 | The sequence is parsed one token at a time. If non-nil is | ||
| 520 | returned, `match-data' will have one or more of the following | ||
| 521 | groups set according to next matched token: | ||
| 522 | |||
| 523 | 1. matched element token | ||
| 524 | 2. unmatched garbage characters | ||
| 525 | 3. misplaced token (i.e. SEP-REGEXP when ELT-REGEXP is expected) | ||
| 526 | 4. matched separator token | ||
| 527 | 5. matched end token | ||
| 528 | |||
| 529 | Blanks & comments between tokens are silently skipped. | ||
| 530 | Groups 6-9 can be used in any of argument regexps." | ||
| 531 | (let* | ||
| 532 | ((delimited-matcher-re-template | ||
| 533 | "\\=\\(?2:.*?\\)\\(?:\\(?%s:\\(?4:%s\\)\\|\\(?5:%s\\)\\)\\|\\(?%s:\\(?1:%s\\)\\)\\)") | ||
| 534 | ;; There's some magic to this regexp. It works as follows: | ||
| 535 | ;; | ||
| 536 | ;; A. start at (point) | ||
| 537 | ;; B. non-greedy match of garbage-characters (?2:) | ||
| 538 | ;; C. try matching separator (?4:) or end-token (?5:) | ||
| 539 | ;; D. try matching element (?1:) | ||
| 540 | ;; | ||
| 541 | ;; Simple, but there's a trick: pt.C and pt.D are embraced by one more | ||
| 542 | ;; group whose purpose is determined only after the template is | ||
| 543 | ;; formatted (?%s:): | ||
| 544 | ;; | ||
| 545 | ;; - if element is expected, then D's parent group becomes "shy" and C's | ||
| 546 | ;; parent becomes group 3 (aka misplaced token), so if D matches when | ||
| 547 | ;; an element is expected, it'll be marked with warning face. | ||
| 548 | ;; | ||
| 549 | ;; - if separator-or-end-token is expected, then it's the opposite: | ||
| 550 | ;; C's parent becomes shy and D's will be matched as misplaced token. | ||
| 551 | (elt-expected-re (format delimited-matcher-re-template | ||
| 552 | 3 sep-regexp end-regexp "" elt-regexp)) | ||
| 553 | (sep-or-end-expected-re (format delimited-matcher-re-template | ||
| 554 | "" sep-regexp end-regexp 3 elt-regexp))) | ||
| 555 | |||
| 556 | (lambda (end) | ||
| 557 | (let* ((prev-elt-p (match-beginning 1)) | ||
| 558 | (prev-end-p (match-beginning 5)) | ||
| 559 | |||
| 560 | (regexp (if prev-elt-p sep-or-end-expected-re elt-expected-re)) | ||
| 561 | (comment-start (lua-comment-start-pos (syntax-ppss))) | ||
| 562 | (parse-stop end)) | ||
| 563 | |||
| 564 | ;; If token starts inside comment, or end-token was encountered, stop. | ||
| 565 | (when (and (not comment-start) | ||
| 566 | (not prev-end-p)) | ||
| 567 | ;; Skip all comments & whitespace. forward-comment doesn't have boundary | ||
| 568 | ;; argument, so make sure point isn't beyond parse-stop afterwards. | ||
| 569 | (while (and (< (point) end) | ||
| 570 | (forward-comment 1))) | ||
| 571 | (goto-char (min (point) parse-stop)) | ||
| 572 | |||
| 573 | ;; Reuse comment-start variable to store beginning of comment that is | ||
| 574 | ;; placed before line-end-position so as to make sure token search doesn't | ||
| 575 | ;; enter that comment. | ||
| 576 | (setq comment-start | ||
| 577 | (lua-comment-start-pos | ||
| 578 | (save-excursion | ||
| 579 | (parse-partial-sexp (point) parse-stop | ||
| 580 | nil nil nil 'stop-inside-comment))) | ||
| 581 | parse-stop (or comment-start parse-stop)) | ||
| 582 | |||
| 583 | ;; Now, let's match stuff. If regular matcher fails, declare a span of | ||
| 584 | ;; non-blanks 'garbage', and the next iteration will start from where the | ||
| 585 | ;; garbage ends. If couldn't match any garbage, move point to the end | ||
| 586 | ;; and return nil. | ||
| 587 | (or (re-search-forward regexp parse-stop t) | ||
| 588 | (re-search-forward "\\(?1:\\(?2:[^ \t]+\\)\\)" parse-stop 'skip) | ||
| 589 | (prog1 nil (goto-char end))))))))) | ||
| 590 | |||
| 591 | 558 | ||
| 592 | (defvar lua-font-lock-keywords | 559 | (defvar lua-font-lock-keywords |
| 593 | `(;; highlight the hash-bang line "#!/foo/bar/lua" as comment | 560 | `(;; highlight the hash-bang line "#!/foo/bar/lua" as comment |
| @@ -598,59 +565,67 @@ Groups 6-9 can be used in any of argument regexps." | |||
| 598 | . font-lock-constant-face) | 565 | . font-lock-constant-face) |
| 599 | 566 | ||
| 600 | ;; Keywords | 567 | ;; Keywords |
| 601 | (,(lua-rx lua-keyword) | 568 | (,(lua-rx (or lua-keyword lua-keyword-operator)) |
| 602 | . font-lock-keyword-face) | 569 | . font-lock-keyword-face) |
| 603 | 570 | ||
| 604 | ;; Labels used by the "goto" statement | 571 | ;; Labels used by the "goto" statement |
| 605 | ;; Highlights the following syntax: ::label:: | 572 | ;; Highlights the following syntax: ::label:: |
| 606 | (,(lua-rx "::" ws lua-name ws "::") | 573 | (,(lua-rx "::" ws lua-name ws "::") |
| 607 | . font-lock-constant-face) | 574 | . font-lock-constant-face) |
| 608 | 575 | ||
| 609 | ;; Highlights the name of the label in the "goto" statement like | 576 | ;; Highlights the name of the label in the "goto" statement like |
| 610 | ;; "goto label" | 577 | ;; "goto label" |
| 611 | (,(lua-rx (symbol (seq "goto" ws+ (group-n 1 lua-name)))) | 578 | (,(lua-rx (symbol (seq "goto" ws+ (group-n 1 lua-name)))) |
| 612 | (1 font-lock-constant-face)) | 579 | (1 font-lock-constant-face)) |
| 613 | 580 | ||
| 614 | ;; Highlight Lua builtin functions and variables | 581 | ;; Highlight Lua builtin functions and variables |
| 615 | (,lua--builtins | 582 | (,lua--builtins |
| 616 | (1 font-lock-builtin-face) (2 font-lock-builtin-face nil noerror)) | 583 | (1 font-lock-builtin-face) (2 font-lock-builtin-face nil noerror)) |
| 617 | 584 | ||
| 618 | ("^[ \t]*\\_<for\\_>" | 585 | (,(lua-rx (symbol "for") ws+ lua-up-to-9-variables) |
| 619 | (,(lua-make-delimited-matcher (lua-rx lua-name) "," | 586 | (1 font-lock-variable-name-face) |
| 620 | (lua-rx (or (symbol "in") lua-assignment-op))) | 587 | (2 font-lock-variable-name-face nil noerror) |
| 621 | nil nil | 588 | (3 font-lock-variable-name-face nil noerror) |
| 622 | (1 font-lock-variable-name-face nil noerror) | 589 | (4 font-lock-variable-name-face nil noerror) |
| 623 | (2 font-lock-warning-face t noerror) | 590 | (5 font-lock-variable-name-face nil noerror) |
| 624 | (3 font-lock-warning-face t noerror))) | 591 | (6 font-lock-variable-name-face nil noerror) |
| 625 | 592 | (7 font-lock-variable-name-face nil noerror) | |
| 626 | ;; Handle local variable/function names | 593 | (8 font-lock-variable-name-face nil noerror) |
| 627 | ;; local blalba, xyzzy = | 594 | (9 font-lock-variable-name-face nil noerror)) |
| 628 | ;; ^^^^^^ ^^^^^ | ||
| 629 | ;; | ||
| 630 | ;; local function foobar(x,y,z) | ||
| 631 | ;; ^^^^^^ | ||
| 632 | ;; local foobar = function(x,y,z) | ||
| 633 | ;; ^^^^^^ | ||
| 634 | ("^[ \t]*\\_<local\\_>" | ||
| 635 | (0 font-lock-keyword-face) | ||
| 636 | |||
| 637 | ;; (* nonl) at the end is to consume trailing characters or otherwise they | ||
| 638 | ;; delimited matcher would attempt to parse them afterwards and wrongly | ||
| 639 | ;; highlight parentheses as incorrect variable name characters. | ||
| 640 | (,(lua-rx point ws lua-funcheader (* nonl)) | ||
| 641 | nil nil | ||
| 642 | (1 font-lock-function-name-face nil noerror)) | ||
| 643 | 595 | ||
| 644 | (,(lua-make-delimited-matcher (lua-rx lua-name) "," | 596 | (,(lua-rx (symbol "function") (? ws+ lua-funcname) ws "(" ws lua-up-to-9-variables) |
| 645 | (lua-rx lua-assignment-op)) | 597 | (1 font-lock-variable-name-face) |
| 646 | nil nil | 598 | (2 font-lock-variable-name-face nil noerror) |
| 647 | (1 font-lock-variable-name-face nil noerror) | 599 | (3 font-lock-variable-name-face nil noerror) |
| 648 | (2 font-lock-warning-face t noerror) | 600 | (4 font-lock-variable-name-face nil noerror) |
| 649 | (3 font-lock-warning-face t noerror))) | 601 | (5 font-lock-variable-name-face nil noerror) |
| 602 | (6 font-lock-variable-name-face nil noerror) | ||
| 603 | (7 font-lock-variable-name-face nil noerror) | ||
| 604 | (8 font-lock-variable-name-face nil noerror) | ||
| 605 | (9 font-lock-variable-name-face nil noerror)) | ||
| 650 | 606 | ||
| 651 | (,(lua-rx (or bol ";") ws lua-funcheader) | 607 | (,(lua-rx lua-funcheader) |
| 652 | (1 font-lock-function-name-face)) | 608 | (1 font-lock-function-name-face)) |
| 653 | 609 | ||
| 610 | ;; local x, y, z | ||
| 611 | ;; local x = ..... | ||
| 612 | ;; | ||
| 613 | ;; NOTE: this is intentionally below funcheader matcher, so that in | ||
| 614 | ;; | ||
| 615 | ;; local foo = function() ... | ||
| 616 | ;; | ||
| 617 | ;; "foo" is fontified as function-name-face, and variable-name-face is not applied. | ||
| 618 | (,(lua-rx (symbol "local") ws+ lua-up-to-9-variables) | ||
| 619 | (1 font-lock-variable-name-face) | ||
| 620 | (2 font-lock-variable-name-face nil noerror) | ||
| 621 | (3 font-lock-variable-name-face nil noerror) | ||
| 622 | (4 font-lock-variable-name-face nil noerror) | ||
| 623 | (5 font-lock-variable-name-face nil noerror) | ||
| 624 | (6 font-lock-variable-name-face nil noerror) | ||
| 625 | (7 font-lock-variable-name-face nil noerror) | ||
| 626 | (8 font-lock-variable-name-face nil noerror) | ||
| 627 | (9 font-lock-variable-name-face nil noerror)) | ||
| 628 | |||
| 654 | (,(lua-rx (or (group-n 1 | 629 | (,(lua-rx (or (group-n 1 |
| 655 | "@" (symbol "author" "copyright" "field" "release" | 630 | "@" (symbol "author" "copyright" "field" "release" |
| 656 | "return" "see" "usage" "description")) | 631 | "return" "see" "usage" "description")) |
| @@ -662,13 +637,14 @@ Groups 6-9 can be used in any of argument regexps." | |||
| 662 | "Default expressions to highlight in Lua mode.") | 637 | "Default expressions to highlight in Lua mode.") |
| 663 | 638 | ||
| 664 | (defvar lua-imenu-generic-expression | 639 | (defvar lua-imenu-generic-expression |
| 665 | `((nil ,(lua-rx (or bol ";") ws (opt (seq (symbol "local") ws)) lua-funcheader) 1)) | 640 | `(("Requires" ,(lua-rx (or bol ";") ws (opt (seq (symbol "local") ws)) (group-n 1 lua-name) ws "=" ws (symbol "require")) 1) |
| 641 | (nil ,(lua-rx (or bol ";") ws (opt (seq (symbol "local") ws)) lua-funcheader) 1)) | ||
| 666 | "Imenu generic expression for lua-mode. See `imenu-generic-expression'.") | 642 | "Imenu generic expression for lua-mode. See `imenu-generic-expression'.") |
| 667 | 643 | ||
| 668 | (defvar lua-sexp-alist '(("then" . "end") | 644 | (defvar lua-sexp-alist '(("then" . "end") |
| 669 | ("function" . "end") | 645 | ("function" . "end") |
| 670 | ("do" . "end") | 646 | ("do" . "end") |
| 671 | ("repeat" . "until"))) | 647 | ("repeat" . "until"))) |
| 672 | 648 | ||
| 673 | (defvar lua-mode-abbrev-table nil | 649 | (defvar lua-mode-abbrev-table nil |
| 674 | "Abbreviation table used in lua-mode buffers.") | 650 | "Abbreviation table used in lua-mode buffers.") |
| @@ -709,11 +685,11 @@ Groups 6-9 can be used in any of argument regexps." | |||
| 709 | :syntax-table lua-mode-syntax-table | 685 | :syntax-table lua-mode-syntax-table |
| 710 | :group 'lua | 686 | :group 'lua |
| 711 | (setq-local font-lock-defaults '(lua-font-lock-keywords ;; keywords | 687 | (setq-local font-lock-defaults '(lua-font-lock-keywords ;; keywords |
| 712 | nil ;; keywords-only | 688 | nil ;; keywords-only |
| 713 | nil ;; case-fold | 689 | nil ;; case-fold |
| 714 | nil ;; syntax-alist | 690 | nil ;; syntax-alist |
| 715 | nil ;; syntax-begin | 691 | nil ;; syntax-begin |
| 716 | )) | 692 | )) |
| 717 | 693 | ||
| 718 | (setq-local syntax-propertize-function | 694 | (setq-local syntax-propertize-function |
| 719 | 'lua--propertize-multiline-bounds) | 695 | 'lua--propertize-multiline-bounds) |
| @@ -733,7 +709,7 @@ Groups 6-9 can be used in any of argument regexps." | |||
| 733 | ;; If electric-indent-chars is not defined, electric indentation is done | 709 | ;; If electric-indent-chars is not defined, electric indentation is done |
| 734 | ;; via `lua-mode-map'. | 710 | ;; via `lua-mode-map'. |
| 735 | (setq-local electric-indent-chars | 711 | (setq-local electric-indent-chars |
| 736 | (append electric-indent-chars lua--electric-indent-chars))) | 712 | (append electric-indent-chars lua--electric-indent-chars))) |
| 737 | 713 | ||
| 738 | 714 | ||
| 739 | ;; setup menu bar entry (XEmacs style) | 715 | ;; setup menu bar entry (XEmacs style) |
| @@ -770,7 +746,7 @@ Groups 6-9 can be used in any of argument regexps." | |||
| 770 | "Insert character and adjust indentation." | 746 | "Insert character and adjust indentation." |
| 771 | (interactive "P") | 747 | (interactive "P") |
| 772 | (let (blink-paren-function) | 748 | (let (blink-paren-function) |
| 773 | (self-insert-command (prefix-numeric-value arg))) | 749 | (self-insert-command (prefix-numeric-value arg))) |
| 774 | (if lua-electric-flag | 750 | (if lua-electric-flag |
| 775 | (lua-indent-line)) | 751 | (lua-indent-line)) |
| 776 | (blink-matching-open)) | 752 | (blink-matching-open)) |
| @@ -826,22 +802,41 @@ This function replaces previous prefix-key binding with a new one." | |||
| 826 | "Returns true if the point is in a string." | 802 | "Returns true if the point is in a string." |
| 827 | (save-excursion (elt (syntax-ppss pos) 3))) | 803 | (save-excursion (elt (syntax-ppss pos) 3))) |
| 828 | 804 | ||
| 829 | (defun lua-comment-start-pos (parsing-state) | 805 | (defun lua--containing-double-hyphen-start-pos () |
| 806 | "Return position of the beginning comment delimiter (--). | ||
| 807 | |||
| 808 | Emacs syntax framework does not consider comment delimiters as | ||
| 809 | part of the comment itself, but for this package it is useful to | ||
| 810 | consider point as inside comment when it is between the two hyphens" | ||
| 811 | (and (eql (char-before) ?-) | ||
| 812 | (eql (char-after) ?-) | ||
| 813 | (1- (point)))) | ||
| 814 | |||
| 815 | (defun lua-comment-start-pos (&optional parsing-state) | ||
| 830 | "Return position of comment containing current point. | 816 | "Return position of comment containing current point. |
| 831 | 817 | ||
| 832 | If point is not inside a comment, return nil." | 818 | If point is not inside a comment, return nil." |
| 833 | (and parsing-state (nth 4 parsing-state) (nth 8 parsing-state))) | 819 | (unless parsing-state (setq parsing-state (syntax-ppss))) |
| 820 | (and | ||
| 821 | ;; Not a string | ||
| 822 | (not (nth 3 parsing-state)) | ||
| 823 | ;; Syntax-based comment | ||
| 824 | (or (and (nth 4 parsing-state) (nth 8 parsing-state)) | ||
| 825 | (lua--containing-double-hyphen-start-pos)))) | ||
| 834 | 826 | ||
| 835 | (defun lua-comment-or-string-p (&optional pos) | 827 | (defun lua-comment-or-string-p (&optional pos) |
| 836 | "Returns true if the point is in a comment or string." | 828 | "Returns true if the point is in a comment or string." |
| 837 | (save-excursion (let ((parse-result (syntax-ppss pos))) | 829 | (save-excursion (let ((parse-result (syntax-ppss pos))) |
| 838 | (or (elt parse-result 3) (elt parse-result 4))))) | 830 | (or (elt parse-result 3) (lua-comment-start-pos parse-result))))) |
| 839 | 831 | ||
| 840 | (defun lua-comment-or-string-start-pos (&optional pos) | 832 | (defun lua-comment-or-string-start-pos (&optional pos) |
| 841 | "Returns start position of string or comment which contains point. | 833 | "Returns start position of string or comment which contains point. |
| 842 | 834 | ||
| 843 | If point is not inside string or comment, return nil." | 835 | If point is not inside string or comment, return nil." |
| 844 | (save-excursion (elt (syntax-ppss pos) 8))) | 836 | (save-excursion |
| 837 | (when pos (goto-char pos)) | ||
| 838 | (or (elt (syntax-ppss pos) 8) | ||
| 839 | (lua--containing-double-hyphen-start-pos)))) | ||
| 845 | 840 | ||
| 846 | ;; They're propertized as follows: | 841 | ;; They're propertized as follows: |
| 847 | ;; 1. generic-comment | 842 | ;; 1. generic-comment |
| @@ -885,23 +880,15 @@ If none can be found before reaching LIMIT, return nil." | |||
| 885 | ;; inside strings or comments ending either at EOL or at valid token. | 880 | ;; inside strings or comments ending either at EOL or at valid token. |
| 886 | (and (setq last-search-matched | 881 | (and (setq last-search-matched |
| 887 | (re-search-forward lua-ml-begin-regexp limit 'noerror)) | 882 | (re-search-forward lua-ml-begin-regexp limit 'noerror)) |
| 888 | 883 | ;; Ensure --[[ is not inside a comment or string. | |
| 889 | ;; Handle triple-hyphen '---[[' situation in which the multiline | ||
| 890 | ;; opener should be skipped. | ||
| 891 | ;; | 884 | ;; |
| 892 | ;; In HYPHEN1-HYPHEN2-BRACKET1-BRACKET2 situation (match-beginning | 885 | ;; This includes "---[[" sequence, in which "--" at the beginning |
| 893 | ;; 0) points to HYPHEN1, but if there's another hyphen before | 886 | ;; creates a single-line comment, and thus "-[[" is no longer a |
| 894 | ;; HYPHEN1, standard syntax table will only detect comment-start | 887 | ;; multi-line opener. |
| 895 | ;; at HYPHEN2. | ||
| 896 | ;; | 888 | ;; |
| 897 | ;; We could check for comment-start at HYPHEN2, but then we'd have | 889 | ;; XXX: need to ensure syntax-ppss beyond (match-beginning 0) is |
| 898 | ;; to flush syntax-ppss cache to remove the result saying that at | 890 | ;; not calculated, or otherwise we'll need to flush the cache. |
| 899 | ;; HYPHEN2 there's no comment or string, because under some | 891 | (lua-comment-or-string-start-pos (match-beginning 0)))) |
| 900 | ;; circumstances that would hide the fact that we put a | ||
| 901 | ;; comment-start property at HYPHEN1. | ||
| 902 | (or (lua-comment-or-string-start-pos (match-beginning 0)) | ||
| 903 | (and (eq ?- (char-after (match-beginning 0))) | ||
| 904 | (eq ?- (char-before (match-beginning 0))))))) | ||
| 905 | 892 | ||
| 906 | last-search-matched)) | 893 | last-search-matched)) |
| 907 | 894 | ||
| @@ -968,23 +955,70 @@ Return the amount the indentation changed by." | |||
| 968 | 0 | 955 | 0 |
| 969 | lua-indent-level)))))) | 956 | lua-indent-level)))))) |
| 970 | 957 | ||
| 971 | (defun lua-find-regexp (direction regexp &optional limit ignore-p) | 958 | |
| 959 | (defun lua--signum (x) | ||
| 960 | "Return 1 if X is positive, -1 if negative, 0 if zero." | ||
| 961 | ;; XXX: backport from cl-extras for Emacs24 | ||
| 962 | (cond ((> x 0) 1) ((< x 0) -1) (t 0))) | ||
| 963 | |||
| 964 | (defun lua--ensure-point-within-limit (limit backward) | ||
| 965 | "Return non-nil if point is within LIMIT going forward. | ||
| 966 | |||
| 967 | With BACKWARD non-nil, return non-nil if point is within LIMIT | ||
| 968 | going backward. | ||
| 969 | |||
| 970 | If point is beyond limit, move it onto limit." | ||
| 971 | (if (= (lua--signum (- (point) limit)) | ||
| 972 | (if backward 1 -1)) | ||
| 973 | t | ||
| 974 | (goto-char limit) | ||
| 975 | nil)) | ||
| 976 | |||
| 977 | |||
| 978 | (defun lua--escape-from-string (&optional backward) | ||
| 979 | "Move point outside of string if it is inside one. | ||
| 980 | |||
| 981 | By default, point is placed after the string, with BACKWARD it is | ||
| 982 | placed before the string." | ||
| 983 | (interactive) | ||
| 984 | (let ((parse-state (syntax-ppss))) | ||
| 985 | (when (nth 3 parse-state) | ||
| 986 | (if backward | ||
| 987 | (goto-char (nth 8 parse-state)) | ||
| 988 | (parse-partial-sexp (point) (line-end-position) nil nil (syntax-ppss) 'syntax-table)) | ||
| 989 | t))) | ||
| 990 | |||
| 991 | |||
| 992 | (defun lua-find-regexp (direction regexp &optional limit) | ||
| 972 | "Searches for a regular expression in the direction specified. | 993 | "Searches for a regular expression in the direction specified. |
| 994 | |||
| 973 | Direction is one of 'forward and 'backward. | 995 | Direction is one of 'forward and 'backward. |
| 974 | By default, matches in comments and strings are ignored, but what to ignore is | 996 | |
| 975 | configurable by specifying ignore-p. If the regexp is found, returns point | 997 | Matches in comments and strings are ignored. If the regexp is |
| 976 | position, nil otherwise. | 998 | found, returns point position, nil otherwise." |
| 977 | ignore-p returns true if the match at the current point position should be | 999 | (let ((search-func (if (eq direction 'forward) |
| 978 | ignored, nil otherwise." | ||
| 979 | (let ((ignore-func (or ignore-p 'lua-comment-or-string-p)) | ||
| 980 | (search-func (if (eq direction 'forward) | ||
| 981 | 're-search-forward 're-search-backward)) | 1000 | 're-search-forward 're-search-backward)) |
| 982 | (case-fold-search nil)) | 1001 | (case-fold-search nil)) |
| 983 | (catch 'found | 1002 | (cl-loop |
| 984 | (while (funcall search-func regexp limit t) | 1003 | always (or (null limit) |
| 985 | (if (and (not (funcall ignore-func (match-beginning 0))) | 1004 | (lua--ensure-point-within-limit limit (not (eq direction 'forward)))) |
| 986 | (not (funcall ignore-func (match-end 0)))) | 1005 | always (funcall search-func regexp limit 'noerror) |
| 987 | (throw 'found (point))))))) | 1006 | for match-beg = (match-beginning 0) |
| 1007 | for match-end = (match-end 0) | ||
| 1008 | while (or (lua-comment-or-string-p match-beg) | ||
| 1009 | (lua-comment-or-string-p match-end)) | ||
| 1010 | do (let ((parse-state (syntax-ppss))) | ||
| 1011 | (cond | ||
| 1012 | ;; Inside a string | ||
| 1013 | ((nth 3 parse-state) | ||
| 1014 | (lua--escape-from-string (not (eq direction 'forward)))) | ||
| 1015 | ;; Inside a comment | ||
| 1016 | ((nth 4 parse-state) | ||
| 1017 | (goto-char (nth 8 parse-state)) | ||
| 1018 | (when (eq direction 'forward) | ||
| 1019 | (forward-comment 1))))) | ||
| 1020 | finally return (point)))) | ||
| 1021 | |||
| 988 | 1022 | ||
| 989 | (defconst lua-block-regexp | 1023 | (defconst lua-block-regexp |
| 990 | (eval-when-compile | 1024 | (eval-when-compile |
| @@ -1050,7 +1084,7 @@ TOKEN-TYPE determines where the token occurs on a statement. open indicates that | |||
| 1050 | 1084 | ||
| 1051 | (defun lua-get-token-type (token-info) | 1085 | (defun lua-get-token-type (token-info) |
| 1052 | "Returns the relevant match regexp from token info" | 1086 | "Returns the relevant match regexp from token info" |
| 1053 | (nth 3 token-info)) | 1087 | (nth 3 token-info)) |
| 1054 | 1088 | ||
| 1055 | (defun lua-backwards-to-block-begin-or-end () | 1089 | (defun lua-backwards-to-block-begin-or-end () |
| 1056 | "Move backwards to nearest block begin or end. Returns nil if not successful." | 1090 | "Move backwards to nearest block begin or end. Returns nil if not successful." |
| @@ -1159,29 +1193,74 @@ If optional NOREPORT is non-nil, it won't flag an error if there | |||
| 1159 | is no block open/close open." | 1193 | is no block open/close open." |
| 1160 | (interactive) | 1194 | (interactive) |
| 1161 | ;; search backward to the beginning of the keyword if necessary | 1195 | ;; search backward to the beginning of the keyword if necessary |
| 1162 | (if (eq (char-syntax (following-char)) ?w) | 1196 | (when (and (eq (char-syntax (following-char)) ?w) |
| 1163 | (re-search-backward "\\_<" nil t)) | 1197 | (not (looking-at "\\_<"))) |
| 1198 | (re-search-backward "\\_<" nil t)) | ||
| 1164 | (let ((position (lua-goto-matching-block-token))) | 1199 | (let ((position (lua-goto-matching-block-token))) |
| 1165 | (if (and (not position) | 1200 | (if (and (not position) |
| 1166 | (not noreport)) | 1201 | (not noreport)) |
| 1167 | (error "Not on a block control keyword or brace") | 1202 | (error "Not on a block control keyword or brace") |
| 1168 | position))) | 1203 | position))) |
| 1169 | 1204 | ||
| 1205 | (defun lua-skip-ws-and-comments-backward (&optional limit) | ||
| 1206 | "Move point back skipping all whitespace and comments. | ||
| 1207 | |||
| 1208 | If LIMIT is given, stop at it or before. | ||
| 1209 | |||
| 1210 | Return non-nil if moved point." | ||
| 1211 | (interactive) | ||
| 1212 | (unless (lua-string-p) | ||
| 1213 | (let ((start-pos (point)) | ||
| 1214 | (comment-start-pos (lua-comment-start-pos))) | ||
| 1215 | (setq limit (min (point) (or limit (point-min)))) | ||
| 1216 | (when comment-start-pos | ||
| 1217 | (goto-char (max limit comment-start-pos))) | ||
| 1218 | (when (< limit (point)) (forward-comment (- limit (point)))) | ||
| 1219 | (when (< (point) limit) (goto-char limit)) | ||
| 1220 | (when (/= start-pos (point)) | ||
| 1221 | (point))))) | ||
| 1222 | |||
| 1223 | (defun lua-skip-ws-and-comments-forward (&optional limit) | ||
| 1224 | "Move point forward skipping all whitespace and comments. | ||
| 1225 | |||
| 1226 | If LIMIT is given, stop at it or before. | ||
| 1227 | |||
| 1228 | Return non-nil if moved point." | ||
| 1229 | (interactive) | ||
| 1230 | (unless (lua-string-p) | ||
| 1231 | (let ((start-pos (point)) | ||
| 1232 | (comment-start-pos (lua-comment-start-pos))) | ||
| 1233 | (setq limit (max (point) (or limit (point-max)))) | ||
| 1234 | ;; Escape from current comment. It is necessary to use "while" because | ||
| 1235 | ;; luadoc parameters have non-comment face, and parse-partial-sexp with | ||
| 1236 | ;; 'syntax-table flag will stop on them. | ||
| 1237 | (when comment-start-pos | ||
| 1238 | (goto-char comment-start-pos) | ||
| 1239 | (forward-comment 1)) | ||
| 1240 | (when (< (point) limit) (forward-comment (- limit (point)))) | ||
| 1241 | (when (< limit (point)) (goto-char limit)) | ||
| 1242 | (when (/= start-pos (point)) | ||
| 1243 | (point))))) | ||
| 1244 | |||
| 1245 | |||
| 1170 | (defun lua-forward-line-skip-blanks (&optional back) | 1246 | (defun lua-forward-line-skip-blanks (&optional back) |
| 1171 | "Move 1 line forward (back if BACK is non-nil) skipping blank lines. | 1247 | "Move 1 line forward/backward and skip all insignificant ws/comment lines. |
| 1172 | 1248 | ||
| 1173 | Moves point 1 line forward (or backward) skipping lines that contain | 1249 | Moves point 1 line forward (or backward) skipping lines that contain |
| 1174 | no Lua code besides comments. The point is put to the beginning of | 1250 | no Lua code besides comments. The point is put to the beginning of |
| 1175 | the line. | 1251 | the line. |
| 1176 | 1252 | ||
| 1177 | Returns final value of point as integer or nil if operation failed." | 1253 | Returns final value of point as integer or nil if operation failed." |
| 1178 | (catch 'found | 1254 | (let ((start-pos (point))) |
| 1179 | (while t | 1255 | (if back |
| 1180 | (unless (eql (forward-line (if back -1 1)) 0) ;; 0 means success | 1256 | (progn |
| 1181 | (throw 'found nil)) | 1257 | (beginning-of-line) |
| 1182 | (unless (or (looking-at "\\s *\\(--.*\\)?$") | 1258 | (lua-skip-ws-and-comments-backward)) |
| 1183 | (lua-comment-or-string-p)) | 1259 | (forward-line) |
| 1184 | (throw 'found (point)))))) | 1260 | (lua-skip-ws-and-comments-forward)) |
| 1261 | (beginning-of-line) | ||
| 1262 | (when (> (count-lines start-pos (point)) 0) | ||
| 1263 | (point)))) | ||
| 1185 | 1264 | ||
| 1186 | (eval-when-compile | 1265 | (eval-when-compile |
| 1187 | (defconst lua-operator-class | 1266 | (defconst lua-operator-class |
| @@ -1190,17 +1269,17 @@ Returns final value of point as integer or nil if operation failed." | |||
| 1190 | (defconst lua-cont-eol-regexp | 1269 | (defconst lua-cont-eol-regexp |
| 1191 | (eval-when-compile | 1270 | (eval-when-compile |
| 1192 | (concat | 1271 | (concat |
| 1193 | "\\(\\_<" | 1272 | "\\(?:\\(?1:\\_<" |
| 1194 | (regexp-opt '("and" "or" "not" "in" "for" "while" | 1273 | (regexp-opt '("and" "or" "not" "in" "for" "while" |
| 1195 | "local" "function" "if" "until" "elseif" "return") | 1274 | "local" "function" "if" "until" "elseif" "return") |
| 1196 | t) | 1275 | t) |
| 1197 | "\\_>\\|" | 1276 | "\\_>\\)\\|" |
| 1198 | "\\(^\\|[^" lua-operator-class "]\\)" | 1277 | "\\(?:^\\|[^" lua-operator-class "]\\)\\(?2:" |
| 1199 | (regexp-opt '("+" "-" "*" "/" "%" "^" ".." "==" | 1278 | (regexp-opt '("+" "-" "*" "/" "%" "^" ".." "==" |
| 1200 | "=" "<" ">" "<=" ">=" "~=" "." ":" | 1279 | "=" "<" ">" "<=" ">=" "~=" "." ":" |
| 1201 | "&" "|" "~" ">>" "<<" "~") | 1280 | "&" "|" "~" ">>" "<<" "~" ",") |
| 1202 | t) | 1281 | t) |
| 1203 | "\\)" | 1282 | "\\)\\)" |
| 1204 | "\\s *\\=")) | 1283 | "\\s *\\=")) |
| 1205 | "Regexp that matches the ending of a line that needs continuation. | 1284 | "Regexp that matches the ending of a line that needs continuation. |
| 1206 | 1285 | ||
| @@ -1212,14 +1291,14 @@ an optional whitespace till the end of the line.") | |||
| 1212 | (eval-when-compile | 1291 | (eval-when-compile |
| 1213 | (concat | 1292 | (concat |
| 1214 | "\\=\\s *" | 1293 | "\\=\\s *" |
| 1215 | "\\(\\_<" | 1294 | "\\(?:\\(?1:\\_<" |
| 1216 | (regexp-opt '("and" "or" "not") t) | 1295 | (regexp-opt '("and" "or" "not" "in") t) |
| 1217 | "\\_>\\|" | 1296 | "\\_>\\)\\|\\(?2:" |
| 1218 | (regexp-opt '("+" "-" "*" "/" "%" "^" ".." "==" | 1297 | (regexp-opt '("," "+" "-" "*" "/" "%" "^" ".." "==" |
| 1219 | "=" "<" ">" "<=" ">=" "~=" "." ":" | 1298 | "=" "<" ">" "<=" ">=" "~=" "." ":" |
| 1220 | "&" "|" "~" ">>" "<<" "~") | 1299 | "&" "|" "~" ">>" "<<" "~") |
| 1221 | t) | 1300 | t) |
| 1222 | "\\($\\|[^" lua-operator-class "]\\)" | 1301 | "\\)\\(?:$\\|[^" lua-operator-class "]\\)" |
| 1223 | "\\)")) | 1302 | "\\)")) |
| 1224 | "Regexp that matches a line that continues previous one. | 1303 | "Regexp that matches a line that continues previous one. |
| 1225 | 1304 | ||
| @@ -1231,44 +1310,101 @@ previous one even though it looked like an end-of-statement.") | |||
| 1231 | (defun lua-last-token-continues-p () | 1310 | (defun lua-last-token-continues-p () |
| 1232 | "Return non-nil if the last token on this line is a continuation token." | 1311 | "Return non-nil if the last token on this line is a continuation token." |
| 1233 | (let ((line-begin (line-beginning-position)) | 1312 | (let ((line-begin (line-beginning-position)) |
| 1234 | (line-end (line-end-position))) | 1313 | return-value) |
| 1235 | (save-excursion | 1314 | (save-excursion |
| 1236 | (end-of-line) | 1315 | (end-of-line) |
| 1237 | ;; we need to check whether the line ends in a comment and | 1316 | (lua-skip-ws-and-comments-backward line-begin) |
| 1238 | ;; skip that one. | 1317 | (setq return-value (and (re-search-backward lua-cont-eol-regexp line-begin t) |
| 1239 | (while (lua-find-regexp 'backward "-" line-begin 'lua-string-p) | 1318 | (or (match-beginning 1) |
| 1240 | (if (looking-at "--") | 1319 | (match-beginning 2)))) |
| 1241 | (setq line-end (point)))) | 1320 | (if (and return-value |
| 1242 | (goto-char line-end) | 1321 | (string-equal (match-string-no-properties 0) "return")) |
| 1243 | (re-search-backward lua-cont-eol-regexp line-begin t)))) | 1322 | ;; "return" keyword is ambiguous and depends on next token |
| 1323 | (unless (save-excursion | ||
| 1324 | (goto-char (match-end 0)) | ||
| 1325 | (forward-comment (point-max)) | ||
| 1326 | (and | ||
| 1327 | ;; Not continuing: at end of file | ||
| 1328 | (not (eobp)) | ||
| 1329 | (or | ||
| 1330 | ;; "function" keyword: it is a continuation, e.g. | ||
| 1331 | ;; | ||
| 1332 | ;; return | ||
| 1333 | ;; function() return 123 end | ||
| 1334 | ;; | ||
| 1335 | (looking-at (lua-rx (symbol "function"))) | ||
| 1336 | ;; Looking at semicolon or any other keyword: not continuation | ||
| 1337 | (not (looking-at (lua-rx (or ";" lua-keyword))))))) | ||
| 1338 | (setq return-value nil))) | ||
| 1339 | return-value))) | ||
| 1340 | |||
| 1244 | 1341 | ||
| 1245 | (defun lua-first-token-continues-p () | 1342 | (defun lua-first-token-continues-p () |
| 1246 | "Return non-nil if the first token on this line is a continuation token." | 1343 | "Return non-nil if the first token on this line is a continuation token." |
| 1247 | (let ((line-end (line-end-position))) | 1344 | (let ((line-end (line-end-position))) |
| 1248 | (save-excursion | 1345 | (save-excursion |
| 1249 | (beginning-of-line) | 1346 | (beginning-of-line) |
| 1347 | (lua-skip-ws-and-comments-forward line-end) | ||
| 1250 | ;; if first character of the line is inside string, it's a continuation | 1348 | ;; if first character of the line is inside string, it's a continuation |
| 1251 | ;; if strings aren't supposed to be indented, `lua-calculate-indentation' won't even let | 1349 | ;; if strings aren't supposed to be indented, `lua-calculate-indentation' won't even let |
| 1252 | ;; the control inside this function | 1350 | ;; the control inside this function |
| 1253 | (re-search-forward lua-cont-bol-regexp line-end t)))) | 1351 | (and |
| 1352 | (re-search-forward lua-cont-bol-regexp line-end t) | ||
| 1353 | (or (match-beginning 1) | ||
| 1354 | (match-beginning 2)))))) | ||
| 1254 | 1355 | ||
| 1255 | (defconst lua-block-starter-regexp | ||
| 1256 | (eval-when-compile | ||
| 1257 | (concat | ||
| 1258 | "\\(\\_<" | ||
| 1259 | (regexp-opt '("do" "while" "repeat" "until" "if" "then" | ||
| 1260 | "else" "elseif" "end" "for" "local") t) | ||
| 1261 | "\\_>\\)"))) | ||
| 1262 | 1356 | ||
| 1263 | (defun lua-first-token-starts-block-p () | 1357 | (defun lua--backward-up-list-noerror () |
| 1264 | "Return non-nil if the first token on this line is a block starter token." | 1358 | "Safe version of lua-backward-up-list that does not signal an error." |
| 1265 | (let ((line-end (line-end-position))) | 1359 | (condition-case nil |
| 1266 | (save-excursion | 1360 | (lua-backward-up-list) |
| 1267 | (beginning-of-line) | 1361 | (scan-error nil))) |
| 1268 | (re-search-forward (concat "\\s *" lua-block-starter-regexp) line-end t)))) | 1362 | |
| 1363 | |||
| 1364 | (defun lua-backward-up-list () | ||
| 1365 | "Goto starter/opener of the block that contains point." | ||
| 1366 | (interactive) | ||
| 1367 | (let ((start-pos (point)) | ||
| 1368 | end-pos) | ||
| 1369 | (or | ||
| 1370 | ;; Return parent block opener token if it exists. | ||
| 1371 | (cl-loop | ||
| 1372 | ;; Search indentation modifier backward, return nil on failure. | ||
| 1373 | always (lua-find-regexp 'backward lua-indentation-modifier-regexp) | ||
| 1374 | ;; Fetch info about the found token | ||
| 1375 | for token = (match-string-no-properties 0) | ||
| 1376 | for token-info = (lua-get-block-token-info token) | ||
| 1377 | for token-type = (lua-get-token-type token-info) | ||
| 1378 | ;; If the token is a close token, continue to skip its opener. If not | ||
| 1379 | ;; close, stop and return found token. | ||
| 1380 | while (eq token-type 'close) | ||
| 1381 | ;; Find matching opener to skip it and continue from beginning. | ||
| 1382 | ;; | ||
| 1383 | ;; Return nil on failure. | ||
| 1384 | always (let ((position (lua-find-matching-token-word token 'backward))) | ||
| 1385 | (and position (goto-char position))) | ||
| 1386 | finally return token-info) | ||
| 1387 | (progn | ||
| 1388 | (setq end-pos (point)) | ||
| 1389 | (goto-char start-pos) | ||
| 1390 | (signal 'scan-error | ||
| 1391 | (list "Block open token not found" | ||
| 1392 | ;; If start-pos == end-pos, the "obstacle" is current | ||
| 1393 | (if (eql start-pos end-pos) start-pos (match-beginning 0)) | ||
| 1394 | (if (eql start-pos end-pos) start-pos (match-end 0)))))))) | ||
| 1395 | |||
| 1396 | (defun lua--continuation-breaking-line-p () | ||
| 1397 | "Return non-nil if looking at token(-s) that forbid continued line." | ||
| 1398 | (save-excursion | ||
| 1399 | (lua-skip-ws-and-comments-forward (line-end-position)) | ||
| 1400 | (looking-at (lua-rx (or (symbol "do" "while" "repeat" "until" | ||
| 1401 | "if" "then" "elseif" "else" | ||
| 1402 | "for" "local") | ||
| 1403 | lua-funcheader))))) | ||
| 1269 | 1404 | ||
| 1270 | (defun lua-is-continuing-statement-p (&optional parse-start) | 1405 | |
| 1271 | "Return non-nil if the line at PARSE-START continues a statement. | 1406 | (defun lua-is-continuing-statement-p-1 () |
| 1407 | "Return non-nil if current lined continues a statement. | ||
| 1272 | 1408 | ||
| 1273 | More specifically, return the point in the line that is continued. | 1409 | More specifically, return the point in the line that is continued. |
| 1274 | The criteria for a continuing statement are: | 1410 | The criteria for a continuing statement are: |
| @@ -1276,17 +1412,71 @@ The criteria for a continuing statement are: | |||
| 1276 | * the last token of the previous line is a continuing op, | 1412 | * the last token of the previous line is a continuing op, |
| 1277 | OR the first token of the current line is a continuing op | 1413 | OR the first token of the current line is a continuing op |
| 1278 | 1414 | ||
| 1415 | * the expression is not enclosed by a parentheses/braces/brackets" | ||
| 1416 | (let (prev-line continuation-pos parent-block-opener) | ||
| 1417 | (save-excursion (setq prev-line (lua-forward-line-skip-blanks 'back))) | ||
| 1418 | (and prev-line | ||
| 1419 | (not (lua--continuation-breaking-line-p)) | ||
| 1420 | (save-excursion | ||
| 1421 | (or | ||
| 1422 | ;; Binary operator or keyword that implies continuation. | ||
| 1423 | (and (setq continuation-pos | ||
| 1424 | (or (lua-first-token-continues-p) | ||
| 1425 | (save-excursion (and (goto-char prev-line) | ||
| 1426 | ;; check last token of previous nonblank line | ||
| 1427 | (lua-last-token-continues-p))))) | ||
| 1428 | (not | ||
| 1429 | ;; Operators/keywords does not create continuation inside some blocks: | ||
| 1430 | (and | ||
| 1431 | (setq parent-block-opener (car-safe (lua--backward-up-list-noerror))) | ||
| 1432 | (or | ||
| 1433 | ;; - inside parens/brackets | ||
| 1434 | (member parent-block-opener '("(" "[")) | ||
| 1435 | ;; - inside braces if it is a comma | ||
| 1436 | (and (eq (char-after continuation-pos) ?,) | ||
| 1437 | (equal parent-block-opener "{"))))) | ||
| 1438 | continuation-pos)))))) | ||
| 1439 | |||
| 1440 | |||
| 1441 | (defun lua-is-continuing-statement-p (&optional parse-start) | ||
| 1442 | "Returns non-nil if the line at PARSE-START should be indented as continuation line. | ||
| 1443 | |||
| 1444 | This true is when the line : | ||
| 1445 | |||
| 1446 | * is continuing a statement itself | ||
| 1447 | |||
| 1448 | * starts with a 1+ block-closer tokens, an top-most block opener is on a continuation line | ||
| 1279 | " | 1449 | " |
| 1280 | (let ((prev-line nil)) | 1450 | (save-excursion |
| 1281 | (save-excursion | 1451 | (if parse-start (goto-char parse-start)) |
| 1282 | (if parse-start (goto-char parse-start)) | 1452 | |
| 1283 | (save-excursion (setq prev-line (lua-forward-line-skip-blanks 'back))) | 1453 | ;; If line starts with a series of closer tokens, whether or not the line |
| 1284 | (and prev-line | 1454 | ;; is a continuation line is decided by the opener line, e.g. |
| 1285 | (not (lua-first-token-starts-block-p)) | 1455 | ;; |
| 1286 | (or (lua-first-token-continues-p) | 1456 | ;; x = foo + |
| 1287 | (and (goto-char prev-line) | 1457 | ;; long_function_name( |
| 1288 | ;; check last token of previous nonblank line | 1458 | ;; long_parameter_1, |
| 1289 | (lua-last-token-continues-p))))))) | 1459 | ;; long_parameter_2, |
| 1460 | ;; long_parameter_3, | ||
| 1461 | ;; ) + long_function_name2({ | ||
| 1462 | ;; long_parameter_1, | ||
| 1463 | ;; long_parameter_2, | ||
| 1464 | ;; long_parameter_3, | ||
| 1465 | ;; }) | ||
| 1466 | ;; | ||
| 1467 | ;; Final line, "})" is a continuation line, but it is decided by the | ||
| 1468 | ;; opener line, ") + long_function_name2({", which in its turn is decided | ||
| 1469 | ;; by the "long_function_name(" line, which is a continuation line | ||
| 1470 | ;; because the line before it ends with a binary operator. | ||
| 1471 | (cl-loop | ||
| 1472 | ;; Go to opener line | ||
| 1473 | while (and (lua--goto-line-beginning-rightmost-closer) | ||
| 1474 | (lua--backward-up-list-noerror)) | ||
| 1475 | ;; If opener line is continuing, repeat. If opener line is not | ||
| 1476 | ;; continuing, return nil. | ||
| 1477 | always (lua-is-continuing-statement-p-1) | ||
| 1478 | ;; We get here if there was no opener to go to: check current line. | ||
| 1479 | finally return (lua-is-continuing-statement-p-1)))) | ||
| 1290 | 1480 | ||
| 1291 | (defun lua-make-indentation-info-pair (found-token found-pos) | 1481 | (defun lua-make-indentation-info-pair (found-token found-pos) |
| 1292 | "Create a pair from FOUND-TOKEN and FOUND-POS for indentation calculation. | 1482 | "Create a pair from FOUND-TOKEN and FOUND-POS for indentation calculation. |
| @@ -1305,7 +1495,8 @@ Don't use standalone." | |||
| 1305 | (cons 'relative lua-indent-level)) | 1495 | (cons 'relative lua-indent-level)) |
| 1306 | 1496 | ||
| 1307 | ;; block openers | 1497 | ;; block openers |
| 1308 | ((member found-token (list "{" "(" "[")) | 1498 | ((and lua-indent-nested-block-content-align |
| 1499 | (member found-token (list "{" "(" "["))) | ||
| 1309 | (save-excursion | 1500 | (save-excursion |
| 1310 | (let ((found-bol (line-beginning-position))) | 1501 | (let ((found-bol (line-beginning-position))) |
| 1311 | (forward-comment (point-max)) | 1502 | (forward-comment (point-max)) |
| @@ -1326,9 +1517,10 @@ Don't use standalone." | |||
| 1326 | ;; nullify a previous then if on the same line. | 1517 | ;; nullify a previous then if on the same line. |
| 1327 | ((member found-token (list "until" "elseif")) | 1518 | ((member found-token (list "until" "elseif")) |
| 1328 | (save-excursion | 1519 | (save-excursion |
| 1329 | (let ((line (line-number-at-pos))) | 1520 | (let* ((line-beginning (line-beginning-position)) |
| 1330 | (if (and (lua-goto-matching-block-token found-pos 'backward) | 1521 | (same-line (and (lua-goto-matching-block-token found-pos 'backward) |
| 1331 | (= line (line-number-at-pos))) | 1522 | (<= line-beginning (point))))) |
| 1523 | (if same-line | ||
| 1332 | (cons 'remove-matching 0) | 1524 | (cons 'remove-matching 0) |
| 1333 | (cons 'relative 0))))) | 1525 | (cons 'relative 0))))) |
| 1334 | 1526 | ||
| @@ -1337,23 +1529,41 @@ Don't use standalone." | |||
| 1337 | ;; either the next line will be indented correctly, or the end on the same | 1529 | ;; either the next line will be indented correctly, or the end on the same |
| 1338 | ;; line will remove the effect of the else. | 1530 | ;; line will remove the effect of the else. |
| 1339 | ((string-equal found-token "else") | 1531 | ((string-equal found-token "else") |
| 1340 | (save-excursion | 1532 | (save-excursion |
| 1341 | (let ((line (line-number-at-pos))) | 1533 | (let* ((line-beginning (line-beginning-position)) |
| 1342 | (if (and (lua-goto-matching-block-token found-pos 'backward) | 1534 | (same-line (and (lua-goto-matching-block-token found-pos 'backward) |
| 1343 | (= line (line-number-at-pos))) | 1535 | (<= line-beginning (point))))) |
| 1344 | (cons 'replace-matching (cons 'relative lua-indent-level)) | 1536 | (if same-line |
| 1345 | (cons 'relative lua-indent-level))))) | 1537 | (cons 'replace-matching (cons 'relative lua-indent-level)) |
| 1538 | (cons 'relative lua-indent-level))))) | ||
| 1346 | 1539 | ||
| 1347 | ;; Block closers. If they are on the same line as their openers, they simply | 1540 | ;; Block closers. If they are on the same line as their openers, they simply |
| 1348 | ;; eat up the matching indentation modifier. Otherwise, they pull | 1541 | ;; eat up the matching indentation modifier. Otherwise, they pull |
| 1349 | ;; indentation back to the matching block opener. | 1542 | ;; indentation back to the matching block opener. |
| 1350 | ((member found-token (list ")" "}" "]" "end")) | 1543 | ((member found-token (list ")" "}" "]" "end")) |
| 1351 | (save-excursion | 1544 | (save-excursion |
| 1352 | (let ((line (line-number-at-pos))) | 1545 | (let* ((line-beginning (line-beginning-position)) |
| 1353 | (lua-goto-matching-block-token found-pos 'backward) | 1546 | (same-line (and (lua-goto-matching-block-token found-pos 'backward) |
| 1354 | (if (/= line (line-number-at-pos)) | 1547 | (<= line-beginning (point)))) |
| 1355 | (lua-calculate-indentation-info (point)) | 1548 | (opener-pos (point)) |
| 1356 | (cons 'remove-matching 0))))) | 1549 | opener-continuation-offset) |
| 1550 | (if same-line | ||
| 1551 | (cons 'remove-matching 0) | ||
| 1552 | (back-to-indentation) | ||
| 1553 | (setq opener-continuation-offset | ||
| 1554 | (if (lua-is-continuing-statement-p-1) lua-indent-level 0)) | ||
| 1555 | |||
| 1556 | ;; Accumulate indentation up to opener, including indentation. If | ||
| 1557 | ;; there were no other indentation modifiers until said opener, | ||
| 1558 | ;; ensure there is no continuation after the closer. | ||
| 1559 | `(multiple . ((absolute . ,(- (current-indentation) opener-continuation-offset)) | ||
| 1560 | ,@(when (/= opener-continuation-offset 0) | ||
| 1561 | (list (cons 'continued-line opener-continuation-offset))) | ||
| 1562 | ,@(delete nil (list (lua-calculate-indentation-info-1 nil opener-pos))) | ||
| 1563 | (cancel-continued-line . nil))))))) | ||
| 1564 | |||
| 1565 | ((member found-token '("do" "then")) | ||
| 1566 | `(multiple . ((cancel-continued-line . nil) (relative . ,lua-indent-level)))) | ||
| 1357 | 1567 | ||
| 1358 | ;; Everything else. This is from the original code: If opening a block | 1568 | ;; Everything else. This is from the original code: If opening a block |
| 1359 | ;; (match-data 1 exists), then push indentation one level up, if it is | 1569 | ;; (match-data 1 exists), then push indentation one level up, if it is |
| @@ -1365,8 +1575,8 @@ Don't use standalone." | |||
| 1365 | ;; end of a block matched | 1575 | ;; end of a block matched |
| 1366 | (- lua-indent-level)))))) | 1576 | (- lua-indent-level)))))) |
| 1367 | 1577 | ||
| 1368 | (defun lua-add-indentation-info-pair (pair info) | 1578 | (defun lua-add-indentation-info-pair (pair info-list) |
| 1369 | "Add the given indentation info PAIR to the list of indentation INFO. | 1579 | "Add the given indentation info PAIR to the list of indentation INFO-LIST. |
| 1370 | This function has special case handling for two tokens: remove-matching, | 1580 | This function has special case handling for two tokens: remove-matching, |
| 1371 | and replace-matching. These two tokens are cleanup tokens that remove or | 1581 | and replace-matching. These two tokens are cleanup tokens that remove or |
| 1372 | alter the effect of a previously recorded indentation info. | 1582 | alter the effect of a previously recorded indentation info. |
| @@ -1380,17 +1590,27 @@ and the cdr of the replace-matching info is added in its place. This is used | |||
| 1380 | when a middle-of the block (the only case is 'else') is seen on the same line | 1590 | when a middle-of the block (the only case is 'else') is seen on the same line |
| 1381 | the block is opened." | 1591 | the block is opened." |
| 1382 | (cond | 1592 | (cond |
| 1593 | ( (eq 'multiple (car pair)) | ||
| 1594 | (let ((info-pair-elts (cdr pair))) | ||
| 1595 | (while info-pair-elts | ||
| 1596 | (setq info-list (lua-add-indentation-info-pair (car info-pair-elts) info-list) | ||
| 1597 | info-pair-elts (cdr info-pair-elts))) | ||
| 1598 | info-list)) | ||
| 1599 | ( (eq 'cancel-continued-line (car pair)) | ||
| 1600 | (if (eq (caar info-list) 'continued-line) | ||
| 1601 | (cdr info-list) | ||
| 1602 | info-list)) | ||
| 1383 | ( (eq 'remove-matching (car pair)) | 1603 | ( (eq 'remove-matching (car pair)) |
| 1384 | ; Remove head of list | 1604 | ;; Remove head of list |
| 1385 | (cdr info)) | 1605 | (cdr info-list)) |
| 1386 | ( (eq 'replace-matching (car pair)) | 1606 | ( (eq 'replace-matching (car pair)) |
| 1387 | ; remove head of list, and add the cdr of pair instead | 1607 | ;; remove head of list, and add the cdr of pair instead |
| 1388 | (cons (cdr pair) (cdr info))) | 1608 | (cons (cdr pair) (cdr info-list))) |
| 1389 | ( (listp (cdr-safe pair)) | 1609 | ( (listp (cdr-safe pair)) |
| 1390 | (nconc pair info)) | 1610 | (nconc pair info-list)) |
| 1391 | ( t | 1611 | ( t |
| 1392 | ; Just add the pair | 1612 | ;; Just add the pair |
| 1393 | (cons pair info)))) | 1613 | (cons pair info-list)))) |
| 1394 | 1614 | ||
| 1395 | (defun lua-calculate-indentation-info-1 (indentation-info bound) | 1615 | (defun lua-calculate-indentation-info-1 (indentation-info bound) |
| 1396 | "Helper function for `lua-calculate-indentation-info'. | 1616 | "Helper function for `lua-calculate-indentation-info'. |
| @@ -1413,10 +1633,11 @@ The effect of each token can be either a shift relative to the current | |||
| 1413 | indentation level, or indentation to some absolute column. This information | 1633 | indentation level, or indentation to some absolute column. This information |
| 1414 | is collected in a list of indentation info pairs, which denote absolute | 1634 | is collected in a list of indentation info pairs, which denote absolute |
| 1415 | and relative each, and the shift/column to indent to." | 1635 | and relative each, and the shift/column to indent to." |
| 1416 | (let (indentation-info) | 1636 | (let (indentation-info cont-stmt-pos) |
| 1417 | 1637 | (while (setq cont-stmt-pos (lua-is-continuing-statement-p)) | |
| 1418 | (while (lua-is-continuing-statement-p) | 1638 | (lua-forward-line-skip-blanks 'back) |
| 1419 | (lua-forward-line-skip-blanks 'back)) | 1639 | (when (< cont-stmt-pos (point)) |
| 1640 | (goto-char cont-stmt-pos))) | ||
| 1420 | 1641 | ||
| 1421 | ;; calculate indentation modifiers for the line itself | 1642 | ;; calculate indentation modifiers for the line itself |
| 1422 | (setq indentation-info (list (cons 'absolute (current-indentation)))) | 1643 | (setq indentation-info (list (cons 'absolute (current-indentation)))) |
| @@ -1438,7 +1659,7 @@ and relative each, and the shift/column to indent to." | |||
| 1438 | 1659 | ||
| 1439 | ;; if it's the first non-continued line, subtract one level | 1660 | ;; if it's the first non-continued line, subtract one level |
| 1440 | (when (eq (car (car indentation-info)) 'continued-line) | 1661 | (when (eq (car (car indentation-info)) 'continued-line) |
| 1441 | (pop indentation-info))) | 1662 | (push (cons 'stop-continued-line (- lua-indent-level)) indentation-info))) |
| 1442 | 1663 | ||
| 1443 | ;; add modifiers found in this continuation line | 1664 | ;; add modifiers found in this continuation line |
| 1444 | (setq indentation-info | 1665 | (setq indentation-info |
| @@ -1448,19 +1669,29 @@ and relative each, and the shift/column to indent to." | |||
| 1448 | indentation-info)) | 1669 | indentation-info)) |
| 1449 | 1670 | ||
| 1450 | 1671 | ||
| 1451 | (defun lua-accumulate-indentation-info (info) | 1672 | (defun lua-accumulate-indentation-info (reversed-indentation-info) |
| 1452 | "Accumulates the indentation information previously calculated by | 1673 | "Accumulates the indentation information previously calculated by |
| 1453 | lua-calculate-indentation-info. Returns either the relative indentation | 1674 | lua-calculate-indentation-info. Returns either the relative indentation |
| 1454 | shift, or the absolute column to indent to." | 1675 | shift, or the absolute column to indent to." |
| 1455 | (let ((info-list (reverse info)) | 1676 | (let (indentation-info |
| 1456 | (type 'relative) | 1677 | (type 'relative) |
| 1457 | (accu 0)) | 1678 | (accu 0)) |
| 1679 | ;; Aggregate all neighbouring relative offsets, reversing the INFO list. | ||
| 1680 | (cl-dolist (elt reversed-indentation-info) | ||
| 1681 | (if (and (eq (car elt) 'relative) | ||
| 1682 | (eq (caar indentation-info) 'relative)) | ||
| 1683 | (setcdr (car indentation-info) (+ (cdar indentation-info) (cdr elt))) | ||
| 1684 | (push elt indentation-info))) | ||
| 1685 | |||
| 1686 | ;; Aggregate indentation info, taking 'absolute modifiers into account. | ||
| 1458 | (mapc (lambda (x) | 1687 | (mapc (lambda (x) |
| 1459 | (setq accu (if (eq 'absolute (car x)) | 1688 | (let ((new-val (cdr x))) |
| 1460 | (progn (setq type 'absolute) | 1689 | (if (eq 'absolute (car x)) |
| 1461 | (cdr x)) | 1690 | (progn (setq type 'absolute |
| 1462 | (+ accu (cdr x))))) | 1691 | accu new-val)) |
| 1463 | info-list) | 1692 | (setq accu (+ accu new-val))))) |
| 1693 | indentation-info) | ||
| 1694 | |||
| 1464 | (cons type accu))) | 1695 | (cons type accu))) |
| 1465 | 1696 | ||
| 1466 | (defun lua-calculate-indentation-block-modifier (&optional parse-end) | 1697 | (defun lua-calculate-indentation-block-modifier (&optional parse-end) |
| @@ -1510,6 +1741,7 @@ one." | |||
| 1510 | ;; right hand side | 1741 | ;; right hand side |
| 1511 | (or "{" | 1742 | (or "{" |
| 1512 | "function" | 1743 | "function" |
| 1744 | "(" | ||
| 1513 | (seq (group-n 1 (eval lua--function-name-rx) (* blank)) | 1745 | (seq (group-n 1 (eval lua--function-name-rx) (* blank)) |
| 1514 | (any "({"))))))) | 1746 | (any "({"))))))) |
| 1515 | 1747 | ||
| @@ -1551,6 +1783,27 @@ left-shifter expression. " | |||
| 1551 | (looking-at lua--left-shifter-regexp) | 1783 | (looking-at lua--left-shifter-regexp) |
| 1552 | (= old-point (match-end 1)))))) | 1784 | (= old-point (match-end 1)))))) |
| 1553 | 1785 | ||
| 1786 | (defun lua--goto-line-beginning-rightmost-closer (&optional parse-start) | ||
| 1787 | (let (case-fold-search pos line-end-pos return-val) | ||
| 1788 | (save-excursion | ||
| 1789 | (if parse-start (goto-char parse-start)) | ||
| 1790 | (setq line-end-pos (line-end-position)) | ||
| 1791 | (back-to-indentation) | ||
| 1792 | (unless (lua-comment-or-string-p) | ||
| 1793 | (cl-loop while (and (<= (point) line-end-pos) | ||
| 1794 | (looking-at lua-indentation-modifier-regexp)) | ||
| 1795 | for token-info = (lua-get-block-token-info (match-string 0)) | ||
| 1796 | for token-type = (lua-get-token-type token-info) | ||
| 1797 | while (not (eq token-type 'open)) | ||
| 1798 | do (progn | ||
| 1799 | (setq pos (match-beginning 0) | ||
| 1800 | return-val token-info) | ||
| 1801 | (goto-char (match-end 0)) | ||
| 1802 | (forward-comment (line-end-position)))))) | ||
| 1803 | (when pos | ||
| 1804 | (progn | ||
| 1805 | (goto-char pos) | ||
| 1806 | return-val)))) | ||
| 1554 | 1807 | ||
| 1555 | 1808 | ||
| 1556 | (defun lua-calculate-indentation-override (&optional parse-start) | 1809 | (defun lua-calculate-indentation-override (&optional parse-start) |
| @@ -1562,26 +1815,44 @@ line containing block-open token for the last block-close token | |||
| 1562 | in the sequence. | 1815 | in the sequence. |
| 1563 | 1816 | ||
| 1564 | If not, return nil." | 1817 | If not, return nil." |
| 1565 | (let (case-fold-search token-info block-token-pos) | 1818 | (let (case-fold-search rightmost-closer-info opener-info opener-pos) |
| 1566 | (save-excursion | 1819 | (save-excursion |
| 1567 | (if parse-start (goto-char parse-start)) | 1820 | (when (and (setq rightmost-closer-info (lua--goto-line-beginning-rightmost-closer parse-start)) |
| 1821 | (setq opener-info (lua--backward-up-list-noerror)) | ||
| 1822 | ;; Ensure opener matches closer. | ||
| 1823 | (string-match (lua-get-token-match-re rightmost-closer-info 'backward) | ||
| 1824 | (car opener-info))) | ||
| 1568 | 1825 | ||
| 1569 | (back-to-indentation) | 1826 | ;; Special case: "middle" tokens like for/do, while/do, if/then, |
| 1570 | (unless (lua-comment-or-string-p) | 1827 | ;; elseif/then: corresponding "end" or corresponding "else" must be |
| 1571 | (while | 1828 | ;; unindented to the beginning of the statement, which is not |
| 1572 | (and (looking-at lua-indentation-modifier-regexp) | 1829 | ;; necessarily the same as beginning of string that contains "do", e.g. |
| 1573 | (setq token-info (lua-get-block-token-info (match-string 0))) | 1830 | ;; |
| 1574 | (not (eq 'open (lua-get-token-type token-info)))) | 1831 | ;; while ( |
| 1575 | (setq block-token-pos (match-beginning 0)) | 1832 | ;; foo and |
| 1576 | (goto-char (match-end 0)) | 1833 | ;; bar) do |
| 1577 | (skip-syntax-forward " " (line-end-position))) | 1834 | ;; hello_world() |
| 1835 | ;; end | ||
| 1836 | (setq opener-pos (point)) | ||
| 1837 | (when (/= (- opener-pos (line-beginning-position)) (current-indentation)) | ||
| 1838 | (unless (or | ||
| 1839 | (and (string-equal (car opener-info) "do") | ||
| 1840 | (member (car (lua--backward-up-list-noerror)) '("while" "for"))) | ||
| 1841 | (and (string-equal (car opener-info) "then") | ||
| 1842 | (member (car (lua--backward-up-list-noerror)) '("if" "elseif")))) | ||
| 1843 | (goto-char opener-pos))) | ||
| 1844 | |||
| 1845 | ;; (let (cont-stmt-pos) | ||
| 1846 | ;; (while (setq cont-stmt-pos (lua-is-continuing-statement-p)) | ||
| 1847 | ;; (goto-char cont-stmt-pos))) | ||
| 1848 | ;; Exception cases: when the start of the line is an assignment, | ||
| 1849 | ;; go to the start of the assignment instead of the matching item | ||
| 1850 | (if (and lua-indent-close-paren-align | ||
| 1851 | (member (car opener-info) '("{" "(" "[")) | ||
| 1852 | (not (lua-point-is-after-left-shifter-p))) | ||
| 1853 | (current-column) | ||
| 1854 | (current-indentation)))))) | ||
| 1578 | 1855 | ||
| 1579 | (when (lua-goto-matching-block-token block-token-pos 'backward) | ||
| 1580 | ;; Exception cases: when the start of the line is an assignment, | ||
| 1581 | ;; go to the start of the assignment instead of the matching item | ||
| 1582 | (if (lua-point-is-after-left-shifter-p) | ||
| 1583 | (current-indentation) | ||
| 1584 | (current-column))))))) | ||
| 1585 | 1856 | ||
| 1586 | (defun lua-calculate-indentation () | 1857 | (defun lua-calculate-indentation () |
| 1587 | "Return appropriate indentation for current line as Lua code." | 1858 | "Return appropriate indentation for current line as Lua code." |
| @@ -1689,11 +1960,11 @@ This function just searches for a `end' at the beginning of a line." | |||
| 1689 | (goto-char (point-min)) | 1960 | (goto-char (point-min)) |
| 1690 | (while (re-search-forward "[\"'\\\t\\\n]" nil t) | 1961 | (while (re-search-forward "[\"'\\\t\\\n]" nil t) |
| 1691 | (cond | 1962 | (cond |
| 1692 | ((string= (match-string 0) "\n") | 1963 | ((string= (match-string 0) "\n") |
| 1693 | (replace-match "\\\\n")) | 1964 | (replace-match "\\\\n")) |
| 1694 | ((string= (match-string 0) "\t") | 1965 | ((string= (match-string 0) "\t") |
| 1695 | (replace-match "\\\\t")) | 1966 | (replace-match "\\\\t")) |
| 1696 | (t | 1967 | (t |
| 1697 | (replace-match "\\\\\\&" t)))) | 1968 | (replace-match "\\\\\\&" t)))) |
| 1698 | (concat "'" (buffer-string) "'")))) | 1969 | (concat "'" (buffer-string) "'")))) |
| 1699 | 1970 | ||
| @@ -1706,32 +1977,33 @@ This function just searches for a `end' at the beginning of a line." | |||
| 1706 | PROGRAM defaults to NAME, which defaults to `lua-default-application'. | 1977 | PROGRAM defaults to NAME, which defaults to `lua-default-application'. |
| 1707 | When called interactively, switch to the process buffer." | 1978 | When called interactively, switch to the process buffer." |
| 1708 | (interactive) | 1979 | (interactive) |
| 1709 | (or switches | ||
| 1710 | (setq switches lua-default-command-switches)) | ||
| 1711 | (setq name (or name (if (consp lua-default-application) | 1980 | (setq name (or name (if (consp lua-default-application) |
| 1712 | (car lua-default-application) | 1981 | (car lua-default-application) |
| 1713 | lua-default-application))) | 1982 | lua-default-application))) |
| 1714 | (setq program (or program lua-default-application)) | 1983 | (setq program (or program lua-default-application)) |
| 1715 | (setq lua-process-buffer (apply 'make-comint name program startfile switches)) | 1984 | ;; don't re-initialize if there already is a lua process |
| 1716 | (setq lua-process (get-buffer-process lua-process-buffer)) | 1985 | (unless (comint-check-proc (format "*%s*" name)) |
| 1717 | (set-process-query-on-exit-flag lua-process nil) | 1986 | (setq lua-process-buffer (apply #'make-comint name program startfile |
| 1718 | (with-current-buffer lua-process-buffer | 1987 | (or switches lua-default-command-switches))) |
| 1719 | ;; wait for prompt | 1988 | (setq lua-process (get-buffer-process lua-process-buffer)) |
| 1720 | (while (not (lua-prompt-line)) | 1989 | (set-process-query-on-exit-flag lua-process nil) |
| 1721 | (accept-process-output (get-buffer-process (current-buffer))) | 1990 | (with-current-buffer lua-process-buffer |
| 1722 | (goto-char (point-max))) | 1991 | ;; enable error highlighting in stack traces |
| 1723 | ;; send initialization code | 1992 | (require 'compile) |
| 1724 | (lua-send-string lua-process-init-code) | 1993 | (setq lua--repl-buffer-p t) |
| 1994 | (make-local-variable 'compilation-error-regexp-alist) | ||
| 1995 | (setq compilation-error-regexp-alist | ||
| 1996 | (cons (list lua-traceback-line-re 1 2) | ||
| 1997 | compilation-error-regexp-alist)) | ||
| 1998 | (compilation-shell-minor-mode 1) | ||
| 1999 | (setq-local comint-prompt-regexp lua-prompt-regexp) | ||
| 1725 | 2000 | ||
| 1726 | ;; enable error highlighting in stack traces | 2001 | ;; Don't send initialization code until seeing the prompt to ensure that |
| 1727 | (require 'compile) | 2002 | ;; the interpreter is ready. |
| 1728 | (setq lua--repl-buffer-p t) | 2003 | (while (not (lua-prompt-line)) |
| 1729 | (make-local-variable 'compilation-error-regexp-alist) | 2004 | (accept-process-output (get-buffer-process (current-buffer))) |
| 1730 | (setq compilation-error-regexp-alist | 2005 | (goto-char (point-max))) |
| 1731 | (cons (list lua-traceback-line-re 1 2) | 2006 | (lua-send-string lua-process-init-code))) |
| 1732 | compilation-error-regexp-alist)) | ||
| 1733 | (compilation-shell-minor-mode 1) | ||
| 1734 | (setq-local comint-prompt-regexp lua-prompt-regexp)) | ||
| 1735 | 2007 | ||
| 1736 | ;; when called interactively, switch to process buffer | 2008 | ;; when called interactively, switch to process buffer |
| 1737 | (if (called-interactively-p 'any) | 2009 | (if (called-interactively-p 'any) |
| @@ -1739,8 +2011,7 @@ When called interactively, switch to the process buffer." | |||
| 1739 | 2011 | ||
| 1740 | (defun lua-get-create-process () | 2012 | (defun lua-get-create-process () |
| 1741 | "Return active Lua process creating one if necessary." | 2013 | "Return active Lua process creating one if necessary." |
| 1742 | (unless (comint-check-proc lua-process-buffer) | 2014 | (lua-start-process) |
| 1743 | (lua-start-process)) | ||
| 1744 | lua-process) | 2015 | lua-process) |
| 1745 | 2016 | ||
| 1746 | (defun lua-kill-process () | 2017 | (defun lua-kill-process () |
| @@ -1868,12 +2139,22 @@ Create a Lua process if one doesn't already exist." | |||
| 1868 | (when (buffer-live-p lua-process-buffer) | 2139 | (when (buffer-live-p lua-process-buffer) |
| 1869 | (delete-windows-on lua-process-buffer))) | 2140 | (delete-windows-on lua-process-buffer))) |
| 1870 | 2141 | ||
| 2142 | (defun lua--funcname-char-p (c) | ||
| 2143 | "Check if character C is part of a function name. | ||
| 2144 | Return nil if C is nil. See `lua-funcname-at-point'." | ||
| 2145 | (and c (string-match-p "\\`[A-Za-z_.]\\'" (string c)))) | ||
| 2146 | |||
| 1871 | (defun lua-funcname-at-point () | 2147 | (defun lua-funcname-at-point () |
| 1872 | "Get current Name { '.' Name } sequence." | 2148 | "Get current Name { '.' Name } sequence." |
| 1873 | ;; FIXME: copying/modifying syntax table for each call may incur a penalty | 2149 | (when (or (lua--funcname-char-p (char-before)) |
| 1874 | (with-syntax-table (copy-syntax-table) | 2150 | (lua--funcname-char-p (char-after))) |
| 1875 | (modify-syntax-entry ?. "_") | 2151 | (save-excursion |
| 1876 | (current-word t))) | 2152 | (save-match-data |
| 2153 | (re-search-backward "\\`\\|[^A-Za-z_.]") | ||
| 2154 | ;; NOTE: `point' will be either at the start of the buffer or on a | ||
| 2155 | ;; non-symbol character. | ||
| 2156 | (re-search-forward "\\([A-Za-z_]+\\(?:\\.[A-Za-z_]+\\)*\\)") | ||
| 2157 | (match-string-no-properties 1))))) | ||
| 1877 | 2158 | ||
| 1878 | (defun lua-search-documentation () | 2159 | (defun lua-search-documentation () |
| 1879 | "Search Lua documentation for the word at the point." | 2160 | "Search Lua documentation for the word at the point." |
