branch: externals/matlab-mode
commit 216e97fa729f1983be78bdfa29e064e27dd9b7b9
Author: John Ciolfi <[email protected]>
Commit: John Ciolfi <[email protected]>
matlab-ts-mode: treesit-defun-name-function setup for Change Log's
---
contributing/treesit-mode-how-to.org | 15 +++++
matlab-ts-mode.el | 19 ++++--
tests/t-utils.el | 77 +++++++++++++++++++---
.../ts_defun_name_class.m | 14 ++++
.../ts_defun_name_class_expected.txt | 45 +++++++++++++
.../ts_defun_name_fcn.m | 23 +++++++
.../ts_defun_name_fcn_expected.txt | 70 ++++++++++++++++++++
tests/test-matlab-ts-mode-treesit-defun-name.el | 58 ++++++++++++++++
8 files changed, 308 insertions(+), 13 deletions(-)
diff --git a/contributing/treesit-mode-how-to.org
b/contributing/treesit-mode-how-to.org
index 9800eef50a..b293bfa3d1 100644
--- a/contributing/treesit-mode-how-to.org
+++ b/contributing/treesit-mode-how-to.org
@@ -1054,6 +1054,16 @@ LANGUAGE-ts-mode--thing-settings)= after you've setup
your syntax table.
TODO
+* treesit-defun-name-function
+
+Emacs supports the concept of Change Logs for documentating changes. With
version control systems
+like git, there's less need for Change Logs, though the format of the Change
Logs. In Emacs using
+=C-x 4 a= (add-change-log-entry-other-window) will end up calling
=add-log-current-defun= which
+defers to the =treesit-defun-name-function= to get information for the entry
to add to the log file.
+
+TODO
+
+
* IMenu
Emacs =M-g i= (=M-x imenu=), makes it easy to jump to items in your file. If
our mode populates
@@ -1633,3 +1643,8 @@ well worth writing a tree-sitter mode.
10. Accurate type of m-file detection, which improves
matlab-sections-minor-mode.
TODO
+
+ 11. Change Log command now work with MATALB *.m files.
+
+ Running =C-x 4 a= (add-change-log-entry-other-window) will now insert
the name of the function
+ or classdef for the current point.
diff --git a/matlab-ts-mode.el b/matlab-ts-mode.el
index 44c1b98d6e..5d90da202a 100644
--- a/matlab-ts-mode.el
+++ b/matlab-ts-mode.el
@@ -789,6 +789,17 @@ expression."
)
"Tree-sitter rules that things for movement.")
+;;---------------------;;
+;; Section: Change Log ;;
+;;---------------------;;
+
+(defun matlab-ts-mode--defun-name (node)
+ "Return the defun name of NODE for Change Log entries."
+ (when (string-match-p
+ (rx bol (or "function_definition" "class_definition") eol)
+ (treesit-node-type node))
+ (treesit-node-text (treesit-node-child-by-field-name node "name"))))
+
;;-------------------------;;
;; Section: matlab-ts-mode ;;
;;-------------------------;;
@@ -817,12 +828,10 @@ expression."
;; See: ./tests/test-matlab-ts-mode-page.el
(setq-local page-delimiter "^\\(\f\\|%%\\(\\s-\\|\n\\)\\)")
- ;; TODO function end handling
- ;; TODO add strings to syntax table?
+ ;; TODO function name vs file name prompt to fix
;; TODO what about syntax table and electric keywords?
;; TODO function / end match like matlab-mode
;; TODO code folding
- ;; TODO fill paragraph, etc. look at c-ts-common.el
;; TODO outline: look at
https://hg.sr.ht/~pranshu/perl-ts-mode/browse/perl-ts-mode.el?rev=tip
;; TODO imenu: look at
https://hg.sr.ht/~pranshu/perl-ts-mode/browse/perl-ts-mode.el?rev=tip
;; TODO handle file name mismatch between function / classdef name
@@ -853,8 +862,8 @@ expression."
;; Movement. See: tests/test-matlab-ts-mode-movement.el
(setq-local treesit-thing-settings matlab-ts-mode--thing-settings)
- ;; TODO's
- (setq-local treesit-defun-name-function nil) ;; TODO
+ ;; Change Logs. See: tests/test-matlab-ts-mode-treesit-defun-name.el
+ (setq-local treesit-defun-name-function #'matlab-ts-mode--defun-name)
(setq-local treesit-simple-imenu-settings nil) ;; TODO
;;
https://www.reddit.com/r/emacs/comments/1c216kr/experimenting_with_tree_sitter_and_imenulist/
diff --git a/tests/t-utils.el b/tests/t-utils.el
index 467bd40084..7acb5b7558 100644
--- a/tests/t-utils.el
+++ b/tests/t-utils.el
@@ -24,9 +24,10 @@
;;; Code:
-(require 'cl-seq)
(require 'cl-macs)
+(require 'cl-seq)
(require 'diff)
+(require 'treesit)
;; Add abs-path of ".." to load-path so we can require packages from above us.
(let* ((lf (or load-file-name (buffer-file-name (current-buffer))))
@@ -619,9 +620,10 @@ match NAME_expected.txt, NAME_expected.EXT~ will be
created. You are
then instructured to validate the indent and rename NAME_expected.EXT~
to NAME_expected.EXT.
-To add a test for TEST-NAME.el, in it's corresponding TEST-NAME-files/
-directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow
-the messages to accept the generated baseline after validating it.
+To add a test for TEST-NAME.el which call this function, in the
+corresponding TEST-NAME-files/ directory, create
+TEST-NAME-files/NAME.EXT, then run the test. Follow the messages to
+accept the generated baseline after validating it.
Two methods are used to indent each file in LANG-FILES,
1. (indent-region (point-min) (point-man))
@@ -676,14 +678,15 @@ See `t-utils--test-indent-type' for LINE-MANIPULATOR."
Compare syntax-table of each NAME.EXT in LANG-FILES against NAME_expected.txt.
TEST-NAME is used in messages.
-If NAME_expected.txt does not exist or the syntax-table of NAME.txt doesn't
+If NAME_expected.txt does not exist or the syntax-table of NAME.ext doesn't
match NAME_expected.txt, NAME_expected.txt~ will be created. You are
then instructured to validate the syntax-table and rename NAME_expected.txt~
to NAME_expected.txt.
-To add a test for TEST-NAME.el, in it's corresponding TEST-NAME-files/
-directory, create TEST-NAME-files/NAME.EXT, then run the test. Follow
-the messages to accept the generated baseline after validating it."
+To add a test for TEST-NAME.el which call this function, in the
+corresponding TEST-NAME-files/ directory, create
+TEST-NAME-files/NAME.EXT, then run the test. Follow the messages to
+accept the generated baseline after validating it."
(dolist (lang-file lang-files)
(with-temp-buffer
@@ -727,5 +730,63 @@ See %s and if it looks good rename it to %s"
lang-file got-file expected-file)))
(message "PASS: %s %s %s" test-name lang-file (t-utils--took
start-time))))))
+(defun t-utils-test-treesit-defun-name (test-name lang-files)
+ "Test `treesit-defun-name-function' setup.
+Compare the result of `treesit-defun-name-function' against each
+tree-sitter node in each NAME.EXT of LANG-FILES against
+NAME_expected.txt. TEST-NAME is used in messages.
+
+If NAME_expected.txt does not exist or the result from NAME.EXT doesn't
+match NAME_expected.txt, NAME_expected.txt~ will be created. You are
+then instructured to validate the syntax-table and rename NAME_expected.txt~
+to NAME_expected.txt.
+
+To add a test for TEST-NAME.el which call this function, in the
+corresponding TEST-NAME-files/ directory, create
+TEST-NAME-files/NAME.EXT, then run the test. Follow the messages to
+accept the generated baseline after validating it."
+
+ (dolist (lang-file lang-files)
+ (with-temp-buffer
+
+ (let ((start-time (current-time)))
+ (message "START: %s %s" test-name lang-file)
+
+ (t-utils--insert-file-for-test lang-file)
+
+ (let* ((root (treesit-buffer-root-node))
+ (expected-file (replace-regexp-in-string "\\.[^.]+$"
"_expected.txt" lang-file))
+ (expected (when (file-exists-p expected-file)
+ (with-temp-buffer
+ (insert-file-contents-literally expected-file)
+ (buffer-string))))
+ (got "")
+ (got-file (concat expected-file "~")))
+
+ (treesit-search-subtree
+ root
+ (lambda (node)
+ (let ((defun-name (funcall treesit-defun-name-function node))
+ (node-type (replace-regexp-in-string "\n" "\\n"
(treesit-node-type node)))
+ (node-start (treesit-node-start node))
+ (node-end (treesit-node-end node)))
+ (setq got (concat
+ got
+ (format "Node %25s at %4d to %4d: defun-name = %s\n"
+ node-type node-start node-end (if defun-name
defun-name "nil")))))
+ nil))
+
+ (kill-buffer)
+ (when (not (string= got expected))
+ (let ((coding-system-for-write 'raw-text-unix))
+ (write-region got nil got-file))
+ (when (not expected)
+ (error "Baseline for %s does not exists. \
+See %s and if it looks good rename it to %s"
+ lang-file got-file expected-file))
+ (error "Baseline for %s does not match, got: %s, expected: %s"
+ lang-file got-file expected-file)))
+ (message "PASS: %s %s %s" test-name lang-file (t-utils--took
start-time))))))
+
(provide 't-utils)
;;; t-utils.el ends here
diff --git
a/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_class.m
b/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_class.m
new file mode 100644
index 0000000000..1cf1bc090b
--- /dev/null
+++ b/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_class.m
@@ -0,0 +1,14 @@
+% -*- matlab-ts -*-
+classdef ts_defun_name_class
+ properties
+ Value {mustBeNumeric}
+ end
+ methods
+ function r = roundOff(obj)
+ r = round([obj.Value], 2);
+ end
+ function r = multiplyBy(obj, n)
+ r = [obj.Value] * n;
+ end
+ end
+end
diff --git
a/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_class_expected.txt
b/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_class_expected.txt
new file mode 100644
index 0000000000..b2853e28de
--- /dev/null
+++
b/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_class_expected.txt
@@ -0,0 +1,45 @@
+Node source_file at 1 to 298: defun-name = nil
+Node comment at 1 to 20: defun-name = nil
+Node class_definition at 21 to 297: defun-name =
ts_defun_name_class
+Node identifier at 30 to 49: defun-name = nil
+Node properties at 54 to 102: defun-name = nil
+Node property at 73 to 95: defun-name = nil
+Node identifier at 73 to 78: defun-name = nil
+Node validation_functions at 79 to 94: defun-name = nil
+Node identifier at 80 to 93: defun-name = nil
+Node methods at 107 to 293: defun-name = nil
+Node function_definition at 123 to 200: defun-name = roundOff
+Node function_output at 132 to 135: defun-name = nil
+Node identifier at 132 to 133: defun-name = nil
+Node identifier at 136 to 144: defun-name = nil
+Node function_arguments at 144 to 149: defun-name = nil
+Node identifier at 145 to 148: defun-name = nil
+Node block at 162 to 188: defun-name = nil
+Node assignment at 162 to 187: defun-name = nil
+Node identifier at 162 to 163: defun-name = nil
+Node function_call at 166 to 187: defun-name = nil
+Node identifier at 166 to 171: defun-name = nil
+Node arguments at 172 to 186: defun-name = nil
+Node matrix at 172 to 183: defun-name = nil
+Node row at 173 to 182: defun-name = nil
+Node field_expression at 173 to 182: defun-name = nil
+Node identifier at 173 to 176: defun-name = nil
+Node identifier at 177 to 182: defun-name = nil
+Node number at 185 to 186: defun-name = nil
+Node function_definition at 209 to 285: defun-name = multiplyBy
+Node function_output at 218 to 221: defun-name = nil
+Node identifier at 218 to 219: defun-name = nil
+Node identifier at 222 to 232: defun-name = nil
+Node function_arguments at 232 to 240: defun-name = nil
+Node identifier at 233 to 236: defun-name = nil
+Node identifier at 238 to 239: defun-name = nil
+Node block at 253 to 273: defun-name = nil
+Node assignment at 253 to 272: defun-name = nil
+Node identifier at 253 to 254: defun-name = nil
+Node binary_operator at 257 to 272: defun-name = nil
+Node matrix at 257 to 268: defun-name = nil
+Node row at 258 to 267: defun-name = nil
+Node field_expression at 258 to 267: defun-name = nil
+Node identifier at 258 to 261: defun-name = nil
+Node identifier at 262 to 267: defun-name = nil
+Node identifier at 271 to 272: defun-name = nil
diff --git
a/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_fcn.m
b/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_fcn.m
new file mode 100644
index 0000000000..4333104f6a
--- /dev/null
+++ b/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_fcn.m
@@ -0,0 +1,23 @@
+% -*- matlab-ts -*-
+function b = ts_defun_name_fcn(a)
+
+ b = 0;
+ if a > 1
+ if a > 2
+ disp('1 2')
+ switch a
+ case 2
+ disp('case 2')
+ b = fcn1(a);
+ end
+ end
+ end
+end
+
+function b = fcn1(a)
+ b = 5 * fcn2(a);
+
+ function d = fcn2(c)
+ d = c * 2;
+ end
+end
diff --git
a/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_fcn_expected.txt
b/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_fcn_expected.txt
new file mode 100644
index 0000000000..31739fb6b3
--- /dev/null
+++
b/tests/test-matlab-ts-mode-treesit-defun-name-files/ts_defun_name_fcn_expected.txt
@@ -0,0 +1,70 @@
+Node source_file at 1 to 363: defun-name = nil
+Node comment at 1 to 20: defun-name = nil
+Node function_definition at 21 to 262: defun-name = ts_defun_name_fcn
+Node function_output at 30 to 33: defun-name = nil
+Node identifier at 30 to 31: defun-name = nil
+Node identifier at 34 to 51: defun-name = nil
+Node function_arguments at 51 to 54: defun-name = nil
+Node identifier at 52 to 53: defun-name = nil
+Node block at 60 to 259: defun-name = nil
+Node assignment at 60 to 65: defun-name = nil
+Node identifier at 60 to 61: defun-name = nil
+Node number at 64 to 65: defun-name = nil
+Node if_statement at 71 to 258: defun-name = nil
+Node comparison_operator at 74 to 79: defun-name = nil
+Node identifier at 74 to 75: defun-name = nil
+Node number at 78 to 79: defun-name = nil
+Node block at 88 to 251: defun-name = nil
+Node if_statement at 88 to 250: defun-name = nil
+Node comparison_operator at 91 to 96: defun-name = nil
+Node identifier at 91 to 92: defun-name = nil
+Node number at 95 to 96: defun-name = nil
+Node block at 109 to 239: defun-name = nil
+Node function_call at 109 to 120: defun-name = nil
+Node identifier at 109 to 113: defun-name = nil
+Node arguments at 114 to 119: defun-name = nil
+Node string at 114 to 119: defun-name = nil
+Node string_content at 115 to 118: defun-name = nil
+Node switch_statement at 133 to 238: defun-name = nil
+Node identifier at 140 to 141: defun-name = nil
+Node case_clause at 156 to 222: defun-name = nil
+Node number at 161 to 162: defun-name = nil
+Node block at 179 to 222: defun-name = nil
+Node function_call at 179 to 193: defun-name = nil
+Node identifier at 179 to 183: defun-name = nil
+Node arguments at 184 to 192: defun-name = nil
+Node string at 184 to 192: defun-name = nil
+Node string_content at 185 to 191: defun-name = nil
+Node assignment at 210 to 221: defun-name = nil
+Node identifier at 210 to 211: defun-name = nil
+Node function_call at 214 to 221: defun-name = nil
+Node identifier at 214 to 218: defun-name = nil
+Node arguments at 219 to 220: defun-name = nil
+Node identifier at 219 to 220: defun-name = nil
+Node function_definition at 264 to 362: defun-name = fcn1
+Node function_output at 273 to 276: defun-name = nil
+Node identifier at 273 to 274: defun-name = nil
+Node identifier at 277 to 281: defun-name = nil
+Node function_arguments at 281 to 284: defun-name = nil
+Node identifier at 282 to 283: defun-name = nil
+Node block at 289 to 359: defun-name = nil
+Node assignment at 289 to 304: defun-name = nil
+Node identifier at 289 to 290: defun-name = nil
+Node binary_operator at 293 to 304: defun-name = nil
+Node number at 293 to 294: defun-name = nil
+Node function_call at 297 to 304: defun-name = nil
+Node identifier at 297 to 301: defun-name = nil
+Node arguments at 302 to 303: defun-name = nil
+Node identifier at 302 to 303: defun-name = nil
+Node function_definition at 311 to 358: defun-name = fcn2
+Node function_output at 320 to 323: defun-name = nil
+Node identifier at 320 to 321: defun-name = nil
+Node identifier at 324 to 328: defun-name = nil
+Node function_arguments at 328 to 331: defun-name = nil
+Node identifier at 329 to 330: defun-name = nil
+Node block at 340 to 350: defun-name = nil
+Node assignment at 340 to 349: defun-name = nil
+Node identifier at 340 to 341: defun-name = nil
+Node binary_operator at 344 to 349: defun-name = nil
+Node identifier at 344 to 345: defun-name = nil
+Node number at 348 to 349: defun-name = nil
diff --git a/tests/test-matlab-ts-mode-treesit-defun-name.el
b/tests/test-matlab-ts-mode-treesit-defun-name.el
new file mode 100644
index 0000000000..7dfe09796e
--- /dev/null
+++ b/tests/test-matlab-ts-mode-treesit-defun-name.el
@@ -0,0 +1,58 @@
+;;; test-matlab-ts-mode-treesit-defun-name.el --- -*- lexical-binding: t -*-
+;;
+;; Copyright 2025 Free Software Foundation, Inc.
+;;
+;; This program is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+;;
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+;;
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING. If not, write to
+;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
+;;
+
+;;; Commentary:
+;;
+;; Validate matlab-ts-mode indent.
+;; Load ../matlab-ts-mode.el via require and run indent tests using
+;; ./test-matlab-ts-mode-treesit-defun-name-files/NAME.m comparing against
+;; ./test-matlab-ts-mode-treesit-defun-name-files/NAME_expected.org
+;;
+
+;;; Code:
+
+(require 't-utils)
+(require 'matlab-ts-mode)
+
+(cl-defun test-matlab-ts-mode-treesit-defun-name (&optional m-file)
+ "Test defun movement using
./test-matlab-ts-mode-treesit-defun-name-files/NAME.m.
+Using ./test-matlab-ts-mode-treesit-defun-name-files/NAME.m, compare defun
+movement against
+./test-matlab-ts-mode-treesit-defun-name-files/NAME_expected.org. If M-FILE is
+not provided, loop comparing all
+./test-matlab-ts-mode-treesit-defun-name-files/NAME.m files.
+
+To add a test, create
+ ./test-matlab-ts-mode-treesit-defun-name-files/NAME.m
+and run this function. The baseline is saved for you as
+ ./test-matlab-ts-mode-treesit-defun-name-files/NAME_expected.org~
+after validating it, rename it to
+ ./test-matlab-ts-mode-treesit-defun-name-files/NAME_expected.org"
+
+ (let ((test-name "test-matlab-ts-mode-treesit-defun-name"))
+
+ (when (not (t-utils-is-treesit-available 'matlab test-name))
+ (cl-return-from test-matlab-ts-mode-font-lock))
+
+ (let ((m-files (t-utils-get-files (concat test-name "-files") "\\.m$" nil
m-file)))
+ (t-utils-test-treesit-defun-name test-name m-files)))
+ "success")
+
+(provide 'test-matlab-ts-mode-treesit-defun-name)
+;;; test-matlab-ts-mode-treesit-defun-name.el ends here