Package: emacs;
Reported by: ~johnmuhl <jm <at> pub.pink>
Date: Fri, 1 Sep 2023 06:31:03 UTC
Severity: wishlist
Tags: patch
Merged with 65672
Done: Eli Zaretskii <eliz <at> gnu.org>
Bug is archived. No further changes may be made.
Message #24 received at 65673 <at> debbugs.gnu.org (full text, mbox):
From: Philip Kaludercic <philipk <at> posteo.net> To: john muhl <jm <at> pub.pink> Cc: arstoffel <at> gmail.com, maurooaranda <at> gmail.com, 65673 <at> debbugs.gnu.org, ~emacs/emacs-devel <at> lists.sr.ht Subject: Re: [PATCH] Add lua-ts-mode Date: Sun, 10 Sep 2023 11:12:49 +0000
john muhl <jm <at> pub.pink> writes: > * lisp/progmodes/lua-ts-mode.el: > * test/lisp/progmodes/lua-ts-mode-resources/indent.erts: > * test/lisp/progmodes/lua-ts-mode-tests.el: New file. > * etc/NEWS: Mention new mode. > * lisp/progmodes/eglot.el (eglot-server-programs): > * lisp/progmodes/hideshow.el (hs-special-modes-alist): Support > lua-ts-mode. > * admin/notes/tree-sitter/build-module/batch.sh: > * admin/notes/tree-sitter/build-module/build.sh: Add Lua. > * test/infra/Dockerfile.emba: > * test/infra/test-jobs.yml: Include lua-ts-mode tests. > --- > admin/notes/tree-sitter/build-module/batch.sh | 1 + > admin/notes/tree-sitter/build-module/build.sh | 3 + > etc/NEWS | 4 + > lisp/progmodes/eglot.el | 4 +- > lisp/progmodes/hideshow.el | 1 + > lisp/progmodes/lua-ts-mode.el | 419 +++++++++++++ > test/infra/Dockerfile.emba | 1 + > test/infra/test-jobs.yml | 1 + > .../lua-ts-mode-resources/indent.erts | 152 +++++ > .../lua-ts-mode-resources/movement.erts | 553 ++++++++++++++++++ > test/lisp/progmodes/lua-ts-mode-tests.el | 36 ++ > 11 files changed, 1173 insertions(+), 2 deletions(-) > create mode 100644 lisp/progmodes/lua-ts-mode.el > create mode 100644 test/lisp/progmodes/lua-ts-mode-resources/indent.erts > create mode 100644 test/lisp/progmodes/lua-ts-mode-resources/movement.erts > create mode 100644 test/lisp/progmodes/lua-ts-mode-tests.el > > diff --git a/admin/notes/tree-sitter/build-module/batch.sh b/admin/notes/tree-sitter/build-module/batch.sh > index 3c4e1472c89..9988d1eae4e 100755 > --- a/admin/notes/tree-sitter/build-module/batch.sh > +++ b/admin/notes/tree-sitter/build-module/batch.sh > @@ -16,6 +16,7 @@ languages= > 'java' > 'javascript' > 'json' > + 'lua' > 'python' > 'rust' > 'toml' > diff --git a/admin/notes/tree-sitter/build-module/build.sh b/admin/notes/tree-sitter/build-module/build.sh > index 0832875168b..969187b7f92 100755 > --- a/admin/notes/tree-sitter/build-module/build.sh > +++ b/admin/notes/tree-sitter/build-module/build.sh > @@ -42,6 +42,9 @@ grammardir= > "heex") > org="phoenixframework" > ;; > + "lua") > + org="MunifTanjim" > + ;; > "typescript") > sourcedir="tree-sitter-typescript/typescript/src" > grammardir="tree-sitter-typescript/typescript" > diff --git a/etc/NEWS b/etc/NEWS > index 51e89fc96dd..0b7da8b392c 100644 > --- a/etc/NEWS > +++ b/etc/NEWS > @@ -782,6 +782,10 @@ It highlight parens via ‘show-paren-mode’ and ‘blink-matching-paren’ in > a user-friendly way, avoids reporting alleged paren mismatches and makes > sexp navigation more intuitive. > > +--- > +*** New major mode 'lua-ts-mode'. > +A major mode based on the tree-sitter library for editing Lua files. > + > --- > ** The highly accessible Modus themes collection has eight items. > The 'modus-operandi' and 'modus-vivendi' are the main themes that have > diff --git a/lisp/progmodes/eglot.el b/lisp/progmodes/eglot.el > index f7c7c29c094..e2f663998d3 100644 > --- a/lisp/progmodes/eglot.el > +++ b/lisp/progmodes/eglot.el > @@ -268,8 +268,8 @@ eglot-server-programs > (gdscript-mode . ("localhost" 6008)) > ((fortran-mode f90-mode) . ("fortls")) > (futhark-mode . ("futhark" "lsp")) > - (lua-mode . ,(eglot-alternatives > - '("lua-language-server" "lua-lsp"))) > + ((lua-mode lua-ts-mode) . ,(eglot-alternatives > + '("lua-language-server" "lua-lsp"))) > (zig-mode . ("zls")) > ((css-mode css-ts-mode) > . ,(eglot-alternatives '(("vscode-css-language-server" "--stdio") > diff --git a/lisp/progmodes/hideshow.el b/lisp/progmodes/hideshow.el > index b878986d7a4..78e39fad740 100644 > --- a/lisp/progmodes/hideshow.el > +++ b/lisp/progmodes/hideshow.el > @@ -264,6 +264,7 @@ hs-special-modes-alist > (java-ts-mode "{" "}" "/[*/]" nil nil) > (js-mode "{" "}" "/[*/]" nil) > (js-ts-mode "{" "}" "/[*/]" nil) > + (lua-ts-mode "{\\|\\[\\[" "}\\|\\]\\]" "--" nil) > (mhtml-mode "{\\|<[^/>]*?" "}\\|</[^/>]*[^/]>" "<!--" mhtml-forward nil) > ;; Add more support here. > )) > diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el > new file mode 100644 > index 00000000000..b7fe71c5fe2 > --- /dev/null > +++ b/lisp/progmodes/lua-ts-mode.el > @@ -0,0 +1,419 @@ > +;;; lua-ts-mode.el --- Major mode for editing Lua files -*- lexical-binding: t -*- > + > +;; Copyright (C) 2023 Free Software Foundation, Inc. > + > +;; Author: John Muhl <jm <at> pub.pink> > +;; Created: June 27, 2023 > +;; Keywords: lua languages tree-sitter > + > +;; This file is part of GNU Emacs. > + > +;; GNU Emacs is free software: you can redistribute it and/or modify > +;; it under the terms of the GNU General Public License as published by > +;; the Free Software Foundation, either version 3 of the License, or > +;; (at your option) any later version. > +;; > +;; GNU Emacs is distributed in the hope that it will be useful, > +;; but WITHOUT ANY WARRANTY; without even the implied warranty of > +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +;; GNU General Public License for more details. > +;; > +;; You should have received a copy of the GNU General Public License > +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. > + > +;;; Commentary: > + > +;; This package provides `lua-ts-mode' which is a major mode for Lua > +;; files that uses Tree Sitter to parse the language. > +;; > +;; This package is compatible with and tested against the grammar > +;; for Lua found at https://github.com/MunifTanjim/tree-sitter-lua > + > +;;; Code: > + > +(require 'comint) > +(require 'treesit) > + > +(eval-when-compile > + (require 'cl-lib) > + (require 'rx)) > + > +(defcustom lua-ts-indent-offset 4 > + "Number of spaces for each indentation step in `lua-ts-mode'." > + :type 'natnum > + :safe 'natnump > + :group 'lua You still need a defgroup for the package. > + :version "30.1") > + > +(defcustom lua-ts-luacheck-program (executable-find "luacheck") It is better not to hard-code the path to lua during loading, in case the executable is moved around, since you will basically always still be querying PATH when starting a new process. > + "Location of the Luacheck program." > + :type '(choice (const nil) (file :must-match t)) Which is why I think that this shouldn't be a file. > + :group 'lua > + :version "30.1") > + > +(defcustom lua-ts-inferior-buffer "Lua" How about "*Lua*"? > + "Name of the inferior Lua buffer." > + :type 'string > + :safe 'stringp > + :group 'lua > + :version "30.1") > + > +(defcustom lua-ts-inferior-program (executable-find "lua") Same here. > + "Program to run in the inferior Lua process." > + :type '(choice (const nil) (file :must-match t)) > + :group 'lua > + :version "30.1") > + > +(defcustom lua-ts-inferior-options '("-i") > + "Command line options for the inferior Lua process." > + :type '(repeat string) > + :group 'lua > + :version "30.1") > + > +(defcustom lua-ts-inferior-startfile nil > + "File to load into the inferior Lua process at startup." > + :type '(choice (const nil) (file :must-match t)) > + :group 'lua > + :version "30.1") > + > +(defcustom lua-ts-inferior-prompt-regexp "^>>?[[:blank:]]" > + "Regular expression matching the prompt of the inferior Lua process." > + :type 'regexp > + :group 'lua > + :version "30.1") > + > +(defvar lua-ts--builtins > + '("assert" "bit32" "collectgarbage" "coroutine" "debug" "dofile" > + "error" "getmetatable" "io" "ipairs" "load" "loadfile" > + "math" "next" "os" "package" "pairs" "pcall" "print" > + "rawequal" "rawget" "rawlen" "rawset" "require" "select" > + "setmetatable" "string" "table" "tonumber" "tostring" > + "type" "utf8" "warn" "xpcall" "_G" "_VERSION" > + ;; methods for file handlers > + "close" "flush" "lines" "read" "seek" "setvbuf" "write") > + "Lua built-in functions for tree-sitter font-locking.") > + > +(defvar lua-ts--font-lock-settings > + (treesit-font-lock-rules > + :language 'lua > + :feature 'bracket > + '(["(" ")" "[" "]" "{" "}"] @font-lock-bracket-face) > + > + :language 'lua > + :feature 'delimiter > + '(["," ";"] @font-lock-delimiter-face) > + > + :language 'lua > + :feature 'escape > + '((escape_sequence) @font-lock-escape-face) > + > + :language 'lua > + :feature 'constant > + '((variable_list > + attribute: (attribute (["<" ">"] (identifier)))) > + @font-lock-constant-face) > + > + :language 'lua > + :feature 'operator > + '(["and" "not" "or" "+" "-" "*" "/" "%" "^" > + "#" "==" "~=" "<=" ">=" "<" ">" "=" "&" > + "~" "|" "<<" ">>" "//" ".."] > + @font-lock-operator-face > + (vararg_expression) @font-lock-operator-face) > + > + :language 'lua > + :feature 'property > + '((field name: (identifier) @font-lock-property-name-face) > + (dot_index_expression > + field: (identifier) @font-lock-property-use-face)) > + > + :language 'lua > + :feature 'builtin > + `(((identifier) @font-lock-builtin-face > + (:match ,(regexp-opt lua-ts--builtins 'symbols) > + @font-lock-builtin-face))) > + > + :language 'lua > + :feature 'function > + '((function_call name: (identifier) @font-lock-function-call-face) > + (function_call > + name: (method_index_expression > + method: (identifier) @font-lock-function-call-face)) > + (function_call > + name: (dot_index_expression > + table: (identifier) @font-lock-function-call-face))) > + > + :language 'lua > + :feature 'punctuation > + '(["." ":"] @font-lock-punctuation-face) > + > + :language 'lua > + :feature 'variable > + '((function_call > + arguments: (arguments (identifier)) > + @font-lock-variable-use-face) > + (function_call > + name: (method_index_expression > + table: (identifier) @font-lock-variable-use-face)) > + (goto_statement (identifier) @font-lock-variable-use-face)) > + > + :language 'lua > + :feature 'assignment > + '((variable_list (identifier) @font-lock-variable-name-face)) > + > + :language 'lua > + :feature 'number > + '((number) @font-lock-number-face) > + > + :language 'lua > + :feature 'keyword > + '((break_statement) @font-lock-keyword-face > + (true) @font-lock-constant-face > + (false) @font-lock-constant-face > + (nil) @font-lock-constant-face > + ["and" "do" "else" "elseif" "end" "for" "function" > + "goto" "if" "in" "local" "not" "or" "repeat" > + "return" "then" "until" "while"] > + @font-lock-keyword-face) > + > + :language 'lua > + :feature 'string > + '((string) @font-lock-string-face) > + > + :language 'lua > + :feature 'comment > + '((comment) @font-lock-comment-face > + (hash_bang_line) @font-lock-comment-face) > + > + :language 'lua > + :feature 'definition > + '((function_declaration > + name: (identifier) @font-lock-function-name-face) > + (parameters > + name: (identifier) @font-lock-variable-name-face) > + (label_statement) @font-lock-variable-name-face) > + > + :language 'lua > + :feature 'error > + :override t > + '((ERROR) @font-lock-warning-face)) > + "Tree-sitter font-lock settings for `lua-ts-mode'.") > + > +(defvar lua-ts--simple-indent-rules > + `((lua > + ((parent-is "chunk") column-0 0) > + ((node-is "comment_end") column-0 0) > + ((parent-is "block") parent-bol 0) > + ((node-is "}") parent-bol 0) > + ((node-is ")") parent-bol 0) > + ((node-is "else_statement") parent-bol 0) > + ((node-is "elseif_statement") parent-bol 0) > + ((node-is "end") parent-bol 0) > + ((node-is "until") parent-bol 0) > + ((parent-is "for_statement") parent-bol lua-ts-indent-offset) > + ((parent-is "function_declaration") parent-bol lua-ts-indent-offset) > + ((parent-is "function_definition") parent-bol lua-ts-indent-offset) > + ((parent-is "if_statement") parent-bol lua-ts-indent-offset) > + ((parent-is "else_statement") parent-bol lua-ts-indent-offset) > + ((parent-is "repeat_statement") parent-bol lua-ts-indent-offset) > + ((parent-is "while_statement") parent-bol lua-ts-indent-offset) > + ((parent-is "table_constructor") parent-bol lua-ts-indent-offset) > + ((parent-is "arguments") parent-bol lua-ts-indent-offset) > + ((parent-is "parameters") parent-bol lua-ts-indent-offset) > + ((parent-is "ERROR") no-indent 0)))) > + > +(defvar lua-ts--syntax-table > + (let ((table (make-syntax-table))) > + (modify-syntax-entry ?+ "." table) > + (modify-syntax-entry ?- ". 12" table) > + (modify-syntax-entry ?= "." table) > + (modify-syntax-entry ?% "." table) > + (modify-syntax-entry ?^ "." table) > + (modify-syntax-entry ?~ "." table) > + (modify-syntax-entry ?< "." table) > + (modify-syntax-entry ?> "." table) > + (modify-syntax-entry ?/ "." table) > + (modify-syntax-entry ?* "." table) > + (modify-syntax-entry ?\n ">" table) > + (modify-syntax-entry ?\' "\"" table) > + (modify-syntax-entry ?\" "\"" table) > + table) > + "Syntax table for `lua-ts-mode'.") > + > +(defun lua-ts--defun-name-function (node) > + "Return the defun name of NODE. > +Return nil if there is no name or if NODE is not a defun node." > + (let ((child (treesit-node-child-by-field-name node "name"))) > + (pcase (treesit-node-type node) > + ((or "function_declaration" "function_definition") > + (treesit-node-text child t)) > + ("variable_declaration" > + (if child > + (treesit-node-text child t) > + (treesit-node-text > + (treesit-node-child-by-field-name > + (treesit-search-subtree node "assignment_statement" nil nil 1) > + "name")))) > + ("field" > + (and (treesit-search-subtree node "function_definition" nil nil 1) > + (treesit-node-text child t)))))) > + > +(defvar-local lua-ts--flymake-process nil) > + > +(defun lua-ts-flymake-luacheck (report-fn &rest _args) > + "Luacheck backend for Flymake. > +Calls REPORT-FN directly." > + (when (process-live-p lua-ts--flymake-process) > + (kill-process lua-ts--flymake-process)) > + (let ((source (current-buffer))) > + (save-restriction > + (widen) > + (setq lua-ts--flymake-process > + (make-process > + :name "lua-ts-flymake-luacheck" > + :noquery t > + :connection-type 'pipe > + :buffer (generate-new-buffer " *lua-ts-flymake-luacheck*") > + :command `(,lua-ts-luacheck-program > + "--codes" "--ranges" "--formatter" "plain" "-") > + :sentinel > + (lambda (proc _event) > + (when (eq 'exit (process-status proc)) > + (unwind-protect > + (if (with-current-buffer source > + (eq proc lua-ts--flymake-process)) > + (with-current-buffer (process-buffer proc) > + (goto-char (point-min)) > + (cl-loop > + while (search-forward-regexp > + (rx (seq bol > + (0+ alnum) ":" > + (group (1+ digit)) ":" > + (group (1+ digit)) "-" > + (group (1+ digit)) ": " > + (group (0+ nonl)) > + eol)) > + nil t) > + for line = (string-to-number (match-string 1)) > + for beg = (string-to-number (match-string 2)) > + for end = (string-to-number (match-string 3)) > + for msg = (match-string 4) > + for type = (if (string-match "^(W" msg) > + :warning > + :error) > + when (and beg end) > + collect (flymake-make-diagnostic source > + (cons line beg) > + (cons line (1+ end)) > + type > + msg) > + into diags > + finally (funcall report-fn diags))) > + (flymake-log :warning "Canceling obsolete check %s" proc)) > + (kill-buffer (process-buffer proc))))))) > + (process-send-region lua-ts--flymake-process (point-min) (point-max)) > + (process-send-eof lua-ts--flymake-process)))) > + > +;;;###autoload > +(defun lua-ts-inferior-lua () > + "Run a Lua interpreter in an inferior process." > + (interactive) > + (let* ((name lua-ts-inferior-buffer) > + (buffer (concat "*" name "*")) > + (program lua-ts-inferior-program) > + (prompt-regexp lua-ts-inferior-prompt-regexp) > + (switches lua-ts-inferior-options) > + (startfile lua-ts-inferior-startfile)) > + (unless (comint-check-proc buffer) > + (set-buffer (apply (function make-comint) name program startfile switches)) > + (setq-local comint-input-ignoredups t > + comint-prompt-read-only t > + comint-prompt-regexp prompt-regexp > + comint-use-prompt-regexp t)) > + (pop-to-buffer buffer))) I believe that `display-buffer-pop-up-frame' is the preferred alternative to `pop-to-buffer' these days. > + > +;;;###autoload > +(define-derived-mode lua-ts-mode prog-mode "Lua" > + "Major mode for editing Lua files, powered by tree-sitter." > + :syntax-table lua-ts--syntax-table > + > + (when (treesit-ready-p 'lua) > + (treesit-parser-create 'lua) > + > + ;; Comments. > + (setq-local comment-start "--") > + (setq-local comment-start-skip "--\\s-*") > + (setq-local comment-end "") > + > + ;; Font-lock. > + (setq-local treesit-font-lock-settings lua-ts--font-lock-settings) > + (setq-local treesit-font-lock-feature-list > + '((comment definition) > + (keyword property string) > + (assignment builtin constant number) > + (bracket > + delimiter > + escape > + function > + operator > + punctuation > + variable))) > + > + ;; Indent. > + (setq-local treesit-simple-indent-rules lua-ts--simple-indent-rules) > + > + ;; Navigation. > + (setq-local treesit-defun-name-function #'lua-ts--defun-name-function) > + (setq-local treesit-defun-type-regexp > + (rx (or "function_declaration" "function_definition"))) > + (setq-local treesit-thing-settings > + `((lua > + (sentence ,(rx (or "do_statement" > + "field" > + "for_statement" > + "function_call" > + "if_statement" > + "repeat_statement" > + "return_statement" > + "variable_declaration" > + "while_statement"))) > + (sexp ,(rx (or "arguments" > + "block" > + "parameters" > + "string" > + "table_constructor"))) > + (text "comment")))) > + > + ;; Imenu. > + (setq-local treesit-simple-imenu-settings > + `(("Variable" ,(rx bos "variable_declaration" eos) nil nil) > + ("Function" ,(rx bos > + (or "function_declaration" > + "function_definition" > + "field") > + eos) > + nil nil))) > + > + ;; Which-function. > + (setq-local which-func-functions (treesit-defun-at-point)) > + > + ;; Outline. > + (setq-local outline-regexp > + (rx (seq (0+ space) > + (or (seq "--[[" (0+ space) eol) > + (seq symbol-start > + (or "do" "for" "if" "repeat" "while" > + (seq (** 0 1 (seq "local" (1+ space))) aka (? (seq "local" (1+ space))), right? > + "function")) > + symbol-end))))) > + > + (treesit-major-mode-setup)) > + > + (add-hook 'flymake-diagnostic-functions #'lua-ts-flymake-luacheck nil 'local)) > + > +(if (treesit-ready-p 'lua) I would say writing this with `when' would be cleaner. > + (add-to-list 'auto-mode-alist '("\\.lua\\'" . lua-ts-mode))) > + > +(provide 'lua-ts-mode) > + > +;;; lua-ts-mode.el ends here > diff --git a/test/infra/Dockerfile.emba b/test/infra/Dockerfile.emba > index 584e4444dc1..e29098ec270 100644 > --- a/test/infra/Dockerfile.emba > +++ b/test/infra/Dockerfile.emba > @@ -126,6 +126,7 @@ RUN src/emacs -Q --batch \ > (java "https://github.com/tree-sitter/tree-sitter-java") \ > (javascript "https://github.com/tree-sitter/tree-sitter-javascript") \ > (json "https://github.com/tree-sitter/tree-sitter-json") \ > + (lua "https://github.com/MunifTanjim/tree-sitter-lua") \ > (python "https://github.com/tree-sitter/tree-sitter-python") \ > (ruby "https://github.com/tree-sitter/tree-sitter-ruby") \ > (tsx "https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src") \ > diff --git a/test/infra/test-jobs.yml b/test/infra/test-jobs.yml > index 2f6e0dab4d5..1f5d607eda4 100644 > --- a/test/infra/test-jobs.yml > +++ b/test/infra/test-jobs.yml > @@ -580,6 +580,7 @@ test-src-inotify: > lisp/progmodes/go-ts-mode-tests.log > lisp/progmodes/heex-ts-mode-tests.log > lisp/progmodes/java-ts-mode-tests.log > + lisp/progmodes/lua-ts-mode-tests.log > lisp/progmodes/ruby-ts-mode-tests.log > lisp/progmodes/typescript-ts-mode-tests.log > src/treesit-tests.log > diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts > new file mode 100644 > index 00000000000..040225c8580 > --- /dev/null > +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts > @@ -0,0 +1,152 @@ > +Code: > + (lambda () > + (setq indent-tabs-mode nil) > + (setq lua-ts-indent-offset 2) > + (lua-ts-mode) > + (indent-region (point-min) (point-max))) > + > +Name: Basic Indent > + > +=-= > + print( > +0, > + 1 > +) > + > +local function f(o) > + if o.x > o.y then > + return o.x > +elseif o.y > o.z then > + return o.y > + else > +return o.z > + end > +end > + > +f({ > + x = 1, > + y = 2, > + z = 3, > +}) > + > +;(function() > +return false > +)() > +=-= > +print( > + 0, > + 1 > +) > + > +local function f(o) > + if o.x > o.y then > + return o.x > + elseif o.y > o.z then > + return o.y > + else > + return o.z > + end > +end > + > +f({ > + x = 1, > + y = 2, > + z = 3, > +}) > + > +;(function() > + return false > +)() > +=-=-= > + > +Name: Argument Indent > + > +=-= > +function h( > +string, > +number, > +options) > +print(string, number, options) > +end > + > +local p = h( > +"sring", > + 1000, > + { > +cost = 2, > +length = 8, > + parallelism = 4, > +}) > +=-= > +function h( > + string, > + number, > + options) > + print(string, number, options) > +end > + > +local p = h( > + "sring", > + 1000, > + { > + cost = 2, > + length = 8, > + parallelism = 4, > + }) > +=-=-= > + > +Name: Continuation Indent > + > +=-= > +function f() > + local str = [[ > + multi-line > + string > + ]] > +--[[ > +multi-line > +comment > + ]] > +return true > +end > +=-= > +function f() > + local str = [[ > + multi-line > + string > + ]] > + --[[ > +multi-line > +comment > + ]] > + return true > +end > +=-=-= > + > +Name: Loop Indent > + > +=-= > +for k, v in pairs({}) do > + print(k, v) > +end > + > +while n < 10 do > +n = n + 1 > +end > + > +repeat > +z = z * 2 > + until z > 12 > +=-= > +for k, v in pairs({}) do > + print(k, v) > +end > + > +while n < 10 do > + n = n + 1 > +end > + > +repeat > + z = z * 2 > +until z > 12 > +=-=-= > diff --git a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts > new file mode 100644 > index 00000000000..770aa23b18d > --- /dev/null > +++ b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts > @@ -0,0 +1,553 @@ > +Code: > + (lambda () > + (lua-ts-mode) > + (beginning-of-defun 1)) > + > +Point-Char: | > + > +Name: beginning-of-defun moves to start of function declaration > + > +=-= > +local function Test() > + if true then > + print(1) > + else > + print(0) > + end| > +end > +=-= > +|local function Test() > + if true then > + print(1) > + else > + print(0) > + end > +end > +=-=-= > + > +Name: beginning-of-defun moves to start of function definition > + > +=-= > +local t = { > + f = function() > + return true > + end, > +}| > +=-= > +local t = { > +| f = function() > + return true > + end, > +} > +=-=-= > + > +Code: > + (lambda () > + (lua-ts-mode) > + (end-of-defun 1)) > + > +Point-Char: | > + > +Name: end-of-defun moves to end of function declaration > + > +=-= > +local function Test() > + if true then > + pr|int(1) > + else > + print(0) > + end > +end > + > +local t = Test() > +=-= > +local function Test() > + if true then > + print(1) > + else > + print(0) > + end > +end > +| > +local t = Test() > +=-=-= > + > +Name: end-of-defun moves to end of function definition > + > +=-= > +local t = { > + f = function() > + re|turn true > + end, > +} > +=-= > +local t = { > + f = function() > + return true > + end|, > +} > +=-=-= > + > +Code: > + (lambda () > + (lua-ts-mode) > + (forward-sentence 1)) > + > +Point-Char: | > + > +Name: forward-sentence moves over if statements > + > +=-= > +function f() > + |if true then > + print(1) > + elseif false then > + print(0) > + else > + print(2) > + end > +end > +=-= > +function f() > + if true then > + print(1) > + elseif false then > + print(0) > + else > + print(2) > + end| > +end > +=-=-= > + > +Name: forward-sentence moves over variable declaration > + > +=-= > +|local n = 1 > + > +print(n) > +=-= > +local n = 1| > + > +print(n) > +=-=-= > + > +Name: forward-sentence moves over for statements > + > +=-= > +|for k, v in pairs({}) do > + print(k, v) > +end > + > +print(1) > +=-= > +for k, v in pairs({}) do > + print(k, v) > +end| > + > +print(1) > +=-=-= > + > +Name: forward-sentence moves over for statements > + > +=-= > +|do > + local x = 1 > + local y = 2 > + > + print(x, y) > +end > + > +print(1) > +=-= > +do > + local x = 1 > + local y = 2 > + > + print(x, y) > +end| > + > +print(1) > +=-=-= > + > +Name: forward-sentence moves over while statements > + > +=-= > +local i = 0 > +|while i < 9 do > + print(i) > + i = i + 1 > +end > + > +print(1) > +=-= > +local i = 0 > +while i < 9 do > + print(i) > + i = i + 1 > +end| > + > +print(1) > +=-=-= > + > +Name: forward-sentence moves over repeat statements > + > +=-= > +local i = 0 > +|repeat > + print(i) > + i = i + 1 > +until i > 9 > + > +print(1) > +=-= > +local i = 0 > +repeat > + print(i) > + i = i + 1 > +until i > 9| > + > +print(1) > +=-=-= > + > +Name: forward-sentence moves over function calls > + > +=-= > +|print(1) > +=-= > +print(1)| > +=-=-= > + > +Name: forward-sentence moves over return statements > + > +=-= > +function f() > + |return math.random() > +end > +=-= > +function f() > + return math.random()| > +end > +=-=-= > + > +Code: > + (lambda () > + (lua-ts-mode) > + (forward-sentence 2)) > + > +Name: forward-sentence moves over table fields > + > +=-= > +local t = { > + |a = 1, > + b = 2, > +} > +=-= > +local t = { > + a = 1, > + b = 2|, > +} > +=-=-= > + > +Code: > + (lambda () > + (lua-ts-mode) > + (backward-sentence 1)) > + > +Point-Char: | > + > +Name: backward-sentence moves over if statements > + > +=-= > +function f() > + if true then > + print(1) > + elseif false then > + print(0) > + else > + print(2) > + end| > +end > +=-= > +function f() > + |if true then > + print(1) > + elseif false then > + print(0) > + else > + print(2) > + end > +end > +=-=-= > + > +Name: backward-sentence moves over variable declaration > + > +=-= > +local n = 1| > + > +print(n) > +=-= > +|local n = 1 > + > +print(n) > +=-=-= > + > +Name: backward-sentence moves over for statements > + > +=-= > +for k, v in pairs({}) do > + print(k, v) > +end| > + > +print(1) > +=-= > +|for k, v in pairs({}) do > + print(k, v) > +end > + > +print(1) > +=-=-= > + > +Name: backward-sentence moves over for statements > + > +=-= > +do > + local x = 1 > + local y = 2 > + > + print(x, y) > +end| > + > +print(1) > +=-= > +|do > + local x = 1 > + local y = 2 > + > + print(x, y) > +end > + > +print(1) > +=-=-= > + > +Name: backward-sentence moves over while statements > + > +=-= > +local i = 0 > +while i < 9 do > + print(i) > + i = i + 1 > +end| > + > +print(1) > +=-= > +local i = 0 > +|while i < 9 do > + print(i) > + i = i + 1 > +end > + > +print(1) > +=-=-= > + > +Name: backward-sentence moves over repeat statements > + > +=-= > +local i = 0 > +repeat > + print(i) > + i = i + 1 > +until i > 9| > + > +print(1) > +=-= > +local i = 0 > +|repeat > + print(i) > + i = i + 1 > +until i > 9 > + > +print(1) > +=-=-= > + > +Name: backward-sentence moves over function calls > + > +=-= > +print(1)| > +=-= > +|print(1) > +=-=-= > + > +Name: backward-sentence moves over return statements > + > +=-= > +function f() > + return math.random()| > +end > +=-= > +function f() > + |return math.random() > +end > +=-=-= > + > +Code: > + (lambda () > + (lua-ts-mode) > + (backward-sentence 2)) > + > +Point-Char: | > + > +Name: backward-sentence moves over table fields > + > +=-= > +local t = { > + a = 1, > + b = 2|, > +} > +=-= > +local t = { > + |a = 1, > + b = 2, > +} > +=-=-= > + > +Code: > + (lambda () > + (lua-ts-mode) > + (forward-sexp 1)) > + > +Point-Char: | > + > +Name: forward-sexp moves over blocks > + > +=-= > +local function Test() > + |local t = { > + a = 1, > + } > + > + if true then > + print(1) > + else > + print(0) > + end > +end > +=-= > +local function Test() > + local t = { > + a = 1, > + } > + > + if true then > + print(1) > + else > + print(0) > + end| > +end > +=-=-= > + > +Name: forward-sexp moves over arguments > + > +=-= > +print|(1, 2, 3) > +=-= > +print(1, 2, 3)| > +=-=-= > + > +Name: forward-sexp moves over parameters > + > +=-= > +function f|(a, b) end > +=-= > +function f(a, b)| end > +=-=-= > + > +Name: forward-sexp moves over strings > + > +=-= > +print("|1, 2, 3") > +=-= > +print("1, 2, 3|") > +=-=-= > + > +Name: forward-sexp moves over tables > + > +=-= > +local t = |{ 1, > + 2, > + 3 } > +=-= > +local t = { 1, > + 2, > + 3 }| > +=-=-= > + > +Code: > + (lambda () > + (lua-ts-mode) > + (backward-sexp 1)) > + > +Point-Char: | > + > +Name: backward-sexp moves over blocks > + > +=-= > +local function Test() > + local t = { > + a = 1, > + } > + > + if true then > + print(1) > + else > + print(0) > + end| > +end > +=-= > +local function Test() > + |local t = { > + a = 1, > + } > + > + if true then > + print(1) > + else > + print(0) > + end > +end > +=-=-= > + > +Name: backward-sexp moves over arguments > + > +=-= > +print(1, 2, 3)| > +=-= > +print|(1, 2, 3) > +=-=-= > + > +Name: backward-sexp moves over parameters > + > +=-= > +function f(a, b)| end > +=-= > +function f|(a, b) end > +=-=-= > + > +Name: backward-sexp moves over strings > + > +=-= > +print("1, 2, 3|") > +=-= > +print("|1, 2, 3") > +=-=-= > + > +Name: backward-sexp moves over tables > + > +=-= > +local t = { 1, > + 2, > + 3 }| > +=-= > +local t = |{ 1, > + 2, > + 3 } > +=-=-= > diff --git a/test/lisp/progmodes/lua-ts-mode-tests.el b/test/lisp/progmodes/lua-ts-mode-tests.el > new file mode 100644 > index 00000000000..d2105b66f6d > --- /dev/null > +++ b/test/lisp/progmodes/lua-ts-mode-tests.el > @@ -0,0 +1,36 @@ > +;;; lua-ts-mode-tests.el --- Tests for lua-ts-mode -*- lexical-binding: t; -*- > + > +;; Copyright (C) 2023 Free Software Foundation, Inc. > + > +;; This file is part of GNU Emacs. > + > +;; GNU Emacs is free software: you can redistribute it and/or modify > +;; it under the terms of the GNU General Public License as published by > +;; the Free Software Foundation, either version 3 of the License, or > +;; (at your option) any later version. > + > +;; GNU Emacs is distributed in the hope that it will be useful, > +;; but WITHOUT ANY WARRANTY; without even the implied warranty of > +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the > +;; GNU General Public License for more details. > + > +;; You should have received a copy of the GNU General Public License > +;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. > + > +;;; Code: > + > +(require 'ert) > +(require 'ert-x) > +(require 'treesit) > + > +(ert-deftest lua-ts-mode-test-indentation () > + (skip-unless (treesit-ready-p 'lua)) > + (ert-test-erts-file (ert-resource-file "indent.erts"))) > + > +(ert-deftest lua-ts-mode-test-movement () > + (skip-unless (treesit-ready-p 'lua)) > + (ert-test-erts-file (ert-resource-file "movement.erts"))) > + > +(provide 'lua-ts-mode-tests) > + > +;;; lua-ts-mode-tests.el ends here
GNU bug tracking system
Copyright (C) 1999 Darren O. Benham,
1997,2003 nCipher Corporation Ltd,
1994-97 Ian Jackson.