branch: externals/matlab-mode commit 9773232626919a6319e3ac36bc7e0cdd99c46585 Author: John Ciolfi <john.ciolfi...@gmail.com> Commit: John Ciolfi <john.ciolfi...@gmail.com>
matlab-shell: improve matlab-shell-command handling matlab-shell.el: - When matlab-shell-command is set to "matlab" we now 1. Look for matlab on the system path. 2. If not on the system path, we look for matlab in the default install locations - If unable to find the matlab command executable a more informative error is now produced. A *matlab-shell-help* window will appear giving options to provide the location of matlab. mlint.el: - In mlint-reset-program, set program to nil if we do not have matlabroot DEBUGGING.org: - fixed typo See: https://github.com/mathworks/Emacs-MATLAB-Mode/issues/26 --- DEBUGGING.org | 6 +-- matlab-shell.el | 133 ++++++++++++++++++++++++++++++++++++++++++++++++-------- mlint.el | 37 ++++++++-------- 3 files changed, 136 insertions(+), 40 deletions(-) diff --git a/DEBUGGING.org b/DEBUGGING.org index 1f6162f201..53f2aeded7 100644 --- a/DEBUGGING.org +++ b/DEBUGGING.org @@ -8,13 +8,13 @@ To isolate problems, it's often good to run stock Emacs with matlab-mode: #+begin_src bash - # In /path/to/Emacs-MATLAB-mode + # In /path/to/Emacs-MATLAB-Mode make clean make lisp # Build only. If you want to build and run tests remove the lisp target # From anywhere echo "% empty" > startup.m - M=/path/to/Emacs-MATLAB-mode + M=/path/to/Emacs-MATLAB-Mode env MATLABPATH= emacs -Q -L $M -l $M/matlab-autoload.el # If you want to run a specific version of MATLAB, /matlab-install/bin/matlab: @@ -29,7 +29,7 @@ variable. This ensures you are running MATLAB with an unaltered environment. Pro matlab-shell can occur when either MATLABPATH or startup.m is altering the behavior of MATLAB. Therefore, if you see problems, try running with an unaltered environment. -If you open *.m you will be using the matlab-mode from /path/to/Emacs-MATLAB-mode. +If you open *.m you will be using the matlab-mode from /path/to/Emacs-MATLAB-Mode. To run MATLAB in Emacs: diff --git a/matlab-shell.el b/matlab-shell.el index ecd507b883..89432b4dc7 100644 --- a/matlab-shell.el +++ b/matlab-shell.el @@ -58,8 +58,22 @@ "List of functions to call on entry to MATLAB shell mode." :type 'hook) +(defvar matlab-shell--default-command + '((gnu/linux . "/usr/local/MATLAB/R*/bin/matlab") + (darwin . "/Applications/MATLAB_R*.app/bin/matlab") + (windows-nt . "C:/Program Files/MATLAB/R*/bin/matlab.exe")) + "Standard MATLAB command installation locations, SYSTEM => GLOB.") + (defcustom matlab-shell-command "matlab" - "The name of the command to be run which will start the MATLAB process." + "The MATLAB command executable used to start MATLAB. +This can be: + - the name of the MATLAB command (e.g. \"matlab\") which is + found on the system PATH. + - an absolute path to the matlab executable. For example, + \"/<path-to-MATLAB-install-dir>/bin/matlab\" +If matlab-shell-command is set to \"matlab\" and \"matlab\" is not +on the system PATH, `matlab-shell' will look for the matlab +command executable in the default MATLAB installation locations." :type 'string) (defcustom matlab-shell-command-switches '("-nodesktop") @@ -253,22 +267,101 @@ mode.") matlab-really-gaudy-font-lock-keywords) "Keyword symbol used for really gaudy font-lock for MATLAB shell.") -;;; ROOT +(defun matlab-shell--matlab-not-found (no-help-window &optional default-loc) + "Signal error, MATLAB command not on system PATH or in optional DEFAULT-LOC. +If NO-HELP-WINDOW is t, do not show the help window" + (let ((msg (format "Unable to locate \"%s\" on the system PATH%s" + matlab-shell-command + (if default-loc + (format " or in the default installation location, %s" + default-loc) + "")))) + (when (not no-help-window) + (let ((help-buf-name "*matlab-shell-help*")) + (with-current-buffer (get-buffer-create help-buf-name) + (with-help-window help-buf-name + (insert msg " + +To fix, you update your system PATH to include + \"/<path-to-MATLAB-install>/bin\" +To verify matlab is on your path, run \"matlab -h\" in a terminal. + +Alternatively, you can provide the full path to the +MATLAB command executable by customizing option +`matlab-shell-command'\n"))))) + + (user-error "%s" msg))) + +(cl-defun matlab-shell--abs-matlab-exe (&optional no-error) + "Absolute path to the MATLAB command executable. +When `matlab-shell-command' is an absolute path, then this will +be resolved to its true name. Otherwise, `matlab-shell-command' +is found using `executable-find'. If `matlab-shell-command' is +\"matlab\" and not the system PATH, this will return the latest +MATLAB installed command found using +`matlab-shell--default-command'. + +If NO-ERROR is t, and matlab command is not found, nil is return, +otherwise an error is signaled." + (condition-case err + (let (abs-matlab-exe) + (cond + + ;;Case: the path to the matlab executable was provided, validate it exists and + ;; return the true path. + ((file-name-absolute-p matlab-shell-command) + (when (not (file-exists-p matlab-shell-command)) + (user-error "Invalid setting for `matlab-shell-command', %s does not exist" + matlab-shell-command)) + (when (not (file-executable-p matlab-shell-command)) + (user-error "Invalid setting for `matlab-shell-command', %s is not executable" + matlab-shell-command)) + (setq abs-matlab-exe (file-truename matlab-shell-command))) + + ;; Case: set to a relative path + ;; + ((when (file-name-directory matlab-shell-command) + (user-error "Relative paths are not supported for `matlab-shell-command', %s" + matlab-shell-command))) + + ;; Case: "matlab" (or something similar), locate it on the executable path + ;; else locate in standard install locations. + (t + (setq abs-matlab-exe (executable-find matlab-shell-command)) + (when (not abs-matlab-exe) + (if (string= matlab-shell-command "matlab") + ;; Get latest matlab command exe from the default installation location. + (let* ((default-loc (cdr (assoc system-type matlab-shell--default-command))) + (default-matlab (when default-loc + (car (last (sort + (file-expand-wildcards default-loc) + #'string<)))))) + (when (not default-matlab) + (matlab-shell--matlab-not-found no-error default-loc)) + (when (not (file-executable-p default-matlab)) + (user-error "%s is not executable" default-matlab)) + (setq abs-matlab-exe default-matlab)) + ;; else unable to locate it + (matlab-shell--matlab-not-found no-error))))) + + ;; Return existing absolute path to the MATLAB command executable + abs-matlab-exe) + (error (when (not no-error) (error "%s" (error-message-string err)))))) + +;;; ROOT: matlabroot ;; ;;;###autoload (defun matlab-mode-determine-matlabroot () - "Return the MATLABROOT for the `matlab-shell-command'." - (let ((path (file-name-directory matlab-shell-command))) - ;; if we don't have a path, find the MATLAB executable on our path. - (unless path - (setq path (matlab-find-executable-directory matlab-shell-command))) - (when path - ;; When we find the path, we need to massage it to identify where - ;; the M files are that we need for our completion lists. - (if (string-match "/bin/?$" path) - (setq path (substring path 0 (match-beginning 0))))) - path)) - + "Return the MATLABROOT for the `matlab-shell-command'. +The MATLABROOT does not have a trailing slash. +Returns nil if unable to determine the MATLABROOT." + ;; strip "/bin/matlab" from /path/to/matlabroot/bin/matlab + (let ((abs-matlab-exe (matlab-shell--abs-matlab-exe 'no-error))) + (when abs-matlab-exe + (let ((bin-dir (directory-file-name (file-name-directory abs-matlab-exe)))) + ;; matlabroot no slash + (directory-file-name (file-name-directory bin-dir)))))) + ;;; Keymaps & Menus ;; @@ -278,7 +371,7 @@ mode.") (set-keymap-parent km comint-mode-map) ;; We can jump to errors, so take over this keybinding. - ;; FIXME: Shoulw we set `next-error-function' instead? + ;; FIXME: Should we set `next-error-function' instead? ;; https://github.com/mathworks/Emacs-MATLAB-Mode/issues/23 (substitute-key-definition #'next-error #'matlab-shell-last-error km global-map) @@ -499,8 +592,10 @@ Try C-h f matlab-shell RET")) ;; Thx David Chappaz for reminding me about this patch. (let* ((windowid (frame-parameter (selected-frame) 'outer-window-id)) (newvar (concat "WINDOWID=" windowid)) - (process-environment (cons newvar process-environment))) - (apply #'make-comint matlab-shell-buffer-name matlab-shell-command + (process-environment (cons newvar process-environment)) + (abs-matlab-exe (matlab-shell--abs-matlab-exe))) + (message "Running: %s" abs-matlab-exe) + (apply #'make-comint matlab-shell-buffer-name abs-matlab-exe nil matlab-shell-command-switches)) ;; Enable GUD @@ -2502,11 +2597,11 @@ Argument FNAME specifies if we should echo the region to the command line." ;; LocalWords: emacsclient commandline emacsrunregion errorscanning cco defconst defun setq Keymaps ;; LocalWords: keymap subjob kbd emacscd featurep fboundp EDU msbn pc Thx Chappaz windowid tcp lang ;; LocalWords: postoutput capturetext EMACSCAP captext STARTCAP progn eol dbhot erroexamples cdr -;; LocalWords: ENDPT dolist overlaystack mref deref errortext ERRORTXT shellerror Emacsen iq nt +;; LocalWords: ENDPT dolist overlaystack mref deref errortext ERRORTXT shellerror Emacsen iq nt buf ;; LocalWords: auth mlfile emacsinit initcmd nsa ecc ecca clientcmd EMAACSCAP buffname showbuff ;; LocalWords: evalforms Histed pmark memq promptend numchars integerp emacsdocomplete mycmd ba ;; LocalWords: nreverse emacsdocompletion byteswap stringp cbuff mapcar bw FCN's alist substr usr ;; LocalWords: BUILTINFLAG dired bol bobp numberp princ minibuffer fn matlabregex lastcmd notimeout ;; LocalWords: stacktop eltest testme localfcn LF fileref funcall ef ec basec sk nondirectory utils ;; LocalWords: ignoredups boundp edir sexp Fixup mapc emacsrun noshow cnt ellipsis newf bss noselect -;; LocalWords: fname mlx +;; LocalWords: fname mlx xemacs linux darwin truename diff --git a/mlint.el b/mlint.el index ac2b1d94e8..2bfe25a366 100644 --- a/mlint.el +++ b/mlint.el @@ -1,6 +1,6 @@ ;;; mlint.el --- run mlint in a MATLAB buffer -*- lexical-binding: t -*- -;; Copyright (C) 2024 Free Software Foundation, Inc. +;; Copyright (C) 2002-2025 Free Software Foundation, Inc. ;; Author: Eric M. Ludlam <elud...@mathworks.com> ;; Maintainer: Eric M. Ludlam <elud...@mathworks.com> @@ -129,23 +129,24 @@ This value can be automatically set by \\=`mlint-programs\\='.") (defun mlint-reset-program () "Reset `mlint-program'." (setq mlint-program - (let* ((root (matlab-mode-determine-matlabroot)) - (bin (expand-file-name "bin" root)) - (mlp mlint-programs) - (ans nil)) - (while (and mlp (not ans)) - (cond ((null (car mlp)) - nil) - ((file-executable-p (car mlp)) - (setq ans (car mlp))) - ((executable-find (car mlp)) - (setq ans (executable-find (car mlp)))) - ;; Use the matlabroot found by matlab-shell - ((file-executable-p (expand-file-name (car mlp) bin)) - (setq ans (expand-file-name (car mlp) bin))) - (t nil)) - (setq mlp (cdr mlp))) - ans))) + (let ((root (matlab-mode-determine-matlabroot))) + (when root + (let ((bin (expand-file-name "bin" root)) + (mlp mlint-programs) + (ans nil)) + (while (and mlp (not ans)) + (cond ((null (car mlp)) + nil) + ((file-executable-p (car mlp)) + (setq ans (car mlp))) + ((executable-find (car mlp)) + (setq ans (executable-find (car mlp)))) + ;; Use the matlabroot found by matlab-shell + ((file-executable-p (expand-file-name (car mlp) bin)) + (setq ans (expand-file-name (car mlp) bin))) + (t nil)) + (setq mlp (cdr mlp))) + ans))))) (defcustom mlint-programs (list "mlint"