branch: externals/matlab-mode
commit 75f9123d36af8cc75a01992f4b25b43074472fca
Author: John Ciolfi <[email protected]>
Commit: John Ciolfi <[email protected]>
matlab-ts-grammar-install: now does all install activities
---
doc/install-matlab-tree-sitter-grammar.org | 65 +++++----
matlab-ts-grammar-install.el | 213 ++++++++++++++++++++++-------
2 files changed, 200 insertions(+), 78 deletions(-)
diff --git a/doc/install-matlab-tree-sitter-grammar.org
b/doc/install-matlab-tree-sitter-grammar.org
index ee3cbbac19..65c37feb2b 100644
--- a/doc/install-matlab-tree-sitter-grammar.org
+++ b/doc/install-matlab-tree-sitter-grammar.org
@@ -31,11 +31,29 @@
#+title: How to install the MATLAB tree-sitter grammar
#+author: John Ciolfi
-#+date: [2025-09-04]
+#+date: [2025-11-13]
The MATLAB tree-sitter grammar requires Emacs 30 or later. This is typically
installed in
=~/.emacs.d/tree-sitter/libtree-sitter-matlab.so= (=.dll= on Windows, =.dylib=
on Mac).
+* Install the Emacs-MATLAB-Mode pre-built matlab tree-sitter grammar
+
+After installing matlab-mode,
+
+ : M-x matlab-ts-grammar-install
+
+This will download the pre-build matlab tree-sitter grammar from
+https://github.com/mathworks/Emacs-MATLAB-Mode/matlab-ts-bin and save to the
tree-sitter
+subdirectory of `user-emacs-directory'. For example,
+=~/.emacs.d/tree-sitter/libtree-sitter-matlab.so= (=.dylib= on Mac, =.dll= on
Windows). You can
+visit https://github.com/mathworks/Emacs-MATLAB-Mode/matlab-ts-bin to see what
source was used to
+produce these binaries.
+
+In addition, =M-x matlab-ts-grammar-install= will save the customizations
required for
+=matlab-ts-mode= which leverages the matlab tree-sitter grammar.
+
+* Alternative: Manual Installation
+
Below we use the location =~/emacs-projects=. You can change this to another
location if desired.
As described below, installation consists of two steps
@@ -43,27 +61,13 @@ As described below, installation consists of two steps
1. Install the MATLAB tree-sitter grammar
2. Setup Emacs to use the tree-sitter grammar
-* Install MATLAB tree-sitter grammar for Emacs 30
-
For Emacs 30, you need to build the MATLAB tree-sitter grammar for ABI 14
because Emacs 30 uses
version 14 of the tree-sitter application binary interface and as of Sep-2025,
the latest
tree-sitter ABI is 15. There are different methods for installing this.
-** Method 1 - Install the Emacs-MATLAB-Mode pre-built matlab tree-sitter
grammar
+** Install MATLAB tree-sitter grammar for Emacs 30
-After installing the =matlab-mode= package,
-
-: M-x matlab-ts-grammar-install
-
-This will download the pre-build matlab tree-sitter grammar from
-https://github.com/mathworks/Emacs-MATLAB-Mode/matlab-ts-bin and save to the
-tree-sitter subdirectory of `user-emacs-directory'. For example,
-=~/.emacs.d/tree-sitter/libtree-sitter-matlab.so= (=.dylib= on Mac, =.dll= on
Windows).
-
-Visit https://github.com/mathworks/Emacs-MATLAB-Mode/matlab-ts-bin to see what
source was
-used to produce these binaries.
-
-** Method 2 - Install from abi/14 branch
+*** Method 1 - Install from abi/14 branch
Oct-29-2025 matlab-ts-mode is known to work with matlab tree-sitter v1.2.3
branch
[[https://github.com/acristoffers/tree-sitter-matlab/tree/abi/14][abi/14]] at
[[https://github.com/acristoffers/tree-sitter-matlab/tree/9a4e65df4bb08e2b019ca2ef16b2d8f3d95ce978][9a4e65d]].
@@ -120,7 +124,7 @@ Oct-29-2025 matlab-ts-mode is known to work with matlab
tree-sitter v1.2.3 branc
cl /LD /I src\tree_sitter src\parser.c src\scanner.c /link
/out:%HOME%\.emacs.d\tree-sitter\libtree-sitter-matlab.dll
#+end_src
-** Method 3 - Generate the grammar for ABI 14 and install
+*** Method 2 - Generate the grammar for ABI 14 and install
1. Install C/C++ compiler if not installed. See Method 2 for tips on
installing the C/C++ compiler.
@@ -187,25 +191,30 @@ Oct-29-2025 matlab-ts-mode is known to work with matlab
tree-sitter v1.2.3 branc
- _Windows_
- Follow the same Windows build step as in Method 2.
+ Follow the same Windows build step as in Method 1.
-* Setup Emacs to use the MATLAB tree-sitter grammar
+** Setup Emacs to use the MATLAB tree-sitter grammar
Tell Emacs to use *matlab-ts-mode* for MATLAB files by adding the following to
your
=user-init-file= which is typically =~/.emacs=, or add it to your
=site-run-file=
-#+begin_src emacs-lisp
- (add-to-list 'major-mode-remap-alist '(matlab-mode . matlab-ts-mode))
-#+end_src
+1. Map =matlab-mode= to =matlab-ts-mode=
+
+ : M-x customize-variable RET major-mode-remap-alist RET
+
+ and INS (insert):
+
+ : Key: matlab-mode
+ : Value: matlab-ts-mode
-Tell =org-mode= that =#+begin_src matlab ... #end_src= blocks should use
*matlab-ts-mode*:
+2. Tell =org-mode= that =#+begin_src matlab ... #end_src= blocks should use
*matlab-ts-mode*
- : M-x customize-variable RET org-src-lang-modes RET
+ : M-x customize-variable RET org-src-lang-modes RET
-and map matlab to matlab-ts:
+ and map matlab to matlab-ts:
- : Language name: matlab
- : Major mode: matlab-ts
+ : Language name: matlab
+ : Major mode: matlab-ts
# LocalWords: showall usepackage parskip tocloft cftsecnumwidth
cftsubsecindent cftsubsecnumwidth
# LocalWords: libtree dylib workarea ABI langs abi MSys sudo treesit nodejs
npm alist lang MELPA
diff --git a/matlab-ts-grammar-install.el b/matlab-ts-grammar-install.el
index d315dff295..04ba3c6edb 100644
--- a/matlab-ts-grammar-install.el
+++ b/matlab-ts-grammar-install.el
@@ -1,4 +1,4 @@
-;;; matlab-ts-langs-install.el --- -*- lexical-binding: t -*-
+;;; matlab-ts-grammar-install.el --- -*- lexical-binding: t -*-
;; Copyright (C) 2025 Free Software Foundation, Inc.
;;
@@ -18,50 +18,63 @@
;;; Commentary:
;;
;; Download
-;; ~/.emacs.d/tree-sitter/libtree-sitter-LANGUAGES.so (or .dll or .dylib)
+;; ~/.emacs.d/tree-sitter/libtree-sitter-matlab.so (or .dll or .dylib)
;; from
;; https://github.com/mathworks/Emacs-MATLAB-Mode/matlab-ts-bin/
-;;
;;; Code:
+(require 'files)
+(require 'org-src)
(require 'url)
(defun matlab--ts-grammar-arch-and-shared-lib ()
"Return ARCH/libtree-sitter-matlab.SLIB_EXT.
ARCH is the same as the MATLAB computer('arch') command result."
(let ((result (pcase system-type
- ('darwin (cond
+ ('darwin (cond
((string-prefix-p "aarch64" system-configuration)
"maca64/libtree-sitter-matlab.dylib")
((string-prefix-p "x86_64" system-configuration)
"maca64/libtree-sitter-matlab.dylib")))
- ('gnu/linux (cond
+ ('gnu/linux (cond
((string-prefix-p "x86_64" system-configuration)
"glnxa64/libtree-sitter-matlab.so")))
('windows-nt "win64/libtree-sitter-matlab.dll"))))
(when (not result)
- (error "Unsupported system-type %s, system-configuration %s" system-type
- system-configuration))
+ (user-error "Unsupported system-type %s, system-configuration %s"
system-type
+ system-configuration))
result))
-(defun matlab--ts-grammar-download-url (branch)
- "Get the download tree-sitter-matlab URL for BRANCH."
+(defun matlab--ts-grammar-download-url (branch prompt-for-version)
+ "Get the download tree-sitter-matlab URL for BRANCH.
+When PROMPT-FOR-VERSION is non-nil, prompt for the version to download."
;; Use GitHub REST API to get the download URL
(let* ((bin-url (concat
"https://api.github.com/repos/mathworks/Emacs-MATLAB-mode/contents/"
"matlab-ts-bin?ref=" branch))
(raw-url-start (concat
"https://raw.githubusercontent.com/mathworks/Emacs-MATLAB-Mode/"
branch "/matlab-ts-bin"))
-
- (bin-buf (url-retrieve-synchronously bin-url))
+
+ (bin-buf (url-retrieve-synchronously bin-url))
(versions '())
latest-ver-date-num
latest-ver
- download-url)
+ download-url)
(with-current-buffer bin-buf
- (let ((entries (json-read-from-string (cadr (split-string
(buffer-string) "\n\n" t)))))
+ (let* ((response-content
+ (let ((result (buffer-string)))
+ (goto-char (point-min))
+ (if (re-search-forward "^\\(HTTP/[0-9.]* \\([0-9]+\\) .*\\)$"
nil t)
+ (let ((response (match-string 1))
+ (response-code (match-string 2)))
+ (when (not (string= response-code "200"))
+ (user-error "Invalid response \"%s\" received from %s"
+ response bin-url)))
+ (user-error "Unexpected result from %s: %s" bin-url result))
+ (cadr (split-string result "\n\n" t))))
+ (entries (json-read-from-string response-content)))
(cl-loop for entry across entries do
(let ((rel-file (alist-get 'path entry))) ;;
matlab-ts-bin/FILE
;; Have YYYYMMDD-SHA1
@@ -75,59 +88,159 @@ ARCH is the same as the MATLAB computer('arch') command
result."
(push ver versions)))))))
(when (not latest-ver)
- (error "Failed to get release versions from %s" bin-url))
+ (user-error "Failed to get release versions from %s" bin-url))
- (let ((ver-to-download (completing-read (concat
- "Version to download ("
latest-ver " is latest): ")
- versions nil t latest-ver))
- (arch-slib (matlab--ts-grammar-arch-and-shared-lib)))
+ (let ((ver-to-download (if prompt-for-version
+ (completing-read (concat
+ "Version to download ("
latest-ver " is latest): ")
+ versions nil t latest-ver)
+ latest-ver))
+ (arch-slib (matlab--ts-grammar-arch-and-shared-lib)))
(setq download-url (concat raw-url-start "/" ver-to-download "/"
arch-slib)))
-
+
(kill-buffer bin-buf)
download-url))
+(defun matlab--files-equal-p (file1 file2)
+ "Return t if the contents of FILE1 and FILE2 are identical, nil otherwise."
+ (let ((content1 (with-temp-buffer
+ (insert-file-contents-literally file1)
+ (buffer-string)))
+ (content2 (with-temp-buffer
+ (insert-file-contents-literally file2)
+ (buffer-string))))
+ (equal content1 content2)))
+
+(defun matlab--ts-grammar-setup ()
+ "Tell Emacs to use the matlab tree-sitter grammar shared library."
+
+ ;; 1. Add '(matlab-mode . matlab-ts-mode) to `major-mode-remap-alist' if
needed.
+ (let* ((remap-alist major-mode-remap-alist)
+ (value (alist-get 'matlab-mode remap-alist)))
+
+ (when (and value
+ (not (eq value 'matlab-ts-mode))) ;; bad value?
+ (setq remap-alist (delq (assoc 'matlab-mode remap-alist) remap-alist))
+ (setq value nil))
+
+ (when (not value)
+ (push '(matlab-mode . matlab-ts-mode) remap-alist)
+ (message "Updating 'major-mode-remap-alist to contain '(matlab-mode .
matlab-ts-mode)")
+ (customize-save-variable 'major-mode-remap-alist remap-alist)))
+
+ ;; 2. Add ("matlab" . "matlab-ts") to org-src-lang-modes
+ (let* ((lang-modes org-src-lang-modes)
+ (value (alist-get "matlab" lang-modes nil nil 'equal)))
+
+ (when (and value
+ (not (string= value "matlab-ts-mode"))) ;; bad value?
+ (setq lang-modes (delq (assoc "matlab" lang-modes) lang-modes))
+ (setq value nil))
+
+ (when (not value)
+ (push '("matlab" . "matlab-ts") lang-modes)
+ (message "Updating 'major-mode-remap-alist to contain '(\"matlab\" .
\"matlab-ts\")")
+ (customize-save-variable 'org-src-lang-modes lang-modes))))
+
;;;###autoload
-(defun matlab-ts-grammar-install (&optional dir branch)
- "Download the latest matlab tree-sitter grammar build to DIR.
+(defun matlab-ts-grammar-install (arg)
+ "Download the matlab tree-sitter grammar shared library.
-Optional BRANCH defaults to \"default\".
+Download libtree-sitter-matlab.SLIB-EXT (SLIB-EXT = so on Linux, dll on
+Windows, or dylib on Mac) from the matlab-ts-bin directory in
+https://github.com/mathworks/Emacs-MATLAB-Mode
-This will create
- DIR/libtree-sitter-matlab.SLIB-EXT
-shared libraries where SLIB-EXT = so on Linux, dll on Windows, or dylib on Mac.
+The matlab tree-sitter grammar shared library is required for
+`matlab-ts-mode'.
-DIR defaults to tree-sitter subdirectory of `user-emacs-directory' which is
-typically ~/.emacs.d/tree-sitter/.
+With prefix ARG, prompt for
-The matlab tree-sitter grammar is required for `matlab-ts-mode'."
+ - DIR to place libtree-sitter-matlab.SLIB.EXT. This defaults to the
+ tree-sitter subdirectory of `user-emacs-directory' which is typically
+ ~/.emacs.d/tree-sitter/.
- (interactive)
+ - BRANCH in https://github.com/mathworks/Emacs-MATLAB-Mode. This defaults
+ to the \"default\" branch.
- (when (< emacs-major-version 30)
- (error "Unsupported Emacs version, %d" emacs-major-version))
-
- (when (not branch)
- (setq branch "default"))
-
- (if (not dir)
- (progn
- (setq dir (concat user-emacs-directory "tree-sitter"))
- (when (not (file-directory-p dir))
- (make-directory dir t)))
- ;; Else dir was provided and it must exist
- (when (not (file-directory-p dir))
- (error "%s is not an existing directory" dir)))
+ - VERSION of the shared library to download. This defaults to the latest
+ version.
- (setq dir (file-name-as-directory (file-truename dir)))
+When libtree-sitter-matlab.SLIB-EXT already exists on your system,
- (let* ((download-url (matlab--ts-grammar-download-url branch))
- (grammar-slib (concat dir (file-name-nondirectory download-url))))
- (when (y-or-n-p (format "Download %s\nto %s/? " download-url grammar-slib))
- (url-copy-file download-url grammar-slib t)
- (message "Downloaded %s" grammar-slib))))
+ - If it is up-to-date, it will not be touched and a message is displayed
+ that it is up-to-date.
+
+ - If it is out-of-date, it will be updated and you will be prompted
+ to restart Emacs so the new library can be used."
+
+ (interactive "P")
+
+ (when (< emacs-major-version 30)
+ (user-error "Unsupported Emacs version, %d" emacs-major-version))
+
+ (let* ((branch-default "default")
+ (branch (if arg
+ (let ((ans ""))
+ (while (string= ans "")
+ (setq ans (string-trim (read-string "Branch: "
branch-default))))
+ ans)
+ branch-default))
+ (dir-default (concat user-emacs-directory "tree-sitter/"))
+ (dir (if arg
+ (let ((ans ""))
+ (while (string= ans "")
+ (setq ans (read-directory-name "Download directory: "
dir-default)))
+ ans)
+ dir-default)))
+
+ (if (string= dir dir-default)
+ (when (not (file-directory-p dir))
+ (make-directory dir t))
+ (when (not (file-directory-p dir))
+ (user-error "%s is not an existing directory" dir)))
+
+ (setq dir (file-name-as-directory (file-truename dir)))
+
+ (let* ((download-url (matlab--ts-grammar-download-url branch arg))
+ (grammar-slib-base (file-name-nondirectory download-url))
+ (grammar-slib (concat dir grammar-slib-base))
+ (grammar-slib-tmp (concat grammar-slib ".tmp")))
+
+ (when (y-or-n-p (format "Download %s\nto %s? " download-url
grammar-slib))
+
+ (url-copy-file download-url grammar-slib-tmp t)
+
+ (let (update-type)
+ (if (not (file-exists-p grammar-slib))
+ (setq update-type 'downloaded)
+ (if (matlab--files-equal-p grammar-slib grammar-slib-tmp)
+ (message "%s is already up-to-date and thus was not updated"
grammar-slib)
+ (setq update-type 'downloaded-and-updated)))
+
+ (if (not update-type)
+ (delete-file grammar-slib-tmp)
+ ;; Update grammar-slib
+ (rename-file grammar-slib-tmp grammar-slib t)
+
+ ;; Tell Emacs to use matlab-ts-mode for *.m files and matlab
org-mode source blocks
+ (matlab--ts-grammar-setup)
+
+ (pcase update-type
+ ('downloaded
+ (message "Downloaded %s" grammar-slib))
+ ('downloaded-and-updated
+ (let ((prompt (concat "Downloaded and updated " grammar-slib
"\n"
+ "If the older " grammar-slib-base
+ " was in use, Emacs must be restarted.\n"
+ "Exit Emacs? ")))
+ (when (y-or-n-p prompt)
+ (save-buffers-kill-terminal))))
+ (_
+ (error "Assert - invalid update-type %S" update-type)))))))))
(provide 'matlab-ts-grammar-install)
;;; matlab-ts-grammar-install.el ends here
-
+;; LocalWords: libtree dylib defun SLIB pcase darwin aarch maca linux nt buf
cadr alist YYYYMMDD
+;; LocalWords: SHA setq slib truename nondirectory tmp delq lang repeat:nil