branch: externals/matlab-mode
commit 2a75ba07a451eeaf8f75babb9a9f3fc54c3287be
Author: John Ciolfi <john.ciolfi...@gmail.com>
Commit: John Ciolfi <john.ciolfi...@gmail.com>

    matlab-ts-mode: add syntax-table and comment setup
---
 contributing/treesit-mode-how-to.org               |  51 +++-
 matlab-ts-mode.el                                  | 269 ++++++++++++++-------
 tests/test-matlab-ts-mode-font-lock.el             |   2 +-
 tests/test-matlab-ts-mode-indent.el                |  12 +-
 .../syntax_table_test1.m                           |  14 ++
 .../syntax_table_test1_expected.txt                | 252 +++++++++++++++++++
 tests/test-matlab-ts-mode-syntax-table.el          | 114 +++++++++
 7 files changed, 615 insertions(+), 99 deletions(-)

diff --git a/contributing/treesit-mode-how-to.org 
b/contributing/treesit-mode-how-to.org
index bc2b747d12..d26f94ce22 100644
--- a/contributing/treesit-mode-how-to.org
+++ b/contributing/treesit-mode-how-to.org
@@ -20,19 +20,53 @@
 
 #+title: Tree-Sitter How To
 #+author: John Ciolfi
-#+date: Jun-13-2025
+#+date: Jun-22-2025
 
 * TODO
 
 - [ ] Add how to setup comments and syntax table
 - [ ] Add indent assert rule
 - [ ] Add font-lock test
-- [ ] Add indent test  
+- [ ] Add indent tests
+- [ ] Add feature-based test for indent
+      - (directory-files-recursively DIR "\\.m$")
+      - On each file, check parse tree for ERROR nodes and see if it really 
has an error by running
+        matlab/bin/arch/mlint and looking for "Parse error". If no parse 
error, then flag these as
+        issues with the matlab tree-sitter.
+      - Indent the file to see if matlab-ts-mode--indent-assert-rule fires
 
 * Guide to building a tree-sitter mode
 
-This is a set of notes that I'm taking as I develop matlab-ts-mode.el with the 
goal of this
-becoming a guide for writting a tree-sitter mode for Emacs 30 or later.
+This is a set of notes that I'm taking as I develop matlab-ts-mode.el with the 
goal of this becoming
+a guide for writting a tree-sitter mode.
+
+This guide assumes was written when using Emacs 30.1 and the goal is to create 
*LANGUAGE-ts-mode*
+for /file.lang/ files.
+
+In creating a tree-sitter mode for a programming lanugage, you have two 
options. Releverage an
+old-style existing mode via =(define-derived-mode LANGUAGE-ts-mode 
OLD-LANGUAGE-mode "LANGUAGE"
+...)= and overriding items such as font-lock and indent. The other approach is
+to create a new LANGUAGE-ts-mode based on prog-mode which we recommend to 
eliminate coupling between
+the old-style mode and the new tree-sitter mode.
+
+#+begin_src emacs-lisp
+  (define-derived-mode LANGUAGE-ts-mode prog-mode "LANGUAGE" ...)
+#+end_src
+
+To create the mode, we recommend following this order:
+
+1. *Font-lock*. We suggest doing this first, so that /file.lang/ is 
syntatically colored when
+   viewing it.
+2. *Indent*. Next we setup indentation so that you can edit /file.lang/ easily.
+3. *Syntax table and comments*.
+4. *Navigation*. Setup treesit-defun-type-regexp and 
treesit-defun-name-function to enable navigation
+   features like beginning-of-defun and end-of-defun
+5. *Imenu*
+
+** Documentation
+
+ - 
[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Parsing-Program-Source.html][Emacs
 manual: Parsing Program Source]]
+ - 
[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Parser_002dbased-Indentation.html][Emacs
 manual: Parser-based Indentation]]
 
 * Syntax trees and queries
 
@@ -71,11 +105,6 @@ tree is roughly 10 times the text size of the program being 
analyzed. However, t
 tree sitter are highly accuracte and fast syntax coloring (font-lock), 
indentation, code
 navigation via syntatic expressions, etc.
 
-* Documentation
-
- - 
[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Parsing-Program-Source.html][Emacs
 manual: Parsing Program Source]]
- - 
[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Parser_002dbased-Indentation.html][Emacs
 manual: Parser-based Indentation]]
-
 * libtree-sitter-LANGUAGE.EXT
 
 Place the tree-sitter language library in 
=~/.emacs.d/tree-sitter/libtree-sitter-LANGUAGE.EXT=
@@ -154,8 +183,8 @@ You should now be able to use:
 
 * Font-lock
 
-Queries are needed to identify syntax tree nodes to fontify. See
-https://www.gnu.org/software/emacs/manual/html_node/elisp/Pattern-Matching.html
+Queries are needed to identify syntax tree nodes to fontify. See 
[[https://www.gnu.org/software/emacs/manual/html_node/elisp/Pattern-Matching.html][Emacs
 manual - Pattern Matching
+Tree-sitter Nodes]].
 
 You can use =M-x treesit-explore-mode= to see the nodes of the syntax tree.
 
diff --git a/matlab-ts-mode.el b/matlab-ts-mode.el
index 95ad09ca0c..c88f89801c 100644
--- a/matlab-ts-mode.el
+++ b/matlab-ts-mode.el
@@ -70,6 +70,103 @@
                 (const :tag "Standard" 3)
                 (const :tag "Standard plus parse errors" 4)))
 
