Merge the hairycode branch into master. Start testing.
This commit is contained in:
commit
3fbc97b3f2
|
@ -6,6 +6,8 @@
|
||||||
.\#*
|
.\#*
|
||||||
*.orig
|
*.orig
|
||||||
*.rej
|
*.rej
|
||||||
|
*.dat
|
||||||
|
|
||||||
# matlab-load.el is generated
|
# matlab-load.el is generated
|
||||||
matlab-load.el
|
matlab-load.el
|
||||||
|
parse
|
2
Makefile
2
Makefile
|
@ -16,7 +16,7 @@ LOADPATH= ./
|
||||||
LOADDEFS=matlab-load.el
|
LOADDEFS=matlab-load.el
|
||||||
LOADDIRS=.
|
LOADDIRS=.
|
||||||
misc_MISC=ChangeLog ChangeLog.old1 ChangeLog.old2 INSTALL README dl_emacs_support.m
|
misc_MISC=ChangeLog ChangeLog.old1 ChangeLog.old2 INSTALL README dl_emacs_support.m
|
||||||
lisp_LISP=matlab-compat.el matlab.el matlab-shell.el matlab-shell-gud.el matlab-netshell.el matlab-complete.el matlab-cgen.el matlab-publish.el matlab-topic.el mlint.el tlc.el linemark.el matlab-maint.el
|
lisp_LISP=matlab-compat.el matlab-syntax.el matlab-scan.el matlab.el matlab-shell.el matlab-shell-gud.el matlab-netshell.el matlab-complete.el matlab-cgen.el matlab-publish.el matlab-topic.el mlint.el tlc.el linemark.el matlab-maint.el
|
||||||
cedet_LISP=semantic-matlab.el semanticdb-matlab.el srecode-matlab.el cedet-matlab.el company-matlab-shell.el
|
cedet_LISP=semantic-matlab.el semanticdb-matlab.el srecode-matlab.el cedet-matlab.el company-matlab-shell.el
|
||||||
VERSION=4.0
|
VERSION=4.0
|
||||||
DISTDIR=$(top)matlab-emacs-$(VERSION)
|
DISTDIR=$(top)matlab-emacs-$(VERSION)
|
||||||
|
|
138
NEWS.org
138
NEWS.org
|
@ -1,5 +1,141 @@
|
||||||
* Changes and New Features in matlab-emacs
|
* Changes and New Features in matlab-emacs
|
||||||
|
|
||||||
|
** New in 5.0
|
||||||
|
|
||||||
|
*** Syntax tables / Strings and Comments / Font lock
|
||||||
|
|
||||||
|
Command and String syntax handling is now managed using syntax-table customization
|
||||||
|
|
||||||
|
This results in:
|
||||||
|
* More flavors of syntax highlighting around commands and strings, including all of:
|
||||||
|
* strings, unterminated strings, commanddual strings
|
||||||
|
* comments, cellbreak comments, pragma comments, ignored comments, ellipssis
|
||||||
|
* Accurate differentiation between 'char arrays' and "strings" and quoted charts.
|
||||||
|
* Performance improvements for comment/string parsing.
|
||||||
|
|
||||||
|
There is a new shorter 'ignore' comment type that starts with: %^
|
||||||
|
|
||||||
|
In addition, font lock of keywords is now more robust, with keywords not being
|
||||||
|
highlighted when they are not being used in the correct scope.
|
||||||
|
|
||||||
|
*** Syntactic block navigation
|
||||||
|
|
||||||
|
With proper syntax table support now available, built-in emacs commands that depend on
|
||||||
|
sexp now work, such as:
|
||||||
|
* up-list
|
||||||
|
* forward-sexp
|
||||||
|
* kill-sexp
|
||||||
|
* mark-sexp
|
||||||
|
|
||||||
|
In addition, commands that work with defuns now all work correctly, such as:
|
||||||
|
* mark-defun
|
||||||
|
* narrow-to-defun
|
||||||
|
|
||||||
|
All custom commands that used to implement these syntax behaviors have been removed, or
|
||||||
|
had their bindings removed, including:
|
||||||
|
* matlab-beginning-of-command
|
||||||
|
* matlab-end-of-command
|
||||||
|
* matlab-forward-sexp
|
||||||
|
* matlab-backward-sexp
|
||||||
|
* matlab-indent-sexp
|
||||||
|
* matlab-beginning-of-defun
|
||||||
|
* matlab-end-of-defn
|
||||||
|
|
||||||
|
In addition syntactic block navigation is faster, where very large files can now be navigated
|
||||||
|
in fractions of a second that used to take a few minutes.
|
||||||
|
|
||||||
|
*** Support for block validation
|
||||||
|
|
||||||
|
Block navigation now does validation, for example, 'property' keywords should only occur
|
||||||
|
inside a classdef, and 'arguments' keywords should only occur inside a function.
|
||||||
|
|
||||||
|
This means that you can now have variables and functions named 'property' and
|
||||||
|
'arguments' of those words occur outside valid locations.
|
||||||
|
|
||||||
|
*** Indentation
|
||||||
|
|
||||||
|
Indentation performance is greatly improved. Based on our tests, large files that used
|
||||||
|
to take 10 minutes to indent will now complete in just 1 or 2 seconds.
|
||||||
|
|
||||||
|
Several new indentation features exist, such as:
|
||||||
|
* correct indentation of arguemnts blocks
|
||||||
|
* improved indentation of function argument lists that span multiple lines.
|
||||||
|
* improved indentation around block comments
|
||||||
|
* improved indentation accuracy in classdef, property, method blocks.
|
||||||
|
* more accurate indentation of continuations
|
||||||
|
|
||||||
|
Some indentation features were removed, such as:
|
||||||
|
* Max indent distance support inside function call args
|
||||||
|
* Max indent distance support inside switch statements
|
||||||
|
* Line-up rules inside ( ), [ ], and { } have changed subtly dependeing on
|
||||||
|
context after the opening (, [, or {.
|
||||||
|
|
||||||
|
Specialty indentation commands have been removed:
|
||||||
|
* matlab-indent-sexp
|
||||||
|
|
||||||
|
Electric indentation has been added to block keywords such as end, else, case, etc.
|
||||||
|
|
||||||
|
Lots of bug fixes and general improvements for handling edge cases.
|
||||||
|
|
||||||
|
*** matlab-return & friends removed
|
||||||
|
|
||||||
|
The 'matlab-return' and related functions have all been removed. Features of these
|
||||||
|
commands are now part of Emacs' built in handling for RETURN and no longer need to be
|
||||||
|
part of matlab mode.
|
||||||
|
|
||||||
|
*** File type detection
|
||||||
|
|
||||||
|
File type detection has been improved. Previously matlab mode detected if functions had
|
||||||
|
ends, and if functions were indented. It now detects more cases, and displays results
|
||||||
|
in the status line.
|
||||||
|
|
||||||
|
The list of detectable features are:
|
||||||
|
* function (with no end)
|
||||||
|
* function .. end
|
||||||
|
* classdef .. end
|
||||||
|
* scripts
|
||||||
|
* empty files
|
||||||
|
|
||||||
|
Functions with ends also detect if function bodies are indented. Other kinds of
|
||||||
|
functions will always indent.
|
||||||
|
|
||||||
|
The check for the type of file is also auto-re-detected on save, so if you change the
|
||||||
|
type of file while editing, it will automatically adjust.
|
||||||
|
|
||||||
|
*** Auto verify changes
|
||||||
|
|
||||||
|
Auto verify on save has been updated.
|
||||||
|
|
||||||
|
1. verify classname added - this will fix class names for you
|
||||||
|
2. verify add ends - this now asks questions less often, or not at all.
|
||||||
|
In addition, it has a more robust algorithm for adding ends.
|
||||||
|
|
||||||
|
*** mlint support questions
|
||||||
|
|
||||||
|
mlint mode now supports many more auto fix behaviors, including:
|
||||||
|
* missing ends - with nicer guess for where the end goes.
|
||||||
|
* function name - auto fix function, class, and method names.
|
||||||
|
|
||||||
|
Plus several minor bug fixes.
|
||||||
|
|
||||||
|
*** Support for older Emacsen
|
||||||
|
|
||||||
|
Support for Emacs older than Emacs 24 has been dropped. Many of the special
|
||||||
|
compatability layers needed to change, and the new code has not been tested against
|
||||||
|
older versions of Emacs. As a result, many compatability layers were removed.
|
||||||
|
|
||||||
|
*** Test suite improvements
|
||||||
|
|
||||||
|
The test suite that is part of matlab-emacs project has many more test points, and has
|
||||||
|
added support for testing font lock, performance, and other features.
|
||||||
|
|
||||||
|
*** matlab-emacs maintenance mode
|
||||||
|
|
||||||
|
There is now a support file 'matlab-maint' that simplifies the task of building and
|
||||||
|
testing matlab-mode during development. Consider using this library if you intend to
|
||||||
|
develop matlab-mode.
|
||||||
|
|
||||||
|
|
||||||
** News in 4.0
|
** News in 4.0
|
||||||
|
|
||||||
*** Debugging
|
*** Debugging
|
||||||
|
@ -56,7 +192,7 @@ You have the following capabilities when in a MATLAB M-file:
|
||||||
more responsive. For example, in matlab-shell, Emacs is more
|
more responsive. For example, in matlab-shell, Emacs is more
|
||||||
responsive when processing long output lines from MATLAB.
|
responsive when processing long output lines from MATLAB.
|
||||||
|
|
||||||
*** Bug fixex
|
*** Bug fixes
|
||||||
- There are a number of bug fixes.
|
- There are a number of bug fixes.
|
||||||
|
|
||||||
*** Quotes
|
*** Quotes
|
||||||
|
|
|
@ -17,7 +17,7 @@
|
||||||
(ede-proj-target-elisp "ede-proj-target-elisp"
|
(ede-proj-target-elisp "ede-proj-target-elisp"
|
||||||
:name "lisp"
|
:name "lisp"
|
||||||
:path ""
|
:path ""
|
||||||
:source '("matlab-compat.el" "matlab.el" "matlab-shell.el" "matlab-shell-gud.el" "matlab-netshell.el" "matlab-complete.el" "matlab-cgen.el" "matlab-publish.el" "matlab-topic.el" "mlint.el" "tlc.el" "linemark.el" "matlab-maint.el")
|
:source '("matlab-compat.el" "matlab-syntax.el" "matlab-scan.el" "matlab.el" "matlab-shell.el" "matlab-shell-gud.el" "matlab-netshell.el" "matlab-complete.el" "matlab-cgen.el" "matlab-publish.el" "matlab-topic.el" "mlint.el" "tlc.el" "linemark.el" "matlab-maint.el")
|
||||||
:versionsource '("matlab.el")
|
:versionsource '("matlab.el")
|
||||||
:aux-packages '("matlab"))
|
:aux-packages '("matlab"))
|
||||||
(ede-proj-target-elisp "ede-proj-target-elisp"
|
(ede-proj-target-elisp "ede-proj-target-elisp"
|
||||||
|
|
14
linemark.el
14
linemark.el
|
@ -275,7 +275,12 @@ Call the new entrie's activate method."
|
||||||
(oset new-entry face (or face (oref g face)))
|
(oset new-entry face (or face (oref g face)))
|
||||||
(oset g marks (cons new-entry (oref g marks)))
|
(oset g marks (cons new-entry (oref g marks)))
|
||||||
(if (oref g active)
|
(if (oref g active)
|
||||||
(linemark-display new-entry t))
|
(condition-case nil
|
||||||
|
;; Somewhere in the eieio framework this can throw 'end of buffer' error
|
||||||
|
;; after the display function exits. Not sure where that is, but this
|
||||||
|
;; condition-case can capture it and allow things to keep going.
|
||||||
|
(linemark-display new-entry t)
|
||||||
|
(error nil)))
|
||||||
new-entry)
|
new-entry)
|
||||||
))
|
))
|
||||||
|
|
||||||
|
@ -356,7 +361,12 @@ Call the new entrie's activate method."
|
||||||
|
|
||||||
(defun linemark-find-file-hook ()
|
(defun linemark-find-file-hook ()
|
||||||
"Activate all marks which can benifit from this new buffer."
|
"Activate all marks which can benifit from this new buffer."
|
||||||
(mapcar (lambda (g) (linemark-display g t)) linemark-groups))
|
(mapcar (lambda (g) (condition-case nil
|
||||||
|
;; See comment in linemark-add-entry for
|
||||||
|
;; reasoning on this condition-case.
|
||||||
|
(linemark-display g t)
|
||||||
|
(error nil)))
|
||||||
|
linemark-groups))
|
||||||
|
|
||||||
(defun linemark-kill-buffer-hook ()
|
(defun linemark-kill-buffer-hook ()
|
||||||
"Deactivate all entries in the current buffer."
|
"Deactivate all entries in the current buffer."
|
||||||
|
|
|
@ -77,7 +77,9 @@
|
||||||
"Insert and END block based on the current syntax.
|
"Insert and END block based on the current syntax.
|
||||||
Optional argument REINDENT indicates if the specified block should be re-indented."
|
Optional argument REINDENT indicates if the specified block should be re-indented."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
(if (not (matlab-ltype-empty)) (progn (end-of-line) (insert "\n")))
|
(when (not (matlab-line-empty-p (matlab-compute-line-context 1)))
|
||||||
|
(end-of-line) (insert "\n"))
|
||||||
|
|
||||||
(let ((valid t) (begin nil))
|
(let ((valid t) (begin nil))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(condition-case nil
|
(condition-case nil
|
||||||
|
@ -172,7 +174,8 @@ Optional argument REINDENT indicates if the specified block should be re-indente
|
||||||
(error (setq valid nil))))
|
(error (setq valid nil))))
|
||||||
(if (not valid)
|
(if (not valid)
|
||||||
(error "Not in a switch statement")))
|
(error "Not in a switch statement")))
|
||||||
(if (not (matlab-ltype-empty)) (progn (end-of-line) (insert "\n")))
|
(when (not (matlab-line-empty-p (matlab-compute-line-context 1)))
|
||||||
|
(end-of-line) (insert "\n"))
|
||||||
(indent-to 0)
|
(indent-to 0)
|
||||||
(insert "case ")
|
(insert "case ")
|
||||||
(matlab-indent-line))
|
(matlab-indent-line))
|
||||||
|
@ -234,14 +237,16 @@ the region. BEGIN and END mark the region to be stringified."
|
||||||
"Spell check valid strings in region with Ispell.
|
"Spell check valid strings in region with Ispell.
|
||||||
Argument BEGIN and END mark the region boundary."
|
Argument BEGIN and END mark the region boundary."
|
||||||
(interactive "r")
|
(interactive "r")
|
||||||
|
(error "This function needs to be reimplemented.")
|
||||||
(require 'ispell)
|
(require 'ispell)
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char begin)
|
(goto-char begin)
|
||||||
;; Here we use the font lock function for finding strings.
|
;; Here we use the font lock function for finding strings.
|
||||||
;; Its cheap, fast, and accurate.
|
;; Its cheap, fast, and accurate.
|
||||||
;; NOTE: This now also does comments
|
;; NOTE: This now also does comments
|
||||||
(while (and (matlab-font-lock-allstring-comment-match-normal end)
|
;;(while (and (matlab-font-lock-allstring-comment-match-normal end)
|
||||||
(ispell-region (match-beginning 0) (match-end 0))))))
|
;; (ispell-region (match-beginning 0) (match-end 0))))
|
||||||
|
))
|
||||||
|
|
||||||
(defun matlab-ispell-strings-and-comments ()
|
(defun matlab-ispell-strings-and-comments ()
|
||||||
"Spell check valid strings in the current buffer with Ispell.
|
"Spell check valid strings in the current buffer with Ispell.
|
||||||
|
|
|
@ -150,6 +150,11 @@ REGEXP defaults to \"[ \\t\\n\\r]+\"."
|
||||||
out))
|
out))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
;; OBARRAYS
|
||||||
|
(if (fboundp 'obarray-make)
|
||||||
|
(defalias 'matlab-obarray-make 'obarray-make)
|
||||||
|
(defun matlab-obarray-make (sz) (make-vector sz 0)))
|
||||||
|
|
||||||
;; Finding executables
|
;; Finding executables
|
||||||
(defun matlab-find-executable-directory (program)
|
(defun matlab-find-executable-directory (program)
|
||||||
"Find the executable PROGRAM on the exec path, following any links.
|
"Find the executable PROGRAM on the exec path, following any links.
|
||||||
|
|
|
@ -30,7 +30,21 @@
|
||||||
;; and this can be loaded optionally.
|
;; and this can be loaded optionally.
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
(require 'cl-macs)
|
||||||
(require 'matlab)
|
(require 'matlab)
|
||||||
|
(require 'matlab-shell)
|
||||||
|
|
||||||
|
(defun matlab-uniquify-list (lst)
|
||||||
|
"Return a list that is a subset of LST where all elements are unique."
|
||||||
|
(if (fboundp 'cl-remove-duplicates)
|
||||||
|
(cl-remove-duplicates lst :test 'string= :from-end t)
|
||||||
|
;; Else, do it by hand.
|
||||||
|
(let ((nlst nil))
|
||||||
|
(while lst
|
||||||
|
(if (and (car lst) (not (member (car lst) nlst)))
|
||||||
|
(setq nlst (cons (car lst) nlst)))
|
||||||
|
(setq lst (cdr lst)))
|
||||||
|
(nreverse nlst))))
|
||||||
|
|
||||||
;;; Customizations ===========================================================
|
;;; Customizations ===========================================================
|
||||||
;;
|
;;
|
||||||
|
@ -181,9 +195,32 @@ This list still needs lots of help.")
|
||||||
tl (cdr tl)))
|
tl (cdr tl)))
|
||||||
r))
|
r))
|
||||||
|
|
||||||
|
(defun matlab-lattr-semantics (&optional prefix)
|
||||||
|
"Return the semantics of the current position.
|
||||||
|
Values are nil 'solo, 'value, and 'boolean. Boolean is a subset of
|
||||||
|
value. nil means there is no semantic content (ie, string or comment.)
|
||||||
|
If optional PREFIX, then return 'solo if that is the only thing on the
|
||||||
|
line."
|
||||||
|
(cond
|
||||||
|
((or (matlab-line-empty-p (matlab-compute-line-context 1))
|
||||||
|
(and prefix (save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
(looking-at (concat "\\s-*" prefix "\\s-*$")))))
|
||||||
|
'solo)
|
||||||
|
((save-excursion
|
||||||
|
(matlab-beginning-of-command)
|
||||||
|
(looking-at "\\s-*\\(if\\|elseif\\|while\\)\\>"))
|
||||||
|
'boolean)
|
||||||
|
((save-excursion
|
||||||
|
(matlab-beginning-of-command)
|
||||||
|
(looking-at (concat "\\s-*\\(" (matlab-property-function)
|
||||||
|
"\\)\\>")))
|
||||||
|
'property)
|
||||||
|
(t
|
||||||
|
'value)))
|
||||||
|
|
||||||
;;; Completion Framework ===================================================
|
;;; Completion Framework ===================================================
|
||||||
;;
|
;;
|
||||||
|
|
||||||
(defun matlab-find-recent-variable-list (prefix)
|
(defun matlab-find-recent-variable-list (prefix)
|
||||||
"Return a list of most recent variables starting with PREFIX as a string.
|
"Return a list of most recent variables starting with PREFIX as a string.
|
||||||
Reverse searches for the following are done first:
|
Reverse searches for the following are done first:
|
||||||
|
@ -211,28 +248,28 @@ If the list is empty, then searches continue backwards through the code."
|
||||||
(nreverse lst)))
|
(nreverse lst)))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(let ((lst nil))
|
(let ((lst nil))
|
||||||
(while (and (re-search-backward
|
(while (and
|
||||||
(concat "\\<\\(" matlab-block-beg-pre-no-if
|
(< (length lst) 10)
|
||||||
"\\)\\s-+(?\\s-*\\(" prefix
|
(matlab-re-search-keyword-backward (matlab-keyword-regex 'ctrl) bounds t))
|
||||||
"\\w+\\)\\>")
|
(when (looking-at (concat "\\w+\\s-+(?\\(" prefix "\\w+\\)\\_>"))
|
||||||
bounds t)
|
(setq lst (cons (match-string 1) lst))))
|
||||||
(< (length lst) 10))
|
|
||||||
(setq lst (cons (match-string 2) lst)))
|
|
||||||
(nreverse lst)))
|
(nreverse lst)))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(if (re-search-backward "^\\s-*global\\s-+" bounds t)
|
(let ((lst nil) m e)
|
||||||
(let ((lst nil) m e)
|
(while (matlab-re-search-keyword-backward
|
||||||
|
(matlab-keyword-regex 'vardecl) bounds t)
|
||||||
|
(save-excursion
|
||||||
(goto-char (match-end 0))
|
(goto-char (match-end 0))
|
||||||
(while (looking-at "\\(\\w+\\)\\([ \t]+\\|$\\)")
|
(while (looking-at "\\s-*\\(\\w+\\)\\([ \t]+\\|$\\)")
|
||||||
(setq m (match-string 1)
|
(setq m (match-string 1)
|
||||||
e (match-end 0))
|
e (match-end 0))
|
||||||
(if (equal 0 (string-match prefix m))
|
(if (equal 0 (string-match prefix m))
|
||||||
(setq lst (cons m lst)))
|
(setq lst (cons m lst)))
|
||||||
(goto-char e))
|
(goto-char e))))
|
||||||
(nreverse lst))))
|
(nreverse lst)))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(if (and (re-search-backward "^\\s-*function\\>" bounds t)
|
(if (and (re-search-backward "^\\s-*function\\>" bounds t)
|
||||||
(re-search-forward "\\<\\(\\w+\\)("
|
(re-search-forward "\\_<\\(\\w+\\)\\s-*("
|
||||||
(matlab-point-at-eol) t))
|
(matlab-point-at-eol) t))
|
||||||
(let ((lst nil) m e)
|
(let ((lst nil) m e)
|
||||||
(while (looking-at "\\(\\w+\\)\\s-*[,)]\\s-*")
|
(while (looking-at "\\(\\w+\\)\\s-*[,)]\\s-*")
|
||||||
|
@ -278,7 +315,7 @@ In NEXT is non-nil, than continue through the list of elements."
|
||||||
(let ((lst nil))
|
(let ((lst nil))
|
||||||
(while (re-search-forward "^\\s-*function\\>" nil t)
|
(while (re-search-forward "^\\s-*function\\>" nil t)
|
||||||
(if (re-search-forward
|
(if (re-search-forward
|
||||||
(concat "\\(" prefix "\\w+\\)\\s-*\\($\\|(\\)")
|
(concat "\\_<\\(" prefix "\\w+\\)\\s-*\\($\\|(\\)")
|
||||||
(matlab-point-at-eol) t)
|
(matlab-point-at-eol) t)
|
||||||
(setq lst (cons (match-string 1) lst))))
|
(setq lst (cons (match-string 1) lst))))
|
||||||
(nreverse lst)))
|
(nreverse lst)))
|
||||||
|
@ -426,7 +463,33 @@ Use `completion-in-region' to support the completion behavior."
|
||||||
(completion-in-region common-substr-start-pt common-substr-end-pt completions)
|
(completion-in-region common-substr-start-pt common-substr-end-pt completions)
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(defun matlab--complete-compute-search-functions (semantics)
|
||||||
|
"Return the search functions for context specified by SEMATNICS."
|
||||||
|
(cond ((eq semantics 'solo)
|
||||||
|
'(matlab-solo-completions
|
||||||
|
matlab-find-user-functions
|
||||||
|
matlab-find-recent-variable))
|
||||||
|
((eq semantics 'boolean)
|
||||||
|
'(matlab-find-recent-variable
|
||||||
|
matlab-boolean-completions
|
||||||
|
matlab-find-user-functions
|
||||||
|
matlab-value-completions))
|
||||||
|
((eq semantics 'value)
|
||||||
|
'(matlab-find-recent-variable
|
||||||
|
matlab-find-user-functions
|
||||||
|
matlab-value-completions
|
||||||
|
matlab-boolean-completions))
|
||||||
|
((eq semantics 'property)
|
||||||
|
'(matlab-property-completions
|
||||||
|
matlab-find-user-functions
|
||||||
|
matlab-find-recent-variable
|
||||||
|
matlab-value-completions))
|
||||||
|
(t '(matlab-find-recent-variable
|
||||||
|
matlab-find-user-functions
|
||||||
|
matlab-value-completions
|
||||||
|
matlab-boolean-completions))))
|
||||||
|
|
||||||
(defun matlab-complete-symbol-local (&optional arg)
|
(defun matlab-complete-symbol-local (&optional arg)
|
||||||
"Complete a partially typed symbol in a MATLAB mode buffer.
|
"Complete a partially typed symbol in a MATLAB mode buffer.
|
||||||
If the previously entered command was also `matlab-complete-symbol'
|
If the previously entered command was also `matlab-complete-symbol'
|
||||||
|
@ -459,29 +522,7 @@ to change it temporarily."
|
||||||
(setq matlab-last-prefix prefix
|
(setq matlab-last-prefix prefix
|
||||||
matlab-last-semantic sem
|
matlab-last-semantic sem
|
||||||
matlab-completion-search-state
|
matlab-completion-search-state
|
||||||
(cond ((eq sem 'solo)
|
(matlab--complete-compute-search-functions sem)))
|
||||||
'(matlab-solo-completions
|
|
||||||
matlab-find-user-functions
|
|
||||||
matlab-find-recent-variable))
|
|
||||||
((eq sem 'boolean)
|
|
||||||
'(matlab-find-recent-variable
|
|
||||||
matlab-boolean-completions
|
|
||||||
matlab-find-user-functions
|
|
||||||
matlab-value-completions))
|
|
||||||
((eq sem 'value)
|
|
||||||
'(matlab-find-recent-variable
|
|
||||||
matlab-find-user-functions
|
|
||||||
matlab-value-completions
|
|
||||||
matlab-boolean-completions))
|
|
||||||
((eq sem 'property)
|
|
||||||
'(matlab-property-completions
|
|
||||||
matlab-find-user-functions
|
|
||||||
matlab-find-recent-variable
|
|
||||||
matlab-value-completions))
|
|
||||||
(t '(matlab-find-recent-variable
|
|
||||||
matlab-find-user-functions
|
|
||||||
matlab-value-completions
|
|
||||||
matlab-boolean-completions)))))
|
|
||||||
(cond
|
(cond
|
||||||
((eq matlab-completion-technique 'increment)
|
((eq matlab-completion-technique 'increment)
|
||||||
(let ((r nil) (donext (eq last-command 'matlab-complete-symbol)))
|
(let ((r nil) (donext (eq last-command 'matlab-complete-symbol)))
|
||||||
|
|
|
@ -24,6 +24,8 @@
|
||||||
(require 'matlab)
|
(require 'matlab)
|
||||||
(require 'matlab-shell)
|
(require 'matlab-shell)
|
||||||
(require 'matlab-netshell)
|
(require 'matlab-netshell)
|
||||||
|
(require 'semantic/symref)
|
||||||
|
(require 'semantic/symref/list)
|
||||||
|
|
||||||
;;; Code:
|
;;; Code:
|
||||||
|
|
||||||
|
@ -31,8 +33,14 @@
|
||||||
;;
|
;;
|
||||||
(defvar matlab-maint-mode-map
|
(defvar matlab-maint-mode-map
|
||||||
(let ((km (make-sparse-keymap)))
|
(let ((km (make-sparse-keymap)))
|
||||||
|
;; compile debug cycle
|
||||||
(define-key km [f8] 'matlab-maint-run-tests)
|
(define-key km [f8] 'matlab-maint-run-tests)
|
||||||
(define-key km [f9] 'matlab-maint-compile-matlab-emacs)
|
(define-key km [f9] 'matlab-maint-compile-matlab-emacs)
|
||||||
|
(define-key km [f10] 'matlab-maint-reload-mode)
|
||||||
|
;; coding
|
||||||
|
(define-key km [f7] 'matlab-maint-symref-this)
|
||||||
|
;; matlab
|
||||||
|
(define-key km [f5] 'matlab-maint-show-info)
|
||||||
km)
|
km)
|
||||||
"Keymap used by matlab mode maintainers.")
|
"Keymap used by matlab mode maintainers.")
|
||||||
|
|
||||||
|
@ -67,7 +75,35 @@
|
||||||
(matlab-maint-minor-mode 1))))
|
(matlab-maint-minor-mode 1))))
|
||||||
)
|
)
|
||||||
|
|
||||||
;;; Commands
|
;;; Testing stuff in M buffers
|
||||||
|
;;
|
||||||
|
(defun matlab-maint-show-info ()
|
||||||
|
"Show info about line in current matlab buffer."
|
||||||
|
(interactive)
|
||||||
|
(when (eq major-mode 'matlab-mode)
|
||||||
|
(matlab-show-line-info)
|
||||||
|
))
|
||||||
|
|
||||||
|
;;; HACKING ELISP
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defun matlab-maint-symref-this ()
|
||||||
|
"Open a symref buffer on symbol under cursor."
|
||||||
|
(interactive)
|
||||||
|
(save-buffer)
|
||||||
|
(semantic-fetch-tags)
|
||||||
|
(let ((ct (semantic-current-tag)))
|
||||||
|
;; Must have a tag...
|
||||||
|
(when (not ct) (error "Place cursor inside tag to be searched for"))
|
||||||
|
;; Gather results and tags
|
||||||
|
(message "Gathering References for %s.." (semantic-tag-name ct))
|
||||||
|
(let* ((name (semantic-tag-name ct))
|
||||||
|
(res (semantic-symref-find-references-by-name name)))
|
||||||
|
(semantic-symref-produce-list-on-results res name)
|
||||||
|
(semantic-symref-list-expand-all) )))
|
||||||
|
|
||||||
|
|
||||||
|
;;; COMPILE AND TEST
|
||||||
;;
|
;;
|
||||||
;; Helpful commands for maintainers.
|
;; Helpful commands for maintainers.
|
||||||
(defcustom matlab-maint-compile-opts '("emacs" "emacs24" "emacs25" "emacs26")
|
(defcustom matlab-maint-compile-opts '("emacs" "emacs24" "emacs25" "emacs26")
|
||||||
|
@ -112,6 +148,8 @@
|
||||||
"Run the tests for matlab mode.
|
"Run the tests for matlab mode.
|
||||||
With universal ARG, ask for the code to be run with output tracking turned on."
|
With universal ARG, ask for the code to be run with output tracking turned on."
|
||||||
(interactive "P")
|
(interactive "P")
|
||||||
|
(when (buffer-file-name)
|
||||||
|
(save-buffer))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(matlab-maint-set-buffer-to "tests/Makefile")
|
(matlab-maint-set-buffer-to "tests/Makefile")
|
||||||
(if (or arg matlab-shell-io-testing)
|
(if (or arg matlab-shell-io-testing)
|
||||||
|
@ -123,6 +161,21 @@ With universal ARG, ask for the code to be run with output tracking turned on."
|
||||||
(delete-other-windows)
|
(delete-other-windows)
|
||||||
(goto-char (point-max)))
|
(goto-char (point-max)))
|
||||||
|
|
||||||
|
(defun matlab-maint-reload-mode ()
|
||||||
|
"Reload matlab mode, and refresh displayed ML buffers modes."
|
||||||
|
(interactive)
|
||||||
|
(load-library "matlab-syntax")
|
||||||
|
(load-library "matlab-scan")
|
||||||
|
(load-library "matlab")
|
||||||
|
(mapc (lambda (b) (with-current-buffer b
|
||||||
|
(when (eq major-mode 'matlab-mode)
|
||||||
|
(message "Updating matlab mode in %S" b)
|
||||||
|
(matlab-mode))))
|
||||||
|
(buffer-list (selected-frame)))
|
||||||
|
(message "loading done")
|
||||||
|
)
|
||||||
|
;;; MATLAB SHELL tools
|
||||||
|
;;
|
||||||
|
|
||||||
(defun matlab-maint-set-buffer-to (file)
|
(defun matlab-maint-set-buffer-to (file)
|
||||||
"Set the current buffer to FILE found in matlab-mode's source.
|
"Set the current buffer to FILE found in matlab-mode's source.
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -89,7 +89,6 @@ Disable this option if the tooltips are too slow in your setup."
|
||||||
;; (gud-def gud-print "% gud-print not available" "\C-p" "gud-print not available.")
|
;; (gud-def gud-print "% gud-print not available" "\C-p" "gud-print not available.")
|
||||||
|
|
||||||
(when window-system
|
(when window-system
|
||||||
(matlab-frame-init)
|
|
||||||
|
|
||||||
(setq gud-matlab-tool-bar-map
|
(setq gud-matlab-tool-bar-map
|
||||||
(let ((map (make-sparse-keymap)))
|
(let ((map (make-sparse-keymap)))
|
||||||
|
@ -373,10 +372,10 @@ LONGESTNAME specifies the how long the longest name we can expect is."
|
||||||
"Specify a NEWSTACK provided by MATLAB to replace the old one."
|
"Specify a NEWSTACK provided by MATLAB to replace the old one."
|
||||||
(setq mlg-stack nil)
|
(setq mlg-stack nil)
|
||||||
(dolist (L newstack)
|
(dolist (L newstack)
|
||||||
(push (mlg-stack-frame ""
|
(push (make-instance 'mlg-stack-frame
|
||||||
:file (nth 0 L)
|
:file (nth 0 L)
|
||||||
:name (nth 1 L)
|
:name (nth 1 L)
|
||||||
:line (nth 2 L))
|
:line (nth 2 L))
|
||||||
mlg-stack))
|
mlg-stack))
|
||||||
(setq mlg-stack (nreverse mlg-stack))
|
(setq mlg-stack (nreverse mlg-stack))
|
||||||
(mlg-refresh-stack-buffer)
|
(mlg-refresh-stack-buffer)
|
||||||
|
@ -598,9 +597,10 @@ LONGESTNAME specifies the how long the longest name we can expect is."
|
||||||
(setq found t)))
|
(setq found t)))
|
||||||
(when (not found)
|
(when (not found)
|
||||||
(setq matlab-gud-visible-breakpoints
|
(setq matlab-gud-visible-breakpoints
|
||||||
(cons (mlg-breakpoint "" :file file
|
(cons (make-instance 'mlg-breakpoint
|
||||||
:name fcn
|
:file file
|
||||||
:line line)
|
:name fcn
|
||||||
|
:line line)
|
||||||
matlab-gud-visible-breakpoints))
|
matlab-gud-visible-breakpoints))
|
||||||
(mlg-activate (car matlab-gud-visible-breakpoints))
|
(mlg-activate (car matlab-gud-visible-breakpoints))
|
||||||
))
|
))
|
||||||
|
|
113
matlab-shell.el
113
matlab-shell.el
|
@ -204,10 +204,27 @@ If multiple prompts are seen together, only call this once.")
|
||||||
;;; Font Lock
|
;;; Font Lock
|
||||||
;;
|
;;
|
||||||
;; Extra font lock keywords for the MATLAB shell.
|
;; Extra font lock keywords for the MATLAB shell.
|
||||||
(defvar matlab-shell-font-lock-keywords
|
(defconst matlab-shell-font-lock-keywords
|
||||||
|
(list
|
||||||
|
;; How about Errors?
|
||||||
|
'("^\\(Error in\\|Syntax error in\\)\\s-+==>\\s-+\\(.+\\)$"
|
||||||
|
(1 font-lock-comment-face) (2 font-lock-string-face))
|
||||||
|
;; and line numbers
|
||||||
|
'("^\\(\\(On \\)?line [0-9]+\\)" 1 font-lock-comment-face)
|
||||||
|
;; 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.")
|
||||||
|
|
||||||
|
(defconst matlab-shell-object-output-font-lock-keywords
|
||||||
(list
|
(list
|
||||||
;; Startup notices
|
;; Startup notices
|
||||||
;; Various notices
|
|
||||||
'(" M A T L A B " 0 'underline)
|
'(" M A T L A B " 0 'underline)
|
||||||
'("All Rights Reserved" 0 'italic)
|
'("All Rights Reserved" 0 'italic)
|
||||||
'("\\(\\(?:(c)\\)?\\s-+Copyright[^\n]+\\)" 1 font-lock-comment-face)
|
'("\\(\\(?:(c)\\)?\\s-+Copyright[^\n]+\\)" 1 font-lock-comment-face)
|
||||||
|
@ -218,33 +235,38 @@ If multiple prompts are seen together, only call this once.")
|
||||||
'("^To get started, type doc.$" 0 font-lock-comment-face prepend)
|
'("^To get started, type doc.$" 0 font-lock-comment-face prepend)
|
||||||
'("For product information, [^\n]+" 0 font-lock-comment-face)
|
'("For product information, [^\n]+" 0 font-lock-comment-face)
|
||||||
|
|
||||||
;; How about Errors?
|
|
||||||
'("^\\(Error in\\|Syntax error in\\)\\s-+==>\\s-+\\(.+\\)$"
|
|
||||||
(1 font-lock-comment-face) (2 font-lock-string-face))
|
|
||||||
;; and line numbers
|
|
||||||
'("^\\(\\(On \\)?line [0-9]+\\)" 1 font-lock-comment-face)
|
|
||||||
;; User beep things
|
|
||||||
'("\\(\\?\\?\\?[^\n]+\\)" 1 font-lock-comment-face)
|
|
||||||
;; Useful user commands, but not useful programming constructs
|
;; Useful user commands, but not useful programming constructs
|
||||||
'("\\<\\(demo\\|whatsnew\\|info\\|subscribe\\|help\\|doc\\|lookfor\\|what\
|
'("\\<\\(demo\\|whatsnew\\|info\\|subscribe\\|help\\|doc\\|lookfor\\|what\
|
||||||
\\|whos?\\|cd\\|clear\\|load\\|save\\|helpdesk\\|helpwin\\)\\>"
|
\\|whos?\\|cd\\|clear\\|load\\|save\\|helpdesk\\|helpwin\\)\\>"
|
||||||
1 font-lock-keyword-face)
|
1 font-lock-keyword-face)
|
||||||
|
;; disp of objects usually looks like this:
|
||||||
|
'("^\\s-*\\(\\w+\\) with properties:" (1 font-lock-type-face))
|
||||||
|
;; object output - highlight property names after 'with properties:' indicator
|
||||||
|
;; NOTE: Normally a block like this would require us to use `font-lock-multiline' feature
|
||||||
|
;; but since this is shell output, and not a thing you edit, we can skip it and rely
|
||||||
|
;; on matlab-shell dumping the text as a unit.
|
||||||
|
'("^\\s-*\\(\\w+ with properties:\\)\n\\s-*\n"
|
||||||
|
("^\\s-*\\(\\w+\\):[^\n]+$" ;; match the property before the :
|
||||||
|
;; Extend search region across lines.
|
||||||
|
(save-excursion (re-search-forward "\n\\s-*\n" nil t)
|
||||||
|
(beginning-of-line)
|
||||||
|
(point))
|
||||||
|
nil
|
||||||
|
(1 font-lock-variable-name-face)))
|
||||||
|
'("[[{]\\([0-9]+\\(?:x[0-9]+\\)+ \\w+\\)[]}]" (1 font-lock-comment-face))
|
||||||
)
|
)
|
||||||
"Additional keywords used by MATLAB when reporting errors in interactive\
|
"Highlight various extra outputs that are typical for MATLAB.")
|
||||||
mode.")
|
|
||||||
|
|
||||||
(defvar matlab-shell-font-lock-keywords-1
|
(defconst matlab-shell-font-lock-keywords-2
|
||||||
(append matlab-font-lock-keywords matlab-shell-font-lock-keywords)
|
(append matlab-shell-font-lock-keywords-1
|
||||||
"Keyword symbol used for font-lock mode.")
|
matlab-function-font-lock-keywords
|
||||||
|
matlab-shell-object-output-font-lock-keywords)
|
||||||
|
"Keyword symbol used for gaudy font-lock for MATLAB shell.")
|
||||||
|
|
||||||
(defvar matlab-shell-font-lock-keywords-2
|
(defconst matlab-shell-font-lock-keywords-3
|
||||||
(append matlab-shell-font-lock-keywords-1 matlab-gaudy-font-lock-keywords)
|
|
||||||
"Keyword symbol used for gaudy font-lock symbols.")
|
|
||||||
|
|
||||||
(defvar matlab-shell-font-lock-keywords-3
|
|
||||||
(append matlab-shell-font-lock-keywords-2
|
(append matlab-shell-font-lock-keywords-2
|
||||||
matlab-really-gaudy-font-lock-keywords)
|
matlab-really-gaudy-font-lock-keywords)
|
||||||
"Keyword symbol used for really gaudy font-lock symbols.")
|
"Keyword symbol used for really gaudy font-lock for MATLAB shell.")
|
||||||
|
|
||||||
;;; ROOT
|
;;; ROOT
|
||||||
;;
|
;;
|
||||||
|
@ -1575,16 +1597,9 @@ Snatched and hacked from dired-x.el"
|
||||||
(search-forward-regexp comint-prompt-regexp)
|
(search-forward-regexp comint-prompt-regexp)
|
||||||
(buffer-substring (point) (matlab-point-at-eol)))))
|
(buffer-substring (point) (matlab-point-at-eol)))))
|
||||||
(save-excursion
|
(save-excursion
|
||||||
;; In matlab buffer, find all the text for a command.
|
(buffer-substring-no-properties
|
||||||
;; so back over until there is no more continuation.
|
(matlab-scan-beginning-of-command)
|
||||||
(while (save-excursion (forward-line -1) (matlab-lattr-cont))
|
(matlab-scan-end-of-command)))))
|
||||||
(forward-line -1))
|
|
||||||
;; Go forward till there is no continuation
|
|
||||||
(beginning-of-line)
|
|
||||||
(let ((start (point)))
|
|
||||||
(while (matlab-lattr-cont) (forward-line 1))
|
|
||||||
(end-of-line)
|
|
||||||
(buffer-substring start (point))))))
|
|
||||||
|
|
||||||
(defun matlab-non-empty-lines-in-string (str)
|
(defun matlab-non-empty-lines-in-string (str)
|
||||||
"Return number of non-empty lines in STR."
|
"Return number of non-empty lines in STR."
|
||||||
|
@ -2164,7 +2179,13 @@ Similar to `comint-send-input'."
|
||||||
))
|
))
|
||||||
|
|
||||||
;; If not changing dir, maybe we need to use 'run' command instead?
|
;; If not changing dir, maybe we need to use 'run' command instead?
|
||||||
(let ((cmd (concat "run('" dir fn-name "')")))
|
(let* ((match 0)
|
||||||
|
(tmp (while (setq match (string-match "'" param match))
|
||||||
|
(setq param (replace-match "''" t t param))
|
||||||
|
(setq match (+ 2 match))))
|
||||||
|
(cmd (concat "emacsrun('" dir fn-name "'"
|
||||||
|
(if (string= param "") "" (concat ", '" param "'"))
|
||||||
|
")")))
|
||||||
(matlab-shell-send-command cmd)))
|
(matlab-shell-send-command cmd)))
|
||||||
))))
|
))))
|
||||||
|
|
||||||
|
@ -2175,20 +2196,22 @@ Similar to `comint-send-input'."
|
||||||
(defun matlab-shell-run-cell ()
|
(defun matlab-shell-run-cell ()
|
||||||
"Run the cell the cursor is in."
|
"Run the cell the cursor is in."
|
||||||
(interactive)
|
(interactive)
|
||||||
(let ((start (save-excursion (forward-page -1)
|
(let ((start (save-excursion
|
||||||
(if (looking-at "function")
|
(forward-page -1)
|
||||||
(error "You are not in a cell. Try `matlab-shell-save-and-go' instead"))
|
(if (looking-at "function")
|
||||||
(when (matlab-ltype-comm)
|
(error "You are not in a cell. Try `matlab-shell-save-and-go' instead"))
|
||||||
;; Skip over starting comment from the current cell.
|
(when (matlab-line-comment-p (matlab-compute-line-context 1))
|
||||||
(matlab-end-of-command 1)
|
;; Skip over starting comment from the current cell.
|
||||||
(end-of-line)
|
(matlab-end-of-command)
|
||||||
(forward-char 1))
|
(end-of-line)
|
||||||
(point)))
|
(forward-char 1))
|
||||||
(end (save-excursion (forward-page 1)
|
(point)))
|
||||||
(when (matlab-ltype-comm)
|
(end (save-excursion
|
||||||
(beginning-of-line)
|
(forward-page 1)
|
||||||
(forward-char -1))
|
(when (matlab-line-comment-p (matlab-compute-line-context 1))
|
||||||
(point))))
|
(beginning-of-line)
|
||||||
|
(forward-char -1))
|
||||||
|
(point))))
|
||||||
(matlab-shell-run-region start end t)))
|
(matlab-shell-run-region start end t)))
|
||||||
|
|
||||||
(defun matlab-shell-run-region-or-line ()
|
(defun matlab-shell-run-region-or-line ()
|
||||||
|
|
|
@ -0,0 +1,573 @@
|
||||||
|
;;; matlab-syntax.el --- Manage MATLAB syntax tables and buffer parsing.
|
||||||
|
;;
|
||||||
|
;; Copyright (C) 2021 Eric Ludlam
|
||||||
|
;;
|
||||||
|
;; Author: <eludlam@mathworks.com>
|
||||||
|
;;
|
||||||
|
;; 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 of the
|
||||||
|
;; License, 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 this program. If not, see https://www.gnu.org/licenses/.
|
||||||
|
|
||||||
|
;;; Commentary:
|
||||||
|
;;
|
||||||
|
;; Manage syntax handling for `matlab-mode'.
|
||||||
|
;; Matlab's syntax for comments and strings can't be handled by a standard
|
||||||
|
;; Emacs syntax table. This code handles the syntax table, and special
|
||||||
|
;; scanning needed to augment a buffer's syntax for all our special cases.
|
||||||
|
;;
|
||||||
|
;; This file also handles all the special parsing needed to support indentation,
|
||||||
|
;; block scanning, and the line.
|
||||||
|
|
||||||
|
(require 'matlab-compat)
|
||||||
|
|
||||||
|
;;; Code:
|
||||||
|
(defvar matlab-syntax-support-command-dual t
|
||||||
|
"Non-nil means to support command dual for indenting and syntax highlight.
|
||||||
|
Does not work well in classes with properties with datatypes.")
|
||||||
|
(make-variable-buffer-local 'matlab-syntax-support-command-dual)
|
||||||
|
(put 'matlab-syntax-support-command-dual 'safe-local-variable #'booleanp)
|
||||||
|
|
||||||
|
|
||||||
|
(defvar matlab-syntax-table
|
||||||
|
(let ((st (make-syntax-table (standard-syntax-table))))
|
||||||
|
;; Comment Handling:
|
||||||
|
;; Multiline comments: %{ text %}
|
||||||
|
;; Single line comments: % text (single char start)
|
||||||
|
;; Ellipsis omments: ... text (comment char is 1st char after 3rd dot)
|
||||||
|
;; ^ handled in `matlab--syntax-propertize'
|
||||||
|
(modify-syntax-entry ?% "< 13" st)
|
||||||
|
(modify-syntax-entry ?{ "(} 2c" st)
|
||||||
|
(modify-syntax-entry ?} "){ 4c" st)
|
||||||
|
(modify-syntax-entry ?\n ">" st)
|
||||||
|
|
||||||
|
;; String Handling:
|
||||||
|
;; Character vector: 'text'
|
||||||
|
;; String: "text"
|
||||||
|
;; These next syntaxes are handled with `matlab--syntax-propertize'
|
||||||
|
;; Transpose: varname'
|
||||||
|
;; Quoted quotes: ' don''t ' or " this "" "
|
||||||
|
;; Unterminated Char V: ' text
|
||||||
|
(modify-syntax-entry ?' "\"" st)
|
||||||
|
(modify-syntax-entry ?\" "\"" st)
|
||||||
|
|
||||||
|
;; Words and Symbols:
|
||||||
|
(modify-syntax-entry ?_ "_" st)
|
||||||
|
|
||||||
|
;; Punctuation:
|
||||||
|
(modify-syntax-entry ?\\ "." st)
|
||||||
|
(modify-syntax-entry ?\t " " st)
|
||||||
|
(modify-syntax-entry ?+ "." st)
|
||||||
|
(modify-syntax-entry ?- "." st)
|
||||||
|
(modify-syntax-entry ?* "." st)
|
||||||
|
(modify-syntax-entry ?/ "." st)
|
||||||
|
(modify-syntax-entry ?= "." st)
|
||||||
|
(modify-syntax-entry ?< "." st)
|
||||||
|
(modify-syntax-entry ?> "." st)
|
||||||
|
(modify-syntax-entry ?& "." st)
|
||||||
|
(modify-syntax-entry ?| "." st)
|
||||||
|
|
||||||
|
;; Parentheticl blocks:
|
||||||
|
;; Note: these are in standard syntax table, repeated here for completeness.
|
||||||
|
(modify-syntax-entry ?\( "()" st)
|
||||||
|
(modify-syntax-entry ?\) ")(" st)
|
||||||
|
(modify-syntax-entry ?\[ "(]" st)
|
||||||
|
(modify-syntax-entry ?\] ")[" st)
|
||||||
|
;;(modify-syntax-entry ?{ "(}" st) - Handled as part of comments
|
||||||
|
;;(modify-syntax-entry ?} "){" st)
|
||||||
|
|
||||||
|
st)
|
||||||
|
"MATLAB syntax table")
|
||||||
|
|
||||||
|
(defvar matlab-navigation-syntax-table
|
||||||
|
(let ((st (copy-syntax-table matlab-syntax-table)))
|
||||||
|
;; Make _ a part of words so we can skip them better
|
||||||
|
(modify-syntax-entry ?_ "w" st)
|
||||||
|
st)
|
||||||
|
"The syntax table used when navigating blocks.")
|
||||||
|
|
||||||
|
(defmacro matlab-navigation-syntax (&rest forms)
|
||||||
|
"Set the current environment for syntax-navigation and execute FORMS."
|
||||||
|
(declare (indent 0))
|
||||||
|
(list 'let '((oldsyntax (syntax-table))
|
||||||
|
(case-fold-search nil))
|
||||||
|
(list 'unwind-protect
|
||||||
|
(list 'progn
|
||||||
|
'(set-syntax-table matlab-navigation-syntax-table)
|
||||||
|
(cons 'progn forms))
|
||||||
|
'(set-syntax-table oldsyntax))))
|
||||||
|
|
||||||
|
(add-hook 'edebug-setup-hook
|
||||||
|
(lambda ()
|
||||||
|
(def-edebug-spec matlab-navigation-syntax def-body)))
|
||||||
|
|
||||||
|
;;; Buffer Scanning for Syntax Table Augmentation
|
||||||
|
;;
|
||||||
|
;; To support all our special syntaxes via syntax-ppss (parse partial
|
||||||
|
;; sexp), we need to scan the buffer for patterns, and then leave
|
||||||
|
;; behind the hints pps needs to do the right thing.
|
||||||
|
;;
|
||||||
|
;; Support is broken up in these functions:
|
||||||
|
;; * matlab--put-char-category - Apply a syntax category to a character
|
||||||
|
;; * matlab--syntax-symbol - Create a syntax category symbol
|
||||||
|
;; * matlab--syntax-propertize - Used as `syntax-propertize-function' for
|
||||||
|
;; doing the buffer scan to augment syntxes.
|
||||||
|
;; * matlab--scan-line-* - Scan for specific types of syntax occurances.
|
||||||
|
|
||||||
|
(defun matlab--put-char-category (pos category)
|
||||||
|
"At character POS, put text CATEGORY."
|
||||||
|
(when (not (eobp))
|
||||||
|
(put-text-property pos (1+ pos) 'category category)
|
||||||
|
(put-text-property pos (1+ pos) 'mcm t))
|
||||||
|
)
|
||||||
|
|
||||||
|
(defmacro matlab--syntax-symbol (symbol syntax doc)
|
||||||
|
"Create a new SYMBOL used as a text property category with SYNTAX."
|
||||||
|
(declare (indent defun))
|
||||||
|
`(progn (defvar ,symbol ,syntax ,doc)
|
||||||
|
(set ',symbol ,syntax) ;; So you can re-eval it.
|
||||||
|
(put ',symbol 'syntax-table ,symbol)
|
||||||
|
))
|
||||||
|
|
||||||
|
(matlab--syntax-symbol matlab--command-dual-syntax '(15 . nil) ;; Generic string
|
||||||
|
"Syntax placed on end-of-line for unterminated strings.")
|
||||||
|
(put 'matlab--command-dual-syntax 'command-dual t) ;; Font-lock cookie
|
||||||
|
|
||||||
|
(matlab--syntax-symbol matlab--unterminated-string-syntax '(15 . nil) ;; Generic string end
|
||||||
|
"Syntax placed on end-of-line for unterminated strings.")
|
||||||
|
(put 'matlab--unterminated-string-syntax 'unterminated t) ;; Font-lock cookie
|
||||||
|
|
||||||
|
(matlab--syntax-symbol matlab--ellipsis-syntax (string-to-syntax "< ") ;; comment char
|
||||||
|
"Syntax placed on ellipsis to treat them as comments.")
|
||||||
|
|
||||||
|
(matlab--syntax-symbol matlab--not-block-comment-syntax (string-to-syntax "(}") ;; Just a regular open brace
|
||||||
|
"Syntax placed on ellipsis to treat them as comments.")
|
||||||
|
|
||||||
|
(defun matlab--syntax-propertize (&optional start end)
|
||||||
|
"Scan region between START and END for unterminated strings.
|
||||||
|
Only scans whole-lines, as MATLAB is a line-based language.
|
||||||
|
If region is not specified, scan the whole buffer.
|
||||||
|
See `matlab--scan-line-for-ellipsis', `matlab--san-line-bad-blockcomment',
|
||||||
|
and `matlab--scan-line-for-unterminated-string' for specific details."
|
||||||
|
(save-match-data ;; avoid 'Syntax Checking transmuted the match-data'
|
||||||
|
(save-excursion
|
||||||
|
;; Scan region, but always expand to beginning of line
|
||||||
|
(goto-char (or start (point-min)))
|
||||||
|
(beginning-of-line)
|
||||||
|
;; Clear old properties
|
||||||
|
(remove-text-properties (point) (save-excursion (goto-char (or end (point-max)))
|
||||||
|
(end-of-line) (point))
|
||||||
|
'(category nil mcm nil))
|
||||||
|
;; Apply properties
|
||||||
|
(while (and (not (>= (point) (or end (point-max)))) (not (eobp)))
|
||||||
|
|
||||||
|
(when matlab-syntax-support-command-dual
|
||||||
|
;; Commandl line dual comes first to prevent wasting time
|
||||||
|
;; in later checks.
|
||||||
|
(beginning-of-line)
|
||||||
|
(when (matlab--scan-line-for-command-dual)
|
||||||
|
(matlab--put-char-category (point) 'matlab--command-dual-syntax)
|
||||||
|
(end-of-line)
|
||||||
|
(matlab--put-char-category (point) 'matlab--command-dual-syntax)
|
||||||
|
))
|
||||||
|
|
||||||
|
;; Multiple ellipsis can be on a line. Find them all
|
||||||
|
(beginning-of-line)
|
||||||
|
(while (matlab--scan-line-for-ellipsis)
|
||||||
|
;; Mark ellipsis as if a comment.
|
||||||
|
(matlab--put-char-category (point) 'matlab--ellipsis-syntax)
|
||||||
|
(forward-char 3)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Multiple invalid block comment starts possible. Find them all
|
||||||
|
(beginning-of-line)
|
||||||
|
(while (matlab--scan-line-bad-blockcomment)
|
||||||
|
;; Mark 2nd char as just open brace, not punctuation.
|
||||||
|
(matlab--put-char-category (point) 'matlab--not-block-comment-syntax)
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Look for an unterminated string. Only one possible per line.
|
||||||
|
(beginning-of-line)
|
||||||
|
(when (matlab--scan-line-for-unterminated-string)
|
||||||
|
;; Mark this one char plus EOL as end of string.
|
||||||
|
(let ((start (point)))
|
||||||
|
(matlab--put-char-category (point) 'matlab--unterminated-string-syntax)
|
||||||
|
(end-of-line)
|
||||||
|
(matlab--put-char-category (point) 'matlab--unterminated-string-syntax)
|
||||||
|
))
|
||||||
|
|
||||||
|
(beginning-of-line)
|
||||||
|
(forward-line 1))
|
||||||
|
)))
|
||||||
|
|
||||||
|
(defconst matlab-syntax-commanddual-functions
|
||||||
|
'("warning" "disp" "cd"
|
||||||
|
;; debug
|
||||||
|
"dbstop" "dbclear"
|
||||||
|
;; Graphics
|
||||||
|
"print" "xlim" "ylim" "zlim" "grid" "hold" "box" "colormap" "axis")
|
||||||
|
"Functions that are commonly used with commandline dual")
|
||||||
|
(defconst matlab-cds-regex (regexp-opt matlab-syntax-commanddual-functions 'symbols))
|
||||||
|
|
||||||
|
(defun matlab--scan-line-for-command-dual (&optional debug)
|
||||||
|
"Scan this line for command line duality strings."
|
||||||
|
;; Note - add \s$ b/c we'll add that syntax to the first letter, and it
|
||||||
|
;; might still be there during an edit!
|
||||||
|
(let ((case-fold-search nil))
|
||||||
|
(when (and (not (nth 9 (syntax-ppss (point))))
|
||||||
|
(looking-at
|
||||||
|
(concat "^\\s-*"
|
||||||
|
matlab-cds-regex
|
||||||
|
"\\s-+\\(\\s$\\|\\w\\|\\s_\\)")))
|
||||||
|
(goto-char (match-beginning 2)))))
|
||||||
|
|
||||||
|
(matlab--syntax-symbol matlab--transpose-syntax '(3 . nil) ;; 3 = symbol
|
||||||
|
"Treat ' as non-string when used as transpose.")
|
||||||
|
|
||||||
|
(matlab--syntax-symbol matlab--quoted-string-syntax '(9 . nil) ;; 9 = escape in a string
|
||||||
|
"Treat '' or \"\" as not string delimeteres when inside a string.")
|
||||||
|
|
||||||
|
(defun matlab--scan-line-for-unterminated-string (&optional debug)
|
||||||
|
"Scan this line for an unterminated string, leave cursor on starting string char."
|
||||||
|
;; First, scan over all the string chars.
|
||||||
|
(save-restriction
|
||||||
|
(narrow-to-region (point-at-bol) (point-at-eol))
|
||||||
|
(beginning-of-line)
|
||||||
|
(condition-case err
|
||||||
|
(while (re-search-forward "\\s\"\\|\\s<" nil t)
|
||||||
|
(let ((start-str (match-string 0))
|
||||||
|
(start-char (match-beginning 0)))
|
||||||
|
(forward-char -1)
|
||||||
|
(if (looking-at "\\s<")
|
||||||
|
(progn
|
||||||
|
(matlab--scan-line-comment-disable-strings)
|
||||||
|
(forward-comment 1))
|
||||||
|
;; Else, check for valid string
|
||||||
|
(if (or (bolp)
|
||||||
|
(string= start-str "\"")
|
||||||
|
(save-excursion
|
||||||
|
(forward-char -1)
|
||||||
|
(not (looking-at "\\(\\w\\|\\s_\\|\\s)\\|\"\\|\\.\\)"))))
|
||||||
|
(progn
|
||||||
|
;; Valid string start, try to skip the string
|
||||||
|
(forward-sexp 1)
|
||||||
|
;; If we just finished and we have a double of ourselves,
|
||||||
|
;; convert those doubles into punctuation.
|
||||||
|
(when (looking-at start-str)
|
||||||
|
(matlab--put-char-category (1- (point)) 'matlab--quoted-string-syntax)
|
||||||
|
;; and try again.
|
||||||
|
(goto-char start-char)
|
||||||
|
))
|
||||||
|
(when (string= start-str "'")
|
||||||
|
;; If it isn't valid string, it's just transpose or something.
|
||||||
|
;; convert to a symbol - as a VAR'', the second ' needs to think it
|
||||||
|
;; is not after punctuation.
|
||||||
|
(matlab--put-char-category (point) 'matlab--transpose-syntax))
|
||||||
|
;; Move forward 1.
|
||||||
|
(forward-char 1)
|
||||||
|
)))
|
||||||
|
nil)
|
||||||
|
(error
|
||||||
|
t))))
|
||||||
|
|
||||||
|
(defun matlab--scan-line-comment-disable-strings ()
|
||||||
|
"Disable bad string chars syntax from point to eol.
|
||||||
|
Called when comments found in `matlab--scan-line-for-unterminated-string'."
|
||||||
|
(save-excursion
|
||||||
|
(while (re-search-forward "\\s\"" nil t)
|
||||||
|
(save-excursion
|
||||||
|
(matlab--put-char-category (1- (point)) 'matlab--transpose-syntax)
|
||||||
|
))))
|
||||||
|
|
||||||
|
(defun matlab--scan-line-bad-blockcomment ()
|
||||||
|
"Scan this line for invalid block comment starts."
|
||||||
|
(when (and (re-search-forward "%{" (point-at-eol) t) (not (looking-at "\\s-*$")))
|
||||||
|
(goto-char (1- (match-end 0)))
|
||||||
|
t))
|
||||||
|
|
||||||
|
(defun matlab--scan-line-for-ellipsis ()
|
||||||
|
"Scan this line for an ellipsis."
|
||||||
|
(when (re-search-forward "\\.\\.\\." (point-at-eol) t)
|
||||||
|
(goto-char (match-beginning 0))
|
||||||
|
t))
|
||||||
|
|
||||||
|
;;; Font Lock Support:
|
||||||
|
;;
|
||||||
|
;; The syntax specific font-lock support handles comments and strings.
|
||||||
|
;;
|
||||||
|
;; We'd like to support multiple kinds of strings and comments. To do
|
||||||
|
;; that we overload `font-lock-syntactic-face-function' with our own.
|
||||||
|
;; This does the same job as the orriginal, except we scan the start
|
||||||
|
;; for special cookies left behind by `matlab--syntax-propertize' and
|
||||||
|
;; use that to choose different fonts.
|
||||||
|
(defun matlab--font-lock-syntactic-face (pps)
|
||||||
|
"Return the face to use for the syntax specified in PPS."
|
||||||
|
;; From the default in font-lock.
|
||||||
|
;; (if (nth 3 state) font-lock-string-face font-lock-comment-face)
|
||||||
|
(if (nth 3 pps)
|
||||||
|
;; This is a string. Check the start char to see if it was
|
||||||
|
;; marked as an unterminate string.
|
||||||
|
(cond ((get-text-property (nth 8 pps) 'unterminated)
|
||||||
|
'matlab-unterminated-string-face)
|
||||||
|
((get-text-property (nth 8 pps) 'command-dual)
|
||||||
|
'matlab-commanddual-string-face)
|
||||||
|
(t
|
||||||
|
'font-lock-string-face))
|
||||||
|
|
||||||
|
;; Not a string, must be a comment. Check to see if it is a
|
||||||
|
;; cellbreak comment.
|
||||||
|
(cond ((and (< (nth 8 pps) (point-max))
|
||||||
|
(= (char-after (1+ (nth 8 pps))) ?\%))
|
||||||
|
'matlab-cellbreak-face)
|
||||||
|
((and (< (nth 8 pps) (point-max))
|
||||||
|
(= (char-after (1+ (nth 8 pps))) ?\#))
|
||||||
|
'matlab-pragma-face)
|
||||||
|
((and (< (nth 8 pps) (point-max))
|
||||||
|
(looking-at "\\^\\| \\$\\$\\$"))
|
||||||
|
'matlab-ignored-comment-face)
|
||||||
|
(t
|
||||||
|
'font-lock-comment-face))
|
||||||
|
))
|
||||||
|
|
||||||
|
;;; SETUP
|
||||||
|
;;
|
||||||
|
;; Connect our special logic into a running MATLAB Mode
|
||||||
|
;; replacing existing mechanics.
|
||||||
|
;;
|
||||||
|
;; Delete this if/when it becomes a permanent part of `matlab-mode'.
|
||||||
|
|
||||||
|
(defun matlab-syntax-setup ()
|
||||||
|
"Integrate our syntax handling into a running `matlab-mode' buffer.
|
||||||
|
Safe to use in `matlab-mode-hook'."
|
||||||
|
;; Syntax Table support
|
||||||
|
(set-syntax-table matlab-syntax-table)
|
||||||
|
(make-local-variable 'syntax-propertize-function)
|
||||||
|
(setq syntax-propertize-function 'matlab--syntax-propertize)
|
||||||
|
;; Comment handlers
|
||||||
|
(make-local-variable 'comment-start)
|
||||||
|
(make-local-variable 'comment-end)
|
||||||
|
(make-local-variable 'comment-start-skip)
|
||||||
|
(make-local-variable 'page-delimiter)
|
||||||
|
(setq comment-start "%"
|
||||||
|
comment-end ""
|
||||||
|
comment-start-skip "%\\s-+"
|
||||||
|
page-delimiter "^\\(\f\\|%%\\(\\s-\\|\n\\)\\)")
|
||||||
|
;; Other special regexps handling different kinds of syntax.
|
||||||
|
(make-local-variable 'paragraph-start)
|
||||||
|
(setq paragraph-start (concat "^$\\|" page-delimiter))
|
||||||
|
(make-local-variable 'paragraph-separate)
|
||||||
|
(setq paragraph-separate paragraph-start)
|
||||||
|
(make-local-variable 'paragraph-ignore-fill-prefix)
|
||||||
|
(setq paragraph-ignore-fill-prefix t)
|
||||||
|
|
||||||
|
;; Font lock
|
||||||
|
(make-local-variable 'font-lock-syntactic-face-function)
|
||||||
|
(setq font-lock-syntactic-face-function 'matlab--font-lock-syntactic-face)
|
||||||
|
)
|
||||||
|
|
||||||
|
;;; Syntax Testing for Strings and Comments
|
||||||
|
;;
|
||||||
|
;; These functions detect syntactic context based on the syntax table.
|
||||||
|
(defsubst matlab-cursor-in-string-or-comment ()
|
||||||
|
"Return non-nil if the cursor is in a valid MATLAB comment or string."
|
||||||
|
(nth 8 (syntax-ppss (point))))
|
||||||
|
|
||||||
|
(defsubst matlab-cursor-in-comment ()
|
||||||
|
"Return t if the cursor is in a valid MATLAB comment."
|
||||||
|
(nth 4 (syntax-ppss (point))))
|
||||||
|
|
||||||
|
(defsubst matlab-cursor-in-string (&optional incomplete)
|
||||||
|
"Return t if the cursor is in a valid MATLAB character vector or string scalar.
|
||||||
|
Note: INCOMPLETE is now obsolete
|
||||||
|
If the optional argument INCOMPLETE is non-nil, then return t if we
|
||||||
|
are in what could be a an incomplete string. (Note: this is also the default)"
|
||||||
|
(nth 3 (syntax-ppss (point))))
|
||||||
|
|
||||||
|
(defun matlab-cursor-comment-string-context (&optional bounds-sym)
|
||||||
|
"Return the comment/string context of cursor for the current line.
|
||||||
|
Return 'comment if in a comment.
|
||||||
|
Return 'string if in a string.
|
||||||
|
Return 'charvector if in a character vector
|
||||||
|
Return 'ellipsis if after an ... ellipsis
|
||||||
|
Return 'commanddual if in text interpreted as string for command dual
|
||||||
|
Return nil if none of the above.
|
||||||
|
Scans from the beginning of line to determine the context.
|
||||||
|
If optional BOUNDS-SYM is specified, set that symbol value to the
|
||||||
|
bounds of the string or comment the cursor is in"
|
||||||
|
(let* ((pps (syntax-ppss (point)))
|
||||||
|
(start (nth 8 pps))
|
||||||
|
(end 0)
|
||||||
|
(syntax nil))
|
||||||
|
;; Else, inside something if 'start' is set.
|
||||||
|
(when start
|
||||||
|
(save-match-data
|
||||||
|
(save-excursion
|
||||||
|
(goto-char start) ;; Prep for extra checks.
|
||||||
|
(setq syntax
|
||||||
|
(cond ((eq (nth 3 pps) t)
|
||||||
|
(cond ((= (following-char) ?')
|
||||||
|
'charvector)
|
||||||
|
((= (following-char) ?\")
|
||||||
|
'string)
|
||||||
|
(t
|
||||||
|
'commanddual)))
|
||||||
|
((eq (nth 3 pps) ?')
|
||||||
|
'charvector)
|
||||||
|
((eq (nth 3 pps) ?\")
|
||||||
|
'string)
|
||||||
|
((nth 4 pps)
|
||||||
|
(if (= (following-char) ?\%)
|
||||||
|
'comment
|
||||||
|
'ellipsis))
|
||||||
|
(t nil)))
|
||||||
|
|
||||||
|
;; compute the bounds
|
||||||
|
(when (and syntax bounds-sym)
|
||||||
|
(if (memq syntax '(charvector string))
|
||||||
|
;;(forward-sexp 1) - overridden - need primitive version
|
||||||
|
(goto-char (scan-sexps (point) 1))
|
||||||
|
(forward-comment 1)
|
||||||
|
(if (bolp) (forward-char -1)))
|
||||||
|
(set bounds-sym (list start (point))))
|
||||||
|
)))
|
||||||
|
|
||||||
|
;; Return the syntax
|
||||||
|
syntax))
|
||||||
|
|
||||||
|
(defsubst matlab-beginning-of-string-or-comment (&optional all-comments)
|
||||||
|
"If the cursor is in a string or comment, move to the beginning.
|
||||||
|
Returns non-nil if the cursor is in a comment."
|
||||||
|
(let* ((pps (syntax-ppss (point))))
|
||||||
|
(prog1
|
||||||
|
(when (nth 8 pps)
|
||||||
|
(goto-char (nth 8 pps))
|
||||||
|
|
||||||
|
t)
|
||||||
|
(when all-comments (forward-comment -100000)))))
|
||||||
|
|
||||||
|
(defun matlab-end-of-string-or-comment (&optional all-comments)
|
||||||
|
"If the cursor is in a string or comment, move to the end.
|
||||||
|
If optional ALL-COMMENTS is non-nil, then also move over all
|
||||||
|
adjacent comments.
|
||||||
|
Returns non-nil if the cursor moved."
|
||||||
|
(let* ((pps (syntax-ppss (point)))
|
||||||
|
(start (point)))
|
||||||
|
(if (nth 8 pps)
|
||||||
|
(progn
|
||||||
|
;; syntax-ppss doesn't have the end, so go to the front
|
||||||
|
;; and then skip forward.
|
||||||
|
(goto-char (nth 8 pps))
|
||||||
|
(if (nth 3 pps)
|
||||||
|
(goto-char (scan-sexps (point) 1))
|
||||||
|
(forward-comment (if all-comments 100000 1)))
|
||||||
|
;; If the buffer is malformed, we might end up before starting pt.
|
||||||
|
;; so error.
|
||||||
|
(when (< (point) start)
|
||||||
|
(goto-char start)
|
||||||
|
(error "Error navitaging syntax."))
|
||||||
|
t)
|
||||||
|
;; else not in comment, but still skip 'all-comments' if requested.
|
||||||
|
(when (and all-comments (looking-at "\\s-*\\s<"))
|
||||||
|
(forward-comment 100000)
|
||||||
|
t)
|
||||||
|
)))
|
||||||
|
|
||||||
|
;;; Navigating Lists
|
||||||
|
;;
|
||||||
|
;; MATLAB's lists are (), {}, [].
|
||||||
|
;; We used to need to do special stuff, but now I think this
|
||||||
|
;; is just a call striaght to up-list.
|
||||||
|
|
||||||
|
(defun matlab-up-list (count)
|
||||||
|
"Move forwards or backwards up a list by COUNT.
|
||||||
|
When travelling backward, use `syntax-ppss' counted paren
|
||||||
|
starts to navigate upward.
|
||||||
|
When travelling forward, use 'up-list' diretly, but disable
|
||||||
|
comment and string crossing."
|
||||||
|
(save-restriction
|
||||||
|
(matlab-beginning-of-string-or-comment)
|
||||||
|
(if (< count 0)
|
||||||
|
(let ((pps (syntax-ppss)))
|
||||||
|
(when (< (nth 0 pps) (abs count))
|
||||||
|
(error "Cannot navigate up %d lists" (abs count)))
|
||||||
|
;; When travelling in reverse, we can just use pps'
|
||||||
|
;; parsed paren list in slot 9.
|
||||||
|
(let ((posn (reverse (nth 9 pps)))) ;; Location of parens
|
||||||
|
(goto-char (nth (1- (abs count)) posn))))
|
||||||
|
;; Else - travel forward
|
||||||
|
(up-list count nil t)) ;; will this correctly ignore comments, etc?
|
||||||
|
))
|
||||||
|
|
||||||
|
(defsubst matlab-in-list-p ()
|
||||||
|
"If the cursor is in a list, return positions of the beginnings of the lists.
|
||||||
|
Returns nil if not in a list."
|
||||||
|
(nth 9 (syntax-ppss (point))))
|
||||||
|
|
||||||
|
(defsubst matlab-beginning-of-outer-list ()
|
||||||
|
"If the cursor is in a list, move to the beginning of outermost list.
|
||||||
|
Returns non-nil if the cursor moved."
|
||||||
|
(let ((pps (syntax-ppss (point))))
|
||||||
|
(when (nth 9 pps) (goto-char (car (nth 9 pps))) )))
|
||||||
|
|
||||||
|
(defun matlab-end-of-outer-list ()
|
||||||
|
"If the cursor is in a list, move to the end of the outermost list..
|
||||||
|
Returns non-nil if the cursor moved."
|
||||||
|
(let ((pps (syntax-ppss (point)))
|
||||||
|
(start (point)))
|
||||||
|
(when (nth 9 pps)
|
||||||
|
;; syntax-ppss doesn't have the end, so go to the front
|
||||||
|
;; and then skip forward.
|
||||||
|
(goto-char (car (nth 9 pps)))
|
||||||
|
(goto-char (scan-sexps (point) 1))
|
||||||
|
;; This checks for malformed buffer content
|
||||||
|
;; that can cause this to go backwards.
|
||||||
|
(when (> start (point))
|
||||||
|
(goto-char start)
|
||||||
|
(error "Malformed List"))
|
||||||
|
)))
|
||||||
|
|
||||||
|
;;; Useful checks for state around point.
|
||||||
|
;;
|
||||||
|
(defsubst matlab-syntax-keyword-as-variable-p ()
|
||||||
|
"Return non-nil if the current word is treated like a variable.
|
||||||
|
This could mean it is:
|
||||||
|
* Field of a structure
|
||||||
|
* Assigned from or into with ="
|
||||||
|
(or (save-excursion (skip-syntax-backward "w")
|
||||||
|
(skip-syntax-backward " ")
|
||||||
|
(or (= (preceding-char) ?\.)
|
||||||
|
(= (preceding-char) ?=)))
|
||||||
|
(save-excursion (skip-syntax-forward "w")
|
||||||
|
(skip-syntax-forward " ")
|
||||||
|
(= (following-char) ?=))))
|
||||||
|
|
||||||
|
(defsubst matlab-valid-keyword-syntax ()
|
||||||
|
"Return non-nil if cursor is not in a string, comment, or parens."
|
||||||
|
(let ((pps (syntax-ppss (point))))
|
||||||
|
(not (or (nth 8 pps) (nth 9 pps))))) ;; 8 == string/comment, 9 == parens
|
||||||
|
|
||||||
|
;;; Syntax Compat functions
|
||||||
|
;;
|
||||||
|
;; Left over old APIs. Delete these someday.
|
||||||
|
(defsubst matlab-move-simple-sexp-backward-internal (count)
|
||||||
|
"Move backward COUNT number of MATLAB sexps."
|
||||||
|
(let ((forward-sexp-function nil))
|
||||||
|
(forward-sexp (- count))))
|
||||||
|
|
||||||
|
(defsubst matlab-move-simple-sexp-internal(count)
|
||||||
|
"Move over one MATLAB sexp COUNT times.
|
||||||
|
If COUNT is negative, travel backward."
|
||||||
|
(let ((forward-sexp-function nil))
|
||||||
|
(forward-sexp count)))
|
||||||
|
|
||||||
|
(provide 'matlab-syntax)
|
||||||
|
|
||||||
|
;;; matlab-syntax.el ends here
|
100
mlint.el
100
mlint.el
|
@ -188,8 +188,14 @@ be cause for being turned off in a buffer."
|
||||||
( NOPRT . mlint-lm-quiet )
|
( NOPRT . mlint-lm-quiet )
|
||||||
( NOSEM . mlint-lm-delete-focus )
|
( NOSEM . mlint-lm-delete-focus )
|
||||||
( NOCOM . mlint-lm-delete-focus )
|
( NOCOM . mlint-lm-delete-focus )
|
||||||
|
( MSNU . mlint-lm-delete-focus )
|
||||||
( ST2NM . mlint-lm-str2num )
|
( ST2NM . mlint-lm-str2num )
|
||||||
( FDEPR . mlint-lm-entry-deprecated )
|
( FDEPR . mlint-lm-entry-deprecated )
|
||||||
|
( ENDCT . mlint-lm-missing-end )
|
||||||
|
( ENDCT2 . mlint-lm-missing-end )
|
||||||
|
( FNDEF . mlint-lm-function-name )
|
||||||
|
( MCFIL . mlint-lm-function-name )
|
||||||
|
( MCSCC . mlint-lm-function-name )
|
||||||
)
|
)
|
||||||
"List of warning IDs and auto-fix functions.
|
"List of warning IDs and auto-fix functions.
|
||||||
If the CAR of an association matches an error id then the linemark entry
|
If the CAR of an association matches an error id then the linemark entry
|
||||||
|
@ -468,7 +474,7 @@ ACTIVE-P if it should be made visible."
|
||||||
"Return non-nil if entry E can be automatically fixed."
|
"Return non-nil if entry E can be automatically fixed."
|
||||||
(oref-default e fixable-p))
|
(oref-default e fixable-p))
|
||||||
|
|
||||||
(cl-defmethod mlint-fix-entry :AFTER ((e mlint-lm-entry))
|
(cl-defmethod mlint-fix-entry :after ((e mlint-lm-entry))
|
||||||
"Stuff to do after a warning is considered fixed.
|
"Stuff to do after a warning is considered fixed.
|
||||||
Subclasses fulfill the duty of actually fixing the code."
|
Subclasses fulfill the duty of actually fixing the code."
|
||||||
(linemark-display e nil)
|
(linemark-display e nil)
|
||||||
|
@ -497,6 +503,8 @@ Subclasses fulfill the duty of actually fixing the code."
|
||||||
)
|
)
|
||||||
(goto-char s)
|
(goto-char s)
|
||||||
(delete-region (point) e)
|
(delete-region (point) e)
|
||||||
|
;; If this happened to be at end of line, just delete all left over whitespace.
|
||||||
|
(when (looking-at "\\s-*$") (delete-horizontal-space))
|
||||||
(point)
|
(point)
|
||||||
))
|
))
|
||||||
)
|
)
|
||||||
|
@ -508,13 +516,13 @@ Subclasses fulfill the duty of actually fixing the code."
|
||||||
"Class which can replace the focus area."
|
"Class which can replace the focus area."
|
||||||
:abstract t)
|
:abstract t)
|
||||||
|
|
||||||
(cl-defmethod initialize-instance :AFTER ((this mlint-lm-replace-focus)
|
(cl-defmethod initialize-instance :after ((this mlint-lm-replace-focus)
|
||||||
&rest fields)
|
&rest fields)
|
||||||
"Calculate the new fix description for THIS.
|
"Calculate the new fix description for THIS.
|
||||||
Optional argument FIELDS are the initialization arguments."
|
Optional argument FIELDS are the initialization arguments."
|
||||||
;; After basic initialization, update the fix description.
|
;; After basic initialization, update the fix description.
|
||||||
(oset this fix-description
|
(oset this fix-description
|
||||||
(concat (oref-default mlint-lm-replace-focus fix-description)
|
(concat (oref-default this fix-description)
|
||||||
(oref this new-text))))
|
(oref this new-text))))
|
||||||
|
|
||||||
(cl-defmethod mlint-fix-entry ((ent mlint-lm-replace-focus))
|
(cl-defmethod mlint-fix-entry ((ent mlint-lm-replace-focus))
|
||||||
|
@ -533,7 +541,7 @@ Optional argument FIELDS are the initialization arguments."
|
||||||
"Entry for anything that is deprecated.
|
"Entry for anything that is deprecated.
|
||||||
Extracts the replacement for the deprecated symbol from the warning message.")
|
Extracts the replacement for the deprecated symbol from the warning message.")
|
||||||
|
|
||||||
(cl-defmethod initialize-instance :AFTER ((this mlint-lm-entry-deprecated)
|
(cl-defmethod initialize-instance :after ((this mlint-lm-entry-deprecated)
|
||||||
&rest fields)
|
&rest fields)
|
||||||
"Calculate the 'new text' for THIS instance.
|
"Calculate the 'new text' for THIS instance.
|
||||||
Optional argument FIELDS are the initialization arguments."
|
Optional argument FIELDS are the initialization arguments."
|
||||||
|
@ -544,10 +552,33 @@ Optional argument FIELDS are the initialization arguments."
|
||||||
(oset this new-text newfcn)
|
(oset this new-text newfcn)
|
||||||
;; After basic initialization, update the fix description.
|
;; After basic initialization, update the fix description.
|
||||||
(oset this fix-description
|
(oset this fix-description
|
||||||
(concat (oref-default mlint-lm-replace-focus fix-description)
|
(concat (oref-default this fix-description)
|
||||||
newfcn))
|
newfcn))
|
||||||
))
|
))
|
||||||
|
|
||||||
|
(defclass mlint-lm-function-name (mlint-lm-replace-focus)
|
||||||
|
()
|
||||||
|
"When function name is missmatched with the file name."
|
||||||
|
)
|
||||||
|
|
||||||
|
(cl-defmethod initialize-instance :after ((this mlint-lm-function-name) &rest fields)
|
||||||
|
"Compute the 'new text' for THIS to be the file name from the message.
|
||||||
|
Optional arguments FIELDS are the initialization arguments."
|
||||||
|
(let* ((warn (oref this warning))
|
||||||
|
(junk (or (string-match "file name: '\\([a-zA-z][a-zA-z0-9]+\\)'" warn)
|
||||||
|
(string-match "do not agree: '\\([a-zA-z][a-zA-z0-9]+\\)'" warn)
|
||||||
|
(string-match "of the subclass '\\([a-zA-z][a-zA-z0-9]+\\)'" warn))
|
||||||
|
)
|
||||||
|
(newfcn (when junk (match-string 1 warn))))
|
||||||
|
(oset this new-text newfcn)
|
||||||
|
;; After basic initialization, update the fix description.
|
||||||
|
(oset this fix-description
|
||||||
|
(concat (oref-default this fix-description)
|
||||||
|
newfcn))
|
||||||
|
))
|
||||||
|
|
||||||
|
;;; Custom auto-fix entries
|
||||||
|
;;
|
||||||
(defclass mlint-lm-entry-logicals (mlint-lm-entry)
|
(defclass mlint-lm-entry-logicals (mlint-lm-entry)
|
||||||
((fixable-p :initform t)
|
((fixable-p :initform t)
|
||||||
(fix-description :initform "perform a replacement.")
|
(fix-description :initform "perform a replacement.")
|
||||||
|
@ -600,6 +631,53 @@ Optional argument FIELDS are the initialization arguments."
|
||||||
(insert ";"))
|
(insert ";"))
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(defclass mlint-lm-missing-end (mlint-lm-entry)
|
||||||
|
((fixable-p :initform t)
|
||||||
|
(fix-description :initform "Add matching end for this line."))
|
||||||
|
"Missing end with guess as to where it might go."
|
||||||
|
)
|
||||||
|
|
||||||
|
(cl-defmethod mlint-fix-entry ((ent mlint-lm-missing-end))
|
||||||
|
"Add semi-colon to end of this line."
|
||||||
|
(save-excursion
|
||||||
|
(let* ((msg (oref ent warning))
|
||||||
|
line blockname)
|
||||||
|
;; Extract info about this.
|
||||||
|
(when (string-match "(after line \\([0-9]+\\))" msg)
|
||||||
|
(setq line (match-string 1 msg)))
|
||||||
|
(when (string-match "possibly matching \\([A-Z]+\\)\\." msg)
|
||||||
|
(setq blockname (match-string 1 msg)))
|
||||||
|
|
||||||
|
;; Did we get the right kind of warning
|
||||||
|
(if line
|
||||||
|
;; We have a line number, just go for it there.
|
||||||
|
(progn
|
||||||
|
(mlint-goto-line (string-to-number line))
|
||||||
|
;; add the end and indent
|
||||||
|
(indent-region (point) (save-excursion (insert "end\n") (point)))
|
||||||
|
)
|
||||||
|
(if (and blockname (string= blockname "FUNCTION"))
|
||||||
|
;; It is a function, but no line number. Let's guess where this end
|
||||||
|
;; should go.
|
||||||
|
(save-excursion
|
||||||
|
(mlint-goto-line (oref ent line)) ;; go to the fcn
|
||||||
|
(end-of-line)
|
||||||
|
(if (re-search-forward "^function " nil t)
|
||||||
|
(progn
|
||||||
|
(beginning-of-line)
|
||||||
|
;; skip over comments that might be headers to the found function.
|
||||||
|
(matlab-previous-command-begin
|
||||||
|
(matlab-compute-line-context 2)) ;;(matlab-find-prev-code-line)
|
||||||
|
(forward-line 1)
|
||||||
|
(save-excursion (insert "end\n\n"))
|
||||||
|
(matlab-indent-line))
|
||||||
|
(goto-char (point-max))
|
||||||
|
(save-excursion (insert "\nend\n\n"))
|
||||||
|
(matlab-indent-line))))
|
||||||
|
)
|
||||||
|
))
|
||||||
|
)
|
||||||
|
|
||||||
;;; User functions
|
;;; User functions
|
||||||
;;
|
;;
|
||||||
(defun mlint-highlight (err)
|
(defun mlint-highlight (err)
|
||||||
|
@ -740,10 +818,14 @@ Highlight problems and/or cross-function variables."
|
||||||
(if (not n)
|
(if (not n)
|
||||||
(message "No warning at point.")
|
(message "No warning at point.")
|
||||||
(let ((col (matlab-comment-on-line)))
|
(let ((col (matlab-comment-on-line)))
|
||||||
(or col (end-of-line))
|
(if col
|
||||||
(insert " %#ok")
|
(progn
|
||||||
;; Add spaces if there was a comment.
|
(goto-char col)
|
||||||
(when col (insert " ")))
|
(skip-chars-forward "% ")
|
||||||
|
(insert "#ok "))
|
||||||
|
(end-of-line)
|
||||||
|
(insert " %#ok"))
|
||||||
|
)
|
||||||
;; This causes inconsistencies.
|
;; This causes inconsistencies.
|
||||||
;; (linemark-delete n)
|
;; (linemark-delete n)
|
||||||
))
|
))
|
||||||
|
|
|
@ -206,7 +206,7 @@ Return argument is:
|
||||||
(while (re-search-forward semantic-matlab-match-methods-block-re nil end)
|
(while (re-search-forward semantic-matlab-match-methods-block-re nil end)
|
||||||
(save-excursion ;; find end of properties block
|
(save-excursion ;; find end of properties block
|
||||||
(goto-char (match-beginning 0))
|
(goto-char (match-beginning 0))
|
||||||
(matlab-forward-sexp nil nil)
|
(matlab-forward-sexp nil)
|
||||||
(setq tmpend (point)))
|
(setq tmpend (point)))
|
||||||
|
|
||||||
(setq attrs (semantic-matlab-parse-attributes-and-move))
|
(setq attrs (semantic-matlab-parse-attributes-and-move))
|
||||||
|
@ -239,7 +239,7 @@ Return argument is:
|
||||||
(setq attrs (semantic-matlab-parse-attributes-and-move))
|
(setq attrs (semantic-matlab-parse-attributes-and-move))
|
||||||
|
|
||||||
(save-excursion ;; find end of properties block
|
(save-excursion ;; find end of properties block
|
||||||
(matlab-forward-sexp nil t)
|
(matlab-forward-sexp t)
|
||||||
(beginning-of-line)
|
(beginning-of-line)
|
||||||
(setq tmpend (point)))
|
(setq tmpend (point)))
|
||||||
|
|
||||||
|
|
|
@ -76,7 +76,7 @@
|
||||||
;; Create the database, and add it to searchable databases for matlab mode.
|
;; Create the database, and add it to searchable databases for matlab mode.
|
||||||
(defvar-mode-local matlab-mode semanticdb-project-system-databases
|
(defvar-mode-local matlab-mode semanticdb-project-system-databases
|
||||||
(list
|
(list
|
||||||
(semanticdb-project-database-matlab "Matlab"))
|
(make-instance 'semanticdb-project-database-matlab))
|
||||||
"Search MATLAB path for symbols.")
|
"Search MATLAB path for symbols.")
|
||||||
|
|
||||||
;; NOTE: Be sure to modify this to the best advantage of your
|
;; NOTE: Be sure to modify this to the best advantage of your
|
||||||
|
@ -99,7 +99,7 @@ Create one of our special tables that can act as an intermediary."
|
||||||
;; We need to return something since there is always the "master table"
|
;; We need to return something since there is always the "master table"
|
||||||
;; The table can then answer file name type questions.
|
;; The table can then answer file name type questions.
|
||||||
(when (not (slot-boundp obj 'tables))
|
(when (not (slot-boundp obj 'tables))
|
||||||
(let ((newtable (semanticdb-table-matlab "MATLAB system table")))
|
(let ((newtable (make-instance 'semanticdb-table-matlab)))
|
||||||
(oset obj tables (list newtable))
|
(oset obj tables (list newtable))
|
||||||
(oset newtable parent-db obj)
|
(oset newtable parent-db obj)
|
||||||
(oset newtable tags nil)
|
(oset newtable tags nil)
|
||||||
|
@ -337,8 +337,7 @@ Return a list of tags."
|
||||||
(let ((files (semanticdb-matlab-find-name regex 'regex)))
|
(let ((files (semanticdb-matlab-find-name regex 'regex)))
|
||||||
(delq nil
|
(delq nil
|
||||||
(mapcar #'(lambda (x)
|
(mapcar #'(lambda (x)
|
||||||
(let ((matlab-vers-on-startup nil))
|
(car (semanticdb-file-stream x)))
|
||||||
(car (semanticdb-file-stream x))))
|
|
||||||
files)))))
|
files)))))
|
||||||
|
|
||||||
(cl-defmethod semanticdb-find-tags-for-completion-method
|
(cl-defmethod semanticdb-find-tags-for-completion-method
|
||||||
|
@ -378,8 +377,7 @@ Returns a table of all matching tags."
|
||||||
;; generate tags
|
;; generate tags
|
||||||
(delq nil
|
(delq nil
|
||||||
(mapcar #'(lambda (x)
|
(mapcar #'(lambda (x)
|
||||||
(let ((matlab-vers-on-startup nil))
|
(car (semanticdb-file-stream x)))
|
||||||
(car (semanticdb-file-stream x))))
|
|
||||||
compdb)))))
|
compdb)))))
|
||||||
|
|
||||||
(provide 'semanticdb-matlab)
|
(provide 'semanticdb-matlab)
|
||||||
|
|
|
@ -20,8 +20,11 @@ VERSION=4.0
|
||||||
DISTDIR=$(top)matlab-emacs-$(VERSION)/tests
|
DISTDIR=$(top)matlab-emacs-$(VERSION)/tests
|
||||||
|
|
||||||
|
|
||||||
|
ifdef OS # No MATLAB shell tests on windows.
|
||||||
|
all: tests matlab modetests
|
||||||
|
else # The OS variable is only defined on windows, so linux systems can run shell tests.
|
||||||
all: tests matlab modetests shelltests
|
all: tests matlab modetests shelltests
|
||||||
|
endif
|
||||||
|
|
||||||
.PHONY: modetests
|
.PHONY: modetests
|
||||||
modetests: metest.elc
|
modetests: metest.elc
|
||||||
|
|
|
@ -0,0 +1,213 @@
|
||||||
|
% >>1
|
||||||
|
classdef blocks < handle
|
||||||
|
% !!0
|
||||||
|
|
||||||
|
% >>11
|
||||||
|
properties %!!4
|
||||||
|
normalprop = 1; %!!8
|
||||||
|
end % <<11
|
||||||
|
|
||||||
|
%>>12
|
||||||
|
properties(Access='public') %!!4
|
||||||
|
|
||||||
|
% See if we can create properties using keywords
|
||||||
|
%properties = 1;
|
||||||
|
%methods = 1;
|
||||||
|
%events = 1;
|
||||||
|
arguments %!!8
|
||||||
|
prop = 1;
|
||||||
|
|
||||||
|
end %<<12
|
||||||
|
|
||||||
|
% >> 13
|
||||||
|
events (Access='private') %!!4
|
||||||
|
|
||||||
|
%properties
|
||||||
|
%events
|
||||||
|
%methods
|
||||||
|
arguments %#ok %!!8
|
||||||
|
misc %!!8
|
||||||
|
|
||||||
|
end % <<13
|
||||||
|
|
||||||
|
%>>14
|
||||||
|
methods %!!4
|
||||||
|
|
||||||
|
%>>15
|
||||||
|
function simple_method(obj) %!!8
|
||||||
|
%>>151
|
||||||
|
arguments %!!12
|
||||||
|
obj %!!16
|
||||||
|
end %<<151
|
||||||
|
|
||||||
|
disp(obj.normalprop);
|
||||||
|
end %<<15
|
||||||
|
|
||||||
|
%>>16
|
||||||
|
function obj = blocks(arguments,events,properties,methods,enumeration,normal)%!!8
|
||||||
|
%>>161
|
||||||
|
arguments %!!12
|
||||||
|
arguments%!!16
|
||||||
|
events%!!16
|
||||||
|
properties%!!16
|
||||||
|
methods%!!16
|
||||||
|
enumeration%!!16
|
||||||
|
normal%!!16
|
||||||
|
end %<<161
|
||||||
|
|
||||||
|
obj.prop = arguments;%!!12
|
||||||
|
obj.prop = events;%!!12
|
||||||
|
obj.prop = properties;%!!12
|
||||||
|
obj.prop = methods;%!!12
|
||||||
|
obj.prop = enumeration;%!!12
|
||||||
|
obj.prop = normal;%!!12
|
||||||
|
end %<<16
|
||||||
|
|
||||||
|
%>>17
|
||||||
|
function properties(~)%!!8
|
||||||
|
end %<<17
|
||||||
|
|
||||||
|
%>>18
|
||||||
|
function methods(~)%!!8
|
||||||
|
end %<<18
|
||||||
|
|
||||||
|
%>>19
|
||||||
|
function events(~)%!!8
|
||||||
|
end %<<19
|
||||||
|
|
||||||
|
%>>20
|
||||||
|
function events=arguments(arguments)%!!8
|
||||||
|
arguments, arguments(:,:) {mustBeNumeric}, end %!!12
|
||||||
|
%^ ^kw ^vn ^ty ^df ^kw ^co
|
||||||
|
enumeration ... %!!12
|
||||||
|
...%^ ^df
|
||||||
|
= arguments;
|
||||||
|
%^ ^df
|
||||||
|
|
||||||
|
if enumeration > 0 %!!12
|
||||||
|
arguments = -enumeration; %!!16
|
||||||
|
%^ ^df ^bi ^df
|
||||||
|
end %!!12
|
||||||
|
|
||||||
|
events ... %!!12
|
||||||
|
= arguments + 1;
|
||||||
|
%^ ^df
|
||||||
|
|
||||||
|
end %<<20
|
||||||
|
|
||||||
|
%>>21
|
||||||
|
function enumeration(~)%!!8
|
||||||
|
%^ ^fn
|
||||||
|
end %<<21
|
||||||
|
|
||||||
|
function y = multiple_arg_blocks(a, b, varargin) %!!8
|
||||||
|
|
||||||
|
arguments %!!12
|
||||||
|
%^ ^kw
|
||||||
|
a uint32 %!!16
|
||||||
|
%^ ^vn ^ty
|
||||||
|
b uint32 %!!16
|
||||||
|
%^ ^vn ^ty
|
||||||
|
end %!!12
|
||||||
|
%^ ^kw
|
||||||
|
|
||||||
|
arguments (Repeating) %!!12
|
||||||
|
%^ ^kw ^ty
|
||||||
|
varargin %!!16
|
||||||
|
%^ ^vn
|
||||||
|
end %!!12
|
||||||
|
%^ ^kw
|
||||||
|
|
||||||
|
y = a+b+length(varargin); %!!12
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function linLog(x,y,scale)
|
||||||
|
arguments(Repeating) %!!12
|
||||||
|
x (1,:) double
|
||||||
|
y (1,:) double
|
||||||
|
end %!!12
|
||||||
|
arguments %!!12
|
||||||
|
scale.Plottype(1,1) string %!!16
|
||||||
|
%^ ^vn ^vn ^ty ^ty
|
||||||
|
end %!!12
|
||||||
|
|
||||||
|
sprintf('%d %d %s\n', x, y, scale);
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
%>>22
|
||||||
|
function usestuff(obj)%!!8
|
||||||
|
% Try using the methods of this object
|
||||||
|
obj.properties();%!!12
|
||||||
|
obj.methods();%!!12
|
||||||
|
obj. events();%!!12
|
||||||
|
obj. arguments();%!!12
|
||||||
|
obj. enumeration();%!!12
|
||||||
|
normal();%!!12
|
||||||
|
end %<<22
|
||||||
|
|
||||||
|
%>>23
|
||||||
|
function [m,s] = blarg(~, arguments)%!!8
|
||||||
|
% Starter comments.
|
||||||
|
|
||||||
|
%>>231
|
||||||
|
arguments%!!12
|
||||||
|
~%!!16
|
||||||
|
arguments(:,:) {mustBeNumeric}%!!16
|
||||||
|
end %<<231
|
||||||
|
|
||||||
|
m = mean( ...%!!12
|
||||||
|
arguments, 'all'); %!!16
|
||||||
|
|
||||||
|
arguments = 1;%!!12
|
||||||
|
events = arguments;%!!12
|
||||||
|
methods = events;%!!12
|
||||||
|
properties = methods;%!!12
|
||||||
|
enumeration = properties;%!!12
|
||||||
|
|
||||||
|
s = enumeration;%!!12
|
||||||
|
end %<<23
|
||||||
|
|
||||||
|
%>>24
|
||||||
|
function s = simple(~,arguments)%!!8
|
||||||
|
% Simple function
|
||||||
|
|
||||||
|
events = arguments;%!!12
|
||||||
|
methods = events;%!!12
|
||||||
|
properties = methods;%!!12
|
||||||
|
enumeration = properties;%!!12
|
||||||
|
|
||||||
|
s = enumeration; %!!12
|
||||||
|
end %<<24
|
||||||
|
|
||||||
|
function methods=foo3(obj,properties) %!!8
|
||||||
|
methods=obj.arguments(properties); %!!12
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
function s=struct_stuff(~) %!!8
|
||||||
|
|
||||||
|
s.if = 1; %!!12
|
||||||
|
s.else = 1.5; %!!12
|
||||||
|
s.while = 2; %!!12
|
||||||
|
s.switch = 3; %!!12
|
||||||
|
s.case = 3.1; %!!12
|
||||||
|
s.end = 5; %!!12
|
||||||
|
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
function tightcomments(~)%!!8
|
||||||
|
if condition%!!12
|
||||||
|
switch thing %!!16
|
||||||
|
case b %!!18
|
||||||
|
end%!!16
|
||||||
|
end%!!12
|
||||||
|
end%!!8
|
||||||
|
|
||||||
|
%!!8
|
||||||
|
end %<<14
|
||||||
|
|
||||||
|
%!!4
|
||||||
|
end % <<1
|
||||||
|
|
||||||
|
%!!0
|
|
@ -0,0 +1,47 @@
|
||||||
|
function complete (a_arg1, b_arg2)
|
||||||
|
% This function is for testing completion tools
|
||||||
|
|
||||||
|
arguments
|
||||||
|
a_arg1 (1,1) double
|
||||||
|
b_arg2 (2,1) int
|
||||||
|
end
|
||||||
|
|
||||||
|
global a_global
|
||||||
|
global b_global
|
||||||
|
|
||||||
|
a_localvar = 1;
|
||||||
|
b_localvar = 1;
|
||||||
|
|
||||||
|
for a_for=1:10
|
||||||
|
end
|
||||||
|
|
||||||
|
if bool_var
|
||||||
|
end
|
||||||
|
|
||||||
|
switch a_switch
|
||||||
|
end
|
||||||
|
|
||||||
|
a_
|
||||||
|
% @@(solo var "a_localvar" "a_switch" "a_for" "a_global" "a_arg1")
|
||||||
|
% @@(solo fcn )
|
||||||
|
|
||||||
|
% Note: For b, there are other test files the completion
|
||||||
|
% engine will find, so they are included.
|
||||||
|
b
|
||||||
|
% @@(solo fcn "blocal_fcn" "blazy_fcn" "buggy" "blocks")
|
||||||
|
% @@(solo var "b_localvar" "bool_var" "b_global" "b_arg2")
|
||||||
|
|
||||||
|
|
||||||
|
% quiet mlint
|
||||||
|
blocal_fcn(a_arg1, b_arg2, a_localvar, b_localvar, a_global, b_global);
|
||||||
|
end
|
||||||
|
|
||||||
|
function blocal_fcn(varargin)
|
||||||
|
|
||||||
|
blazy_fcn(varargin{:});
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function blazy_fcn(varargin)
|
||||||
|
end
|
||||||
|
|
|
@ -0,0 +1,184 @@
|
||||||
|
function continuations(a,b) %!!0
|
||||||
|
% !!0 Help Comment
|
||||||
|
|
||||||
|
arguments (Repeating)
|
||||||
|
a (1,1) ... % !!8
|
||||||
|
double % !!12
|
||||||
|
b (1,1) double { mustBeSomething ... %!!8
|
||||||
|
mustBeSomethingElse } %!!25
|
||||||
|
end
|
||||||
|
|
||||||
|
global var1, ... % !!4
|
||||||
|
var2 % !!8
|
||||||
|
|
||||||
|
localfcn(a,b); % !!4
|
||||||
|
|
||||||
|
localfcn(var1, ... % !!4
|
||||||
|
var2); % !!13
|
||||||
|
|
||||||
|
localfcn(a, localfcn(b, localfcn(var1,... %!!4
|
||||||
|
var2)... %!37
|
||||||
|
)... %!!24
|
||||||
|
); %!!12
|
||||||
|
|
||||||
|
|
||||||
|
code1(), ...
|
||||||
|
code2(); %!!8
|
||||||
|
|
||||||
|
% NOTE: Blank space below should cancel the indent effect of ellipsis.
|
||||||
|
code1() ...
|
||||||
|
|
||||||
|
var1 = 1 + ... %!!4
|
||||||
|
... %!!11
|
||||||
|
2 + ... %!!11
|
||||||
|
3; %!!11
|
||||||
|
|
||||||
|
medvar = 1 + ... %!!4
|
||||||
|
2; %!!13
|
||||||
|
|
||||||
|
long_var_name = 1 + ... %!!4
|
||||||
|
2; %!!8
|
||||||
|
|
||||||
|
localfcn (medvar, ... %!!4
|
||||||
|
long_var_name); %!!19
|
||||||
|
|
||||||
|
localfcn( ... %!!4
|
||||||
|
a,b); %!!8
|
||||||
|
|
||||||
|
|
||||||
|
if true, if true, if true %#ok %!!4
|
||||||
|
localfcn(a,b); ... %!!16
|
||||||
|
end; ... %!!4
|
||||||
|
end; ... %!!4
|
||||||
|
end ... %!!4
|
||||||
|
|
||||||
|
odd_if_location(); %!!4 - this after those continued ends
|
||||||
|
|
||||||
|
|
||||||
|
... % !!4 A continuation with a ctrl block after it
|
||||||
|
for g=1:10 %#ok % !!8 b/c continuation
|
||||||
|
localfcn(a,g) % !!8 b/c not continued, and +4 from comment continuation
|
||||||
|
end % !!4 to match
|
||||||
|
|
||||||
|
% !!4 to undo continuation.
|
||||||
|
|
||||||
|
% Indent past 1st arg for special functions
|
||||||
|
set(myhandle, 'Prop1', value, ... %!!4
|
||||||
|
'Prop2', value, ... %!!18
|
||||||
|
'Prop3', value); %!!18
|
||||||
|
|
||||||
|
% Indent past = sign for assignments.
|
||||||
|
A = 1 + ... % !!4
|
||||||
|
2; % !!8
|
||||||
|
|
||||||
|
medvar = 1 + ... % !!4
|
||||||
|
2; % !!13
|
||||||
|
|
||||||
|
alongvariablename = 1 +... % !!4
|
||||||
|
2; % !!8
|
||||||
|
|
||||||
|
|
||||||
|
fancyfunctionname(arg1, ... %!!4
|
||||||
|
innerfcn(arg2, ... %!!22
|
||||||
|
arg3), ... %!!31
|
||||||
|
{ cell1; %!!22
|
||||||
|
cell2; %!!24
|
||||||
|
[ 1 2 ; %!!24
|
||||||
|
3 4 ] ; %!!26
|
||||||
|
cell 4 },... %!!24
|
||||||
|
arg5); %!!22
|
||||||
|
|
||||||
|
|
||||||
|
... % Continuation by itself just before an end.
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
function [ a, ... !!0
|
||||||
|
b, ... !!11
|
||||||
|
c, ... !!11
|
||||||
|
d ] ... !!11
|
||||||
|
= continuations_in_return(opt)
|
||||||
|
% H1 Comment Line !!0
|
||||||
|
|
||||||
|
code(); %!! 4
|
||||||
|
|
||||||
|
end %!! 0
|
||||||
|
|
||||||
|
function [ a, b ] = continuation_in_args(a,...
|
||||||
|
b) %!!41
|
||||||
|
% H1 comment line !!0
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function c=expression_cont(a,b)
|
||||||
|
% H1 line !!0
|
||||||
|
|
||||||
|
if (a > 0 && ... %!!4
|
||||||
|
b < 0) %!!8
|
||||||
|
|
||||||
|
% comment one !!8
|
||||||
|
c=1; %!!8
|
||||||
|
elseif (a < 0 && ... %!!4
|
||||||
|
b > 0) %!!12
|
||||||
|
|
||||||
|
% comment two !!8
|
||||||
|
c=2; %!!8
|
||||||
|
end %!!4
|
||||||
|
|
||||||
|
switch a %!!4
|
||||||
|
case 'ert' %!!6
|
||||||
|
b = 1; %!!8
|
||||||
|
case {'sim', ... %!!6
|
||||||
|
'normalsim'} %!!12
|
||||||
|
b=2; %!!8
|
||||||
|
end %!!4
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function a=odd_if_location(n) %!!0
|
||||||
|
|
||||||
|
i=1; while i<10, if xfcn(i,n)==0, i=i+1; %!!4
|
||||||
|
else, i=20; end; end %!!21
|
||||||
|
|
||||||
|
if i<20 %!!4
|
||||||
|
a=1; %!!8
|
||||||
|
else %!!4
|
||||||
|
a=0; %!!8
|
||||||
|
end %!!4
|
||||||
|
|
||||||
|
foo();
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
function val = localfcn(c,d) %!!0
|
||||||
|
% !!0 Help Comment
|
||||||
|
|
||||||
|
try fclose( fid ); catch, end %!!4
|
||||||
|
|
||||||
|
val = c+d; % !!4
|
||||||
|
|
||||||
|
odd_end_location_from_dspfwiz_load(1);
|
||||||
|
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
function [z,o,n]=odd_end_location_from_dspfwiz_load(opts) %!!0
|
||||||
|
if opts.zeros, z = 'On'; %!!4
|
||||||
|
else, z = 'Off'; end %!!4
|
||||||
|
|
||||||
|
if opts.ones, o = 'On'; %!!4
|
||||||
|
else, o = 'Off'; end %!!4
|
||||||
|
|
||||||
|
if opts.neg_ones, n = 'On'; %!!4
|
||||||
|
else, n = 'Off'; end %!!4
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
function a=foo
|
||||||
|
%{
|
||||||
|
for !!2
|
||||||
|
for !!2
|
||||||
|
%}
|
||||||
|
if true %#ok %!!4
|
||||||
|
if true %!!8
|
||||||
|
a = 1; %!!12
|
||||||
|
end end %#ok %!!8
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
% Empty M file.
|
||||||
|
% %%%empty guess guess
|
167
tests/fontlock.m
167
tests/fontlock.m
|
@ -1,8 +1,36 @@
|
||||||
function [a, b, c] = fontlock(input1, ...
|
|
||||||
input2, ...
|
% TEST FILE FOR FONT LOCK SPECIAL WORDS
|
||||||
input3)
|
function fontlock()
|
||||||
% FONTLOCK testing function for Emacs & MATLAB.
|
%^ ^kw ^fn ^df
|
||||||
|
%^ ^ig
|
||||||
|
|
||||||
|
% $$$ ignored comment
|
||||||
|
%^ ^ig
|
||||||
|
|
||||||
|
persistent var1 % !!4
|
||||||
|
%^ ^kw ^vn ^co
|
||||||
|
|
||||||
|
global var2 % !!4
|
||||||
|
%^ ^kw ^vn ^co
|
||||||
|
|
||||||
|
end
|
||||||
|
%^ ^kw
|
||||||
|
|
||||||
|
function [ var1, var2 ] = local(input1)
|
||||||
|
%^ ^kw ^vn ^fn ^vn ^df
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function [a, b] = local2(input1,...
|
||||||
|
input2)
|
||||||
|
%^ ^vn
|
||||||
|
end
|
||||||
|
|
||||||
|
% TODO - these are cross function variables, but we turn off mlint in
|
||||||
|
% tests, so these aren't tested.
|
||||||
|
function [a, b, c] = localvars(input1, input2, input3)
|
||||||
|
%^ ^kw ^vn ^fn ^vn ^vn ^vn ^df
|
||||||
|
|
||||||
nested(input1);
|
nested(input1);
|
||||||
|
|
||||||
q = input2;
|
q = input2;
|
||||||
|
@ -16,6 +44,135 @@ function [a, b, c] = fontlock(input1, ...
|
||||||
c = r;
|
c = r;
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function keywordstuff()
|
||||||
|
|
||||||
|
while true
|
||||||
|
%^ ^kw ^ma
|
||||||
|
|
||||||
|
for varname=1:10
|
||||||
|
%^ ^kw ^vn ^cn
|
||||||
|
break
|
||||||
|
%^ ^kw
|
||||||
|
end
|
||||||
|
|
||||||
|
if varname == 2
|
||||||
|
%^ ^kw ^df ^bi ^df
|
||||||
|
disp(1)
|
||||||
|
elseif varname==3
|
||||||
|
%^ ^kw ^df ^bi
|
||||||
|
disp(2)
|
||||||
|
else
|
||||||
|
%^ ^kw
|
||||||
|
disp(3)
|
||||||
|
end
|
||||||
|
%^ ^kw
|
||||||
|
|
||||||
|
switch varname
|
||||||
|
%^ ^kw ^cn
|
||||||
|
case 1
|
||||||
|
%^ ^kw ^cn
|
||||||
|
disp(1)
|
||||||
|
continue
|
||||||
|
%^ ^kw
|
||||||
|
case 2
|
||||||
|
%^ ^kw ^cn
|
||||||
|
disp(2)
|
||||||
|
otherwise
|
||||||
|
%^ ^kw
|
||||||
|
disp('other');
|
||||||
|
%^ ^df ^st
|
||||||
|
return
|
||||||
|
%^ ^kw
|
||||||
|
end
|
||||||
|
%^ ^kw
|
||||||
|
|
||||||
|
try
|
||||||
|
%^ ^kw
|
||||||
|
disp(1)
|
||||||
|
catch
|
||||||
|
%^ ^kw
|
||||||
|
disp(2)
|
||||||
|
end
|
||||||
|
%^ ^kw
|
||||||
|
|
||||||
|
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function dographics(value)
|
||||||
|
|
||||||
|
f = figure;
|
||||||
|
%^ ^bi
|
||||||
|
ax = axes(f);
|
||||||
|
%^ ^bi
|
||||||
|
|
||||||
|
set ( ax, 'property',value)
|
||||||
|
%^ ^bi ^vn ^st
|
||||||
|
|
||||||
|
s = open_system('foo.mdl');
|
||||||
|
%^ ^si ^st
|
||||||
|
|
||||||
|
set_param(s, 'param', value);
|
||||||
|
%^ ^si ^vn ^st ^df
|
||||||
|
end
|
||||||
|
|
||||||
|
function dodebug()
|
||||||
|
|
||||||
|
dbstop in dodebug
|
||||||
|
%^ ^bo ^cd
|
||||||
|
|
||||||
|
dbclear
|
||||||
|
%^ ^bo
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function mathstuff()
|
||||||
|
|
||||||
|
myvar = eps + pi + nan + ans + i + NaT + true ;
|
||||||
|
%^ ^df ^ma ^bi ^ma ^bi ^ma ^bi ^ma ^bi ^ma ^bi ^ma ^bi ^ma ^df
|
||||||
|
end
|
||||||
|
|
||||||
|
function helptest()
|
||||||
|
% HELPTEXT has fancy fonts in it.
|
||||||
|
%^ ^cn
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function name_no_args
|
||||||
|
%^ ^kw ^fn
|
||||||
|
end
|
||||||
|
|
||||||
|
function retarg = ret_and_name_no_args % comment
|
||||||
|
%^ ^kw ^vn ^df ^fn ^co
|
||||||
|
end
|
||||||
|
|
||||||
|
function retarg = args_have_cont (arg_1, ...
|
||||||
|
arg_2)
|
||||||
|
%^ ^vn
|
||||||
|
end
|
||||||
|
|
||||||
|
function [ retarg1, ...
|
||||||
|
retarg2, ...
|
||||||
|
retarg3 ] ...
|
||||||
|
= name_of_fcn (arg1)
|
||||||
|
%^ ^df ^fn ^vn ^df
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
classdef (Abstract) myclass < handle
|
||||||
|
%^ ^kw ^ty ^fn ^bi ^cn
|
||||||
|
end
|
||||||
|
|
||||||
|
classdef (Abstract)myclass<handle
|
||||||
|
%^ ^kw ^ty ^fn ^bi ^ty
|
||||||
|
end
|
||||||
|
|
||||||
|
%{
|
||||||
|
% Local Variables:
|
||||||
|
% matlab-show-mlint-warnings: nil
|
||||||
|
% End:
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
220
tests/indents.m
220
tests/indents.m
|
@ -1,4 +1,5 @@
|
||||||
function indents(a,b,stuff)
|
|
||||||
|
function indents(a,b,stuff,cmddual1fake,cmddual2fake)
|
||||||
% Help text
|
% Help text
|
||||||
% !!0
|
% !!0
|
||||||
% of many lines
|
% of many lines
|
||||||
|
@ -11,26 +12,37 @@ function indents(a,b,stuff)
|
||||||
a (1,1) {mustBeNumeric} % !!8
|
a (1,1) {mustBeNumeric} % !!8
|
||||||
b (:,:) double % !!8
|
b (:,:) double % !!8
|
||||||
stuff {mustBeMember(stuff, { 'this' 'that' 'other' })} % !!8
|
stuff {mustBeMember(stuff, { 'this' 'that' 'other' })} % !!8
|
||||||
|
cmddual1fake double % !!8
|
||||||
|
cmddual2fake int % !!8
|
||||||
end % !!4
|
end % !!4
|
||||||
|
|
||||||
|
persistent var1 % !!4
|
||||||
|
global var2 % !!4
|
||||||
|
persistent var3 % !!4
|
||||||
|
|
||||||
|
|
||||||
locala = a; %#ok
|
locala = a; %#ok
|
||||||
localb = b; %#ok
|
localb = b; %#ok
|
||||||
localstuff = stuff; %#ok
|
localstuff = stuff; %#ok
|
||||||
|
|
||||||
ends_in_comments_and_strings(); % has end in name
|
if isempty(var1) var1=1; end %#ok !!4
|
||||||
|
if isempty(var3) var3=2; end %#ok !!4
|
||||||
|
|
||||||
|
ends_in_comments_and_strings(var1, var2, var3); % !!4 has end in name
|
||||||
|
|
||||||
% !!4
|
% !!4
|
||||||
|
|
||||||
block_starts_in_comments_and_strings();
|
block_starts_in_comments_and_strings(cmddual1fake,cmddual2fake);
|
||||||
|
array_constant_decls();
|
||||||
|
|
||||||
% !!4
|
% !!4
|
||||||
|
|
||||||
continuations_and_block_comments();
|
continuations_and_block_comments();
|
||||||
|
|
||||||
% $$$ !!0
|
% $$$ !!0
|
||||||
% $$$ special ignore comments
|
% $$$ special ignore comments
|
||||||
|
|
||||||
has_nested_fcn();
|
has_nested_fcn(); % !!4
|
||||||
|
|
||||||
% !!4 - after ignore comments
|
% !!4 - after ignore comments
|
||||||
|
|
||||||
|
@ -52,7 +64,8 @@ function B = ends_in_comments_and_strings()
|
||||||
|
|
||||||
B = A(1:end); %#ok
|
B = A(1:end); %#ok
|
||||||
|
|
||||||
if foo
|
%% cell start comment !!4
|
||||||
|
if foo %!!4
|
||||||
C = "this is the end of the line";
|
C = "this is the end of the line";
|
||||||
% !!8
|
% !!8
|
||||||
else %!!4
|
else %!!4
|
||||||
|
@ -62,25 +75,25 @@ function B = ends_in_comments_and_strings()
|
||||||
% !!4
|
% !!4
|
||||||
|
|
||||||
E = [ D C];
|
E = [ D C];
|
||||||
|
|
||||||
if bar
|
if bar
|
||||||
|
|
||||||
A = E;
|
A = E;
|
||||||
|
|
||||||
end; B = A(1:end);
|
end; B = A(1:end);
|
||||||
% !!4
|
% !!4
|
||||||
|
|
||||||
E = B;
|
E = B;
|
||||||
|
|
||||||
if baz
|
if baz
|
||||||
|
|
||||||
A = C;
|
A = C;
|
||||||
|
|
||||||
end; B = [ 1 2 ... % is this the end?
|
end; B = [ 1 2 ... % is this the end?
|
||||||
3 4 ]; % !!15
|
3 4 ]; % !!15
|
||||||
|
|
||||||
% !!4
|
% !!4
|
||||||
|
|
||||||
if foo
|
if foo
|
||||||
|
|
||||||
A = E;
|
A = E;
|
||||||
|
@ -88,21 +101,15 @@ function B = ends_in_comments_and_strings()
|
||||||
end ... the other end
|
end ... the other end
|
||||||
% !! 4
|
% !! 4
|
||||||
|
|
||||||
code1() ...
|
|
||||||
code2(); %!!8
|
|
||||||
|
|
||||||
% NOTE: Blank space below should cancel the indent effect of ellipsis.
|
|
||||||
code1() ...
|
|
||||||
|
|
||||||
B = [ B A ]; % !!4
|
B = [ B A ]; % !!4
|
||||||
|
|
||||||
str = 'This is a char array with ... in it';
|
str = 'This is a char array with ... in it';
|
||||||
foo(str); % !!4
|
foo(str); % !!4
|
||||||
|
|
||||||
fcncall(arg1, '...', arg3); % !!4
|
fcncall(arg1, '...', arg3); % !!4
|
||||||
1; % !!4
|
1; % !!4
|
||||||
|
|
||||||
% Multi-ends
|
% Multi- end s
|
||||||
% >>8
|
% >>8
|
||||||
if foo %#ok
|
if foo %#ok
|
||||||
if bar %#ok
|
if bar %#ok
|
||||||
|
@ -116,24 +123,126 @@ function B = ends_in_comments_and_strings()
|
||||||
|
|
||||||
% !!4
|
% !!4
|
||||||
B = A;
|
B = A;
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function out = array_constant_decls()
|
||||||
|
|
||||||
|
A = [ 1 2 3 ]; %!!4
|
||||||
|
|
||||||
|
Blong = [ 1 2; %!!4
|
||||||
|
3 4; %!!14
|
||||||
|
]; %!!12
|
||||||
|
|
||||||
|
Csep = [
|
||||||
|
1 2; %!!8
|
||||||
|
3 4; %!!8
|
||||||
|
]; %!!11
|
||||||
|
|
||||||
|
multinest = { [ 1 2 %!!4
|
||||||
|
3 4 ]; %!!20
|
||||||
|
{ 5 6 7 ... %!!18
|
||||||
|
8 9 10 ... %!!20
|
||||||
|
}; %!!18
|
||||||
|
fcncall(10, ... %!!18
|
||||||
|
12, ... %!!26
|
||||||
|
[ 13 14; %!!26
|
||||||
|
15 16 ]) %!!28
|
||||||
|
} ; %!!16
|
||||||
|
|
||||||
|
nest = { ... %!!4
|
||||||
|
1 %!!8
|
||||||
|
[ ... %!!8
|
||||||
|
2 3 %!!10
|
||||||
|
] ... %!!8
|
||||||
|
3 %!!8
|
||||||
|
}; %!!11
|
||||||
|
|
||||||
|
cascade_long_name = ... %!!4
|
||||||
|
{ ... %!!8
|
||||||
|
1 %!!10
|
||||||
|
2 %!!10
|
||||||
|
}; %!!8
|
||||||
|
|
||||||
|
% TODO
|
||||||
|
% I don't know why the below indents this way.
|
||||||
|
% It should either do all max indent, or all lined up with parens.
|
||||||
|
thing.thing.long.long.longname({ 'str' %!!4
|
||||||
|
'str' %!!37
|
||||||
|
'str' %!!37
|
||||||
|
'str' %!!37
|
||||||
|
}); %!!35
|
||||||
|
|
||||||
|
thing.thing.long.long.longname('str', ... %!!4
|
||||||
|
'str', ... %!!35
|
||||||
|
'str', ... %!!35
|
||||||
|
'str' ... %!!35
|
||||||
|
); %!!34
|
||||||
|
|
||||||
|
% Line starting with end inside parens
|
||||||
|
disp(Csep(1: ... %!!4
|
||||||
|
end)); %!!14
|
||||||
|
|
||||||
|
% This array has bad syntactic expression parsing due to the
|
||||||
|
% apostrophy
|
||||||
|
Closures = [
|
||||||
|
755009 ; ... % 21-Feb-2067 Washington's Birthday (Mon)
|
||||||
|
755010 ; % !!8
|
||||||
|
];
|
||||||
|
|
||||||
|
dep = [
|
||||||
|
root(info.function, factory, workspace, []), ... % likewise this isn't a keyword
|
||||||
|
fcn3.finalize % the single quote used to break [] scanning
|
||||||
|
];
|
||||||
|
|
||||||
|
% This long fcn name last symbol starts with 'get' which
|
||||||
|
% used to confuse and move to indent past 1st arg.
|
||||||
|
if qesimcheck.utils.GetYesNoAnswer('Do ',... !!4
|
||||||
|
'n',... !!39
|
||||||
|
'once') %!!39
|
||||||
|
code(); %!!8
|
||||||
|
end %!!4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
% !!4
|
||||||
|
out = { A %!!4
|
||||||
|
Blong %!!12
|
||||||
|
Csep %!!12
|
||||||
|
nest %!!12
|
||||||
|
multinest%!!12
|
||||||
|
cascade_long_name%!!12
|
||||||
|
Closures%!!12
|
||||||
|
dep %!!12
|
||||||
|
}; %!!10
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function C = block_starts_in_comments_and_strings()
|
function C = block_starts_in_comments_and_strings(varargin)
|
||||||
% !!0
|
% !!0
|
||||||
|
|
||||||
C = 0;
|
C = 0;
|
||||||
|
|
||||||
if true % if true
|
if varargin{1} % if true
|
||||||
|
|
||||||
|
% !!8
|
||||||
|
else % !!4
|
||||||
|
|
||||||
|
% !!8
|
||||||
end % if true
|
end % if true
|
||||||
|
|
||||||
|
|
||||||
% see previous function
|
% see previous function
|
||||||
% !!4
|
% !!4
|
||||||
for x=1:length(C) % !!4
|
for x=1:length(C) % !!4
|
||||||
|
if varargin{2} % !!8
|
||||||
% !!8
|
continue % !!12
|
||||||
|
end % !!8
|
||||||
|
|
||||||
|
break % !!8
|
||||||
|
% !!14
|
||||||
|
|
||||||
|
%!!8
|
||||||
end
|
end
|
||||||
|
|
||||||
switch foo() %!!4
|
switch foo() %!!4
|
||||||
|
@ -149,7 +258,7 @@ function C = block_starts_in_comments_and_strings()
|
||||||
try
|
try
|
||||||
% !!8
|
% !!8
|
||||||
catch %!!4
|
catch %!!4
|
||||||
|
|
||||||
% !!8
|
% !!8
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -160,10 +269,12 @@ function B = continuations_and_block_comments
|
||||||
% !!0
|
% !!0
|
||||||
% !!0
|
% !!0
|
||||||
|
|
||||||
%{
|
%{
|
||||||
!!6
|
!!2 { }
|
||||||
!!6
|
!!2
|
||||||
%}
|
%}
|
||||||
|
|
||||||
|
arg1=1;
|
||||||
|
|
||||||
%{
|
%{
|
||||||
% !!4
|
% !!4
|
||||||
|
@ -188,9 +299,9 @@ function B = continuations_and_block_comments
|
||||||
3 4 ]; % !!10
|
3 4 ]; % !!10
|
||||||
|
|
||||||
foo(['this is a very long string' ... %!!4
|
foo(['this is a very long string' ... %!!4
|
||||||
'with a continution to do something very exciting'])%!!9
|
'with a continution to do something very exciting']);%!!9
|
||||||
|
|
||||||
set(gcf,'Position',[ 1 2 3 4],... !!4
|
set(gcf,'Position',[ 1 2 3 4], ... !!4
|
||||||
'Color', 'red'); % !!12
|
'Color', 'red'); % !!12
|
||||||
|
|
||||||
B = A + 1 + 4 ...
|
B = A + 1 + 4 ...
|
||||||
|
@ -200,6 +311,14 @@ function B = continuations_and_block_comments
|
||||||
% continuation-comment !!17
|
% continuation-comment !!17
|
||||||
|
|
||||||
% !!4 -blank between this & continuation comment
|
% !!4 -blank between this & continuation comment
|
||||||
|
% !!4 - more comments
|
||||||
|
|
||||||
|
if condition1 || ... % !!4
|
||||||
|
fcn_call(arg1, ... % !!12
|
||||||
|
arg2) % !!21
|
||||||
|
line_in_if();
|
||||||
|
end % !!4
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
end
|
end
|
||||||
|
@ -208,15 +327,44 @@ function has_nested_fcn
|
||||||
|
|
||||||
plot(1:10); %!!4
|
plot(1:10); %!!4
|
||||||
|
|
||||||
function am_nested_fcn %!!4
|
A = 1;
|
||||||
|
|
||||||
|
function am_nested_fcn() %!!4
|
||||||
% help
|
% help
|
||||||
% !!4
|
% !!4
|
||||||
code();
|
code(A);
|
||||||
%!!8
|
%!!8
|
||||||
end
|
end
|
||||||
|
|
||||||
%!!4
|
%!!4
|
||||||
am_nested_fcn();
|
am_nested_fcn();
|
||||||
|
function_end_same_line(1);
|
||||||
|
function_after_end_same_line();
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function b=function_end_same_line(a), b=a; end %!!0
|
||||||
|
|
||||||
|
function function_after_end_same_line()%!!0
|
||||||
|
%!!0
|
||||||
|
disp('foo');%!!4
|
||||||
|
|
||||||
|
debug_cmd_dual();
|
||||||
|
|
||||||
|
end%!!0
|
||||||
|
|
||||||
|
function debug_cmd_dual ()
|
||||||
|
% These dbstop command dual content have 'if' blocks in them.
|
||||||
|
% The command dual detection needs to block these from being
|
||||||
|
% detected as block initiators which would cause indentaiton.
|
||||||
|
|
||||||
|
dbstop in hRandomFile at 14 if func() % !!4
|
||||||
|
dbstop in hRandomFile at 30@1 if x==1 % !!4
|
||||||
|
dbstop in hPFile % !!4
|
||||||
|
dbstop in hSimpleFile at 2 % !!4
|
||||||
|
dbstop if error % !!4
|
||||||
|
|
||||||
|
%!!4
|
||||||
|
|
||||||
|
debug_cmd_dual(); %!!4
|
||||||
|
|
||||||
|
end
|
|
@ -1,30 +1,39 @@
|
||||||
% >>1
|
% >>1
|
||||||
classdef (abstract) mclass < handle & matlab.mixin.SetGetExactNames % #7#
|
classdef (abstract) mclass < handle & matlab.mixin.SetGetExactNames % #7#
|
||||||
|
%^ ^kw ^ty ^fn ^cn ^bi ^cn ^co
|
||||||
% !!0
|
% !!0
|
||||||
|
% %%% class class class
|
||||||
|
|
||||||
% >>11
|
% >>11
|
||||||
properties (Access='public') % #2#
|
properties (Access='public') % #2#
|
||||||
|
%^ ^kw ^ty ^st ^co
|
||||||
|
|
||||||
% !!8
|
% !!8
|
||||||
AP = []; % #2#
|
AP = []; % #2#
|
||||||
|
%^ ^vn ^df ^co
|
||||||
AB = 'charvec with space'; % #2#
|
AB = 'charvec with space'; % #2#
|
||||||
AC = "string with space and ( "; % #2#
|
AC = "string with space and ( "; % #2#
|
||||||
AD = fun_call(1,2); % #3#
|
AD = fun_call(1,2); % #3#
|
||||||
AE (1,:) double {mustBePositive} = 1; % #5#
|
AE (1,:) double {mustBePositive} = 1; % #5#
|
||||||
|
%^ ^vn ^ty ^df ^co
|
||||||
end % <<11
|
end % <<11
|
||||||
|
|
||||||
% >> 111
|
% >> 111
|
||||||
properties (AbortSet=true, NonCopyable=true) % #2#
|
properties (AbortSet=true, NonCopyable=true) % #2#
|
||||||
|
%^ ^kw ^ty ^ma ^ty ^ma ^co
|
||||||
|
|
||||||
% !!8
|
% !!8
|
||||||
AF (1,1) char {mustBeMember(AF, {'High','Medium','Low'})} = 'Low'; % #5#
|
AF (1,1) char {mustBeMember(AF, {'High','Medium','Low'})} = 'Low'; % #5#
|
||||||
|
%^ ^vn ^ty ^df ^st ^df ^st ^co
|
||||||
AG (1,1) matlab.lang.OnOffSwitchState = 'on'; % #6#
|
AG (1,1) matlab.lang.OnOffSwitchState = 'on'; % #6#
|
||||||
|
%^ ^vn ^ty ^ty ^st ^co
|
||||||
end % <<111
|
end % <<111
|
||||||
|
|
||||||
% >> 112
|
% >> 112
|
||||||
events
|
events
|
||||||
% !!8
|
% !!8
|
||||||
Event1
|
Event1
|
||||||
|
%^ ^vn
|
||||||
Event2
|
Event2
|
||||||
end % <<112
|
end % <<112
|
||||||
|
|
||||||
|
@ -34,10 +43,14 @@ classdef (abstract) mclass < handle & matlab.mixin.SetGetExactNames % #7#
|
||||||
|
|
||||||
% >>16
|
% >>16
|
||||||
function obj = mclass()
|
function obj = mclass()
|
||||||
|
%^ ^kw ^vn ^fn ^df
|
||||||
% !!8
|
% !!8
|
||||||
|
|
||||||
obj.AB = obj.AP(1:end);
|
obj.AB = obj.AP(1:end);
|
||||||
% !!12
|
% !!12
|
||||||
|
|
||||||
|
unusedvar = 1; %#ok
|
||||||
|
%^ ^df ^pr
|
||||||
|
|
||||||
disp('charvect with if and for words [ in it'); % #2#
|
disp('charvect with if and for words [ in it'); % #2#
|
||||||
|
|
||||||
|
@ -46,18 +59,22 @@ classdef (abstract) mclass < handle & matlab.mixin.SetGetExactNames % #7#
|
||||||
notify(obj,'Event1',...
|
notify(obj,'Event1',...
|
||||||
'indent test');
|
'indent test');
|
||||||
|
|
||||||
|
notify(obj, 'Event1', 'indent test');
|
||||||
|
%^ ^df ^vn ^st ^st ^df
|
||||||
|
|
||||||
|
|
||||||
% >>17
|
% >>17
|
||||||
while obj.AB % #3#
|
while obj.AB % #3#
|
||||||
|
|
||||||
disp("while loop going on here ("); % #2#
|
disp("while loop going on here ("); % #2#
|
||||||
% !!52
|
% !!52
|
||||||
|
|
||||||
% !!16
|
% !!16
|
||||||
|
|
||||||
end % <<17
|
end % <<17
|
||||||
|
|
||||||
error('function mclass in charvec }'); % #2#
|
error('function mclass in charvec }'); % #2#
|
||||||
|
|
||||||
% !!12
|
% !!12
|
||||||
|
|
||||||
end % <<16
|
end % <<16
|
||||||
|
@ -66,7 +83,7 @@ classdef (abstract) mclass < handle & matlab.mixin.SetGetExactNames % #7#
|
||||||
methods (Access='public')
|
methods (Access='public')
|
||||||
% >>13
|
% >>13
|
||||||
function meth(obj) % #3#
|
function meth(obj) % #3#
|
||||||
|
|
||||||
% >>14
|
% >>14
|
||||||
if obj.AP % #3#
|
if obj.AP % #3#
|
||||||
|
|
||||||
|
@ -74,8 +91,8 @@ classdef (abstract) mclass < handle & matlab.mixin.SetGetExactNames % #7#
|
||||||
|
|
||||||
else
|
else
|
||||||
|
|
||||||
% >>15
|
% >>15
|
||||||
try
|
try
|
||||||
|
|
||||||
% comment with if, while, parfor words in it.
|
% comment with if, while, parfor words in it.
|
||||||
|
|
||||||
|
@ -91,13 +108,52 @@ classdef (abstract) mclass < handle & matlab.mixin.SetGetExactNames % #7#
|
||||||
end % <<12
|
end % <<12
|
||||||
|
|
||||||
methods (Abstract, Hidden=true) % #2#
|
methods (Abstract, Hidden=true) % #2#
|
||||||
|
|
||||||
result = abs_func(a,b) % #3#
|
result = abs_func(a,b) % #3#
|
||||||
|
|
||||||
result = other_abs_fun(a,b) % #3#
|
result = other_abs_fun(a,b) % #3#
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
methods %!!4
|
||||||
|
|
||||||
|
function end_separate_line(~) %!!8
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
function end_same_line(~), end %!!8
|
||||||
|
|
||||||
|
function after_end_same_line(~), end %!!8
|
||||||
|
|
||||||
|
end %!!4
|
||||||
|
|
||||||
|
methods %!!4
|
||||||
|
function properties(~) %!!8
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
function methods(~) %!!8
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
function events(~) %!!8
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
function arguments(~) %!!8
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
function enumeration(~) %!!8
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
function usestuff(obj) %!!8
|
||||||
|
% Try using the methods of this object
|
||||||
|
obj.properties(); %!!12
|
||||||
|
%^ ^df ^df ^co
|
||||||
|
obj.methods(); %!!12
|
||||||
|
obj.events(); %!!12
|
||||||
|
obj.arguments(); %!!12
|
||||||
|
obj.enumeration(); %!!12
|
||||||
|
end %!!8
|
||||||
|
|
||||||
|
end %!!4
|
||||||
|
|
||||||
end % <<1
|
end % <<1
|
||||||
|
|
||||||
% End
|
% End
|
|
@ -0,0 +1,8 @@
|
||||||
|
classdef mclass_cont < otherThing & ... % !!0 This continuation can case issue for next prop block
|
||||||
|
handle %!!8
|
||||||
|
|
||||||
|
properties (Dependent, SetAccess = private) %!!4
|
||||||
|
TopicName %!!8
|
||||||
|
end %!!4
|
||||||
|
|
||||||
|
end %!!0
|
618
tests/metest.el
618
tests/metest.el
|
@ -34,6 +34,7 @@
|
||||||
(require 'matlab-load)
|
(require 'matlab-load)
|
||||||
(require 'matlab)
|
(require 'matlab)
|
||||||
(require 'cedet-matlab)
|
(require 'cedet-matlab)
|
||||||
|
(require 'matlab-complete)
|
||||||
(require 'semantic-matlab)
|
(require 'semantic-matlab)
|
||||||
|
|
||||||
;; Enable semantic
|
;; Enable semantic
|
||||||
|
@ -42,68 +43,224 @@
|
||||||
|
|
||||||
(defun metest-all-syntax-tests ()
|
(defun metest-all-syntax-tests ()
|
||||||
"Run all the syntax tests in this file."
|
"Run all the syntax tests in this file."
|
||||||
(metest-comment-string-syntax-test)
|
(setq debug-on-error t)
|
||||||
(metest-sexp-counting-test)
|
(matlab-scan-stat-reset ) ;; Enable scanner statistics logging.
|
||||||
(metest-sexp-traversal-test)
|
|
||||||
(metest-indents-test)
|
(metest-log-init)
|
||||||
(metest-parse-test)
|
|
||||||
|
(setq-default matlab-indent-function-body 'guess) ;; Force the guess system to be exercised.
|
||||||
|
(metest-run 'metest-end-detect-test)
|
||||||
|
(setq-default matlab-indent-function-body 'MathWorks-Standard) ;; put it back
|
||||||
|
|
||||||
|
(metest-run 'metest-comment-string-syntax-test)
|
||||||
|
(metest-run 'metest-fontlock-test)
|
||||||
|
(metest-run 'metest-sexp-counting-test)
|
||||||
|
(metest-run 'metest-sexp-traversal-test)
|
||||||
|
|
||||||
|
;; Randomize indentation first before indenting
|
||||||
|
;; to force the indenter to make changes and give
|
||||||
|
;; the cahce and performance a harder problem.
|
||||||
|
(metest-indents-randomize-files)
|
||||||
|
(metest-run 'metest-indents-test)
|
||||||
|
|
||||||
|
;; Parsing and completion are high level tools
|
||||||
|
(metest-run 'metest-parse-test)
|
||||||
|
(metest-run 'metest-complete-test)
|
||||||
|
|
||||||
|
(metest-log-report (metest-log-write))
|
||||||
|
|
||||||
|
(matlab-scan-stats-print)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(defun metest-run (test)
|
||||||
|
"Run and time TEST."
|
||||||
|
(let* ((config (symbol-value test))
|
||||||
|
(name (if (stringp config) config (car config)))
|
||||||
|
(files (or (cdr-safe config) '("")))
|
||||||
|
(strlen (apply 'max (mapcar 'length files))))
|
||||||
|
(message ">> Starting %s loop on %S" name files)
|
||||||
|
(dolist (F files)
|
||||||
|
(princ (format (concat "<< %s %-" (number-to-string strlen) "s ") name F) 'external-debugging-output)
|
||||||
|
(let ((old debug-on-error)
|
||||||
|
(out (progn (setq debug-on-error nil)
|
||||||
|
(metest-timeit test F))))
|
||||||
|
(setq debug-on-error old)
|
||||||
|
(when (listp out)
|
||||||
|
(princ (format "passed: %s %.2f s\n" (cdr out) (car out)) 'external-debugging-output)
|
||||||
|
)
|
||||||
|
))
|
||||||
|
(message "")))
|
||||||
|
|
||||||
|
(defvar metest-test-error nil)
|
||||||
|
(defmacro metest-condition-case-error-msg (&rest forms)
|
||||||
|
"Run FORMS, capturing any errors and associating with (point)."
|
||||||
|
(declare (indent 0) (debug t))
|
||||||
|
`(condition-case err
|
||||||
|
,@forms
|
||||||
|
(error (cond (metest-test-error (error (car (cdr err))))
|
||||||
|
(t (metest-error "Lisp: %s" (error-message-string err))))
|
||||||
|
0)
|
||||||
|
))
|
||||||
|
|
||||||
|
(defvar met-end-detect-files '("empty.m" "stringtest.m" "mfuncnoend.m" "mfuncnoendblock.m" "mfuncends.m" "mclass.m" "mfuncspacey.m" "mfuncnoendindent.m" "mfuncnofuncindent.m")
|
||||||
|
"List of files for running end detection tests on.")
|
||||||
|
|
||||||
|
(defvar metest-end-detect-test (cons "END detection" met-end-detect-files))
|
||||||
|
(defun metest-end-detect-test (F)
|
||||||
|
"Run a test to make sure we correctly detect the state of managing 'end'."
|
||||||
|
(let ((buf (metest-find-file F))
|
||||||
|
(ret nil)
|
||||||
|
(cnt 0))
|
||||||
|
(with-current-buffer buf
|
||||||
|
(goto-char (point-min))
|
||||||
|
;;(message ">> Checking END detection in %S" (current-buffer))
|
||||||
|
(if (re-search-forward "%%%\\s-*\\(\\w+\\)\\s-+\\(\\w+\\)\\s-+\\(\\w+\\)$" nil t)
|
||||||
|
(let ((st-expect (intern (match-string-no-properties 1)))
|
||||||
|
(end-expect (intern (match-string-no-properties 2)))
|
||||||
|
(indent-expect (intern (match-string-no-properties 3)))
|
||||||
|
(st-actual (matlab-guess-script-type))
|
||||||
|
(end-actual (matlab-do-functions-have-end-p))
|
||||||
|
(indent-actual (matlab-indent-function-body-p))
|
||||||
|
)
|
||||||
|
(unless (eq st-actual st-expect)
|
||||||
|
(metest-error "Script type detection failure: Expected %s but found %s"
|
||||||
|
st-expect st-actual))
|
||||||
|
(unless (eq end-actual end-expect)
|
||||||
|
(metest-error "Script end detection failure: Expected %s but found %s"
|
||||||
|
end-expect end-actual))
|
||||||
|
(unless (eq indent-actual indent-expect)
|
||||||
|
(metest-error "Script indent detection failure: Expected %s but found %s"
|
||||||
|
indent-expect indent-actual))
|
||||||
|
|
||||||
|
(setq ret (list "script[" st-actual "] end[" end-actual "] indent-p[" indent-actual "]"))
|
||||||
|
;;(message "<< Script type and end detection passed: %s, %s" st-actual end-actual)
|
||||||
|
)
|
||||||
|
;; No expected values found in the file.
|
||||||
|
(metest-error "Test file did not include expected script-type cookie")
|
||||||
|
))
|
||||||
|
ret))
|
||||||
|
|
||||||
(defvar met-stringtest-files '("stringtest.m")
|
(defvar met-stringtest-files '("stringtest.m")
|
||||||
"List of files for running string tests on.")
|
"List of files for running string tests on.")
|
||||||
|
|
||||||
(defun metest-comment-string-syntax-test ()
|
(defvar metest-comment-string-syntax-test (cons "string/comment detection" met-stringtest-files))
|
||||||
|
(defun metest-comment-string-syntax-test (F)
|
||||||
"Run a test to make sure string nd comment highlighting work."
|
"Run a test to make sure string nd comment highlighting work."
|
||||||
(dolist (F met-stringtest-files)
|
(let ((buf (metest-find-file F))
|
||||||
(let ((buf (find-file-noselect (expand-file-name F met-testfile-path)))
|
(cnt 0)
|
||||||
(cnt 0))
|
(noninteractive nil) ;; fake out font lock
|
||||||
|
)
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(message ">> Starting search loop in %S" (current-buffer))
|
|
||||||
(while (re-search-forward "#\\([csveb]\\)#" nil t)
|
(let ((md (match-data)))
|
||||||
(goto-char (match-end 1))
|
;; Force font lock to throw catchable errors.
|
||||||
(let ((md (match-data))
|
(font-lock-mode 1)
|
||||||
(mc (match-string 1))
|
(font-lock-flush (point-min) (point-max))
|
||||||
(bc (matlab-ltype-block-comm))
|
(font-lock-ensure (point-min) (point-max))
|
||||||
(qd (matlab-cursor-comment-string-context)))
|
(font-lock-fontify-region (point-min) (point-max))
|
||||||
|
|
||||||
|
;; FL test 1: make sure font lock is on and match data didn't change.
|
||||||
|
(unless font-lock-mode
|
||||||
|
(metest-error "Font Lock failed to turn on."))
|
||||||
|
;;(unless (equal md (match-data))
|
||||||
|
;; (metest-error "Font Locking transmuted the match data"))
|
||||||
|
(when (not (get-text-property 2 'fontified))
|
||||||
|
(metest-error "Font Lock Failure: can't run test because font lock failed to fontify region."))
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
;;(message ">> Starting string/comment detect loop in %S" (current-buffer))
|
||||||
|
(while (re-search-forward "#\\([cCisSvVebdr]\\)#" nil t)
|
||||||
|
(let* ((md (match-data))
|
||||||
|
(pt (match-end 1))
|
||||||
|
(mc (match-string-no-properties 1))
|
||||||
|
(fnt (get-text-property pt 'face))
|
||||||
|
(lv1 (matlab-compute-line-context 1))
|
||||||
|
(bc (metest-condition-case-error-msg (matlab-line-block-comment-start lv1)))
|
||||||
|
(qd (metest-condition-case-error-msg (matlab-cursor-comment-string-context)))
|
||||||
|
)
|
||||||
|
(goto-char pt)
|
||||||
|
|
||||||
;; Test 1 - what are we?
|
;; Test 1 - what are we?
|
||||||
(unless (or (and (string= "b" mc) bc)
|
(unless (or (and (string= "b" mc) (and bc (eq 'comment qd)))
|
||||||
(and (string= "v" mc) (eq 'charvector qd))
|
(and (string= "v" mc) (eq 'charvector qd))
|
||||||
|
(and (string= "V" mc) (eq 'charvector qd))
|
||||||
(and (string= "s" mc) (eq 'string qd))
|
(and (string= "s" mc) (eq 'string qd))
|
||||||
|
(and (string= "S" mc) (eq 'string qd))
|
||||||
(and (string= "c" mc) (eq 'comment qd))
|
(and (string= "c" mc) (eq 'comment qd))
|
||||||
(and (string= "e" mc) (eq 'elipsis qd))
|
(and (string= "C" mc) (eq 'comment qd))
|
||||||
|
(and (string= "i" mc) (eq 'comment qd))
|
||||||
|
(and (string= "e" mc) (eq 'ellipsis qd))
|
||||||
|
(and (string= "d" mc) (eq 'commanddual qd))
|
||||||
|
(and (string= "r" mc) (eq nil qd))
|
||||||
)
|
)
|
||||||
(error "Syntax Test Failure @ line %d: Expected %s but found %S"
|
(metest-error "Syntax Test Failure @ char %d: Expected %s but found %S"
|
||||||
(line-number-at-pos)
|
pt
|
||||||
(cond ((string= mc "b") "block comment")
|
(cond ((string= mc "b") "block comment")
|
||||||
((string= mc "v") "charvector")
|
((string= mc "v") "charvector")
|
||||||
((string= mc "s") "string")
|
((string= mc "V") "charvector")
|
||||||
((string= mc "c") "comment")
|
((string= mc "s") "string")
|
||||||
((string= mc "e") "elipsis")
|
((string= mc "S") "string")
|
||||||
(t "unknown test token"))
|
((string= mc "c") "comment")
|
||||||
qd))
|
((string= mc "C") "comment")
|
||||||
|
((string= mc "i") "comment")
|
||||||
|
((string= mc "e") "ellipsis")
|
||||||
|
((string= mc "d") "commanddual")
|
||||||
|
((string= mc "r") "normal code")
|
||||||
|
(t "unknown test token"))
|
||||||
|
qd))
|
||||||
;; Test 2 - is match-data unchanged?
|
;; Test 2 - is match-data unchanged?
|
||||||
(unless (equal md (match-data))
|
(unless (equal md (match-data))
|
||||||
(error "Syntax checking transmuted the match data"))
|
(metest-error "Syntax checking transmuted the match data"))
|
||||||
|
|
||||||
|
;; FL test 2 - Is the matched location fontified correctly?
|
||||||
|
(when (consp fnt) (setq fnt (car fnt)))
|
||||||
|
(unless (or (and (string= "b" mc) (eq fnt 'font-lock-comment-face))
|
||||||
|
(and (string= "v" mc) (eq fnt 'font-lock-string-face))
|
||||||
|
(and (string= "V" mc) (eq fnt 'matlab-unterminated-string-face))
|
||||||
|
(and (string= "s" mc) (eq fnt 'font-lock-string-face))
|
||||||
|
(and (string= "S" mc) (eq fnt 'matlab-unterminated-string-face))
|
||||||
|
(and (string= "c" mc) (eq fnt 'font-lock-comment-face))
|
||||||
|
(and (string= "C" mc) (eq fnt 'matlab-cellbreak-face))
|
||||||
|
(and (string= "i" mc) (eq fnt 'matlab-ignored-comment-face))
|
||||||
|
(and (string= "e" mc) (eq fnt 'font-lock-comment-face))
|
||||||
|
(and (string= "d" mc) (eq fnt 'matlab-commanddual-string-face))
|
||||||
|
(and (string= "r" mc) (eq fnt nil))
|
||||||
|
)
|
||||||
|
(metest-error "Font Lock Failure @ char %d: Expected %s but found %S"
|
||||||
|
pt
|
||||||
|
(cond ((string= mc "b") "comment face")
|
||||||
|
((string= mc "v") "string face")
|
||||||
|
((string= mc "V") "unterminated string face")
|
||||||
|
((string= mc "s") "string face")
|
||||||
|
((string= mc "S") "unterminated string face")
|
||||||
|
((string= mc "c") "comment face")
|
||||||
|
((string= mc "C") "cellbreak face")
|
||||||
|
((string= mc "i") "ignored comment face")
|
||||||
|
((string= mc "e") "comment face")
|
||||||
|
((string= mc "d") "commanddual string face")
|
||||||
|
((string= mc "r") "regular code / no face")
|
||||||
|
(t "unknown test token"))
|
||||||
|
(get-text-property pt 'face)))
|
||||||
;; Track
|
;; Track
|
||||||
(setq cnt (1+ cnt))
|
(setq cnt (1+ cnt))
|
||||||
))
|
))
|
||||||
(kill-buffer buf))
|
(kill-buffer buf))
|
||||||
(message "<< Comment and string syntax test: %d points passed" cnt)
|
|
||||||
))
|
(list cnt "tests")))
|
||||||
(message ""))
|
|
||||||
|
|
||||||
(defvar met-sexptest-files '("expressions.m" "mclass.m")
|
(defvar met-sexptest-files '("expressions.m" "mclass.m" "blocks.m")
|
||||||
"List of files for running syntactic expression tests.")
|
"List of files for running syntactic expression tests.")
|
||||||
|
|
||||||
(defun metest-sexp-counting-test ()
|
(defvar metest-sexp-counting-test (cons "sexp counting" met-sexptest-files))
|
||||||
"Run a test to make sure string nd comment highlighting work."
|
(defun metest-sexp-counting-test (F)
|
||||||
(dolist (F met-sexptest-files)
|
"Run a test to make sure string and comment highlighting work."
|
||||||
(let ((buf (find-file-noselect (expand-file-name F met-testfile-path)))
|
(let ((buf (metest-find-file F))
|
||||||
(cnt 0))
|
(cnt 0))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(message ">> Starting sexp counting loop in %S" (current-buffer))
|
;;(message ">> Starting sexp counting loop in %S" (current-buffer))
|
||||||
(while (re-search-forward "#\\([0-9]\\)#" nil t)
|
(while (re-search-forward "#\\([0-9]\\)#" nil t)
|
||||||
(save-excursion
|
(save-excursion
|
||||||
(goto-char (match-beginning 0))
|
(goto-char (match-beginning 0))
|
||||||
|
@ -111,102 +268,122 @@
|
||||||
(let* ((num (string-to-number (match-string 1))))
|
(let* ((num (string-to-number (match-string 1))))
|
||||||
(save-restriction
|
(save-restriction
|
||||||
(narrow-to-region (point-at-bol) (point))
|
(narrow-to-region (point-at-bol) (point))
|
||||||
(matlab-move-simple-sexp-internal (- num))
|
(metest-condition-case-error-msg
|
||||||
|
(matlab-move-simple-sexp-internal (- num)))
|
||||||
(skip-chars-backward " \t;.=%")
|
(skip-chars-backward " \t;.=%")
|
||||||
(if (not (eq (point) (point-min)))
|
(if (not (eq (point) (point-min)))
|
||||||
(save-restriction
|
(save-restriction
|
||||||
(widen)
|
(widen)
|
||||||
(error "error at %d: Backward Sexp miscount tried %d, point %d, min %d"
|
(metest-error "Backward Sexp miscount tried %d, point %d, min %d"
|
||||||
(line-number-at-pos)
|
num (point) (point-at-bol))))
|
||||||
num (point) (point-at-bol))))
|
|
||||||
(skip-chars-forward " \t;.=%")
|
(skip-chars-forward " \t;.=%")
|
||||||
(matlab-move-simple-sexp-internal num)
|
(matlab-move-simple-sexp-internal num)
|
||||||
(skip-chars-forward " \t\n;.=%")
|
(skip-chars-forward " \t\n;.=%")
|
||||||
(if (not (eq (point) (point-max)))
|
(if (not (eq (point) (point-max)))
|
||||||
(save-restriction
|
(save-restriction
|
||||||
(widen)
|
(widen)
|
||||||
(error "Error at %d: Forward Sexp miscount tried %d, point %d, dest %d"
|
(metest-error "Forward Sexp miscount tried %d, point %d, dest %d"
|
||||||
(line-number-at-pos)
|
num (point) (point-at-eol)))))
|
||||||
num (point) (point-at-eol)))))
|
|
||||||
))
|
))
|
||||||
(end-of-line)
|
(end-of-line)
|
||||||
(setq cnt (1+ cnt))))
|
(setq cnt (1+ cnt))))
|
||||||
(kill-buffer buf)
|
(kill-buffer buf)
|
||||||
(message "<< Sexp counting syntax test: %d points passed" cnt)
|
(list cnt "tests")))
|
||||||
))
|
|
||||||
(message ""))
|
|
||||||
|
|
||||||
(defun metest-sexp-traversal-test ()
|
(defvar metest-sexp-traversal-test (cons "sexp block traversal" met-sexptest-files))
|
||||||
|
(defun metest-sexp-traversal-test (F)
|
||||||
"Run a test to make sure high level block navigation works."
|
"Run a test to make sure high level block navigation works."
|
||||||
(dolist (F met-sexptest-files)
|
(let ((buf (metest-find-file F))
|
||||||
(let ((buf (find-file-noselect (expand-file-name F met-testfile-path)))
|
|
||||||
(cnt 0))
|
(cnt 0))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(message ">> Starting sexp traversal loop in %S" (current-buffer))
|
;;(message ">> Starting sexp traversal loop in %S" (current-buffer))
|
||||||
(while (re-search-forward ">>\\([0-9]+\\)" nil t)
|
(while (re-search-forward ">>\\([0-9]+\\)" nil t)
|
||||||
(let* ((num (string-to-number (match-string 1)))
|
(let* ((num (string-to-number (match-string 1)))
|
||||||
(num2 0)
|
(num2 0)
|
||||||
(begin nil))
|
(begin nil))
|
||||||
(skip-chars-forward " \n\t;%")
|
(skip-chars-forward " \n\t;%")
|
||||||
(setq begin (point))
|
(setq begin (point))
|
||||||
(matlab-forward-sexp)
|
(metest-condition-case-error-msg (matlab--scan-block-forward))
|
||||||
(skip-chars-forward " \n\t;%")
|
(save-excursion
|
||||||
(if (not (looking-at "<<\\([0-9]+\\)"))
|
(skip-chars-forward " \n\t;%")
|
||||||
(error "Error at %d: Failed to find matching test end token for %d"
|
(if (not (looking-at "<<\\([0-9]+\\)"))
|
||||||
(line-number-at-pos) num)
|
(metest-error "Failed to find matching test end token for %d"
|
||||||
(setq num2 (string-to-number (match-string 1)))
|
num)
|
||||||
(when (/= num num2)
|
(setq num2 (string-to-number (match-string 1)))
|
||||||
(error "Error at %d: Failed to match correct test token. Start is %d, end is %d"
|
(when (/= num num2)
|
||||||
(line-number-at-pos) num num2)))
|
(metest-error "Failed to match correct test token. Start is %d, end is %d"
|
||||||
(matlab-backward-sexp)
|
num num2))))
|
||||||
|
(metest-condition-case-error-msg (matlab--scan-block-backward))
|
||||||
(when (/= (point) begin)
|
(when (/= (point) begin)
|
||||||
(error "Error at %d: Failed to reverse navigate sexp for %d"
|
(metest-error "Failed to reverse navigate sexp for %d"
|
||||||
(line-number-at-pos) num))
|
num))
|
||||||
)
|
)
|
||||||
(end-of-line)
|
(end-of-line)
|
||||||
(setq cnt (1+ cnt))))
|
(setq cnt (1+ cnt))))
|
||||||
(kill-buffer buf)
|
(kill-buffer buf)
|
||||||
(message "<< Sexp counting syntax test: %d points passed" cnt)
|
(list cnt "test")))
|
||||||
))
|
|
||||||
(message ""))
|
|
||||||
|
|
||||||
|
|
||||||
(defvar met-indents-files '("indents.m" "mclass.m")
|
(defvar met-indents-files '("indents.m" "continuations.m" "mclass.m" "blocks.m" "mfuncends.m" "mfuncnoendblock.m" "mclass_cont.m" "mfuncnofuncindent.m")
|
||||||
"List of files for running syntactic indentation tests.")
|
"List of files for running syntactic indentation tests.")
|
||||||
|
|
||||||
(defun metest-indents-test ()
|
(defun metest-indents-randomize-files ()
|
||||||
"Run a test to make sure high level block navigation works."
|
"Randomize the indentation in the inents test files."
|
||||||
(dolist (F met-indents-files)
|
(interactive)
|
||||||
(let ((buf (find-file-noselect (expand-file-name F met-testfile-path)))
|
(message "<< Flattening indentation ...")
|
||||||
(cnt 0))
|
(let ((matlab-scan-temporal-cache nil)) ;; disable cache for file load
|
||||||
(with-current-buffer buf
|
(dolist (F met-indents-files)
|
||||||
|
(with-current-buffer (metest-find-file F)
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
;; (indent-region (point-min) (point-max))
|
(while (not (eobp))
|
||||||
(message ">> Starting indents loop in %S" (current-buffer))
|
(beginning-of-line)
|
||||||
(while (re-search-forward "!!\\([0-9]+\\)" nil t)
|
(if (looking-at "^\\s-*$")
|
||||||
(let* ((num (string-to-number (match-string 1)))
|
(matlab--change-indentation 0)
|
||||||
(calc (matlab-calc-indent))
|
(matlab--change-indentation 3)) ;;(random 13)?
|
||||||
(begin nil))
|
(forward-line 1)
|
||||||
(when (not (= num calc))
|
)
|
||||||
(error "Error at %d: Indentation found is %d, expected %d"
|
;; And don't delete - leave it to find for the next test.
|
||||||
(line-number-at-pos) calc num))
|
;; but we do want to restart the mode and force a re-guess of the file type.
|
||||||
)
|
(matlab-mode)
|
||||||
(end-of-line)
|
))))
|
||||||
(setq cnt (1+ cnt))))
|
|
||||||
(kill-buffer buf)
|
(defvar metest-indents-test (cons "indenting" met-indents-files))
|
||||||
(message "<< Indentation syntax test: %d points passed" cnt)
|
(defvar metest-indent-counts 0)
|
||||||
))
|
(defun metest-indents-test (F)
|
||||||
(message ""))
|
"Run a test to make sure high level block navigation works."
|
||||||
|
(with-current-buffer (metest-find-file F)
|
||||||
|
(goto-char (point-min))
|
||||||
|
(let ((metest-indent-counts 0)
|
||||||
|
(matlab--change-indentation-override #'metest-indents-test-hook-fcn))
|
||||||
|
(metest-condition-case-error-msg
|
||||||
|
(matlab-indent-region (point-min) (point-max) nil t))
|
||||||
|
(kill-buffer (current-buffer))
|
||||||
|
(list metest-indent-counts "tests"))))
|
||||||
|
|
||||||
|
(defun metest-indents-test-hook-fcn (indent)
|
||||||
|
"Hook fcn used to capture indents from `indent-region'."
|
||||||
|
(save-excursion
|
||||||
|
(beginning-of-line)
|
||||||
|
|
||||||
|
(when (re-search-forward "!!\\([0-9]+\\)" (point-at-eol) t)
|
||||||
|
(let ((num (string-to-number (match-string 1))))
|
||||||
|
(setq metest-indent-counts (1+ metest-indent-counts))
|
||||||
|
(when (not (eq num indent))
|
||||||
|
(metest-error "Indentation computed is %s, expected %s"
|
||||||
|
indent num))))
|
||||||
|
|
||||||
|
;; Now do the indent in case a bad indent will trigger a bug later.
|
||||||
|
(matlab--change-indentation indent)
|
||||||
|
))
|
||||||
|
|
||||||
(defvar met-parser-files '("mpclass.m")
|
(defvar met-parser-files '("mpclass.m")
|
||||||
"List of files for running semantic parsing tests.")
|
"List of files for running semantic parsing tests.")
|
||||||
|
|
||||||
(defun metest-parse-test ()
|
(defvar metest-parse-test (cons "semantic parser" met-parser-files))
|
||||||
|
(defun metest-parse-test (F)
|
||||||
"Run the semantic parsing test to make sure the parse works."
|
"Run the semantic parsing test to make sure the parse works."
|
||||||
|
(let ((buf (metest-find-file F))
|
||||||
(dolist (F met-parser-files)
|
|
||||||
(let ((buf (find-file-noselect (expand-file-name F met-testfile-path)))
|
|
||||||
exp act
|
exp act
|
||||||
(cnt 0))
|
(cnt 0))
|
||||||
(with-current-buffer buf
|
(with-current-buffer buf
|
||||||
|
@ -217,12 +394,12 @@
|
||||||
|
|
||||||
;; Do the test
|
;; Do the test
|
||||||
(goto-char (point-min))
|
(goto-char (point-min))
|
||||||
(message ">> Starting semantic parser test in %S" (current-buffer))
|
;;(message ">> Starting semantic parser test in %S" (current-buffer))
|
||||||
|
|
||||||
(unless (re-search-forward "^%%\\s-*>>\\s-+SEMANTIC TEST" nil t)
|
(unless (re-search-forward "^%%\\s-*>>\\s-+SEMANTIC TEST" nil t)
|
||||||
(error "Semantic parser test: Failed to find test cookie."))
|
(metest-error "Semantic parser test: Failed to find test cookie."))
|
||||||
(unless (re-search-forward "^%{[ \t\n]+\\(((\\)" nil t)
|
(unless (re-search-forward "^%{[ \t\n]+\\(((\\)" nil t)
|
||||||
(error "Semantic parser test: Failed to find expected values."))
|
(metest-error "Semantic parser test: Failed to find expected values."))
|
||||||
(goto-char (match-beginning 1))
|
(goto-char (match-beginning 1))
|
||||||
(setq exp (read (buffer-substring (point)
|
(setq exp (read (buffer-substring (point)
|
||||||
(save-excursion (re-search-forward "%}" nil t)
|
(save-excursion (re-search-forward "%}" nil t)
|
||||||
|
@ -232,25 +409,262 @@
|
||||||
;; Compare the two lists ... simply.
|
;; Compare the two lists ... simply.
|
||||||
(while (and exp act)
|
(while (and exp act)
|
||||||
(unless (metest-compare-tags (car exp) (car act))
|
(unless (metest-compare-tags (car exp) (car act))
|
||||||
(error "Expected tag %s, found %s" (semantic-format-tag-prototype (car exp))
|
(metest-error "Expected tag %s, found %s" (semantic-format-tag-prototype (car exp))
|
||||||
(semantic-format-tag-prototype (car act))))
|
(semantic-format-tag-prototype (car act))))
|
||||||
(setq exp (cdr exp) act (cdr act) cnt (1+ cnt))
|
(setq exp (cdr exp) act (cdr act) cnt (1+ cnt))
|
||||||
)
|
)
|
||||||
(when (or exp act)
|
(when (or exp act)
|
||||||
(error "Found tags and expected tag lists differnet lengths.\nExpected Remains: %S\nActual Remains: %S"
|
(metest-error "Found tags and expected tag lists differnet lengths.\nExpected Remains: %S\nActual Remains: %S"
|
||||||
exp act))
|
exp act))
|
||||||
|
|
||||||
)
|
)
|
||||||
|
(list cnt "tests")))
|
||||||
(message ">> Semantic parser test: %d tags matched" cnt))))
|
|
||||||
|
|
||||||
|
|
||||||
(defun metest-compare-tags (EXP ACT)
|
(defun metest-compare-tags (EXP ACT)
|
||||||
"Return non-nil if EXP tag is similiar to ACT"
|
"Return non-nil if EXP tag is similiar to ACT"
|
||||||
(semantic-tag-similar-p EXP ACT :documentation)
|
(semantic-tag-similar-p EXP ACT :documentation)
|
||||||
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
(defconst met-kw-font-alist '(( "kw" . font-lock-keyword-face )
|
||||||
|
( "ty" . font-lock-type-face )
|
||||||
|
( "fn" . font-lock-function-name-face )
|
||||||
|
( "vn" . font-lock-variable-name-face )
|
||||||
|
( "vc" . (font-lock-variable-name-face
|
||||||
|
matlab-cross-function-variable-face) )
|
||||||
|
( "cn" . font-lock-constant-face )
|
||||||
|
( "co" . font-lock-comment-face )
|
||||||
|
( "st" . font-lock-string-face )
|
||||||
|
( "bi" . font-lock-builtin-face )
|
||||||
|
|
||||||
|
( "cb" . matlab-cellbreak-face )
|
||||||
|
( "ig" . matlab-ignored-comment-face )
|
||||||
|
( "pr" . matlab-pragma-face )
|
||||||
|
( "cd" . matlab-commanddual-string-face )
|
||||||
|
( "us" . matlab-unterminated-string-face )
|
||||||
|
( "ma" . matlab-math-face )
|
||||||
|
( "si" . matlab-simulink-keyword-face )
|
||||||
|
|
||||||
|
( "bo" . bold )
|
||||||
|
( "df" . nil )
|
||||||
|
)
|
||||||
|
"List of testing keywords and associated faces.")
|
||||||
|
|
||||||
|
|
||||||
|
(defvar met-complete-files '("complete.m")
|
||||||
|
"List of files for running font completion tests.")
|
||||||
|
|
||||||
|
(defvar met-complete-tools '((var . matlab-find-recent-variable)
|
||||||
|
(fcn . matlab-find-user-functions)
|
||||||
|
)
|
||||||
|
"List of tools that generate completions.")
|
||||||
|
|
||||||
|
(defvar metest-complete-test (cons "completion" met-complete-files))
|
||||||
|
(defun metest-complete-test (F)
|
||||||
|
"Test the completion tools in matlab-complete.el"
|
||||||
|
(let ((buf (metest-find-file F))
|
||||||
|
exp act
|
||||||
|
(cnt 0))
|
||||||
|
(with-current-buffer buf
|
||||||
|
(goto-char (point-min))
|
||||||
|
|
||||||
|
(while (re-search-forward "%\\s-*@@" nil t)
|
||||||
|
(setq exp (read (buffer-substring-no-properties (point) (scan-sexps (point) 1))))
|
||||||
|
;; Move to end of previous line, and try to do a complete
|
||||||
|
(matlab-with-context-line (matlab-previous-code-line (matlab-compute-line-context 2))
|
||||||
|
(end-of-line)
|
||||||
|
(let* ((prefix (buffer-substring-no-properties
|
||||||
|
(save-excursion (forward-word -1) (point))
|
||||||
|
(point)))
|
||||||
|
(sem (matlab-lattr-semantics prefix))
|
||||||
|
)
|
||||||
|
;; Did we get the expected semantics of this location?
|
||||||
|
(when (not (eq sem (car exp)))
|
||||||
|
(metest-error "Completion Semantic Missmatch: Expected %s but found %s" (car exp) sem))
|
||||||
|
|
||||||
|
(let* ((expR (nthcdr 2 exp))
|
||||||
|
(fcn (assoc (nth 1 exp) met-complete-tools))
|
||||||
|
(act (funcall (cdr fcn) prefix)))
|
||||||
|
(when (not (equal act expR))
|
||||||
|
(metest-error "Completion Missmatch: Expected %S but found %S using function %S"
|
||||||
|
expR act fcn))
|
||||||
|
)
|
||||||
|
))
|
||||||
|
(setq cnt (1+ cnt))
|
||||||
|
;; Skip this match, find the next.
|
||||||
|
(end-of-line)))
|
||||||
|
(list cnt "tests")))
|
||||||
|
|
||||||
|
|
||||||
|
(defvar met-fontlock-files '("fontlock.m" "mclass.m" "blocks.m")
|
||||||
|
"List of files for running font lock tests.")
|
||||||
|
|
||||||
|
(defvar metest-fontlock-test (cons "font lock" met-fontlock-files))
|
||||||
|
(defun metest-fontlock-test (F)
|
||||||
|
"Run the semantic parsing test to make sure the parse works."
|
||||||
|
(let ((buf (metest-find-file F))
|
||||||
|
(noninteractive nil) ;; fake out font lock
|
||||||
|
(cnt 0) (fntcnt 0))
|
||||||
|
(with-current-buffer buf
|
||||||
|
|
||||||
|
(goto-char (point-min))
|
||||||
|
|
||||||
|
(let ((md (match-data)))
|
||||||
|
;; Force font lock to throw catchable errors.
|
||||||
|
(font-lock-mode 1)
|
||||||
|
(font-lock-flush (point-min) (point-max))
|
||||||
|
(font-lock-ensure (point-min) (point-max))
|
||||||
|
(font-lock-fontify-region (point-min) (point-max))
|
||||||
|
|
||||||
|
;; FL test 1: make sure font lock is on and match data didn't change.
|
||||||
|
(unless font-lock-mode
|
||||||
|
(metest-error "Font Lock failed to turn on."))
|
||||||
|
;;(unless (equal md (match-data))
|
||||||
|
;; (metest-error "Font Locking transmuted the match data"))
|
||||||
|
(when (not (get-text-property 2 'fontified))
|
||||||
|
(metest-error "Font Lock Failure: can't run test because font lock failed to fontify region."))
|
||||||
|
)
|
||||||
|
|
||||||
|
;; Lines that start with %^ comments are FL keyword test features.
|
||||||
|
;; Find the line, then look for every ^ and find it's column and match
|
||||||
|
;; to previous line's column.
|
||||||
|
(while (re-search-forward "^\\s-*%\\(?: \\$\\$\\$\\)?\\^" nil t)
|
||||||
|
(let ((next (point-at-eol))
|
||||||
|
(prevstart (save-excursion (forward-line -1) (point-at-bol)))
|
||||||
|
)
|
||||||
|
(while (re-search-forward "\\^\\(\\w\\w\\)\\>" (point-at-eol) t)
|
||||||
|
(let* ((col (- (match-beginning 0) (point-at-bol)))
|
||||||
|
(fk (match-string-no-properties 1))
|
||||||
|
(pt (+ prevstart col))
|
||||||
|
(fnt (get-text-property pt 'face))
|
||||||
|
(fnt1 (if (consp fnt) (car fnt) fnt))
|
||||||
|
(fnt2 (if (consp fnt) (nth 1 fnt) nil))
|
||||||
|
(exp (cdr (assoc fk met-kw-font-alist))))
|
||||||
|
|
||||||
|
(cond
|
||||||
|
((consp exp)
|
||||||
|
(when (not (eq (car exp) fnt1))
|
||||||
|
(metest-error "Bad font layer 1 found @ col %d: Expected %S but found %S"
|
||||||
|
col (car exp) fnt1))
|
||||||
|
(when (not (eq (nth 1 exp) fnt2))
|
||||||
|
(metest-error "Bad font layer 2 found @ col %d: Expected %S but found %S"
|
||||||
|
col (nth 1 exp) fnt2)))
|
||||||
|
(t
|
||||||
|
(when (not (eq exp fnt1))
|
||||||
|
(metest-error "Bad font found @ col %d: Expected %S but found %S"
|
||||||
|
col exp fnt))))
|
||||||
|
|
||||||
|
(setq fntcnt (1+ fntcnt))
|
||||||
|
))
|
||||||
|
(goto-char next)
|
||||||
|
(setq cnt (1+ cnt))))
|
||||||
|
|
||||||
|
(list cnt "lines with " fntcnt "fonts tested"))))
|
||||||
|
|
||||||
|
;;; UTILS
|
||||||
|
;;
|
||||||
|
|
||||||
|
(defun metest-find-file (file)
|
||||||
|
"Read FILE into a buffer and return it.
|
||||||
|
Do error checking to provide easier debugging."
|
||||||
|
(let ((F (expand-file-name file met-testfile-path)))
|
||||||
|
(unless (file-exists-p F)
|
||||||
|
(error "Test file %s does not exist in %s" file met-testfile-path))
|
||||||
|
(find-file-noselect F)))
|
||||||
|
|
||||||
|
(defvar metest-error-context-lines 4)
|
||||||
|
(defun metest-error (&rest args)
|
||||||
|
"Produce an err with standardized file/line prefix."
|
||||||
|
(declare (indent 1))
|
||||||
|
(let* ((lineno (line-number-at-pos))
|
||||||
|
(fname (file-name-nondirectory (buffer-file-name)))
|
||||||
|
(pre (format "\n%s:%d: Error: " fname lineno))
|
||||||
|
(post (apply 'format args))
|
||||||
|
(prelines (min lineno metest-error-context-lines)))
|
||||||
|
(message "\n--vv buffer snip: %s vv--" fname)
|
||||||
|
(save-excursion
|
||||||
|
(forward-line (- prelines))
|
||||||
|
(while (> prelines 0)
|
||||||
|
(message "|%s" (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
|
||||||
|
(forward-line 1)
|
||||||
|
(setq prelines (1- prelines)))
|
||||||
|
(message ">%s" (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
|
||||||
|
(forward-line 1)
|
||||||
|
(while (and (> metest-error-context-lines prelines) (not (eobp)))
|
||||||
|
(message "|%s" (buffer-substring-no-properties (point-at-bol) (point-at-eol)))
|
||||||
|
(forward-line 1)
|
||||||
|
(setq prelines (1+ prelines))))
|
||||||
|
(message "---^^ buffer snip ^^---")
|
||||||
|
(setq metest-test-error t)
|
||||||
|
(error (concat pre post))))
|
||||||
|
|
||||||
|
;;; Logging prormance data for the tests
|
||||||
|
;;
|
||||||
|
(defvar metest-log-file "metest_timing_log.dat"
|
||||||
|
"File to store timing data to.")
|
||||||
|
|
||||||
|
(defvar metest-time-log nil
|
||||||
|
"Data stored for each run.")
|
||||||
|
|
||||||
|
(defun metest-log-init ()
|
||||||
|
"Init the log file and data variable."
|
||||||
|
(setq metest-time-log nil)
|
||||||
|
)
|
||||||
|
|
||||||
|
(defun metest-shorten (sym)
|
||||||
|
"Convert SYM into a column header."
|
||||||
|
(let ((str (symbol-name sym)))
|
||||||
|
(substring str 7 -5)))
|
||||||
|
|
||||||
|
(defun metest-log-write ()
|
||||||
|
"Write dta into our log file."
|
||||||
|
(save-current-buffer
|
||||||
|
(set-buffer (find-file-noselect metest-log-file))
|
||||||
|
(let ((LOG (reverse metest-time-log)))
|
||||||
|
(when (= (point-min) (point-max))
|
||||||
|
;; Initialize the new buffer
|
||||||
|
(insert "Time\t")
|
||||||
|
(insert (mapconcat (lambda (log) (metest-shorten (car log))) LOG "\t")))
|
||||||
|
;; Insert our measurements
|
||||||
|
(goto-char (point-max))
|
||||||
|
(newline)
|
||||||
|
(insert (format-time-string "\"%Y/%m/%d %H:%M\"\t" (current-time)))
|
||||||
|
(insert (mapconcat (lambda (log2) (format "%f" (cdr log2))) LOG "\t"))
|
||||||
|
(save-buffer)
|
||||||
|
;; Go back and find our baseline and return it.
|
||||||
|
(goto-char (point-min))
|
||||||
|
(forward-line 1)
|
||||||
|
(read (concat "(" (buffer-substring-no-properties (point-at-bol) (point-at-eol)) ")"))
|
||||||
|
)))
|
||||||
|
|
||||||
|
(defun metest-log-report (baseline)
|
||||||
|
"Report via message what happened during the test suite."
|
||||||
|
(let ((log (reverse metest-time-log))
|
||||||
|
(base (cdr baseline)))
|
||||||
|
(princ "Baseln\tRun\tImprovement\tTest\n")
|
||||||
|
(while (and log base)
|
||||||
|
(princ (format "%.4f\t" (car base)))
|
||||||
|
(princ (format "%.4f\t" (cdr (car log))))
|
||||||
|
(princ (format "%.4f\t\t" (- (car base) (cdr (car log)))))
|
||||||
|
(princ (metest-shorten (car (car log))))
|
||||||
|
(princ "\n")
|
||||||
|
(setq log (cdr log)
|
||||||
|
base (cdr base)))
|
||||||
|
))
|
||||||
|
|
||||||
|
(defun metest-timeit (fcn &optional file)
|
||||||
|
"Time running FCN and save result in LOGFILE.
|
||||||
|
Use this to track perforamnce improvements during development automatically."
|
||||||
|
(let* ((start (current-time))
|
||||||
|
(out (funcall fcn file))
|
||||||
|
(end (current-time))
|
||||||
|
(diff (float-time (time-subtract end start))))
|
||||||
|
(if (eq fcn (car-safe (car-safe metest-time-log)))
|
||||||
|
;; Same fcn, append our number
|
||||||
|
(setcdr (car metest-time-log) (+ diff (cdr (car metest-time-log))))
|
||||||
|
(push (cons fcn diff) metest-time-log))
|
||||||
|
(cons diff out)))
|
||||||
|
|
||||||
(provide 'metest)
|
(provide 'metest)
|
||||||
|
|
||||||
;;; metest.el ends here
|
;;; metest.el ends here
|
||||||
|
|
|
@ -0,0 +1,26 @@
|
||||||
|
function mfuncends( )
|
||||||
|
% Test function that has ends for each function. !!0
|
||||||
|
% !!0
|
||||||
|
% Used with test harness to validate indentation and end detection. !!0
|
||||||
|
% !!0
|
||||||
|
% %%%function function function
|
||||||
|
|
||||||
|
fcn_call(); %!!4
|
||||||
|
|
||||||
|
if condition %!!4
|
||||||
|
fcn_call(); %!!8
|
||||||
|
fcn_call ... !!8
|
||||||
|
(); %!!12
|
||||||
|
end %!!4
|
||||||
|
|
||||||
|
end%!!0 - also no space after end
|
||||||
|
|
||||||
|
function a=fcn_call(inp) %!!0
|
||||||
|
|
||||||
|
while inp > 0 %!!4
|
||||||
|
fcn_call(inp-1); %!!8
|
||||||
|
a = [ 1 2 ... !!8
|
||||||
|
3 4 ]; %!!14
|
||||||
|
end %!!4
|
||||||
|
|
||||||
|
end %!!0
|
|
@ -0,0 +1,15 @@
|
||||||
|
function mfuncnoend
|
||||||
|
% A function file that does not have ends at the end of functions.
|
||||||
|
%
|
||||||
|
% %%% function nil nil
|
||||||
|
|
||||||
|
fcn_call(1)
|
||||||
|
|
||||||
|
|
||||||
|
function fcn_call(idx)
|
||||||
|
|
||||||
|
if idx > 0
|
||||||
|
fcn_call(ix-1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,33 @@
|
||||||
|
%{
|
||||||
|
Add a block comment at the beginning to skip over.
|
||||||
|
x % !!2
|
||||||
|
% !! 0
|
||||||
|
%}
|
||||||
|
function mfuncnoendblock
|
||||||
|
% A function file that does not have ends at the end of functions.
|
||||||
|
% !!0
|
||||||
|
% %%% function nil nil
|
||||||
|
|
||||||
|
fcn_call(1) %!!0
|
||||||
|
|
||||||
|
|
||||||
|
function fcn_call(idx) %!!0
|
||||||
|
|
||||||
|
if idx > 0 %!!0
|
||||||
|
fcn_call(ix-1) %!!4
|
||||||
|
goo(3);
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
function c=goo(p3) %!!0
|
||||||
|
if p3 < 3 %!!0
|
||||||
|
if p3 < 0 %!!4
|
||||||
|
c = p3 * -3; %!!8
|
||||||
|
else %!!4
|
||||||
|
c = p3 * 3; %!!8
|
||||||
|
for i=1:10 %!!8
|
||||||
|
c = c + i; %!!12
|
||||||
|
end %!!8
|
||||||
|
end %!!4
|
||||||
|
else %!!0
|
||||||
|
c=p3*4; %!!4
|
||||||
|
end %!!0
|
|
@ -0,0 +1,15 @@
|
||||||
|
function mfuncnoendindent
|
||||||
|
% A function file that does not have ends at the end of functions.
|
||||||
|
%
|
||||||
|
% %%% function nil t
|
||||||
|
|
||||||
|
fcn_call(1)
|
||||||
|
|
||||||
|
|
||||||
|
function fcn_call(idx)
|
||||||
|
|
||||||
|
if idx > 0
|
||||||
|
fcn_call(ix-1)
|
||||||
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
function mfuncnofuncindent( )
|
||||||
|
% Test function that has ends for each function. !!0
|
||||||
|
% !!0
|
||||||
|
% Used with test harness to validate indentation and end detection. !!0
|
||||||
|
% !!0
|
||||||
|
% %%%function function nil
|
||||||
|
|
||||||
|
fcn_call(); %!!0
|
||||||
|
|
||||||
|
if condition %!!0
|
||||||
|
fcn_call(); %!!4
|
||||||
|
fcn_call ... !!4
|
||||||
|
(); %!!8
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
end%!!0 - also no space after end
|
||||||
|
|
||||||
|
function a=fcn_call(inp) %!!0
|
||||||
|
|
||||||
|
while inp > 0 %!!0
|
||||||
|
fcn_call(inp-1); %!!4
|
||||||
|
a = [ 1 2 ... !!4
|
||||||
|
3 4 ]; %!!10
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
end %!!0
|
||||||
|
|
||||||
|
%{
|
||||||
|
% Local Variables:
|
||||||
|
% matlab-indent-function-body: nil
|
||||||
|
% End:
|
||||||
|
%}
|
|
@ -0,0 +1,11 @@
|
||||||
|
function mfuncspacey( )
|
||||||
|
% Test function that has ends for each function.
|
||||||
|
%
|
||||||
|
% Used with test harness to validate indentation and end detection.
|
||||||
|
%
|
||||||
|
% %%%function function function
|
||||||
|
|
||||||
|
fcn_call();
|
||||||
|
|
||||||
|
end
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
%% Tests for char vector and string handling.
|
%% Tests for char vector and string handling.
|
||||||
%
|
%
|
||||||
% #c#
|
% #c#
|
||||||
|
%
|
||||||
|
% %%%script script script
|
||||||
|
|
||||||
%% Basic strings
|
%% Basic strings
|
||||||
|
|
||||||
|
@ -13,8 +15,8 @@ stringscalar = "string scalar #s#";
|
||||||
% Comment with 'character vector #c#' in it.
|
% Comment with 'character vector #c#' in it.
|
||||||
% Comment with "string scalar #c#" in it.
|
% Comment with "string scalar #c#" in it.
|
||||||
|
|
||||||
charvi = 'char vector incomplete #v#
|
charvi = 'char vector incomplete #V#
|
||||||
stringi = "string scalar incomplete #s#
|
stringi = "string scalar incomplete #S#
|
||||||
|
|
||||||
% Comment with 'char vector incomplete #c#
|
% Comment with 'char vector incomplete #c#
|
||||||
% Comment with "string scalar incomplete #c#
|
% Comment with "string scalar incomplete #c#
|
||||||
|
@ -27,16 +29,16 @@ stringcv = "string scalar with 'char vec #s#' in it";
|
||||||
chard = 'char vector with '' in it #v#';
|
chard = 'char vector with '' in it #v#';
|
||||||
stringd = "string scalar with "" in it #s#";
|
stringd = "string scalar with "" in it #s#";
|
||||||
|
|
||||||
chardi = 'incomplete char vector with '' in it #v#
|
chardi = 'incomplete char vector with '' in it #V#
|
||||||
stringdi = "incomplete string scalar with "" in it #s#
|
stringdi = "incomplete string scalar with "" in it #S#
|
||||||
|
|
||||||
%% Strings with Comments
|
%% Strings with Comments
|
||||||
|
|
||||||
charvc = 'char vector with % comment char #v#';
|
charvc = 'char vector with % comment char #v#';
|
||||||
stringc = "string scalar with % comment char #s#";
|
stringc = "string scalar with % comment char #s#";
|
||||||
|
|
||||||
charvci = 'incomplete char vector with % comment char #v#
|
charvci = 'incomplete char vector with % comment char #V#
|
||||||
stringci = "incomplete string scalar with % comment char #s#
|
stringci = "incomplete string scalar with % comment char #S#
|
||||||
|
|
||||||
charvbc = 'char vector with %{ comment char #v# %} ';
|
charvbc = 'char vector with %{ comment char #v# %} ';
|
||||||
stringbc = "string scalar with %{ comment char #s# %} ";
|
stringbc = "string scalar with %{ comment char #s# %} ";
|
||||||
|
@ -69,19 +71,24 @@ icell_in_strs2_nested = { 'charv innercell " #v# }' "strinc innercel ' #s# }"
|
||||||
%% Elipsis as comment
|
%% Elipsis as comment
|
||||||
|
|
||||||
fun_call(); ... This is a comment after an elipsis #e#
|
fun_call(); ... This is a comment after an elipsis #e#
|
||||||
fun_call(); ... 'charvec in elipsis comment #e#'
|
|
||||||
fun_call(); ... "string in elipsis comment #e#"
|
|
||||||
fun_call(); ... % comment after an elipsis is still elipsis #e#
|
|
||||||
|
|
||||||
|
fun_call(); ... 'charvec in elipsis comment #e#'
|
||||||
|
|
||||||
|
fun_call(); ... "string in elipsis comment #e#"
|
||||||
|
|
||||||
|
fun_call(); ... % comment after an elipsis is still elipsis #e#
|
||||||
|
|
||||||
%% Elipsis and strings and other comments
|
%% Elipsis and strings and other comments
|
||||||
|
|
||||||
Ecv = 'string with ... in #v# it';
|
Ecv = 'string with ... in #v# it';
|
||||||
Es = "string with ... in #s# it";
|
Es = "string with ... in #s# it";
|
||||||
% Comment with ... in it #c#
|
% Comment with ... in it #c#
|
||||||
|
eecv = '...'; % string with only ellipsis in it #c#
|
||||||
|
ees = "..."; % string with only ellipsis in it #c#
|
||||||
|
|
||||||
x = [ 'foo bar',newline,...
|
x = [ 'foo bar', newline, ... #e#
|
||||||
' ''-goo'', ... #v#',newline,...
|
' ''-goo'', ... #v#', newline, ... #e#
|
||||||
' ''-bar'', ... #v#',newline];
|
' ''-bar'', ... #v#', newline ];
|
||||||
|
|
||||||
func_call1('function with charvec', ... #e#
|
func_call1('function with charvec', ... #e#
|
||||||
'after ellipsis charvec with ellipsis ... #v#');
|
'after ellipsis charvec with ellipsis ... #v#');
|
||||||
|
@ -141,7 +148,7 @@ else
|
||||||
Cs = "not unreachable #s#";
|
Cs = "not unreachable #s#";
|
||||||
end
|
end
|
||||||
|
|
||||||
%% Block Comments #c#
|
%% Block Comments #C#
|
||||||
|
|
||||||
%{
|
%{
|
||||||
|
|
||||||
|
@ -154,4 +161,34 @@ end
|
||||||
|
|
||||||
not_commented();
|
not_commented();
|
||||||
|
|
||||||
|
%{ just a regular comment #c# %} should_be_comment #c#
|
||||||
|
|
||||||
% Normal comment #c#
|
% Normal comment #c#
|
||||||
|
|
||||||
|
%% Ignored Comments #C#
|
||||||
|
|
||||||
|
% $$$ This comment is ignored by indentation engine. #i#
|
||||||
|
|
||||||
|
%^ This comment is igored too, used in tests for font lock. #i#
|
||||||
|
|
||||||
|
|
||||||
|
%% Command line dual #C#
|
||||||
|
% Note: stuff after a symbol<space> treated as string
|
||||||
|
|
||||||
|
disp _this is string input to function #d#_
|
||||||
|
disp _this is also string input to a function #d#_
|
||||||
|
|
||||||
|
regularcode; #r#
|
||||||
|
|
||||||
|
% Note: Case sensitivity of cmd dual functions
|
||||||
|
DISP _regular code even though ML would treat as cmd dual #r#_
|
||||||
|
|
||||||
|
%{
|
||||||
|
% Local Variables:
|
||||||
|
% matlab-syntax-support-command-dual: t
|
||||||
|
% matlab-show-mlint-warnings: nil
|
||||||
|
% End:
|
||||||
|
%}
|
||||||
|
|
||||||
|
|
||||||
|
%% END
|
||||||
|
|
|
@ -0,0 +1,28 @@
|
||||||
|
function emacsrun(mfile, varargin)
|
||||||
|
% Run code from MFILE.
|
||||||
|
% Assumes MFILE was recently edited, and proactively clears that function.
|
||||||
|
%
|
||||||
|
% Command sent by Emacs for save-and-go functionality
|
||||||
|
|
||||||
|
% Now figure out if shortFileName is on the path.
|
||||||
|
[ fullFilePath, shortFileName ] = fileparts(mfile);
|
||||||
|
onpath = ~isempty(which(shortFileName));
|
||||||
|
|
||||||
|
if ~exist(fullFilePath,'file')
|
||||||
|
error('You must save your file into a location accessible by MATLAB process.');
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
% If not on the path, temporarilly switch to that directory so it and an files it references are
|
||||||
|
% accessible
|
||||||
|
if ~onpath
|
||||||
|
oldpath = pwd;
|
||||||
|
cd(fullFilePath);
|
||||||
|
cleanup = onCleanup(@()cd(oldpath));
|
||||||
|
end
|
||||||
|
clear(shortFileName);
|
||||||
|
|
||||||
|
cmd = [ shortFileName varargin{:} ];
|
||||||
|
|
||||||
|
evalin('base',cmd);
|
||||||
|
end
|
Loading…
Reference in New Issue