branch: externals/matlab-mode
commit a716c2684a53e6e3c7e82b8ec798938a109a3bfd
Author: John Ciolfi <[email protected]>
Commit: John Ciolfi <[email protected]>
matlab-ts-mode: indent continued fcn-call in fcn-call
---
matlab-ts-mode.el | 58 +++++++++++----
.../indent_fcn_call_in_fcn_call_rules.m | 82 ++++++++++++++++++++++
.../indent_fcn_call_in_fcn_call_rules_expected.m | 82 ++++++++++++++++++++++
...dent_fcn_call_in_fcn_call_rules_expected_msgs.m | 82 ++++++++++++++++++++++
4 files changed, 292 insertions(+), 12 deletions(-)
diff --git a/matlab-ts-mode.el b/matlab-ts-mode.el
index 86a6865c47..114d2a09f2 100644
--- a/matlab-ts-mode.el
+++ b/matlab-ts-mode.el
@@ -1643,7 +1643,7 @@ incomplete statements where NODE is nil and PARENT is
line_continuation."
(cdr matlab-ts-mode--i-cont-incomplete-matcher-pair))
(defun matlab-ts-mode--is-next-line-fcn-args-anchor-node (anchor-node)
- "Is ANCHOR-NODE for a \"fcn(\ ...?"
+ "Is ANCHOR-NODE for a \"fcn(\ ...\", if so return new anchor node."
(when (string= (treesit-node-type anchor-node) "(")
(save-excursion
(goto-char (treesit-node-start anchor-node))
@@ -1653,8 +1653,40 @@ incomplete statements where NODE is nil and PARENT is
line_continuation."
(equal (treesit-node-type (treesit-node-at (point)))
"line_continuation")
(goto-char (treesit-node-start anchor-node))
(> (point) 1)
- (goto-char (1- (point)))
- (looking-at "[.a-z0-9_]" t)))))
+
+ (goto-char (1- (point))) ;; just before the "("
+ (progn ;; skip back to first non-whitespace char before the "("
+ (when (looking-at "[ \t]")
+ (re-search-backward "[^ \t\r\n]" nil t))
+ t)
+ ;; is "fcn(" or "fcn ("?
+ ;; ^ ^
+ (looking-at "[a-z0-9_]" t)
+
+ ;; Found something that looks like a function-call, e.g. "id("
+ ;; Return id-node if it's a fcn-call in a fcn-call.
+ (or (let ((id-node (treesit-node-at (point))))
+
+ (goto-char (treesit-node-start id-node))
+
+ ;; Move over field expression,
other1.other2.fcn1(foo.bar.fcn2(
+ (when (> (current-column) 0)
+ (goto-char (1- (point)))
+ (while (and (> (current-column) 0)
+ (looking-at "\\." t))
+ (goto-char (1- (point)))
+ (when (looking-at "[a-z0-9_]" t)
+ (setq id-node (treesit-node-at (point)))
+ (goto-char (treesit-node-start id-node))
+ (when (> (current-column) 0)
+ (goto-char (1- (point)))))))
+
+ (when (looking-at "[ \t]")
+ (re-search-backward "[^ \t\r\n]" nil t))
+ (when (looking-at "(")
+ id-node))
+ (treesit-node-parent anchor-node))
+ ))))
(defvar matlab-ts-mode--i-next-line-pair)
@@ -1686,12 +1718,13 @@ Sets `matlab-ts-mode--i-next-line-pair' to (ANCHOR-NODE
. OFFSET)"
(< (treesit-node-start anchor-last-child)
(treesit-node-start node))))
(setq anchor-node anchor-last-child)))
- (when (matlab-ts-mode--is-next-line-fcn-args-anchor-node anchor-node)
- ;; Case: var_b = my_function( ...
- ;; ^ <== RET/TAB to here
- ;; See: tests/test-matlab-ts-mode-indent-xr-files/indent_xr_fun_call1.m
- (setq anchor-node (treesit-node-parent anchor-node)
- last-child-of-error-node nil))
+ (let ((updated-anchor-node
(matlab-ts-mode--is-next-line-fcn-args-anchor-node anchor-node)))
+ (when updated-anchor-node
+ ;; Case: var_b = my_function( ...
+ ;; ^ <== RET/TAB to here
+ ;; See: tests/test-matlab-ts-mode-indent-xr-files/indent_xr_fun_call1.m
+ (setq anchor-node updated-anchor-node
+ last-child-of-error-node nil)))
(let ((indent-level
(if (and node (string= (treesit-node-type node) "end"))
@@ -1974,9 +2007,10 @@ For LAST-CHILD-OF-ERROR-NODE and NODE-TO-CHECK see
((string= prev-sibling-type ")")
(setq close-paren-count (1+ close-paren-count)))
- ((and (string= prev-sibling-type "(")
- (> close-paren-count 0))
- (setq close-paren-count (1- close-paren-count)) 0)
+ ((string= prev-sibling-type "(")
+ (if (> close-paren-count 0)
+ (setq close-paren-count (1- close-paren-count))
+ (setq prev-sibling-to-check prev-sibling)))
((and (string-match-p matlab-ts-mode--i-next-line-anchors-rx
prev-sibling-type)
(or (not (string= prev-sibling-type "("))
diff --git
a/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules.m
b/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules.m
new file mode 100644
index 0000000000..eaf95e255a
--- /dev/null
+++ b/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules.m
@@ -0,0 +1,82 @@
+% -*- matlab-ts -*-
+
+% Here MATLAB indent "SomeLongString" to be 4 from the '(' in "someFunction1("
+% This differs from clang-format on C code where it will produce:
+% something.foo = someFunction1(someFunction2(
+% "SomeLongString"));
+%
+something.foo = someFunction1(someFunction2( ...
+ "SomeLongString"));
+
+% Here MATLAB indents similar to the prior.
+% clang-format C also indents this way:
+% something.foo = someFunction1(someFunction2(
+% "SomeLongString"),
+% arg2,
+% arg3);
+%
+something.foo = someFunction1(someFunction2( ...
+ "SomeLongString"), ...
+ arg2, ...
+ arg3);
+
+% Here MATLAB indents similar to the prior.
+% This differs from clang-format on C code where it will produce:
+% something.foo = someFunction1(someFunction2(
+% "SomeLongString",
+% arg2,
+% arg3));
+something.foo = someFunction1(someFunction2( ...
+ "SomeLongString", ...
+ arg2, ...
+ arg3));
+
+% *** Conclusion ***
+% For consistency, MATLAB is correct. Adding an argument to a function
shouldn't cause
+% indent differences. This is likely a miss on clang-format indent rules
part.
+
+
+% --- Test unnecessary spaces ---
+
+something.foo = someFunction1 (someFunction2 ( ...
+ "SomeLongString"));
+
+something.foo = someFunction1 (someFunction2 ( ...
+ "SomeLongString"), ...
+ arg2, ...
+ arg3);
+
+something.foo = someFunction1 (someFunction2 ( ...
+ "SomeLongString", ...
+ arg2, ...
+ arg3));
+
+% --- Test namespaces ---
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ...
+ "SomeLongString"));
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ...
+ "SomeLongString"), ...
+ arg2, ...
+ arg3);
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ...
+ "SomeLongString", ...
+ arg2, ...
+ arg3));
+
+% --- Test namespaces with unnecessary spaces
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
+ "SomeLongString"));
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
+ "SomeLongString"), ...
+ arg2, ...
+ arg3);
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
+ "SomeLongString", ...
+ arg2, ...
+ arg3));
diff --git
a/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules_expected.m
b/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules_expected.m
new file mode 100644
index 0000000000..eaf95e255a
--- /dev/null
+++
b/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules_expected.m
@@ -0,0 +1,82 @@
+% -*- matlab-ts -*-
+
+% Here MATLAB indent "SomeLongString" to be 4 from the '(' in "someFunction1("
+% This differs from clang-format on C code where it will produce:
+% something.foo = someFunction1(someFunction2(
+% "SomeLongString"));
+%
+something.foo = someFunction1(someFunction2( ...
+ "SomeLongString"));
+
+% Here MATLAB indents similar to the prior.
+% clang-format C also indents this way:
+% something.foo = someFunction1(someFunction2(
+% "SomeLongString"),
+% arg2,
+% arg3);
+%
+something.foo = someFunction1(someFunction2( ...
+ "SomeLongString"), ...
+ arg2, ...
+ arg3);
+
+% Here MATLAB indents similar to the prior.
+% This differs from clang-format on C code where it will produce:
+% something.foo = someFunction1(someFunction2(
+% "SomeLongString",
+% arg2,
+% arg3));
+something.foo = someFunction1(someFunction2( ...
+ "SomeLongString", ...
+ arg2, ...
+ arg3));
+
+% *** Conclusion ***
+% For consistency, MATLAB is correct. Adding an argument to a function
shouldn't cause
+% indent differences. This is likely a miss on clang-format indent rules
part.
+
+
+% --- Test unnecessary spaces ---
+
+something.foo = someFunction1 (someFunction2 ( ...
+ "SomeLongString"));
+
+something.foo = someFunction1 (someFunction2 ( ...
+ "SomeLongString"), ...
+ arg2, ...
+ arg3);
+
+something.foo = someFunction1 (someFunction2 ( ...
+ "SomeLongString", ...
+ arg2, ...
+ arg3));
+
+% --- Test namespaces ---
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ...
+ "SomeLongString"));
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ...
+ "SomeLongString"), ...
+ arg2, ...
+ arg3);
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ...
+ "SomeLongString", ...
+ arg2, ...
+ arg3));
+
+% --- Test namespaces with unnecessary spaces
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
+ "SomeLongString"));
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
+ "SomeLongString"), ...
+ arg2, ...
+ arg3);
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
+ "SomeLongString", ...
+ arg2, ...
+ arg3));
diff --git
a/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules_expected_msgs.m
b/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules_expected_msgs.m
new file mode 100644
index 0000000000..11f8e6b98a
--- /dev/null
+++
b/tests/test-matlab-ts-mode-indent-files/indent_fcn_call_in_fcn_call_rules_expected_msgs.m
@@ -0,0 +1,82 @@
+% -*- matlab-ts -*- % <{Matched rule: ((lambda (node parent _bol &rest _)
(and node (not (string= (treesit-node-type node) "line_continuation")) (equal
(treesit-node-type parent) "source_file"))) (lambda (_node _parent bol &rest _)
(save-excursion (goto-char bol) (line-beginning-position))) 0)}>
+
+% Here MATLAB indent "SomeLongString" to be 4 from the '(' in "someFunction1("
% <{Matched rule: ((lambda (node parent _bol &rest _) (and node (not (string=
(treesit-node-type node) "line_continuation")) (equal (treesit-node-type
parent) "source_file"))) (lambda (_node _parent bol &rest _) (save-excursion
(goto-char bol) (line-beginning-position))) 0)}>
+% This differs from clang-format on C code where it will produce: % <{Matched
rule: (matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% something.foo = someFunction1(someFunction2( % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% "SomeLongString")); % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% % <{Matched rule: (matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+something.foo = someFunction1(someFunction2( ... % <{Matched rule: ((lambda
(node parent _bol &rest _) (and node (not (string= (treesit-node-type node)
"line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+ "SomeLongString")); % <{Matched rule:
((node-is "\\`arguments\\'") parent 4)}>
+
+% Here MATLAB indents similar to the prior. % <{Matched rule: ((lambda (node
parent _bol &rest _) (and node (not (string= (treesit-node-type node)
"line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+% clang-format C also indents this way: % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% something.foo = someFunction1(someFunction2( % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% "SomeLongString"), % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% arg2, % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% arg3); % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% % <{Matched rule: (matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+something.foo = someFunction1(someFunction2( ... % <{Matched rule: ((lambda
(node parent _bol &rest _) (and node (not (string= (treesit-node-type node)
"line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+ "SomeLongString"), ... % <{Matched rule:
((node-is "\\`arguments\\'") parent 4)}>
+ arg2, ... % <{Matched rule: ((parent-is
"\\`arguments\\'") parent 0)}>
+ arg3); % <{Matched rule: ((parent-is
"\\`arguments\\'") parent 0)}>
+
+% Here MATLAB indents similar to the prior. % <{Matched rule: ((lambda (node
parent _bol &rest _) (and node (not (string= (treesit-node-type node)
"line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+% This differs from clang-format on C code where it will produce: % <{Matched
rule: (matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% something.foo = someFunction1(someFunction2( % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% "SomeLongString", % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+% arg2, % <{Matched rule: (matlab-ts-mode--i-block-comment-end-matcher
parent 0)}>
+% arg3)); % <{Matched rule:
(matlab-ts-mode--i-block-comment-end-matcher parent 0)}>
+something.foo = someFunction1(someFunction2( ... % <{Matched rule: ((lambda
(node parent _bol &rest _) (and node (not (string= (treesit-node-type node)
"line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+ "SomeLongString", ... % <{Matched rule:
((node-is "\\`arguments\\'") parent 4)}>
+ arg2, ... % <{Matched rule: ((parent-is
"\\`arguments\\'") parent 0)}>
+ arg3)); % <{Matched rule: ((parent-is
"\\`arguments\\'") parent 0)}>
+
+% *** Conclusion *** % <{Matched rule: ((lambda (node parent _bol &rest _)
(and node (not (string= (treesit-node-type node) "line_continuation")) (equal
(treesit-node-type parent) "source_file"))) (lambda (_node _parent bol &rest _)
(save-excursion (goto-char bol) (line-beginning-position))) 0)}>
+% For consistency, MATLAB is correct. Adding an argument to a function
shouldn't cause % <{Matched rule: (matlab-ts-mode--i-block-comment-end-matcher
parent 0)}>
+% indent differences. This is likely a miss on clang-format indent rules
part. % <{Matched rule: (matlab-ts-mode--i-block-comment-end-matcher parent
0)}>
+
+
+% --- Test unnecessary spaces --- % <{Matched rule: ((lambda (node parent
_bol &rest _) (and node (not (string= (treesit-node-type node)
"line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+
+something.foo = someFunction1 (someFunction2 ( ... % <{Matched rule:
((lambda (node parent _bol &rest _) (and node (not (string= (treesit-node-type
node) "line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+ "SomeLongString")); % <{Matched rule:
((node-is "\\`arguments\\'") parent 4)}>
+
+something.foo = someFunction1 (someFunction2 ( ... % <{Matched rule:
((lambda (node parent _bol &rest _) (and node (not (string= (treesit-node-type
node) "line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+ "SomeLongString"), ... % <{Matched rule:
((node-is "\\`arguments\\'") parent 4)}>
+ arg2, ... % <{Matched rule: ((parent-is
"\\`arguments\\'") parent 0)}>
+ arg3); % <{Matched rule: ((parent-is
"\\`arguments\\'") parent 0)}>
+
+something.foo = someFunction1 (someFunction2 ( ... % <{Matched rule:
((lambda (node parent _bol &rest _) (and node (not (string= (treesit-node-type
node) "line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+ "SomeLongString", ... % <{Matched rule:
((node-is "\\`arguments\\'") parent 4)}>
+ arg2, ... % <{Matched rule: ((parent-is
"\\`arguments\\'") parent 0)}>
+ arg3)); % <{Matched rule: ((parent-is
"\\`arguments\\'") parent 0)}>
+
+% --- Test namespaces --- % <{Matched rule: ((lambda (node parent _bol &rest
_) (and node (not (string= (treesit-node-type node) "line_continuation"))
(equal (treesit-node-type parent) "source_file"))) (lambda (_node _parent bol
&rest _) (save-excursion (goto-char bol) (line-beginning-position))) 0)}>
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ... %
<{Matched rule: ((lambda (node parent _bol &rest _) (and node (not (string=
(treesit-node-type node) "line_continuation")) (equal (treesit-node-type
parent) "source_file"))) (lambda (_node _parent bol &rest _) (save-excursion
(goto-char bol) (line-beginning-position))) 0)}>
+ "SomeLongString")); %
<{Matched rule: ((n-p-gp "\\`arguments\\'" "\\`function_call\\'"
"\\`field_expression\\'") grand-parent 4)}>
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ... %
<{Matched rule: ((lambda (node parent _bol &rest _) (and node (not (string=
(treesit-node-type node) "line_continuation")) (equal (treesit-node-type
parent) "source_file"))) (lambda (_node _parent bol &rest _) (save-excursion
(goto-char bol) (line-beginning-position))) 0)}>
+ "SomeLongString"), ... %
<{Matched rule: ((n-p-gp "\\`arguments\\'" "\\`function_call\\'"
"\\`field_expression\\'") grand-parent 4)}>
+ arg2, ... % <{Matched rule:
((parent-is "\\`arguments\\'") parent 0)}>
+ arg3); % <{Matched rule:
((parent-is "\\`arguments\\'") parent 0)}>
+
+something.foo = fooNamespace.someFunction1(fooNamespace.someFunction2( ... %
<{Matched rule: ((lambda (node parent _bol &rest _) (and node (not (string=
(treesit-node-type node) "line_continuation")) (equal (treesit-node-type
parent) "source_file"))) (lambda (_node _parent bol &rest _) (save-excursion
(goto-char bol) (line-beginning-position))) 0)}>
+ "SomeLongString", ... %
<{Matched rule: ((n-p-gp "\\`arguments\\'" "\\`function_call\\'"
"\\`field_expression\\'") grand-parent 4)}>
+ arg2, ... % <{Matched rule:
((parent-is "\\`arguments\\'") parent 0)}>
+ arg3)); % <{Matched rule:
((parent-is "\\`arguments\\'") parent 0)}>
+
+% --- Test namespaces with unnecessary spaces % <{Matched rule: ((lambda
(node parent _bol &rest _) (and node (not (string= (treesit-node-type node)
"line_continuation")) (equal (treesit-node-type parent) "source_file")))
(lambda (_node _parent bol &rest _) (save-excursion (goto-char bol)
(line-beginning-position))) 0)}>
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
% <{Matched rule: ((lambda (node parent _bol &rest _) (and node (not (string=
(treesit-node-type node) "line_continuation")) (equal (treesit-node-type
parent) "source_file"))) (lambda (_node _parent bol &rest _) (save-excursion
(goto-char bol) (line-beginning-position))) 0)}>
+ "SomeLongString")); %
<{Matched rule: ((n-p-gp "\\`arguments\\'" "\\`function_call\\'"
"\\`field_expression\\'") grand-parent 4)}>
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
% <{Matched rule: ((lambda (node parent _bol &rest _) (and node (not (string=
(treesit-node-type node) "line_continuation")) (equal (treesit-node-type
parent) "source_file"))) (lambda (_node _parent bol &rest _) (save-excursion
(goto-char bol) (line-beginning-position))) 0)}>
+ "SomeLongString"), ... %
<{Matched rule: ((n-p-gp "\\`arguments\\'" "\\`function_call\\'"
"\\`field_expression\\'") grand-parent 4)}>
+ arg2, ... % <{Matched rule:
((parent-is "\\`arguments\\'") parent 0)}>
+ arg3); % <{Matched rule:
((parent-is "\\`arguments\\'") parent 0)}>
+
+something.foo = fooNamespace.someFunction1 (fooNamespace.someFunction2 ( ...
% <{Matched rule: ((lambda (node parent _bol &rest _) (and node (not (string=
(treesit-node-type node) "line_continuation")) (equal (treesit-node-type
parent) "source_file"))) (lambda (_node _parent bol &rest _) (save-excursion
(goto-char bol) (line-beginning-position))) 0)}>
+ "SomeLongString", ... %
<{Matched rule: ((n-p-gp "\\`arguments\\'" "\\`function_call\\'"
"\\`field_expression\\'") grand-parent 4)}>
+ arg2, ... % <{Matched rule:
((parent-is "\\`arguments\\'") parent 0)}>
+ arg3)); % <{Matched rule:
((parent-is "\\`arguments\\'") parent 0)}>