branch: externals/matlab-mode
commit 2fbbc079316b49180df13984401201ace1a319a3
Author: John Ciolfi <[email protected]>
Commit: John Ciolfi <[email protected]>
matlab-shell: make it work with matlab-ts-mode or matlab-mode
---
contributing/treesit-mode-how-to.org | 5 +
matlab--shell-bridge.el | 79 +++++++
matlab--shell-map.el | 20 ++
matlab-complete.el | 1 +
matlab-shell.el | 107 ++++------
matlab-topic.el | 3 +-
matlab-ts-mode.el | 220 ++++++++++++-------
matlab.el | 69 ++----
.../movement_statements.m | 22 ++
.../movement_statements_expected.org | 235 +++++++++++++++++++++
tests/test-matlab-ts-mode-movement.el | 69 ++++++
11 files changed, 638 insertions(+), 192 deletions(-)
diff --git a/contributing/treesit-mode-how-to.org
b/contributing/treesit-mode-how-to.org
index 1793a302c3..3750b7cab7 100644
--- a/contributing/treesit-mode-how-to.org
+++ b/contributing/treesit-mode-how-to.org
@@ -2038,6 +2038,11 @@ Install, using default branch
TODO - show how to do in lsp-mode and update lsp-mode org on this.
+ 14. matlab-shell now has one correct ways of running code sections, via menu
=MATLAB -> Code
+ Sections -> Run Section (C-c C-<return>)= or and the older =MATLAB -> Run
Code Section=
+ (matlab-shell-run-code-section) because it was duplication and wasn't
correctly handling all
+ cases.
+
# LocalWords: showall usepackage parskip tocloft cftsecnumwidth
cftsubsecindent cftsubsecnumwidth
# LocalWords: lang utils Imenu LSP defun ELPA tuils setq SLIB libtree dylib
sexp xr defcusom
# LocalWords: defface EDebug ielm fontify Fontifying fontified defcustom
alist eos bol NPS prev BUF
diff --git a/matlab--shell-bridge.el b/matlab--shell-bridge.el
new file mode 100644
index 0000000000..f993408c30
--- /dev/null
+++ b/matlab--shell-bridge.el
@@ -0,0 +1,79 @@
+;;; matlab--shell-bridge.el --- -*- lexical-binding: t -*-
+
+;;; Commentary:
+;; Utilities to brdige between the older matlab-mode and matlab-ts-mode
+;;
+
+;;; Code:
+
+
+(defun matlab--is-matlab-ts-mode-active ()
+ "Return t if `matlab-ts-mode' is active.
+Is `matlab-ts-mode' active per
+ (add-to-list \\='major-mode-remap-alist \\='(matlab-mode . matlab-ts-mode))
+If so, require `matlab-ts-mode' else require `matlab-mode'?"
+ (cond
+ ((rassoc 'matlab-ts-mode major-mode-remap-alist)
+ (require 'matlab-ts-mode)
+ t)
+ (t
+ (require 'matlab-mode)
+ nil)))
+
+(defvar matlab-ts-mode--syntax-table)
+(defvar matlab-mode-syntax-table)
+
+(defun matlab--shell-get-syntax-table ()
+ "Get either matlab-ts-mode or matlab-mode syntax table.
+If using `matlab-ts-mode' per
+ (add-to-list \\='major-mode-remap-alist \\='(matlab-mode . matlab-ts-mode))
+use `matlab-ts-mode--syntax-table' else use
+`matlab-mode-syntax-table'. The tables are the same with respect
+to strings and comments."
+ (if (matlab--is-matlab-ts-mode-active)
+ matlab-ts-mode--syntax-table
+ matlab-mode-syntax-table))
+
+(declare-function matlab-scan-beginning-of-command "matlab-mode")
+(declare-function matlab-scan-end-of-command "matlab-mode")
+
+(declare-function matlab-ts-mode-beginning-of-command "matlab-ts-mode")
+(declare-function matlab-ts-mode-end-of-command "matlab-ts-mode")
+
+(defun matlab--get-command-at-point-to-run ()
+ "Based on the major-mode get the MATLAB command to run in `matlab-shell'."
+ (save-excursion
+ (pcase major-mode
+ ('matlab-ts-mode
+ (require 'matlab-ts-mode)
+ (let* ((start-point (save-excursion
+ (matlab-ts-mode-beginning-of-command)))
+ (end-point (when start-point
+ (save-excursion
+ (matlab-ts-mode-end-of-command)))))
+ (if start-point
+ (buffer-substring-no-properties start-point end-point)
+ "")))
+ ('matlab-mode
+ (require 'matlab-mode)
+ (save-excursion
+ (buffer-substring-no-properties
+ (matlab-scan-beginning-of-command)
+ (matlab-scan-end-of-command))))
+ (_
+ (error "This cannot be run in %s" (symbol-name major-mode))))))
+
+(defun matlab--function-called-at-point ()
+ "Return a string representing the function called nearby point."
+ (save-excursion
+ (beginning-of-line)
+ (cond ((looking-at "\\s-*\\([a-zA-Z]\\w+\\)[^=][^=]")
+ (match-string 1))
+ ((and (re-search-forward "=" (line-end-position) t)
+ (looking-at "\\s-*\\([a-zA-Z]\\w+\\)\\s-*[^=]"))
+ (match-string 1))
+ (t nil))))
+
+(provide 'matlab--shell-bridge)
+;;; matlab--shell-bridge.el ends here
+
diff --git a/matlab--shell-map.el b/matlab--shell-map.el
new file mode 100644
index 0000000000..1809500a0b
--- /dev/null
+++ b/matlab--shell-map.el
@@ -0,0 +1,20 @@
+;;; matlab--shell-map.el --- -*- lexical-binding: t -*-
+
+;;; Commentary:
+;; Keymaps used in both matlab-ts-mode and matlab-mode for matlab-shell.
+;;
+
+;;; Code:
+
+(defvar matlab--shell-help-map
+ (let ((km (make-sparse-keymap)))
+ (define-key km "r" 'matlab-shell-run-command)
+ (define-key km "f" 'matlab-shell-describe-command)
+ (define-key km "a" 'matlab-shell-apropos)
+ (define-key km "v" 'matlab-shell-describe-variable)
+ km)
+ "Help key map for `matlab-ts-mode' / `matlab-mode' and `matlab-shell-mode'.")
+
+(provide 'matlab--shell-map)
+;;; matlab--shell-map.el ends here
+
diff --git a/matlab-complete.el b/matlab-complete.el
index 82428ecc96..147e7b09e2 100644
--- a/matlab-complete.el
+++ b/matlab-complete.el
@@ -33,6 +33,7 @@
(require 'cl-macs)
(require 'matlab)
(require 'matlab-shell)
+(require 'matlab--shell-bridge)
(defun matlab-uniquify-list (lst)
"Return a list that is a subset of LST where all elements are unique."
diff --git a/matlab-shell.el b/matlab-shell.el
index 797a860e3d..8129308178 100644
--- a/matlab-shell.el
+++ b/matlab-shell.el
@@ -26,10 +26,17 @@
;;; Code:
-(require 'matlab)
(require 'matlab-compat)
(eval-and-compile
(require 'matlab--access))
+(require 'matlab--shell-bridge)
+(require 'matlab--shell-map)
+
+;; Note this should *NOT*
+;; (require 'matlab) ;; or (require 'matlab-mode)
+;; or
+;; (require 'matlab-ts-mode)
+;; because it is designed to work with both `matlab-mode' and `matlab-ts-mode'
(require 'comint)
(require 'server)
@@ -157,12 +164,18 @@ narrow completions, you may find the responses slow and
if so,
you can try turning this off."
:type 'boolean)
+(defcustom matlab-change-current-directory nil
+ "*If non nil, make file's directory the current directory when evaluating
it."
+ :type 'boolean)
+
+(make-variable-buffer-local 'matlab-change-current-directory)
+
(defvar matlab-shell-tab-company-available (if (locate-library "company") t
nil)
"Non-nil if we have `company' installed.
Use this to override initial check.")
(defvar matlab-shell-errorscanning-syntax-table
- (let ((st (copy-syntax-table matlab-mode-syntax-table)))
+ (let ((st (copy-syntax-table (matlab--shell-get-syntax-table))))
;; Make \n be whitespace when scanning output.
(modify-syntax-entry ?\n " " st)
st)
@@ -188,8 +201,9 @@ If multiple prompts are seen together, only call this
once.")
;;; Font Lock
;;
-;; Extra font lock keywords for the MATLAB shell.
-(defconst matlab-shell-font-lock-keywords
+;; Font lock keywords for the MATLAB shell.
+
+(defconst matlab-shell-error-font-lock-keywords
(list
;; How about Errors?
'("^\\(Error in\\|Syntax error in\\)\\s-+==>\\s-+\\(.+\\)$"
@@ -199,13 +213,7 @@ If multiple prompts are seen together, only call this
once.")
;; User beep things
'("\\(\\?\\?\\?[^\n]+\\)" 1 font-lock-comment-face)
)
- "Additional keywords used by MATLAB when reporting errors in interactive\
-mode.")
-
-(defconst matlab-shell-font-lock-keywords-1
- (append matlab-basic-font-lock-keywords
- matlab-shell-font-lock-keywords)
- "Keyword symbol used for basic font-lock for MATLAB shell.")
+ "The matlab-shell error keywords.")
(defconst matlab-shell-object-output-font-lock-keywords
(list
@@ -240,18 +248,12 @@ mode.")
(1 font-lock-variable-name-face)))
'("[[{]\\([0-9]+\\(?:x[0-9]+\\)+ \\w+\\)[]}]" (1 font-lock-comment-face))
)
- "Highlight various extra outputs that are typical for MATLAB.")
+ "The matlab-shell output related keywords.")
-(defconst matlab-shell-font-lock-keywords-2
- (append matlab-shell-font-lock-keywords-1
- matlab-function-font-lock-keywords
+(defconst matlab-shell-font-lock-keywords
+ (append matlab-shell-error-font-lock-keywords
matlab-shell-object-output-font-lock-keywords)
- "Keyword symbol used for gaudy font-lock for MATLAB shell.")
-
-(defconst matlab-shell-font-lock-keywords-3
- (append matlab-shell-font-lock-keywords-2
- matlab-really-gaudy-font-lock-keywords)
- "Keyword symbol used for really gaudy font-lock for MATLAB shell.")
+ "The matlab-shell keywords.")
;;; Keymaps & Menus
@@ -271,7 +273,7 @@ mode.")
(define-key km [(control c) (control c)] #'matlab-shell-interrupt-subjob)
;; Help system
- (define-key km [(control h) (control m)] matlab-help-map)
+ (define-key km [(control h) (control m)] matlab--shell-help-map)
;; Completion
(define-key km (kbd "TAB") #'matlab-shell-tab)
@@ -382,18 +384,16 @@ in a popup buffer.
(if (fboundp 'comint-read-input-ring)
(comint-read-input-ring t))
- ;;; MODE Settings
- (make-local-variable 'comment-start)
- (setq comment-start "%")
+ (setq-local comment-start "%")
(use-local-map matlab-shell-mode-map)
- (set-syntax-table matlab-mode-syntax-table)
+ (set-syntax-table (matlab--shell-get-syntax-table))
- (make-local-variable 'font-lock-defaults)
- (setq font-lock-defaults '((matlab-shell-font-lock-keywords-1
- matlab-shell-font-lock-keywords-2
- matlab-shell-font-lock-keywords-3)
- t nil ((?_ . "w"))))
+ (setq-local font-lock-defaults '((matlab-shell-font-lock-keywords)
+ t ;; syntatic fontification (strings and
comments) is not performed.
+ nil ;; keywords are case sensitive
+ ;; Put _ as a word constituent, simplifying
keywords
+ ((?_ . "w"))))
;; GUD support
(matlab-shell-mode-gud-enable-bindings)
@@ -1620,10 +1620,7 @@ Snatched and hacked from dired-x.el"
""
(search-forward-regexp comint-prompt-regexp)
(buffer-substring (point) (line-end-position)))))
- (save-excursion
- (buffer-substring-no-properties
- (matlab-scan-beginning-of-command)
- (matlab-scan-end-of-command)))))
+ (matlab--get-command-at-point-to-run)))
(defun matlab-non-empty-lines-in-string (str)
"Return number of non-empty lines in STR."
@@ -1655,7 +1652,7 @@ This command requires an active MATLAB shell."
"MATLAB command line: "
(cons (matlab-read-line-at-point) 0))))
(let ((doc (matlab-shell-collect-command-output command)))
- (matlab-output-to-temp-buffer "*MATLAB Help*" doc)))
+ (matlab-output-to-temp-buffer "*MATLAB Run Command Result*" doc)))
(defun matlab-shell-describe-variable (variable)
"Get the contents of VARIABLE and display them in a buffer.
@@ -1672,7 +1669,7 @@ This command requires an active MATLAB shell."
This uses the lookfor command to find viable commands.
This command requires an active MATLAB shell."
(interactive
- (let ((fn (matlab-function-called-at-point))
+ (let ((fn (matlab--function-called-at-point))
val)
(setq val (read-string (if fn
(format "Describe function (default %s): " fn)
@@ -2254,30 +2251,10 @@ Similar to `comint-send-input'."
;;
;; Run some subset of the buffer in matlab-shell.
-(defun matlab-shell-run-code-section ()
- "Run the code-section the cursor is in."
- (interactive)
- (let ((start (save-excursion
- (forward-page -1)
- (if (looking-at "function")
- (error "You are not in a code-section. Try
`matlab-shell-save-and-go' instead"))
- (when (matlab-line-comment-p (matlab-compute-line-context 1))
- ;; Skip over starting comment from the current code-section.
- (matlab-end-of-command)
- (end-of-line)
- (forward-char 1))
- (point)))
- (end (save-excursion
- (forward-page 1)
- (when (matlab-line-comment-p (matlab-compute-line-context 1))
- (beginning-of-line)
- (forward-char -1))
- (point))))
- (matlab-shell-run-region start end t)))
-
(defun matlab-shell-run-region-or-line ()
"Run region from BEG to END and display result in MATLAB shell.
-pIf region is not active run the current line.
+This should be called from a *.m file in `matlab-ts-mode' or
+`matlab-mode'. If region is not active run the current line.
This command requires an active MATLAB shell."
(interactive)
(if (and transient-mark-mode mark-active)
@@ -2288,8 +2265,9 @@ This command requires an active MATLAB shell."
;;;###autoload
(defun matlab-shell-run-region (beg end &optional noshow)
"Run region from BEG to END and display result in MATLAB shell.
-If NOSHOW is non-nil, replace newlines with commas to suppress
-output. This command requires an active MATLAB shell."
+If NOSHOW is non-nil, replace newlines with commas to suppress output.
+This should be called from a *.m file in `matlab-ts-mode' or
+`matlab-mode'. This command requires an active MATLAB shell."
(interactive "r")
(if (> beg end) (let (mid) (setq mid beg beg end end mid)))
@@ -2364,6 +2342,9 @@ Optional argument NOSHOW specifies if we should echo the
region to the
(t
(funcall matlab-shell-run-region-function beg end noshow))))
+(defsubst matlab--cursor-in-string ()
+ "Return t if the cursor is in a valid MATLAB character vector or string
scalar."
+ (nth 3 (syntax-ppss (point))))
(defun matlab-shell-region->commandline (beg end &optional noshow)
"Convert the region between BEG and END into a MATLAB command.
@@ -2377,7 +2358,7 @@ When NOSHOW is non-nil, suppress output by adding ; to
commands."
(goto-char (point-min))
;; Delete all the comments
(while (search-forward "%" nil t)
- (unless (matlab-cursor-in-string)
+ (unless (matlab--cursor-in-string)
(delete-region (1- (point)) (line-end-position))))
(setq str (buffer-substring-no-properties (point-min) (point-max))))
@@ -2393,7 +2374,7 @@ When NOSHOW is non-nil, suppress output by adding ; to
commands."
;; Remove continuations
(while (string-match
(concat "\\s-*"
- (regexp-quote matlab-ellipsis-string)
+ (regexp-quote "...")
"\\s-*\n")
str)
(setq str (replace-match " " t t str)))
diff --git a/matlab-topic.el b/matlab-topic.el
index 852dd9fc7a..66db975835 100644
--- a/matlab-topic.el
+++ b/matlab-topic.el
@@ -24,6 +24,7 @@
;;; Code:
(require 'matlab)
+(require 'matlab--shell-map)
(require 'matlab-shell)
(require 'view)
@@ -71,7 +72,7 @@
(let ((km (make-sparse-keymap)))
(define-key km [return] 'matlab-shell-help-choose)
(define-key km "q" 'bury-buffer)
- (define-key km [(control h) (control m)] matlab-help-map)
+ (define-key km [(control h) (control m)] matlab--shell-help-map)
(if (string-match "XEmacs" emacs-version)
(define-key km [button2] 'matlab-shell-help-click)
(define-key km [mouse-2] 'matlab-shell-help-click)
diff --git a/matlab-ts-mode.el b/matlab-ts-mode.el
index 59b03bf64a..0918ea20c8 100644
--- a/matlab-ts-mode.el
+++ b/matlab-ts-mode.el
@@ -1,4 +1,4 @@
- ;;; matlab-ts-mode.el --- MATLAB(R) Tree-Sitter Mode -*- lexical-binding: t
-*-
+;;; matlab-ts-mode.el --- MATLAB(R) Tree-Sitter Mode -*- lexical-binding: t -*-
;; Copyright 2025 Free Software Foundation, Inc.
;;
@@ -1486,84 +1486,144 @@ incomplete statements where NODE is nil and PARENT is
line_continuation."
;;; Thing settings for movement, etc.
+
+(defvar matlab-ts-mode--statements-type-re
+ (rx (seq
+ bos
+ (or "arguments_statement"
+ "assignment"
+ "lambda"
+ "class_definition"
+ "enumeration"
+ "events"
+ "for_statement"
+ "function_call"
+ "function_definition"
+ "if_statement"
+ "methods"
+ "property"
+ "properties"
+ "spmd_statement"
+ "switch_statement"
+ "try_statement"
+ "while_statement")
+ eos))
+ "MATLAB command statements.")
+
;; TODO should we use following for M-a, M-e?
;; This needs tune up, but could workout better than using
matlab-ts-mode--thing-settings
-;;
-;; (defvar matlab-ts-mode--statements-ht
-;; #s(hash-table
-;; test equal
-;; data ("arguments_statement" t
-;; "assignment" t
-;; "lambda" t
-;; "class_definition" t
-;; "enumeration" t
-;; "events" t
-;; "for_statement" t
-;; "function_definition" t
-;; "if_statement" t
-;; "methods" t
-;; "property" t
-;; "properties" t
-;; "spmd_statement" t
-;; "switch_statement" t
-;; "try_statement" t
-;; "while_statement" t))
-;; "MATLAB command statements.")
-;;
-;; (cl-defun matlab-ts-mode-beginning-of-statement (&optional goto-end)
-;; "Move to the beginning of a command statement.
-;; If optional GOTO-END is \\='end, move to end of the current statement.
-;;
-;; We define a command statement to be a complete syntatic unit that has
-;; a start and end. For example, if point is in an assigment statement
-;; var = ...
-;; 1;
-;; move point to the \"v\" when GOTO-END is nil, otherwise move to the
-;; \";\". If point is in an if statement, move to the start or end of
-;; that. Likewise for other command statements.
-;;
-;; The point is moved to the start or end of the innermost statement that
-;; the point is on. No movement is performed if point is not in a
-;; statement. This can occur when there are syntax errors or the buffer
-;; has no content.
-;;
-;; Returns nil if not in a statement, otherwise the `point' which
-;; will be a new point if the starting point was not at the start
-;; or end of the command statement."
-;; (interactive)
-;;
-;; (cl-assert (or (not goto-end) (eq goto-end 'end)))
-;;
-;; (let ((node (treesit-node-at (point))))
-;;
-;; (when (and (> (point) 1)
-;; (equal (treesit-node-type node) "\n")
-;; (re-search-backward "[^ \t\n\r]" nil t))
-;; (setq node (treesit-node-at (point))))
-;;
-;; (while (and node
-;; (let ((type (treesit-node-type node)))
-;; (when (equal type "ERROR")
-;; ;; No movement if we have a syntax error
-;; (message "Not in statement due to syntax error.")
-;; (cl-return nil))
-;; (not (gethash type matlab-ts-mode--statements-ht))))
-;; (setq node (treesit-node-parent node)))
-;;
-;; (when (not node)
-;; (message "Not in a statement.")
-;; (cl-return))
-;;
-;; (when node
-;; (goto-char (if (eq goto-end 'end)
-;; (treesit-node-end node)
-;; (treesit-node-start node))))))
-;;
-;; (defun matlab-ts-mode-end-of-statement ()
-;; "Move to the end of a command statement.
-;; This is the opposite of `matlab-ts-mode-beginning-of-statement'."
-;; (interactive)
-;; (matlab-ts-mode-beginning-of-statement 'end))
+
+(cl-defun matlab-ts-mode-beginning-of-statement (&optional goto-end
statement-type-re)
+ "Move to the beginning of a statement.
+If optional GOTO-END is \\='end, move to end of the current statement.
+
+We define a command statement to be a complete syntatic unit that has
+a start and end. For example, if point is in an assigment statement
+ var = ...
+ 1;
+move point to the \"v\" when GOTO-END is nil, otherwise move to the the
+point after \";\". Likewise for other command statements.
+
+The point is moved to the start or end of the innermost statement that
+the point is on. No movement is performed if point is not in a
+statement. This can occur when there are syntax errors or the buffer
+has no content.
+
+Optional STATEMENT-TYPE-RE is a regular expression matching the type of
+statement to look for. For example, to move to the begining of the
+current assignment statement, use
+
+ (matlab-ts-mode-beginning-of-statement nil
+ (rx (seq bos \"assignment\" eos))
+
+If STATEMENT-TYPE-RE is not specified, `matlab-ts-mode--statements-type-re'
+is used.
+
+Returns nil if not in a statement, otherwise the `point' which
+will be a new point if the starting point was not at the start
+or end of the command statement."
+ (interactive)
+
+ (cl-assert (or (not goto-end) (eq goto-end 'end)))
+
+ (when (not statement-type-re)
+ (setq statement-type-re matlab-ts-mode--statements-type-re))
+
+ (let ((start-point (point))
+ (node (treesit-node-at (point))))
+
+ ;; When on a newline, back up to prior statement
+ (when (and (> (point) 1)
+ (equal (treesit-node-type node) "\n")
+ (re-search-backward "[^ \t\n\r]" nil t))
+ (setq node (treesit-node-at (point))))
+
+ ;; When at ";" use prev-sibling
+ (when (equal (treesit-node-type node) ";")
+ (setq node (treesit-node-prev-sibling node)))
+
+ ;; find nearest ancestor that matches statement-type-re
+ (while (and node
+ (let ((type (treesit-node-type node)))
+ (when (equal type "ERROR")
+ ;; No movement if we have a syntax error
+ (message "Not in statement due to syntax error.")
+ (cl-return-from matlab-ts-mode-beginning-of-statement))
+ (not (string-match-p statement-type-re type))))
+ (setq node (treesit-node-parent node)))
+
+ (when (not node)
+ (message "Not in a statement")
+ (cl-return-from matlab-ts-mode-beginning-of-statement))
+
+ (when node
+ (let* ((statement-start-point (treesit-node-start node))
+ (end-node (or
+ ;; Use next sibling node if it's a ";" for the an
+ ;; assignment or function_call.
+ (and (string-match-p (rx (seq bos (or "assignment"
+ "function_call")
+ eos))
+ (treesit-node-type node))
+ (let ((next-node (treesit-node-next-sibling
node)))
+ (when (and next-node
+ (string= ";" (treesit-node-type
next-node)))
+ next-node)))
+ node))
+ (statement-end-point (treesit-node-end end-node)))
+ (when (and (>= start-point statement-start-point)
+ (<= start-point statement-end-point))
+ (goto-char (if (eq goto-end 'end)
+ statement-end-point
+ statement-start-point)))))))
+
+(defun matlab-ts-mode-end-of-statement (&optional statement-type)
+ "Move to the end of a command statement.
+This is the opposite of `matlab-ts-mode-beginning-of-statement'.
+Optional STATEMENT-TYPE is the type of statement to look for. If
+not specified statement in `matlab-ts-mode--statements-ht' are used."
+ (interactive)
+ (matlab-ts-mode-beginning-of-statement 'end statement-type))
+
+(defun matlab-ts-mode-beginning-of-command ()
+ "Move to the beginning of the command at point.
+Commands are either assignement or function_call statements that can be
+evaluated at the matlab prompt. Movement occurs only if the point is in
+an assignment or function call. Note array indexing is considered a
+function call."
+ (matlab-ts-mode-beginning-of-statement nil (rx (seq bos (or "assignment"
+ "function_call")
+ eos))))
+
+(defun matlab-ts-mode-end-of-command ()
+ "Move to the end of the command at point.
+Commands are either assignement or function_call statements that can be
+evaluated at the matlab prompt. Movement occurs only if the point is in
+an assignment or function call. Note array indexing is considered a
+function call."
+ (matlab-ts-mode-beginning-of-statement 'end (rx (seq bos (or "assignment"
+ "function_call")
+ eos))))
(defvar matlab-ts-mode--thing-settings
`((matlab
@@ -2206,7 +2266,11 @@ is t, add the following to an Init File (e.g.
`user-init-file' or
;;
;; TODO create defcustom matlab-ts-mode-electric-ends that inserts end
statements
;; when a function, switch, while, for, etc. is entered. This should
handle continuations.
-
+ ;;
+ ;; TODO on load enter matlab-ts-mode when file contains mcode and
+ ;; (add-to-list 'major-mode-remap-alist '(matlab-mode .
matlab-ts-mode))
+ ;; is active. Also look at matlab-mode magic-mode-alist setup.
+ ;;
(treesit-major-mode-setup)
;; Correct forward-sexp setup created by `treesit-major-mode' so that for
parenthesis, brackets,
diff --git a/matlab.el b/matlab.el
index e23c189d2a..0a570ee441 100644
--- a/matlab.el
+++ b/matlab.el
@@ -56,6 +56,7 @@
(require 'matlab-scan)
(require 'matlab-sections)
(require 'matlab-syntax)
+(require 'matlab--shell-map)
(require 'derived)
(require 'easymenu)
@@ -540,13 +541,6 @@ point, but it will be restored for them."
(make-variable-buffer-local 'matlab-return-add-semicolon)
-(defcustom matlab-change-current-directory nil
- "*If non nil, make file's directory the current directory when evaluating
it."
- :group 'matlab
- :type 'boolean)
-
-(make-variable-buffer-local 'matlab-change-current-directory)
-
(defvar matlab-mode-abbrev-table nil
"The abbrev table used in `matlab-mode' buffers.")
(define-abbrev-table 'matlab-mode-abbrev-table ())
@@ -554,15 +548,6 @@ point, but it will be restored for them."
;;; Keybindings ===============================================================
-(defvar matlab-help-map
- (let ((km (make-sparse-keymap)))
- (define-key km "r" 'matlab-shell-run-command)
- (define-key km "f" 'matlab-shell-describe-command)
- (define-key km "a" 'matlab-shell-apropos)
- (define-key km "v" 'matlab-shell-describe-variable)
- km)
- "The help key map for `matlab-mode' and `matlab-shell-mode'.")
-
(defvar matlab-mode-map
(let ((km (make-sparse-keymap)))
;; Navigation Commands
@@ -588,11 +573,10 @@ point, but it will be restored for them."
;; Connecting to MATLAB Shell
(define-key km [(control c) (control s)] 'matlab-shell-save-and-go)
(define-key km [(control c) (control r)] 'matlab-shell-run-region)
- (define-key km [(meta control return)] 'matlab-shell-run-code-section)
(define-key km [(control return)] 'matlab-shell-run-region-or-line)
(define-key km [(control c) (control t)] 'matlab-show-line-info)
(define-key km [(control c) ?. ] 'matlab-shell-locate-fcn)
- (define-key km [(control h) (control m)] matlab-help-map)
+ (define-key km [(control h) (control m)] matlab--shell-help-map)
(define-key km [(meta s)] 'matlab-show-matlab-shell-buffer)
(define-key km [(control meta mouse-2)] 'matlab-find-file-click)
;; Debugger interconnect
@@ -614,25 +598,6 @@ point, but it will be restored for them."
:active (matlab-any-shell-active-p)]
["Run Region" matlab-shell-run-region
:active (matlab-any-shell-active-p)]
- ["Run Code Section" matlab-shell-run-code-section
- :active (matlab-any-shell-active-p)]
- "----"
- ["Locate MATLAB function" matlab-shell-locate-fcn
- :active (matlab-shell-active-p)
- :help "Run 'which FCN' in matlab-shell, then open the file in Emacs"]
- ["Show M-Lint Warnings" matlab-toggle-show-mlint-warnings
- :active (and (locate-library "mlint") (fboundp 'mlint-minor-mode))
- :style toggle :selected matlab-show-mlint-warnings
- ]
- ("Auto Fix"
- ["Verify/Fix source" matlab-mode-verify-fix-file t]
- ["Quiesce source" matlab-mode-vf-quiesce-buffer t]
- )
- ("Format"
- ["Justify Line" matlab-justify-line t]
- ["Fill Comment" fill-paragraph]
- ["Comment Region" matlab-comment-region t]
- ["Uncomment Region" matlab-uncomment-region t])
("Code Sections"
["Run section" matlab-sections-run-section
:active matlab-sections-minor-mode
@@ -666,6 +631,23 @@ mark at the beginning of the \"%% section\" and point at
the end of the section"
:help "Move the current \"%% section\" down."]
"--"
["Sections help" matlab-sections-help])
+ "----"
+ ["Locate MATLAB function" matlab-shell-locate-fcn
+ :active (matlab-shell-active-p)
+ :help "Run 'which FCN' in matlab-shell, then open the file in Emacs"]
+ ["Show M-Lint Warnings" matlab-toggle-show-mlint-warnings
+ :active (and (locate-library "mlint") (fboundp 'mlint-minor-mode))
+ :style toggle :selected matlab-show-mlint-warnings
+ ]
+ ("Auto Fix"
+ ["Verify/Fix source" matlab-mode-verify-fix-file t]
+ ["Quiesce source" matlab-mode-vf-quiesce-buffer t]
+ )
+ ("Format"
+ ["Justify Line" matlab-justify-line t]
+ ["Fill Comment" fill-paragraph]
+ ["Comment Region" matlab-comment-region t]
+ ["Uncomment Region" matlab-uncomment-region t])
("Debug"
["Edit File (toggle read-only)" matlab-shell-gud-mode-edit
:help "Exit MATLAB debug minor mode to edit without exiting MATLAB's K>>
prompt."
@@ -1785,19 +1767,6 @@ A negative number means there were more ends than starts.
depth))))
-
-(defun matlab-function-called-at-point ()
- "Return a string representing the function called nearby point."
- (save-excursion
- (beginning-of-line)
- (cond ((looking-at "\\s-*\\([a-zA-Z]\\w+\\)[^=][^=]")
- (match-string 1))
- ((and (re-search-forward "=" (line-end-position) t)
- (looking-at "\\s-*\\([a-zA-Z]\\w+\\)\\s-*[^=]"))
- (match-string 1))
- (t nil))))
-
-
(defun matlab-comment-on-line ()
"Place the cursor on the beginning of a valid comment on this line.
If there isn't one, then return nil, point otherwise."
diff --git a/tests/test-matlab-ts-mode-movement-files/movement_statements.m
b/tests/test-matlab-ts-mode-movement-files/movement_statements.m
new file mode 100644
index 0000000000..bc8863a88f
--- /dev/null
+++ b/tests/test-matlab-ts-mode-movement-files/movement_statements.m
@@ -0,0 +1,22 @@
+% -*- matlab-ts -*-
+
+% (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+s = 'my string';
+
+% (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+m = [1, 2;
+ 3, 4];
+
+% (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+plot(1, 10)
+
+% (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+sprintf("%s", s)
+
+% (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+v=1:10;
+
+% (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+v(2:3)
+
+
diff --git
a/tests/test-matlab-ts-mode-movement-files/movement_statements_expected.org
b/tests/test-matlab-ts-mode-movement-files/movement_statements_expected.org
new file mode 100644
index 0000000000..95474c48d7
--- /dev/null
+++ b/tests/test-matlab-ts-mode-movement-files/movement_statements_expected.org
@@ -0,0 +1,235 @@
+#+startup: showall
+
+* Executing commands from movement_statements.m:3:2:
+
+ (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+
+- Invoking : "C-n" = next-line
+ Start point : 124
+ Moved to point: 141
+ : 4:16: s = 'my string';
+ : ^
+ No buffer modifications
+
+- Invoking : "C-a" = move-beginning-of-line
+ Start point : 141
+ Moved to point: 125
+ : 4:0: s = 'my string';
+ : ^
+ No buffer modifications
+
+- Invoking : "C-f" = forward-char
+ Start point : 125
+ Moved to point: 126
+ : 4:1: s = 'my string';
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-beginning-of-command)
+ Start point : 126
+ Moved to point: 125
+ : 4:0: s = 'my string';
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-end-of-command)
+ Start point : 125
+ Moved to point: 141
+ : 4:16: s = 'my string';
+ : ^
+ No buffer modifications
+
+* Executing commands from movement_statements.m:6:2:
+
+ (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+
+- Invoking : "C-n" = next-line
+ Start point : 245
+ Moved to point: 256
+ : 7:10: m = [1, 2;
+ : ^
+ No buffer modifications
+
+- Invoking : "C-a" = move-beginning-of-line
+ Start point : 256
+ Moved to point: 246
+ : 7:0: m = [1, 2;
+ : ^
+ No buffer modifications
+
+- Invoking : "C-f" = forward-char
+ Start point : 246
+ Moved to point: 247
+ : 7:1: m = [1, 2;
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-beginning-of-command)
+ Start point : 247
+ Moved to point: 246
+ : 7:0: m = [1, 2;
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-end-of-command)
+ Start point : 246
+ Moved to point: 268
+ : 8:11: 3, 4];
+ : ^
+ No buffer modifications
+
+* Executing commands from movement_statements.m:10:2:
+
+ (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+
+- Invoking : "C-n" = next-line
+ Start point : 372
+ Moved to point: 384
+ : 11:11: plot(1, 10)
+ : ^
+ No buffer modifications
+
+- Invoking : "C-a" = move-beginning-of-line
+ Start point : 384
+ Moved to point: 373
+ : 11:0: plot(1, 10)
+ : ^
+ No buffer modifications
+
+- Invoking : "C-f" = forward-char
+ Start point : 373
+ Moved to point: 374
+ : 11:1: plot(1, 10)
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-beginning-of-command)
+ Start point : 374
+ Moved to point: 373
+ : 11:0: plot(1, 10)
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-end-of-command)
+ Start point : 373
+ Moved to point: 384
+ : 11:11: plot(1, 10)
+ : ^
+ No buffer modifications
+
+* Executing commands from movement_statements.m:13:2:
+
+ (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+
+- Invoking : "C-n" = next-line
+ Start point : 488
+ Moved to point: 505
+ : 14:16: sprintf("%s", s)
+ : ^
+ No buffer modifications
+
+- Invoking : "C-a" = move-beginning-of-line
+ Start point : 505
+ Moved to point: 489
+ : 14:0: sprintf("%s", s)
+ : ^
+ No buffer modifications
+
+- Invoking : "C-f" = forward-char
+ Start point : 489
+ Moved to point: 490
+ : 14:1: sprintf("%s", s)
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-beginning-of-command)
+ Start point : 490
+ Moved to point: 489
+ : 14:0: sprintf("%s", s)
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-end-of-command)
+ Start point : 489
+ Moved to point: 505
+ : 14:16: sprintf("%s", s)
+ : ^
+ No buffer modifications
+
+* Executing commands from movement_statements.m:16:2:
+
+ (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+
+- Invoking : "C-n" = next-line
+ Start point : 609
+ Moved to point: 617
+ : 17:7: v=1:10;
+ : ^
+ No buffer modifications
+
+- Invoking : "C-a" = move-beginning-of-line
+ Start point : 617
+ Moved to point: 610
+ : 17:0: v=1:10;
+ : ^
+ No buffer modifications
+
+- Invoking : "C-f" = forward-char
+ Start point : 610
+ Moved to point: 611
+ : 17:1: v=1:10;
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-beginning-of-command)
+ Start point : 611
+ Moved to point: 610
+ : 17:0: v=1:10;
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-end-of-command)
+ Start point : 610
+ Moved to point: 617
+ : 17:7: v=1:10;
+ : ^
+ No buffer modifications
+
+* Executing commands from movement_statements.m:19:2:
+
+ (t-utils-xr "C-n" "C-a" "C-f" (matlab-ts-mode-beginning-of-command)
(matlab-ts-mode-end-of-command))
+
+- Invoking : "C-n" = next-line
+ Start point : 721
+ Moved to point: 728
+ : 20:6: v(2:3)
+ : ^
+ No buffer modifications
+
+- Invoking : "C-a" = move-beginning-of-line
+ Start point : 728
+ Moved to point: 722
+ : 20:0: v(2:3)
+ : ^
+ No buffer modifications
+
+- Invoking : "C-f" = forward-char
+ Start point : 722
+ Moved to point: 723
+ : 20:1: v(2:3)
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-beginning-of-command)
+ Start point : 723
+ Moved to point: 722
+ : 20:0: v(2:3)
+ : ^
+ No buffer modifications
+
+- Invoking : (matlab-ts-mode-end-of-command)
+ Start point : 722
+ Moved to point: 728
+ : 20:6: v(2:3)
+ : ^
+ No buffer modifications
diff --git a/tests/test-matlab-ts-mode-movement.el
b/tests/test-matlab-ts-mode-movement.el
new file mode 100644
index 0000000000..162d7553ab
--- /dev/null
+++ b/tests/test-matlab-ts-mode-movement.el
@@ -0,0 +1,69 @@
+;;; test-matlab-ts-mode-movement.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-movement-files/NAME.m comparing against
+;; ./test-matlab-ts-mode-movement-files/NAME_expected.org
+;;
+
+;;; Code:
+
+(require 't-utils)
+(require 'matlab-ts-mode)
+
+(defvar test-matlab-ts-mode-movement--file nil)
+
+(defun test-matlab-ts-mode-movement--file (m-file)
+ "Test an individual M-FILE.
+This is provided for debugging.
+ M-: (test-matlab-ts-mode-movement--file
+ \"test-matlab-ts-mode-movement-files/M-FILE\")"
+ (let ((test-matlab-ts-mode-movement--file m-file))
+ (ert-run-tests-interactively "test-matlab-ts-mode-movement")))
+
+(ert-deftest test-matlab-ts-mode-movement ()
+ "Test movement commands using ./test-matlab-ts-mode-movement-files/NAME.m.
+Using ./test-matlab-ts-mode-movement-files/NAME.m, compare
+movement of `matlab-mode-ts-beginning-of-command' and
+`matlab-mode-ts-end-of-command' against baseline:
+./test-matlab-ts-mode-movement-files/NAME_expected.org.
+This loops on all
+./test-matlab-ts-mode-movement-files/NAME.m files.
+
+To add a test, create
+ ./test-matlab-ts-mode-movement-files/NAME.m
+and run this function. The baseline is saved for you as
+ ./test-matlab-ts-mode-movement-files/NAME_expected.org~
+after validating it, rename it to
+ ./test-matlab-ts-mode-movement-files/NAME_expected.org"
+
+ (let* ((test-name "test-matlab-ts-mode-movement")
+ (m-files (t-utils-get-files
+ test-name
+ (rx ".m" eos)
+ nil
+ test-matlab-ts-mode-movement--file)))
+ (t-utils-error-if-no-treesit-for 'matlab test-name)
+ (t-utils-test-xr test-name m-files)))
+
+(provide 'test-matlab-ts-mode-movement)
+;;; test-matlab-ts-mode-movement.el ends here