+;;-----------------------;;
+;; Section: Syntax table ;;
+;;-----------------------;;
+
+(defvar matlab-ts-mode--syntax-table
+  (let ((st (make-syntax-table (standard-syntax-table))))
+    ;; Comment Handling:
+    ;; 1. Single line comments: % text (single char start),
+    ;;                          note includes "%{ text"
+    ;; 2. Multiline comments:   %{
+    ;;                            lines
+    ;;                          %}
+    ;; 3. Ellipsis line continuations comments: "... optional text"
+    ;;    are handled in `matlab-ts-mode--syntax-propertize'
+    (modify-syntax-entry ?%  "< 13" st)
+    (modify-syntax-entry ?{  "(} 2c" st)
+    (modify-syntax-entry ?}  "){ 4c" st)
+    (modify-syntax-entry ?\n ">"    st)
+
+    ;; String Handling:
+    ;;   Single quoted string (character vector):    'text'
+    ;;   Double-quoted string:                       "text"
+    ;;   Transpose:           varname'
+    ;;   Quoted quotes:       ' don''t '    or " this "" "
+    ;;   Unterminated Char V: ' text
+    (modify-syntax-entry ?'  "\"" st)
+    (modify-syntax-entry ?\" "\"" st)
+
+    ;; Words and Symbols:
+    (modify-syntax-entry ?_  "_" st)
+
+    ;; Punctuation:
+    (modify-syntax-entry ?\\ "." st)
+    (modify-syntax-entry ?\t " " st)
+    (modify-syntax-entry ?+  "." st)
+    (modify-syntax-entry ?-  "." st)
+    (modify-syntax-entry ?*  "." st)
+    (modify-syntax-entry ?/  "." st)
+    (modify-syntax-entry ?=  "." st)
+    (modify-syntax-entry ?<  "." st)
+    (modify-syntax-entry ?>  "." st)
+    (modify-syntax-entry ?&  "." st)
+    (modify-syntax-entry ?|  "." st)
+
+    ;; Parenthetical blocks:
+    ;;   Note: these are in standard syntax table, repeated here for 
completeness.
+    (modify-syntax-entry ?\(  "()" st)
+    (modify-syntax-entry ?\)  ")(" st)
+    (modify-syntax-entry ?\[  "(]" st)
+    (modify-syntax-entry ?\]  ")[" st)
+    (modify-syntax-entry ?{   "(}" st)
+    (modify-syntax-entry ?}   "){" st)
+
+    st)
+  "The matlab-ts-mode syntax table.")
+
+(defun matlab-ts-mode--put-char-category (pos category)
+  "At character POS, put text proerty CATEGORY."
+  (when (not (eobp))
+    (put-text-property pos (1+ pos) 'category category)
+    (put-text-property pos (1+ pos) 'mcm t)))
+
+(defmacro matlab-ts-mode--syntax-symbol (symbol syntax doc)
+  "Create a new SYMBOL with DOC used as a text property category with SYNTAX."
+  (declare (indent defvar) (debug (sexp form sexp)) (doc-string 3))
+  `(progn (defconst ,symbol ,syntax ,doc)
+         (put ',symbol 'syntax-table ,symbol)))
+
+;; In the Syntax Table descriptors, "<" is for comments
+(matlab-ts-mode--syntax-symbol matlab-ts-mode--ellipsis-syntax 
(string-to-syntax "<")
+  "Syntax placed on ellipsis to treat them as comments.")
+
+(defun matlab-ts-mode--syntax-propertize (&optional start end)
+  "Scan region between START and END to add properties.
+If region is not specified, scan the whole buffer.
+This will mark ellipsis line continuation's
+  ... optional text
+as comments which is how they are treated by MATLAB."
+  (save-match-data ;; avoid 'Syntax Checking transmuted the match-data'
+    (save-excursion
+      ;; Scan region, but always expand to beginning of line
+      (goto-char (or start (point-min)))
+      (beginning-of-line)
+
+      ;; Edits can change what properties characters can have so remove ours 
and reapply
+      (remove-text-properties (point) (save-excursion (goto-char (or end 
(point-max)))
+                                                     (end-of-line) (point))
+                             '(category nil mcm nil))
+
+      ;; Tell Emacs that ellipsis (...) line continuations are comments.
+      (while (and (not (>= (point) (or end (point-max)))) (not (eobp)))
+        (if (treesit-search-forward-goto (treesit-node-at (point))
+                                         (rx bol "line_continuation" eol)
+                                         t) ;; goto start of: ... optional text
+           (matlab-ts-mode--put-char-category (point) 
'matlab-ts-mode--ellipsis-syntax)
+          (goto-char (point-max)))))))
+
 ;;--------------------;;
 ;; Section: font-lock ;;
 ;;--------------------;;
@@ -187,13 +284,13 @@ START and END specify the region to be fontified."
 (defvar matlab-ts-mode--font-lock-settings
   (treesit-font-lock-rules
 
-   ;; Comments and line continuation: ... optional text
+   ;; F-Rule: Comments and line continuation: ... optional text
    :language 'matlab
    :feature 'comment
    '((comment) @font-lock-comment-face
      (line_continuation) @font-lock-comment-face)
 
-   ;; Special comments that override normal comment font
+   ;; F-Rule: special comments that override normal comment font
    :language 'matlab
    :feature 'comment
    :override t
@@ -203,12 +300,12 @@ START and END specify the region to be fontified."
      (function_definition (comment) @matlab-ts-mode--doc-comment-capture) ;; 
doc help comments
      (class_definition (comment) @matlab-ts-mode--doc-comment-capture)) ;; doc 
help comments
 
-   ;; ;; Keywords: if, else, etc.
+   ;; F-Rule: keywords: if, else, etc.
    :language 'matlab
    :feature 'keyword
    `([,@matlab-ts-mode--keywords] @font-lock-keyword-face)
 
-   ;; function/classdef
+   ;; F-Rule: function/classdef and items definiting them, e.g. the function 
arguments
    :language 'matlab
    :feature 'definition
    '((function_definition name: (identifier) @font-lock-function-name-face)
@@ -237,21 +334,21 @@ START and END specify the region to be fontified."
      (attribute (identifier) @font-lock-type-face "=" (identifier) 
@font-lock-builtin-face)
      (attribute (identifier) @font-lock-type-face))
 
-   ;; Strings
+   ;; F-Rule: strings "double quote" and 'single quote'
    :language 'matlab
    :feature 'string
    '((string_content) @font-lock-string-face
      ((string_content) ["\"" "'"]) @matlab-ts-string-delimiter-face
      (string ["\"" "'"] @matlab-ts-string-delimiter-face))
 
-   ;; Transpose uses "'" after an identifier, e.g. for matrix A we tranpose it 
via: A' since "'" is
-   ;; also used as a string, we use a different face for transpose and put it 
under the string
-   ;; category.
+   ;; F-Rule: transpose uses "'" after an identifier, e.g. for matrix A we 
tranpose it via: A'
+   ;; since "'" is also used as a string, we use a different face for 
transpose and put it under
+   ;; the string category.
    :language 'matlab
    :feature 'string
    '((postfix_operator "'" @font-lock-function-name-face))
 
-   ;; Types, e.g. int32()
+   ;; F-Rule: Types, e.g. int32()
    :language 'matlab
    :feature 'type
    `((function_call name: (identifier)
@@ -262,24 +359,24 @@ START and END specify the region to be fontified."
                                     eol))
                               @font-lock-type-face)))
 
