[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
bug#65672: bug#65673: [PATCH emacs 0/1] Add lua-ts-mode
From: |
Philip Kaludercic |
Subject: |
bug#65672: bug#65673: [PATCH emacs 0/1] Add lua-ts-mode |
Date: |
Sat, 02 Sep 2023 12:14:26 +0000 |
~johnmuhl <johnmuhl@git.sr.ht> writes:
> From: john muhl <jm@pub.pink>
>
> * test/lisp/progmodes/lua-ts-mode-tests.el:
> * test/lisp/progmodes/lua-ts-mode-resources/indent.ert:
> * lisp/progmodes/lua-ts-mode.el: New file.
> * lisp/progmodes/eglot.el (eglot-server-programs):
> * lisp/progmodes/hideshow.el (hs-special-modes-alist):
> Add support for lua-ts-mode.
> * admin/notes/tree-sitter/build-module/batch.sh:
> * admin/notes/tree-sitter/build-module/build.sh: Add Lua grammar.
> * test/infra/Dockerfile.emba:
> * test/infra/test-jobs.yml: Add 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 | 2 +-
> lisp/progmodes/hideshow.el | 1 +
> lisp/progmodes/lua-ts-mode.el | 457 ++++++++++++++++++
> test/infra/Dockerfile.emba | 1 +
> test/infra/test-jobs.yml | 1 +
> .../lua-ts-mode-resources/indent.erts | 152 ++++++
> test/lisp/progmodes/lua-ts-mode-tests.el | 32 ++
> 10 files changed, 653 insertions(+), 1 deletion(-)
> 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-tests.el
>
> diff --git a/admin/notes/tree-sitter/build-module/batch.sh
> b/admin/notes/tree-sitter/build-module/batch.sh
> index 1d4076564dc..685a35c269d 100755
> --- a/admin/notes/tree-sitter/build-module/batch.sh
> +++ b/admin/notes/tree-sitter/build-module/batch.sh
> @@ -15,6 +15,7 @@ languages=(
> 'html'
> '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 @@ case "${lang}" in
> "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 9a98db8c83a..1a40a62615b 100644
> --- a/etc/NEWS
> +++ b/etc/NEWS
> @@ -730,6 +730,10 @@ A major mode based on the tree-sitter library for
> editing HEEx files.
> A major mode based on the tree-sitter library for editing Elixir
> files.
>
> +---
> +*** 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 65daa0941d5..f249e3c81b4 100644
> --- a/lisp/progmodes/eglot.el
> +++ b/lisp/progmodes/eglot.el
> @@ -237,7 +237,7 @@ chosen (interactively or automatically)."
> (gdscript-mode . ("localhost" 6008))
> ((fortran-mode f90-mode) . ("fortls"))
> (futhark-mode . ("futhark" "lsp"))
> - (lua-mode . ,(eglot-alternatives
> + ((lua-mode lua-ts-mode) .
> ,(eglot-alternatives
> '("lua-language-server"
> "lua-lsp")))
> (zig-mode . ("zls"))
> ((css-mode css-ts-mode)
> 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 @@ This has effect only if `search-invisible' is set to
> `open'."
> (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..76d1781b30e
> --- /dev/null
> +++ b/lisp/progmodes/lua-ts-mode.el
> @@ -0,0 +1,457 @@
> +;;; lua-ts-mode.el --- Major mode for editing Lua files -*- lexical-binding:
> t -*-
> +
> +;; Copyright (C) 2023 Free Software Foundation, Inc.
> +
> +;; Author: John Muhl <jm@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 'integer
> + :safe 'integerp
> + :group 'lua
> + :version "30.1")
> +
> +(defcustom lua-ts-luacheck-program "luacheck"
> + "Location of the Luacheck program."
> + :type 'string
> + :group 'lua
> + :version "30.1")
> +
> +(defcustom lua-ts-lua-manual
> + (if (file-readable-p "/usr/share/doc/lua/manual.html")
> + "file:///usr/share/doc/lua/manual.html" "")
> + "Location of the Lua `manual.html' file."
> + :type 'string
> + :safe 'stringp
> + :group 'lua
> + :version "30.1")
Could this fall back to some online manual?
> +
> +(defcustom inferior-lua-buffer "*Lua*"
> + "Name of the inferior Lua buffer."
> + :type 'string
> + :safe 'stringp
> + :group 'lua
> + :version "30.1")
> +
> +(defcustom inferior-lua-interpreter "lua"
> + "Program to run in the inferior Lua process."
> + :type 'string
> + :safe 'stringp
> + :group 'lua
> + :version "30.1")
Are you sure that any string is safe? That would include "rm -rf ~".
> +(defcustom inferior-lua-switches "-i"
> + "Command line options for the inferior Lua process."
> + :type 'string
> + :safe 'stringp
> + :group 'lua
> + :version "30.1")
> +
> +(defcustom inferior-lua-startfile ""
> + "File to load into the inferior Lua process at startup."
> + :type 'string
> + :safe 'stringp
> + :group 'lua
> + :version "30.1")
> +
> +(defcustom inferior-lua-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" "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"
> + ;; 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))))))
> +
> +(defun lua-ts--builtin-p (node)
> + "Return t if the NODE is a builtin or nil if not."
> + (let ((name (pcase (treesit-node-type node)
> + ("dot_index_expression"
> + (car (string-split (treesit-node-text node t) "\\." t)))
> + ("function_call"
> + (let* ((child (treesit-node-child-by-field-name node
> "name"))
> + (text (treesit-node-text child t)))
> + (if (string-match-p ":" text)
> + (cadr (string-split text ":" t))
> + text))))))
> + (and name (string-match-p (regexp-opt lua-ts--builtins 'words) name))))
> +
> +(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))))
> +
> +(defun lua-ts-documentation-at-point ()
> + "Show documentation of function at point in Lua manual."
> + (interactive)
> + (unless (string-blank-p lua-ts-lua-manual)
> + (let ((character-before (char-to-string (char-before)))
> + id)
> + (save-excursion
> + ;; When point is mid-word `treesit-thing-at-point'
> + ;; may return the parent node of the thing at point.
> + (unless (or (bolp)
> + (not (string-match-p "[[:alnum:]]" character-before)))
> + (backward-word))
> + (let ((node (treesit-thing-at-point 'builtin nil)))
> + (setq id (pcase (treesit-node-type node)
> + ("dot_index_expression" (treesit-node-text node t))
> + ("function_call"
> + (let* ((child (treesit-node-child-by-field-name node
> "name"))
> + (name (treesit-node-text child t)))
> + (if (string-match-p ":" name)
> + (replace-regexp-in-string "^.*:" "file:" name)
> + name)))))))
> + (when id (browse-url (concat lua-ts-lua-manual "#pdf-" id))))))
> +
> +;;;###autoload
> +(defun inferior-lua ()
> + "Run the Lua interpreter in an inferior process."
> + (interactive)
> + (let ((buffer (get-buffer-create inferior-lua-buffer))
> + (program inferior-lua-interpreter)
> + (switches inferior-lua-switches)
> + (startfile (unless (string-blank-p inferior-lua-startfile)
> + (expand-file-name inferior-lua-startfile))))
> + (make-comint-in-buffer program buffer program startfile switches)
> + (with-current-buffer buffer
> + (setq-local comint-input-ignoredups t
> + comint-prompt-read-only t
> + comint-prompt-regexp inferior-lua-prompt-regexp
> + comint-use-prompt-regexp t))
> + (pop-to-buffer buffer)))
> +
> +;;;###autoload
> +(define-derived-mode lua-ts-mode prog-mode "Lua"
> + "Major mode for editing Lua files, powered by tree-sitter."
> + :group 'lua
The :group is redundant here, it will automatically use the last
defgroup defined in the file.
> + :syntax-table lua-ts--syntax-table
> +
> + (when (treesit-ready-p 'lua)
> + (treesit-parser-create 'lua)
> +
> + (setq-local treesit-thing-settings
> + '((lua . ((builtin lua-ts--builtin-p)))))
> +
> + ;; 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-sentence-type-regexp
> + (rx (or "do_statement" "while_statement" "repeat_statement"
> + "if_statement" "for_statement"
> "variable_declaration")))
> +
> + (setq-local treesit-sexp-type-regexp
> + (rx (or "arguments" "comment" "string" "table_constructor")))
> +
> + ;; 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 (or "--[[" "do" "for" "if" "repeat" "while"
> + (seq (** 0 1 "local ") "function"))))
> +
> + (treesit-major-mode-setup))
> +
> + (add-hook 'flymake-diagnostic-functions #'lua-ts-flymake-luacheck nil
> 'local))
> +
> +(if (treesit-ready-p 'lua)
> + (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-tests.el
> b/test/lisp/progmodes/lua-ts-mode-tests.el
> new file mode 100644
> index 00000000000..62ec2652ba8
> --- /dev/null
> +++ b/test/lisp/progmodes/lua-ts-mode-tests.el
> @@ -0,0 +1,32 @@
> +;;; 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")))
> +
> +(provide 'lua-ts-mode-tests)
> +
> +;;; lua-ts-mode-tests.el ends here
bug#65673: [PATCH] Add lua-ts-mode, john muhl, 2023/09/11