diff options
Diffstat (limited to '.emacs.d/lisp')
| -rw-r--r-- | .emacs.d/lisp/lua-mode.el | 1907 | ||||
| -rw-r--r-- | .emacs.d/lisp/php-mode.el | 81 | ||||
| -rw-r--r-- | .emacs.d/lisp/php-project.el | 47 | ||||
| -rw-r--r-- | .emacs.d/lisp/yasnippet.el | 82 |
4 files changed, 2074 insertions, 43 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 | |||
| 110 | See `rx-to-string' documentation for more information FORM and | ||
| 111 | NO-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 | |||
| 118 | See `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 | |||
| 129 | FORM is a cons (NAME . DEFN), see more in `rx-constituents' doc. | ||
| 130 | This function enables specifying new definitions using old ones: | ||
| 131 | if DEFN is a list that starts with `:rx' symbol its second | ||
| 132 | element 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'. | ||
| 210 | Should 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 | |||
| 273 | If 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. | ||
| 345 | Usually, 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. | ||
| 358 | Otherwise 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 | ||
| 364 | variable is non-nil and a traceback occurs when running Lua code in a | ||
| 365 | process, jump immediately to the source code of the innermost | ||
| 366 | traceback 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 | |||
| 468 | This is a compilation of 5.1, 5.2 and 5.3 builtins taken from the | ||
| 469 | index 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 | |||
| 475 | It's supposed to match sequences with following EBNF: | ||
| 476 | |||
| 477 | ELT-REGEXP { SEP-REGEXP ELT-REGEXP } END-REGEXP | ||
| 478 | |||
| 479 | The sequence is parsed one token at a time. If non-nil is | ||
| 480 | returned, `match-data' will have one or more of the following | ||
| 481 | groups set according to next matched token: | ||
| 482 | |||
| 483 | 1. matched element token | ||
| 484 | 2. unmatched garbage characters | ||
| 485 | 3. misplaced token (i.e. SEP-REGEXP when ELT-REGEXP is expected) | ||
| 486 | 4. matched separator token | ||
| 487 | 5. matched end token | ||
| 488 | |||
| 489 | Blanks & comments between tokens are silently skipped. | ||
| 490 | Groups 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 | |||
| 783 | This 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 | |||
| 796 | If 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 | |||
| 807 | If 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 | |||
| 821 | Basically, detect form of close bracket from syntactic | ||
| 822 | information 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 | |||
| 843 | Find next opening long bracket outside of any string/comment. | ||
| 844 | If 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 | |||
| 881 | Intended 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. | ||
| 895 | Return 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. | ||
| 937 | Direction is one of 'forward and 'backward. | ||
| 938 | By default, matches in comments and strings are ignored, but what to ignore is | ||
| 939 | configurable by specifying ignore-p. If the regexp is found, returns point | ||
| 940 | position, nil otherwise. | ||
| 941 | ignore-p returns true if the match at the current point position should be | ||
| 942 | ignored, 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. | ||
| 981 | Each token information entry is of the form: | ||
| 982 | KEYWORD FORWARD-MATCH-REGEXP BACKWARDS-MATCH-REGEXP TOKEN-TYPE | ||
| 983 | KEYWORD is the token. | ||
| 984 | FORWARD-MATCH-REGEXP is a regexp that matches all possble tokens when going forward. | ||
| 985 | BACKWARDS-MATCH-REGEXP is a regexp that matches all possble tokens when going backwards. | ||
| 986 | TOKEN-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. | ||
| 1094 | This function moves the point to the token that matches the one | ||
| 1095 | at the current point. Returns the point position of the first character of | ||
| 1096 | the 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. | ||
| 1107 | If the point is on a keyword/brace that starts a block, go to the | ||
| 1108 | matching 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 | |||
| 1122 | Moves point 1 line forward (or backward) skipping lines that contain | ||
| 1123 | no Lua code besides comments. The point is put to the beginning of | ||
| 1124 | the line. | ||
| 1125 | |||
| 1126 | Returns 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 | |||
| 1156 | This regexp starts from eol and looks for a binary operator or an unclosed | ||
| 1157 | block intro (i.e. 'for' without 'do' or 'if' without 'then') followed by | ||
| 1158 | an 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 | |||
| 1175 | This regexp means, starting from point there is an optional whitespace followed | ||
| 1176 | by Lua binary operator. Lua is very liberal when it comes to continuation line, | ||
| 1177 | so we're safe to assume that every line that starts with a binop continues | ||
| 1178 | previous 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. | ||
| 1221 | More specifically, return the point in the line that is continued. | ||
| 1222 | The 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 | ||
| 1241 | use 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. | ||
| 1316 | This function has special case handling for two tokens: remove-matching, | ||
| 1317 | and replace-matching. These two tokens are cleanup tokens that remove or | ||
| 1318 | alter the effect of a previously recorded indentation info. | ||
| 1319 | |||
| 1320 | When a remove-matching token is encountered, the last recorded info, i.e. | ||
| 1321 | the car of the list is removed. This is used to roll-back an indentation of a | ||
| 1322 | block opening statement when it is closed. | ||
| 1323 | |||
| 1324 | When a replace-matching token is seen, the last recorded info is removed, | ||
| 1325 | and the cdr of the replace-matching info is added in its place. This is used | ||
| 1326 | when a middle-of the block (the only case is 'else') is seen on the same line | ||
| 1327 | the 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 | |||
| 1344 | Return 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. | ||
| 1360 | The effect of each token can be either a shift relative to the current | ||
| 1361 | indentation level, or indentation to some absolute column. This information | ||
| 1362 | is collected in a list of indentation info pairs, which denote absolute | ||
| 1363 | and 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 | ||
| 1402 | lua-calculate-indentation-info. Returns either the relative indentation | ||
| 1403 | shift, 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. | ||
| 1417 | Beginnings of blocks add lua-indent-level once each, and endings | ||
| 1418 | of blocks subtract lua-indent-level once each. This function is used | ||
| 1419 | to determine how the indentation of the following line relates to this | ||
| 1420 | one." | ||
| 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 | |||
| 1467 | Left-shifter expression is defined as follows. If a block | ||
| 1468 | follows a left-shifter expression, its contents & block-close | ||
| 1469 | token should be indented relative to left-shifter expression | ||
| 1470 | indentation rather then to block-open token. | ||
| 1471 | |||
| 1472 | For 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 | |||
| 1481 | The following left-shifter expressions are currently handled: | ||
| 1482 | 1. local function definition with function block, begin-end | ||
| 1483 | 2. function call with arguments block, () or {} | ||
| 1484 | 3. 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 | |||
| 1493 | See `lua--left-shifter-regexp' for description & example of | ||
| 1494 | left-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 | |||
| 1508 | If there's a sequence of block-close tokens starting at the | ||
| 1509 | beginning of the line, calculate indentation according to the | ||
| 1510 | line containing block-open token for the last block-close token | ||
| 1511 | in the sequence. | ||
| 1512 | |||
| 1513 | If 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 | |||
| 1564 | With argument, do it that many times. Negative arg -N | ||
| 1565 | means move forward to Nth following beginning of proc. | ||
| 1566 | |||
| 1567 | Returns 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). | ||
| 1584 | With argument, do it that many times. Negative argument -N means move | ||
| 1585 | back to Nth preceding end of proc. | ||
| 1586 | |||
| 1587 | This 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. | ||
| 1656 | PROGRAM defaults to NAME, which defaults to `lua-default-application'. | ||
| 1657 | When 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 | |||
| 1715 | If `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'. | ||
| 1722 | If `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 | |||
| 1751 | Return a position that is after Lua-recognized shebang line (1st | ||
| 1752 | character in file must be ?#) if START is at its beginning. | ||
| 1753 | Otherwise, 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. | ||
| 1809 | Create 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. | ||
| 1835 | Optional numeric ARG, if supplied, turns on electric indentation when | ||
| 1836 | positive, turns it off when negative, and just toggles it when zero or | ||
| 1837 | left 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 | ||
diff --git a/.emacs.d/lisp/php-mode.el b/.emacs.d/lisp/php-mode.el index e1b2597..79bf356 100644 --- a/.emacs.d/lisp/php-mode.el +++ b/.emacs.d/lisp/php-mode.el | |||
| @@ -1,5 +1,6 @@ | |||
| 1 | ;;; php-mode.el --- Major mode for editing PHP code | 1 | ;;; php-mode.el --- Major mode for editing PHP code |
| 2 | 2 | ||
| 3 | ;; Copyright (C) 2018 Friends of Emacs-PHP development | ||
| 3 | ;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad | 4 | ;; Copyright (C) 1999, 2000, 2001, 2003, 2004 Turadg Aleahmad |
| 4 | ;; 2008 Aaron S. Hawley | 5 | ;; 2008 Aaron S. Hawley |
| 5 | ;; 2011, 2012, 2013, 2014, 2015, 2016, 2017 Eric James Michael Ritz | 6 | ;; 2011, 2012, 2013, 2014, 2015, 2016, 2017 Eric James Michael Ritz |
| @@ -8,14 +9,14 @@ | |||
| 8 | ;; Maintainer: USAMI Kenta <tadsan@zonu.me> | 9 | ;; Maintainer: USAMI Kenta <tadsan@zonu.me> |
| 9 | ;; URL: https://github.com/emacs-php/php-mode | 10 | ;; URL: https://github.com/emacs-php/php-mode |
| 10 | ;; Keywords: languages php | 11 | ;; Keywords: languages php |
| 11 | ;; Version: 1.19.1 | 12 | ;; Version: 1.20.0 |
| 12 | ;; Package-Requires: ((emacs "24.3") (cl-lib "0.5")) | 13 | ;; Package-Requires: ((emacs "24.3") (cl-lib "0.5")) |
| 13 | ;; License: GPL-3.0-or-later | 14 | ;; License: GPL-3.0-or-later |
| 14 | 15 | ||
| 15 | (defconst php-mode-version-number "1.19.1" | 16 | (defconst php-mode-version-number "1.20.0" |
| 16 | "PHP Mode version number.") | 17 | "PHP Mode version number.") |
| 17 | 18 | ||
| 18 | (defconst php-mode-modified "2018-08-28" | 19 | (defconst php-mode-modified "2018-12-05" |
| 19 | "PHP Mode build date.") | 20 | "PHP Mode build date.") |
| 20 | 21 | ||
| 21 | ;; This file is free software; you can redistribute it and/or | 22 | ;; This file is free software; you can redistribute it and/or |
| @@ -92,6 +93,7 @@ | |||
| 92 | 93 | ||
| 93 | (eval-when-compile | 94 | (eval-when-compile |
| 94 | (require 'regexp-opt) | 95 | (require 'regexp-opt) |
| 96 | (autoload 'pkg-info-version-info "pkg-info") | ||
| 95 | (defvar c-vsemi-status-unknown-p) | 97 | (defvar c-vsemi-status-unknown-p) |
| 96 | (defvar syntax-propertize-via-font-lock)) | 98 | (defvar syntax-propertize-via-font-lock)) |
| 97 | 99 | ||
| @@ -122,10 +124,20 @@ | |||
| 122 | ;; Local variables | 124 | ;; Local variables |
| 123 | ;;;###autoload | 125 | ;;;###autoload |
| 124 | (defgroup php nil | 126 | (defgroup php nil |
| 125 | "Major mode for editing PHP code." | 127 | "Language support for PHP." |
| 126 | :tag "PHP" | 128 | :tag "PHP" |
| 127 | :prefix "php-" | ||
| 128 | :group 'languages | 129 | :group 'languages |
| 130 | :group 'php | ||
| 131 | :link '(url-link :tag "Official Site" "https://github.com/emacs-php/php-mode") | ||
| 132 | :link '(url-link :tag "PHP Mode Wiki" "https://github.com/emacs-php/php-mode/wiki")) | ||
| 133 | |||
| 134 | ;;;###autoload | ||
| 135 | (defgroup php-mode nil | ||
| 136 | "Major mode for editing PHP code." | ||
| 137 | :tag "PHP Mode" | ||
| 138 | :prefix "php-mode-" | ||
| 139 | :group 'languages | ||
| 140 | :group 'php | ||
| 129 | :link '(url-link :tag "Official Site" "https://github.com/emacs-php/php-mode") | 141 | :link '(url-link :tag "Official Site" "https://github.com/emacs-php/php-mode") |
| 130 | :link '(url-link :tag "PHP Mode Wiki" "https://github.com/emacs-php/php-mode/wiki")) | 142 | :link '(url-link :tag "PHP Mode Wiki" "https://github.com/emacs-php/php-mode/wiki")) |
| 131 | 143 | ||
| @@ -134,13 +146,17 @@ | |||
| 134 | "The location of the PHP executable." | 146 | "The location of the PHP executable." |
| 135 | :type 'string) | 147 | :type 'string) |
| 136 | 148 | ||
| 137 | (defcustom php-default-face 'default | 149 | (define-obsolete-variable-alias 'php-default-face 'php-mode-default-face "1.20.0") |
| 150 | (defcustom php-mode-default-face 'default | ||
| 138 | "Default face in `php-mode' buffers." | 151 | "Default face in `php-mode' buffers." |
| 152 | :group 'php-mode | ||
| 139 | :type 'face) | 153 | :type 'face) |
| 140 | 154 | ||
| 141 | (defcustom php-speedbar-config t | 155 | (define-obsolete-variable-alias 'php-speedbar-config 'php-mode-speedbar-config "1.20.0") |
| 156 | (defcustom php-mode-speedbar-config t | ||
| 142 | "When set to true automatically configures Speedbar to observe PHP files. | 157 | "When set to true automatically configures Speedbar to observe PHP files. |
| 143 | Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s345]?\\)\"" | 158 | Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s345]?\\)\"" |
| 159 | :group 'php-mode | ||
| 144 | :type 'boolean | 160 | :type 'boolean |
| 145 | :set (lambda (sym val) | 161 | :set (lambda (sym val) |
| 146 | (set-default sym val) | 162 | (set-default sym val) |
| @@ -151,14 +167,17 @@ Ignores php-file patterns option; fixed to expression \"\\.\\(inc\\|php[s345]?\\ | |||
| 151 | (defcustom php-mode-speedbar-open nil | 167 | (defcustom php-mode-speedbar-open nil |
| 152 | "Normally `php-mode' starts with the speedbar closed. | 168 | "Normally `php-mode' starts with the speedbar closed. |
| 153 | Turning this on will open it whenever `php-mode' is loaded." | 169 | Turning this on will open it whenever `php-mode' is loaded." |
| 170 | :group 'php-mode | ||
| 154 | :type 'boolean | 171 | :type 'boolean |
| 155 | :set (lambda (sym val) | 172 | :set (lambda (sym val) |
| 156 | (set-default sym val) | 173 | (set-default sym val) |
| 157 | (when val | 174 | (when val |
| 158 | (speedbar 1)))) | 175 | (speedbar 1)))) |
| 159 | 176 | ||
| 160 | (defcustom php-template-compatibility t | 177 | (define-obsolete-variable-alias 'php-template-compatibility 'php-mode-template-compatibility "1.20.0") |
| 178 | (defcustom php-mode-template-compatibility t | ||
| 161 | "Should detect presence of html tags." | 179 | "Should detect presence of html tags." |
| 180 | :group 'php-mode | ||
| 162 | :type 'boolean) | 181 | :type 'boolean) |
| 163 | 182 | ||
| 164 | (defsubst php-in-string-p () | 183 | (defsubst php-in-string-p () |
| @@ -170,7 +189,7 @@ Turning this on will open it whenever `php-mode' is loaded." | |||
| 170 | (defsubst php-in-string-or-comment-p () | 189 | (defsubst php-in-string-or-comment-p () |
| 171 | (nth 8 (syntax-ppss))) | 190 | (nth 8 (syntax-ppss))) |
| 172 | 191 | ||
| 173 | (defun php-mode-extra-constants-create-regexp(kwds) | 192 | (defun php-mode-extra-constants-create-regexp (kwds) |
| 174 | "Create regexp for the list of extra constant keywords KWDS." | 193 | "Create regexp for the list of extra constant keywords KWDS." |
| 175 | (concat "[^_$]?\\<\\(" | 194 | (concat "[^_$]?\\<\\(" |
| 176 | (regexp-opt | 195 | (regexp-opt |
| @@ -178,7 +197,7 @@ Turning this on will open it whenever `php-mode' is loaded." | |||
| 178 | (when (boundp 'web-mode-extra-php-constants) web-mode-extra-php-constants))) | 197 | (when (boundp 'web-mode-extra-php-constants) web-mode-extra-php-constants))) |
| 179 | "\\)\\>[^_]?")) | 198 | "\\)\\>[^_]?")) |
| 180 | 199 | ||
| 181 | (defun php-mode-extra-constants-set(sym value) | 200 | (defun php-mode-extra-constants-set (sym value) |
| 182 | "Apply the list of extra constant keywords `VALUE'. | 201 | "Apply the list of extra constant keywords `VALUE'. |
| 183 | 202 | ||
| 184 | This function is called when the custom variable php-extra-constants | 203 | This function is called when the custom variable php-extra-constants |
| @@ -194,14 +213,18 @@ of constants when set." | |||
| 194 | 'php-mode `((,(php-mode-extra-constants-create-regexp value) 1 'php-constant)))) | 213 | 'php-mode `((,(php-mode-extra-constants-create-regexp value) 1 'php-constant)))) |
| 195 | (set sym value)) | 214 | (set sym value)) |
| 196 | 215 | ||
| 197 | (defcustom php-lineup-cascaded-calls nil | 216 | (define-obsolete-variable-alias 'php-lineup-cascaded-calls 'php-mode-lineup-cascaded-calls "1.20.0") |
| 217 | (defcustom php-mode-lineup-cascaded-calls nil | ||
| 198 | "Indent chained method calls to the previous line." | 218 | "Indent chained method calls to the previous line." |
| 219 | :group 'php-mode | ||
| 199 | :type 'boolean) | 220 | :type 'boolean) |
| 200 | 221 | ||
| 201 | ;;;###autoload | 222 | |
| 202 | (defcustom php-extra-constants '() | 223 | (define-obsolete-variable-alias 'php-extra-constants 'php-mode-extra-constants "1.20.0") |
| 224 | (defcustom php-mode-extra-constants '() | ||
| 203 | "A list of additional strings to treat as PHP constants." | 225 | "A list of additional strings to treat as PHP constants." |
| 204 | :type 'list | 226 | :group 'php-mode |
| 227 | :type '(repeat string) | ||
| 205 | :set 'php-mode-extra-constants-set) | 228 | :set 'php-mode-extra-constants-set) |
| 206 | 229 | ||
| 207 | (defun php-create-regexp-for-method (visibility) | 230 | (defun php-create-regexp-for-method (visibility) |
| @@ -265,10 +288,11 @@ can be used to match against definitions for that classlike." | |||
| 265 | "^\\s-*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)) | 288 | "^\\s-*function\\s-+\\(\\(?:\\sw\\|\\s_\\)+\\)\\s-*(" 1)) |
| 266 | "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") | 289 | "Imenu generic expression for PHP Mode. See `imenu-generic-expression'.") |
| 267 | 290 | ||
| 268 | (defcustom php-do-not-use-semantic-imenu t | 291 | (define-obsolete-variable-alias 'php-do-not-use-semantic-imenu 'php-mode-do-not-use-semantic-imenu "1.20.0") |
| 292 | (defcustom php-mode-do-not-use-semantic-imenu t | ||
| 269 | "Customize `imenu-create-index-function' for `php-mode'. | 293 | "Customize `imenu-create-index-function' for `php-mode'. |
| 270 | 294 | ||
| 271 | If using `semantic-mode' `imenu-create-index-function' will be | 295 | If using function `semantic-mode' `imenu-create-index-function' will be |
| 272 | set to `semantic-create-imenu-index' due to `c-mode' being its | 296 | set to `semantic-create-imenu-index' due to `c-mode' being its |
| 273 | parent. Set this variable to t if you want to use | 297 | parent. Set this variable to t if you want to use |
| 274 | `imenu-default-create-index-function' even with `semantic-mode' | 298 | `imenu-default-create-index-function' even with `semantic-mode' |
| @@ -394,6 +418,11 @@ This function may interfere with other hooks and other behaviors. | |||
| 394 | In that case set to `NIL'." | 418 | In that case set to `NIL'." |
| 395 | :type 'boolean) | 419 | :type 'boolean) |
| 396 | 420 | ||
| 421 | (defcustom php-mode-disable-parent-mode-hooks t | ||
| 422 | "When set to `T', do not run hooks of parent modes (`java-mode', `c-mode')." | ||
| 423 | :type 'boolean | ||
| 424 | :group 'php-mode) | ||
| 425 | |||
| 397 | (defun php-mode-version () | 426 | (defun php-mode-version () |
| 398 | "Display string describing the version of PHP Mode." | 427 | "Display string describing the version of PHP Mode." |
| 399 | (interactive) | 428 | (interactive) |
| @@ -405,9 +434,9 @@ In that case set to `NIL'." | |||
| 405 | (define-obsolete-variable-alias 'php-available-project-root-files 'php-project-available-root-files "1.19.0") | 434 | (define-obsolete-variable-alias 'php-available-project-root-files 'php-project-available-root-files "1.19.0") |
| 406 | 435 | ||
| 407 | (defvar php-mode-map | 436 | (defvar php-mode-map |
| 408 | (let ((map (make-sparse-keymap))) | 437 | (let ((map (make-sparse-keymap "PHP Mode"))) |
| 409 | ;; (define-key map [menu-bar php] | 438 | ;; Remove menu item for c-mode |
| 410 | ;; (cons "PHP" (make-sparse-keymap "PHP"))) | 439 | (define-key map [menu-bar C] nil) |
| 411 | 440 | ||
| 412 | ;; (define-key map [menu-bar php complete-function] | 441 | ;; (define-key map [menu-bar php complete-function] |
| 413 | ;; '("Complete function name" . php-complete-function)) | 442 | ;; '("Complete function name" . php-complete-function)) |
| @@ -1014,7 +1043,7 @@ this ^ lineup" | |||
| 1014 | (defgroup php-faces nil | 1043 | (defgroup php-faces nil |
| 1015 | "Faces used in PHP Mode" | 1044 | "Faces used in PHP Mode" |
| 1016 | :tag "PHP Faces" | 1045 | :tag "PHP Faces" |
| 1017 | :group 'php | 1046 | :group 'php-mode |
| 1018 | :group 'faces) | 1047 | :group 'faces) |
| 1019 | 1048 | ||
| 1020 | (defface php-string '((t (:inherit font-lock-string-face))) | 1049 | (defface php-string '((t (:inherit font-lock-string-face))) |
| @@ -1234,7 +1263,9 @@ After setting the stylevars run hooks according to STYLENAME | |||
| 1234 | "Major mode for editing PHP code. | 1263 | "Major mode for editing PHP code. |
| 1235 | 1264 | ||
| 1236 | \\{php-mode-map}" | 1265 | \\{php-mode-map}" |
| 1237 | 1266 | (when php-mode-disable-parent-mode-hooks | |
| 1267 | (setq-local c-mode-hook nil) | ||
| 1268 | (setq-local java-mode-hook nil)) | ||
| 1238 | (c-initialize-cc-mode t) | 1269 | (c-initialize-cc-mode t) |
| 1239 | (c-init-language-vars php-mode) | 1270 | (c-init-language-vars php-mode) |
| 1240 | (c-common-init 'php-mode) | 1271 | (c-common-init 'php-mode) |
| @@ -1310,7 +1341,6 @@ After setting the stylevars run hooks according to STYLENAME | |||
| 1310 | (save-excursion | 1341 | (save-excursion |
| 1311 | (php-syntax-propertize-function (point-min) (point-max)))))) | 1342 | (php-syntax-propertize-function (point-min) (point-max)))))) |
| 1312 | 1343 | ||
| 1313 | |||
| 1314 | (declare-function semantic-create-imenu-index "semantic/imenu" (&optional stream)) | 1344 | (declare-function semantic-create-imenu-index "semantic/imenu" (&optional stream)) |
| 1315 | 1345 | ||
| 1316 | (defvar-mode-local php-mode imenu-create-index-function | 1346 | (defvar-mode-local php-mode imenu-create-index-function |
| @@ -1859,9 +1889,4 @@ The output will appear in the buffer *PHP*." | |||
| 1859 | t) | 1889 | t) |
| 1860 | 1890 | ||
| 1861 | (provide 'php-mode) | 1891 | (provide 'php-mode) |
| 1862 | |||
| 1863 | ;;; php-mode.el ends here | 1892 | ;;; php-mode.el ends here |
| 1864 | |||
| 1865 | ;; Local Variables: | ||
| 1866 | ;; firestarter: ert-run-tests-interactively | ||
| 1867 | ;; End: | ||
diff --git a/.emacs.d/lisp/php-project.el b/.emacs.d/lisp/php-project.el index 2f4d571..bbcc19c 100644 --- a/.emacs.d/lisp/php-project.el +++ b/.emacs.d/lisp/php-project.el | |||
| @@ -5,7 +5,7 @@ | |||
| 5 | ;; Author: USAMI Kenta <tadsan@zonu.me> | 5 | ;; Author: USAMI Kenta <tadsan@zonu.me> |
| 6 | ;; Keywords: tools, files | 6 | ;; Keywords: tools, files |
| 7 | ;; URL: https://github.com/emacs-php/php-mode | 7 | ;; URL: https://github.com/emacs-php/php-mode |
| 8 | ;; Version: 1.19.1 | 8 | ;; Version: 1.20.0 |
| 9 | ;; Package-Requires: ((emacs "24.3") (cl-lib "0.5")) | 9 | ;; Package-Requires: ((emacs "24.3") (cl-lib "0.5")) |
| 10 | ;; License: GPL-3.0-or-later | 10 | ;; License: GPL-3.0-or-later |
| 11 | 11 | ||
| @@ -134,6 +134,51 @@ defines constants, and sets the class loaders.") | |||
| 134 | Typically it is `pear', `drupal', `wordpress', `symfony2' and `psr2'.") | 134 | Typically it is `pear', `drupal', `wordpress', `symfony2' and `psr2'.") |
| 135 | (put 'php-project-coding-style 'safe-local-variable #'symbolp)) | 135 | (put 'php-project-coding-style 'safe-local-variable #'symbolp)) |
| 136 | 136 | ||
| 137 | ;;;###autoload | ||
| 138 | (progn | ||
| 139 | (defvar php-project-repl nil | ||
| 140 | "Function name or path to REPL (interactive shell) script.") | ||
| 141 | (make-variable-buffer-local 'php-project-repl) | ||
| 142 | (put 'php-project-repl 'safe-local-variable | ||
| 143 | #'(lambda (v) (or (functionp v) | ||
| 144 | (php-project--eval-bootstrap-scripts v))))) | ||
| 145 | |||
| 146 | ;;;###autoload | ||
| 147 | (progn | ||
| 148 | (defvar php-project-unit-test nil | ||
| 149 | "Function name or path to unit test script.") | ||
| 150 | (make-variable-buffer-local 'php-project-unit-test) | ||
| 151 | (put 'php-project-unit-test 'safe-local-variable | ||
| 152 | #'(lambda (v) (or (functionp v) | ||
| 153 | (php-project--eval-bootstrap-scripts v))))) | ||
| 154 | |||
| 155 | ;;;###autoload | ||
| 156 | (progn | ||
| 157 | (defvar php-project-deploy nil | ||
| 158 | "Function name or path to deploy script.") | ||
| 159 | (make-variable-buffer-local 'php-project-deploy) | ||
| 160 | (put 'php-project-deploy 'safe-local-variable | ||
| 161 | #'(lambda (v) (or (functionp v) | ||
| 162 | (php-project--eval-bootstrap-scripts v))))) | ||
| 163 | |||
| 164 | ;;;###autoload | ||
| 165 | (progn | ||
| 166 | (defvar php-project-build nil | ||
| 167 | "Function name or path to build script.") | ||
| 168 | (make-variable-buffer-local 'php-project-build) | ||
| 169 | (put 'php-project-build 'safe-local-variable | ||
| 170 | #'(lambda (v) (or (functionp v) | ||
| 171 | (php-project--eval-bootstrap-scripts v))))) | ||
| 172 | |||
| 173 | ;;;###autoload | ||
| 174 | (progn | ||
| 175 | (defvar php-project-server-start nil | ||
| 176 | "Function name or path to server-start script.") | ||
| 177 | (make-variable-buffer-local 'php-project-server-start) | ||
| 178 | (put 'php-project-server-start 'safe-local-variable | ||
| 179 | #'(lambda (v) (or (functionp v) | ||
| 180 | (php-project--eval-bootstrap-scripts v))))) | ||
| 181 | |||
| 137 | 182 | ||
| 138 | ;; Functions | 183 | ;; Functions |
| 139 | 184 | ||
diff --git a/.emacs.d/lisp/yasnippet.el b/.emacs.d/lisp/yasnippet.el index 46624ed..065e709 100644 --- a/.emacs.d/lisp/yasnippet.el +++ b/.emacs.d/lisp/yasnippet.el | |||
| @@ -132,6 +132,7 @@ | |||
| 132 | ;;; Code: | 132 | ;;; Code: |
| 133 | 133 | ||
| 134 | (require 'cl-lib) | 134 | (require 'cl-lib) |
| 135 | (require 'eldoc) ; Needed for 24. | ||
| 135 | (declare-function cl-progv-after "cl-extra") ; Needed for 23.4. | 136 | (declare-function cl-progv-after "cl-extra") ; Needed for 23.4. |
| 136 | (require 'easymenu) | 137 | (require 'easymenu) |
| 137 | (require 'help-mode) | 138 | (require 'help-mode) |
| @@ -402,7 +403,15 @@ It must be set to nil before loading yasnippet to take effect." | |||
| 402 | "A conditional key definition. | 403 | "A conditional key definition. |
| 403 | This can be used as a key definition in keymaps to bind a key to | 404 | This can be used as a key definition in keymaps to bind a key to |
| 404 | `yas-skip-and-clear-field' only when at the beginning of an | 405 | `yas-skip-and-clear-field' only when at the beginning of an |
| 405 | unmodified snippey field.") | 406 | unmodified snippet field.") |
| 407 | |||
| 408 | (defconst yas-maybe-clear-field | ||
| 409 | '(menu-item "" yas-clear-field | ||
| 410 | :filter yas--maybe-clear-field-filter) | ||
| 411 | "A conditional key definition. | ||
| 412 | This can be used as a key definition in keymaps to bind a key to | ||
| 413 | `yas-clear-field' only when at the beginning of an | ||
| 414 | unmodified snippet field.") | ||
| 406 | 415 | ||
| 407 | (defvar yas-keymap (let ((map (make-sparse-keymap))) | 416 | (defvar yas-keymap (let ((map (make-sparse-keymap))) |
| 408 | (define-key map [(tab)] 'yas-next-field-or-maybe-expand) | 417 | (define-key map [(tab)] 'yas-next-field-or-maybe-expand) |
| @@ -411,6 +420,7 @@ unmodified snippey field.") | |||
| 411 | (define-key map [backtab] 'yas-prev-field) | 420 | (define-key map [backtab] 'yas-prev-field) |
| 412 | (define-key map (kbd "C-g") 'yas-abort-snippet) | 421 | (define-key map (kbd "C-g") 'yas-abort-snippet) |
| 413 | (define-key map (kbd "C-d") yas-maybe-skip-and-clear-field) | 422 | (define-key map (kbd "C-d") yas-maybe-skip-and-clear-field) |
| 423 | (define-key map (kbd "DEL") yas-maybe-clear-field) | ||
| 414 | map) | 424 | map) |
| 415 | "The active keymap while a snippet expansion is in progress.") | 425 | "The active keymap while a snippet expansion is in progress.") |
| 416 | 426 | ||
| @@ -442,7 +452,7 @@ are looked for first. Failing that, longer keys composed of | |||
| 442 | \"word\" or \"symbol\" syntax are looked for. Therefore, | 452 | \"word\" or \"symbol\" syntax are looked for. Therefore, |
| 443 | triggering after | 453 | triggering after |
| 444 | 454 | ||
| 445 | foo-bar | 455 | foo-barbaz |
| 446 | 456 | ||
| 447 | will, according to the \"w\" element first try \"barbaz\". If | 457 | will, according to the \"w\" element first try \"barbaz\". If |
| 448 | that isn't a trigger key, \"foo-barbaz\" is tried, respecting the | 458 | that isn't a trigger key, \"foo-barbaz\" is tried, respecting the |
| @@ -623,13 +633,19 @@ override bindings from other packages (e.g., `company-mode')." | |||
| 623 | 633 | ||
| 624 | (defvar yas--condition-cache-timestamp nil) | 634 | (defvar yas--condition-cache-timestamp nil) |
| 625 | 635 | ||
| 626 | (defun yas--maybe-expand-key-filter (cmd) | 636 | (defun yas-maybe-expand-abbrev-key-filter (cmd) |
| 637 | "Return CMD if there is an expandable snippet at point. | ||
| 638 | This function is useful as a `:filter' to a conditional key | ||
| 639 | definition." | ||
| 627 | (when (let ((yas--condition-cache-timestamp (current-time))) | 640 | (when (let ((yas--condition-cache-timestamp (current-time))) |
| 628 | (yas--templates-for-key-at-point)) | 641 | (yas--templates-for-key-at-point)) |
| 629 | cmd)) | 642 | cmd)) |
| 630 | 643 | ||
| 644 | (define-obsolete-function-alias 'yas--maybe-expand-key-filter | ||
| 645 | #'yas-maybe-expand-abbrev-key-filter "0.14") | ||
| 646 | |||
| 631 | (defconst yas-maybe-expand | 647 | (defconst yas-maybe-expand |
| 632 | '(menu-item "" yas-expand :filter yas--maybe-expand-key-filter) | 648 | '(menu-item "" yas-expand :filter yas-maybe-expand-abbrev-key-filter) |
| 633 | "A conditional key definition. | 649 | "A conditional key definition. |
| 634 | This can be used as a key definition in keymaps to bind a key to | 650 | This can be used as a key definition in keymaps to bind a key to |
| 635 | `yas-expand' only when there is a snippet available to be | 651 | `yas-expand' only when there is a snippet available to be |
| @@ -801,7 +817,10 @@ which decides on the snippet to expand.") | |||
| 801 | (yas--dfs | 817 | (yas--dfs |
| 802 | (lambda (mode) | 818 | (lambda (mode) |
| 803 | (cl-loop for neighbour | 819 | (cl-loop for neighbour |
| 804 | in (cl-list* (get mode 'derived-mode-parent) | 820 | in (cl-list* (or (get mode 'derived-mode-parent) |
| 821 | ;; Consider `fundamental-mode' | ||
| 822 | ;; as ultimate ancestor. | ||
| 823 | 'fundamental-mode) | ||
| 805 | ;; NOTE: `fboundp' check is redundant | 824 | ;; NOTE: `fboundp' check is redundant |
| 806 | ;; since Emacs 24.4. | 825 | ;; since Emacs 24.4. |
| 807 | (and (fboundp mode) (symbol-function mode)) | 826 | (and (fboundp mode) (symbol-function mode)) |
| @@ -2984,6 +3003,16 @@ The last element of POSSIBILITIES may be a list of strings." | |||
| 2984 | (funcall fn "Choose: " possibilities)) | 3003 | (funcall fn "Choose: " possibilities)) |
| 2985 | yas-prompt-functions))) | 3004 | yas-prompt-functions))) |
| 2986 | 3005 | ||
| 3006 | (defun yas-completing-read (&rest args) | ||
| 3007 | "A snippet-aware version of `completing-read'. | ||
| 3008 | This can be used to query the user for the initial value of a | ||
| 3009 | snippet field. The arguments are the same as `completing-read'. | ||
| 3010 | |||
| 3011 | \(fn PROMPT COLLECTION &optional PREDICATE REQUIRE-MATCH INITIAL-INPUT HIST DEF INHERIT-INPUT-METHOD)" | ||
| 3012 | (unless (or yas-moving-away-p | ||
| 3013 | yas-modified-p) | ||
| 3014 | (apply #'completing-read args))) | ||
| 3015 | |||
| 2987 | (defun yas--auto-next () | 3016 | (defun yas--auto-next () |
| 2988 | "Helper for `yas-auto-next'." | 3017 | "Helper for `yas-auto-next'." |
| 2989 | (remove-hook 'post-command-hook #'yas--auto-next t) | 3018 | (remove-hook 'post-command-hook #'yas--auto-next t) |
| @@ -3013,7 +3042,7 @@ The last element of POSSIBILITIES may be a list of strings." | |||
| 3013 | (defun yas-verify-value (possibilities) | 3042 | (defun yas-verify-value (possibilities) |
| 3014 | "Verify that the current field value is in POSSIBILITIES. | 3043 | "Verify that the current field value is in POSSIBILITIES. |
| 3015 | Otherwise signal `yas-exception'." | 3044 | Otherwise signal `yas-exception'." |
| 3016 | (when (and yas-moving-away-p (cl-notany (lambda (pos) (string= pos yas-text)) possibilities)) | 3045 | (when (and yas-moving-away-p (not (member yas-text possibilities))) |
| 3017 | (yas-throw (format "Field only allows %s" possibilities)))) | 3046 | (yas-throw (format "Field only allows %s" possibilities)))) |
| 3018 | 3047 | ||
| 3019 | (defun yas-field-value (number) | 3048 | (defun yas-field-value (number) |
| @@ -3326,8 +3355,9 @@ Otherwise delegate to `yas-next-field'." | |||
| 3326 | If there's none, exit the snippet." | 3355 | If there's none, exit the snippet." |
| 3327 | (interactive) | 3356 | (interactive) |
| 3328 | (unless arg (setq arg 1)) | 3357 | (unless arg (setq arg 1)) |
| 3329 | (let* ((snippet (car (yas-active-snippets))) | 3358 | (let* ((active-field (overlay-get yas--active-field-overlay 'yas--field)) |
| 3330 | (active-field (overlay-get yas--active-field-overlay 'yas--field)) | 3359 | (snippet (car (yas-active-snippets (yas--field-start active-field) |
| 3360 | (yas--field-end active-field)))) | ||
| 3331 | (target-field (yas--find-next-field arg snippet active-field))) | 3361 | (target-field (yas--find-next-field arg snippet active-field))) |
| 3332 | (yas--letenv (yas--snippet-expand-env snippet) | 3362 | (yas--letenv (yas--snippet-expand-env snippet) |
| 3333 | ;; Apply transform to active field. | 3363 | ;; Apply transform to active field. |
| @@ -3658,6 +3688,11 @@ Use as a `:filter' argument for a conditional keybinding." | |||
| 3658 | (yas--skip-and-clear (or field (yas-current-field))) | 3688 | (yas--skip-and-clear (or field (yas-current-field))) |
| 3659 | (yas-next-field 1)) | 3689 | (yas-next-field 1)) |
| 3660 | 3690 | ||
| 3691 | (defun yas-clear-field (&optional field) | ||
| 3692 | "Clears unmodified FIELD if at field start." | ||
| 3693 | (interactive) | ||
| 3694 | (yas--skip-and-clear (or field (yas-current-field)))) | ||
| 3695 | |||
| 3661 | (defun yas-skip-and-clear-or-delete-char (&optional field) | 3696 | (defun yas-skip-and-clear-or-delete-char (&optional field) |
| 3662 | "Clears unmodified field if at field start, skips to next tab. | 3697 | "Clears unmodified field if at field start, skips to next tab. |
| 3663 | 3698 | ||
| @@ -3745,7 +3780,15 @@ field start. This hook does nothing if an undo is in progress." | |||
| 3745 | ;; We delete text starting from the END of insertion. | 3780 | ;; We delete text starting from the END of insertion. |
| 3746 | (yas--skip-and-clear field end)) | 3781 | (yas--skip-and-clear field end)) |
| 3747 | (setf (yas--field-modified-p field) t) | 3782 | (setf (yas--field-modified-p field) t) |
| 3748 | (yas--advance-end-maybe field (overlay-end overlay)) | 3783 | ;; Adjust any pending active fields in case of stacked |
| 3784 | ;; expansion. | ||
| 3785 | (let ((pfield field) | ||
| 3786 | (psnippets (yas-active-snippets beg end))) | ||
| 3787 | (while (and pfield psnippets) | ||
| 3788 | (let ((psnippet (pop psnippets))) | ||
| 3789 | (cl-assert (memq pfield (yas--snippet-fields psnippet))) | ||
| 3790 | (yas--advance-end-maybe pfield (overlay-end overlay)) | ||
| 3791 | (setq pfield (yas--snippet-previous-active-field psnippet))))) | ||
| 3749 | (save-excursion | 3792 | (save-excursion |
| 3750 | (yas--field-update-display field)) | 3793 | (yas--field-update-display field)) |
| 3751 | (yas--update-mirrors snippet))) | 3794 | (yas--update-mirrors snippet))) |
| @@ -4033,15 +4076,21 @@ Returns the newly created snippet." | |||
| 4033 | (yas--letenv expand-env | 4076 | (yas--letenv expand-env |
| 4034 | ;; Put a single undo action for the expanded snippet's | 4077 | ;; Put a single undo action for the expanded snippet's |
| 4035 | ;; content. | 4078 | ;; content. |
| 4036 | (let ((buffer-undo-list t)) | 4079 | (let ((buffer-undo-list t) |
| 4080 | (inhibit-modification-hooks t)) | ||
| 4037 | ;; Some versions of cc-mode fail when inserting snippet | 4081 | ;; Some versions of cc-mode fail when inserting snippet |
| 4038 | ;; content in a narrowed buffer. | 4082 | ;; content in a narrowed buffer, so make sure to insert |
| 4083 | ;; before narrowing. Furthermore, call before and after | ||
| 4084 | ;; change functions manually, otherwise cc-mode's cache can | ||
| 4085 | ;; get messed up. | ||
| 4039 | (goto-char begin) | 4086 | (goto-char begin) |
| 4087 | (run-hook-with-args 'before-change-functions begin begin) | ||
| 4040 | (insert content) | 4088 | (insert content) |
| 4041 | (setq end (+ end (length content))) | 4089 | (setq end (+ end (length content))) |
| 4042 | (narrow-to-region begin end) | 4090 | (narrow-to-region begin end) |
| 4043 | (goto-char (point-min)) | 4091 | (goto-char (point-min)) |
| 4044 | (yas--snippet-parse-create snippet)) | 4092 | (yas--snippet-parse-create snippet) |
| 4093 | (run-hook-with-args 'after-change-functions (point-min) (point-max) 0)) | ||
| 4045 | (when (listp buffer-undo-list) | 4094 | (when (listp buffer-undo-list) |
| 4046 | (push (cons (point-min) (point-max)) | 4095 | (push (cons (point-min) (point-max)) |
| 4047 | buffer-undo-list)) | 4096 | buffer-undo-list)) |
| @@ -4505,8 +4554,7 @@ Lisp expression." | |||
| 4505 | current-string '(?`)))))) | 4554 | current-string '(?`)))))) |
| 4506 | (goto-char (match-beginning 0)) | 4555 | (goto-char (match-beginning 0)) |
| 4507 | (when transformed | 4556 | (when transformed |
| 4508 | (let ((marker (make-marker)) | 4557 | (let ((marker (make-marker))) |
| 4509 | (before-change-functions (cdr before-change-functions))) | ||
| 4510 | (yas--save-restriction-and-widen | 4558 | (yas--save-restriction-and-widen |
| 4511 | (insert "Y") ;; quite horrendous, I love it :) | 4559 | (insert "Y") ;; quite horrendous, I love it :) |
| 4512 | (set-marker marker (point)) | 4560 | (set-marker marker (point)) |
| @@ -4905,6 +4953,12 @@ object satisfying `yas--field-p' to restrict the expansion to."))) | |||
| 4905 | (help-xref-button 1 'help-snippet-def template) | 4953 | (help-xref-button 1 'help-snippet-def template) |
| 4906 | (delete-region (match-end 1) (match-end 0)) | 4954 | (delete-region (match-end 1) (match-end 0)) |
| 4907 | (delete-region (match-beginning 0) (match-beginning 1))))))) | 4955 | (delete-region (match-beginning 0) (match-beginning 1))))))) |
| 4956 | |||
| 4957 | ;;; Eldoc configuration. | ||
| 4958 | (eldoc-add-command 'yas-next-field-or-maybe-expand | ||
| 4959 | 'yas-next-field 'yas-prev-field | ||
| 4960 | 'yas-expand 'yas-expand-from-keymap | ||
| 4961 | 'yas-expand-from-trigger-key) | ||
| 4908 | 4962 | ||
| 4909 | ;;; Utils | 4963 | ;;; Utils |
| 4910 | 4964 | ||
