branch: externals/matlab-mode
commit 8c8fbd05c98ab3f7511f70e942ff19f7ec5fbbcf
Author: John Ciolfi <[email protected]>
Commit: John Ciolfi <[email protected]>
matlab-ts-mode.el: indent level for end-less functions is 0
---
contributing/treesit-mode-how-to.org | 40 ++++++++++++
matlab-ts-mode.el | 75 ++++++++++++++++++++--
.../indent_end_less_function.m | 15 +++++
.../indent_end_less_function_expected.m | 15 +++++
4 files changed, 140 insertions(+), 5 deletions(-)
diff --git a/contributing/treesit-mode-how-to.org
b/contributing/treesit-mode-how-to.org
index 64cf9c125c..9800eef50a 100644
--- a/contributing/treesit-mode-how-to.org
+++ b/contributing/treesit-mode-how-to.org
@@ -223,6 +223,8 @@ You should now be able to use:
* Font-lock
+TODO - add FIXME, XXX, and TODO marker coloring.
+
Queries are needed to identify syntax tree nodes to semantically color
language elements
(font-lock). 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.
@@ -1593,3 +1595,41 @@ well worth writing a tree-sitter mode.
TODO verify
+* new matlab-ts-mode
+
+ 1. Improved font-lock (semantic coloring) performance, making editing even
more smooth.
+
+ 2. More accurate fontification, we now identify language elements accurately
and use
+ more faces to color them.
+
+ 3. Fixes edge-case fontification issues when compared with matlab-mode
+
+ Create issue for this:
+ #+begin_src matlab-ts
+ x = [1 2; 3 4];
+ y = x'' % this is valid double transpose where
matlab-mode gets it wrong
+ #+end_src
+
+ Function identification, see
https://github.com/mathworks/Emacs-MATLAB-Mode/issues/48
+
+ 4. In comments, we now highlight =FIXME=, =TODO=, and =XXX= markers.
+
+ 5. Simplifies the semantics for indent. The indent rules are:
+
+ - TODO
+
+ 6. Improved indent performance, making editing even more smooth.
+
+ 7. Fixes various edge-case indent issues, some are
+
+ - Auto-indentation of end, see
https://github.com/mathworks/Emacs-MATLAB-Mode/issues/33
+
+ 8. There's no longer prompting if you want functions to have end's. This is
now computed
+ automatically
+
+ 9. Improved fill-paragraph, M-q, which will now fill comments and when not
in a comment, indent
+ the current function or statement.
+
+ 10. Accurate type of m-file detection, which improves
matlab-sections-minor-mode.
+
+ TODO
diff --git a/matlab-ts-mode.el b/matlab-ts-mode.el
index dd697b8adc..44c1b98d6e 100644
--- a/matlab-ts-mode.el
+++ b/matlab-ts-mode.el
@@ -347,6 +347,8 @@ START and END specify the region to be fontified."
(goto-char start)
(let ((case-fold-search nil))
(while (< (point) end)
+ ;; Note, the markers below have spaces in them so we don't find them
when typing C-s
+ ;; while editing this file.
(if (re-search-forward (rx word-start (group (or (seq "FIX" "ME")
(seq "X" "XX")
(seq "TO" "DO")))
@@ -481,6 +483,63 @@ START and END specify the region to be fontified."
(defvar matlab-ts-mode--array-indent-level 2
"Indentation level for elements in an array.")
+;; `matlab-ts-mode--function-indent-level'
+;;
+;; It is recommended that all function statemements have terminating end
statements. In some cases
+;; for compatibilty MATLAB doesn't require a function end statement. When
functions do not have an
+;; end, we don't indent the body of the function per older MATLAB coding
standard. Example:
+;;
+;; function a = fcn1 | function a = fcn2
+;; a = 1; | a = 1;
+;; | end
+;;
+;; If a *.m file contains functions, and one of the functions is terminated
with end, then every
+;; function in the file must be terminated with end. If a *.m file contains a
function with one or
+;; more nested functions, then every function in the file must be terminated
with end. If a script
+;; contains one or more local functions, then every function in the file must
be terminated with
+;; end.
+;;
+;; When we enter `matlab-ts-mode', we examine the content and set the state of
this variable. If
+;; matlab-ts--function-indent-level is nil, while editing, if functions become
terminated with
+;; ends, we set this to t. We never go from t to nil because it's easy to get
in a temporary nil
+;; state during edits and we don't want to cause unexpected indentation
behavior.")
+
+(defvar-local matlab-ts-mode--function-indent-level 'unset
+ "Function indent level is 0 or `matlab-ts-mode--indent-level'.")
+
+(defun matlab-ts-mode--set-function-indent-level (&optional _node parent _bol
&rest _)
+ "Setup the function indent level for end vs end-less functions.
+For optional _NODE, PARENT, and _BOL see `treesit-simple-indent-rules'."
+
+ ;; - When matlab-ts-mode--function-indent-level is 'unset we set this to
+ ;; 0 or matlab-ts-mode--indent-level
+ ;; based on the buffer content.
+ ;; - Otherwise, matlab-ts-mode--function-indent-level is 0, we will
"upgrade" it to
+ ;; matlab-ts-mode--indent-level if function end's appear.
+
+ (let ((root (if (and parent (string= (treesit-node-type parent)
"function_definition"))
+ parent
+ (treesit-buffer-root-node))))
+ (if (treesit-search-subtree (treesit-buffer-root-node) "^ERROR$")
+ ;; If we have syntax errors, assume that functions will have ends when
entering
+ ;; matlab-ts-mode, otherwise leave matlab-ts--function-indent-level
unchanged.
+ (when (equal matlab-ts-mode--function-indent-level 'unset)
+ (setq-local matlab-ts-mode--function-indent-level
matlab-ts-mode--indent-level))
+ (let ((first-fcn (treesit-search-subtree root (rx bol
"function_definition" eol))))
+ (if (not first-fcn)
+ ;; assume that if functions are added they will have ends
+ (setq-local matlab-ts--function-indent-level t)
+ (let ((have-end (string= (treesit-node-type (treesit-node-child
first-fcn -1)) "end")))
+ (if (equal matlab-ts-mode--function-indent-level 'unset)
+ (setq-local matlab-ts-mode--function-indent-level
+ (if have-end
+ matlab-ts-mode--indent-level
+ 0))
+ (when have-end
+ (setq-local matlab-ts-mode--function-indent-level
matlab-ts-mode--indent-level))
+ ))))))
+ matlab-ts-mode--function-indent-level)
+
(defun matlab-ts-mode--prev-real-line (_n _p bol &rest _)
"Return point of first non-whitespace looking backward.
BOL, beginning-of-line point, is where to start from."
@@ -584,20 +643,25 @@ expression."
parent ,matlab-ts-mode--switch-indent-level)
;; I-Rule: nested functions
- ((n-p-gp ,(rx bol "function_definition" eol) ,(rx bol "block" eol)
+ ((n-p-gp ,(rx bol "function_definition" eol)
+ ,(rx bol "block" eol)
,(rx bol "function_definition" eol))
parent 0)
+ ;; 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)
+
+ ;; I-Rule: function's
+ ((parent-is ,(rx bol "function_definition" eol))
+ parent ,#'matlab-ts-mode--set-function-indent-level)
+
;; 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)
- ;; 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)
-
- ;; I-Rule: code in if, for, methods, function, arguments statements
+ ;; I-Rule: code in if, for, methods, arguments statements, etc.
((parent-is ,(rx bol (or "if_statement" "for_statement" "while_statement"
"methods" "events" "enumeration"
"function_definition" "arguments_statement")
@@ -777,6 +841,7 @@ expression."
(syntax-error)))
;; Indent. See: ./tests/test-matlab-ts-mode-indent.el
+ (matlab-ts-mode--set-function-indent-level)
(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?
diff --git a/tests/test-matlab-ts-mode-indent-files/indent_end_less_function.m
b/tests/test-matlab-ts-mode-indent-files/indent_end_less_function.m
new file mode 100644
index 0000000000..998c8de80a
--- /dev/null
+++ b/tests/test-matlab-ts-mode-indent-files/indent_end_less_function.m
@@ -0,0 +1,15 @@
+% -*- matlab-ts -*-
+function indent_end_less_function(a)
+% function without a terminating end
+
+ x = {'a', 'c()' 'b'};
+ if a
+ disp('foo');
+ else
+disp('bar');
+end
+
+indent_end_less_function2
+
+function indent_end_less_function2
+ disp('in indent_end_less_function2')
diff --git
a/tests/test-matlab-ts-mode-indent-files/indent_end_less_function_expected.m
b/tests/test-matlab-ts-mode-indent-files/indent_end_less_function_expected.m
new file mode 100644
index 0000000000..8720fec481
--- /dev/null
+++ b/tests/test-matlab-ts-mode-indent-files/indent_end_less_function_expected.m
@@ -0,0 +1,15 @@
+% -*- matlab-ts -*-
+function indent_end_less_function(a)
+% function without a terminating end
+
+x = {'a', 'c()' 'b'};
+if a
+ disp('foo');
+else
+ disp('bar');
+end
+
+indent_end_less_function2
+
+function indent_end_less_function2
+disp('in indent_end_less_function2')