* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems @ 2023-09-22 19:17 Andrey Listopadov 2023-09-22 19:49 ` Eli Zaretskii ` (2 more replies) 0 siblings, 3 replies; 25+ messages in thread From: Andrey Listopadov @ 2023-09-22 19:17 UTC (permalink / raw) To: 66159 I've been editing Lua using the long-existing lua-mode[1] and it works well enough for me, but it's indentation implementation is very slow. Indenting a file with just 600 lines takes several seconds on my machine. So when I saw that Emacs now features a lua-ts-mode package in its core, I tried to move to it, in hopes that it would be faster. However, a lot of code is now indented differently, not how I used to, and this creates a lot of noise in commits, as I often re-indent the whole buffer before saving the file. Here are some examples. lua-mode: function foo (e) if e == nil then return 1000 else return e end end lua-ts-mode: function foo (e) if e == nil then return 1000 else return e end end My thoughts: `then' is indented as the part of the block of code that is part of the `true' branch itself. In lua-mode, it is indented the same as `if' itself, and everything after `then' is indented if moved to a new line: function foo (e) if e == nil then return 1000 else return e end end In lua-ts-mode it is indented together with the body which isn't idiomatic: function foo (e) if e == nil then return 1000 else return e end end Another thing that bothers me is that I prefer Gassanenko-style packing of `end' keywords so that they vertically align with the scope of the opened block, as it saves so much vertical space and is easier for me to read, but lua-ts-mode moves it to the latest innermost indentation level, as opposed to the outermost depending on the count of ends in the line itself: function lowest_entropy_cell(world) | local lowest,res=math.huge,nil | for y=1,world.height do | | for x=1,world.width do | | | local cell=world:get(x,y) | | | if cell.is_set then | | | | local e=cell_enthropy(cell) | | | | trace(e) | | | | if e <= lowest then | | | | | lowest,res=e,{x,y} | end end end end | return res or {math.random(world.width),math.random(world.height)} end However, lua-ts-mode indents it like so: function lowest_entropy_cell(world) local lowest,res=math.huge,nil for y=1,world.height do for x=1,world.width do local cell=world:get(x,y) if cell.is_set then local e=cell_enthropy(cell) trace(e) if e <= lowest then lowest,res=e,{x,y} end end end end return res or {math.random(world.width),math.random(world.height)} end I noticed the difference in table indentations as well. lua-mode: local Recipe = { Floor={up={Floor=true,Wall=true}, down={Floor=true,Wall=true}, left={Floor=true,Wall=true}, right={Floor=true,Wall=true}}, Wall={up={Floor=true,Wall=true}, down={Floor=true,Wall=true}, left={Floor=true,Wall=true}, right={Floor=true,Wall=true}}, Corridor={up={Corridoor=true}, down={Corridoor=true}, left={Corridoor=true}, right={Corridoor=true}} } lua-ts-mode: local Recipe = { Floor={up={Floor=true,Wall=true}, down={Floor=true,Wall=true}, left={Floor=true,Wall=true}, right={Floor=true,Wall=true}}, Wall={up={Floor=true,Wall=true}, down={Floor=true,Wall=true}, left={Floor=true,Wall=true}, right={Floor=true,Wall=true}}, Corridor={up={Corridoor=true}, down={Corridoor=true}, left={Corridoor=true}, right={Corridoor=true}} } The first one is more logical and obeys scope levels. Should I expect this to be the default new way of indenting or the indentation can be made to match the lua-mode where it is sensible? Thanks! P.S. I know that stacking `end' isn't really idiomatic Lua style, but it works in old-lua mode sensible enough that it is actually surprising, and transforms Lua into code that is easy to parse just by looking on the indentation level, much like Lisps. [1] https://github.com/immerrr/lua-mode In GNU Emacs 30.0.50 (build 1, x86_64-pc-linux-gnu, GTK+ Version 3.24.38, cairo version 1.17.8) of 2023-09-18 built on toolbox Repository revision: 861f9cb78370e2b78f852e5ccde9b63c94486ca8 Repository branch: master System Description: Fedora Linux 38 (Container Image) Configured using: 'configure --without-compress-install --with-native-compilation=aot --with-pgtk --with-mailutils --with-xwidgets --prefix=/var/home/alist/.local' Configured features: ACL CAIRO DBUS FREETYPE GIF GLIB GMP GNUTLS GPM GSETTINGS HARFBUZZ JPEG JSON LCMS2 LIBOTF LIBSELINUX LIBXML2 MODULES NATIVE_COMP NOTIFY INOTIFY PDUMPER PGTK PNG RSVG SECCOMP SOUND SQLITE3 THREADS TIFF TOOLKIT_SCROLL_BARS TREE_SITTER XIM XWIDGETS GTK3 ZLIB Important settings: value of $LANG: en_US.UTF-8 locale-coding-system: utf-8-unix Major mode: Lua Minor modes in effect: repeat-mode: t global-git-commit-mode: t magit-auto-revert-mode: t electric-pair-mode: t hl-todo-mode: t savehist-mode: t delete-selection-mode: t pixel-scroll-precision-mode: t global-auto-revert-mode: t corfu-popupinfo-mode: t global-corfu-mode: t corfu-mode: t global-region-bindings-mode: t recentf-mode: t gcmh-mode: t server-mode: t marginalia-mode: t vertico-mode: t override-global-mode: t tooltip-mode: t global-eldoc-mode: t show-paren-mode: t electric-indent-mode: t mouse-wheel-mode: t menu-bar-mode: t file-name-shadow-mode: t context-menu-mode: t global-font-lock-mode: t font-lock-mode: t blink-cursor-mode: t minibuffer-regexp-mode: t column-number-mode: t line-number-mode: t transient-mark-mode: t auto-composition-mode: t auto-encryption-mode: t auto-compression-mode: t abbrev-mode: t hs-minor-mode: t Load-path shadows: /var/home/alist/.config/emacs/elpa/transient-20230915.1911/transient hides /var/home/alist/.local/share/emacs/30.0.50/lisp/transient /var/home/alist/.config/emacs/elpa/modus-themes-20230916.905/theme-loaddefs hides /var/home/alist/.local/share/emacs/30.0.50/lisp/theme-loaddefs Features: (shadow emacsbug dabbrev lua-ts-mode rect lua-mode modus-operandi-theme python geiser-mode geiser-xref geiser-compile geiser-guile tramp trampver tramp-integration tramp-message tramp-compat tramp-loaddefs info-look geiser geiser-debug geiser-repl geiser-image geiser-capf geiser-doc geiser-menu geiser-autodoc geiser-edit etags fileloop geiser-completion geiser-eval geiser-connection tq geiser-syntax geiser-log geiser-popup geiser-impl help-fns radix-tree geiser-custom geiser-base scheme find-dired grep display-line-numbers css-mode treesit smie mu4e-alert advice time ht alert log4e notifications gntp mu4e mu4e-org mu4e-main mu4e-view mu4e-headers mu4e-compose mu4e-draft mu4e-actions smtpmail mu4e-search mu4e-lists mu4e-bookmarks mu4e-mark mu4e-message flow-fill hl-line mu4e-contacts mu4e-update mu4e-folders mu4e-server mu4e-context mu4e-vars mu4e-helpers mu4e-config ido tabify cus-start repeat files-x org-archive puni pulse color consult ox-odt rng-loc rng-uri rng-parse rng-match rng-dt rng-util rng-pttrn nxml-parse nxml-ns nxml-enc xmltok nxml-util ox-icalendar org-agenda ox-ascii ox-latex ox-hugo ox-hugo-deprecated ffap ox-blackfriday ox-md ox-html table ox-publish tomelr ox sgml-mode facemenu xwidget magit-bookmark bookmark goto-addr vc-hg vc-bzr vc-src vc-sccs vc-svn vc-cvs vc-rcs log-view vc bug-reference vc-git vc-dispatcher misearch multi-isearch dired-aux face-remap magit-extras orderless flyspell ispell org-element org-persist org-id org-refile avl-tree generator oc-basic ol-eww eww xdg url-queue mm-url ol-rmail ol-mhe ol-irc ol-info ol-gnus nnselect gnus-art mm-uu mml2015 mm-view mml-smime smime gnutls dig gnus-sum shr pixel-fill kinsoku url-file svg dom gnus-group gnus-undo gnus-start gnus-dbus gnus-cloud nnimap nnmail mail-source utf7 nnoo parse-time gnus-spec gnus-int gnus-range gnus-win gnus nnheader range ol-docview doc-view jka-compr image-mode exif ol-bibtex bibtex iso8601 ol-bbdb ol-w3m ol-doi org-link-doi org-tempo tempo ob-fennel fennel-proto-repl fennel-mode inf-lisp xref magit-submodule magit-blame magit-stash magit-reflog magit-bisect magit-push magit-pull magit-fetch magit-clone magit-remote magit-commit magit-sequence magit-notes magit-worktree magit-tag magit-merge magit-branch magit-reset magit-files magit-refs magit-status magit magit-repos magit-apply magit-wip magit-log which-func imenu magit-diff smerge-mode diff diff-mode git-commit log-edit message sendmail yank-media puny dired dired-loaddefs rfc822 mml mml-sec epa epg rfc6068 epg-config gnus-util mm-decode mm-bodies mm-encode mail-parse rfc2231 rfc2047 rfc2045 mm-util ietf-drums mail-prsvr mailabbrev mail-utils gmm-utils mailheader pcvs-util add-log magit-core magit-autorevert magit-margin magit-transient magit-process with-editor magit-mode transient magit-git magit-base magit-section cursor-sensor crm project ob-lua ob-shell shell org ob ob-tangle ob-ref ob-lob ob-table ob-exp org-macro org-src ob-comint org-pcomplete pcomplete org-list org-footnote org-faces org-entities ob-emacs-lisp ob-core ob-eval org-cycle org-table org-keys oc org-loaddefs find-func cal-menu calendar cal-loaddefs vertico-directory mule-util time-date noutline outline elec-pair isayt disp-table hideshow hl-todo savehist delsel pixel-scroll cua-base autorevert filenotify corfu-popupinfo cape corfu region-bindings recentf tree-widget gcmh init proxy gsettings s gvariant parsec dash zig-compilation-mode fennel-compilation-mode clojure-compilation-mode derived compile text-property-search server ediff ediff-merg ediff-mult ediff-wind ediff-diff ediff-help ediff-init ediff-util sql-indent sql view thingatpt comint ansi-osc ring zig-mode reformatter ansi-color ol org-fold org-fold-core org-compat org-version org-macs format-spec blog marginalia vertico compat use-package-delight formfeed modus-vivendi-theme modus-themes dbus xml common-lisp-modes novice cus-edit pp cus-load wid-edit font mode-line edmacro kmacro messages use-package-bind-key bind-key defaults functions local-config delight comp comp-cstr warnings icons rx use-package-ensure cl-extra help-mode use-package-core early-init cape-autoloads clj-decompiler-autoloads clj-refactor-autoloads cider-autoloads clojure-mode-autoloads common-lisp-modes-autoloads consult-autoloads corfu-terminal-autoloads corfu-autoloads csv-mode-autoloads delight-autoloads dumb-jump-autoloads eat-autoloads elfeed-autoloads expand-region-autoloads fennel-mode-autoloads gcmh-autoloads geiser-guile-autoloads geiser-autoloads gsettings-autoloads gvariant-autoloads hl-todo-autoloads inflections-autoloads isayt-autoloads jdecomp-autoloads lisp-extra-font-lock-autoloads lsp-java-autoloads lsp-metals-autoloads dap-mode-autoloads lsp-docker-autoloads bui-autoloads lsp-treemacs-autoloads lsp-mode-autoloads f-autoloads lua-mode-autoloads marginalia-autoloads markdown-mode-autoloads message-view-patch-autoloads magit-autoloads pcase magit-section-autoloads git-commit-autoloads modus-themes-autoloads mu4e-alert-autoloads alert-autoloads log4e-autoloads gntp-autoloads multiple-cursors-autoloads orderless-autoloads org-modern-autoloads org-tree-slide-autoloads ox-hugo-autoloads package-lint-flymake-autoloads package-lint-autoloads paredit-autoloads parsec-autoloads parseedn-autoloads parseclj-autoloads phi-search-autoloads poly-org-autoloads polymode-autoloads popon-autoloads popup-autoloads puni-autoloads easy-mmode finder-inf queue-autoloads racket-mode-autoloads region-bindings-autoloads request-autoloads scala-mode-autoloads separedit-autoloads edit-indirect-autoloads sesman-autoloads sly-autoloads spinner-autoloads sql-indent-autoloads tomelr-autoloads transient-autoloads treemacs-autoloads cfrs-autoloads posframe-autoloads ht-autoloads hydra-autoloads lv-autoloads pfuture-autoloads ace-window-autoloads avy-autoloads s-autoloads dash-autoloads vertico-autoloads vundo-autoloads with-editor-autoloads info compat-autoloads yaml-autoloads yaml-mode-autoloads yasnippet-autoloads zig-mode-autoloads reformatter-autoloads package browse-url url url-proxy url-privacy url-expand url-methods url-history url-cookie generate-lisp-file url-domsuf url-util mailcap url-handlers url-parse auth-source cl-seq eieio eieio-core cl-macs password-cache json subr-x map byte-opt gv bytecomp byte-compile url-vars cl-loaddefs cl-lib rmc iso-transl tooltip cconv eldoc paren electric uniquify ediff-hook vc-hooks lisp-float-type elisp-mode mwheel term/pgtk-win pgtk-win term/common-win pgtk-dnd touch-screen tool-bar dnd fontset image regexp-opt fringe tabulated-list replace newcomment text-mode lisp-mode prog-mode register page tab-bar menu-bar rfn-eshadow isearch easymenu timer select scroll-bar mouse jit-lock font-lock syntax font-core term/tty-colors frame minibuffer nadvice seq simple cl-generic indonesian philippine cham georgian utf-8-lang misc-lang vietnamese tibetan thai tai-viet lao korean japanese eucjp-ms cp51932 hebrew greek romanian slovak czech european ethiopic indian cyrillic chinese composite emoji-zwj charscript charprop case-table epa-hook jka-cmpr-hook help abbrev obarray oclosure cl-preloaded button loaddefs theme-loaddefs faces cus-face macroexp files window text-properties overlay sha1 md5 base64 format env code-pages mule custom widget keymap hashtable-print-readable backquote threads xwidget-internal dbusbind inotify dynamic-setting system-font-setting font-render-setting cairo gtk pgtk lcms2 multi-tty move-toolbar make-network-process native-compile emacs) Memory information: ((conses 16 1147781 1425356) (symbols 48 52742 50) (strings 32 272573 78657) (string-bytes 1 9908365) (vectors 16 119200) (vector-slots 8 2827929 951125) (floats 8 888 21739) (intervals 56 40788 17575) (buffers 992 46)) -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-22 19:17 bug#66159: 30.0.50; lua-ts-mode semantic indentation problems Andrey Listopadov @ 2023-09-22 19:49 ` Eli Zaretskii 2023-09-24 15:06 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-06 19:44 ` bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2 siblings, 0 replies; 25+ messages in thread From: Eli Zaretskii @ 2023-09-22 19:49 UTC (permalink / raw) To: Andrey Listopadov, john muhl; +Cc: 66159 > From: Andrey Listopadov <andreyorst@gmail.com> > Date: Fri, 22 Sep 2023 22:17:55 +0300 > > > I've been editing Lua using the long-existing lua-mode[1] and it works > well enough for me, but it's indentation implementation is very slow. > Indenting a file with just 600 lines takes several seconds on my > machine. So when I saw that Emacs now features a lua-ts-mode package in > its core, I tried to move to it, in hopes that it would be faster. > > However, a lot of code is now indented differently, not how I used to, > and this creates a lot of noise in commits, as I often re-indent the > whole buffer before saving the file. Here are some examples. John, could you please look into this? ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-22 19:17 bug#66159: 30.0.50; lua-ts-mode semantic indentation problems Andrey Listopadov 2023-09-22 19:49 ` Eli Zaretskii @ 2023-09-24 15:06 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-24 15:44 ` Eli Zaretskii 2023-09-24 16:38 ` Andrey Listopadov 2023-10-06 19:44 ` bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2 siblings, 2 replies; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-24 15:06 UTC (permalink / raw) To: Andrey Listopadov; +Cc: 66159 [-- Attachment #1: Type: text/plain, Size: 2157 bytes --] Andrey Listopadov <andreyorst@gmail.com> writes: > I've been editing Lua using the long-existing lua-mode[1] and it works > well enough for me, but it's indentation implementation is very slow. > Indenting a file with just 600 lines takes several seconds on my > machine. So when I saw that Emacs now features a lua-ts-mode package > in its core, I tried to move to it, in hopes that it would be faster. Thanks for trying. > However, a lot of code is now indented differently, not how I used to, > and this creates a lot of noise in commits, as I often re-indent the > whole buffer before saving the file. Here are some examples. The "then" and table examples should indent how you like with the attached patch. Arguments and parameters now also work like your table example so you can have: local function fn(a, b, c, another) end fn(1, 2, 3, {a="first", b="second"}) > Another thing that bothers me is that I prefer Gassanenko-style packing > of `end' keywords so that they vertically align with the scope of the > opened block, as it saves so much vertical space and is easier for me to > read, but lua-ts-mode moves it to the latest innermost indentation > level, as opposed to the outermost depending on the count of ends in the > line itself: > > function lowest_entropy_cell(world) > | local lowest,res=math.huge,nil > | for y=1,world.height do > | | for x=1,world.width do > | | | local cell=world:get(x,y) > | | | if cell.is_set then > | | | | local e=cell_enthropy(cell) > | | | | trace(e) > | | | | if e <= lowest then > | | | | | lowest,res=e,{x,y} > | end end end end > | return res or {math.random(world.width),math.random(world.height)} > end I don't see any reason not to support that style but I'm not sure how to do it. A patch would be welcome but I'll try to figure it out sometime. > Should I expect this to be the default new way of indenting or the > indentation can be made to match the lua-mode where it is sensible? Sure. It's a new mode so nothing is really set in stone. Let me know if you have other suggestions. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Improve-indentation-in-lus-ts-mode-Bug-66159.patch --] [-- Type: text/x-patch, Size: 5287 bytes --] From d24d1d128fd29ead355334612ccca3f5e2e1fbd2 Mon Sep 17 00:00:00 2001 From: john muhl <jm@pub.pink> Date: Sat, 23 Sep 2023 10:49:11 -0500 Subject: [PATCH] Improve indentation in lus-ts-mode (Bug#66159) - Align "then" with if/elseif/else/end when it appears at the beginning of a line. - Anchor indent of the first child in arguments, parameters and tables to the parent and the other children to the first. * lisp/progmodes/lua-ts-mode.el (lua-ts--first-child) (lua-ts--simple-indent-rules): Improve indentation. * test/lisp/progmodes/lua-ts-mode-resources/indent.erts: Add tests. --- lisp/progmodes/lua-ts-mode.el | 17 ++- .../lua-ts-mode-resources/indent.erts | 125 ++++++++++++++++++ 2 files changed, 139 insertions(+), 3 deletions(-) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 030a3585158..3d946dd1de2 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -233,6 +233,10 @@ lua-ts--font-lock-settings '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `lua-ts-mode'.") +(defun lua-ts--first-child (node _p _b &rest _) + "Matches if NODE is the first among its siblings." + (= (treesit-node-index node) 1)) + (defvar lua-ts--simple-indent-rules `((lua ((parent-is "chunk") column-0 0) @@ -240,6 +244,7 @@ lua-ts--simple-indent-rules ((parent-is "block") parent-bol 0) ((node-is "}") parent-bol 0) ((node-is ")") parent-bol 0) + ((node-is "then") standalone-parent 0) ((node-is "else_statement") parent-bol 0) ((node-is "elseif_statement") parent-bol 0) ((node-is "end") parent-bol 0) @@ -251,9 +256,15 @@ lua-ts--simple-indent-rules ((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) + ((and (parent-is "table_constructor") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "table_constructor") (nth-sibling 1) 0) + ((and (parent-is "arguments") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "arguments") (nth-sibling 1) 0) + ((and (parent-is "parameters") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "parameters") (nth-sibling 1) 0) ((parent-is "ERROR") no-indent 0)))) (defvar lua-ts--syntax-table diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts index 040225c8580..999e01e3e37 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts @@ -32,6 +32,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-= print( 0, @@ -57,6 +73,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-=-= Name: Argument Indent @@ -77,6 +109,13 @@ cost = 2, length = 8, parallelism = 4, }) + +fn(1, +2, + 3) + +fn(1, 2, +3) =-= function h( string, @@ -93,6 +132,13 @@ local p = h( length = 8, parallelism = 4, }) + +fn(1, + 2, + 3) + +fn(1, 2, + 3) =-=-= Name: Continuation Indent @@ -150,3 +196,82 @@ repeat z = z * 2 until z > 12 =-=-= + +Name: Parameter Indent + +=-= +fn(a, +b) end + +fn(a, b, +c) end + +fn( +a, +b +) end +=-= +fn(a, + b) end + +fn(a, b, + c) end + +fn( + a, + b +) end +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq lua-ts-indent-offset 4) + (lua-ts-mode) + (indent-region (point-min) (point-max))) + +Name: Table Indent + +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { +a = 1, + b = 2, + c = 3, +} +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { + a = 1, + b = 2, + c = 3, +} +=-=-= -- 2.41.0 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-24 15:06 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-24 15:44 ` Eli Zaretskii 2023-09-24 16:38 ` Andrey Listopadov 1 sibling, 0 replies; 25+ messages in thread From: Eli Zaretskii @ 2023-09-24 15:44 UTC (permalink / raw) To: john muhl; +Cc: andreyorst, 66159 > Cc: 66159@debbugs.gnu.org > Date: Sun, 24 Sep 2023 10:06:50 -0500 > From: john muhl via "Bug reports for GNU Emacs, > the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> > > > Another thing that bothers me is that I prefer Gassanenko-style packing > > of `end' keywords so that they vertically align with the scope of the > > opened block, as it saves so much vertical space and is easier for me to > > read, but lua-ts-mode moves it to the latest innermost indentation > > level, as opposed to the outermost depending on the count of ends in the > > line itself: > > > > function lowest_entropy_cell(world) > > | local lowest,res=math.huge,nil > > | for y=1,world.height do > > | | for x=1,world.width do > > | | | local cell=world:get(x,y) > > | | | if cell.is_set then > > | | | | local e=cell_enthropy(cell) > > | | | | trace(e) > > | | | | if e <= lowest then > > | | | | | lowest,res=e,{x,y} > > | end end end end > > | return res or {math.random(world.width),math.random(world.height)} > > end > > I don't see any reason not to support that style but I'm not sure how to > do it. A patch would be welcome but I'll try to figure it out sometime. Maybe introduce indentation styles into lua-ts-mode, like CC Mode and c-ts-mode have? ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-24 15:06 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-24 15:44 ` Eli Zaretskii @ 2023-09-24 16:38 ` Andrey Listopadov 2023-09-24 18:20 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 25+ messages in thread From: Andrey Listopadov @ 2023-09-24 16:38 UTC (permalink / raw) To: john muhl; +Cc: 66159 Thanks! The patch seems to work as I would expect for most cases. > I don't see any reason not to support that style but I'm not sure how to > do it. A patch would be welcome but I'll try to figure it out sometime. A far as I understand it, in the `lua-mode' the overall line indentation is computed via subtracting indentation for every `end' in that line, e.g. `end end end' subtracts `lua-indent-level three times from current indent level. > Sure. It's a new mode so nothing is really set in stone. Let me know if > you have other suggestions. I also noticed that `lua-ts-inferior-lua` for some reason starts itself in a new frame instead of just a new window. I haven't seen this behavior with other inferior-*-modes, and the `lua-start-process' function from `lua-mode' doesn't spawn a new frame either. Looking at the code, it seems that it was a deliberate choice, as I see the use of `display-buffer-pop-up-frame' in the `display-buffer' ACTION arg. -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-24 16:38 ` Andrey Listopadov @ 2023-09-24 18:20 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-26 19:21 ` Andrey Listopadov 2023-09-30 7:52 ` Philip Kaludercic 0 siblings, 2 replies; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-24 18:20 UTC (permalink / raw) To: Andrey Listopadov; +Cc: 66159, Philip Kaludercic, Eli Zaretskii [-- Attachment #1: Type: text/plain, Size: 2481 bytes --] Eli Zaretskii <eliz@gnu.org> writes: >> > Another thing that bothers me is that I prefer Gassanenko-style packing >> > of `end' keywords so that they vertically align with the scope of the >> > opened block, as it saves so much vertical space and is easier for me to >> > read, but lua-ts-mode moves it to the latest innermost indentation >> > level, as opposed to the outermost depending on the count of ends in the >> > line itself: >> >> I don't see any reason not to support that style but I'm not sure how to >> do it. A patch would be welcome but I'll try to figure it out sometime. > > Maybe introduce indentation styles into lua-ts-mode, like CC Mode and > c-ts-mode have? I’ll have a look at what the c-ts-mode styles do and see what might be applicable. In this case the changes can be accommodated by default. Andrey Listopadov <andreyorst@gmail.com> writes: > Thanks! The patch seems to work as I would expect for most cases. > >> I don't see any reason not to support that style but I'm not sure how to >> do it. A patch would be welcome but I'll try to figure it out sometime. > > A far as I understand it, in the `lua-mode' the overall line indentation > is computed via subtracting indentation for every `end' in that line, > e.g. `end end end' subtracts `lua-indent-level three times from current > indent level. Thanks for the explanation. The attached patch should make end packing work now. >> Sure. It's a new mode so nothing is really set in stone. Let me know if >> you have other suggestions. > > I also noticed that `lua-ts-inferior-lua` for some reason starts itself > in a new frame instead of just a new window. I haven't seen this > behavior with other inferior-*-modes, and the `lua-start-process' > function from `lua-mode' doesn't spawn a new frame either. > > Looking at the code, it seems that it was a deliberate choice, as I see > the use of `display-buffer-pop-up-frame' in the `display-buffer' ACTION > arg. It did use a window originally but I was asked to change it: >> + (pop-to-buffer buffer))) > > I believe that `display-buffer-pop-up-frame' is the preferred alternative > to `pop-to-buffer' these days. Maybe I misunderstood and it was only about not using ‘pop-to-buffer’ and should have been ‘display-buffer-pop-up-window’. CC’d Philip for clarification. If you customize where you want it with ‘display-buffer-alist’ that should be respected. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Improve-indentation-in-lus-ts-mode-Bug-66159.patch --] [-- Type: text/x-patch, Size: 7431 bytes --] From c32ce5aef2c8692cb93e6d91a7dc08af4b50c210 Mon Sep 17 00:00:00 2001 From: john muhl <jm@pub.pink> Date: Sat, 23 Sep 2023 10:49:11 -0500 Subject: [PATCH] Improve indentation in lus-ts-mode (Bug#66159) - Align "then" with if/elseif/else/end when it appears at the beginning of a line. - Align a single-line of "end"s with the beginning of the outermost block being closed. - Anchor indent of the first child in arguments, parameters and tables to the parent and the other children to the first. * lisp/progmodes/lua-ts-mode.el (lua-ts--first-child) (lua-ts--end-indent-offset) (lua-ts--simple-indent-rules): Improve indentation. * test/lisp/progmodes/lua-ts-mode-resources/indent.erts: Add tests. --- lisp/progmodes/lua-ts-mode.el | 26 ++- .../lua-ts-mode-resources/indent.erts | 179 ++++++++++++++++++ 2 files changed, 201 insertions(+), 4 deletions(-) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 030a3585158..fcab8ec610b 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -233,6 +233,17 @@ lua-ts--font-lock-settings '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `lua-ts-mode'.") +(defun lua-ts--first-child (node _p _b &rest _) + "Matches if NODE is the first among its siblings." + (= (treesit-node-index node) 1)) + +(defun lua-ts--end-indent-offset (_n _p _b &rest _) + "Calculate indent offset based on `end' count." + (let* ((beg (line-beginning-position)) + (end (line-end-position)) + (count (count-matches "end" beg end))) + (- (* (1- count) lua-ts-indent-offset)))) + (defvar lua-ts--simple-indent-rules `((lua ((parent-is "chunk") column-0 0) @@ -240,9 +251,10 @@ lua-ts--simple-indent-rules ((parent-is "block") parent-bol 0) ((node-is "}") parent-bol 0) ((node-is ")") parent-bol 0) + ((node-is "then") standalone-parent 0) ((node-is "else_statement") parent-bol 0) ((node-is "elseif_statement") parent-bol 0) - ((node-is "end") parent-bol 0) + ((node-is "end") parent-bol lua-ts--end-indent-offset) ((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) @@ -251,9 +263,15 @@ lua-ts--simple-indent-rules ((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) + ((and (parent-is "table_constructor") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "table_constructor") (nth-sibling 1) 0) + ((and (parent-is "arguments") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "arguments") (nth-sibling 1) 0) + ((and (parent-is "parameters") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "parameters") (nth-sibling 1) 0) ((parent-is "ERROR") no-indent 0)))) (defvar lua-ts--syntax-table diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts index 040225c8580..b0cfe11ef6f 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts @@ -32,6 +32,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-= print( 0, @@ -57,6 +73,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-=-= Name: Argument Indent @@ -77,6 +109,13 @@ cost = 2, length = 8, parallelism = 4, }) + +fn(1, +2, + 3) + +fn(1, 2, +3) =-= function h( string, @@ -93,6 +132,13 @@ local p = h( length = 8, parallelism = 4, }) + +fn(1, + 2, + 3) + +fn(1, 2, + 3) =-=-= Name: Continuation Indent @@ -150,3 +196,136 @@ repeat z = z * 2 until z > 12 =-=-= + +Name: Parameter Indent + +=-= +fn(a, +b) end + +fn(a, b, +c) end + +fn( +a, +b +) end +=-= +fn(a, + b) end + +fn(a, b, + c) end + +fn( + a, + b +) end +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq lua-ts-indent-offset 4) + (lua-ts-mode) + (indent-region (point-min) (point-max))) + +Name: Table Indent + +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { +a = 1, + b = 2, + c = 3, +} +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { + a = 1, + b = 2, + c = 3, +} +=-=-= + +Name: Single Line End + +=-= +function lowest_entropy_cell(world) + local lowest,res=math.huge,nil + for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end end end end + return res or {math.random(w.w),math.random(w.h)} +end + +for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end + end end end +=-= +function lowest_entropy_cell(world) + local lowest,res=math.huge,nil + for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end end end end + return res or {math.random(w.w),math.random(w.h)} +end + +for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end +end end end +=-=-= -- 2.41.0 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-24 18:20 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-26 19:21 ` Andrey Listopadov 2023-09-27 1:18 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-30 7:52 ` Philip Kaludercic 1 sibling, 1 reply; 25+ messages in thread From: Andrey Listopadov @ 2023-09-26 19:21 UTC (permalink / raw) To: john muhl; +Cc: 66159, Philip Kaludercic, Eli Zaretskii john muhl <jm@pub.pink> writes: > Eli Zaretskii <eliz@gnu.org> writes: > >>> > Another thing that bothers me is that I prefer Gassanenko-style packing >>> > of `end' keywords so that they vertically align with the scope of the >>> > opened block, as it saves so much vertical space and is easier for me to >>> > read, but lua-ts-mode moves it to the latest innermost indentation >>> > level, as opposed to the outermost depending on the count of ends in the >>> > line itself: >>> >>> I don't see any reason not to support that style but I'm not sure how to >>> do it. A patch would be welcome but I'll try to figure it out sometime. >> >> Maybe introduce indentation styles into lua-ts-mode, like CC Mode and >> c-ts-mode have? > > I’ll have a look at what the c-ts-mode styles do and see what might be > applicable. In this case the changes can be accommodated by default. In my opinion, this isn't distinct enough to introduce a new style. But it's up to you to decide, of course - I'm all for better editing experience for Lua! >> A far as I understand it, in the `lua-mode' the overall line indentation >> is computed via subtracting indentation for every `end' in that line, >> e.g. `end end end' subtracts `lua-indent-level three times from current >> indent level. > > Thanks for the explanation. The attached patch should make end packing > work now. I've tried your latest patch and indeed `end' now pack themselves as in the lua-mode. Thank you very much! >>> Sure. It's a new mode so nothing is really set in stone. Let me know if >>> you have other suggestions. I noticed that the `do' keyword is indented similarly to `then' before the patch when put on the new line: for i=1,10 do print(i) end I'm not sure if that's a proper way to indent it or not though, but `do' usually signifies start of the scope, so perhaps it shouldn't be indented in this case. There are also some weirdness in semantic navigation, but it's more likely that I'm just not used to new ts-backed navigation yet. Thanks for your work on lua-ts-mode, it's much more snappy editing experience now! If you're willing to dig into some (pretty crazy) involved examples, I can send here some really convoluted nested anonymous functions that currently are indented in a weird way in both modes. Neither does it exactly right in my opiion, but I also don't know if there is the right way to indent this. I can send these examples later this week once I finish an article I'm working on rightnow. -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-26 19:21 ` Andrey Listopadov @ 2023-09-27 1:18 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-30 9:59 ` Andrey Listopadov 0 siblings, 1 reply; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-27 1:18 UTC (permalink / raw) To: Andrey Listopadov; +Cc: 66159, Philip Kaludercic, Eli Zaretskii [-- Attachment #1: Type: text/plain, Size: 3035 bytes --] Andrey Listopadov <andreyorst@gmail.com> writes: > john muhl <jm@pub.pink> writes: > >> Eli Zaretskii <eliz@gnu.org> writes: >> >>>> > Another thing that bothers me is that I prefer Gassanenko-style packing >>>> > of `end' keywords so that they vertically align with the scope of the >>>> > opened block, as it saves so much vertical space and is easier for me to >>>> > read, but lua-ts-mode moves it to the latest innermost indentation >>>> > level, as opposed to the outermost depending on the count of ends in the >>>> > line itself: >>>> >>>> I don't see any reason not to support that style but I'm not sure how to >>>> do it. A patch would be welcome but I'll try to figure it out sometime. >>> >>> Maybe introduce indentation styles into lua-ts-mode, like CC Mode and >>> c-ts-mode have? >> >> I’ll have a look at what the c-ts-mode styles do and see what might be >> applicable. In this case the changes can be accommodated by default. > > In my opinion, this isn't distinct enough to introduce a new style. > But it's up to you to decide, of course - I'm all for better editing > experience for Lua! I agree there’s no immediate need. Could you explain what the lua-indent-* options do in lua-mode? I tried toggling them but didn’t see any difference between on/off. >>> A far as I understand it, in the `lua-mode' the overall line indentation >>> is computed via subtracting indentation for every `end' in that line, >>> e.g. `end end end' subtracts `lua-indent-level three times from current >>> indent level. >> >> Thanks for the explanation. The attached patch should make end packing >> work now. > > I've tried your latest patch and indeed `end' now pack themselves as in > the lua-mode. Thank you very much! > >>>> Sure. It's a new mode so nothing is really set in stone. Let me know if >>>> you have other suggestions. > > I noticed that the `do' keyword is indented similarly to `then' before > the patch when put on the new line: > > for i=1,10 > do > print(i) > end > > I'm not sure if that's a proper way to indent it or not though, but `do' > usually signifies start of the scope, so perhaps it shouldn't be > indented in this case. Fixed in the attached. > There are also some weirdness in semantic navigation, but it's more > likely that I'm just not used to new ts-backed navigation yet. I’m sure there is room for improvement here too. Suggestions welcome. > Thanks for your work on lua-ts-mode, it's much more snappy editing > experience now! Glad to hear it. > If you're willing to dig into some (pretty crazy) involved examples, I > can send here some really convoluted nested anonymous functions that > currently are indented in a weird way in both modes. Neither does it > exactly right in my opiion, but I also don't know if there is the right > way to indent this. I can send these examples later this week once I > finish an article I'm working on rightnow. Sure. Whenever you have the time. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Improve-indentation-in-lus-ts-mode-Bug-66159.patch --] [-- Type: text/x-patch, Size: 7874 bytes --] From 5d41635442d2c1032d015d90527bc5bf6113d291 Mon Sep 17 00:00:00 2001 From: john muhl <jm@pub.pink> Date: Sat, 23 Sep 2023 10:49:11 -0500 Subject: [PATCH] Improve indentation in lus-ts-mode (Bug#66159) - Align lines starting with "then" or "do" to the same level as the corresponding "if" or "for" statement. - Align a single-line of "end"s with the beginning of the outermost block being closed. - Anchor indent of the first child in arguments, parameters and tables to the parent and the other children to the first. * lisp/progmodes/lua-ts-mode.el (lua-ts--first-child) (lua-ts--end-indent-offset) (lua-ts--simple-indent-rules): Improve indentation. * test/lisp/progmodes/lua-ts-mode-resources/indent.erts: Add tests. --- lisp/progmodes/lua-ts-mode.el | 27 ++- .../lua-ts-mode-resources/indent.erts | 199 ++++++++++++++++++ 2 files changed, 222 insertions(+), 4 deletions(-) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 030a3585158..418d53e0578 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -233,6 +233,17 @@ lua-ts--font-lock-settings '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `lua-ts-mode'.") +(defun lua-ts--first-child (node _p _b &rest _) + "Matches if NODE is the first among its siblings." + (= (treesit-node-index node) 1)) + +(defun lua-ts--end-indent-offset (_n _p _b &rest _) + "Calculate indent offset based on `end' count." + (let* ((beg (line-beginning-position)) + (end (line-end-position)) + (count (count-matches "end" beg end))) + (- (* (1- count) lua-ts-indent-offset)))) + (defvar lua-ts--simple-indent-rules `((lua ((parent-is "chunk") column-0 0) @@ -240,9 +251,11 @@ lua-ts--simple-indent-rules ((parent-is "block") parent-bol 0) ((node-is "}") parent-bol 0) ((node-is ")") parent-bol 0) + ((node-is "do") standalone-parent 0) + ((node-is "then") standalone-parent 0) ((node-is "else_statement") parent-bol 0) ((node-is "elseif_statement") parent-bol 0) - ((node-is "end") parent-bol 0) + ((node-is "end") parent-bol lua-ts--end-indent-offset) ((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) @@ -251,9 +264,15 @@ lua-ts--simple-indent-rules ((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) + ((and (parent-is "table_constructor") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "table_constructor") (nth-sibling 1) 0) + ((and (parent-is "arguments") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "arguments") (nth-sibling 1) 0) + ((and (parent-is "parameters") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "parameters") (nth-sibling 1) 0) ((parent-is "ERROR") no-indent 0)))) (defvar lua-ts--syntax-table diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts index 040225c8580..a36a933e640 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts @@ -32,6 +32,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-= print( 0, @@ -57,6 +73,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-=-= Name: Argument Indent @@ -77,6 +109,13 @@ cost = 2, length = 8, parallelism = 4, }) + +fn(1, +2, + 3) + +fn(1, 2, +3) =-= function h( string, @@ -93,6 +132,13 @@ local p = h( length = 8, parallelism = 4, }) + +fn(1, + 2, + 3) + +fn(1, 2, + 3) =-=-= Name: Continuation Indent @@ -130,10 +176,20 @@ for k, v in pairs({}) do print(k, v) end +for i=1,10 + do + print(i) +end + while n < 10 do n = n + 1 end +while n < 10 + do + n = n + 1 +end + repeat z = z * 2 until z > 12 @@ -142,11 +198,154 @@ for k, v in pairs({}) do print(k, v) end +for i=1,10 +do + print(i) +end + while n < 10 do n = n + 1 end +while n < 10 +do + n = n + 1 +end + repeat z = z * 2 until z > 12 =-=-= + +Name: Parameter Indent + +=-= +fn(a, +b) end + +fn(a, b, +c) end + +fn( +a, +b +) end +=-= +fn(a, + b) end + +fn(a, b, + c) end + +fn( + a, + b +) end +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq lua-ts-indent-offset 4) + (lua-ts-mode) + (indent-region (point-min) (point-max))) + +Name: Table Indent + +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { +a = 1, + b = 2, + c = 3, +} +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { + a = 1, + b = 2, + c = 3, +} +=-=-= + +Name: Single Line End + +=-= +function lowest_entropy_cell(world) + local lowest,res=math.huge,nil + for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end end end end + return res or {math.random(w.w),math.random(w.h)} +end + +for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end + end end end +=-= +function lowest_entropy_cell(world) + local lowest,res=math.huge,nil + for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end end end end + return res or {math.random(w.w),math.random(w.h)} +end + +for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end +end end end +=-=-= -- 2.41.0 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-27 1:18 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-30 9:59 ` Andrey Listopadov 2023-09-30 13:57 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 25+ messages in thread From: Andrey Listopadov @ 2023-09-30 9:59 UTC (permalink / raw) To: john muhl; +Cc: 66159, Philip Kaludercic, Eli Zaretskii john muhl <jm@pub.pink> writes: > I agree there’s no immediate need. > > Could you explain what the lua-indent-* options do in lua-mode? I tried > toggling them but didn’t see any difference between on/off. I don't really know it myself, sorry. There seem to be some specifics regarding how the content inside parenthesis is indented, but I'm not using these either. >> There are also some weirdness in semantic navigation, but it's more >> likely that I'm just not used to new ts-backed navigation yet. > > I’m sure there is room for improvement here too. Suggestions welcome. Here are a few examples. the █ represents the point: █(function (x) return x + 1 end)(41) Pressing C-M-f (forward-sexp) puts the point here: (function (x)█return x + 1 end)(41) I would expect it to go over the whole parenthesized expression: (function (x) return x + 1 end)█(41) Another weird thing here: function foo (x) if false then print "foo" elseif true then print "bar" end end█ Pressing C-M-b (backward-sexp) puts the point here: function foo (x) █if false then print "foo" elseif true then print "bar" end end I would expect it to go before the `function' instead: █function foo (x) if false then print "foo" elseif true then print "bar" end end >> If you're willing to dig into some (pretty crazy) involved examples, I >> can send here some really convoluted nested anonymous functions that >> currently are indented in a weird way in both modes. Neither does it >> exactly right in my opiion, but I also don't know if there is the right >> way to indent this. I can send these examples later this week once I >> finish an article I'm working on rightnow. > > Sure. Whenever you have the time. I've tried a couple of Lua formatters available, and as far as I can see, most of them indent my code in a weird way too, so perhaps it's not really a problem, although I'm not sure. For example, here's a piece of code that implements an iterator wrapper with anonymous functions only: 1 function partitioning (n, collect) 2 return function (iterator) 3 return function (...) 4 return ( 5 function (next1, ...) 6 local count, arr, last = 0, {} 7 return (function (f, ...) 8 return (function (i, ...) return i(i, ...) end)( 9 function (i, ...) 10 return f(function (x, ...) 11 return i(i, ...)(x, ...) 12 end, ...) 13 end) 14 end)(function (step) 15 return function(iterable, ...) 16 return (function (recur, iterable, ...) 17 if nil ~= ... then 18 if n-1 == count then 19 local arr1, count1 = arr, count 20 arr, count = {}, 0 21 return (function (...) 22 last = ... 23 return ... 24 end)(collect(arr1, count1+1, ...)) 25 else 26 count = count + 1 27 return recur(iterable, 28 (function (...) 29 last = ... 30 return ... 31 end)(collect(arr, count, ...))) 32 end 33 elseif count ~= 0 then 34 count = 0 35 return last, arr 36 end 37 end)(step, iterable, next1(iterable, ...)) 38 end 39 end), ... 40 end)(iterator(...)) 41 end 42 end 43 end Here are the lines I find strange. First, the Immediately Invoked Function Expression (IIFE) indentation is all over the place: 8 return (function (i, ...) return i(i, ...) end)( 9 function (i, ...) 10 return f(function (x, ...) 11 return i(i, ...)(x, ...) 12 end, ...) 13 end) The I would expect the inner IIFE to be indented like this: 8 return (function (i, ...) return i(i, ...) end)( 9 function (i, ...) 10 return f(function (x, ...) 11 return i(i, ...)(x, ...) 12 end, ...) 13 end) Another strange snippet: 21 return (function (...) 22 last = ... 23 return ... 24 end)(collect(arr1, count1+1, ...)) The `last' and `return' statements are not properly indented to the function's scope. I expected it to be indented like this: 21 return (function (...) 22 last = ... 23 return ... 24 end)(collect(arr1, count1+1, ...)) And, weirdly, enough, a bit further in the code there's a similar expression, but it is indented correctly: 27 return recur(iterable, 28 (function (...) 29 last = ... 30 return ... 31 end)(collect(arr, count, ...))) I know, that this code is convoluted, and probably no one writes like this, it was done on purpose for an article about the power of anonymous functions, so perhaps it isn't really a problem for most Lua programmers. But it makes reading code a bit harder in rare cases like this. I have more examples in the article, feel free to grab them if you need code snippets for testing: https://andreyor.st/posts/2023-09-26-iterator-based-transducers-in-lua/ Other than that, and the navigation issues I've mentioned above, the mode works solidly. I've also noticed that some of the `lua-mode' default shortcuts are missing, like `C-c C-f' (lua-search-documentation) and `C-c C-l' (lua-send-buffer), but these may be out of the scope of this module, so let me know if I should just define these myself. Thanks! -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-30 9:59 ` Andrey Listopadov @ 2023-09-30 13:57 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-03 15:04 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-09-30 13:57 UTC (permalink / raw) To: Andrey Listopadov; +Cc: 66159, Eli Zaretskii [-- Attachment #1: Type: text/plain, Size: 2914 bytes --] Andrey Listopadov <andreyorst@gmail.com> writes: > john muhl <jm@pub.pink> writes: > >> I agree there’s no immediate need. >> >> Could you explain what the lua-indent-* options do in lua-mode? I tried >> toggling them but didn’t see any difference between on/off. > > I don't really know it myself, sorry. There seem to be some specifics > regarding how the content inside parenthesis is indented, but I'm not > using these either. I found <https://github.com/immerrr/lua-mode/pull/151> with the explanation of those options. >>> There are also some weirdness in semantic navigation, but it's more >>> likely that I'm just not used to new ts-backed navigation yet. >> >> I’m sure there is room for improvement here too. Suggestions welcome. > > Here are a few examples. the █ represents the point: Fixed in the attached. >>> If you're willing to dig into some (pretty crazy) involved examples, I >>> can send here some really convoluted nested anonymous functions that >>> currently are indented in a weird way in both modes. Neither does it >>> exactly right in my opiion, but I also don't know if there is the right >>> way to indent this. I can send these examples later this week once I >>> finish an article I'm working on rightnow. >> >> Sure. Whenever you have the time. > > I know, that this code is convoluted, and probably no one writes like > this, it was done on purpose for an article about the power of anonymous > functions, so perhaps it isn't really a problem for most Lua > programmers. But it makes reading code a bit harder in rare cases like > this. I have more examples in the article, feel free to grab them if you > need code snippets for testing: > > https://andreyor.st/posts/2023-09-26-iterator-based-transducers-in-lua/ Thanks. The patch gets pretty close on the partitioning function from your article (the mapping, filtering and taking functions indent correctly now). The trouble is that you end up with a tree like: (return_statement (expression_list (function_call (parenthesized_expression (function_definition (end)))))) with two different indent styles. return (function (f, ...) -- L7 end)(function (step) -- L14 return (function (...) -- L21 end)(collect(arr1, count1+1, ...)) -- L24 Is there some pattern for deciding that I’m missing? > Other than that, and the navigation issues I've mentioned above, the > mode works solidly. I've also noticed that some of the `lua-mode' > default shortcuts are missing, like `C-c C-f' > (lua-search-documentation) The opening a browser to look at the docs approach isn’t very Emacs-y so didn’t make the cut. Ideally it should integrate with info and/or eldoc but I haven’t gotten to it yet. This should get you by in the meantime: [-- Attachment #2: lua-ts-documentation-at-point --] [-- Type: text/plain, Size: 1193 bytes --] (defun jm~lua-ts-documentation-at-point () "Show documentation of function at point in the Lua manual." (interactive) (save-excursion ;; When point is mid-word `treesit-thing-at-point' may return ;; the parent node of the thing at point. Go to the beginning ;; of the line or word to make sure we have the right thing. (unless (or (bolp) (not (string-match-p "[[:alnum:]]" (char-to-string (char-before))))) (backward-word)) (when-let* ((node (treesit-thing-at-point 'sentence nil)) ((equal "function_call" (treesit-node-type node))) (child (treesit-node-child-by-field-name node "name")) (name (treesit-node-text child t)) (id (if (string-match-p ":" name) (replace-regexp-in-string "^.*:" "file:" name) name)) ((string-match-p (rx-to-string `(: (? "file:") (or ,@lua-ts--builtins))) id))) (browse-url (concat "file:///usr/share/doc/lua/manual.html" "#pdf-" id))))) [-- Attachment #3: Type: text/plain, Size: 434 bytes --] > and `C-c C-l' (lua-send-buffer), but these may be out of the scope of > this module, so let me know if I should just define these myself. The attached patch includes lua-ts-send-{buffer,file,region} commands with bindings for: C-c C-n start inferior Lua C-c C-c send buffer C-c C-l send file C-c C-r send region I’ve been using a send-thing but wasn’t sure it’s worth including. What do you think? [-- Attachment #4: lua-ts-send-thing --] [-- Type: text/plain, Size: 928 bytes --] (defun jm~lua-ts-send-thing (point) "Send thing near POINT to the inferior Lua process." (interactive "d") (when-let* ((node (treesit-node-at point)) (parent (treesit-parent-until node (lambda (p) (string-match-p (rx (or "do_statement" "for_statement" "function_call" "function_declaration" "if_statement" "repeat_statement" "while_statement")) (treesit-node-type p))) t))) (lua-ts-send-region (treesit-node-start parent) (treesit-node-end parent)))) [-- Attachment #5: Type: text/plain, Size: 258 bytes --] It looks at the tree around point and tries to find something to eval; e.g. function fun[1](n) if n > 1 th[2]en print(1) else p[3]rint(0) end end Point at [1] sends the function, [2] the if statement, [3] the print statement. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #6: 0001-Various-improvements-in-lus-ts-mode-Bug-66159.patch --] [-- Type: text/x-patch, Size: 18355 bytes --] From f746dc8bcbe70cccb6d810cfa0e6480d7d6a752a Mon Sep 17 00:00:00 2001 From: john muhl <jm@pub.pink> Date: Sat, 23 Sep 2023 10:49:11 -0500 Subject: [PATCH] Various improvements in lus-ts-mode (Bug#66159) * lisp/progmodes/lua-ts-mode.el (lua-ts--first-child) (lua-ts--end-indent-offset) (lua-ts--simple-indent-rules): Improve indentation. (lua-ts-inferior--write-history) (lua-ts-inferior-lua): Improve inferior Lua interaction. (lua-ts-mode-map): Add keymap. (lua-ts-mode-menu): Add menu. (lua-ts-mode): Add mode map and improve sexp navigation. (lua-ts-send-buffer) (lua-ts-send-file) (lua-ts-send-line) (lua-ts-send-region) (lua-ts-show-process-buffer) (lua-ts-hide-process-buffer) (lua-ts-kill-process): New functions. (lua-ts-mode-hook) (lua-ts-inferior-prompt-regexp) (lua-ts-inferior-prompt) (lua-ts-inferior-prompt-continue) (lua-ts-inferior-history): New variables. --- lisp/progmodes/lua-ts-mode.el | 207 ++++++++++++++++-- .../lua-ts-mode-resources/indent.erts | 199 +++++++++++++++++ .../lua-ts-mode-resources/movement.erts | 56 +++++ 3 files changed, 438 insertions(+), 24 deletions(-) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 030a3585158..f3fb48ee18a 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -48,6 +48,15 @@ lua-ts :prefix "lua-ts-" :group 'languages) +(defcustom lua-ts-mode-hook nil + "Hook run after entering `lua-ts-mode'." + :type 'hook + :options '(flymake-mode + hs-minor-mode + outline-minor-mode) + :group 'lua-ts + :version "30.1") + (defcustom lua-ts-indent-offset 4 "Number of spaces for each indentation step in `lua-ts-mode'." :type 'natnum @@ -86,9 +95,22 @@ lua-ts-inferior-startfile :group 'lua-ts :version "30.1") -(defcustom lua-ts-inferior-prompt-regexp "^>>?[[:blank:]]" - "Regular expression matching the prompt of the inferior Lua process." - :type 'regexp +(defcustom lua-ts-inferior-prompt ">" + "The prompt of the inferior Lua process." + :type 'string + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-prompt-continue ">>" + "The continuation prompt of the inferior Lua process." + :type 'string + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-history nil + "File used to save command history of the inferior Lua process." + :type '(choice (const nil) file) + :safe 'string-or-null-p :group 'lua-ts :version "30.1") @@ -233,27 +255,65 @@ lua-ts--font-lock-settings '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `lua-ts-mode'.") +(defun lua-ts--first-child (node _p _b &rest _) + "Matches if NODE is the first among its siblings." + (= (treesit-node-index node) 1)) + +(defun lua-ts--end-indent-offset (_n _p _b &rest _) + "Calculate indent offset based on `end' count." + (let* ((beg (line-beginning-position)) + (end (line-end-position)) + (count (count-matches "end" beg end))) + (- (* (1- count) lua-ts-indent-offset)))) + (defvar lua-ts--simple-indent-rules `((lua + ((n-p-gp "end" "function_definition" "arguments") + parent 0) + ((n-p-gp "end" "function_definition" "parenthesized_expression") + parent 0) + ((and (n-p-gp "block" "function_definition" "arguments") + (lambda (_n parent &rest _) + (save-excursion + (goto-char (treesit-node-start parent)) + (backward-char 2) + (not (looking-at ")"))))) + parent lua-ts-indent-offset) + ((and (n-p-gp "block" "function_definition" "parenthesized_expression") + (lambda (node _p bol &rest _) + (equal "assignment_statement" + (treesit-node-type + (treesit-node-first-child-for-pos node bol))))) + parent lua-ts-indent-offset) ((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 "do") standalone-parent 0) + ((node-is "then") standalone-parent 0) ((node-is "else_statement") parent-bol 0) ((node-is "elseif_statement") parent-bol 0) - ((node-is "end") parent-bol 0) + ((node-is "end") parent-bol lua-ts--end-indent-offset) ((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 "function_definition") standalone-parent lua-ts-indent-offset) + ((parent-is "parenthesized_expression") + standalone-parent 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) + ((and (parent-is "table_constructor") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "table_constructor") (nth-sibling 1) 0) + ((and (parent-is "arguments") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "arguments") (nth-sibling 1) 0) + ((and (parent-is "parameters") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "parameters") (nth-sibling 1) 0) ((parent-is "ERROR") no-indent 0)))) (defvar lua-ts--syntax-table @@ -348,30 +408,127 @@ lua-ts-flymake-luacheck (process-send-region lua-ts--flymake-process (point-min) (point-max)) (process-send-eof lua-ts--flymake-process)))) +(defun lua-ts-inferior--write-history (process _event) + "Write history file for inferior Lua PROCESS." + ;; Depending on how the process is killed the buffer may + ;; not be around anymore; e.g. `kill-buffer'. + (when-let* ((buffer (process-buffer process)) + ((buffer-live-p buffer))) + (with-current-buffer buffer (comint-write-input-ring)))) + ;;;###autoload (defun lua-ts-inferior-lua () "Run a Lua interpreter in an inferior process." (interactive) - (let* ((buffer lua-ts-inferior-buffer) - (name (string-replace "*" "" buffer)) - (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)) - (select-window (display-buffer buffer '((display-buffer-reuse-window - display-buffer-pop-up-frame) - (reusable-frames . t)))))) + (unless (comint-check-proc lua-ts-inferior-buffer) + (apply #'make-comint-in-buffer + (string-replace "*" "" lua-ts-inferior-buffer) + lua-ts-inferior-buffer + lua-ts-inferior-program + lua-ts-inferior-startfile + lua-ts-inferior-options) + (when lua-ts-inferior-history + (set-process-sentinel (get-buffer-process lua-ts-inferior-buffer) + 'lua-ts-inferior--write-history)) + (with-current-buffer lua-ts-inferior-buffer + (setq comint-prompt-regexp (rx-to-string `(: bol + ,lua-ts-inferior-prompt + space))) + (setq-local comint-input-ignoredups t) + (setq-local comint-input-ring-file-name lua-ts-inferior-history) + (setq-local comint-prompt-read-only t) + (setq-local comint-use-prompt-regexp t) + (comint-read-input-ring t) + (add-hook 'comint-preoutput-filter-functions + (lambda (string) + (if (equal string (concat lua-ts-inferior-prompt-continue " ")) + string ; Don't mess with continuation prompts. + (concat + ;; Filter out the extra prompt characters that + ;; accumulate in the output when sending regions + ;; to the inferior process. + (replace-regexp-in-string (rx-to-string + `(: bol + (* ,lua-ts-inferior-prompt + (? ,lua-ts-inferior-prompt) + space) + (group (* nonl)))) + "\\1" string) + ;; Re-add the prompt for the next line. + lua-ts-inferior-prompt " ")))))) + (select-window (display-buffer lua-ts-inferior-buffer + '((display-buffer-reuse-window + display-buffer-pop-up-window) + (reusable-frames . t)))) + (get-buffer-process (current-buffer))) + +(defun lua-ts-send-buffer () + "Send current buffer to the inferior Lua process." + (interactive) + (lua-ts-send-region (point-min) (point-max))) + +(defun lua-ts-send-file (file) + "Send contents of FILE to the inferior Lua process." + (interactive "f") + (with-temp-buffer + (insert-file-contents-literally file) + (lua-ts-send-region (point-min) (point-max)))) + +(defun lua-ts-send-region (beg end) + "Send region between BEG and END to the inferior Lua process." + (interactive "r") + (let ((string (buffer-substring-no-properties beg end)) + (proc-buffer (lua-ts-inferior-lua))) + (comint-send-string proc-buffer "print()") ; Prevent output from + (comint-send-string proc-buffer "\n") ; appearing at prompt. + (comint-send-string proc-buffer string) + (comint-send-string proc-buffer "\n"))) + +(defun lua-ts-show-process-buffer () + "Show the inferior Lua process buffer." + (interactive) + (display-buffer lua-ts-inferior-buffer)) + +(defun lua-ts-hide-process-buffer () + "Hide the inferior Lua process buffer." + (interactive) + (delete-windows-on lua-ts-inferior-buffer)) + +(defun lua-ts-kill-process () + "Kill the inferior Lua process." + (interactive) + (with-current-buffer lua-ts-inferior-buffer + (kill-buffer-and-window))) + +(defvar lua-ts-mode-map + (let ((map (make-sparse-keymap "Lua"))) + (define-key map "\C-c\C-n" 'lua-ts-inferior-lua) + (define-key map "\C-c\C-c" 'lua-ts-send-buffer) + (define-key map "\C-c\C-l" 'lua-ts-send-file) + map) + "Keymap for `lua-ts-mode' buffers.") + +(easy-menu-define lua-ts-mode-menu lua-ts-mode-map + "Menu bar entry for `lua-ts-mode'." + `("Lua" + ["Evaluate Buffer" lua-ts-send-buffer] + ["Evaluate File" lua-ts-send-file] + ["Evaluate Region" lua-ts-send-region] + "--" + ["Start Process" lua-ts-inferior-lua] + ["Show Process Buffer" lua-ts-show-process-buffer] + ["Hide Process Buffer" lua-ts-hide-process-buffer] + ["Kill Process" lua-ts-kill-process] + "--" + ["Customize" (lambda () (interactive) (customize-group "lua-ts"))])) ;;;###autoload (define-derived-mode lua-ts-mode prog-mode "Lua" - "Major mode for editing Lua files, powered by tree-sitter." + "Major mode for editing Lua files, powered by tree-sitter. + +\\{lua-ts-mode-map}" :syntax-table lua-ts--syntax-table + (use-local-map lua-ts-mode-map) (when (treesit-ready-p 'lua) (treesit-parser-create 'lua) @@ -415,7 +572,9 @@ lua-ts-mode "while_statement"))) (sexp ,(rx (or "arguments" "block" + "function_declaration" "parameters" + "parenthesized_expression" "string" "table_constructor"))) (text "comment")))) diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts index 040225c8580..c407d3400f8 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts @@ -32,6 +32,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-= print( 0, @@ -57,6 +73,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-=-= Name: Argument Indent @@ -77,6 +109,13 @@ cost = 2, length = 8, parallelism = 4, }) + +fn(1, +2, + 3) + +fn(1, 2, +3) =-= function h( string, @@ -93,6 +132,13 @@ local p = h( length = 8, parallelism = 4, }) + +fn(1, + 2, + 3) + +fn(1, 2, + 3) =-=-= Name: Continuation Indent @@ -130,10 +176,20 @@ for k, v in pairs({}) do print(k, v) end +for i=1,10 + do + print(i) +end + while n < 10 do n = n + 1 end +while n < 10 + do + n = n + 1 +end + repeat z = z * 2 until z > 12 @@ -142,11 +198,154 @@ for k, v in pairs({}) do print(k, v) end +for i=1,10 +do + print(i) +end + while n < 10 do n = n + 1 end +while n < 10 +do + n = n + 1 +end + repeat z = z * 2 until z > 12 =-=-= + +Name: Parameter Indent + +=-= +fn(a, +b) + +fn(a, b, +c) + +fn( +a, +b +) +=-= +fn(a, + b) + +fn(a, b, + c) + +fn( + a, + b +) +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq lua-ts-indent-offset 4) + (lua-ts-mode) + (indent-region (point-min) (point-max))) + +Name: Table Indent + +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { +a = 1, + b = 2, + c = 3, +} +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { + a = 1, + b = 2, + c = 3, +} +=-=-= + +Name: Single Line End + +=-= +function lowest_entropy_cell(world) + local lowest,res=math.huge,nil + for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end end end end + return res or {math.random(w.w),math.random(w.h)} +end + +for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end + end end end +=-= +function lowest_entropy_cell(world) + local lowest,res=math.huge,nil + for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end end end end + return res or {math.random(w.w),math.random(w.h)} +end + +for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end +end end end +=-=-= diff --git a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts index 770aa23b18d..afebe93de3f 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts @@ -481,6 +481,34 @@ local t = { 1, 3 }| =-=-= +Name: forward-sexp moves over parenthesized expressions + +=-= +|(function (x) return x + 1 end)(41) +=-= +(function (x) return x + 1 end)|(41) +=-=-= + +Name: forward-sexp moves over function declarations + +=-= +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-=-= + Code: (lambda () (lua-ts-mode) @@ -551,3 +579,31 @@ local t = |{ 1, 2, 3 } =-=-= + +Name: backward-sexp moves over parenthesized expressions + +=-= +(function (x) return x + 1 end)|(41) +=-= +|(function (x) return x + 1 end)(41) +=-=-= + +Name: backward-sexp moves over function declarations + +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-= +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-=-= -- 2.41.0 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-30 13:57 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-03 15:04 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-03 19:13 ` Andrey Listopadov 0 siblings, 1 reply; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-03 15:04 UTC (permalink / raw) To: Andrey Listopadov; +Cc: 66159, Eli Zaretskii [-- Attachment #1: Type: text/plain, Size: 92 bytes --] Whoops. Looks like I forgot to update the patch before sending. This one should be better. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Various-improvements-in-lus-ts-mode-Bug-66159.patch --] [-- Type: text/x-patch, Size: 18788 bytes --] From 4ee42d82557e188537693c3a27b2246ed690c2a6 Mon Sep 17 00:00:00 2001 From: john muhl <jm@pub.pink> Date: Sat, 23 Sep 2023 10:49:11 -0500 Subject: [PATCH] Various improvements in lus-ts-mode (Bug#66159) * lisp/progmodes/lua-ts-mode.el (lua-ts--first-child) (lua-ts--end-indent-offset) (lua-ts--simple-indent-rules): Improve indentation. (lua-ts-inferior--write-history) (lua-ts-inferior-lua): Improve inferior Lua interaction. (lua-ts-mode-map): Add keymap. (lua-ts-mode-menu): Add menu. (lua-ts-mode): Add mode map and improve sexp navigation. (lua-ts-send-buffer) (lua-ts-send-file) (lua-ts-send-line) (lua-ts-send-region) (lua-ts-show-process-buffer) (lua-ts-hide-process-buffer) (lua-ts-kill-process): New functions. (lua-ts-mode-hook) (lua-ts-inferior-prompt-regexp) (lua-ts-inferior-prompt) (lua-ts-inferior-prompt-continue) (lua-ts-inferior-history): New variables. --- lisp/progmodes/lua-ts-mode.el | 210 ++++++++++++++++-- .../lua-ts-mode-resources/indent.erts | 199 +++++++++++++++++ .../lua-ts-mode-resources/movement.erts | 56 +++++ 3 files changed, 441 insertions(+), 24 deletions(-) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 030a3585158..d1930d9f2b1 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -39,7 +39,9 @@ (require 'rx)) (declare-function treesit-node-child-by-field-name "treesit.c") +(declare-function treesit-node-first-child-for-pos "treesit.c") (declare-function treesit-node-type "treesit.c") +(declare-function treesit-node-start "treesit.c") (declare-function treesit-parser-create "treesit.c") (declare-function treesit-search-subtree "treesit.c") @@ -48,6 +50,15 @@ lua-ts :prefix "lua-ts-" :group 'languages) +(defcustom lua-ts-mode-hook nil + "Hook run after entering `lua-ts-mode'." + :type 'hook + :options '(flymake-mode + hs-minor-mode + outline-minor-mode) + :group 'lua-ts + :version "30.1") + (defcustom lua-ts-indent-offset 4 "Number of spaces for each indentation step in `lua-ts-mode'." :type 'natnum @@ -86,9 +97,22 @@ lua-ts-inferior-startfile :group 'lua-ts :version "30.1") -(defcustom lua-ts-inferior-prompt-regexp "^>>?[[:blank:]]" - "Regular expression matching the prompt of the inferior Lua process." - :type 'regexp +(defcustom lua-ts-inferior-prompt ">" + "The prompt of the inferior Lua process." + :type 'string + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-prompt-continue ">>" + "The continuation prompt of the inferior Lua process." + :type 'string + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-history nil + "File used to save command history of the inferior Lua process." + :type '(choice (const nil) file) + :safe 'string-or-null-p :group 'lua-ts :version "30.1") @@ -233,27 +257,65 @@ lua-ts--font-lock-settings '((ERROR) @font-lock-warning-face)) "Tree-sitter font-lock settings for `lua-ts-mode'.") +(defun lua-ts--first-child (node _p _b &rest _) + "Matches if NODE is the first among its siblings." + (= (treesit-node-index node) 1)) + +(defun lua-ts--end-indent-offset (_n _p _b &rest _) + "Calculate indent offset based on `end' count." + (let* ((beg (line-beginning-position)) + (end (line-end-position)) + (count (count-matches "end" beg end))) + (- (* (1- count) lua-ts-indent-offset)))) + (defvar lua-ts--simple-indent-rules `((lua + ((n-p-gp "end" "function_definition" "arguments") + parent 0) + ((n-p-gp "end" "function_definition" "parenthesized_expression") + parent 0) + ((and (n-p-gp "block" "function_definition" "arguments") + (lambda (_n parent &rest _) + (save-excursion + (goto-char (treesit-node-start parent)) + (backward-char 2) + (not (looking-at ")"))))) + parent lua-ts-indent-offset) + ((and (n-p-gp "block" "function_definition" "parenthesized_expression") + (lambda (node _p bol &rest _) + (equal "assignment_statement" + (treesit-node-type + (treesit-node-first-child-for-pos node bol))))) + parent lua-ts-indent-offset) ((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 "do") standalone-parent 0) + ((node-is "then") standalone-parent 0) ((node-is "else_statement") parent-bol 0) ((node-is "elseif_statement") parent-bol 0) - ((node-is "end") parent-bol 0) + ((node-is "end") parent-bol lua-ts--end-indent-offset) ((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 "function_definition") standalone-parent lua-ts-indent-offset) + ((parent-is "parenthesized_expression") + standalone-parent 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) + ((and (parent-is "table_constructor") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "table_constructor") (nth-sibling 1) 0) + ((and (parent-is "arguments") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "arguments") (nth-sibling 1) 0) + ((and (parent-is "parameters") lua-ts--first-child) + parent-bol lua-ts-indent-offset) + ((parent-is "parameters") (nth-sibling 1) 0) ((parent-is "ERROR") no-indent 0)))) (defvar lua-ts--syntax-table @@ -348,30 +410,128 @@ lua-ts-flymake-luacheck (process-send-region lua-ts--flymake-process (point-min) (point-max)) (process-send-eof lua-ts--flymake-process)))) +(defun lua-ts-inferior--write-history (process _event) + "Write history file for inferior Lua PROCESS." + ;; Depending on how the process is killed the buffer may + ;; not be around anymore; e.g. `kill-buffer'. + (when-let* ((buffer (process-buffer process)) + ((buffer-live-p buffer))) + (with-current-buffer buffer (comint-write-input-ring)))) + ;;;###autoload (defun lua-ts-inferior-lua () "Run a Lua interpreter in an inferior process." (interactive) - (let* ((buffer lua-ts-inferior-buffer) - (name (string-replace "*" "" buffer)) - (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)) - (select-window (display-buffer buffer '((display-buffer-reuse-window - display-buffer-pop-up-frame) - (reusable-frames . t)))))) + (unless (comint-check-proc lua-ts-inferior-buffer) + (apply #'make-comint-in-buffer + (string-replace "*" "" lua-ts-inferior-buffer) + lua-ts-inferior-buffer + lua-ts-inferior-program + lua-ts-inferior-startfile + lua-ts-inferior-options) + (when lua-ts-inferior-history + (set-process-sentinel (get-buffer-process lua-ts-inferior-buffer) + 'lua-ts-inferior--write-history)) + (with-current-buffer lua-ts-inferior-buffer + (setq comint-prompt-regexp (rx-to-string `(: bol + ,lua-ts-inferior-prompt + space))) + (setq-local comint-input-ignoredups t) + (setq-local comint-input-ring-file-name lua-ts-inferior-history) + (setq-local comint-prompt-read-only t) + (setq-local comint-use-prompt-regexp t) + (comint-read-input-ring t) + (add-hook 'comint-preoutput-filter-functions + (lambda (string) + (if (equal string (concat lua-ts-inferior-prompt-continue " ")) + string ; Don't mess with continuation prompts. + (concat + ;; Filter out the extra prompt characters that + ;; accumulate in the output when sending regions + ;; to the inferior process. + (replace-regexp-in-string (rx-to-string + `(: bol + (* ,lua-ts-inferior-prompt + (? ,lua-ts-inferior-prompt) + space) + (group (* nonl)))) + "\\1" string) + ;; Re-add the prompt for the next line. + lua-ts-inferior-prompt " ")))))) + (select-window (display-buffer lua-ts-inferior-buffer + '((display-buffer-reuse-window + display-buffer-pop-up-window) + (reusable-frames . t)))) + (get-buffer-process (current-buffer))) + +(defun lua-ts-send-buffer () + "Send current buffer to the inferior Lua process." + (interactive) + (lua-ts-send-region (point-min) (point-max))) + +(defun lua-ts-send-file (file) + "Send contents of FILE to the inferior Lua process." + (interactive "f") + (with-temp-buffer + (insert-file-contents-literally file) + (lua-ts-send-region (point-min) (point-max)))) + +(defun lua-ts-send-region (beg end) + "Send region between BEG and END to the inferior Lua process." + (interactive "r") + (let ((string (buffer-substring-no-properties beg end)) + (proc-buffer (lua-ts-inferior-lua))) + (comint-send-string proc-buffer "print()") ; Prevent output from + (comint-send-string proc-buffer "\n") ; appearing at prompt. + (comint-send-string proc-buffer string) + (comint-send-string proc-buffer "\n"))) + +(defun lua-ts-show-process-buffer () + "Show the inferior Lua process buffer." + (interactive) + (display-buffer lua-ts-inferior-buffer)) + +(defun lua-ts-hide-process-buffer () + "Hide the inferior Lua process buffer." + (interactive) + (delete-windows-on lua-ts-inferior-buffer)) + +(defun lua-ts-kill-process () + "Kill the inferior Lua process." + (interactive) + (with-current-buffer lua-ts-inferior-buffer + (kill-buffer-and-window))) + +(defvar lua-ts-mode-map + (let ((map (make-sparse-keymap "Lua"))) + (define-key map "\C-c\C-n" 'lua-ts-inferior-lua) + (define-key map "\C-c\C-c" 'lua-ts-send-buffer) + (define-key map "\C-c\C-l" 'lua-ts-send-file) + (define-key map "\C-c\C-r" 'lua-ts-send-region) + map) + "Keymap for `lua-ts-mode' buffers.") + +(easy-menu-define lua-ts-mode-menu lua-ts-mode-map + "Menu bar entry for `lua-ts-mode'." + `("Lua" + ["Evaluate Buffer" lua-ts-send-buffer] + ["Evaluate File" lua-ts-send-file] + ["Evaluate Region" lua-ts-send-region] + "--" + ["Start Process" lua-ts-inferior-lua] + ["Show Process Buffer" lua-ts-show-process-buffer] + ["Hide Process Buffer" lua-ts-hide-process-buffer] + ["Kill Process" lua-ts-kill-process] + "--" + ["Customize" (lambda () (interactive) (customize-group "lua-ts"))])) ;;;###autoload (define-derived-mode lua-ts-mode prog-mode "Lua" - "Major mode for editing Lua files, powered by tree-sitter." + "Major mode for editing Lua files, powered by tree-sitter. + +\\{lua-ts-mode-map}" :syntax-table lua-ts--syntax-table + (use-local-map lua-ts-mode-map) (when (treesit-ready-p 'lua) (treesit-parser-create 'lua) @@ -415,7 +575,9 @@ lua-ts-mode "while_statement"))) (sexp ,(rx (or "arguments" "block" + "function_declaration" "parameters" + "parenthesized_expression" "string" "table_constructor"))) (text "comment")))) diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts index 040225c8580..c407d3400f8 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts @@ -32,6 +32,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-= print( 0, @@ -57,6 +73,22 @@ f({ ;(function() return false )() + +function foo (e) + if e == nil + then return 1000 + else return e + end +end + +function foo (e) + if e == nil + then + return 1000 + else + return e + end +end =-=-= Name: Argument Indent @@ -77,6 +109,13 @@ cost = 2, length = 8, parallelism = 4, }) + +fn(1, +2, + 3) + +fn(1, 2, +3) =-= function h( string, @@ -93,6 +132,13 @@ local p = h( length = 8, parallelism = 4, }) + +fn(1, + 2, + 3) + +fn(1, 2, + 3) =-=-= Name: Continuation Indent @@ -130,10 +176,20 @@ for k, v in pairs({}) do print(k, v) end +for i=1,10 + do + print(i) +end + while n < 10 do n = n + 1 end +while n < 10 + do + n = n + 1 +end + repeat z = z * 2 until z > 12 @@ -142,11 +198,154 @@ for k, v in pairs({}) do print(k, v) end +for i=1,10 +do + print(i) +end + while n < 10 do n = n + 1 end +while n < 10 +do + n = n + 1 +end + repeat z = z * 2 until z > 12 =-=-= + +Name: Parameter Indent + +=-= +fn(a, +b) + +fn(a, b, +c) + +fn( +a, +b +) +=-= +fn(a, + b) + +fn(a, b, + c) + +fn( + a, + b +) +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq lua-ts-indent-offset 4) + (lua-ts-mode) + (indent-region (point-min) (point-max))) + +Name: Table Indent + +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { +a = 1, + b = 2, + c = 3, +} +=-= +local Recipe = { + Floor={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Wall={up={Floor=true,Wall=true}, + down={Floor=true,Wall=true}, + left={Floor=true,Wall=true}, + right={Floor=true,Wall=true}}, + Corridor={up={Corridoor=true}, + down={Corridoor=true}, + left={Corridoor=true}, + right={Corridoor=true}} +} + +local Other = { + a = 1, + b = 2, + c = 3, +} +=-=-= + +Name: Single Line End + +=-= +function lowest_entropy_cell(world) + local lowest,res=math.huge,nil + for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end end end end + return res or {math.random(w.w),math.random(w.h)} +end + +for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end + end end end +=-= +function lowest_entropy_cell(world) + local lowest,res=math.huge,nil + for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end end end end + return res or {math.random(w.w),math.random(w.h)} +end + +for y=1,world.height do + for x=1,world.width do + local cell=world:get(x,y) + if cell.is_set then + local e=cell_enthropy(cell) + trace(e) + if e <= lowest then + lowest,res=e,{x,y} + end +end end end +=-=-= diff --git a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts index 770aa23b18d..afebe93de3f 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts @@ -481,6 +481,34 @@ local t = { 1, 3 }| =-=-= +Name: forward-sexp moves over parenthesized expressions + +=-= +|(function (x) return x + 1 end)(41) +=-= +(function (x) return x + 1 end)|(41) +=-=-= + +Name: forward-sexp moves over function declarations + +=-= +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-=-= + Code: (lambda () (lua-ts-mode) @@ -551,3 +579,31 @@ local t = |{ 1, 2, 3 } =-=-= + +Name: backward-sexp moves over parenthesized expressions + +=-= +(function (x) return x + 1 end)|(41) +=-= +|(function (x) return x + 1 end)(41) +=-=-= + +Name: backward-sexp moves over function declarations + +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-= +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-=-= -- 2.41.0 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-10-03 15:04 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-03 19:13 ` Andrey Listopadov 0 siblings, 0 replies; 25+ messages in thread From: Andrey Listopadov @ 2023-10-03 19:13 UTC (permalink / raw) To: john muhl; +Cc: 66159, Eli Zaretskii john muhl <jm@pub.pink> writes: > Whoops. Looks like I forgot to update the patch before sending. This one > should be better. > > [2. text/x-patch; 0001-Various-improvements-in-lus-ts-mode-Bug-66159.patch]... Thanks! I tried the patch, and it works great! I noticed a small indentation problem: function (...) return (function (x) return x end)(foo(...)) end probably this should be: function (...) return (function (x) return x end)(...) end The movement now works great, thanks. -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: 30.0.50; lua-ts-mode semantic indentation problems 2023-09-24 18:20 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-26 19:21 ` Andrey Listopadov @ 2023-09-30 7:52 ` Philip Kaludercic 1 sibling, 0 replies; 25+ messages in thread From: Philip Kaludercic @ 2023-09-30 7:52 UTC (permalink / raw) To: john muhl; +Cc: Andrey Listopadov, 66159, Eli Zaretskii john muhl <jm@pub.pink> writes: > Eli Zaretskii <eliz@gnu.org> writes: > >>> > Another thing that bothers me is that I prefer Gassanenko-style packing >>> > of `end' keywords so that they vertically align with the scope of the >>> > opened block, as it saves so much vertical space and is easier for me to >>> > read, but lua-ts-mode moves it to the latest innermost indentation >>> > level, as opposed to the outermost depending on the count of ends in the >>> > line itself: >>> >>> I don't see any reason not to support that style but I'm not sure how to >>> do it. A patch would be welcome but I'll try to figure it out sometime. >> >> Maybe introduce indentation styles into lua-ts-mode, like CC Mode and >> c-ts-mode have? > > I’ll have a look at what the c-ts-mode styles do and see what might be > applicable. In this case the changes can be accommodated by default. > > Andrey Listopadov <andreyorst@gmail.com> writes: > >> Thanks! The patch seems to work as I would expect for most cases. >> >>> I don't see any reason not to support that style but I'm not sure how to >>> do it. A patch would be welcome but I'll try to figure it out sometime. >> >> A far as I understand it, in the `lua-mode' the overall line indentation >> is computed via subtracting indentation for every `end' in that line, >> e.g. `end end end' subtracts `lua-indent-level three times from current >> indent level. > > Thanks for the explanation. The attached patch should make end packing > work now. > >>> Sure. It's a new mode so nothing is really set in stone. Let me know if >>> you have other suggestions. >> >> I also noticed that `lua-ts-inferior-lua` for some reason starts itself >> in a new frame instead of just a new window. I haven't seen this >> behavior with other inferior-*-modes, and the `lua-start-process' >> function from `lua-mode' doesn't spawn a new frame either. >> >> Looking at the code, it seems that it was a deliberate choice, as I see >> the use of `display-buffer-pop-up-frame' in the `display-buffer' ACTION >> arg. > > It did use a window originally but I was asked to change it: > >>> + (pop-to-buffer buffer))) >> >> I believe that `display-buffer-pop-up-frame' is the preferred alternative >> to `pop-to-buffer' these days. > > Maybe I misunderstood and it was only about not using ‘pop-to-buffer’ > and should have been ‘display-buffer-pop-up-window’. CC’d Philip for > clarification. Yes, you are right, I meant `display-buffer-pop-up-window'. > If you customize where you want it with ‘display-buffer-alist’ that > should be respected. ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-09-22 19:17 bug#66159: 30.0.50; lua-ts-mode semantic indentation problems Andrey Listopadov 2023-09-22 19:49 ` Eli Zaretskii 2023-09-24 15:06 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-06 19:44 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-07 10:11 ` Mauro Aranda 2023-10-07 16:15 ` Andrey Listopadov 2 siblings, 2 replies; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-06 19:44 UTC (permalink / raw) To: 66159; +Cc: Andrey Listopadov [-- Attachment #1: Type: text/plain, Size: 363 bytes --] Tags: patch Here is a cleaned up patch. A couple of small additions unrelated to this bug are included but I can separate them if anyone prefers. The additions are: - Make lua-ts-mode-hook a defcustom. - Add an option to use a history file for inferior process input. Andrey if you could test this one it’d be appreciated. Thanks for your help. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Various-improvements-to-lua-ts-mode-Bug-66159.patch --] [-- Type: text/x-patch, Size: 28954 bytes --] From 8f128eb7e68e0bafe0a123623e40cd59a062b93f Mon Sep 17 00:00:00 2001 From: john muhl <jm@pub.pink> Date: Wed, 4 Oct 2023 20:46:15 -0500 Subject: [PATCH] Various improvements to lua-ts-mode (Bug#66159) * lisp/progmodes/lua-ts-mode.el (lua-ts-mode): Navigate function declarations and parenthesized expressions with *-sexp commands. (lua-ts--simple-indent-rules): Improve indentation rules. (lua-ts-mode-map): Add key bindings and menus. (lua-ts-mode-hook): Make hook available in Customize. (lua-ts-inferior-history): (lua-ts-inferior--write-history): Add option to read/write an input history file. (lua-ts-inferior-lua): (lua-ts-send-buffer): (lua-ts-send-file): (lua-ts-send-region): (lua-ts-inferior-prompt): (lua-ts-inferior-prompt-continue): Support for sending buffer, file or region to the inferior process. (lua-ts-show-process-buffer): (lua-ts-hide-process-buffer): (lua-ts-kill-process): New functions. (lua-ts-inferior-prompt-regexp): Remove option. * test/lisp/progmodes/lua-ts-mode-resources/indent.erts: * test/lisp/progmodes/lua-ts-mode-resources/movement.erts: Add tests. --- lisp/progmodes/lua-ts-mode.el | 296 +++++++- .../lua-ts-mode-resources/indent.erts | 675 +++++++++++++++--- .../lua-ts-mode-resources/movement.erts | 56 ++ 3 files changed, 903 insertions(+), 124 deletions(-) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 030a3585158..8b4a60e74bf 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -38,7 +38,11 @@ (require 'cl-lib) (require 'rx)) +(declare-function treesit-induce-sparse-tree "treesit.c") (declare-function treesit-node-child-by-field-name "treesit.c") +(declare-function treesit-node-first-child-for-pos "treesit.c") +(declare-function treesit-node-parent "treesit.c") +(declare-function treesit-node-start "treesit.c") (declare-function treesit-node-type "treesit.c") (declare-function treesit-parser-create "treesit.c") (declare-function treesit-search-subtree "treesit.c") @@ -48,6 +52,15 @@ lua-ts :prefix "lua-ts-" :group 'languages) +(defcustom lua-ts-mode-hook nil + "Hook run after entering `lua-ts-mode'." + :type 'hook + :options '(flymake-mode + hs-minor-mode + outline-minor-mode) + :group 'lua-ts + :version "30.1") + (defcustom lua-ts-indent-offset 4 "Number of spaces for each indentation step in `lua-ts-mode'." :type 'natnum @@ -86,9 +99,24 @@ lua-ts-inferior-startfile :group 'lua-ts :version "30.1") -(defcustom lua-ts-inferior-prompt-regexp "^>>?[[:blank:]]" - "Regular expression matching the prompt of the inferior Lua process." - :type 'regexp +(defcustom lua-ts-inferior-prompt ">" + "Prompt used by the inferior Lua process." + :type 'string + :safe 'stringp + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-prompt-continue ">>" + "Continuation prompt used by the inferior Lua process." + :type 'string + :safe 'stringp + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-history nil + "File used to save command history of the inferior Lua process." + :type '(choice (const nil) file) + :safe 'string-or-null-p :group 'lua-ts :version "30.1") @@ -235,27 +263,125 @@ lua-ts--font-lock-settings (defvar lua-ts--simple-indent-rules `((lua + ((or (node-is "comment") + (parent-is "comment_content") + (parent-is "string_content") + (node-is "]]")) + no-indent 0) + ((or (node-is "do") + (node-is "then") + (node-is "elseif_statement") + (node-is "else_statement") + (node-is "until") + (node-is ")") + (node-is "}")) + standalone-parent 0) + ((or (and (parent-is "arguments") lua-ts--first-child-matcher) + (and (parent-is "parameters") lua-ts--first-child-matcher) + (and (parent-is "table_constructor") lua-ts--first-child-matcher)) + standalone-parent lua-ts-indent-offset) + ((or (parent-is "arguments") + (parent-is "parameters") + (parent-is "table_constructor")) + (nth-sibling 1) 0) + ((and (n-p-gp "block" "function_definition" "parenthesized_expression") + lua-ts--nested-function-block-matcher + lua-ts--nested-function-block-include-matcher) + parent lua-ts-indent-offset) + ((and (n-p-gp "block" "function_definition" "arguments") + lua-ts--nested-function-argument-matcher) + parent lua-ts-indent-offset) + ((match "function_definition" "parenthesized_expression") + standalone-parent lua-ts-indent-offset) + ((node-is "block") standalone-parent lua-ts-indent-offset) + ((parent-is "block") parent 0) + ((and (node-is "end") lua-ts--end-line-matcher) + standalone-parent lua-ts--end-indent-offset) + ((match "end" "function_declaration") parent 0) + ((and (n-p-gp "end" "function_definition" "parenthesized_expression") + lua-ts--nested-function-end-argument-matcher) + parent 0) + ((and (n-p-gp "end" "function_definition" "parenthesized_expression") + lua-ts--nested-function-block-matcher + lua-ts--nested-function-end-matcher + lua-ts--nested-function-last-function-matcher) + parent 0) + ((n-p-gp "end" "function_definition" "arguments") parent 0) + ((or (match "end" "function_definition") + (node-is "end")) + standalone-parent 0) ((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)))) +(defun lua-ts--end-line-matcher (&rest _) + "Matches if there is more than one `end' on the current line." + (> (lua-ts--end-count) 1)) + +(defun lua-ts--end-indent-offset (&rest _) + "Calculate indent offset based on `end' count." + (- (* (1- (lua-ts--end-count)) lua-ts-indent-offset))) + +(defun lua-ts--end-count () + "Count the number of `end's on the current line." + (count-matches "end" (line-beginning-position) (line-end-position))) + +(defun lua-ts--first-child-matcher (node &rest _) + "Matches if NODE is the first among its siblings." + (= (treesit-node-index node) 1)) + +(defun lua-ts--function-definition-p (node) + "Return t if NODE is a function_definition." + (equal "function_definition" (treesit-node-type node))) + +(defun lua-ts--g-g-g-parent (node) + "Return the great-great-grand-parent of NODE." + (let* ((parent (treesit-node-parent node)) + (g-parent (treesit-node-parent parent)) + (g-g-parent (treesit-node-parent g-parent))) + (treesit-node-parent g-g-parent))) + +(defun lua-ts--nested-function-argument-matcher (node &rest _) + "Matches if NODE is in a nested function argument." + (save-excursion + (goto-char (treesit-node-start node)) + (treesit-beginning-of-defun) + (backward-char 2) + (not (looking-at ")(")))) + +(defun lua-ts--nested-function-block-matcher (node &rest _) + "Matches if NODE is in a nested function block." + (let* ((g-g-g-parent (lua-ts--g-g-g-parent node)) + (g-g-g-type (treesit-node-type g-g-g-parent))) + (not (equal g-g-g-type "chunk")))) + +(defun lua-ts--nested-function-block-include-matcher (node _p bol &rest _) + "Matches if NODE's child at BOL is not another block." + (let* ((child (treesit-node-first-child-for-pos node bol)) + (child-type (treesit-node-type child)) + (g-g-g-type (treesit-node-type (lua-ts--g-g-g-parent node)))) + (or (equal child-type "assignment_statement") + (and (equal child-type "return_statement") + (or (equal g-g-g-type "arguments") + (and (equal g-g-g-type "expression_list") + (not (treesit-search-subtree child "function_call")))))))) + +(defun lua-ts--nested-function-end-matcher (node &rest _) + "Matches if NODE is the `end' of a nested function." + (save-excursion + (goto-char (treesit-node-start node)) + (treesit-beginning-of-defun) + (looking-at "function[[:space:]]*"))) + +(defun lua-ts--nested-function-end-argument-matcher (node &rest _) + "Matches if great-great-grandparent of NODE is arguments." + (equal "arguments" (treesit-node-type (lua-ts--g-g-g-parent node)))) + +(defun lua-ts--nested-function-last-function-matcher (_n parent &rest _) + "Matches if PARENT is the last nested function." + (let ((sparse-tree + (treesit-induce-sparse-tree parent #'lua-ts--function-definition-p))) + (= 1 (length (cadr sparse-tree))))) + (defvar lua-ts--syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?+ "." table) @@ -352,26 +478,124 @@ lua-ts-flymake-luacheck (defun lua-ts-inferior-lua () "Run a Lua interpreter in an inferior process." (interactive) - (let* ((buffer lua-ts-inferior-buffer) - (name (string-replace "*" "" buffer)) - (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)) + (unless (comint-check-proc lua-ts-inferior-buffer) + (apply #'make-comint-in-buffer + (string-replace "*" "" lua-ts-inferior-buffer) + lua-ts-inferior-buffer + lua-ts-inferior-program + lua-ts-inferior-startfile + lua-ts-inferior-options) + (when lua-ts-inferior-history + (set-process-sentinel (get-buffer-process lua-ts-inferior-buffer) + 'lua-ts-inferior--write-history)) + (with-current-buffer lua-ts-inferior-buffer (setq-local comint-input-ignoredups t + comint-input-ring-file-name lua-ts-inferior-history + comint-use-prompt-regexp t comint-prompt-read-only t - comint-prompt-regexp prompt-regexp - comint-use-prompt-regexp t)) - (select-window (display-buffer buffer '((display-buffer-reuse-window - display-buffer-pop-up-frame) - (reusable-frames . t)))))) + comint-prompt-regexp (rx-to-string `(: bol + ,lua-ts-inferior-prompt + (1+ space)))) + (comint-read-input-ring t) + (add-hook 'comint-preoutput-filter-functions + (lambda (string) + (if (equal string (concat lua-ts-inferior-prompt-continue " ")) + string ; Don't mess with continuation prompts. + (concat + ;; Filter out the extra prompt characters that + ;; accumulate in the output when sending regions + ;; to the inferior process. + (replace-regexp-in-string (rx-to-string + `(: bol + (* ,lua-ts-inferior-prompt + (? ,lua-ts-inferior-prompt) + (1+ space)) + (group (* nonl)))) + "\\1" string) + ;; Re-add the prompt for the next line. + lua-ts-inferior-prompt " ")))))) + (select-window (display-buffer lua-ts-inferior-buffer + '((display-buffer-reuse-window + display-buffer-pop-up-frame) + (reusable-frames . t)))) + (get-buffer-process (current-buffer))) + +(defun lua-ts-send-buffer () + "Send current buffer to the inferior Lua process." + (interactive) + (lua-ts-send-region (point-min) (point-max))) + +(defun lua-ts-send-file (file) + "Send contents of FILE to the inferior Lua process." + (interactive "f") + (with-temp-buffer + (insert-file-contents-literally file) + (lua-ts-send-region (point-min) (point-max)))) + +(defun lua-ts-send-region (beg end) + "Send region between BEG and END to the inferior Lua process." + (interactive "r") + (let ((string (buffer-substring-no-properties beg end)) + (proc-buffer (lua-ts-inferior-lua))) + (comint-send-string proc-buffer "print()") ; Prevent output from + (comint-send-string proc-buffer "\n") ; appearing at prompt. + (comint-send-string proc-buffer string) + (comint-send-string proc-buffer "\n"))) + +(defun lua-ts-show-process-buffer () + "Show the inferior Lua process buffer." + (interactive) + (display-buffer lua-ts-inferior-buffer)) + +(defun lua-ts-hide-process-buffer () + "Hide the inferior Lua process buffer." + (interactive) + (delete-windows-on lua-ts-inferior-buffer)) + +(defun lua-ts-kill-process () + "Kill the inferior Lua process." + (interactive) + (with-current-buffer lua-ts-inferior-buffer + (kill-buffer-and-window))) + +(defun lua-ts-inferior--write-history (process _) + "Write history file for inferior Lua PROCESS." + ;; Depending on how the process is killed the buffer may not be + ;; around anymore; e.g. `kill-buffer'. + (when-let* ((buffer (process-buffer process)) + ((buffer-live-p (process-buffer process)))) + (with-current-buffer buffer (comint-write-input-ring)))) + +(defvar lua-ts-mode-map + (let ((map (make-sparse-keymap "Lua"))) + (define-key map "\C-c\C-n" 'lua-ts-inferior-lua) + (define-key map "\C-c\C-c" 'lua-ts-send-buffer) + (define-key map "\C-c\C-l" 'lua-ts-send-file) + (define-key map "\C-c\C-r" 'lua-ts-send-region) + map) + "Keymap for `lua-ts-mode' buffers.") + +(easy-menu-define lua-ts-mode-menu lua-ts-mode-map + "Menu bar entry for `lua-ts-mode'." + `("Lua" + ["Evaluate Buffer" lua-ts-send-buffer] + ["Evaluate File" lua-ts-send-file] + ["Evaluate Region" lua-ts-send-region] + "--" + ["Start Process" lua-ts-inferior-lua] + ["Show Process Buffer" lua-ts-show-process-buffer] + ["Hide Process Buffer" lua-ts-hide-process-buffer] + ["Kill Process" lua-ts-kill-process] + "--" + ["Customize" (lambda () (interactive) (customize-group "lua-ts"))])) ;;;###autoload (define-derived-mode lua-ts-mode prog-mode "Lua" - "Major mode for editing Lua files, powered by tree-sitter." + "Major mode for editing Lua files, powered by tree-sitter. + +\\{lua-ts-mode-map}" :syntax-table lua-ts--syntax-table + (use-local-map lua-ts-mode-map) (when (treesit-ready-p 'lua) (treesit-parser-create 'lua) @@ -415,7 +639,9 @@ lua-ts-mode "while_statement"))) (sexp ,(rx (or "arguments" "block" + "function_declaration" "parameters" + "parenthesized_expression" "string" "table_constructor"))) (text "comment")))) diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts index 040225c8580..25d29e0fbc5 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts @@ -5,148 +5,645 @@ Code: (lua-ts-mode) (indent-region (point-min) (point-max))) -Name: Basic Indent +Name: Chunk Indent =-= - print( -0, - 1 -) + print(1) + print(2) +=-= +print(1) +print(2) +=-=-= -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 +Name: Function Indent + +=-= +function f1(n) +print(n) +return n + 1 end -f({ - x = 1, - y = 2, - z = 3, -}) +local function f2(n) +print(n) +return n * 2 +end -;(function() -return false -)() +local f3 = function(n) +print(n) +return n / 3 +end + +function f4(...) +local f = function (...) +if ok +then print(1) +else print(0) +end +end +return f +end + +function f5(...) +local f = function (...) +if ok +then +print(1) +else +print(0) +end +end +return f +end + +function f6(...) +local f = function (...) +if ok then +print(1) +else +print(0) +end +end +return f +end + +;(function () + return true + end)() =-= -print( - 0, - 1 -) +function f1(n) + print(n) + return n + 1 +end + +local function f2(n) + print(n) + return n * 2 +end -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 +local f3 = function(n) + print(n) + return n / 3 +end + +function f4(...) + local f = function (...) + if ok + then print(1) + else print(0) + end end + return f end -f({ - x = 1, - y = 2, - z = 3, -}) +function f5(...) + local f = function (...) + if ok + then + print(1) + else + print(0) + end + end + return f +end -;(function() - return false -)() +function f6(...) + local f = function (...) + if ok then + print(1) + else + print(0) + end + end + return f +end + +;(function () + return true +end)() =-=-= -Name: Argument Indent +Name: Conditional Indent =-= -function h( -string, -number, -options) -print(string, number, options) +if true then +print(true) +return 1 +elseif false then +print(false) +return -1 +else +print(nil) +return 0 end -local p = h( -"sring", - 1000, - { -cost = 2, -length = 8, - parallelism = 4, -}) +if true + then + print(true) + return 1 + elseif false + then + print(false) + return -1 + else + print(nil) + return 0 +end + +if true + then return 1 + elseif false + then return -1 + else return 0 +end =-= -function h( - string, - number, - options) - print(string, number, options) +if true then + print(true) + return 1 +elseif false then + print(false) + return -1 +else + print(nil) + return 0 end -local p = h( - "sring", - 1000, - { - cost = 2, - length = 8, - parallelism = 4, - }) +if true +then + print(true) + return 1 +elseif false +then + print(false) + return -1 +else + print(nil) + return 0 +end + +if true +then return 1 +elseif false +then return -1 +else return 0 +end +=-=-= + +Name: Loop Indent + +=-= +for k,v in pairs({}) do + print(k) + print(v) +end + +for i=1,10 + do print(i) +end + +while n < 10 do + n = n + 1 + print(n) +end + +while n < 10 + do + n = n + 1 + print(n) +end + +for i=0,9 do +repeat n = n+1 + until n > 99 +end + +repeat +z = z * 2 +print(z) +until z > 12 + + for i,x in ipairs(t) do + while i < 9 + do + local n = t[x] + repeat n = n + 1 + until n > #t + while n < 99 + do + print(n) + end + end + print(t[i]) + end +=-= +for k,v in pairs({}) do + print(k) + print(v) +end + +for i=1,10 +do print(i) +end + +while n < 10 do + n = n + 1 + print(n) +end + +while n < 10 +do + n = n + 1 + print(n) +end + +for i=0,9 do + repeat n = n+1 + until n > 99 +end + +repeat + z = z * 2 + print(z) +until z > 12 + +for i,x in ipairs(t) do + while i < 9 + do + local n = t[x] + repeat n = n + 1 + until n > #t + while n < 99 + do + print(n) + end + end + print(t[i]) +end +=-=-= + +Name: Bracket Indent + +=-= +fn( + ) + +tb={ + } +=-= +fn( +) + +tb={ +} =-=-= -Name: Continuation Indent +Name: Multi-line String Indent =-= +local s = [[ + Multi-line + string content + ]] + function f() local str = [[ multi-line string ]] ---[[ -multi-line -comment - ]] return true end =-= +local s = [[ + Multi-line + string content + ]] + function f() local str = [[ multi-line string ]] - --[[ + return true +end +=-=-= + +Name: Multi-line Comment Indent + +=-= +--[[ + Multi-line + comment content + ]] + +function f() +--[[ +multi-line + comment + ]] + return true +end +=-= +--[[ + Multi-line + comment content + ]] + +function f() +--[[ multi-line -comment + comment ]] return true end =-=-= -Name: Loop Indent +Name: Argument Indent =-= -for k, v in pairs({}) do - print(k, v) + h( + "string", + 1000 + ) + +local p = h( +"string", + 1000 +) + +fn(1, +2, + 3) + +fn( 1, 2, +3, 4 ) + +f({ +x = 1, +y = 2, +z = 3, +}) + +f({ x = 1, +y = 2, +z = 3, }) +=-= +h( + "string", + 1000 +) + +local p = h( + "string", + 1000 +) + +fn(1, + 2, + 3) + +fn( 1, 2, + 3, 4 ) + +f({ + x = 1, + y = 2, + z = 3, +}) + +f({ x = 1, + y = 2, + z = 3, }) +=-=-= + +Name: Parameter Indent + +=-= +function f1( +a, +b +) +print(a,b) end -while n < 10 do -n = n + 1 +local function f2(a, + b) +print(a,b) end -repeat -z = z * 2 - until z > 12 +local f3 = function( a, b, + c, d ) +print(a,b,c,d) +end =-= -for k, v in pairs({}) do - print(k, v) +function f1( + a, + b +) + print(a,b) end -while n < 10 do - n = n + 1 +local function f2(a, + b) + print(a,b) end -repeat - z = z * 2 -until z > 12 +local f3 = function( a, b, + c, d ) + print(a,b,c,d) +end +=-=-= + +Name: Table Indent + +=-= +local Other = { + First={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Second={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Third={up={Goto=true}, + down={Goto=true}, + left={Goto=true}, + right={Goto=true}} +} + +local Other = { +a = 1, + b = 2, + c = 3, +} +=-= +local Other = { + First={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Second={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Third={up={Goto=true}, + down={Goto=true}, + left={Goto=true}, + right={Goto=true}} +} + +local Other = { + a = 1, + b = 2, + c = 3, +} +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq lua-ts-indent-offset 4) + (lua-ts-mode) + (indent-region (point-min) (point-max))) + +Name: End Indent + +=-= +function f(x) + for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end end end end + return {x,y} or {math.random(),math.random()} + end + +for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end + end end end +=-= +function f(x) + for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end end end end + return {x,y} or {math.random(),math.random()} +end + +for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end +end end end +=-=-= + +Name: Nested Function Indent + +=-= +function a(...) + return (function (x) + return x + end)(foo(...)) +end + +function b(n) + local x = 1 + return function (i) + return function (...) + return (function (n, ...) + return function (f, ...) + return (function (...) + if ... and x < 9 then + x = x + 1 + return ... + end end)(n(f, ...)) + end, ... + end)(i(...)) +end end end + +function c(f) + local f1 = function (...) + if nil ~= ... then + return f(...) + end + end + return function (i) + return function (...) + local fn = function (n, ...) + local x = function (f, ...) + return f1(n(f, ...)) + end + return x + end + return fn(i(...)) + end + end +end + +function d(f) + local f1 = function (c, f, ...) + if ... then + if f(...) then + return ... + else + return c(f, ...) + end end end + return function (i) + return function (...) + return (function (n, ...) + local function j (f, ...) + return f1(j, f, n(f, ...)) + end + return j, ... + end)(i(...)) +end end end + +function e (n, t) + return function (i) + return function (...) + return ( + function (n, ...) + local x, y, z = 0, {} + return (function (f, ...) + return (function (i, ...) return i(i, ...) end)( + function (i, ...) + return f(function (x, ...) + return i(i, ...)(x, ...) + end, ...) + end) + end)(function (j) + return function(f, ...) + return (function (c, f, ...) + if ... then + if n+1 == x then + local y1, x1 = y, x + y, x = {}, 0 + return (function (...) + z = ... + return ... + end)(t(y1-1, x1-1, ...)) + else + x = x - 1 + return c(f, + (function (...) + z = ... + return ... + end)(t(y, x, ...))) + end + elseif x ~= 0 then + x = 0 + return z, y + end end)(j, f, n(f, ...)) + end end), ... + end)(i(...)) +end end end =-=-= diff --git a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts index 770aa23b18d..afebe93de3f 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts @@ -481,6 +481,34 @@ local t = { 1, 3 }| =-=-= +Name: forward-sexp moves over parenthesized expressions + +=-= +|(function (x) return x + 1 end)(41) +=-= +(function (x) return x + 1 end)|(41) +=-=-= + +Name: forward-sexp moves over function declarations + +=-= +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-=-= + Code: (lambda () (lua-ts-mode) @@ -551,3 +579,31 @@ local t = |{ 1, 2, 3 } =-=-= + +Name: backward-sexp moves over parenthesized expressions + +=-= +(function (x) return x + 1 end)|(41) +=-= +|(function (x) return x + 1 end)(41) +=-=-= + +Name: backward-sexp moves over function declarations + +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-= +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-=-= -- 2.41.0 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-06 19:44 ` bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-07 10:11 ` Mauro Aranda 2023-10-07 16:15 ` Andrey Listopadov 1 sibling, 0 replies; 25+ messages in thread From: Mauro Aranda @ 2023-10-07 10:11 UTC (permalink / raw) To: john muhl, 66159; +Cc: Andrey Listopadov On 6/10/23 16:44, john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors wrote: > +(defcustom lua-ts-inferior-history nil > + "File used to save command history of the inferior Lua process." > + :type '(choice (const nil) file) Please, give a :tag for the const option. IMO, it makes for a better Customize UI. ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-06 19:44 ` bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-07 10:11 ` Mauro Aranda @ 2023-10-07 16:15 ` Andrey Listopadov 2023-10-07 18:10 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 1 sibling, 1 reply; 25+ messages in thread From: Andrey Listopadov @ 2023-10-07 16:15 UTC (permalink / raw) To: john muhl; +Cc: 66159 john muhl <jm@pub.pink> writes: > Tags: patch > > Here is a cleaned up patch. A couple of small additions unrelated to > this bug are included but I can separate them if anyone prefers. The > additions are: > > - Make lua-ts-mode-hook a defcustom. > - Add an option to use a history file for inferior process input. > > Andrey if you could test this one it’d be appreciated. Thanks for your > help. > > [2. text/x-patch; 0001-Various-improvements-to-lua-ts-mode-Bug-66159.patch]... It seems the last patch broke the movement. -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-07 16:15 ` Andrey Listopadov @ 2023-10-07 18:10 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-08 9:43 ` Andrey Listopadov 0 siblings, 1 reply; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-07 18:10 UTC (permalink / raw) To: Andrey Listopadov; +Cc: 66159 Andrey Listopadov <andreyorst@gmail.com> writes: > john muhl <jm@pub.pink> writes: > >> Tags: patch >> >> Here is a cleaned up patch. A couple of small additions unrelated to >> this bug are included but I can separate them if anyone prefers. The >> additions are: >> >> - Make lua-ts-mode-hook a defcustom. >> - Add an option to use a history file for inferior process input. >> >> Andrey if you could test this one it’d be appreciated. Thanks for your >> help. >> >> [2. text/x-patch; 0001-Various-improvements-to-lua-ts-mode-Bug-66159.patch]... > > It seems the last patch broke the movement. The tests for those pass and are still working here. Maybe you found another case that needs to be improved. What is the specific problem? ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-07 18:10 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-08 9:43 ` Andrey Listopadov 2023-10-09 3:28 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 25+ messages in thread From: Andrey Listopadov @ 2023-10-08 9:43 UTC (permalink / raw) To: john muhl; +Cc: 66159 john muhl <jm@pub.pink> writes: >> It seems the last patch broke the movement. > > The tests for those pass and are still working here. Maybe you found > another case that needs to be improved. What is the specific problem? It seems so, sorry for not including this, I thought I sent this before. Here's an example: █for i=1,10 do print(x) end Pressing Pressing C-M-f (forward-sexp) puts the point here: for i=1,10 do print(x)█ end I think it should go over the `for' loop right to the `end'. Pressing Pressing C-M-b (backward-sexp), however, puts the point here: for i=1,10 do █print(x) end Pressing C-M-b again doesn't move the point anymore. Same thing happens with for-each style loop: █for k,v in pairs({1,2,3}) do print(x) end C-M-f: for k,v in pairs({1,2,3})█do print(x) end C-M-f: for k,v in pairs({1,2,3}) do print(x)█ end Backward movement manages to take the point way back to the pairs: C-M-b, C-M-b: for k,v in pairs█({1,2,3}) do print(x) end I went to https://devhints.io/lua and copied a bunch of examples of other loops to the scratch buffer, and the movement is as follows: █while condition do end for i = 1,5 do end for i = start,finish,delta do end for k,v in pairs(tab) do end repeat until condition -- Breaking out: while x do if condition then break end end C-M-f: while condition do end for i = 1,5 do end for i = start,finish,delta do end for k,v in pairs(tab)█do end repeat until condition -- Breaking out: while x do if condition then break end end C-M-f: while condition do end for i = 1,5 do end for i = start,finish,delta do end for k,v in pairs(tab) do end repeat until condition -- Breaking out: while x do if condition then break end█ end -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-08 9:43 ` Andrey Listopadov @ 2023-10-09 3:28 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-17 3:26 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 0 siblings, 1 reply; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-09 3:28 UTC (permalink / raw) To: 66159; +Cc: Andrey Listopadov, Mauro Aranda [-- Attachment #1: Type: text/plain, Size: 2740 bytes --] Mauro Aranda <maurooaranda@gmail.com> writes: > On 6/10/23 16:44, john muhl via Bug reports for GNU Emacs, the Swiss > army knife of text editors wrote: > >> +(defcustom lua-ts-inferior-history nil >> + "File used to save command history of the inferior Lua process." >> + :type '(choice (const nil) file) > > Please, give a :tag for the const option. IMO, it makes for a better > Customize UI. Fixed here and for the other choices. Andrey Listopadov <andreyorst@gmail.com> writes: > john muhl <jm@pub.pink> writes: > >>> It seems the last patch broke the movement. >> >> The tests for those pass and are still working here. Maybe you found >> another case that needs to be improved. What is the specific problem? > > It seems so, sorry for not including this, I thought I sent this before. > Here's an example: > > > █for i=1,10 do > print(x) > end > > Pressing Pressing C-M-f (forward-sexp) puts the point here: > > for i=1,10 do > print(x)█ > end > > I think it should go over the `for' loop right to the `end'. > > Pressing Pressing C-M-b (backward-sexp), however, puts the point here: > > for i=1,10 do > █print(x) > end > > Pressing C-M-b again doesn't move the point anymore. > > Same thing happens with for-each style loop: > > █for k,v in pairs({1,2,3}) do > print(x) > end > > C-M-f: > > for k,v in pairs({1,2,3})█do > print(x) > end > > C-M-f: > > for k,v in pairs({1,2,3}) do > print(x)█ > end > > Backward movement manages to take the point way back to the pairs: > > C-M-b, C-M-b: > > for k,v in pairs█({1,2,3}) do > print(x) > end > > I went to https://devhints.io/lua and copied a bunch of examples of > other loops to the scratch buffer, and the movement is as follows: > > █while condition do > end > > for i = 1,5 do > end > > for i = start,finish,delta do > end > > for k,v in pairs(tab) do > end > > repeat > until condition > > -- Breaking out: > while x do > if condition then break end > end > > C-M-f: > > while condition do > end > > for i = 1,5 do > end > > for i = start,finish,delta do > end > > for k,v in pairs(tab)█do > end > > repeat > until condition > > -- Breaking out: > while x do > if condition then break end > end > > C-M-f: > > while condition do > end > > for i = 1,5 do > end > > for i = start,finish,delta do > end > > for k,v in pairs(tab) do > end > > repeat > until condition > > -- Breaking out: > while x do > if condition then break end█ > end Navigation should be all around improved now. Let me know if I missed something. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Various-improvements-to-lua-ts-mode-Bug-66159.patch --] [-- Type: text/x-patch, Size: 35241 bytes --] From de03aed39d67f0a14b2586e59b2b713891bc37d0 Mon Sep 17 00:00:00 2001 From: john muhl <jm@pub.pink> Date: Wed, 4 Oct 2023 20:46:15 -0500 Subject: [PATCH] Various improvements to lua-ts-mode (Bug#66159) * lisp/progmodes/lua-ts-mode.el (lua-ts-mode): Navigate function declarations and parenthesized expressions with *-sexp commands. (lua-ts--simple-indent-rules): Improve indentation rules. (lua-ts-mode-map): Add key bindings and menus. (lua-ts-mode-hook): Make hook available in Customize. (lua-ts-inferior-history): (lua-ts-inferior--write-history): Add option to read/write an input history file. (lua-ts-inferior-lua): (lua-ts-send-buffer): (lua-ts-send-file): (lua-ts-send-region): (lua-ts-inferior-prompt): (lua-ts-inferior-prompt-continue): Support for sending buffer, file or region to the inferior process. (lua-ts-show-process-buffer): (lua-ts-hide-process-buffer): (lua-ts-kill-process): New functions. (lua-ts-inferior-prompt-regexp): Remove option. * test/lisp/progmodes/lua-ts-mode-resources/indent.erts: * test/lisp/progmodes/lua-ts-mode-resources/movement.erts: Add tests. --- lisp/progmodes/lua-ts-mode.el | 369 +++++++-- .../lua-ts-mode-resources/indent.erts | 705 +++++++++++++++--- .../lua-ts-mode-resources/movement.erts | 156 ++-- 3 files changed, 1032 insertions(+), 198 deletions(-) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 030a3585158..e7a36f3bb93 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -38,7 +38,11 @@ (require 'cl-lib) (require 'rx)) +(declare-function treesit-induce-sparse-tree "treesit.c") (declare-function treesit-node-child-by-field-name "treesit.c") +(declare-function treesit-node-first-child-for-pos "treesit.c") +(declare-function treesit-node-parent "treesit.c") +(declare-function treesit-node-start "treesit.c") (declare-function treesit-node-type "treesit.c") (declare-function treesit-parser-create "treesit.c") (declare-function treesit-search-subtree "treesit.c") @@ -48,6 +52,15 @@ lua-ts :prefix "lua-ts-" :group 'languages) +(defcustom lua-ts-mode-hook nil + "Hook run after entering `lua-ts-mode'." + :type 'hook + :options '(flymake-mode + hs-minor-mode + outline-minor-mode) + :group 'lua-ts + :version "30.1") + (defcustom lua-ts-indent-offset 4 "Number of spaces for each indentation step in `lua-ts-mode'." :type 'natnum @@ -57,7 +70,7 @@ lua-ts-indent-offset (defcustom lua-ts-luacheck-program "luacheck" "Location of the Luacheck program." - :type '(choice (const nil) string) + :type '(choice (const :tag "None" nil) string) :group 'lua-ts :version "30.1") @@ -70,7 +83,7 @@ lua-ts-inferior-buffer (defcustom lua-ts-inferior-program "lua" "Program to run in the inferior Lua process." - :type '(choice (const nil) string) + :type '(choice (const :tag "None" nil) string) :group 'lua-ts :version "30.1") @@ -82,13 +95,28 @@ lua-ts-inferior-options (defcustom lua-ts-inferior-startfile nil "File to load into the inferior Lua process at startup." - :type '(choice (const nil) (file :must-match t)) + :type '(choice (const :tag "None" nil) (file :must-match t)) + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-prompt ">" + "Prompt used by the inferior Lua process." + :type 'string + :safe 'stringp + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-prompt-continue ">>" + "Continuation prompt used by the inferior Lua process." + :type 'string + :safe 'stringp :group 'lua-ts :version "30.1") -(defcustom lua-ts-inferior-prompt-regexp "^>>?[[:blank:]]" - "Regular expression matching the prompt of the inferior Lua process." - :type 'regexp +(defcustom lua-ts-inferior-history nil + "File used to save command history of the inferior Lua process." + :type '(choice (const :tag "None" nil) file) + :safe 'string-or-null-p :group 'lua-ts :version "30.1") @@ -103,6 +131,12 @@ lua-ts--builtins "close" "flush" "lines" "read" "seek" "setvbuf" "write") "Lua built-in functions for tree-sitter font-locking.") +(defvar lua-ts--keywords + '("and" "do" "else" "elseif" "end" "for" "function" + "goto" "if" "in" "local" "not" "or" "repeat" + "return" "then" "until" "while") + "Lua keywords for tree-sitter font-locking and navigation.") + (defvar lua-ts--font-lock-settings (treesit-font-lock-rules :language 'lua @@ -167,13 +201,11 @@ lua-ts--font-lock-settings :language 'lua :feature 'keyword - '((break_statement) @font-lock-keyword-face + `((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"] + ,(vconcat lua-ts--keywords) @font-lock-keyword-face) :language 'lua @@ -235,27 +267,135 @@ lua-ts--font-lock-settings (defvar lua-ts--simple-indent-rules `((lua + ((or (node-is "comment") + (parent-is "comment_content") + (parent-is "string_content") + (node-is "]]")) + no-indent 0) + ((and (n-p-gp "field" "table_constructor" "arguments") + lua-ts--multi-arg-function-call-matcher) + parent lua-ts-indent-offset) + ((and (n-p-gp "}" "table_constructor" "arguments") + lua-ts--multi-arg-function-call-matcher) + parent 0) + ((or (node-is "do") + (node-is "then") + (node-is "elseif_statement") + (node-is "else_statement") + (node-is "until") + (node-is ")") + (node-is "}")) + standalone-parent 0) + ((or (and (parent-is "arguments") lua-ts--first-child-matcher) + (and (parent-is "parameters") lua-ts--first-child-matcher) + (and (parent-is "table_constructor") lua-ts--first-child-matcher)) + standalone-parent lua-ts-indent-offset) + ((or (parent-is "arguments") + (parent-is "parameters") + (parent-is "table_constructor")) + (nth-sibling 1) 0) + ((and (n-p-gp "block" "function_definition" "parenthesized_expression") + lua-ts--nested-function-block-matcher + lua-ts--nested-function-block-include-matcher) + parent lua-ts-indent-offset) + ((and (n-p-gp "block" "function_definition" "arguments") + lua-ts--nested-function-argument-matcher) + parent lua-ts-indent-offset) + ((match "function_definition" "parenthesized_expression") + standalone-parent lua-ts-indent-offset) + ((node-is "block") standalone-parent lua-ts-indent-offset) + ((parent-is "block") parent 0) + ((and (node-is "end") lua-ts--end-line-matcher) + standalone-parent lua-ts--end-indent-offset) + ((match "end" "function_declaration") parent 0) + ((and (n-p-gp "end" "function_definition" "parenthesized_expression") + lua-ts--nested-function-end-argument-matcher) + parent 0) + ((and (n-p-gp "end" "function_definition" "parenthesized_expression") + lua-ts--nested-function-block-matcher + lua-ts--nested-function-end-matcher + lua-ts--nested-function-last-function-matcher) + parent 0) + ((n-p-gp "end" "function_definition" "arguments") parent 0) + ((or (match "end" "function_definition") + (node-is "end")) + standalone-parent 0) ((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)))) +(defun lua-ts--end-line-matcher (&rest _) + "Matches if there is more than one `end' on the current line." + (> (lua-ts--end-count) 1)) + +(defun lua-ts--end-indent-offset (&rest _) + "Calculate indent offset based on `end' count." + (- (* (1- (lua-ts--end-count)) lua-ts-indent-offset))) + +(defun lua-ts--end-count () + "Count the number of `end's on the current line." + (count-matches "end" (line-beginning-position) (line-end-position))) + +(defun lua-ts--first-child-matcher (node &rest _) + "Matches if NODE is the first among its siblings." + (= (treesit-node-index node) 1)) + +(defun lua-ts--function-definition-p (node) + "Return t if NODE is a function_definition." + (equal "function_definition" (treesit-node-type node))) + +(defun lua-ts--g-g-g-parent (node) + "Return the great-great-grand-parent of NODE." + (let* ((parent (treesit-node-parent node)) + (g-parent (treesit-node-parent parent)) + (g-g-parent (treesit-node-parent g-parent))) + (treesit-node-parent g-g-parent))) + +(defun lua-ts--multi-arg-function-call-matcher (_n parent &rest _) + "Matches if PARENT has multiple arguments." + (> (treesit-node-child-count (treesit-node-parent parent)) 3)) + +(defun lua-ts--nested-function-argument-matcher (node &rest _) + "Matches if NODE is in a nested function argument." + (save-excursion + (goto-char (treesit-node-start node)) + (treesit-beginning-of-defun) + (backward-char 2) + (not (looking-at ")(")))) + +(defun lua-ts--nested-function-block-matcher (node &rest _) + "Matches if NODE is in a nested function block." + (let* ((g-g-g-parent (lua-ts--g-g-g-parent node)) + (g-g-g-type (treesit-node-type g-g-g-parent))) + (not (equal g-g-g-type "chunk")))) + +(defun lua-ts--nested-function-block-include-matcher (node _p bol &rest _) + "Matches if NODE's child at BOL is not another block." + (let* ((child (treesit-node-first-child-for-pos node bol)) + (child-type (treesit-node-type child)) + (g-g-g-type (treesit-node-type (lua-ts--g-g-g-parent node)))) + (or (equal child-type "assignment_statement") + (and (equal child-type "return_statement") + (or (equal g-g-g-type "arguments") + (and (equal g-g-g-type "expression_list") + (not (treesit-search-subtree child "function_call")))))))) + +(defun lua-ts--nested-function-end-matcher (node &rest _) + "Matches if NODE is the `end' of a nested function." + (save-excursion + (goto-char (treesit-node-start node)) + (treesit-beginning-of-defun) + (looking-at "function[[:space:]]*"))) + +(defun lua-ts--nested-function-end-argument-matcher (node &rest _) + "Matches if great-great-grandparent of NODE is arguments." + (equal "arguments" (treesit-node-type (lua-ts--g-g-g-parent node)))) + +(defun lua-ts--nested-function-last-function-matcher (_n parent &rest _) + "Matches if PARENT is the last nested function." + (let ((sparse-tree + (treesit-induce-sparse-tree parent #'lua-ts--function-definition-p))) + (= 1 (length (cadr sparse-tree))))) + (defvar lua-ts--syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?+ "." table) @@ -352,26 +492,124 @@ lua-ts-flymake-luacheck (defun lua-ts-inferior-lua () "Run a Lua interpreter in an inferior process." (interactive) - (let* ((buffer lua-ts-inferior-buffer) - (name (string-replace "*" "" buffer)) - (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)) + (unless (comint-check-proc lua-ts-inferior-buffer) + (apply #'make-comint-in-buffer + (string-replace "*" "" lua-ts-inferior-buffer) + lua-ts-inferior-buffer + lua-ts-inferior-program + lua-ts-inferior-startfile + lua-ts-inferior-options) + (when lua-ts-inferior-history + (set-process-sentinel (get-buffer-process lua-ts-inferior-buffer) + 'lua-ts-inferior--write-history)) + (with-current-buffer lua-ts-inferior-buffer (setq-local comint-input-ignoredups t + comint-input-ring-file-name lua-ts-inferior-history + comint-use-prompt-regexp t comint-prompt-read-only t - comint-prompt-regexp prompt-regexp - comint-use-prompt-regexp t)) - (select-window (display-buffer buffer '((display-buffer-reuse-window - display-buffer-pop-up-frame) - (reusable-frames . t)))))) + comint-prompt-regexp (rx-to-string `(: bol + ,lua-ts-inferior-prompt + (1+ space)))) + (comint-read-input-ring t) + (add-hook 'comint-preoutput-filter-functions + (lambda (string) + (if (equal string (concat lua-ts-inferior-prompt-continue " ")) + string ; Don't mess with continuation prompts. + (concat + ;; Filter out the extra prompt characters that + ;; accumulate in the output when sending regions + ;; to the inferior process. + (replace-regexp-in-string (rx-to-string + `(: bol + (* ,lua-ts-inferior-prompt + (? ,lua-ts-inferior-prompt) + (1+ space)) + (group (* nonl)))) + "\\1" string) + ;; Re-add the prompt for the next line. + lua-ts-inferior-prompt " ")))))) + (select-window (display-buffer lua-ts-inferior-buffer + '((display-buffer-reuse-window + display-buffer-pop-up-frame) + (reusable-frames . t)))) + (get-buffer-process (current-buffer))) + +(defun lua-ts-send-buffer () + "Send current buffer to the inferior Lua process." + (interactive) + (lua-ts-send-region (point-min) (point-max))) + +(defun lua-ts-send-file (file) + "Send contents of FILE to the inferior Lua process." + (interactive "f") + (with-temp-buffer + (insert-file-contents-literally file) + (lua-ts-send-region (point-min) (point-max)))) + +(defun lua-ts-send-region (beg end) + "Send region between BEG and END to the inferior Lua process." + (interactive "r") + (let ((string (buffer-substring-no-properties beg end)) + (proc-buffer (lua-ts-inferior-lua))) + (comint-send-string proc-buffer "print()") ; Prevent output from + (comint-send-string proc-buffer "\n") ; appearing at prompt. + (comint-send-string proc-buffer string) + (comint-send-string proc-buffer "\n"))) + +(defun lua-ts-show-process-buffer () + "Show the inferior Lua process buffer." + (interactive) + (display-buffer lua-ts-inferior-buffer)) + +(defun lua-ts-hide-process-buffer () + "Hide the inferior Lua process buffer." + (interactive) + (delete-windows-on lua-ts-inferior-buffer)) + +(defun lua-ts-kill-process () + "Kill the inferior Lua process." + (interactive) + (with-current-buffer lua-ts-inferior-buffer + (kill-buffer-and-window))) + +(defun lua-ts-inferior--write-history (process _) + "Write history file for inferior Lua PROCESS." + ;; Depending on how the process is killed the buffer may not be + ;; around anymore; e.g. `kill-buffer'. + (when-let* ((buffer (process-buffer process)) + ((buffer-live-p (process-buffer process)))) + (with-current-buffer buffer (comint-write-input-ring)))) + +(defvar lua-ts-mode-map + (let ((map (make-sparse-keymap "Lua"))) + (define-key map "\C-c\C-n" 'lua-ts-inferior-lua) + (define-key map "\C-c\C-c" 'lua-ts-send-buffer) + (define-key map "\C-c\C-l" 'lua-ts-send-file) + (define-key map "\C-c\C-r" 'lua-ts-send-region) + map) + "Keymap for `lua-ts-mode' buffers.") + +(easy-menu-define lua-ts-mode-menu lua-ts-mode-map + "Menu bar entry for `lua-ts-mode'." + `("Lua" + ["Evaluate Buffer" lua-ts-send-buffer] + ["Evaluate File" lua-ts-send-file] + ["Evaluate Region" lua-ts-send-region] + "--" + ["Start Process" lua-ts-inferior-lua] + ["Show Process Buffer" lua-ts-show-process-buffer] + ["Hide Process Buffer" lua-ts-hide-process-buffer] + ["Kill Process" lua-ts-kill-process] + "--" + ["Customize" (lambda () (interactive) (customize-group "lua-ts"))])) ;;;###autoload (define-derived-mode lua-ts-mode prog-mode "Lua" - "Major mode for editing Lua files, powered by tree-sitter." + "Major mode for editing Lua files, powered by tree-sitter. + +\\{lua-ts-mode-map}" :syntax-table lua-ts--syntax-table + (use-local-map lua-ts-mode-map) (when (treesit-ready-p 'lua) (treesit-parser-create 'lua) @@ -404,20 +642,39 @@ lua-ts-mode (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"))) + (function ,(rx (or "function_declaration" + "function_definition"))) + (keyword ,(regexp-opt lua-ts--keywords + 'symbols)) + (loop-statement ,(rx (or "do_statement" + "for_statement" + "repeat_statement" + "while_statement"))) + (sentence (or function + loop-statement + ,(rx (or "assignment_statement" + "comment" + "field" + "function_call" + "if_statement" + "return_statement" + "variable_declaration")))) + (sexp (or function + keyword + loop-statement + ,(rx (or "arguments" + "break_statement" + "expression_list" + "false" + "identifier" + "nil" + "number" + "parameters" + "parenthesized_expression" + "string" + "table_constructor" + "true" + "vararg_expression")))) (text "comment")))) ;; Imenu. diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts index 040225c8580..9797467bbe5 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts @@ -5,148 +5,675 @@ Code: (lua-ts-mode) (indent-region (point-min) (point-max))) -Name: Basic Indent +Name: Chunk Indent =-= - print( -0, - 1 -) + print(1) + print(2) +=-= +print(1) +print(2) +=-=-= -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 +Name: Function Indent + +=-= +function f1(n) +print(n) +return n + 1 end -f({ - x = 1, - y = 2, - z = 3, -}) +local function f2(n) +print(n) +return n * 2 +end -;(function() -return false -)() +local f3 = function(n) +print(n) +return n / 3 +end + +function f4(...) +local f = function (...) +if ok +then print(1) +else print(0) +end +end +return f +end + +function f5(...) +local f = function (...) +if ok +then +print(1) +else +print(0) +end +end +return f +end + +function f6(...) +local f = function (...) +if ok then +print(1) +else +print(0) +end +end +return f +end + +;(function () + return true + end)() =-= -print( - 0, - 1 -) +function f1(n) + print(n) + return n + 1 +end -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 +local function f2(n) + print(n) + return n * 2 +end + +local f3 = function(n) + print(n) + return n / 3 +end + +function f4(...) + local f = function (...) + if ok + then print(1) + else print(0) + end end + return f end -f({ - x = 1, - y = 2, - z = 3, -}) +function f5(...) + local f = function (...) + if ok + then + print(1) + else + print(0) + end + end + return f +end + +function f6(...) + local f = function (...) + if ok then + print(1) + else + print(0) + end + end + return f +end -;(function() - return false -)() +;(function () + return true +end)() =-=-= -Name: Argument Indent +Name: Conditional Indent =-= -function h( -string, -number, -options) -print(string, number, options) +if true then +print(true) +return 1 +elseif false then +print(false) +return -1 +else +print(nil) +return 0 end -local p = h( -"sring", - 1000, - { -cost = 2, -length = 8, - parallelism = 4, -}) +if true + then + print(true) + return 1 + elseif false + then + print(false) + return -1 + else + print(nil) + return 0 +end + +if true + then return 1 + elseif false + then return -1 + else return 0 +end =-= -function h( - string, - number, - options) - print(string, number, options) +if true then + print(true) + return 1 +elseif false then + print(false) + return -1 +else + print(nil) + return 0 end -local p = h( - "sring", - 1000, - { - cost = 2, - length = 8, - parallelism = 4, - }) +if true +then + print(true) + return 1 +elseif false +then + print(false) + return -1 +else + print(nil) + return 0 +end + +if true +then return 1 +elseif false +then return -1 +else return 0 +end =-=-= -Name: Continuation Indent +Name: Loop Indent =-= +for k,v in pairs({}) do + print(k) + print(v) +end + +for i=1,10 + do print(i) +end + +while n < 10 do + n = n + 1 + print(n) +end + +while n < 10 + do + n = n + 1 + print(n) +end + +for i=0,9 do +repeat n = n+1 + until n > 99 +end + +repeat +z = z * 2 +print(z) +until z > 12 + + for i,x in ipairs(t) do + while i < 9 + do + local n = t[x] + repeat n = n + 1 + until n > #t + while n < 99 + do + print(n) + end + end + print(t[i]) + end + +do +local a = b +print(a + 1) +end +=-= +for k,v in pairs({}) do + print(k) + print(v) +end + +for i=1,10 +do print(i) +end + +while n < 10 do + n = n + 1 + print(n) +end + +while n < 10 +do + n = n + 1 + print(n) +end + +for i=0,9 do + repeat n = n+1 + until n > 99 +end + +repeat + z = z * 2 + print(z) +until z > 12 + +for i,x in ipairs(t) do + while i < 9 + do + local n = t[x] + repeat n = n + 1 + until n > #t + while n < 99 + do + print(n) + end + end + print(t[i]) +end + +do + local a = b + print(a + 1) +end +=-=-= + +Name: Bracket Indent + +=-= +fn( + ) + +tb={ + } +=-= +fn( +) + +tb={ +} +=-=-= + +Name: Multi-line String Indent + +=-= +local s = [[ + Multi-line + string content + ]] + function f() local str = [[ multi-line string ]] ---[[ -multi-line -comment - ]] return true end =-= +local s = [[ + Multi-line + string content + ]] + function f() local str = [[ multi-line string ]] - --[[ + return true +end +=-=-= + +Name: Multi-line Comment Indent + +=-= +--[[ + Multi-line + comment content + ]] + +function f() +--[[ +multi-line + comment + ]] + return true +end +=-= +--[[ + Multi-line + comment content + ]] + +function f() +--[[ multi-line -comment + comment ]] return true end =-=-= -Name: Loop Indent +Name: Argument Indent + +=-= + h( + "string", + 1000 + ) + +local p = h( +"string", + 1000 +) + +fn(1, +2, + 3) + +fn( 1, 2, +3, 4 ) + +f({ +x = 1, +y = 2, +z = 3, +}) + +f({ x = 1, +y = 2, +z = 3, }) + +Test({ +a=1 +}) + +Test({ +a = 1, +b = 2, +}, +nil) +=-= +h( + "string", + 1000 +) + +local p = h( + "string", + 1000 +) + +fn(1, + 2, + 3) + +fn( 1, 2, + 3, 4 ) + +f({ + x = 1, + y = 2, + z = 3, +}) + +f({ x = 1, + y = 2, + z = 3, }) + +Test({ + a=1 +}) + +Test({ + a = 1, + b = 2, + }, + nil) +=-=-= + +Name: Parameter Indent =-= -for k, v in pairs({}) do - print(k, v) +function f1( +a, +b +) +print(a,b) end -while n < 10 do -n = n + 1 +local function f2(a, + b) +print(a,b) end -repeat -z = z * 2 - until z > 12 +local f3 = function( a, b, + c, d ) +print(a,b,c,d) +end =-= -for k, v in pairs({}) do - print(k, v) +function f1( + a, + b +) + print(a,b) end -while n < 10 do - n = n + 1 +local function f2(a, + b) + print(a,b) end -repeat - z = z * 2 -until z > 12 +local f3 = function( a, b, + c, d ) + print(a,b,c,d) +end +=-=-= + +Name: Table Indent + +=-= +local Other = { + First={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Second={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Third={up={Goto=true}, + down={Goto=true}, + left={Goto=true}, + right={Goto=true}} +} + +local Other = { +a = 1, + b = 2, + c = 3, +} +=-= +local Other = { + First={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Second={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Third={up={Goto=true}, + down={Goto=true}, + left={Goto=true}, + right={Goto=true}} +} + +local Other = { + a = 1, + b = 2, + c = 3, +} +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq lua-ts-indent-offset 4) + (lua-ts-mode) + (indent-region (point-min) (point-max))) + +Name: End Indent + +=-= +function f(x) + for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end end end end + return {x,y} or {math.random(),math.random()} + end + +for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end + end end end +=-= +function f(x) + for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end end end end + return {x,y} or {math.random(),math.random()} +end + +for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end +end end end +=-=-= + +Name: Nested Function Indent + +=-= +function a(...) + return (function (x) + return x + end)(foo(...)) +end + +function b(n) + local x = 1 + return function (i) + return function (...) + return (function (n, ...) + return function (f, ...) + return (function (...) + if ... and x < 9 then + x = x + 1 + return ... + end end)(n(f, ...)) + end, ... + end)(i(...)) +end end end + +function c(f) + local f1 = function (...) + if nil ~= ... then + return f(...) + end + end + return function (i) + return function (...) + local fn = function (n, ...) + local x = function (f, ...) + return f1(n(f, ...)) + end + return x + end + return fn(i(...)) + end + end +end + +function d(f) + local f1 = function (c, f, ...) + if ... then + if f(...) then + return ... + else + return c(f, ...) + end end end + return function (i) + return function (...) + return (function (n, ...) + local function j (f, ...) + return f1(j, f, n(f, ...)) + end + return j, ... + end)(i(...)) +end end end + +function e (n, t) + return function (i) + return function (...) + return ( + function (n, ...) + local x, y, z = 0, {} + return (function (f, ...) + return (function (i, ...) return i(i, ...) end)( + function (i, ...) + return f(function (x, ...) + return i(i, ...)(x, ...) + end, ...) + end) + end)(function (j) + return function(f, ...) + return (function (c, f, ...) + if ... then + if n+1 == x then + local y1, x1 = y, x + y, x = {}, 0 + return (function (...) + z = ... + return ... + end)(t(y1-1, x1-1, ...)) + else + x = x - 1 + return c(f, + (function (...) + z = ... + return ... + end)(t(y, x, ...))) + end + elseif x ~= 0 then + x = 0 + return z, y + end end)(j, f, n(f, ...)) + end end), ... + end)(i(...)) +end end end =-=-= diff --git a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts index 770aa23b18d..11e86f12926 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts @@ -147,7 +147,7 @@ end| print(1) =-=-= -Name: forward-sentence moves over for statements +Name: forward-sentence moves over do statements =-= |do @@ -417,34 +417,6 @@ Code: 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 =-= @@ -481,41 +453,91 @@ local t = { 1, 3 }| =-=-= -Code: - (lambda () - (lua-ts-mode) - (backward-sexp 1)) +Name: forward-sexp moves over parenthesized expressions -Point-Char: | +=-= +|(function (x) return x + 1 end)(41) +=-= +(function (x) return x + 1 end)|(41) +=-=-= -Name: backward-sexp moves over blocks +Name: forward-sexp moves over function declarations =-= -local function Test() - local t = { - a = 1, - } +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-=-= - if true then - print(1) - else - print(0) - end| +Name: forward-sexp moves over do statements + +=-= +|do + print(a + 1) end =-= -local function Test() - |local t = { - a = 1, - } +do + print(a + 1) +end| +=-=-= - if true then - print(1) - else - print(0) - end +Name: forward-sexp moves over for statements + +=-= +|for k,v in pairs({}) do + print(k, v) +end +=-= +for k,v in pairs({}) do + print(k, v) +end| +=-=-= + +Name: forward-sexp moves over repeat statements + +=-= +|repeat + n = n + 1 +until n > 10 +=-= +repeat + n = n + 1 +until n > 10| +=-=-= + +Name: forward-sexp moves over while statements + +=-= +|while n < 99 +do + n = n+1 end +=-= +while n < 99 +do + n = n+1 +end| =-=-= +Code: + (lambda () + (lua-ts-mode) + (backward-sexp 1)) + +Point-Char: | + Name: backward-sexp moves over arguments =-= @@ -551,3 +573,31 @@ local t = |{ 1, 2, 3 } =-=-= + +Name: backward-sexp moves over parenthesized expressions + +=-= +(function (x) return x + 1 end)|(41) +=-= +|(function (x) return x + 1 end)(41) +=-=-= + +Name: backward-sexp moves over function declarations + +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-= +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-=-= -- 2.41.0 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-09 3:28 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-17 3:26 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-20 20:40 ` Stefan Kangas ` (2 more replies) 0 siblings, 3 replies; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-17 3:26 UTC (permalink / raw) To: 66159; +Cc: Andrey Listopadov, Mauro Aranda [-- Attachment #1: Type: text/plain, Size: 3097 bytes --] john muhl <jm@pub.pink> writes: > Mauro Aranda <maurooaranda@gmail.com> writes: > >> On 6/10/23 16:44, john muhl via Bug reports for GNU Emacs, the Swiss >> army knife of text editors wrote: >> >>> +(defcustom lua-ts-inferior-history nil >>> + "File used to save command history of the inferior Lua process." >>> + :type '(choice (const nil) file) >> >> Please, give a :tag for the const option. IMO, it makes for a better >> Customize UI. > > Fixed here and for the other choices. > > Andrey Listopadov <andreyorst@gmail.com> writes: > >> john muhl <jm@pub.pink> writes: >> >>>> It seems the last patch broke the movement. >>> >>> The tests for those pass and are still working here. Maybe you found >>> another case that needs to be improved. What is the specific problem? >> >> It seems so, sorry for not including this, I thought I sent this before. >> Here's an example: >> >> >> █for i=1,10 do >> print(x) >> end >> >> Pressing Pressing C-M-f (forward-sexp) puts the point here: >> >> for i=1,10 do >> print(x)█ >> end >> >> I think it should go over the `for' loop right to the `end'. >> >> Pressing Pressing C-M-b (backward-sexp), however, puts the point here: >> >> for i=1,10 do >> █print(x) >> end >> >> Pressing C-M-b again doesn't move the point anymore. >> >> Same thing happens with for-each style loop: >> >> █for k,v in pairs({1,2,3}) do >> print(x) >> end >> >> C-M-f: >> >> for k,v in pairs({1,2,3})█do >> print(x) >> end >> >> C-M-f: >> >> for k,v in pairs({1,2,3}) do >> print(x)█ >> end >> >> Backward movement manages to take the point way back to the pairs: >> >> C-M-b, C-M-b: >> >> for k,v in pairs█({1,2,3}) do >> print(x) >> end >> >> I went to https://devhints.io/lua and copied a bunch of examples of >> other loops to the scratch buffer, and the movement is as follows: >> >> █while condition do >> end >> >> for i = 1,5 do >> end >> >> for i = start,finish,delta do >> end >> >> for k,v in pairs(tab) do >> end >> >> repeat >> until condition >> >> -- Breaking out: >> while x do >> if condition then break end >> end >> >> C-M-f: >> >> while condition do >> end >> >> for i = 1,5 do >> end >> >> for i = start,finish,delta do >> end >> >> for k,v in pairs(tab)█do >> end >> >> repeat >> until condition >> >> -- Breaking out: >> while x do >> if condition then break end >> end >> >> C-M-f: >> >> while condition do >> end >> >> for i = 1,5 do >> end >> >> for i = start,finish,delta do >> end >> >> for k,v in pairs(tab) do >> end >> >> repeat >> until condition >> >> -- Breaking out: >> while x do >> if condition then break end█ >> end > > Navigation should be all around improved now. Let me know if I missed something. > > [2. text/x-patch; 0001-Various-improvements-to-lua-ts-mode-Bug-66159.patch]... Here is the latest version. Fixed a missing declare-function and other minor omissions. [-- Warning: decoded text below may be mangled, UTF-8 assumed --] [-- Attachment #2: 0001-Various-improvements-to-lua-ts-mode-Bug-66159.patch --] [-- Type: text/x-patch, Size: 35728 bytes --] From 8d3b9e3617364eb9e20d489bc3979405d50abdee Mon Sep 17 00:00:00 2001 From: john muhl <jm@pub.pink> Date: Wed, 4 Oct 2023 20:46:15 -0500 Subject: [PATCH] Various improvements to lua-ts-mode (Bug#66159) * lisp/progmodes/lua-ts-mode.el (lua-ts-mode): Improve movement. (lua-ts--simple-indent-rules): Improve indentation rules. (lua-ts-mode-map): Add key bindings and menus. (lua-ts-mode-hook): Make hook available in Customize. (lua-ts-inferior-history): (lua-ts-inferior--write-history): Add option to read/write an input history file. (lua-ts-inferior-lua): (lua-ts-send-buffer): (lua-ts-send-file): (lua-ts-send-region): (lua-ts-inferior-prompt): (lua-ts-inferior-prompt-continue): Support for sending buffer, file or region to the inferior process. (lua-ts-show-process-buffer): (lua-ts-hide-process-buffer): (lua-ts-kill-process): New functions. (lua-ts-inferior-prompt-regexp): Remove option. * test/lisp/progmodes/lua-ts-mode-resources/indent.erts: * test/lisp/progmodes/lua-ts-mode-resources/movement.erts: Add tests. --- lisp/progmodes/lua-ts-mode.el | 382 ++++++++-- .../lua-ts-mode-resources/indent.erts | 705 +++++++++++++++--- .../lua-ts-mode-resources/movement.erts | 156 ++-- 3 files changed, 1045 insertions(+), 198 deletions(-) diff --git a/lisp/progmodes/lua-ts-mode.el b/lisp/progmodes/lua-ts-mode.el index 8db6816d6e4..2193779b759 100644 --- a/lisp/progmodes/lua-ts-mode.el +++ b/lisp/progmodes/lua-ts-mode.el @@ -38,7 +38,12 @@ (require 'cl-lib) (require 'rx)) +(declare-function treesit-induce-sparse-tree "treesit.c") (declare-function treesit-node-child-by-field-name "treesit.c") +(declare-function treesit-node-child-count "treesit.c") +(declare-function treesit-node-first-child-for-pos "treesit.c") +(declare-function treesit-node-parent "treesit.c") +(declare-function treesit-node-start "treesit.c") (declare-function treesit-node-type "treesit.c") (declare-function treesit-parser-create "treesit.c") (declare-function treesit-search-subtree "treesit.c") @@ -48,6 +53,15 @@ lua-ts :prefix "lua-ts-" :group 'languages) +(defcustom lua-ts-mode-hook nil + "Hook run after entering `lua-ts-mode'." + :type 'hook + :options '(flymake-mode + hs-minor-mode + outline-minor-mode) + :group 'lua-ts + :version "30.1") + (defcustom lua-ts-indent-offset 4 "Number of spaces for each indentation step in `lua-ts-mode'." :type 'natnum @@ -57,7 +71,7 @@ lua-ts-indent-offset (defcustom lua-ts-luacheck-program "luacheck" "Location of the Luacheck program." - :type '(choice (const nil) string) + :type '(choice (const :tag "None" nil) string) :group 'lua-ts :version "30.1") @@ -70,7 +84,7 @@ lua-ts-inferior-buffer (defcustom lua-ts-inferior-program "lua" "Program to run in the inferior Lua process." - :type '(choice (const nil) string) + :type '(choice (const :tag "None" nil) string) :group 'lua-ts :version "30.1") @@ -82,13 +96,28 @@ lua-ts-inferior-options (defcustom lua-ts-inferior-startfile nil "File to load into the inferior Lua process at startup." - :type '(choice (const nil) (file :must-match t)) + :type '(choice (const :tag "None" nil) (file :must-match t)) + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-prompt ">" + "Prompt used by the inferior Lua process." + :type 'string + :safe 'stringp + :group 'lua-ts + :version "30.1") + +(defcustom lua-ts-inferior-prompt-continue ">>" + "Continuation prompt used by the inferior Lua process." + :type 'string + :safe 'stringp :group 'lua-ts :version "30.1") -(defcustom lua-ts-inferior-prompt-regexp "^>>?[[:blank:]]" - "Regular expression matching the prompt of the inferior Lua process." - :type 'regexp +(defcustom lua-ts-inferior-history nil + "File used to save command history of the inferior Lua process." + :type '(choice (const :tag "None" nil) file) + :safe 'string-or-null-p :group 'lua-ts :version "30.1") @@ -103,6 +132,12 @@ lua-ts--builtins "close" "flush" "lines" "read" "seek" "setvbuf" "write") "Lua built-in functions for tree-sitter font-locking.") +(defvar lua-ts--keywords + '("and" "do" "else" "elseif" "end" "for" "function" + "goto" "if" "in" "local" "not" "or" "repeat" + "return" "then" "until" "while") + "Lua keywords for tree-sitter font-locking and navigation.") + (defvar lua-ts--font-lock-settings (treesit-font-lock-rules :language 'lua @@ -167,13 +202,11 @@ lua-ts--font-lock-settings :language 'lua :feature 'keyword - '((break_statement) @font-lock-keyword-face + `((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"] + ,(vconcat lua-ts--keywords) @font-lock-keyword-face) :language 'lua @@ -235,27 +268,145 @@ lua-ts--font-lock-settings (defvar lua-ts--simple-indent-rules `((lua + ((or (node-is "comment") + (parent-is "comment_content") + (parent-is "string_content") + (node-is "]]")) + no-indent 0) + ((and (n-p-gp "field" "table_constructor" "arguments") + lua-ts--multi-arg-function-call-matcher) + parent lua-ts-indent-offset) + ((and (n-p-gp "}" "table_constructor" "arguments") + lua-ts--multi-arg-function-call-matcher) + parent 0) + ((or (node-is "do") + (node-is "then") + (node-is "elseif_statement") + (node-is "else_statement") + (node-is "until") + (node-is ")") + (node-is "}")) + standalone-parent 0) + ((or (and (parent-is "arguments") lua-ts--first-child-matcher) + (and (parent-is "parameters") lua-ts--first-child-matcher) + (and (parent-is "table_constructor") lua-ts--first-child-matcher)) + standalone-parent lua-ts-indent-offset) + ((or (parent-is "arguments") + (parent-is "parameters") + (parent-is "table_constructor")) + (nth-sibling 1) 0) + ((and (n-p-gp "block" "function_definition" "parenthesized_expression") + lua-ts--nested-function-block-matcher + lua-ts--nested-function-block-include-matcher) + parent lua-ts-indent-offset) + ((and (n-p-gp "block" "function_definition" "arguments") + lua-ts--nested-function-argument-matcher) + parent lua-ts-indent-offset) + ((match "function_definition" "parenthesized_expression") + standalone-parent lua-ts-indent-offset) + ((node-is "block") standalone-parent lua-ts-indent-offset) + ((parent-is "block") parent 0) + ((and (node-is "end") lua-ts--end-line-matcher) + standalone-parent lua-ts--end-indent-offset) + ((match "end" "function_declaration") parent 0) + ((and (n-p-gp "end" "function_definition" "parenthesized_expression") + lua-ts--nested-function-end-argument-matcher) + parent 0) + ((and (n-p-gp "end" "function_definition" "parenthesized_expression") + lua-ts--nested-function-block-matcher + lua-ts--nested-function-end-matcher + lua-ts--nested-function-last-function-matcher) + parent 0) + ((n-p-gp "end" "function_definition" "arguments") parent 0) + ((or (match "end" "function_definition") + (node-is "end")) + standalone-parent 0) + ((or (parent-is "function_declaration") + (parent-is "function_definition") + (parent-is "do_statement") + (parent-is "for_statement") + (parent-is "repeat_statement") + (parent-is "while_statement") + (parent-is "if_statement") + (parent-is "else_statement") + (parent-is "elseif_statement")) + standalone-parent lua-ts-indent-offset) ((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)))) +(defun lua-ts--end-line-matcher (&rest _) + "Matches if there is more than one `end' on the current line." + (> (lua-ts--end-count) 1)) + +(defun lua-ts--end-indent-offset (&rest _) + "Calculate indent offset based on `end' count." + (- (* (1- (lua-ts--end-count)) lua-ts-indent-offset))) + +(defun lua-ts--end-count () + "Count the number of `end's on the current line." + (count-matches "end" (line-beginning-position) (line-end-position))) + +(defun lua-ts--first-child-matcher (node &rest _) + "Matches if NODE is the first among its siblings." + (= (treesit-node-index node) 1)) + +(defun lua-ts--function-definition-p (node) + "Return t if NODE is a function_definition." + (equal "function_definition" (treesit-node-type node))) + +(defun lua-ts--g-g-g-parent (node) + "Return the great-great-grand-parent of NODE." + (let* ((parent (treesit-node-parent node)) + (g-parent (treesit-node-parent parent)) + (g-g-parent (treesit-node-parent g-parent))) + (treesit-node-parent g-g-parent))) + +(defun lua-ts--multi-arg-function-call-matcher (_n parent &rest _) + "Matches if PARENT has multiple arguments." + (> (treesit-node-child-count (treesit-node-parent parent)) 3)) + +(defun lua-ts--nested-function-argument-matcher (node &rest _) + "Matches if NODE is in a nested function argument." + (save-excursion + (goto-char (treesit-node-start node)) + (treesit-beginning-of-defun) + (backward-char 2) + (not (looking-at ")(")))) + +(defun lua-ts--nested-function-block-matcher (node &rest _) + "Matches if NODE is in a nested function block." + (let* ((g-g-g-parent (lua-ts--g-g-g-parent node)) + (g-g-g-type (treesit-node-type g-g-g-parent))) + (not (equal g-g-g-type "chunk")))) + +(defun lua-ts--nested-function-block-include-matcher (node _p bol &rest _) + "Matches if NODE's child at BOL is not another block." + (let* ((child (treesit-node-first-child-for-pos node bol)) + (child-type (treesit-node-type child)) + (g-g-g-type (treesit-node-type (lua-ts--g-g-g-parent node)))) + (or (equal child-type "assignment_statement") + (and (equal child-type "return_statement") + (or (equal g-g-g-type "arguments") + (and (equal g-g-g-type "expression_list") + (not (treesit-search-subtree child "function_call")))))))) + +(defun lua-ts--nested-function-end-matcher (node &rest _) + "Matches if NODE is the `end' of a nested function." + (save-excursion + (goto-char (treesit-node-start node)) + (treesit-beginning-of-defun) + (looking-at "function[[:space:]]*"))) + +(defun lua-ts--nested-function-end-argument-matcher (node &rest _) + "Matches if great-great-grandparent of NODE is arguments." + (equal "arguments" (treesit-node-type (lua-ts--g-g-g-parent node)))) + +(defun lua-ts--nested-function-last-function-matcher (_n parent &rest _) + "Matches if PARENT is the last nested function." + (let ((sparse-tree + (treesit-induce-sparse-tree parent #'lua-ts--function-definition-p))) + (= 1 (length (cadr sparse-tree))))) + (defvar lua-ts--syntax-table (let ((table (make-syntax-table))) (modify-syntax-entry ?+ "." table) @@ -379,26 +530,126 @@ lua-ts-flymake-luacheck (defun lua-ts-inferior-lua () "Run a Lua interpreter in an inferior process." (interactive) - (let* ((buffer lua-ts-inferior-buffer) - (name (string-replace "*" "" buffer)) - (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)) + (unless (comint-check-proc lua-ts-inferior-buffer) + (apply #'make-comint-in-buffer + (string-replace "*" "" lua-ts-inferior-buffer) + lua-ts-inferior-buffer + lua-ts-inferior-program + lua-ts-inferior-startfile + lua-ts-inferior-options) + (when lua-ts-inferior-history + (set-process-sentinel (get-buffer-process lua-ts-inferior-buffer) + 'lua-ts-inferior--write-history)) + (with-current-buffer lua-ts-inferior-buffer (setq-local comint-input-ignoredups t + comint-input-ring-file-name lua-ts-inferior-history + comint-use-prompt-regexp t comint-prompt-read-only t - comint-prompt-regexp prompt-regexp - comint-use-prompt-regexp t)) - (select-window (display-buffer buffer '((display-buffer-reuse-window - display-buffer-pop-up-frame) - (reusable-frames . t)))))) + comint-prompt-regexp (rx-to-string `(: bol + ,lua-ts-inferior-prompt + (1+ space)))) + (comint-read-input-ring t) + (add-hook 'comint-preoutput-filter-functions + (lambda (string) + (if (or (not (equal (buffer-name) lua-ts-inferior-buffer)) + (equal string + (concat lua-ts-inferior-prompt-continue " "))) + string + (concat + ;; Filter out the extra prompt characters that + ;; accumulate in the output when sending regions + ;; to the inferior process. + (replace-regexp-in-string (rx-to-string + `(: bol + (* ,lua-ts-inferior-prompt + (? ,lua-ts-inferior-prompt) + (1+ space)) + (group (* nonl)))) + "\\1" string) + ;; Re-add the prompt for the next line. + lua-ts-inferior-prompt " ")))))) + (select-window (display-buffer lua-ts-inferior-buffer + '((display-buffer-reuse-window + display-buffer-pop-up-frame) + (reusable-frames . t)))) + (get-buffer-process (current-buffer))) + +(defun lua-ts-send-buffer () + "Send current buffer to the inferior Lua process." + (interactive) + (lua-ts-send-region (point-min) (point-max))) + +(defun lua-ts-send-file (file) + "Send contents of FILE to the inferior Lua process." + (interactive "f") + (with-temp-buffer + (insert-file-contents-literally file) + (lua-ts-send-region (point-min) (point-max)))) + +(defun lua-ts-send-region (beg end) + "Send region between BEG and END to the inferior Lua process." + (interactive "r") + (let ((string (buffer-substring-no-properties beg end)) + (proc-buffer (lua-ts-inferior-lua))) + (comint-send-string proc-buffer "print()") ; Prevent output from + (comint-send-string proc-buffer "\n") ; appearing at prompt. + (comint-send-string proc-buffer string) + (comint-send-string proc-buffer "\n"))) + +(defun lua-ts-show-process-buffer () + "Show the inferior Lua process buffer." + (interactive) + (display-buffer lua-ts-inferior-buffer)) + +(defun lua-ts-hide-process-buffer () + "Hide the inferior Lua process buffer." + (interactive) + (delete-windows-on lua-ts-inferior-buffer)) + +(defun lua-ts-kill-process () + "Kill the inferior Lua process." + (interactive) + (with-current-buffer lua-ts-inferior-buffer + (kill-buffer-and-window))) + +(defun lua-ts-inferior--write-history (process _) + "Write history file for inferior Lua PROCESS." + ;; Depending on how the process is killed the buffer may not be + ;; around anymore; e.g. `kill-buffer'. + (when-let* ((buffer (process-buffer process)) + ((buffer-live-p (process-buffer process)))) + (with-current-buffer buffer (comint-write-input-ring)))) + +(defvar lua-ts-mode-map + (let ((map (make-sparse-keymap "Lua"))) + (define-key map "\C-c\C-n" 'lua-ts-inferior-lua) + (define-key map "\C-c\C-c" 'lua-ts-send-buffer) + (define-key map "\C-c\C-l" 'lua-ts-send-file) + (define-key map "\C-c\C-r" 'lua-ts-send-region) + map) + "Keymap for `lua-ts-mode' buffers.") + +(easy-menu-define lua-ts-mode-menu lua-ts-mode-map + "Menu bar entry for `lua-ts-mode'." + `("Lua" + ["Evaluate Buffer" lua-ts-send-buffer] + ["Evaluate File" lua-ts-send-file] + ["Evaluate Region" lua-ts-send-region] + "--" + ["Start Process" lua-ts-inferior-lua] + ["Show Process Buffer" lua-ts-show-process-buffer] + ["Hide Process Buffer" lua-ts-hide-process-buffer] + ["Kill Process" lua-ts-kill-process] + "--" + ["Customize" (lambda () (interactive) (customize-group "lua-ts"))])) ;;;###autoload (define-derived-mode lua-ts-mode prog-mode "Lua" - "Major mode for editing Lua files, powered by tree-sitter." + "Major mode for editing Lua files, powered by tree-sitter. + +\\{lua-ts-mode-map}" :syntax-table lua-ts--syntax-table + (use-local-map lua-ts-mode-map) (when (treesit-ready-p 'lua) (treesit-parser-create 'lua) @@ -431,20 +682,39 @@ lua-ts-mode (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"))) + (function ,(rx (or "function_declaration" + "function_definition"))) + (keyword ,(regexp-opt lua-ts--keywords + 'symbols)) + (loop-statement ,(rx (or "do_statement" + "for_statement" + "repeat_statement" + "while_statement"))) + (sentence (or function + loop-statement + ,(rx (or "assignment_statement" + "comment" + "field" + "function_call" + "if_statement" + "return_statement" + "variable_declaration")))) + (sexp (or function + keyword + loop-statement + ,(rx (or "arguments" + "break_statement" + "expression_list" + "false" + "identifier" + "nil" + "number" + "parameters" + "parenthesized_expression" + "string" + "table_constructor" + "true" + "vararg_expression")))) (text "comment")))) ;; Imenu. diff --git a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts index 040225c8580..9797467bbe5 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/indent.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/indent.erts @@ -5,148 +5,675 @@ Code: (lua-ts-mode) (indent-region (point-min) (point-max))) -Name: Basic Indent +Name: Chunk Indent =-= - print( -0, - 1 -) + print(1) + print(2) +=-= +print(1) +print(2) +=-=-= -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 +Name: Function Indent + +=-= +function f1(n) +print(n) +return n + 1 end -f({ - x = 1, - y = 2, - z = 3, -}) +local function f2(n) +print(n) +return n * 2 +end -;(function() -return false -)() +local f3 = function(n) +print(n) +return n / 3 +end + +function f4(...) +local f = function (...) +if ok +then print(1) +else print(0) +end +end +return f +end + +function f5(...) +local f = function (...) +if ok +then +print(1) +else +print(0) +end +end +return f +end + +function f6(...) +local f = function (...) +if ok then +print(1) +else +print(0) +end +end +return f +end + +;(function () + return true + end)() =-= -print( - 0, - 1 -) +function f1(n) + print(n) + return n + 1 +end -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 +local function f2(n) + print(n) + return n * 2 +end + +local f3 = function(n) + print(n) + return n / 3 +end + +function f4(...) + local f = function (...) + if ok + then print(1) + else print(0) + end end + return f end -f({ - x = 1, - y = 2, - z = 3, -}) +function f5(...) + local f = function (...) + if ok + then + print(1) + else + print(0) + end + end + return f +end + +function f6(...) + local f = function (...) + if ok then + print(1) + else + print(0) + end + end + return f +end -;(function() - return false -)() +;(function () + return true +end)() =-=-= -Name: Argument Indent +Name: Conditional Indent =-= -function h( -string, -number, -options) -print(string, number, options) +if true then +print(true) +return 1 +elseif false then +print(false) +return -1 +else +print(nil) +return 0 end -local p = h( -"sring", - 1000, - { -cost = 2, -length = 8, - parallelism = 4, -}) +if true + then + print(true) + return 1 + elseif false + then + print(false) + return -1 + else + print(nil) + return 0 +end + +if true + then return 1 + elseif false + then return -1 + else return 0 +end =-= -function h( - string, - number, - options) - print(string, number, options) +if true then + print(true) + return 1 +elseif false then + print(false) + return -1 +else + print(nil) + return 0 end -local p = h( - "sring", - 1000, - { - cost = 2, - length = 8, - parallelism = 4, - }) +if true +then + print(true) + return 1 +elseif false +then + print(false) + return -1 +else + print(nil) + return 0 +end + +if true +then return 1 +elseif false +then return -1 +else return 0 +end =-=-= -Name: Continuation Indent +Name: Loop Indent =-= +for k,v in pairs({}) do + print(k) + print(v) +end + +for i=1,10 + do print(i) +end + +while n < 10 do + n = n + 1 + print(n) +end + +while n < 10 + do + n = n + 1 + print(n) +end + +for i=0,9 do +repeat n = n+1 + until n > 99 +end + +repeat +z = z * 2 +print(z) +until z > 12 + + for i,x in ipairs(t) do + while i < 9 + do + local n = t[x] + repeat n = n + 1 + until n > #t + while n < 99 + do + print(n) + end + end + print(t[i]) + end + +do +local a = b +print(a + 1) +end +=-= +for k,v in pairs({}) do + print(k) + print(v) +end + +for i=1,10 +do print(i) +end + +while n < 10 do + n = n + 1 + print(n) +end + +while n < 10 +do + n = n + 1 + print(n) +end + +for i=0,9 do + repeat n = n+1 + until n > 99 +end + +repeat + z = z * 2 + print(z) +until z > 12 + +for i,x in ipairs(t) do + while i < 9 + do + local n = t[x] + repeat n = n + 1 + until n > #t + while n < 99 + do + print(n) + end + end + print(t[i]) +end + +do + local a = b + print(a + 1) +end +=-=-= + +Name: Bracket Indent + +=-= +fn( + ) + +tb={ + } +=-= +fn( +) + +tb={ +} +=-=-= + +Name: Multi-line String Indent + +=-= +local s = [[ + Multi-line + string content + ]] + function f() local str = [[ multi-line string ]] ---[[ -multi-line -comment - ]] return true end =-= +local s = [[ + Multi-line + string content + ]] + function f() local str = [[ multi-line string ]] - --[[ + return true +end +=-=-= + +Name: Multi-line Comment Indent + +=-= +--[[ + Multi-line + comment content + ]] + +function f() +--[[ +multi-line + comment + ]] + return true +end +=-= +--[[ + Multi-line + comment content + ]] + +function f() +--[[ multi-line -comment + comment ]] return true end =-=-= -Name: Loop Indent +Name: Argument Indent + +=-= + h( + "string", + 1000 + ) + +local p = h( +"string", + 1000 +) + +fn(1, +2, + 3) + +fn( 1, 2, +3, 4 ) + +f({ +x = 1, +y = 2, +z = 3, +}) + +f({ x = 1, +y = 2, +z = 3, }) + +Test({ +a=1 +}) + +Test({ +a = 1, +b = 2, +}, +nil) +=-= +h( + "string", + 1000 +) + +local p = h( + "string", + 1000 +) + +fn(1, + 2, + 3) + +fn( 1, 2, + 3, 4 ) + +f({ + x = 1, + y = 2, + z = 3, +}) + +f({ x = 1, + y = 2, + z = 3, }) + +Test({ + a=1 +}) + +Test({ + a = 1, + b = 2, + }, + nil) +=-=-= + +Name: Parameter Indent =-= -for k, v in pairs({}) do - print(k, v) +function f1( +a, +b +) +print(a,b) end -while n < 10 do -n = n + 1 +local function f2(a, + b) +print(a,b) end -repeat -z = z * 2 - until z > 12 +local f3 = function( a, b, + c, d ) +print(a,b,c,d) +end =-= -for k, v in pairs({}) do - print(k, v) +function f1( + a, + b +) + print(a,b) end -while n < 10 do - n = n + 1 +local function f2(a, + b) + print(a,b) end -repeat - z = z * 2 -until z > 12 +local f3 = function( a, b, + c, d ) + print(a,b,c,d) +end +=-=-= + +Name: Table Indent + +=-= +local Other = { + First={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Second={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Third={up={Goto=true}, + down={Goto=true}, + left={Goto=true}, + right={Goto=true}} +} + +local Other = { +a = 1, + b = 2, + c = 3, +} +=-= +local Other = { + First={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Second={up={Step=true,Jump=true}, + down={Step=true,Jump=true}, + left={Step=true,Jump=true}, + right={Step=true,Jump=true}}, + Third={up={Goto=true}, + down={Goto=true}, + left={Goto=true}, + right={Goto=true}} +} + +local Other = { + a = 1, + b = 2, + c = 3, +} +=-=-= + +Code: + (lambda () + (setq indent-tabs-mode nil) + (setq lua-ts-indent-offset 4) + (lua-ts-mode) + (indent-region (point-min) (point-max))) + +Name: End Indent + +=-= +function f(x) + for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end end end end + return {x,y} or {math.random(),math.random()} + end + +for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end + end end end +=-= +function f(x) + for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end end end end + return {x,y} or {math.random(),math.random()} +end + +for y=1,x.y do + for x=1,x.z do + if x.y and x.z then + if y <= x then + y = y + 1 + end +end end end +=-=-= + +Name: Nested Function Indent + +=-= +function a(...) + return (function (x) + return x + end)(foo(...)) +end + +function b(n) + local x = 1 + return function (i) + return function (...) + return (function (n, ...) + return function (f, ...) + return (function (...) + if ... and x < 9 then + x = x + 1 + return ... + end end)(n(f, ...)) + end, ... + end)(i(...)) +end end end + +function c(f) + local f1 = function (...) + if nil ~= ... then + return f(...) + end + end + return function (i) + return function (...) + local fn = function (n, ...) + local x = function (f, ...) + return f1(n(f, ...)) + end + return x + end + return fn(i(...)) + end + end +end + +function d(f) + local f1 = function (c, f, ...) + if ... then + if f(...) then + return ... + else + return c(f, ...) + end end end + return function (i) + return function (...) + return (function (n, ...) + local function j (f, ...) + return f1(j, f, n(f, ...)) + end + return j, ... + end)(i(...)) +end end end + +function e (n, t) + return function (i) + return function (...) + return ( + function (n, ...) + local x, y, z = 0, {} + return (function (f, ...) + return (function (i, ...) return i(i, ...) end)( + function (i, ...) + return f(function (x, ...) + return i(i, ...)(x, ...) + end, ...) + end) + end)(function (j) + return function(f, ...) + return (function (c, f, ...) + if ... then + if n+1 == x then + local y1, x1 = y, x + y, x = {}, 0 + return (function (...) + z = ... + return ... + end)(t(y1-1, x1-1, ...)) + else + x = x - 1 + return c(f, + (function (...) + z = ... + return ... + end)(t(y, x, ...))) + end + elseif x ~= 0 then + x = 0 + return z, y + end end)(j, f, n(f, ...)) + end end), ... + end)(i(...)) +end end end =-=-= diff --git a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts index 770aa23b18d..11e86f12926 100644 --- a/test/lisp/progmodes/lua-ts-mode-resources/movement.erts +++ b/test/lisp/progmodes/lua-ts-mode-resources/movement.erts @@ -147,7 +147,7 @@ end| print(1) =-=-= -Name: forward-sentence moves over for statements +Name: forward-sentence moves over do statements =-= |do @@ -417,34 +417,6 @@ Code: 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 =-= @@ -481,41 +453,91 @@ local t = { 1, 3 }| =-=-= -Code: - (lambda () - (lua-ts-mode) - (backward-sexp 1)) +Name: forward-sexp moves over parenthesized expressions -Point-Char: | +=-= +|(function (x) return x + 1 end)(41) +=-= +(function (x) return x + 1 end)|(41) +=-=-= -Name: backward-sexp moves over blocks +Name: forward-sexp moves over function declarations =-= -local function Test() - local t = { - a = 1, - } +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-=-= - if true then - print(1) - else - print(0) - end| +Name: forward-sexp moves over do statements + +=-= +|do + print(a + 1) end =-= -local function Test() - |local t = { - a = 1, - } +do + print(a + 1) +end| +=-=-= - if true then - print(1) - else - print(0) - end +Name: forward-sexp moves over for statements + +=-= +|for k,v in pairs({}) do + print(k, v) +end +=-= +for k,v in pairs({}) do + print(k, v) +end| +=-=-= + +Name: forward-sexp moves over repeat statements + +=-= +|repeat + n = n + 1 +until n > 10 +=-= +repeat + n = n + 1 +until n > 10| +=-=-= + +Name: forward-sexp moves over while statements + +=-= +|while n < 99 +do + n = n+1 end +=-= +while n < 99 +do + n = n+1 +end| =-=-= +Code: + (lambda () + (lua-ts-mode) + (backward-sexp 1)) + +Point-Char: | + Name: backward-sexp moves over arguments =-= @@ -551,3 +573,31 @@ local t = |{ 1, 2, 3 } =-=-= + +Name: backward-sexp moves over parenthesized expressions + +=-= +(function (x) return x + 1 end)|(41) +=-= +|(function (x) return x + 1 end)(41) +=-=-= + +Name: backward-sexp moves over function declarations + +=-= +function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end| +=-= +|function foo (x) + if false then + print "foo" + elseif true then + print "bar" + end +end +=-=-= -- 2.41.0 ^ permalink raw reply related [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-17 3:26 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-20 20:40 ` Stefan Kangas 2023-10-22 20:03 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-21 5:15 ` Andrey 2023-10-21 11:37 ` Andrey 2 siblings, 1 reply; 25+ messages in thread From: Stefan Kangas @ 2023-10-20 20:40 UTC (permalink / raw) To: john muhl, 66159; +Cc: Andrey Listopadov, Mauro Aranda john muhl via "Bug reports for GNU Emacs, the Swiss army knife of text editors" <bug-gnu-emacs@gnu.org> writes: > Here is the latest version. Fixed a missing declare-function > and other minor omissions. Thanks. Is this ready for installing on master, or is there anything else that needs doing first? ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-20 20:40 ` Stefan Kangas @ 2023-10-22 20:03 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-23 8:11 ` Stefan Kangas 0 siblings, 1 reply; 25+ messages in thread From: john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-22 20:03 UTC (permalink / raw) To: Stefan Kangas; +Cc: 66159, Andrey Listopadov, Mauro Aranda Stefan Kangas <stefankangas@gmail.com> writes: > john muhl via "Bug reports for GNU Emacs, the Swiss army knife of text > editors" <bug-gnu-emacs@gnu.org> writes: > >> Here is the latest version. Fixed a missing declare-function >> and other minor omissions. > > Thanks. Is this ready for installing on master, or is there anything > else that needs doing first? It should be ok to install. ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-22 20:03 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors @ 2023-10-23 8:11 ` Stefan Kangas 0 siblings, 0 replies; 25+ messages in thread From: Stefan Kangas @ 2023-10-23 8:11 UTC (permalink / raw) To: john muhl; +Cc: 66159-done, Andrey Listopadov, Mauro Aranda Version: 30.1 john muhl <jm@pub.pink> writes: > It should be ok to install. Thanks, installed on master. I'm consequently closing this bug. [1: 1c261e0a6ca]: 2023-10-23 10:07:52 +0200 Various improvements to lua-ts-mode (Bug#66159) https://git.savannah.gnu.org/cgit/emacs.git/commit/?id=1c261e0a6cae09e3ff36930442f2c9da44bccd6d ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-17 3:26 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-20 20:40 ` Stefan Kangas @ 2023-10-21 5:15 ` Andrey 2023-10-21 11:37 ` Andrey 2 siblings, 0 replies; 25+ messages in thread From: Andrey @ 2023-10-21 5:15 UTC (permalink / raw) To: john muhl, 66159; +Cc: Mauro Aranda >Here is the latest version. Fixed a missing declare-function >and other minor omissions. > Thanks! Unfortunately, I'm on the trip right now and can't check the patch. Sorry for delay. The last patch was great, so I have no objections from my part. -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
* bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) 2023-10-17 3:26 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-20 20:40 ` Stefan Kangas 2023-10-21 5:15 ` Andrey @ 2023-10-21 11:37 ` Andrey 2 siblings, 0 replies; 25+ messages in thread From: Andrey @ 2023-10-21 11:37 UTC (permalink / raw) To: john muhl, 66159; +Cc: Mauro Aranda >Here is the latest version. Fixed a missing declare-function >and other minor omissions. > Thanks! Unfortunately, I'm on the trip right now and can't check the patch. Sorry for delay. The last patch was great, so I have no objections from my part. -- Andrey Listopadov -- Andrey Listopadov ^ permalink raw reply [flat|nested] 25+ messages in thread
end of thread, other threads:[~2023-10-23 8:11 UTC | newest] Thread overview: 25+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2023-09-22 19:17 bug#66159: 30.0.50; lua-ts-mode semantic indentation problems Andrey Listopadov 2023-09-22 19:49 ` Eli Zaretskii 2023-09-24 15:06 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-24 15:44 ` Eli Zaretskii 2023-09-24 16:38 ` Andrey Listopadov 2023-09-24 18:20 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-26 19:21 ` Andrey Listopadov 2023-09-27 1:18 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-09-30 9:59 ` Andrey Listopadov 2023-09-30 13:57 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-03 15:04 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-03 19:13 ` Andrey Listopadov 2023-09-30 7:52 ` Philip Kaludercic 2023-10-06 19:44 ` bug#66159: [PATCH] Various improvements to lua-ts-mode (Bug#66159) john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-07 10:11 ` Mauro Aranda 2023-10-07 16:15 ` Andrey Listopadov 2023-10-07 18:10 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-08 9:43 ` Andrey Listopadov 2023-10-09 3:28 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-17 3:26 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-20 20:40 ` Stefan Kangas 2023-10-22 20:03 ` john muhl via Bug reports for GNU Emacs, the Swiss army knife of text editors 2023-10-23 8:11 ` Stefan Kangas 2023-10-21 5:15 ` Andrey 2023-10-21 11:37 ` Andrey
Code repositories for project(s) associated with this public inbox https://git.savannah.gnu.org/cgit/emacs.git This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).