-   ;; Constant numbers
+   ;; F-Rule: Constant literal numbers, e.g. 1234
    :language 'matlab
    :feature 'number
    '((number) @font-lock-constant-face)
 
-   ;; Brackets
+   ;; F-Rule: Brackets
    :language 'matlab
    :feature 'bracket
    '((["(" ")" "[" "]" "{" "}"]) @font-lock-bracket-face)
 
-   ;; Delimiters
+   ;; F-Rule: Delimiters, e.g. semicolon
    :language 'matlab
    :feature 'delimiter
    '((["," "." ";" ":" "@" "?"]) @font-lock-delimiter-face)
 
-   ;; Syntax errors
+   ;; F-Rule: Syntax errors
    :language 'matlab
-   :feature 'error
+   :feature 'syntax-error
    :override t
    '((ERROR) @font-lock-warning-face)
 
@@ -328,7 +425,7 @@ expression."
              (p-node (treesit-node-at prev-real-line-bol)))
         (string-match-p prev-real-line-node-type (or (treesit-node-type 
p-node) ""))))))
 
-(defvar tmp-debug-indent-rule
+(defvar matlab-ts--indent-debug-rule
   '((lambda (node parent bol)
       (message "-->N:%S P:%S BOL:%S GP:%S NPS:%S"
                node parent bol
@@ -355,12 +452,10 @@ expression."
 (defvar matlab-ts-mode--indent-rules
   `((matlab
 
-     ;; ,tmp-debug-indent-rule
-
-     ;; Rule: classdef's, function's, or code for a script that is at the 
top-level
+     ;; I-Rule: classdef's, function's, or code for a script that is at the 
top-level
      ((parent-is ,(rx bol "source_file" eol)) column-0 0)
 
-     ;; Rule: within a function/classdef doc block comment "%{ ... %}"?
+     ;; I-Rule: within a function/classdef doc block comment "%{ ... %}"?
      ((lambda (node parent bol &rest _)
         (and (not node)
              (string= "comment" (treesit-node-type parent))
@@ -369,7 +464,7 @@ expression."
              (matlab-ts-mode--is-doc-comment parent (treesit-node-parent 
parent))))
       parent 2)
 
-     ;; Rule: function/classdef doc comment?
+     ;; I-Rule: function/classdef doc comment?
      ((lambda (node parent &rest _)
         (or (and (string= "comment" (or (treesit-node-type node) ""))
                  (matlab-ts-mode--is-doc-comment node parent))
@@ -378,7 +473,7 @@ expression."
                  (matlab-ts-mode--is-doc-comment parent (treesit-node-parent 
parent)))))
       parent 0)
 
-     ;; Rule: within a code block comment "%{ ... %}"?
+     ;; I-Rule: within a code block comment "%{ ... %}"?
      ((lambda (node parent bol &rest _)
         (and (not node)
              (string= "comment" (treesit-node-type parent))
@@ -387,7 +482,7 @@ expression."
       parent
       2)
 
-     ;; Rule: last line of code block coment "%{ ... %}"?
+     ;; I-Rule: last line of code block coment "%{ ... %}"?
      ((lambda (node parent bol &rest _)
         (and (not node)
              (string= "comment" (treesit-node-type parent))
@@ -396,141 +491,141 @@ expression."
       parent
       0)
 
-     ;; Rule: switch case and otherwise statements
+     ;; I-Rule: switch case and otherwise statements
      ((node-is ,(rx bol (or "case_clause" "otherwise_clause") eol))
       parent ,matlab-ts-mode--switch-indent-level)
 
-     ;; Rule: first line of code witin a switch case or otherwise statement, 
node is block
+     ;; I-Rule: first line of code witin a switch case or otherwise statement, 
node is block
      ((parent-is ,(rx bol (or "case_clause" "otherwise_clause") eol))
       parent ,matlab-ts-mode--switch-indent-level)
 
-     ;; Rule: nested functions
+     ;; I-Rule: nested functions
      ((n-p-gp ,(rx bol "function_definition" eol) ,(rx bol "block" eol)
               ,(rx bol "function_definition" eol))
       parent 0)
 
-     ;; Rule: constructs within classdef or function's.
+     ;; I-Rule: constructs within classdef or function's.
      ((node-is ,(rx bol (or "arguments_statement" "block" "enumeration" "enum" 
"methods" "events"
                             "function_definition" "property" "properties")
                     eol))
       parent ,matlab-ts-mode--indent-level)
 
-     ;; Rule: elseif, else, catch, end statements go back to parent level
+     ;; I-Rule: elseif, else, catch, end statements go back to parent level
      ((node-is ,(rx bol (or "elseif_clause" "else_clause" "catch_clause" 
"end") eol)) parent 0)
 
-     ;; Rule: code in if, for, methods, function, arguments statements
+     ;; I-Rule: code in if, for, methods, function, arguments statements
      ((parent-is ,(rx bol (or "if_statement" "for_statement" "while_statement"
                               "methods" "events" "enumeration"
                               "function_definition" "arguments_statement")
                       eol))
       parent ,matlab-ts-mode--indent-level)
 
-     ;; Rule: function a<RET>
-     ;;       end
+     ;; I-Rule: function a<RET>
+     ;;         end
      ((n-p-gp nil ,(rx bol "\n" eol) ,(rx bol (or "function_definition") eol))
       grand-parent ,matlab-ts-mode--indent-level)
 
-     ;; Rule: case 10<RET>
+     ;; I-Rule: case 10<RET>
      ((n-p-gp nil ,(rx bol "\n" eol) ,(rx bol (or "switch_statement" 
"case_clause"
                                                   "otherwise_clause")
                                           eol))
       grand-parent ,matlab-ts-mode--switch-indent-level)
 
-     ;; Rule:  if condition1 || ...     |      if condition1 + condition2 == 
...
-     ;; <TAB>     condition2 || ...     |         2770000 ...
+     ;; I-Rule:  if condition1 || ...     |      if condition1 + condition2 == 
...
+     ;; <TAB>       condition2 || ...     |         2770000 ...
      ((parent-is ,(rx bol (or "boolean_operator" "comparison_operator") eol)) 
parent 0)
 
-     ;; Rule:  elseif ...
-     ;; <TAB>      condition2 || ...
+     ;; I-Rule:  elseif ...
+     ;; <TAB>        condition2 || ...
      ((parent-is ,(rx bol (or "else_clause" "elseif_clause") eol))
       parent ,matlab-ts-mode--indent-level)
-     
-     ;; Rule: if a ...
+
+     ;; I-Rule: if a ...
      ;; <TAB>
      ((n-p-gp nil ,(rx bol "\n" eol)
               ,(rx bol (or "if_statement" "else_clause" "elseif_clause" ) eol))
       grand-parent ,matlab-ts-mode--indent-level)
 
-     ;; Rule: disp(myMatrix(1:  ...
-     ;; <TAB>               end)); 
+     ;; I-Rule: disp(myMatrix(1:  ...
+     ;; <TAB>                 end));
      ((parent-is ,(rx bol "range" eol)) parent 0)
 
-     ;; Rule: try<RET>    |   catch<RET>
+     ;; I-Rule: try<RET>    |   catch<RET>
      ((parent-is ,(rx bol (or "try_statement" "catch_clause") eol))
       parent ,matlab-ts-mode--indent-level)
 
-     ;; Rule: function a
-     ;;           x = 1;
-     ;; <TAB>     y = 2;
+     ;; I-Rule: function a
+     ;;             x = 1;
+     ;; <TAB>       y = 2;
      ((parent-is ,(rx bol "block" eol)) parent 0)
 
-     ;; Rule: "switch var" and we type RET after the var
+     ;; I-Rule: "switch var" and we type RET after the var
      (,(matlab-ts-mode--prev-real-line-is (rx bol "\n" eol) (rx bol "switch" 
eol))
       ,#'matlab-ts-mode--prev-real-line ,matlab-ts-mode--switch-indent-level)
 
-     ;; Rule: "function foo()" and we type RET after the ")"
+     ;; I-Rule: "function foo()" and we type RET after the ")"
      (,(matlab-ts-mode--prev-real-line-is nil (rx bol "function" eol))
       ,#'matlab-ts-mode--prev-real-line ,matlab-ts-mode--indent-level)
 
-     ;; Rule:  a = ...
-     ;; <TAB>      1;
+     ;; I-Rule:  a = ...
+     ;; <TAB>        1;
      ((parent-is ,(rx bol "assignment" eol)) parent 
,matlab-ts-mode--indent-level)
 
-     ;; Rule:  a = 2 * ...
-     ;; <TAB>      1;
+     ;; I-Rule:  a = 2 * ...
+     ;; <TAB>        1;
      ((parent-is ,(rx bol "binary_operator" eol)) parent 0)
 
-     ;; Rule:  a = ( ...       |     a = [  ...     |     a = {    ...
-     ;;             1 ...      |          1 ...     |            1 ...
-     ;; <TAB>      );          |         ];         |         };
+     ;; I-Rule:  a = ( ...       |     a = [  ...     |     a = {    ...
+     ;;               1 ...      |          1 ...     |            1 ...
+     ;; <TAB>        );          |         ];         |         };
      ((node-is ,(rx bol (or ")" "]" "}") eol)) parent 0)
 
-     ;; Rule:  a = ( ...
-     ;; <TAB>       1 ...
+     ;; I-Rule:  a = ( ...
+     ;; <TAB>         1 ...
      ((parent-is ,(rx bol "parenthesis" eol)) parent 1)
 
-     ;; Rule:  a = [   ...    |    a = { ...
-     ;; <TAB>        2 ...    |          2 ...
+     ;; I-Rule:  a = [   ...    |    a = { ...
+     ;; <TAB>          2 ...    |          2 ...
      ((parent-is ,(rx bol (or "matrix" "cell") eol)) parent 
,matlab-ts-mode--array-indent-level)
 
-     ;; Rule:  function [   ...              |    function name (   ...
-     ;; <TAB>            a, ... % comment    |                   a, ... % 
comment
+     ;; I-Rule:  function [   ...              |    function name (   ...
+     ;; <TAB>              a, ... % comment    |                   a, ... % 
comment
      ((parent-is ,(rx bol (or "multioutput_variable" "function_arguments") 
eol)) parent 1)
 
-     ;; Rule:  a = [    2 ...       |   function a ...
-     ;; <TAB>           1 ...       |            = fcn
+     ;; I-Rule:  a = [    2 ...       |   function a ...
+     ;; <TAB>             1 ...       |            = fcn
      ((parent-is ,(rx bol (or "row" "function_output") eol)) parent 0)
 
-     ;; Rule:  a = ...
-     ;; <TAB>      1;
+     ;; I-Rule:  a = ...
+     ;; <TAB>        1;
      ((n-p-gp nil nil ,(rx bol "assignment" eol)) grand-parent 
,matlab-ts-mode--indent-level)
 
-     ;; Rule:  a = my_function(1, ...
-     ;; <TAB>                  2, ...
+     ;; I-Rule:  a = my_function(1, ...
+     ;; <TAB>                    2, ...
      ((parent-is ,(rx bol "arguments" eol)) parent 0)
 
-     ;; Rule:  my_function( ...
-     ;; <TAB>      1, ...
+     ;; I-Rule:  my_function( ...
+     ;; <TAB>        1, ...
      ((node-is ,(rx bol "arguments" eol)) parent ,matlab-ts-mode--indent-level)
 
-     ;; Rule: function indent_tab_between_fcns   |   function indent_tab_in_fcn
-     ;;       end                                |      disp('here')
-     ;; <TAB>                                    |
-     ;;       function b                         |   end
-     ;;       end                                |
+     ;; I-Rule: function indent_tab_between_fcns   |   function 
indent_tab_in_fcn
+     ;;         end                                |      disp('here')
+     ;; <TAB>                                      |
+     ;;         function b                         |   end
+     ;;         end                                |
      ((lambda (node parent bol)
         (and (not node)
              (string= (treesit-node-type parent) "\n")))
       grand-parent 0)
 
-     ;; Rule: In an empty line, string, etc. just maintain indent
-     ;;       switch in
-     ;;         case 10
-     ;;           disp('11');
+     ;; I-Rule: In an empty line, string, etc. just maintain indent
+     ;;         switch in
+     ;;           case 10
+     ;;             disp('11');
      ;; <TAB>
      (no-node ,#'matlab-ts-mode--prev-real-line 0)
 
-     ;; Rule: Assert if no rule matched and asserts are enabled.
+     ;; I-Rule: Assert if no rule matched and asserts are enabled.
      ,matlab-ts-mode--indent-assert-rule
      ))
   "Tree-sitter indent rules for `matlab-ts-mode'.")
@@ -542,12 +637,19 @@ expression."
   (when (treesit-ready-p 'matlab)
     (treesit-parser-create 'matlab)
 
+    ;; Syntax table - think of this as a "language character descriptor". It 
tells us what
+    ;; characters belong to word like things giving us movement commands e.g. 
C-M-f, matching
+    ;; parens, `show-paren-mode', etc.
+    (set-syntax-table matlab-ts-mode--syntax-table)
+    (setq-local syntax-propertize-function #'matlab-ts-mode--syntax-propertize)
+    ;; TODO: check other items in matlab--syntax-propertize, i.e. command-dual
+
     ;; Comments
-    ;;   TODO: M-; on code comments, then a 2nd M-; doesn't uncomment
-    ;;   likely need to also set up the syntax table.
     (setq-local comment-start      "%")
     (setq-local comment-end        "")
     (setq-local comment-start-skip "%\\s-+")
+    ;; TODO - page-delimiter, paragraph-start, etc. from matlab-mode
+
 
     ;; TODO function end handling
     ;; TODO add strings to syntax table?
@@ -571,11 +673,16 @@ expression."
                 '((comment definition)
                   (keyword string type)
                   (number bracket delimiter)
-                  ( error)))
+                  (syntax-error)))
 
     ;; Indent
-    (setq-local indent-tabs-mode nil ;; for consistency between Unix and 
Windows we don't use TABs.
-                treesit-simple-indent-rules matlab-ts-mode--indent-rules)
+    (setq-local indent-tabs-mode nil) ;; for consistency between Unix and 
Windows we don't use TABs.
+    (setq-local treesit-simple-indent-rules
+                (if treesit--indent-verbose ;; add debugging print as first 
rule?
+                    (list (append `,(list (caar matlab-ts-mode--indent-rules))
+                                  (list matlab-ts--indent-debug-rule)
+                                  (cdar matlab-ts-mode--indent-rules)))
+                  matlab-ts-mode--indent-rules))
 
     (treesit-major-mode-setup)))
 
diff --git a/tests/test-matlab-ts-mode-font-lock.el 
b/tests/test-matlab-ts-mode-font-lock.el
index 6a5a514b4f..2809c29e22 100644
--- a/tests/test-matlab-ts-mode-font-lock.el
+++ b/tests/test-matlab-ts-mode-font-lock.el
@@ -1,6 +1,6 @@
 ;;; test-matlab-ts-mode-font-lock.el --- Test matlab-ts-mode font-lock -*- 
lexical-binding: t -*-
 ;;
-;; Copyright Free Software Foundation
+;; 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
diff --git a/tests/test-matlab-ts-mode-indent.el 
b/tests/test-matlab-ts-mode-indent.el
index 60e87a631e..f1d744eb74 100644
--- a/tests/test-matlab-ts-mode-indent.el
+++ b/tests/test-matlab-ts-mode-indent.el
@@ -48,7 +48,7 @@
 (defvar test-matlab-ts-mode-indent (cons "test-matlab-ts-mode-indent"
                                          (test-matlab-ts-mode-indent-files)))
 
-(defun trim ()
+(defun test-matlab-ts-mode-indent--trim ()
   "Trim trailing whitespace and lines."
   (setq buffer-file-coding-system 'utf-8-unix)
   (let ((delete-trailing-lines t))
@@ -87,7 +87,7 @@ EXPECTED content in EXPECTED-FILE."
               (parent (and node (treesit-node-parent node))))
          (when (string= (treesit-node-type parent) "ERROR")
            (insert " ")))
-               
+
         (call-interactively #'indent-for-tab-command) ;; TAB on code just added
 
         ;; While next line in our original contents is a newline insert "\n"
@@ -101,7 +101,7 @@ EXPECTED content in EXPECTED-FILE."
           (call-interactively #'indent-for-tab-command))
         (forward-line))
 
-      (trim)
+      (test-matlab-ts-mode-indent--trim)
 
       (let ((typing-got (buffer-substring (point-min) (point-max))))
         (set-buffer-modified-p nil)
@@ -123,7 +123,7 @@ If M-FILE (NAME.m) is not provided, loop comparing all
 
 For debugging, you can run with a specified NAME.m,
   M-: (test-matlab-ts-mode-font-lock 
\"test-matlab-ts-mode-indent-files/NAME.m\")"
-  
+
   (let* ((m-files (if m-file
                       (progn
                         (setq m-file (file-truename m-file))
@@ -142,7 +142,7 @@ For debugging, you can run with a specified NAME.m,
           (message "START: test-matlab-ts-mode-indent %s" m-file)
           (find-file m-file)
           (indent-region (point-min) (point-max))
-          (trim)
+          (test-matlab-ts-mode-indent--trim)
           (let ((got (buffer-substring (point-min) (point-max)))
                 (got-file (concat expected-file "~")))
             (set-buffer-modified-p nil)
@@ -158,7 +158,7 @@ For debugging, you can run with a specified NAME.m,
 
         (when expected ;; expected-file exists?
           (test-matlab-ts-mode-indent--typing m-file expected expected-file)))
-          
+
       (message "PASS: test-matlab-ts-mode-indent %s" m-file)))
   "success")
 
diff --git a/tests/test-matlab-ts-mode-syntax-table-files/syntax_table_test1.m 
b/tests/test-matlab-ts-mode-syntax-table-files/syntax_table_test1.m
new file mode 100644
index 0000000000..97fb8d9075
--- /dev/null
+++ b/tests/test-matlab-ts-mode-syntax-table-files/syntax_table_test1.m
@@ -0,0 +1,14 @@
+function syntax_table_test1
+% help comment
+
+    % code comment
+    x = "double quote string";
+    y = 'double quote string';
+    x = [
+          1 2; ...
+          3 4; ... comment
+        ];
+    x = x';
+    x = x'';
+    y = x(2, 2);
+end
diff --git 
a/tests/test-matlab-ts-mode-syntax-table-files/syntax_table_test1_expected.txt 
b/tests/test-matlab-ts-mode-syntax-table-files/syntax_table_test1_expected.txt
new file mode 100644
index 0000000000..7f92a8d4c7
--- /dev/null
+++ 
b/tests/test-matlab-ts-mode-syntax-table-files/syntax_table_test1_expected.txt
@@ -0,0 +1,252 @@
+Line:1: function syntax_table_test1
+   f: (0 nil nil nil nil nil 0 nil nil nil nil)
+   u: (0 nil 1 nil nil nil 0 nil nil nil nil)
+   n: (0 nil 1 nil nil nil 0 nil nil nil nil)
+   c: (0 nil 1 nil nil nil 0 nil nil nil nil)
+   t: (0 nil 1 nil nil nil 0 nil nil nil nil)
+   i: (0 nil 1 nil nil nil 0 nil nil nil nil)
+   o: (0 nil 1 nil nil nil 0 nil nil nil nil)
+   n: (0 nil 1 nil nil nil 0 nil nil nil nil)
+    : (0 nil 1 nil nil nil 0 nil nil nil nil)
+   s: (0 nil 1 nil nil nil 0 nil nil nil nil)
+   y: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   n: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   t: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   a: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   x: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   _: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   t: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   a: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   b: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   l: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   e: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   _: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   t: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   e: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   s: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   t: (0 nil 10 nil nil nil 0 nil nil nil nil)
+   1: (0 nil 10 nil nil nil 0 nil nil nil nil)
+  \n: (0 nil 10 nil nil nil 0 nil nil nil nil)
+Line:2: % help comment
+   %: (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 10 nil t nil 0 nil 29 nil 327691)
+   h: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   e: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   l: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   p: (0 nil 10 nil t nil 0 nil 29 nil nil)
+    : (0 nil 10 nil t nil 0 nil 29 nil nil)
+   c: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   o: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   m: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   m: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   e: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   n: (0 nil 10 nil t nil 0 nil 29 nil nil)
+   t: (0 nil 10 nil t nil 0 nil 29 nil nil)
+  \n: (0 nil 10 nil t nil 0 nil 29 nil nil)
+Line:3: 
+  \n: (0 nil 10 nil nil nil 0 nil nil nil nil)
+Line:4:     % code comment
+    : (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 10 nil nil nil 0 nil nil nil nil)
+   %: (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 10 nil t nil 0 nil 49 nil 327691)
+   c: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   o: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   d: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   e: (0 nil 10 nil t nil 0 nil 49 nil nil)
+    : (0 nil 10 nil t nil 0 nil 49 nil nil)
+   c: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   o: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   m: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   m: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   e: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   n: (0 nil 10 nil t nil 0 nil 49 nil nil)
+   t: (0 nil 10 nil t nil 0 nil 49 nil nil)
+  \n: (0 nil 10 nil t nil 0 nil 49 nil nil)
+Line:5:     x = "double quote string";
+    : (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 10 nil nil nil 0 nil nil nil nil)
+   x: (0 nil 10 nil nil nil 0 nil nil nil nil)
+    : (0 nil 68 nil nil nil 0 nil nil nil nil)
+   =: (0 nil 68 nil nil nil 0 nil nil nil nil)
+    : (0 nil 68 nil nil nil 0 nil nil nil nil)
+   ": (0 nil 68 nil nil nil 0 nil nil nil nil)
+   d: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   o: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   u: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   b: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   l: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   e: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+    : (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   q: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   u: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   o: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   t: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   e: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+    : (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   s: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   t: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   r: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   i: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   n: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   g: (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   ": (0 nil 68 34 nil nil 0 nil 72 nil nil)
+   ;: (0 nil 72 nil nil nil 0 nil nil nil nil)
+  \n: (0 nil 72 nil nil nil 0 nil nil nil nil)
+Line:6:     y = 'double quote string';
+    : (0 nil 72 nil nil nil 0 nil nil nil nil)
+    : (0 nil 72 nil nil nil 0 nil nil nil nil)
+    : (0 nil 72 nil nil nil 0 nil nil nil nil)
+    : (0 nil 72 nil nil nil 0 nil nil nil nil)
+   y: (0 nil 72 nil nil nil 0 nil nil nil nil)
+    : (0 nil 99 nil nil nil 0 nil nil nil nil)
+   =: (0 nil 99 nil nil nil 0 nil nil nil nil)
+    : (0 nil 99 nil nil nil 0 nil nil nil nil)
+   ': (0 nil 99 nil nil nil 0 nil nil nil nil)
+   d: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   o: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   u: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   b: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   l: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   e: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+    : (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   q: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   u: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   o: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   t: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   e: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+    : (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   s: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   t: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   r: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   i: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   n: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   g: (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   ': (0 nil 99 39 nil nil 0 nil 103 nil nil)
+   ;: (0 nil 103 nil nil nil 0 nil nil nil nil)
+  \n: (0 nil 103 nil nil nil 0 nil nil nil nil)
+Line:7:     x = [
+    : (0 nil 103 nil nil nil 0 nil nil nil nil)
+    : (0 nil 103 nil nil nil 0 nil nil nil nil)
+    : (0 nil 103 nil nil nil 0 nil nil nil nil)
+    : (0 nil 103 nil nil nil 0 nil nil nil nil)
+   x: (0 nil 103 nil nil nil 0 nil nil nil nil)
+    : (0 nil 130 nil nil nil 0 nil nil nil nil)
+   =: (0 nil 130 nil nil nil 0 nil nil nil nil)
+    : (0 nil 130 nil nil nil 0 nil nil nil nil)
+   [: (0 nil 130 nil nil nil 0 nil nil nil nil)
+  \n: (1 134 nil nil nil nil 0 nil nil (134) nil)
+Line:8:           1 2; ...
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 nil nil nil nil 0 nil nil (134) nil)
+   1: (1 134 nil nil nil nil 0 nil nil (134) nil)
+    : (1 134 146 nil nil nil 0 nil nil (134) nil)
+   2: (1 134 146 nil nil nil 0 nil nil (134) nil)
+   ;: (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+   .: (1 134 148 nil nil nil 0 nil nil (134) nil)
+   .: (1 134 148 nil t nil 0 nil 151 (134) nil)
+   .: (1 134 148 nil t nil 0 nil 151 (134) nil)
+  \n: (1 134 148 nil t nil 0 nil 151 (134) nil)
+Line:9:           3 4; ... comment
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 148 nil nil nil 0 nil nil (134) nil)
+   3: (1 134 148 nil nil nil 0 nil nil (134) nil)
+    : (1 134 165 nil nil nil 0 nil nil (134) nil)
+   4: (1 134 165 nil nil nil 0 nil nil (134) nil)
+   ;: (1 134 167 nil nil nil 0 nil nil (134) nil)
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+   .: (1 134 167 nil nil nil 0 nil nil (134) nil)
+   .: (1 134 167 nil t nil 0 nil 170 (134) nil)
+   .: (1 134 167 nil t nil 0 nil 170 (134) nil)
+    : (1 134 167 nil t nil 0 nil 170 (134) nil)
+   c: (1 134 167 nil t nil 0 nil 170 (134) nil)
+   o: (1 134 167 nil t nil 0 nil 170 (134) nil)
+   m: (1 134 167 nil t nil 0 nil 170 (134) nil)
+   m: (1 134 167 nil t nil 0 nil 170 (134) nil)
+   e: (1 134 167 nil t nil 0 nil 170 (134) nil)
+   n: (1 134 167 nil t nil 0 nil 170 (134) nil)
+   t: (1 134 167 nil t nil 0 nil 170 (134) nil)
+  \n: (1 134 167 nil t nil 0 nil 170 (134) nil)
+Line:10:         ];
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+    : (1 134 167 nil nil nil 0 nil nil (134) nil)
+   ]: (1 134 167 nil nil nil 0 nil nil (134) nil)
+   ;: (0 nil 134 nil nil nil 0 nil nil nil nil)
+  \n: (0 nil 134 nil nil nil 0 nil nil nil nil)
+Line:11:     x = x';
+    : (0 nil 134 nil nil nil 0 nil nil nil nil)
+    : (0 nil 134 nil nil nil 0 nil nil nil nil)
+    : (0 nil 134 nil nil nil 0 nil nil nil nil)
+    : (0 nil 134 nil nil nil 0 nil nil nil nil)
+   x: (0 nil 134 nil nil nil 0 nil nil nil nil)
+    : (0 nil 197 nil nil nil 0 nil nil nil nil)
+   =: (0 nil 197 nil nil nil 0 nil nil nil nil)
+    : (0 nil 197 nil nil nil 0 nil nil nil nil)
+   x: (0 nil 197 nil nil nil 0 nil nil nil nil)
+   ': (0 nil 201 nil nil nil 0 nil nil nil nil)
+   ;: (0 nil 201 nil nil nil 0 nil nil nil nil)
+  \n: (0 nil 201 nil nil nil 0 nil nil nil nil)
+Line:12:     x = x'';
+    : (0 nil 201 nil nil nil 0 nil nil nil nil)
+    : (0 nil 201 nil nil nil 0 nil nil nil nil)
+    : (0 nil 201 nil nil nil 0 nil nil nil nil)
+    : (0 nil 201 nil nil nil 0 nil nil nil nil)
+   x: (0 nil 201 nil nil nil 0 nil nil nil nil)
+    : (0 nil 209 nil nil nil 0 nil nil nil nil)
+   =: (0 nil 209 nil nil nil 0 nil nil nil nil)
+    : (0 nil 209 nil nil nil 0 nil nil nil nil)
+   x: (0 nil 209 nil nil nil 0 nil nil nil nil)
+   ': (0 nil 213 nil nil nil 0 nil nil nil nil)
+   ': (0 nil 213 nil nil nil 0 nil nil nil nil)
+   ;: (0 nil 213 t nil nil 0 nil 215 nil nil)
+  \n: (0 nil 213 t nil nil 0 nil 215 nil nil)
+Line:13:     y = x(2, 2);
+    : (0 nil 215 nil nil nil 0 nil nil nil nil)
+    : (0 nil 215 nil nil nil 0 nil nil nil nil)
+    : (0 nil 215 nil nil nil 0 nil nil nil nil)
+    : (0 nil 215 nil nil nil 0 nil nil nil nil)
+   y: (0 nil 215 nil nil nil 0 nil nil nil nil)
+    : (0 nil 222 nil nil nil 0 nil nil nil nil)
+   =: (0 nil 222 nil nil nil 0 nil nil nil nil)
+    : (0 nil 222 nil nil nil 0 nil nil nil nil)
+   x: (0 nil 222 nil nil nil 0 nil nil nil nil)
+   (: (0 nil 226 nil nil nil 0 nil nil nil nil)
+   2: (1 227 nil nil nil nil 0 nil nil (227) nil)
+   ,: (1 227 228 nil nil nil 0 nil nil (227) nil)
+    : (1 227 228 nil nil nil 0 nil nil (227) nil)
+   2: (1 227 228 nil nil nil 0 nil nil (227) nil)
+   ): (1 227 231 nil nil nil 0 nil nil (227) nil)
+   ;: (0 nil 227 nil nil nil 0 nil nil nil nil)
+  \n: (0 nil 227 nil nil nil 0 nil nil nil nil)
+Line:14: end
+   e: (0 nil 227 nil nil nil 0 nil nil nil nil)
+   n: (0 nil 235 nil nil nil 0 nil nil nil nil)
+   d: (0 nil 235 nil nil nil 0 nil nil nil nil)
+  \n: (0 nil 235 nil nil nil 0 nil nil nil nil)
diff --git a/tests/test-matlab-ts-mode-syntax-table.el 
b/tests/test-matlab-ts-mode-syntax-table.el
new file mode 100644
index 0000000000..4832d1e4a2
--- /dev/null
+++ b/tests/test-matlab-ts-mode-syntax-table.el
@@ -0,0 +1,114 @@
+;;; test-matlab-ts-mode-syntax-table.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 of the
+;; License, 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 this program.  If not, see http://www.gnu.org/licenses/.
+
+;;; Commentary:
+;;
+;; Validate matlab-ts-mode syntax faces.
+;; Load ../matlab-ts-mode.el via require and run syntax table tests using
+;; ./test-matlab-ts-mode-syntax-table-files/NAME.m comparing against
+;; ./test-matlab-ts-mode-syntax-table-files/NAME_expected.txt
+;;
+
+;;; Code:
+
+(require 'cl-macs)
+
+;; Add abs-path of ".." to load-path so we can (require 'matlab-ts-mode)
+(let* ((lf (or load-file-name (buffer-file-name (current-buffer))))
+       (d1 (file-name-directory lf))
+       (parent-dir (expand-file-name (file-name-directory (directory-file-name 
d1)))))
+  (add-to-list 'load-path parent-dir t))
+
+(require 'matlab-ts-mode)
+
+(defun test-matlab-ts-mode-syntax-table-files ()
+  "Return list of full paths to each 
test-matlab-ts-mode-syntax-table-files/*.m."
+  (directory-files "test-matlab-ts-mode-syntax-table-files" t "\\.m$"))
+
+(defvar test-matlab-ts-mode-syntax-table
+  (cons "test-matlab-ts-mode-syntax-table" 
(test-matlab-ts-mode-syntax-table-files)))
+
+(cl-defun test-matlab-ts-mode-syntax-table (&optional m-file)
+  "Test syntax-table using ./test-matlab-ts-mode-syntax-table-files/NAME.m.
+Compare ./test-matlab-ts-mode-syntax-table-files/NAME.m against
+./test-matlab-ts-mode-syntax-table-files/NAME_expected.txt, where
+NAME_expected.txt gives the `syntax-ppss` value of each character in NAME.m
+
+If M-FILE NAME.m is not provided, loop comparing all
+./test-matlab-ts-mode-syntax-table-files/NAME.m files.
+
+For debugging, you can run with a specified NAME.m,
+  M-: (test-matlab-ts-mode-syntax-table 
\"test-matlab-ts-mode-syntax-table-files/NAME.m\")"
+
+  (when (or (< emacs-major-version 30)
+            (not (progn
+                   (require 'treesit)
+                   (when (fboundp 'treesit-ready-p)
+                     (treesit-ready-p 'matlab t)))))
+    (message "skipping-test: test-matlab-ts-mode-syntax-table.el - tree sitter 
not available.")
+    (cl-return-from test-matlab-ts-mode-syntax-table))
+
+  (let ((m-files (if m-file
+                     (progn
+                       (setq m-file (file-truename m-file))
+                       (when (not (file-exists-p m-file))
+                         (error "File %s does not exist" m-file))
+                       (list m-file))
+                   (test-matlab-ts-mode-syntax-table-files))))
+    (dolist (m-file m-files)
+      (save-excursion
+        (message "START: test-matlab-ts-mode-syntax-table %s" m-file)
+
+        (find-file m-file)
+        (goto-char (point-min))
+
+        (let* ((got "")
+               (expected-file (replace-regexp-in-string "\\.m$" 
"_expected.txt" m-file))
+               (got-file (concat expected-file "~"))
+               (expected (when (file-exists-p expected-file)
+                           (with-temp-buffer
+                             (insert-file-contents-literally expected-file)
+                             (buffer-string)))))
+          (while (not (eobp))
+            (when (looking-at "^")
+              (setq got (concat got (format "Line:%d: %s\n"
+                                            (line-number-at-pos)
+                                            (buffer-substring-no-properties 
(point)
+                                                                            
(line-end-position))))))
+            
+            (let ((char (buffer-substring-no-properties (point) (1+ (point)))))
+              (when (string= char "\n")
+                (setq char "\\n"))
+              (setq got (concat got (format "  %2s: %S\n" char (syntax-ppss 
(point))))))
+
+            (forward-char))
+
+          (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"
+                     m-file got-file expected-file))
+            (error "Baseline for %s does not match, got: %s, expected: %s"
+                   m-file got-file expected-file))
+          (kill-buffer)))
+      (message "PASS: test-matlab-ts-mode-syntax-table %s" m-file)))
+  "success")
+
+(provide 'test-matlab-ts-mode-syntax-table)
+;;; test-matlab-ts-mode-syntax-table.el ends here


Reply via email to