summaryrefslogtreecommitdiff
path: root/.emacs.d/lisp/lua-mode.el
diff options
context:
space:
mode:
authorSimeon Simeonov2019-01-08 10:41:09 +0100
committerSimeon Simeonov2019-01-08 10:41:09 +0100
commit1adfb1d130c27b4d0f12d956446604a3714c1bc9 (patch)
tree4a5acbabe5c01af7fa0e2fbcca183d634df16c78 /.emacs.d/lisp/lua-mode.el
parent91a787a67152d5c62a311a0e49a5242d8a6fb2b8 (diff)
Add lua-mode.el, update php-mode and yasnippet, add some new C and Python snippets
Diffstat (limited to '.emacs.d/lisp/lua-mode.el')
-rw-r--r--.emacs.d/lisp/lua-mode.el1907
1 files changed, 1907 insertions, 0 deletions
diff --git a/.emacs.d/lisp/lua-mode.el b/.emacs.d/lisp/lua-mode.el
new file mode 100644
index 0000000..91fd0a4
--- /dev/null
+++ b/.emacs.d/lisp/lua-mode.el
@@ -0,0 +1,1907 @@
1;;; lua-mode.el --- a major-mode for editing Lua scripts
2
3;; Author: 2011-2013 immerrr <immerrr+lua@gmail.com>
4;; 2010-2011 Reuben Thomas <rrt@sc3d.org>
5;; 2006 Juergen Hoetzel <juergen@hoetzel.info>
6;; 2004 various (support for Lua 5 and byte compilation)
7;; 2001 Christian Vogler <cvogler@gradient.cis.upenn.edu>
8;; 1997 Bret Mogilefsky <mogul-lua@gelatinous.com> starting from
9;; tcl-mode by Gregor Schmid <schmid@fb3-s7.math.tu-berlin.de>
10;; with tons of assistance from
11;; Paul Du Bois <pld-lua@gelatinous.com> and
12;; Aaron Smith <aaron-lua@gelatinous.com>.
13;;
14;; URL: http://immerrr.github.com/lua-mode
15;; Version: 20151025
16;;
17;; This file is NOT part of Emacs.
18;;
19;; This program is free software; you can redistribute it and/or
20;; modify it under the terms of the GNU General Public License
21;; as published by the Free Software Foundation; either version 2
22;; of the License, or (at your option) any later version.
23;;
24;; This program is distributed in the hope that it will be useful,
25;; but WITHOUT ANY WARRANTY; without even the implied warranty of
26;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27;; GNU General Public License for more details.
28;;
29;; You should have received a copy of the GNU General Public License
30;; along with this program; if not, write to the Free Software
31;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
32;; MA 02110-1301, USA.
33
34;; Keywords: languages, processes, tools
35
36;; This field is expanded to commit SHA, date & associated heads/tags during
37;; archive creation.
38;; Revision: $Format:%h (%cD %d)$
39;;
40
41;;; Commentary:
42
43;; lua-mode provides support for editing Lua, including automatical
44;; indentation, syntactical font-locking, running interactive shell,
45;; interacting with `hs-minor-mode' and online documentation lookup.
46
47;; The following variables are available for customization (see more via
48;; `M-x customize-group lua`):
49
50;; - Var `lua-indent-level':
51;; indentation offset in spaces
52;; - Var `lua-indent-string-contents':
53;; set to `t` if you like to have contents of multiline strings to be
54;; indented like comments
55;; - Var `lua-mode-hook':
56;; list of functions to execute when lua-mode is initialized
57;; - Var `lua-documentation-url':
58;; base URL for documentation lookup
59;; - Var `lua-documentation-function': function used to
60;; show documentation (`eww` is a viable alternative for Emacs 25)
61
62;; These are variables/commands that operate on the Lua process:
63
64;; - Var `lua-default-application':
65;; command to start the Lua process (REPL)
66;; - Var `lua-default-command-switches':
67;; arguments to pass to the Lua process on startup (make sure `-i` is there
68;; if you expect working with Lua shell interactively)
69;; - Cmd `lua-start-process': start new REPL process, usually happens automatically
70;; - Cmd `lua-kill-process': kill current REPL process
71
72;; These are variables/commands for interaction with the Lua process:
73
74;; - Cmd `lua-show-process-buffer': switch to REPL buffer
75;; - Cmd `lua-hide-process-buffer': hide window showing REPL buffer
76;; - Var `lua-always-show': show REPL buffer after sending something
77;; - Cmd `lua-send-buffer': send whole buffer
78;; - Cmd `lua-send-current-line': send current line
79;; - Cmd `lua-send-defun': send current top-level function
80;; - Cmd `lua-send-region': send active region
81;; - Cmd `lua-restart-with-whole-file': restart REPL and send whole buffer
82
83;; See "M-x apropos-command ^lua-" for a list of commands.
84;; See "M-x customize-group lua" for a list of customizable variables.
85
86
87;;; Code:
88(eval-when-compile
89 (require 'cl))
90
91(require 'comint)
92(require 'newcomment)
93(require 'rx)
94
95
96;; rx-wrappers for Lua
97
98(eval-when-compile
99 ;; Silence compilation warning about `compilation-error-regexp-alist' defined
100 ;; in compile.el.
101 (require 'compile))
102
103(eval-and-compile
104 (defvar lua-rx-constituents)
105 (defvar rx-parent)
106
107 (defun lua-rx-to-string (form &optional no-group)
108 "Lua-specific replacement for `rx-to-string'.
109
110See `rx-to-string' documentation for more information FORM and
111NO-GROUP arguments."
112 (let ((rx-constituents lua-rx-constituents))
113 (rx-to-string form no-group)))
114
115 (defmacro lua-rx (&rest regexps)
116 "Lua-specific replacement for `rx'.
117
118See `rx' documentation for more information about REGEXPS param."
119 (cond ((null regexps)
120 (error "No regexp"))
121 ((cdr regexps)
122 (lua-rx-to-string `(and ,@regexps) t))
123 (t
124 (lua-rx-to-string (car regexps) t))))
125
126 (defun lua--new-rx-form (form)
127 "Add FORM definition to `lua-rx' macro.
128
129FORM is a cons (NAME . DEFN), see more in `rx-constituents' doc.
130This function enables specifying new definitions using old ones:
131if DEFN is a list that starts with `:rx' symbol its second
132element is itself expanded with `lua-rx-to-string'. "
133 (let ((name (car form))
134 (form-definition (cdr form)))
135 (when (and (listp form-definition) (eq ':rx (car form-definition)))
136 (setcdr form (lua-rx-to-string (cadr form-definition) 'nogroup)))
137 (push form lua-rx-constituents)))
138
139 (defun lua--rx-symbol (form)
140 ;; form is a list (symbol XXX ...)
141 ;; Skip initial 'symbol
142 (setq form (cdr form))
143 ;; If there's only one element, take it from the list, otherwise wrap the
144 ;; whole list into `(or XXX ...)' form.
145 (setq form (if (eq 1 (length form))
146 (car form)
147 (append '(or) form)))
148 (rx-form `(seq symbol-start ,form symbol-end) rx-parent))
149
150 (setq lua-rx-constituents (copy-sequence rx-constituents))
151
152 (mapc #'lua--new-rx-form
153 `((symbol lua--rx-symbol 1 nil)
154 (ws . "[ \t]*") (ws+ . "[ \t]+")
155 (lua-name :rx (symbol (regexp "[[:alpha:]_]+[[:alnum:]_]*")))
156 (lua-funcname
157 :rx (seq lua-name (* ws "." ws lua-name)
158 (opt ws ":" ws lua-name)))
159 (lua-funcheader
160 ;; Outer (seq ...) is here to shy-group the definition
161 :rx (seq (or (seq (symbol "function") ws (group-n 1 lua-funcname))
162 (seq (group-n 1 lua-funcname) ws "=" ws
163 (symbol "function")))))
164 (lua-number
165 :rx (seq (or (seq (+ digit) (opt ".") (* digit))
166 (seq (* digit) (opt ".") (+ digit)))
167 (opt (regexp "[eE][+-]?[0-9]+"))))
168 (lua-assignment-op
169 :rx (seq "=" (or buffer-end (not (any "=")))))
170 (lua-token
171 :rx (or "+" "-" "*" "/" "%" "^" "#" "==" "~=" "<=" ">=" "<"
172 ">" "=" ";" ":" "," "." ".." "..."))
173 (lua-keyword
174 :rx (symbol "and" "break" "do" "else" "elseif" "end" "for" "function"
175 "goto" "if" "in" "local" "not" "or" "repeat" "return"
176 "then" "until" "while")))
177 ))
178
179
180;; Local variables
181(defgroup lua nil
182 "Major mode for editing Lua code."
183 :prefix "lua-"
184 :group 'languages)
185
186(defcustom lua-indent-level 3
187 "Amount by which Lua subexpressions are indented."
188 :type 'integer
189 :group 'lua
190 :safe #'integerp)
191
192(defcustom lua-comment-start "-- "
193 "Default value of `comment-start'."
194 :type 'string
195 :group 'lua)
196
197(defcustom lua-comment-start-skip "---*[ \t]*"
198 "Default value of `comment-start-skip'."
199 :type 'string
200 :group 'lua)
201
202(defcustom lua-default-application "lua"
203 "Default application to run in Lua process."
204 :type '(choice (string)
205 (cons string integer))
206 :group 'lua)
207
208(defcustom lua-default-command-switches (list "-i")
209 "Command switches for `lua-default-application'.
210Should be a list of strings."
211 :type '(repeat string)
212 :group 'lua)
213(make-variable-buffer-local 'lua-default-command-switches)
214
215(defcustom lua-always-show t
216 "*Non-nil means display lua-process-buffer after sending a command."
217 :type 'boolean
218 :group 'lua)
219
220(defcustom lua-documentation-function 'browse-url
221 "Function used to fetch the Lua reference manual."
222 :type `(radio (function-item browse-url)
223 ,@(when (fboundp 'eww) '((function-item eww)))
224 ,@(when (fboundp 'w3m-browse-url) '((function-item w3m-browse-url)))
225 (function :tag "Other function"))
226 :group 'lua)
227
228(defcustom lua-documentation-url
229 (or (and (file-readable-p "/usr/share/doc/lua/manual.html")
230 "file:///usr/share/doc/lua/manual.html")
231 "http://www.lua.org/manual/5.1/manual.html")
232 "URL pointing to the Lua reference manual."
233 :type 'string
234 :group 'lua)
235
236
237(defvar lua-process nil
238 "The active Lua process")
239
240(defvar lua-process-buffer nil
241 "Buffer used for communication with the Lua process")
242
243(defun lua--customize-set-prefix-key (prefix-key-sym prefix-key-val)
244 (cl-assert (eq prefix-key-sym 'lua-prefix-key))
245 (set prefix-key-sym (if (and prefix-key-val (> (length prefix-key-val) 0))
246 ;; read-kbd-macro returns a string or a vector
247 ;; in both cases (elt x 0) is ok
248 (elt (read-kbd-macro prefix-key-val) 0)))
249 (if (fboundp 'lua-prefix-key-update-bindings)
250 (lua-prefix-key-update-bindings)))
251
252(defcustom lua-prefix-key "\C-c"
253 "Prefix for all lua-mode commands."
254 :type 'string
255 :group 'lua
256 :set 'lua--customize-set-prefix-key
257 :get '(lambda (sym)
258 (let ((val (eval sym))) (if val (single-key-description (eval sym)) ""))))
259
260(defvar lua-mode-menu (make-sparse-keymap "Lua")
261 "Keymap for lua-mode's menu.")
262
263(defvar lua-prefix-mode-map
264 (eval-when-compile
265 (let ((result-map (make-sparse-keymap)))
266 (mapc (lambda (key_defn)
267 (define-key result-map (read-kbd-macro (car key_defn)) (cdr key_defn)))
268 '(("C-l" . lua-send-buffer)
269 ("C-f" . lua-search-documentation)))
270 result-map))
271 "Keymap that is used to define keys accessible by `lua-prefix-key'.
272
273If the latter is nil, the keymap translates into `lua-mode-map' verbatim.")
274
275(defvar lua--electric-indent-chars
276 (mapcar #'string-to-char '("}" "]" ")")))
277
278
279(defvar lua-mode-map
280 (let ((result-map (make-sparse-keymap))
281 prefix-key)
282 (unless (boundp 'electric-indent-chars)
283 (mapc (lambda (electric-char)
284 (define-key result-map
285 (read-kbd-macro
286 (char-to-string electric-char))
287 #'lua-electric-match))
288 lua--electric-indent-chars))
289 (define-key result-map [menu-bar lua-mode] (cons "Lua" lua-mode-menu))
290
291 ;; FIXME: see if the declared logic actually works
292 ;; handle prefix-keyed bindings:
293 ;; * if no prefix, set prefix-map as parent, i.e.
294 ;; if key is not defined look it up in prefix-map
295 ;; * if prefix is set, bind the prefix-map to that key
296 (if (boundp 'lua-prefix-key)
297 (define-key result-map (vector lua-prefix-key) lua-prefix-mode-map)
298 (set-keymap-parent result-map lua-prefix-mode-map))
299 result-map)
300 "Keymap used in lua-mode buffers.")
301
302(defvar lua-electric-flag t
303 "If t, electric actions (like automatic reindentation) will happen when an electric
304 key like `{' is pressed")
305(make-variable-buffer-local 'lua-electric-flag)
306
307(defcustom lua-prompt-regexp "[^\n]*\\(>[\t ]+\\)+$"
308 "Regexp which matches the Lua program's prompt."
309 :type 'regexp
310 :group 'lua)
311
312(defcustom lua-traceback-line-re
313 ;; This regexp skips prompt and meaningless "stdin:N:" prefix when looking
314 ;; for actual file-line locations.
315 "^\\(?:[\t ]*\\|.*>[\t ]+\\)\\(?:[^\n\t ]+:[0-9]+:[\t ]*\\)*\\(?:\\([^\n\t ]+\\):\\([0-9]+\\):\\)"
316 "Regular expression that describes tracebacks and errors."
317 :type 'regexp
318 :group 'lua)
319
320(defvar lua--repl-buffer-p nil
321 "Buffer-local flag saying if this is a Lua REPL buffer.")
322(make-variable-buffer-local 'lua--repl-buffer-p)
323
324
325(defadvice compilation-find-file (around lua--repl-find-file
326 (marker filename directory &rest formats)
327 activate)
328 "Return Lua REPL buffer when looking for \"stdin\" file in it."
329 (if (and
330 lua--repl-buffer-p
331 (string-equal filename "stdin")
332 ;; NOTE: this doesn't traverse `compilation-search-path' when
333 ;; looking for filename.
334 (not (file-exists-p (expand-file-name
335 filename
336 (when directory (expand-file-name directory))))))
337 (setq ad-return-value (current-buffer))
338 ad-do-it))
339
340
341(defadvice compilation-goto-locus (around lua--repl-goto-locus
342 (msg mk end-mk)
343 activate)
344 "When message points to Lua REPL buffer, go to the message itself.
345Usually, stdin:XX line number points to nowhere."
346 (let ((errmsg-buf (marker-buffer msg))
347 (error-buf (marker-buffer mk)))
348 (if (and (with-current-buffer errmsg-buf lua--repl-buffer-p)
349 (eq error-buf errmsg-buf))
350 (progn
351 (compilation-set-window (display-buffer (marker-buffer msg)) msg)
352 (goto-char msg))
353 ad-do-it)))
354
355
356(defcustom lua-indent-string-contents nil
357 "If non-nil, contents of multiline string will be indented.
358Otherwise leading amount of whitespace on each line is preserved."
359 :group 'lua
360 :type 'boolean)
361
362(defcustom lua-jump-on-traceback t
363 "*Jump to innermost traceback location in *lua* buffer. When this
364variable is non-nil and a traceback occurs when running Lua code in a
365process, jump immediately to the source code of the innermost
366traceback location."
367 :type 'boolean
368 :group 'lua)
369
370(defcustom lua-mode-hook nil
371 "Hooks called when Lua mode fires up."
372 :type 'hook
373 :group 'lua)
374
375(defvar lua-region-start (make-marker)
376 "Start of special region for Lua communication.")
377
378(defvar lua-region-end (make-marker)
379 "End of special region for Lua communication.")
380
381(defvar lua-emacs-menu
382 '(["Restart With Whole File" lua-restart-with-whole-file t]
383 ["Kill Process" lua-kill-process t]
384 ["Hide Process Buffer" lua-hide-process-buffer t]
385 ["Show Process Buffer" lua-show-process-buffer t]
386 ["Beginning Of Proc" lua-beginning-of-proc t]
387 ["End Of Proc" lua-end-of-proc t]
388 ["Set Lua-Region Start" lua-set-lua-region-start t]
389 ["Set Lua-Region End" lua-set-lua-region-end t]
390 ["Send Lua-Region" lua-send-lua-region t]
391 ["Send Current Line" lua-send-current-line t]
392 ["Send Region" lua-send-region t]
393 ["Send Proc" lua-send-proc t]
394 ["Send Buffer" lua-send-buffer t]
395 ["Search Documentation" lua-search-documentation t])
396 "Emacs menu for Lua mode.")
397
398;; the whole defconst is inside eval-when-compile, because it's later referenced
399;; inside another eval-and-compile block
400(eval-and-compile
401 (defconst
402 lua--builtins
403 (let*
404 ((modules
405 '("_G" "_VERSION" "assert" "collectgarbage" "dofile" "error" "getfenv"
406 "getmetatable" "ipairs" "load" "loadfile" "loadstring" "module"
407 "next" "pairs" "pcall" "print" "rawequal" "rawget" "rawlen" "rawset"
408 "require" "select" "setfenv" "setmetatable" "tonumber" "tostring"
409 "type" "unpack" "xpcall" "self"
410 ("bit32" . ("arshift" "band" "bnot" "bor" "btest" "bxor" "extract"
411 "lrotate" "lshift" "replace" "rrotate" "rshift"))
412 ("coroutine" . ("create" "isyieldable" "resume" "running" "status"
413 "wrap" "yield"))
414 ("debug" . ("debug" "getfenv" "gethook" "getinfo" "getlocal"
415 "getmetatable" "getregistry" "getupvalue" "getuservalue"
416 "setfenv" "sethook" "setlocal" "setmetatable"
417 "setupvalue" "setuservalue" "traceback" "upvalueid"
418 "upvaluejoin"))
419 ("io" . ("close" "flush" "input" "lines" "open" "output" "popen"
420 "read" "stderr" "stdin" "stdout" "tmpfile" "type" "write"))
421 ("math" . ("abs" "acos" "asin" "atan" "atan2" "ceil" "cos" "cosh"
422 "deg" "exp" "floor" "fmod" "frexp" "huge" "ldexp" "log"
423 "log10" "max" "maxinteger" "min" "mininteger" "modf" "pi"
424 "pow" "rad" "random" "randomseed" "sin" "sinh" "sqrt"
425 "tan" "tanh" "tointeger" "type" "ult"))
426 ("os" . ("clock" "date" "difftime" "execute" "exit" "getenv"
427 "remove" "rename" "setlocale" "time" "tmpname"))
428 ("package" . ("config" "cpath" "loaded" "loaders" "loadlib" "path"
429 "preload" "searchers" "searchpath" "seeall"))
430 ("string" . ("byte" "char" "dump" "find" "format" "gmatch" "gsub"
431 "len" "lower" "match" "pack" "packsize" "rep" "reverse"
432 "sub" "unpack" "upper"))
433 ("table" . ("concat" "insert" "maxn" "move" "pack" "remove" "sort"
434 "unpack"))
435 ("utf8" . ("char" "charpattern" "codepoint" "codes" "len"
436 "offset")))))
437
438 (cl-labels
439 ((module-name-re (x)
440 (concat "\\(?1:\\_<"
441 (if (listp x) (car x) x)
442 "\\_>\\)"))
443 (module-members-re (x) (if (listp x)
444 (concat "\\(?:[ \t]*\\.[ \t]*"
445 "\\_<\\(?2:"
446 (regexp-opt (cdr x))
447 "\\)\\_>\\)?")
448 "")))
449
450 (concat
451 ;; common prefix:
452 ;; - beginning-of-line
453 ;; - or neither of [ '.', ':' ] to exclude "foo.string.rep"
454 ;; - or concatenation operator ".."
455 "\\(?:^\\|[^:. \t]\\|[.][.]\\)"
456 ;; optional whitespace
457 "[ \t]*"
458 "\\(?:"
459 ;; any of modules/functions
460 (mapconcat (lambda (x) (concat (module-name-re x)
461 (module-members-re x)))
462 modules
463 "\\|")
464 "\\)"))))
465
466 "A regexp that matches Lua builtin functions & variables.
467
468This is a compilation of 5.1, 5.2 and 5.3 builtins taken from the
469index of respective Lua reference manuals.")
470
471(eval-and-compile
472 (defun lua-make-delimited-matcher (elt-regexp sep-regexp end-regexp)
473 "Construct matcher function for `font-lock-keywords' to match a sequence.
474
475It's supposed to match sequences with following EBNF:
476
477ELT-REGEXP { SEP-REGEXP ELT-REGEXP } END-REGEXP
478
479The sequence is parsed one token at a time. If non-nil is
480returned, `match-data' will have one or more of the following
481groups set according to next matched token:
482
4831. matched element token
4842. unmatched garbage characters
4853. misplaced token (i.e. SEP-REGEXP when ELT-REGEXP is expected)
4864. matched separator token
4875. matched end token
488
489Blanks & comments between tokens are silently skipped.
490Groups 6-9 can be used in any of argument regexps."
491 (lexical-let*
492 ((delimited-matcher-re-template
493 "\\=\\(?2:.*?\\)\\(?:\\(?%s:\\(?4:%s\\)\\|\\(?5:%s\\)\\)\\|\\(?%s:\\(?1:%s\\)\\)\\)")
494 ;; There's some magic to this regexp. It works as follows:
495 ;;
496 ;; A. start at (point)
497 ;; B. non-greedy match of garbage-characters (?2:)
498 ;; C. try matching separator (?4:) or end-token (?5:)
499 ;; D. try matching element (?1:)
500 ;;
501 ;; Simple, but there's a trick: pt.C and pt.D are embraced by one more
502 ;; group whose purpose is determined only after the template is
503 ;; formatted (?%s:):
504 ;;
505 ;; - if element is expected, then D's parent group becomes "shy" and C's
506 ;; parent becomes group 3 (aka misplaced token), so if D matches when
507 ;; an element is expected, it'll be marked with warning face.
508 ;;
509 ;; - if separator-or-end-token is expected, then it's the opposite:
510 ;; C's parent becomes shy and D's will be matched as misplaced token.
511 (elt-expected-re (format delimited-matcher-re-template
512 3 sep-regexp end-regexp "" elt-regexp))
513 (sep-or-end-expected-re (format delimited-matcher-re-template
514 "" sep-regexp end-regexp 3 elt-regexp)))
515
516 (lambda (end)
517 (let* ((prev-elt-p (match-beginning 1))
518 (prev-sep-p (match-beginning 4))
519 (prev-end-p (match-beginning 5))
520
521 (regexp (if prev-elt-p sep-or-end-expected-re elt-expected-re))
522 (comment-start (lua-comment-start-pos (syntax-ppss)))
523 (parse-stop end))
524
525 ;; If token starts inside comment, or end-token was encountered, stop.
526 (when (and (not comment-start)
527 (not prev-end-p))
528 ;; Skip all comments & whitespace. forward-comment doesn't have boundary
529 ;; argument, so make sure point isn't beyond parse-stop afterwards.
530 (while (and (< (point) end)
531 (forward-comment 1)))
532 (goto-char (min (point) parse-stop))
533
534 ;; Reuse comment-start variable to store beginning of comment that is
535 ;; placed before line-end-position so as to make sure token search doesn't
536 ;; enter that comment.
537 (setq comment-start
538 (lua-comment-start-pos
539 (save-excursion
540 (parse-partial-sexp (point) parse-stop
541 nil nil nil 'stop-inside-comment)))
542 parse-stop (or comment-start parse-stop))
543
544 ;; Now, let's match stuff. If regular matcher fails, declare a span of
545 ;; non-blanks 'garbage', and the next iteration will start from where the
546 ;; garbage ends. If couldn't match any garbage, move point to the end
547 ;; and return nil.
548 (or (re-search-forward regexp parse-stop t)
549 (re-search-forward "\\(?1:\\(?2:[^ \t]+\\)\\)" parse-stop 'skip)
550 (prog1 nil (goto-char end)))))))))
551
552
553(defvar lua-font-lock-keywords
554 `(;; highlight the hash-bang line "#!/foo/bar/lua" as comment
555 ("^#!.*$" . font-lock-comment-face)
556
557 ;; Builtin constants
558 (,(lua-rx (symbol "true" "false" "nil"))
559 . font-lock-constant-face)
560
561 ;; Keywords
562 (,(lua-rx lua-keyword)
563 . font-lock-keyword-face)
564
565 ;; Labels used by the "goto" statement
566 ;; Highlights the following syntax: ::label::
567 (,(lua-rx "::" ws lua-name ws "::")
568 . font-lock-constant-face)
569
570 ;; Hightlights the name of the label in the "goto" statement like
571 ;; "goto label"
572 (,(lua-rx (symbol (seq "goto" ws+ (group-n 1 lua-name))))
573 (1 font-lock-constant-face))
574
575 ;; Highlight Lua builtin functions and variables
576 (,lua--builtins
577 (1 font-lock-builtin-face) (2 font-lock-builtin-face nil noerror))
578
579 ("^[ \t]*\\_<for\\_>"
580 (,(lua-make-delimited-matcher (lua-rx lua-name) ","
581 (lua-rx (or (symbol "in") lua-assignment-op)))
582 nil nil
583 (1 font-lock-variable-name-face nil noerror)
584 (2 font-lock-warning-face t noerror)
585 (3 font-lock-warning-face t noerror)))
586
587 ;; Handle local variable/function names
588 ;; local blalba, xyzzy =
589 ;; ^^^^^^ ^^^^^
590 ;;
591 ;; local function foobar(x,y,z)
592 ;; ^^^^^^
593 ;; local foobar = function(x,y,z)
594 ;; ^^^^^^
595 ("^[ \t]*\\_<local\\_>"
596 (0 font-lock-keyword-face)
597
598 ;; (* nonl) at the end is to consume trailing characters or otherwise they
599 ;; delimited matcher would attempt to parse them afterwards and wrongly
600 ;; highlight parentheses as incorrect variable name characters.
601 (,(lua-rx point ws lua-funcheader (* nonl))
602 nil nil
603 (1 font-lock-function-name-face nil noerror))
604
605 (,(lua-make-delimited-matcher (lua-rx lua-name) ","
606 (lua-rx lua-assignment-op))
607 nil nil
608 (1 font-lock-variable-name-face nil noerror)
609 (2 font-lock-warning-face t noerror)
610 (3 font-lock-warning-face t noerror)))
611
612 (,(lua-rx (or bol ";") ws lua-funcheader)
613 (1 font-lock-function-name-face))
614
615 (,(lua-rx (or (group-n 1
616 "@" (symbol "author" "copyright" "field" "release"
617 "return" "see" "usage" "description"))
618 (seq (group-n 1 "@" (symbol "param" "class" "name")) ws+
619 (group-n 2 lua-name))))
620 (1 font-lock-keyword-face t)
621 (2 font-lock-variable-name-face t noerror)))
622
623 "Default expressions to highlight in Lua mode.")
624
625(defvar lua-imenu-generic-expression
626 `((nil ,(lua-rx (or bol ";") ws (opt (seq (symbol "local") ws)) lua-funcheader) 1))
627 "Imenu generic expression for lua-mode. See `imenu-generic-expression'.")
628
629(defvar lua-sexp-alist '(("then" . "end")
630 ("function" . "end")
631 ("do" . "end")
632 ("repeat" . "until")))
633
634(defvar lua-mode-abbrev-table nil
635 "Abbreviation table used in lua-mode buffers.")
636
637(define-abbrev-table 'lua-mode-abbrev-table
638 '(("end" "end" lua-indent-line :system t)
639 ("else" "else" lua-indent-line :system t)
640 ("elseif" "elseif" lua-indent-line :system t)))
641
642(defvar lua-mode-syntax-table
643 (with-syntax-table (copy-syntax-table)
644 ;; main comment syntax: begins with "--", ends with "\n"
645 (modify-syntax-entry ?- ". 12")
646 (modify-syntax-entry ?\n ">")
647
648 ;; main string syntax: bounded by ' or "
649 (modify-syntax-entry ?\' "\"")
650 (modify-syntax-entry ?\" "\"")
651
652 ;; single-character binary operators: punctuation
653 (modify-syntax-entry ?+ ".")
654 (modify-syntax-entry ?* ".")
655 (modify-syntax-entry ?/ ".")
656 (modify-syntax-entry ?^ ".")
657 (modify-syntax-entry ?% ".")
658 (modify-syntax-entry ?> ".")
659 (modify-syntax-entry ?< ".")
660 (modify-syntax-entry ?= ".")
661 (modify-syntax-entry ?~ ".")
662
663 (syntax-table))
664 "`lua-mode' syntax table.")
665
666;;;###autoload
667(define-derived-mode lua-mode prog-mode "Lua"
668 "Major mode for editing Lua code."
669 :abbrev-table lua-mode-abbrev-table
670 :syntax-table lua-mode-syntax-table
671 :group 'lua
672 (setq comint-prompt-regexp lua-prompt-regexp)
673
674
675 (setq-local font-lock-defaults '(lua-font-lock-keywords ;; keywords
676 nil ;; keywords-only
677 nil ;; case-fold
678 nil ;; syntax-alist
679 nil ;; syntax-begin
680 ))
681
682 (setq-local syntax-propertize-function
683 'lua--propertize-multiline-bounds)
684
685 (setq-local parse-sexp-lookup-properties t)
686 (setq-local indent-line-function 'lua-indent-line)
687 (setq-local beginning-of-defun-function 'lua-beginning-of-proc)
688 (setq-local end-of-defun-function 'lua-end-of-proc)
689 (setq-local comment-start lua-comment-start)
690 (setq-local comment-start-skip lua-comment-start-skip)
691 (setq-local comment-use-syntax t)
692 (setq-local fill-paragraph-function #'lua--fill-paragraph)
693 (with-no-warnings
694 (setq-local comment-use-global-state t))
695 (setq-local imenu-generic-expression lua-imenu-generic-expression)
696 (when (boundp 'electric-indent-chars)
697 ;; If electric-indent-chars is not defined, electric indentation is done
698 ;; via `lua-mode-map'.
699 (setq-local electric-indent-chars
700 (append electric-indent-chars lua--electric-indent-chars)))
701
702
703 ;; setup menu bar entry (XEmacs style)
704 (if (and (featurep 'menubar)
705 (boundp 'current-menubar)
706 (fboundp 'set-buffer-menubar)
707 (fboundp 'add-menu)
708 (not (assoc "Lua" current-menubar)))
709 (progn
710 (set-buffer-menubar (copy-sequence current-menubar))
711 (add-menu nil "Lua" lua-emacs-menu)))
712 ;; Append Lua menu to popup menu for Emacs.
713 (if (boundp 'mode-popup-menu)
714 (setq mode-popup-menu
715 (cons (concat mode-name " Mode Commands") lua-emacs-menu)))
716
717 ;; hideshow setup
718 (unless (assq 'lua-mode hs-special-modes-alist)
719 (add-to-list 'hs-special-modes-alist
720 `(lua-mode
721 ,(regexp-opt (mapcar 'car lua-sexp-alist) 'words) ;start
722 ,(regexp-opt (mapcar 'cdr lua-sexp-alist) 'words) ;end
723 nil lua-forward-sexp))))
724
725
726
727;;;###autoload
728(add-to-list 'auto-mode-alist '("\\.lua\\'" . lua-mode))
729
730;;;###autoload
731(add-to-list 'interpreter-mode-alist '("lua" . lua-mode))
732
733(defun lua-electric-match (arg)
734 "Insert character and adjust indentation."
735 (interactive "P")
736 (let (blink-paren-function)
737 (self-insert-command (prefix-numeric-value arg)))
738 (if lua-electric-flag
739 (lua-indent-line))
740 (blink-matching-open))
741
742;; private functions
743
744(defun lua--fill-paragraph (&optional justify region)
745 ;; Implementation of forward-paragraph for filling.
746 ;;
747 ;; This function works around a corner case in the following situations:
748 ;;
749 ;; <>
750 ;; -- some very long comment ....
751 ;; some_code_right_after_the_comment
752 ;;
753 ;; If point is at the beginning of the comment line, fill paragraph code
754 ;; would have gone for comment-based filling and done the right thing, but it
755 ;; does not find a comment at the beginning of the empty line before the
756 ;; comment and falls back to text-based filling ignoring comment-start and
757 ;; spilling the comment into the code.
758 (save-excursion
759 (while (and (not (eobp))
760 (progn (move-to-left-margin)
761 (looking-at paragraph-separate)))
762 (forward-line 1))
763 (let ((fill-paragraph-handle-comment t))
764 (fill-paragraph justify region))))
765
766
767(defun lua-prefix-key-update-bindings ()
768 (let (old-cons)
769 (if (eq lua-prefix-mode-map (keymap-parent lua-mode-map))
770 ;; if prefix-map is a parent, delete the parent
771 (set-keymap-parent lua-mode-map nil)
772 ;; otherwise, look for it among children
773 (if (setq old-cons (rassoc lua-prefix-mode-map lua-mode-map))
774 (delq old-cons lua-mode-map)))
775
776 (if (null lua-prefix-key)
777 (set-keymap-parent lua-mode-map lua-prefix-mode-map)
778 (define-key lua-mode-map (vector lua-prefix-key) lua-prefix-mode-map))))
779
780(defun lua-set-prefix-key (new-key-str)
781 "Changes `lua-prefix-key' properly and updates keymaps
782
783This function replaces previous prefix-key binding with a new one."
784 (interactive "sNew prefix key (empty string means no key): ")
785 (lua--customize-set-prefix-key 'lua-prefix-key new-key-str)
786 (message "Prefix key set to %S" (single-key-description lua-prefix-key))
787 (lua-prefix-key-update-bindings))
788
789(defun lua-string-p (&optional pos)
790 "Returns true if the point is in a string."
791 (save-excursion (elt (syntax-ppss pos) 3)))
792
793(defun lua-comment-start-pos (parsing-state)
794 "Return position of comment containing current point.
795
796If point is not inside a comment, return nil."
797 (and parsing-state (nth 4 parsing-state) (nth 8 parsing-state)))
798
799(defun lua-comment-or-string-p (&optional pos)
800 "Returns true if the point is in a comment or string."
801 (save-excursion (let ((parse-result (syntax-ppss pos)))
802 (or (elt parse-result 3) (elt parse-result 4)))))
803
804(defun lua-comment-or-string-start-pos (&optional pos)
805 "Returns start position of string or comment which contains point.
806
807If point is not inside string or comment, return nil."
808 (save-excursion (elt (syntax-ppss pos) 8)))
809
810;; They're propertized as follows:
811;; 1. generic-comment
812;; 2. generic-string
813;; 3. equals signs
814(defconst lua-ml-begin-regexp
815 "\\(?:\\(?1:-\\)-\\[\\|\\(?2:\\[\\)\\)\\(?3:=*\\)\\[")
816
817
818(defun lua-try-match-multiline-end (end)
819 "Try to match close-bracket for multiline literal around point.
820
821Basically, detect form of close bracket from syntactic
822information provided at point and re-search-forward to it."
823 (let ((comment-or-string-start-pos (lua-comment-or-string-start-pos)))
824 ;; Is there a literal around point?
825 (and comment-or-string-start-pos
826 ;; It is, check if the literal is a multiline open-bracket
827 (save-excursion
828 (goto-char comment-or-string-start-pos)
829 (looking-at lua-ml-begin-regexp))
830
831 ;; Yes it is, look for it matching close-bracket. Close-bracket's
832 ;; match group is determined by match-group of open-bracket.
833 (re-search-forward
834 (format "]%s\\(?%s:]\\)"
835 (match-string-no-properties 3)
836 (if (match-beginning 1) 1 2))
837 end 'noerror))))
838
839
840(defun lua-try-match-multiline-begin (limit)
841 "Try to match multiline open-brackets.
842
843Find next opening long bracket outside of any string/comment.
844If none can be found before reaching LIMIT, return nil."
845
846 (let (last-search-matched)
847 (while
848 ;; This loop will iterate skipping all multiline-begin tokens that are
849 ;; inside strings or comments ending either at EOL or at valid token.
850 (and (setq last-search-matched
851 (re-search-forward lua-ml-begin-regexp limit 'noerror))
852
853 ;; Handle triple-hyphen '---[[' situation in which the multiline
854 ;; opener should be skipped.
855 ;;
856 ;; In HYPHEN1-HYPHEN2-BRACKET1-BRACKET2 situation (match-beginning
857 ;; 0) points to HYPHEN1, but if there's another hyphen before
858 ;; HYPHEN1, standard syntax table will only detect comment-start
859 ;; at HYPHEN2.
860 ;;
861 ;; We could check for comment-start at HYPHEN2, but then we'd have
862 ;; to flush syntax-ppss cache to remove the result saying that at
863 ;; HYPHEN2 there's no comment or string, because under some
864 ;; circumstances that would hide the fact that we put a
865 ;; comment-start property at HYPHEN1.
866 (or (lua-comment-or-string-start-pos (match-beginning 0))
867 (and (eq ?- (char-after (match-beginning 0)))
868 (eq ?- (char-before (match-beginning 0)))))))
869
870 last-search-matched))
871
872(defun lua-match-multiline-literal-bounds (limit)
873 ;; First, close any multiline literal spanning from previous block. This will
874 ;; move the point accordingly so as to avoid double traversal.
875 (or (lua-try-match-multiline-end limit)
876 (lua-try-match-multiline-begin limit)))
877
878(defun lua--propertize-multiline-bounds (start end)
879 "Put text properties on beginnings and ends of multiline literals.
880
881Intended to be used as a `syntax-propertize-function'."
882 (save-excursion
883 (goto-char start)
884 (while (lua-match-multiline-literal-bounds end)
885 (when (match-beginning 1)
886 (put-text-property (match-beginning 1) (match-end 1)
887 'syntax-table (string-to-syntax "!")))
888 (when (match-beginning 2)
889 (put-text-property (match-beginning 2) (match-end 2)
890 'syntax-table (string-to-syntax "|"))))))
891
892
893(defun lua-indent-line ()
894 "Indent current line for Lua mode.
895Return the amount the indentation changed by."
896 (let (indent
897 (case-fold-search nil)
898 ;; save point as a distance to eob - it's invariant w.r.t indentation
899 (pos (- (point-max) (point))))
900 (back-to-indentation)
901 (if (lua-comment-or-string-p)
902 (setq indent (lua-calculate-string-or-comment-indentation)) ;; just restore point position
903 (setq indent (max 0 (lua-calculate-indentation nil))))
904
905 (when (not (equal indent (current-column)))
906 (delete-region (line-beginning-position) (point))
907 (indent-to indent))
908
909 ;; If initial point was within line's indentation,
910 ;; position after the indentation. Else stay at same point in text.
911 (if (> (- (point-max) pos) (point))
912 (goto-char (- (point-max) pos)))
913
914 indent))
915
916(defun lua-calculate-string-or-comment-indentation ()
917 "This function should be run when point at (current-indentation) is inside string"
918 (if (and (lua-string-p) (not lua-indent-string-contents))
919 ;; if inside string and strings aren't to be indented, return current indentation
920 (current-indentation)
921
922 ;; At this point, we know that we're inside comment, so make sure
923 ;; close-bracket is unindented like a block that starts after
924 ;; left-shifter.
925 (let ((left-shifter-p (looking-at "\\s *\\(?:--\\)?\\]\\(?1:=*\\)\\]")))
926 (save-excursion
927 (goto-char (lua-comment-or-string-start-pos))
928 (+ (current-indentation)
929 (if (and left-shifter-p
930 (looking-at (format "--\\[%s\\["
931 (match-string-no-properties 1))))
932 0
933 lua-indent-level))))))
934
935(defun lua-find-regexp (direction regexp &optional limit ignore-p)
936 "Searches for a regular expression in the direction specified.
937Direction is one of 'forward and 'backward.
938By default, matches in comments and strings are ignored, but what to ignore is
939configurable by specifying ignore-p. If the regexp is found, returns point
940position, nil otherwise.
941ignore-p returns true if the match at the current point position should be
942ignored, nil otherwise."
943 (let ((ignore-func (or ignore-p 'lua-comment-or-string-p))
944 (search-func (if (eq direction 'forward)
945 're-search-forward 're-search-backward))
946 (case-fold-search nil))
947 (catch 'found
948 (while (funcall search-func regexp limit t)
949 (if (and (not (funcall ignore-func (match-beginning 0)))
950 (not (funcall ignore-func (match-end 0))))
951 (throw 'found (point)))))))
952
953(defconst lua-block-regexp
954 (eval-when-compile
955 (concat
956 "\\(\\_<"
957 (regexp-opt '("do" "function" "repeat" "then"
958 "else" "elseif" "end" "until") t)
959 "\\_>\\)\\|"
960 (regexp-opt '("{" "(" "[" "]" ")" "}") t))))
961
962(defconst lua-block-token-alist
963 '(("do" "\\_<end\\_>" "\\_<for\\|while\\_>" middle-or-open)
964 ("function" "\\_<end\\_>" nil open)
965 ("repeat" "\\_<until\\_>" nil open)
966 ("then" "\\_<\\(e\\(lse\\(if\\)?\\|nd\\)\\)\\_>" "\\_<\\(else\\)?if\\_>" middle)
967 ("{" "}" nil open)
968 ("[" "]" nil open)
969 ("(" ")" nil open)
970 ("if" "\\_<then\\_>" nil open)
971 ("for" "\\_<do\\_>" nil open)
972 ("while" "\\_<do\\_>" nil open)
973 ("else" "\\_<end\\_>" "\\_<then\\_>" middle)
974 ("elseif" "\\_<then\\_>" "\\_<then\\_>" middle)
975 ("end" nil "\\_<\\(do\\|function\\|then\\|else\\)\\_>" close)
976 ("until" nil "\\_<repeat\\_>" close)
977 ("}" nil "{" close)
978 ("]" nil "\\[" close)
979 (")" nil "(" close))
980 "This is a list of block token information blocks.
981Each token information entry is of the form:
982 KEYWORD FORWARD-MATCH-REGEXP BACKWARDS-MATCH-REGEXP TOKEN-TYPE
983KEYWORD is the token.
984FORWARD-MATCH-REGEXP is a regexp that matches all possble tokens when going forward.
985BACKWARDS-MATCH-REGEXP is a regexp that matches all possble tokens when going backwards.
986TOKEN-TYPE determines where the token occurs on a statement. open indicates that the token appears at start, close indicates that it appears at end, middle indicates that it is a middle type token, and middle-or-open indicates that it can appear both as a middle or an open type.")
987
988(defconst lua-indentation-modifier-regexp
989 ;; The absence of else is deliberate, since it does not modify the
990 ;; indentation level per se. It only may cause the line, in which the
991 ;; else is, to be shifted to the left.
992 (concat
993 "\\(\\_<"
994 (regexp-opt '("do" "function" "repeat" "then" "if" "else" "elseif" "for" "while") t)
995 "\\_>\\|"
996 (regexp-opt '("{" "(" "["))
997 "\\)\\|\\(\\_<"
998 (regexp-opt '("end" "until") t)
999 "\\_>\\|"
1000 (regexp-opt '("]" ")" "}"))
1001 "\\)")
1002 )
1003
1004(defun lua-get-block-token-info (token)
1005 "Returns the block token info entry for TOKEN from lua-block-token-alist"
1006 (assoc token lua-block-token-alist))
1007
1008(defun lua-get-token-match-re (token-info direction)
1009 "Returns the relevant match regexp from token info"
1010 (cond
1011 ((eq direction 'forward) (cadr token-info))
1012 ((eq direction 'backward) (caddr token-info))
1013 (t nil)))
1014
1015(defun lua-get-token-type (token-info)
1016 "Returns the relevant match regexp from token info"
1017 (cadddr token-info))
1018
1019(defun lua-backwards-to-block-begin-or-end ()
1020 "Move backwards to nearest block begin or end. Returns nil if not successful."
1021 (interactive)
1022 (lua-find-regexp 'backward lua-block-regexp))
1023
1024(defun lua-find-matching-token-word (token &optional direction)
1025 (let* ((token-info (lua-get-block-token-info token))
1026 (match-type (lua-get-token-type token-info))
1027 ;; If we are on a middle token, go backwards. If it is a middle or open,
1028 ;; go forwards
1029 (search-direction (or direction
1030 (if (or (eq match-type 'open)
1031 (eq match-type 'middle-or-open))
1032 'forward
1033 'backward)
1034 'backward))
1035 (match (lua-get-token-match-re token-info search-direction))
1036 maybe-found-pos)
1037 ;; if we are searching forward from the token at the current point
1038 ;; (i.e. for a closing token), need to step one character forward
1039 ;; first, or the regexp will match the opening token.
1040 (if (eq search-direction 'forward) (forward-char 1))
1041 (catch 'found
1042 ;; If we are attempting to find a matching token for a terminating token
1043 ;; (i.e. a token that starts a statement when searching back, or a token
1044 ;; that ends a statement when searching forward), then we don't need to look
1045 ;; any further.
1046 (if (or (and (eq search-direction 'forward)
1047 (eq match-type 'close))
1048 (and (eq search-direction 'backward)
1049 (eq match-type 'open)))
1050 (throw 'found nil))
1051 (while (lua-find-regexp search-direction lua-indentation-modifier-regexp)
1052 ;; have we found a valid matching token?
1053 (let ((found-token (match-string 0))
1054 (found-pos (match-beginning 0)))
1055 (let ((found-type (lua-get-token-type
1056 (lua-get-block-token-info found-token))))
1057 (if (not (and match (string-match match found-token)))
1058 ;; no - then there is a nested block. If we were looking for
1059 ;; a block begin token, found-token must be a block end
1060 ;; token; likewise, if we were looking for a block end token,
1061 ;; found-token must be a block begin token, otherwise there
1062 ;; is a grammatical error in the code.
1063 (if (not (and
1064 (or (eq match-type 'middle)
1065 (eq found-type 'middle)
1066 (eq match-type 'middle-or-open)
1067 (eq found-type 'middle-or-open)
1068 (eq match-type found-type))
1069 (goto-char found-pos)
1070 (lua-find-matching-token-word found-token
1071 search-direction)))
1072 (when maybe-found-pos
1073 (goto-char maybe-found-pos)
1074 (throw 'found maybe-found-pos)))
1075 ;; yes.
1076 ;; if it is a not a middle kind, report the location
1077 (when (not (or (eq found-type 'middle)
1078 (eq found-type 'middle-or-open)))
1079 (throw 'found found-pos))
1080 ;; if it is a middle-or-open type, record location, but keep searching.
1081 ;; If we fail to complete the search, we'll report the location
1082 (when (eq found-type 'middle-or-open)
1083 (setq maybe-found-pos found-pos))
1084 ;; Cannot use tail recursion. too much nesting on long chains of
1085 ;; if/elseif. Will reset variables instead.
1086 (setq token found-token)
1087 (setq token-info (lua-get-block-token-info token))
1088 (setq match (lua-get-token-match-re token-info search-direction))
1089 (setq match-type (lua-get-token-type token-info))))))
1090 maybe-found-pos)))
1091
1092(defun lua-goto-matching-block-token (&optional parse-start direction)
1093 "Find block begion/end token matching the one at the point.
1094This function moves the point to the token that matches the one
1095at the current point. Returns the point position of the first character of
1096the matching token if successful, nil otherwise."
1097 (if parse-start (goto-char parse-start))
1098 (let ((case-fold-search nil))
1099 (if (looking-at lua-indentation-modifier-regexp)
1100 (let ((position (lua-find-matching-token-word (match-string 0)
1101 direction)))
1102 (and position
1103 (goto-char position))))))
1104
1105(defun lua-goto-matching-block (&optional noreport)
1106 "Go to the keyword balancing the one under the point.
1107If the point is on a keyword/brace that starts a block, go to the
1108matching keyword that ends the block, and vice versa."
1109 (interactive)
1110 ;; search backward to the beginning of the keyword if necessary
1111 (if (eq (char-syntax (following-char)) ?w)
1112 (re-search-backward "\\_<" nil t))
1113 (let ((position (lua-goto-matching-block-token)))
1114 (if (and (not position)
1115 (not noreport))
1116 (error "Not on a block control keyword or brace")
1117 position)))
1118
1119(defun lua-forward-line-skip-blanks (&optional back)
1120 "Move 1 line forward (back if BACK is non-nil) skipping blank lines.
1121
1122Moves point 1 line forward (or backward) skipping lines that contain
1123no Lua code besides comments. The point is put to the beginning of
1124the line.
1125
1126Returns final value of point as integer or nil if operation failed."
1127 (catch 'found
1128 (while t
1129 (unless (eql (forward-line (if back -1 1)) 0) ;; 0 means success
1130 (throw 'found nil))
1131 (unless (or (looking-at "\\s *\\(--.*\\)?$")
1132 (lua-comment-or-string-p))
1133 (throw 'found (point))))))
1134
1135(eval-when-compile
1136 (defconst lua-operator-class
1137 "-+*/^.=<>~:&|"))
1138
1139(defconst lua-cont-eol-regexp
1140 (eval-when-compile
1141 (concat
1142 "\\(\\_<"
1143 (regexp-opt '("and" "or" "not" "in" "for" "while"
1144 "local" "function" "if" "until" "elseif" "return")
1145 t)
1146 "\\_>\\|"
1147 "\\(^\\|[^" lua-operator-class "]\\)"
1148 (regexp-opt '("+" "-" "*" "/" "%" "^" ".." "=="
1149 "=" "<" ">" "<=" ">=" "~=" "." ":"
1150 "&" "|" "~" ">>" "<<" "~")
1151 t)
1152 "\\)"
1153 "\\s *\\="))
1154 "Regexp that matches the ending of a line that needs continuation
1155
1156This regexp starts from eol and looks for a binary operator or an unclosed
1157block intro (i.e. 'for' without 'do' or 'if' without 'then') followed by
1158an optional whitespace till the end of the line.")
1159
1160(defconst lua-cont-bol-regexp
1161 (eval-when-compile
1162 (concat
1163 "\\=\\s *"
1164 "\\(\\_<"
1165 (regexp-opt '("and" "or" "not") t)
1166 "\\_>\\|"
1167 (regexp-opt '("+" "-" "*" "/" "%" "^" ".." "=="
1168 "=" "<" ">" "<=" ">=" "~=" "." ":"
1169 "&" "|" "~" ">>" "<<" "~")
1170 t)
1171 "\\($\\|[^" lua-operator-class "]\\)"
1172 "\\)"))
1173 "Regexp that matches a line that continues previous one
1174
1175This regexp means, starting from point there is an optional whitespace followed
1176by Lua binary operator. Lua is very liberal when it comes to continuation line,
1177so we're safe to assume that every line that starts with a binop continues
1178previous one even though it looked like an end-of-statement.")
1179
1180(defun lua-last-token-continues-p ()
1181 "Returns true if the last token on this line is a continuation token."
1182 (let ((line-begin (line-beginning-position))
1183 (line-end (line-end-position)))
1184 (save-excursion
1185 (end-of-line)
1186 ;; we need to check whether the line ends in a comment and
1187 ;; skip that one.
1188 (while (lua-find-regexp 'backward "-" line-begin 'lua-string-p)
1189 (if (looking-at "--")
1190 (setq line-end (point))))
1191 (goto-char line-end)
1192 (re-search-backward lua-cont-eol-regexp line-begin t))))
1193
1194(defun lua-first-token-continues-p ()
1195 "Returns true if the first token on this line is a continuation token."
1196 (let ((line-end (line-end-position)))
1197 (save-excursion
1198 (beginning-of-line)
1199 ;; if first character of the line is inside string, it's a continuation
1200 ;; if strings aren't supposed to be indented, `lua-calculate-indentation' won't even let
1201 ;; the control inside this function
1202 (re-search-forward lua-cont-bol-regexp line-end t))))
1203
1204(defconst lua-block-starter-regexp
1205 (eval-when-compile
1206 (concat
1207 "\\(\\_<"
1208 (regexp-opt '("do" "while" "repeat" "until" "if" "then"
1209 "else" "elseif" "end" "for" "local") t)
1210 "\\_>\\)")))
1211
1212(defun lua-first-token-starts-block-p ()
1213 "Returns true if the first token on this line is a block starter token."
1214 (let ((line-end (line-end-position)))
1215 (save-excursion
1216 (beginning-of-line)
1217 (re-search-forward (concat "\\s *" lua-block-starter-regexp) line-end t))))
1218
1219(defun lua-is-continuing-statement-p (&optional parse-start)
1220 "Return non-nil if the line continues a statement.
1221More specifically, return the point in the line that is continued.
1222The criteria for a continuing statement are:
1223
1224* the last token of the previous line is a continuing op,
1225 OR the first token of the current line is a continuing op
1226
1227"
1228 (let ((prev-line nil))
1229 (save-excursion
1230 (if parse-start (goto-char parse-start))
1231 (save-excursion (setq prev-line (lua-forward-line-skip-blanks 'back)))
1232 (and prev-line
1233 (not (lua-first-token-starts-block-p))
1234 (or (lua-first-token-continues-p)
1235 (and (goto-char prev-line)
1236 ;; check last token of previous nonblank line
1237 (lua-last-token-continues-p)))))))
1238
1239(defun lua-make-indentation-info-pair (found-token found-pos)
1240 "This is a helper function to lua-calculate-indentation-info. Don't
1241use standalone."
1242 (cond
1243 ;; function is a bit tricky to indent right. They can appear in a lot ot
1244 ;; different contexts. Until I find a shortcut, I'll leave it with a simple
1245 ;; relative indentation.
1246 ;; The special cases are for indenting according to the location of the
1247 ;; function. i.e.:
1248 ;; (cons 'absolute (+ (current-column) lua-indent-level))
1249 ;; TODO: Fix this. It causes really ugly indentations for in-line functions.
1250 ((string-equal found-token "function")
1251 (cons 'relative lua-indent-level))
1252
1253 ;; block openers
1254 ((member found-token (list "{" "(" "["))
1255 (save-excursion
1256 (let ((found-bol (line-beginning-position)))
1257 (forward-comment (point-max))
1258 ;; If the next token is on this line and it's not a block opener,
1259 ;; the next line should align to that token.
1260 (if (and (zerop (count-lines found-bol (line-beginning-position)))
1261 (not (looking-at lua-indentation-modifier-regexp)))
1262 (cons 'absolute (current-column))
1263 (cons 'relative lua-indent-level)))))
1264
1265 ;; These are not really block starters. They should not add to indentation.
1266 ;; The corresponding "then" and "do" handle the indentation.
1267 ((member found-token (list "if" "for" "while"))
1268 (cons 'relative 0))
1269 ;; closing tokens follow: These are usually taken care of by
1270 ;; lua-calculate-indentation-override.
1271 ;; elseif is a bit of a hack. It is not handled separately, but it needs to
1272 ;; nullify a previous then if on the same line.
1273 ((member found-token (list "until" "elseif"))
1274 (save-excursion
1275 (let ((line (line-number-at-pos)))
1276 (if (and (lua-goto-matching-block-token found-pos 'backward)
1277 (= line (line-number-at-pos)))
1278 (cons 'remove-matching 0)
1279 (cons 'relative 0)))))
1280
1281 ;; else is a special case; if its matching block token is on the same line,
1282 ;; instead of removing the matching token, it has to replace it, so that
1283 ;; either the next line will be indented correctly, or the end on the same
1284 ;; line will remove the effect of the else.
1285 ((string-equal found-token "else")
1286 (save-excursion
1287 (let ((line (line-number-at-pos)))
1288 (if (and (lua-goto-matching-block-token found-pos 'backward)
1289 (= line (line-number-at-pos)))
1290 (cons 'replace-matching (cons 'relative lua-indent-level))
1291 (cons 'relative lua-indent-level)))))
1292
1293 ;; Block closers. If they are on the same line as their openers, they simply
1294 ;; eat up the matching indentation modifier. Otherwise, they pull
1295 ;; indentation back to the matching block opener.
1296 ((member found-token (list ")" "}" "]" "end"))
1297 (save-excursion
1298 (let ((line (line-number-at-pos)))
1299 (lua-goto-matching-block-token found-pos 'backward)
1300 (if (/= line (line-number-at-pos))
1301 (lua-calculate-indentation-info (point))
1302 (cons 'remove-matching 0)))))
1303
1304 ;; Everything else. This is from the original code: If opening a block
1305 ;; (match-data 1 exists), then push indentation one level up, if it is
1306 ;; closing a block, pull it one level down.
1307 ('other-indentation-modifier
1308 (cons 'relative (if (nth 2 (match-data))
1309 ;; beginning of a block matched
1310 lua-indent-level
1311 ;; end of a block matched
1312 (- lua-indent-level))))))
1313
1314(defun lua-add-indentation-info-pair (pair info)
1315 "Add the given indentation info pair to the list of indentation information.
1316This function has special case handling for two tokens: remove-matching,
1317and replace-matching. These two tokens are cleanup tokens that remove or
1318alter the effect of a previously recorded indentation info.
1319
1320When a remove-matching token is encountered, the last recorded info, i.e.
1321the car of the list is removed. This is used to roll-back an indentation of a
1322block opening statement when it is closed.
1323
1324When a replace-matching token is seen, the last recorded info is removed,
1325and the cdr of the replace-matching info is added in its place. This is used
1326when a middle-of the block (the only case is 'else') is seen on the same line
1327the block is opened."
1328 (cond
1329 ( (eq 'remove-matching (car pair))
1330 ; Remove head of list
1331 (cdr info))
1332 ( (eq 'replace-matching (car pair))
1333 ; remove head of list, and add the cdr of pair instead
1334 (cons (cdr pair) (cdr info)))
1335 ( (listp (cdr-safe pair))
1336 (nconc pair info))
1337 ( t
1338 ; Just add the pair
1339 (cons pair info))))
1340
1341(defun lua-calculate-indentation-info-1 (indentation-info bound)
1342 "Helper function for `lua-calculate-indentation-info'.
1343
1344Return list of indentation modifiers from point to BOUND."
1345 (while (lua-find-regexp 'forward lua-indentation-modifier-regexp
1346 bound)
1347 (let ((found-token (match-string 0))
1348 (found-pos (match-beginning 0))
1349 (found-end (match-end 0))
1350 (data (match-data)))
1351 (setq indentation-info
1352 (lua-add-indentation-info-pair
1353 (lua-make-indentation-info-pair found-token found-pos)
1354 indentation-info))))
1355 indentation-info)
1356
1357
1358(defun lua-calculate-indentation-info (&optional parse-end)
1359 "For each block token on the line, computes how it affects the indentation.
1360The effect of each token can be either a shift relative to the current
1361indentation level, or indentation to some absolute column. This information
1362is collected in a list of indentation info pairs, which denote absolute
1363and relative each, and the shift/column to indent to."
1364 (let ((combined-line-end (line-end-position))
1365 indentation-info)
1366
1367 (while (lua-is-continuing-statement-p)
1368 (lua-forward-line-skip-blanks 'back))
1369
1370 ;; calculate indentation modifiers for the line itself
1371 (setq indentation-info (list (cons 'absolute (current-indentation))))
1372
1373 (back-to-indentation)
1374 (setq indentation-info
1375 (lua-calculate-indentation-info-1
1376 indentation-info (min parse-end (line-end-position))))
1377
1378 ;; and do the following for each continuation line before PARSE-END
1379 (while (and (eql (forward-line 1) 0)
1380 (<= (point) parse-end))
1381
1382 ;; handle continuation lines:
1383 (if (lua-is-continuing-statement-p)
1384 ;; if it's the first continuation line, add one level
1385 (unless (eq (car (car indentation-info)) 'continued-line)
1386 (push (cons 'continued-line lua-indent-level) indentation-info))
1387
1388 ;; if it's the first non-continued line, subtract one level
1389 (when (eq (car (car indentation-info)) 'continued-line)
1390 (pop indentation-info)))
1391
1392 ;; add modifiers found in this continuation line
1393 (setq indentation-info
1394 (lua-calculate-indentation-info-1
1395 indentation-info (min parse-end (line-end-position)))))
1396
1397 indentation-info))
1398
1399
1400(defun lua-accumulate-indentation-info (info)
1401 "Accumulates the indentation information previously calculated by
1402lua-calculate-indentation-info. Returns either the relative indentation
1403shift, or the absolute column to indent to."
1404 (let ((info-list (reverse info))
1405 (type 'relative)
1406 (accu 0))
1407 (mapc (lambda (x)
1408 (setq accu (if (eq 'absolute (car x))
1409 (progn (setq type 'absolute)
1410 (cdr x))
1411 (+ accu (cdr x)))))
1412 info-list)
1413 (cons type accu)))
1414
1415(defun lua-calculate-indentation-block-modifier (&optional parse-end)
1416 "Return amount by which this line modifies the indentation.
1417Beginnings of blocks add lua-indent-level once each, and endings
1418of blocks subtract lua-indent-level once each. This function is used
1419to determine how the indentation of the following line relates to this
1420one."
1421 (let (indentation-info)
1422 (save-excursion
1423 ;; First go back to the line that starts it all
1424 ;; lua-calculate-indentation-info will scan through the whole thing
1425 (let ((case-fold-search nil))
1426 (setq indentation-info
1427 (lua-accumulate-indentation-info
1428 (lua-calculate-indentation-info parse-end)))))
1429
1430 (if (eq (car indentation-info) 'absolute)
1431 (- (cdr indentation-info) (current-indentation))
1432 (cdr indentation-info))))
1433
1434
1435(eval-when-compile
1436 (defconst lua--function-name-rx
1437 '(seq symbol-start
1438 (+ (any alnum "_"))
1439 (* "." (+ (any alnum "_")))
1440 (? ":" (+ (any alnum "_")))
1441 symbol-end)
1442 "Lua function name regexp in `rx'-SEXP format."))
1443
1444
1445(defconst lua--left-shifter-regexp
1446 (eval-when-compile
1447 (rx
1448 ;; This regexp should answer the following questions:
1449 ;; 1. is there a left shifter regexp on that line?
1450 ;; 2. where does block-open token of that left shifter reside?
1451 (or (seq (group-n 1 symbol-start "local" (+ blank)) "function" symbol-end)
1452
1453 (seq (group-n 1 (eval lua--function-name-rx) (* blank)) (any "{("))
1454 (seq (group-n 1 (or
1455 ;; assignment statement prefix
1456 (seq (* nonl) (not (any "<=>~")) "=" (* blank))
1457 ;; return statement prefix
1458 (seq word-start "return" word-end (* blank))))
1459 ;; right hand side
1460 (or "{"
1461 "function"
1462 (seq (group-n 1 (eval lua--function-name-rx) (* blank))
1463 (any "({")))))))
1464
1465 "Regular expression that matches left-shifter expression.
1466
1467Left-shifter expression is defined as follows. If a block
1468follows a left-shifter expression, its contents & block-close
1469token should be indented relative to left-shifter expression
1470indentation rather then to block-open token.
1471
1472For example:
1473 -- 'local a = ' is a left-shifter expression
1474 -- 'function' is a block-open token
1475 local a = function()
1476 -- block contents is indented relative to left-shifter
1477 foobarbaz()
1478 -- block-end token is unindented to left-shifter indentation
1479 end
1480
1481The following left-shifter expressions are currently handled:
14821. local function definition with function block, begin-end
14832. function call with arguments block, () or {}
14843. assignment/return statement with
1485 - table constructor block, {}
1486 - function call arguments block, () or {} block
1487 - function expression a.k.a. lambda, begin-end block.")
1488
1489
1490(defun lua-point-is-after-left-shifter-p ()
1491 "Check if point is right after a left-shifter expression.
1492
1493See `lua--left-shifter-regexp' for description & example of
1494left-shifter expression. "
1495 (save-excursion
1496 (let ((old-point (point)))
1497 (back-to-indentation)
1498 (and
1499 (/= (point) old-point)
1500 (looking-at lua--left-shifter-regexp)
1501 (= old-point (match-end 1))))))
1502
1503
1504
1505(defun lua-calculate-indentation-override (&optional parse-start)
1506 "Return overriding indentation amount for special cases.
1507
1508If there's a sequence of block-close tokens starting at the
1509beginning of the line, calculate indentation according to the
1510line containing block-open token for the last block-close token
1511in the sequence.
1512
1513If not, return nil."
1514 (let (case-fold-search token-info block-token-pos)
1515 (save-excursion
1516 (if parse-start (goto-char parse-start))
1517
1518 (back-to-indentation)
1519 (unless (lua-comment-or-string-p)
1520 (while
1521 (and (looking-at lua-indentation-modifier-regexp)
1522 (setq token-info (lua-get-block-token-info (match-string 0)))
1523 (not (eq 'open (lua-get-token-type token-info))))
1524 (setq block-token-pos (match-beginning 0))
1525 (goto-char (match-end 0))
1526 (skip-syntax-forward " " (line-end-position)))
1527
1528 (when (lua-goto-matching-block-token block-token-pos 'backward)
1529 ;; Exception cases: when the start of the line is an assignment,
1530 ;; go to the start of the assignment instead of the matching item
1531 (if (lua-point-is-after-left-shifter-p)
1532 (current-indentation)
1533 (current-column)))))))
1534
1535(defun lua-calculate-indentation (&optional parse-start)
1536 "Return appropriate indentation for current line as Lua code."
1537 (save-excursion
1538 (let ((continuing-p (lua-is-continuing-statement-p))
1539 (cur-line-begin-pos (line-beginning-position)))
1540 (or
1541 ;; when calculating indentation, do the following:
1542 ;; 1. check, if the line starts with indentation-modifier (open/close brace)
1543 ;; and if it should be indented/unindented in special way
1544 (lua-calculate-indentation-override)
1545
1546 (when (lua-forward-line-skip-blanks 'back)
1547 ;; the order of function calls here is important. block modifier
1548 ;; call may change the point to another line
1549 (let* ((modifier
1550 (lua-calculate-indentation-block-modifier cur-line-begin-pos)))
1551 (+ (current-indentation) modifier)))
1552
1553 ;; 4. if there's no previous line, indentation is 0
1554 0))))
1555
1556(defvar lua--beginning-of-defun-re
1557 (lua-rx-to-string '(: bol (? (symbol "local") ws+) lua-funcheader))
1558 "Lua top level (matches only at the beginning of line) function header regex.")
1559
1560
1561(defun lua-beginning-of-proc (&optional arg)
1562 "Move backward to the beginning of a Lua proc (or similar).
1563
1564With argument, do it that many times. Negative arg -N
1565means move forward to Nth following beginning of proc.
1566
1567Returns t unless search stops due to beginning or end of buffer."
1568 (interactive "P")
1569 (or arg (setq arg 1))
1570
1571 (while (and (> arg 0)
1572 (re-search-backward lua--beginning-of-defun-re nil t))
1573 (setq arg (1- arg)))
1574
1575 (while (and (< arg 0)
1576 (re-search-forward lua--beginning-of-defun-re nil t))
1577 (beginning-of-line)
1578 (setq arg (1+ arg)))
1579
1580 (zerop arg))
1581
1582(defun lua-end-of-proc (&optional arg)
1583 "Move forward to next end of Lua proc (or similar).
1584With argument, do it that many times. Negative argument -N means move
1585back to Nth preceding end of proc.
1586
1587This function just searches for a `end' at the beginning of a line."
1588 (interactive "P")
1589 (or arg
1590 (setq arg 1))
1591 (let ((found nil)
1592 (ret t))
1593 (if (and (< arg 0)
1594 (not (bolp))
1595 (save-excursion
1596 (beginning-of-line)
1597 (eq (following-char) ?})))
1598 (forward-char -1))
1599 (while (> arg 0)
1600 (if (re-search-forward "^end" nil t)
1601 (setq arg (1- arg)
1602 found t)
1603 (setq ret nil
1604 arg 0)))
1605 (while (< arg 0)
1606 (if (re-search-backward "^end" nil t)
1607 (setq arg (1+ arg)
1608 found t)
1609 (setq ret nil
1610 arg 0)))
1611 (if found
1612 (progn
1613 (beginning-of-line)
1614 (forward-line)))
1615 ret))
1616
1617(defvar lua-process-init-code
1618 (mapconcat
1619 'identity
1620 '("local loadstring = loadstring or load"
1621 "function luamode_loadstring(str, displayname, lineoffset)"
1622 " if lineoffset > 1 then"
1623 " str = string.rep('\\n', lineoffset - 1) .. str"
1624 " end"
1625 ""
1626 " local x, e = loadstring(str, '@'..displayname)"
1627 " if e then"
1628 " error(e)"
1629 " end"
1630 " return x()"
1631 "end")
1632 " "))
1633
1634(defun lua-make-lua-string (str)
1635 "Convert string to Lua literal."
1636 (save-match-data
1637 (with-temp-buffer
1638 (insert str)
1639 (goto-char (point-min))
1640 (while (re-search-forward "[\"'\\\t\\\n]" nil t)
1641 (cond
1642 ((string= (match-string 0) "\n")
1643 (replace-match "\\\\n"))
1644 ((string= (match-string 0) "\t")
1645 (replace-match "\\\\t"))
1646 (t
1647 (replace-match "\\\\\\&" t))))
1648 (concat "'" (buffer-string) "'"))))
1649
1650;;;###autoload
1651(defalias 'run-lua #'lua-start-process)
1652
1653;;;###autoload
1654(defun lua-start-process (&optional name program startfile &rest switches)
1655 "Start a Lua process named NAME, running PROGRAM.
1656PROGRAM defaults to NAME, which defaults to `lua-default-application'.
1657When called interactively, switch to the process buffer."
1658 (interactive)
1659 (or switches
1660 (setq switches lua-default-command-switches))
1661 (setq name (or name (if (consp lua-default-application)
1662 (car lua-default-application)
1663 lua-default-application)))
1664 (setq program (or program lua-default-application))
1665 (setq lua-process-buffer (apply 'make-comint name program startfile switches))
1666 (setq lua-process (get-buffer-process lua-process-buffer))
1667 (set-process-query-on-exit-flag lua-process nil)
1668 (with-current-buffer lua-process-buffer
1669 ;; wait for prompt
1670 (while (not (lua-prompt-line))
1671 (accept-process-output (get-buffer-process (current-buffer)))
1672 (goto-char (point-max)))
1673 ;; send initialization code
1674 (lua-send-string lua-process-init-code)
1675
1676 ;; enable error highlighting in stack traces
1677 (require 'compile)
1678 (setq lua--repl-buffer-p t)
1679 (make-local-variable 'compilation-error-regexp-alist)
1680 (setq compilation-error-regexp-alist
1681 (cons (list lua-traceback-line-re 1 2)
1682 compilation-error-regexp-alist))
1683 (compilation-shell-minor-mode 1))
1684
1685 ;; when called interactively, switch to process buffer
1686 (if (called-interactively-p 'any)
1687 (switch-to-buffer lua-process-buffer)))
1688
1689(defun lua-get-create-process ()
1690 "Return active Lua process creating one if necessary."
1691 (unless (comint-check-proc lua-process-buffer)
1692 (lua-start-process))
1693 lua-process)
1694
1695(defun lua-kill-process ()
1696 "Kill Lua process and its buffer."
1697 (interactive)
1698 (when (buffer-live-p lua-process-buffer)
1699 (kill-buffer lua-process-buffer)
1700 (setq lua-process-buffer nil)))
1701
1702(defun lua-set-lua-region-start (&optional arg)
1703 "Set start of region for use with `lua-send-lua-region'."
1704 (interactive)
1705 (set-marker lua-region-start (or arg (point))))
1706
1707(defun lua-set-lua-region-end (&optional arg)
1708 "Set end of region for use with `lua-send-lua-region'."
1709 (interactive)
1710 (set-marker lua-region-end (or arg (point))))
1711
1712(defun lua-send-string (str)
1713 "Send STR plus a newline to the Lua process.
1714
1715If `lua-process' is nil or dead, start a new process first."
1716 (unless (string-equal (substring str -1) "\n")
1717 (setq str (concat str "\n")))
1718 (process-send-string (lua-get-create-process) str))
1719
1720(defun lua-send-current-line ()
1721 "Send current line to the Lua process, found in `lua-process'.
1722If `lua-process' is nil or dead, start a new process first."
1723 (interactive)
1724 (lua-send-region (line-beginning-position) (line-end-position)))
1725
1726(defun lua-send-defun (pos)
1727 "Send the function definition around point to the Lua process."
1728 (interactive "d")
1729 (save-excursion
1730 (let ((start (if (save-match-data (looking-at "^function[ \t]"))
1731 ;; point already at the start of "function".
1732 ;; We need to handle this case explicitly since
1733 ;; lua-beginning-of-proc will move to the
1734 ;; beginning of the _previous_ function.
1735 (point)
1736 ;; point is not at the beginning of function, move
1737 ;; there and bind start to that position
1738 (lua-beginning-of-proc)
1739 (point)))
1740 (end (progn (lua-end-of-proc) (point))))
1741
1742 ;; make sure point is in a function definition before sending to
1743 ;; the process
1744 (if (and (>= pos start) (< pos end))
1745 (lua-send-region start end)
1746 (error "Not on a function definition")))))
1747
1748(defun lua-maybe-skip-shebang-line (start)
1749 "Skip shebang (#!/path/to/interpreter/) line at beginning of buffer.
1750
1751Return a position that is after Lua-recognized shebang line (1st
1752character in file must be ?#) if START is at its beginning.
1753Otherwise, return START."
1754 (save-restriction
1755 (widen)
1756 (if (and (eq start (point-min))
1757 (eq (char-after start) ?#))
1758 (save-excursion
1759 (goto-char start)
1760 (forward-line)
1761 (point))
1762 start)))
1763
1764(defun lua-send-region (start end)
1765 (interactive "r")
1766 (setq start (lua-maybe-skip-shebang-line start))
1767 (let* ((lineno (line-number-at-pos start))
1768 (lua-file (or (buffer-file-name) (buffer-name)))
1769 (region-str (buffer-substring-no-properties start end))
1770 (command
1771 ;; Print empty line before executing the code so that the first line
1772 ;; of output doesn't end up on the same line as current prompt.
1773 (format "print(''); luamode_loadstring(%s, %s, %s);\n"
1774 (lua-make-lua-string region-str)
1775 (lua-make-lua-string lua-file)
1776 lineno)))
1777 (lua-send-string command)
1778 (when lua-always-show (lua-show-process-buffer))))
1779
1780(defun lua-prompt-line ()
1781 (save-excursion
1782 (save-match-data
1783 (forward-line 0)
1784 (if (looking-at comint-prompt-regexp)
1785 (match-end 0)))))
1786
1787(defun lua-send-lua-region ()
1788 "Send preset Lua region to Lua process."
1789 (interactive)
1790 (unless (and lua-region-start lua-region-end)
1791 (error "lua-region not set"))
1792 (lua-send-region lua-region-start lua-region-end))
1793
1794(defalias 'lua-send-proc 'lua-send-defun)
1795
1796(defun lua-send-buffer ()
1797 "Send whole buffer to Lua process."
1798 (interactive)
1799 (lua-send-region (point-min) (point-max)))
1800
1801(defun lua-restart-with-whole-file ()
1802 "Restart Lua process and send whole file as input."
1803 (interactive)
1804 (lua-kill-process)
1805 (lua-send-buffer))
1806
1807(defun lua-show-process-buffer ()
1808 "Make sure `lua-process-buffer' is being displayed.
1809Create a Lua process if one doesn't already exist."
1810 (interactive)
1811 (display-buffer (process-buffer (lua-get-create-process))))
1812
1813
1814(defun lua-hide-process-buffer ()
1815 "Delete all windows that display `lua-process-buffer'."
1816 (interactive)
1817 (when (buffer-live-p lua-process-buffer)
1818 (delete-windows-on lua-process-buffer)))
1819
1820(defun lua-funcname-at-point ()
1821 "Get current Name { '.' Name } sequence."
1822 ;; FIXME: copying/modifying syntax table for each call may incur a penalty
1823 (with-syntax-table (copy-syntax-table)
1824 (modify-syntax-entry ?. "_")
1825 (current-word t)))
1826
1827(defun lua-search-documentation ()
1828 "Search Lua documentation for the word at the point."
1829 (interactive)
1830 (let ((url (concat lua-documentation-url "#pdf-" (lua-funcname-at-point))))
1831 (funcall lua-documentation-function url)))
1832
1833(defun lua-toggle-electric-state (&optional arg)
1834 "Toggle the electric indentation feature.
1835Optional numeric ARG, if supplied, turns on electric indentation when
1836positive, turns it off when negative, and just toggles it when zero or
1837left out."
1838 (interactive "P")
1839 (let ((num_arg (prefix-numeric-value arg)))
1840 (setq lua-electric-flag (cond ((or (null arg)
1841 (zerop num_arg)) (not lua-electric-flag))
1842 ((< num_arg 0) nil)
1843 ((> num_arg 0) t))))
1844 (message "%S" lua-electric-flag))
1845
1846(defun lua-forward-sexp (&optional count)
1847 "Forward to block end"
1848 (interactive "p")
1849 ;; negative offsets not supported
1850 (assert (or (not count) (>= count 0)))
1851 (save-match-data
1852 (let* ((count (or count 1))
1853 (block-start (mapcar 'car lua-sexp-alist))
1854 (block-end (mapcar 'cdr lua-sexp-alist))
1855 (block-regex (regexp-opt (append block-start block-end) 'words))
1856 current-exp)
1857 (while (> count 0)
1858 ;; skip whitespace
1859 (skip-chars-forward " \t\n")
1860 (if (looking-at (regexp-opt block-start 'words))
1861 (let ((keyword (match-string 1)))
1862 (lua-find-matching-token-word keyword 'forward))
1863 ;; If the current keyword is not a "begin" keyword, then just
1864 ;; perform the normal forward-sexp.
1865 (forward-sexp 1))
1866 (setq count (1- count))))))
1867
1868
1869;; menu bar
1870
1871(define-key lua-mode-menu [restart-with-whole-file]
1872 '("Restart With Whole File" . lua-restart-with-whole-file))
1873(define-key lua-mode-menu [kill-process]
1874 '("Kill Process" . lua-kill-process))
1875
1876(define-key lua-mode-menu [hide-process-buffer]
1877 '("Hide Process Buffer" . lua-hide-process-buffer))
1878(define-key lua-mode-menu [show-process-buffer]
1879 '("Show Process Buffer" . lua-show-process-buffer))
1880
1881(define-key lua-mode-menu [end-of-proc]
1882 '("End Of Proc" . lua-end-of-proc))
1883(define-key lua-mode-menu [beginning-of-proc]
1884 '("Beginning Of Proc" . lua-beginning-of-proc))
1885
1886(define-key lua-mode-menu [send-lua-region]
1887 '("Send Lua-Region" . lua-send-lua-region))
1888(define-key lua-mode-menu [set-lua-region-end]
1889 '("Set Lua-Region End" . lua-set-lua-region-end))
1890(define-key lua-mode-menu [set-lua-region-start]
1891 '("Set Lua-Region Start" . lua-set-lua-region-start))
1892
1893(define-key lua-mode-menu [send-current-line]
1894 '("Send Current Line" . lua-send-current-line))
1895(define-key lua-mode-menu [send-region]
1896 '("Send Region" . lua-send-region))
1897(define-key lua-mode-menu [send-proc]
1898 '("Send Proc" . lua-send-proc))
1899(define-key lua-mode-menu [send-buffer]
1900 '("Send Buffer" . lua-send-buffer))
1901(define-key lua-mode-menu [search-documentation]
1902 '("Search Documentation" . lua-search-documentation))
1903
1904
1905(provide 'lua-mode)
1906
1907;;; lua-mode.el ends here