comparison packages/matlab.el @ 67:b5370dfae4e3

Rename plugins/ to packages/
author Jordi Gutiérrez Hermoso <jordigh@octave.org>
date Thu, 02 Aug 2012 12:20:20 -0400
parents plugins/matlab.el@e26268005d54
children
comparison
equal deleted inserted replaced
66:8fe5451431c2 67:b5370dfae4e3
1 ;;; matlab.el --- major mode for MATLAB(R) dot-m files
2 ;;
3 ;; Author: Matt Wette <mwette@alumni.caltech.edu>,
4 ;; Eric M. Ludlam <eludlam@mathworks.com>
5 ;; Maintainer: Eric M. Ludlam <eludlam@mathworks.com>
6 ;; Created: 04 Jan 91
7 ;; Keywords: MATLAB(R)
8 ;; Version:
9
10 (defconst matlab-mode-version "3.3.0"
11 "Current version of MATLAB(R) mode.")
12
13 ;;
14 ;; Copyright (C) 2004-2005 The Mathworks, Inc
15 ;; Copyright (C) 1997-2004 Eric M. Ludlam: The MathWorks, Inc
16 ;; Copyright (C) 1991-1997 Matthew R. Wette
17 ;;
18 ;; This program is free software; you can redistribute it and/or modify
19 ;; it under the terms of the GNU General Public License as published by
20 ;; the Free Software Foundation; either version 2, or (at your option)
21 ;; any later version.
22 ;;
23 ;; This program is distributed in the hope that it will be useful,
24 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
25 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
26 ;; GNU General Public License for more details.
27 ;;
28 ;; You should have received a copy of the GNU General Public License
29 ;; along with GNU Emacs; see the file COPYING. If not, write to
30 ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
31 ;;
32 ;;; Commentary:
33 ;;
34 ;; This major mode for GNU Emacs provides support for editing MATLAB(R) dot-m
35 ;; files. It automatically indents for block structures (including nested
36 ;; functions), line continuations (e.g., ...), and comments.
37 ;;
38 ;; Additional features include auto-fill including auto-additions of
39 ;; ellipsis for commands, and even strings. Block/end construct
40 ;; highlighting as you edit. Primitive code-verification and
41 ;; identification. Templates and other code editing functions.
42 ;; Advanced symbol completion. Code highlighting via font-lock.
43 ;; There are many navigation commands that let you move across blocks
44 ;; of code at different levels.
45 ;;
46 ;; Lastly, there is support for running MATLAB(R) in an Emacs buffer,
47 ;; with full shell history and debugger support (when used with the db
48 ;; commands.) The shell can be used as an online help while editing
49 ;; code, providing help on functions, variables, or running arbitrary
50 ;; blocks of code from the buffer you are editing.
51
52 ;;; Code:
53
54 (require 'easymenu)
55 (require 'tempo)
56 (require 'derived)
57
58 ;; compatibility
59 (if (string-match "X[Ee]macs" emacs-version)
60 (progn
61 (defalias 'matlab-make-overlay 'make-extent)
62 (defalias 'matlab-overlay-put 'set-extent-property)
63 (defalias 'matlab-overlay-get 'extent-property)
64 (defalias 'matlab-delete-overlay 'delete-extent)
65 (defalias 'matlab-overlay-start 'extent-start-position)
66 (defalias 'matlab-overlay-end 'extent-end-position)
67 (defalias 'matlab-previous-overlay-change 'previous-extent-change)
68 (defalias 'matlab-next-overlay-change 'next-extent-change)
69 (defalias 'matlab-overlays-at
70 (lambda (pos) (extent-list nil pos pos)))
71 (defalias 'matlab-cancel-timer 'delete-itimer)
72 (defun matlab-run-with-idle-timer (secs repeat function &rest args)
73 (condition-case nil
74 (apply 'start-itimer
75 "matlab" function secs
76 (if repeat secs nil) t
77 t (car args))
78 (error
79 ;; If the above doesn't work, then try this old version of
80 ;; start itimer.
81 (start-itimer "matlab" function secs (if repeat secs nil)))))
82 )
83 (defalias 'matlab-make-overlay 'make-overlay)
84 (defalias 'matlab-overlay-put 'overlay-put)
85 (defalias 'matlab-overlay-get 'overlay-get)
86 (defalias 'matlab-delete-overlay 'delete-overlay)
87 (defalias 'matlab-overlay-start 'overlay-start)
88 (defalias 'matlab-overlay-end 'overlay-end)
89 (defalias 'matlab-previous-overlay-change 'previous-overlay-change)
90 (defalias 'matlab-next-overlay-change 'next-overlay-change)
91 (defalias 'matlab-overlays-at 'overlays-at)
92 (defalias 'matlab-cancel-timer 'cancel-timer)
93 (defalias 'matlab-run-with-idle-timer 'run-with-idle-timer)
94 )
95
96 (cond ((fboundp 'point-at-bol)
97 (defalias 'matlab-point-at-bol 'point-at-bol)
98 (defalias 'matlab-point-at-eol 'point-at-eol))
99 ;; Emacs 20.4
100 ((fboundp 'line-beginning-position)
101 (defalias 'matlab-point-at-bol 'line-beginning-position)
102 (defalias 'matlab-point-at-eol 'line-end-position))
103 (t
104 (defmacro matlab-point-at-bol ()
105 (save-excursion (beginning-of-line) (point)))
106 (defmacro matlab-point-at-eol ()
107 (save-excursion (end-of-line) (point)))))
108
109 (defmacro matlab-run-in-matlab-mode-only (&rest body)
110 "Execute BODY only if the active buffer is a MATLAB(R) M-file buffer."
111 `(if (eq major-mode 'matlab-mode)
112 (progn
113 ,@body)
114 (error "This command works only in a MATLAB M-file buffer")))
115
116 (defun matlab-with-emacs-link ()
117 "Return non-nil if Emacs Link is running and user wants to use it."
118 (and (featurep 'matlab-eei)
119 matlab-use-eei
120 matlab-eei-process))
121
122 ;;; User-changeable variables =================================================
123
124 ;; Variables which the user can change
125 (defgroup matlab nil
126 "MATLAB(R) mode."
127 :prefix "matlab-"
128 :group 'languages)
129
130 (defcustom matlab-indent-level 4
131 "*The basic indentation amount in `matlab-mode'."
132 :group 'matlab
133 :type 'integer)
134
135 (defcustom matlab-cont-level 4
136 "*Basic indentation after continuation if no other methods are found."
137 :group 'matlab
138 :type 'integer)
139
140 (defcustom matlab-cont-requires-ellipsis t
141 "*Specify if ellipses are required at the end of a line for continuation.
142 Future versions of Matlab may not require ellipses ... , so a heuristic
143 determining if there is to be continuation is used instead."
144 :group 'matlab
145 :type 'integer)
146
147 (defcustom matlab-case-level '(2 . 2)
148 "*How far to indent case/otherwise statements in a switch.
149 This can be an integer, which is the distance to indent the CASE and
150 OTHERWISE commands, and how far to indent commands appearing in CASE
151 and OTHERWISE blocks. It can also be a cons cell which is of form
152 (CASEINDENT . COMMANDINDENT)
153 where CASEINDENT is the indentation of the CASE and OTHERWISE
154 statements, and COMMANDINDENT is the indentation of commands appearing
155 after the CASE or OTHERWISE command.
156
157 Note: Currently a bug exists if:
158 CASEINDENT+COMMANDINDENT != `matlab-indent-level'
159 so if you customize these variables, follow the above rule, and you
160 should be ok."
161 :group 'matlab
162 :type 'sexp)
163
164 (defcustom matlab-indent-function-body 'guess
165 "*If non-nil, indent body of function.
166 If the global value is nil, do not indent function bodies.
167 If the global value is t, always indent function bodies.
168 If the global value is 'guess, then the local value will be set to
169 either nil or t when the MATLAB mode is started based on the
170 file's current indentation."
171 :group 'matlab
172 :type '(choice (const :tag "Always" t)
173 (const :tag "Never" nil)
174 (const :tag "Guess" 'guess)))
175
176 (make-variable-buffer-local 'matlab-indent-function-body)
177
178 (defcustom matlab-functions-have-end nil
179 "*If non-nil, functions-have-end minor mode is on by default."
180 :group 'matlab
181 :type 'boolean)
182
183 (make-variable-buffer-local 'matlab-functions-have-end)
184
185 (defun matlab-toggle-functions-have-end ()
186 (interactive)
187 (matlab-toggle-functions-have-end-minor-mode))
188
189 ;; The following minor mode is on if and only if the above variable is true;
190 (easy-mmode-define-minor-mode matlab-functions-have-end-minor-mode
191 "Toggle functions-have-end minor mode, indicating function/end pairing."
192 nil
193 (condition-case nil ;; avoid parse error on xemacs
194 (eval (read "#(\" function...end\" 0 15 (face (font-lock-keyword-face) fontified t))"))
195 (error " function...end"))
196 nil ; empty mode-map
197 )
198
199 (defun matlab-toggle-functions-have-end-minor-mode ()
200 (matlab-functions-have-end-minor-mode)
201 (if (and matlab-functions-have-end-minor-mode (not (eq major-mode 'matlab-mode)))
202 (progn
203 (matlab-functions-have-end-minor-mode -1)
204 (error "functions-have-end minor mode is only for MATLAB Major mode")))
205 (setq matlab-functions-have-end matlab-functions-have-end-minor-mode))
206
207 (defcustom matlab-indent-past-arg1-functions
208 "[sg]et\\(_param\\)?\\|waitfor"
209 "*Regex describing functions whose first arg is special.
210 This specialness means that all following parameters which appear on
211 continued lines should appear indented to line up with the second
212 argument, not the first argument."
213 :group 'matlab
214 :type 'string)
215
216 (defcustom matlab-arg1-max-indent-length 15
217 "*The maximum length to indent when indenting past arg1.
218 If arg1 is exceptionally long, then only this number of characters
219 will be indented beyond the open paren starting the parameter list.")
220
221 (defcustom matlab-maximum-indents '(;; = is a convenience. Don't go too far
222 (?= . (10 . 4))
223 ;; Fns should provide hard limits
224 (?\( . 50)
225 ;; Matrix/Cell arrays
226 (?\[ . 20)
227 (?\{ . 20))
228 "Alist of maximum indentations when lining up code.
229 Each element is of the form (CHAR . INDENT) where char is a character
230 the indent engine is using, and INDENT is the maximum indentation
231 allowed. Indent could be of the form (MAXIMUM . INDENT), where
232 MAXIMUM is the maximum allowed calculated indent, and INDENT is the
233 amount to use if MAXIMUM is reached."
234 :group 'matlab
235 :type '(repeat (cons (character :tag "Open List Character")
236 (sexp :tag "Number (max) or cons (max indent)"))))
237
238 (defcustom matlab-handle-simulink t
239 "*If true, add in a few simulink customizations.
240 This variable's state is mostly useful when set at load time when
241 simulink font lock keywords can be removed. This will handle
242 additional cases as the need arrises."
243 :group 'matlab
244 :type 'boolean)
245
246 (defcustom matlab-auto-fill t
247 "*If true, set variable `auto-fill-function' to our function at startup."
248 :group 'matlab
249 :type 'boolean)
250
251 (defcustom matlab-fill-fudge 10
252 "Number of characters around `fill-column' we can fudge filling.
253 Basically, there are places that are very convenient to fill at, but
254 might not be the closest fill spot, or occur after `fill-column'.
255 If they occur within this fudge factor, we will use them.
256 Also, if none of the above occur, and we find a symbol to break at,
257 but an open paren (group) starts or ends within this fudge factor,
258 move there to boost the amount of fill leverage we can get."
259 :group 'matlab
260 :type 'integer)
261
262 (defcustom matlab-fill-fudge-hard-maximum 79
263 "The longest line allowed when auto-filling code.
264 This overcomes situations where the `fill-column' plus the
265 `matlab-fill-fudge' is greater than some hard desired limit."
266 :group 'matlab
267 :type 'integer)
268
269 (defcustom matlab-elipsis-string "..."
270 "Text used to perform continuation on code lines.
271 This is used to generate and identify continuation lines.")
272
273 (defcustom matlab-fill-code t
274 "*If true, `auto-fill-mode' causes code lines to be automatically continued."
275 :group 'matlab
276 :type 'boolean)
277
278 (defcustom matlab-fill-count-ellipsis-flag t
279 "*Non-nil means to count the ellipsis when auto filling.
280 This effectively shortens the `fill-column' by the length of
281 `matlab-elipsis-string'.")
282
283 (defcustom matlab-fill-strings-flag t
284 "*Non-nil means that when auto-fill is on, strings are broken across lines.
285 If `matlab-fill-count-ellipsis-flag' is non nil, this shortens the
286 `fill-column' by the length of `matlab-elipsis-string'.")
287
288 (defcustom matlab-comment-column 40
289 "*The goal comment column in `matlab-mode' buffers."
290 :group 'matlab
291 :type 'integer)
292
293 (defcustom matlab-comment-anti-indent 0
294 "*Amount of anti-indentation to use for comments in relation to code."
295 :group 'matlab
296 :type 'integer)
297
298 (defcustom matlab-comment-line-s "% "
299 "*String to start comment on line by itself."
300 :group 'matlab
301 :type 'string)
302
303 (defcustom matlab-comment-on-line-s "% "
304 "*String to start comment on line with code."
305 :group 'matlab
306 :type 'string)
307
308 (defcustom matlab-comment-region-s "% $$$ "
309 "*String inserted by \\[matlab-comment-region] at start of each line in \
310 region."
311 :group 'matlab
312 :type 'string)
313
314 (defcustom matlab-verify-on-save-flag t
315 "*Non-nil means to verify M whenever we save a file."
316 :group 'matlab
317 :type 'boolean)
318
319 (defcustom matlab-mode-verify-fix-functions
320 '(matlab-mode-vf-functionname)
321 "List of function symbols which perform a verification and fix to M code.
322 Each function gets no arguments, and returns nothing. They can move
323 point, but it will be restored for them."
324 :group 'matlab
325 :type '(repeat (choice :tag "Function: "
326 '(matlab-mode-vf-functionname
327 matlab-mode-vf-block-matches-forward
328 matlab-mode-vf-block-matches-backward
329 matlab-mode-vf-quiesce-buffer
330 ))))
331
332 (defcustom matlab-block-verify-max-buffer-size 50000
333 "*Largest buffer size allowed for block verification during save."
334 :group 'matlab
335 :type 'integer)
336
337 ;; It is time to disable this.
338 (defcustom matlab-vers-on-startup nil
339 "*If non-nil, show the version number on startup."
340 :group 'matlab
341 :type 'boolean)
342
343 (defcustom matlab-highlight-block-match-flag t
344 "*Non-nil means to highlight the matching if/end/whatever.
345 The highlighting only occurs when the cursor is on a block start or end
346 keyword."
347 :group 'matlab
348 :type 'boolean)
349
350 (defcustom matlab-show-periodic-code-details-flag nil
351 "*Non-nil means to show code details in the minibuffer.
352 This will only work if `matlab-highlight-block-match-flag' is non-nil."
353 :group 'matlab
354 :type 'boolean)
355
356 (defcustom matlab-use-eei t
357 "*Use Emacs Link for save-and-go and run-region."
358 :group 'matlab
359 :type 'boolean)
360
361 (defcustom matlab-mode-hook nil
362 "*List of functions to call on entry to MATLAB mode."
363 :group 'matlab
364 :type 'hook)
365
366 (defcustom matlab-completion-technique 'complete
367 "*How the `matlab-complete-symbol' interfaces with the user.
368 Valid values are:
369
370 'increment - which means that new strings are tried with each
371 successive call until all methods are exhausted.
372 (Similar to `hippie-expand'.)
373 'complete - Which means that if there is no single completion, then
374 all possibilities are displayed in a completion buffer."
375 :group 'matlab
376 :type '(radio (const :tag "Incremental completion (hippie-expand)."
377 increment)
378 (const :tag "Show completion buffer."
379 complete)))
380
381 (defcustom matlab-show-mlint-warnings nil
382 "*If non-nil, show mlint warnings."
383 :group 'matlab
384 :type 'boolean)
385
386 (make-variable-buffer-local 'matlab-show-mlint-warnings)
387
388 (defcustom matlab-highlight-cross-function-variables nil
389 "*If non-nil, highlight cross-function variables."
390 :group 'matlab
391 :type 'boolean)
392
393 (make-variable-buffer-local 'matlab-highlight-cross-function-variables)
394
395 (defcustom matlab-return-add-semicolon nil
396 "*If non nil, check to see a semicolon is needed when RET is pressed."
397 :group 'matlab
398 :type 'boolean)
399
400 (make-variable-buffer-local 'matlab-return-add-semicolon)
401
402 ;; Load in the region we use for highlighting stuff.
403 (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
404
405 (let ((l-region-face (if (facep 'region) 'region 'zmacs-region)))
406 ;; If we have custom, we can make our own special face like this
407 (defface matlab-region-face
408 (list
409 (list t
410 (list :background (face-background l-region-face)
411 :foreground (face-foreground l-region-face))))
412 "*Face used to highlight a matlab region."
413 :group 'matlab))
414
415 ;; If we do not, then we can fake it by copying 'region.
416 (cond ((facep 'region)
417 (copy-face 'region 'matlab-region-face))
418 (t
419 (copy-face 'zmacs-region 'matlab-region-face))))
420
421 (defvar matlab-unterminated-string-face 'matlab-unterminated-string-face
422 "Self reference for unterminated string face.")
423
424 (defvar matlab-simulink-keyword-face 'matlab-simulink-keyword-face
425 "Self reference for simulink keywords.")
426
427 (defvar matlab-nested-function-keyword-face 'matlab-nested-function-keyword-face
428 "Self reference for nested function/end keywords.")
429
430 (defvar matlab-cross-function-variable-face 'matlab-cross-function-variable-face
431 "Self reference for cross-function variables.")
432
433 (defvar matlab-cellbreak-face 'matlab-cellbreak-face
434 "Self reference for cellbreaks.")
435
436 (defun matlab-font-lock-adjustments ()
437 "Make adjustments for font lock.
438 If font lock is not loaded, lay in wait."
439 (if (and (featurep 'custom) (fboundp 'custom-declare-variable))
440
441 (progn
442 (defface matlab-unterminated-string-face
443 (list
444 (list t
445 (list :background (face-background font-lock-string-face)
446 :foreground (face-foreground font-lock-string-face)
447 :underline t)))
448 "*Face used to highlight unterminated strings."
449 :group 'matlab)
450 (defface matlab-simulink-keyword-face
451 (list
452 (list t
453 (list :background (face-background font-lock-type-face)
454 :foreground (face-foreground font-lock-type-face)
455 :underline t)))
456 "*Face used to highlight simulink specific functions."
457 :group 'matlab)
458 (defface matlab-nested-function-keyword-face
459 (list
460 (list t
461 (list :slant 'italic)))
462 "*Face to use for cross-function variables.")
463 (defface matlab-cross-function-variable-face
464 (list
465 (list t
466 (list :weight 'bold
467 :slant 'italic)))
468 "*Face to use for cross-function variables."
469 :group 'matlab)
470 (defface matlab-cellbreak-face
471 (list
472 (list t
473 (list :background (face-background font-lock-comment-face)
474 :foreground (face-foreground font-lock-comment-face)
475 :overline t
476 :bold t)))
477 "*Face to use for cellbreak %% lines.")
478 )
479
480 ;; Now, lets make the unterminated string face
481 (cond ((facep 'font-lock-string-face)
482 (copy-face 'font-lock-string-face
483 'matlab-unterminated-string-face))
484 (t
485 (make-face 'matlab-unterminated-string-face)))
486 (set-face-underline-p 'matlab-unterminated-string-face t)
487
488 ;; Now make some simulink faces
489 (cond ((facep 'font-lock-type-face)
490 (copy-face 'font-lock-type-face 'matlab-simulink-keyword-face))
491 (t
492 (make-face 'matlab-simulink-keyword-face)))
493 (set-face-underline-p 'matlab-simulink-keyword-face t)
494
495 ;; Now make some nested function/end keyword faces
496 (cond ((facep 'font-lock-type-face)
497 (copy-face 'font-lock-type-face 'matlab-nested-function-keyword-face))
498 (t
499 (make-face 'matlab-nested-function-keyword-face)))
500
501 ;; Now make some cross-function variable faces
502 (cond ((facep 'font-lock-type-face)
503 (copy-face 'font-lock-type-face 'matlab-cross-function-variable-face))
504 (t
505 (make-face 'matlab-cross-function-variable-face)))
506 (set-face-bold-p 'matlab-cross-function-variable-face t)
507
508 ;; Now make some cellbreak variable faces
509 (cond ((facep 'font-comment-face)
510 (copy-face 'font-lock-comment-face 'matlab-cellbreak-face))
511 (t
512 (make-face 'matlab-cellbreak-face)))
513 (set-face-bold-p 'matlab-cellbreak-face t)
514 (condition-case nil
515 (set-face-attribute 'matlab-cellbreak-face nil :overline t)
516 (error nil))
517 )
518 (remove-hook 'font-lock-mode-hook 'matlab-font-lock-adjustments))
519
520 ;; Make the adjustments for font lock after it's loaded.
521 ;; I found that eval-after-load was unreliable.
522 (if (featurep 'font-lock)
523 (matlab-font-lock-adjustments)
524 (add-hook 'font-lock-mode-hook 'matlab-font-lock-adjustments))
525
526
527 ;;; MATLAB mode variables =====================================================
528
529 (defvar matlab-tempo-tags nil
530 "List of templates used in MATLAB mode.")
531
532 ;; syntax table
533 (defvar matlab-mode-syntax-table
534 (let ((st (make-syntax-table (standard-syntax-table))))
535 (modify-syntax-entry ?_ "_" st)
536 (modify-syntax-entry ?% "<" st)
537 (modify-syntax-entry ?\n ">" st)
538 (modify-syntax-entry ?\\ "." st)
539 (modify-syntax-entry ?\t " " st)
540 (modify-syntax-entry ?+ "." st)
541 (modify-syntax-entry ?- "." st)
542 (modify-syntax-entry ?* "." st)
543 (modify-syntax-entry ?' "." st)
544 (modify-syntax-entry ?/ "." st)
545 (modify-syntax-entry ?= "." st)
546 (modify-syntax-entry ?< "." st)
547 (modify-syntax-entry ?> "." st)
548 (modify-syntax-entry ?& "." st)
549 (modify-syntax-entry ?| "." st)
550 st)
551 "The syntax table used in `matlab-mode' buffers.")
552
553 (defvar matlab-mode-special-syntax-table
554 (let ((st (copy-syntax-table matlab-mode-syntax-table)))
555 ;; Make _ a part of words so we can skip them better
556 (modify-syntax-entry ?_ "w" st)
557 st)
558 "The syntax table used when navigating blocks.")
559
560 ;; abbrev table
561 (defvar matlab-mode-abbrev-table nil
562 "The abbrev table used in `matlab-mode' buffers.")
563
564 (define-abbrev-table 'matlab-mode-abbrev-table ())
565
566 ;;; Keybindings ===============================================================
567
568 (defvar matlab-help-map
569 (let ((km (make-sparse-keymap)))
570 (define-key km "r" 'matlab-shell-run-command)
571 (define-key km "f" 'matlab-shell-describe-command)
572 (define-key km "a" 'matlab-shell-apropos)
573 (define-key km "v" 'matlab-shell-describe-variable)
574 (define-key km "t" 'matlab-shell-topic-browser)
575 km)
576 "The help key map for `matlab-mode' and `matlab-shell-mode'.")
577
578 (defvar matlab-insert-map
579 (let ((km (make-sparse-keymap)))
580 (define-key km "c" 'matlab-insert-next-case)
581 (define-key km "e" 'matlab-insert-end-block)
582 (define-key km "i" 'tempo-template-matlab-if)
583 (define-key km "I" 'tempo-template-matlab-if-else)
584 (define-key km "f" 'tempo-template-matlab-for)
585 (define-key km "s" 'tempo-template-matlab-switch)
586 (define-key km "t" 'tempo-template-matlab-try)
587 (define-key km "w" 'tempo-template-matlab-while)
588 (define-key km "F" 'tempo-template-matlab-function)
589 (define-key km "'" 'matlab-stringify-region)
590 ;; Not really inserts, but auto coding stuff
591 (define-key km "\C-s" 'matlab-ispell-strings)
592 (define-key km "\C-c" 'matlab-ispell-comments)
593 km)
594 "Keymap used for inserting simple texts based on context.")
595
596 ;; mode map
597 (defvar matlab-mode-map
598 (let ((km (make-sparse-keymap)))
599 (define-key km [return] 'matlab-return)
600 (define-key km "%" 'matlab-electric-comment)
601 (define-key km "\C-c;" 'matlab-comment-region)
602 (define-key km "\C-c:" 'matlab-uncomment-region)
603 (define-key km [(control c) return] 'matlab-comment-return)
604 (define-key km [(control c) (control c)] matlab-insert-map)
605 (define-key km [(control c) (control f)] 'matlab-fill-comment-line)
606 (define-key km [(control c) (control j)] 'matlab-justify-line)
607 (define-key km [(control c) (control q)] 'matlab-fill-region)
608 (define-key km [(control c) (control s)] 'matlab-shell-save-and-go)
609 (define-key km [(control c) (control r)] 'matlab-shell-run-region)
610 (define-key km [(meta control return)] 'matlab-shell-run-cell)
611 (define-key km [(control c) (control t)] 'matlab-show-line-info)
612 (define-key km [(control c) ?. ] 'matlab-find-file-on-path)
613 (define-key km [(control h) (control m)] matlab-help-map)
614 (define-key km [(control j)] 'matlab-linefeed)
615 (define-key km "\M-\r" 'newline)
616 (define-key km [(meta \;)] 'matlab-comment)
617 (define-key km [(meta q)] 'matlab-fill-paragraph)
618 (define-key km [(meta a)] 'matlab-beginning-of-command)
619 (define-key km [(meta e)] 'matlab-end-of-command)
620 (define-key km [(meta j)] 'matlab-comment-line-break-function)
621 (define-key km [(meta s)] 'matlab-show-matlab-shell-buffer)
622 (define-key km "\M-\t" 'matlab-complete-symbol)
623 (define-key km [(meta control f)] 'matlab-forward-sexp)
624 (define-key km [(meta control b)] 'matlab-backward-sexp)
625 (define-key km [(meta control q)] 'matlab-indent-sexp)
626 (define-key km [(meta control a)] 'matlab-beginning-of-defun)
627 (define-key km [(meta control e)] 'matlab-end-of-defun)
628 (if (string-match "XEmacs" emacs-version)
629 (define-key km [(control meta button1)] 'matlab-find-file-click)
630 (define-key km [(control meta mouse-2)] 'matlab-find-file-click))
631 (substitute-key-definition 'comment-region 'matlab-comment-region
632 km) ; global-map ;torkel
633 km)
634 "The keymap used in `matlab-mode'.")
635
636 ;;; Font locking keywords =====================================================
637
638 (defvar matlab-string-start-regexp "\\(^\\|[^]})a-zA-Z0-9_.']\\)"
639 "Regexp used to represent the character before the string char '.
640 The ' character has restrictions on what starts a string which is needed
641 when attempting to understand the current context.")
642
643 ;; To quote a quote, put two in a row, thus we need an anchored
644 ;; first quote. In addition, we don't want to color strings in comments.
645 (defvar matlab-string-end-regexp "[^'\n]*\\(''[^'\n]*\\)*'"
646 "Regexp used to represent the character pattern for ending a string.
647 The ' character can be used as a transpose, and can transpose transposes.
648 Therefore, to end, we must check all that goop.")
649
650 (defun matlab-font-lock-string-match-normal (limit)
651 "When font locking strings, call this function for normal strings.
652 Argument LIMIT is the maximum distance to scan."
653 (matlab-font-lock-string-match-here
654 (concat matlab-string-start-regexp
655 "\\('" matlab-string-end-regexp "\\)"
656 "\\([^']\\|$\\)")
657 limit))
658
659 (defun matlab-font-lock-string-match-unterminated (limit)
660 "When font locking strings, call this function for normal strings.
661 Argument LIMIT is the maximum distance to scan."
662 (matlab-font-lock-string-match-here
663 (concat matlab-string-start-regexp "\\('[^'\n]*\\(''[^'\n]*\\)*\\)$")
664 limit))
665
666 (defun matlab-font-lock-string-match-here (regex limit)
667 "When font-locking strings, call this function to determine a match.
668 Argument REGEX is the expression to scan for. Match 2 must be the string.
669 Argument LIMIT is the maximum distance to scan."
670 (let (e)
671 (while (and (re-search-forward regex limit t)
672 (progn
673 ;; This gets us out of a comment after the string.
674 (setq e (match-end 2))
675 (goto-char (match-beginning 2))
676 (prog1
677 (or (matlab-cursor-in-comment)
678 (if (bolp) nil
679 (save-excursion
680 (forward-char -1)
681 (matlab-cursor-in-string))))
682 (goto-char e))))
683 (setq e nil))
684 (if (not e)
685 nil
686 (goto-char e)
687 t)))
688
689 (defun matlab-font-lock-comment-match (limit)
690 "When font-locking comments, call this function to determine a match.
691 Argument LIMIT is the maximum distance to scan."
692 (let (e)
693 (while (and (re-search-forward "\\(%[^%\n]*\\)" limit t)
694 (progn
695 (setq e (match-end 1))
696 (member (get-text-property (match-beginning 0) 'face)
697 '(font-lock-string-face
698 matlab-unterminated-string-face))))
699 (setq e nil))
700 (if (not e)
701 nil
702 (goto-char e)
703 t)))
704
705 (defun matlab-find-unreachable-code (limit)
706 "Find code that is if'd out with if(0) or if(false), and mark it as a comment.
707 The if(0) and else/end construct should be highlighted differently.
708 Argument LIMIT is the maximum distance to search."
709 (if (and (< (point) limit)
710 (re-search-forward
711 "\\<\\(if\\>\\s-*(?\\s-*\\(0\\|false\\)\\s-*)?$\\)"
712 limit t))
713 (let ((b1 (match-beginning 1))
714 (e1 (match-end 1))
715 (b2 nil) (e2 nil)
716 (b3 nil) (e3 nil))
717 (goto-char b1)
718 (condition-case nil
719 (progn
720 ;; Go forward over the matlab sexp. Include scanning
721 ;; for ELSE since parts of the ELSE block are not
722 ;; `commented out'.
723 (matlab-forward-sexp t)
724 (forward-word -1)
725 ;; Is there an ELSE in this block?
726 (if (looking-at (matlab-block-mid-re))
727 (progn
728 (setq b3 (match-beginning 0)
729 e3 (match-end 0))
730 ;; Now find the REAL end.
731 (matlab-forward-sexp)
732 (forward-word -1)))
733 ;; End of block stuff
734 (if (looking-at (matlab-block-end-re))
735 (progn
736 (setq b2 (match-beginning 0)
737 e2 (match-end 0))
738 ;; make sure something exists...
739 (if (not b3) (setq b3 b2 e3 e2)))
740 (error "Eh?"))
741 ;; Ok, build up some match data.
742 (set-match-data
743 (list b1 e2 ;the real deal.
744 b1 e1 ;if (0)
745 b2 e2 ;end
746 b3 e3 ;else (if applicable.)
747 b1 e3)) ;body commented out.
748 t)
749 (error nil)))))
750
751 (defun matlab-font-lock-nested-function-keyword-match (limit)
752 "Find next nested function/end keyword for font-lock.
753 Argument LIMIT is the maximum distance to search."
754 ; Because of the way overlays are setup, the cursor will be sitting
755 ; on either a "function" or "end" keyword.
756 (catch 'result
757 (let ((pos (point))
758 overlays)
759 (while (< pos limit)
760 (setq overlays (matlab-overlays-at pos))
761 (while overlays
762 (let ((overlay (car overlays)))
763 (when (matlab-overlay-get overlay 'nested-function)
764 (when (= pos (matlab-overlay-start overlay))
765 (goto-char pos)
766 ;; The following line presumably returns true.
767 (throw 'result (re-search-forward "function" (+ pos 8) t)))
768 (let ((end-of-overlay (- (matlab-overlay-end overlay) 3)))
769 (when (<= pos end-of-overlay)
770 (goto-char end-of-overlay)
771 (throw 'result
772 (re-search-forward "end" (+ end-of-overlay 3) t))))))
773 (setq overlays (cdr overlays)))
774 (setq pos (matlab-next-overlay-change pos)))
775 nil ;; no matches, stop
776 )))
777
778 (defun matlab-font-lock-cross-function-variables-match (limit)
779 "Find next cross-function variable for font-lock.
780 Argument LIMIT is the maximum distance to search."
781 (catch 'result
782 (let ((pos (point))
783 overlays variables)
784 (while (< pos limit)
785 (let ((overlays (matlab-overlays-at pos)))
786 (while overlays
787 (let ((overlay (car overlays)))
788 (setq variables (matlab-overlay-get
789 overlay 'cross-function-variables))
790 (if variables
791 (progn
792 (goto-char pos)
793 (setq pos (min limit (matlab-overlay-end overlay)))
794 (if (re-search-forward variables pos t)
795 (progn
796 (throw 'result t))))))
797 (setq overlays (cdr overlays))))
798 (setq pos (matlab-next-overlay-change pos)))
799 nil ;; no matches, stop
800 )))
801
802 (defun matlab-find-block-comments (limit)
803 "Find code that is commented out with %{ until %}.
804 Argument LIMIT is the maximum distance to search."
805 (if (and (< (point) limit)
806 (re-search-forward "%{" limit t))
807 (let ((b1 (match-beginning 0))
808 (e1 (match-end 0))
809 (b2 nil) (e2 nil)
810 (b3 nil) (e3 nil))
811 (goto-char b1)
812 (forward-char -1)
813 (when (not (matlab-cursor-in-comment))
814 (setq b2 (re-search-forward "%}" limit t))
815 (when b2
816 (setq b2 (match-beginning 0)
817 e2 (match-end 0))
818 (set-match-data
819 (list b1 e2 ; full match
820 b1 e2 ; the full comment
821 b1 e1 ; the block start
822 b2 e2 ; the block end
823 ))
824 t
825 )))))
826
827 (defcustom matlab-keyword-list '("global" "persistent" "for" "parfor" "while"
828 "spmd" "if" "elseif" "else"
829 "endfunction" "return" "break" "continue"
830 "switch" "case" "otherwise" "try"
831 "catch" "tic" "toc"
832 ;; MCOS keywords
833 "classdef" "properties" "methods" "enumeration"
834 )
835 "List of keywords for MATLAB used in highlighting.
836 Customizing this variable is only useful if `regexp-opt' is available."
837 :group 'matlab
838 :type '(repeat (string :tag "Keyword: ")))
839
840 (defcustom matlab-handle-graphics-list '("figure" "axes" "axis" "line"
841 "surface" "patch" "text" "light"
842 "image" "set" "get" "uicontrol"
843 "uimenu" "uitoolbar"
844 "uitoggletool" "uipushtool"
845 "uicontext" "uicontextmenu"
846 "setfont" "setcolor")
847 "List of handle graphics functions used in highlighting.
848 Customizing this variable is only useful if `regexp-opt' is available."
849 :group 'matlab
850 :type '(repeat (string :tag "HG Keyword: ")))
851
852 (defcustom matlab-debug-list '("dbstop" "dbclear" "dbcont" "dbdown" "dbmex"
853 "dbstack" "dbstatus" "dbstep" "dbtype" "dbup"
854 "dbquit")
855 "List of debug commands used in highlighting.
856 Customizing this variable is only useful if `regexp-opt' is available."
857 :group 'matlab
858 :type '(repeat (string :tag "Debug Keyword: ")))
859
860 ;; font-lock keywords
861 (defvar matlab-font-lock-keywords
862 (list
863 ;; String quote chars are also used as transpose, but only if directly
864 ;; after characters, numbers, underscores, or closing delimiters.
865 '(matlab-font-lock-string-match-normal 2 font-lock-string-face)
866 ;; A string with no termination is not currently highlighted.
867 ;; This will show that the string needs some attention.
868 '(matlab-font-lock-string-match-unterminated
869 2 matlab-unterminated-string-face)
870 ;; Comments must occur after the string, that way we can check to see
871 ;; if the comment start char has occurred inside our string. (EL)
872 '(matlab-font-lock-comment-match 1 font-lock-comment-face)
873 ;; Various pragmas should be in different colors.
874 ;; I think pragmas are always lower case?
875 '("%#\\([a-z]+\\)" (1 'bold prepend))
876 ;; General keywords
877 (list
878 (if (fboundp 'regexp-opt)
879 (concat "\\<\\(" (regexp-opt matlab-keyword-list) "\\)\\>")
880 ;; Original hard-coded value for pre Emacs 20.1
881 "\\<\\(break\\|ca\\(se\\|tch\\)\\|e\\(lse\\(\\|if\\)\\|ndfunction\\)\
882 \\|\\(par\\)?for\\|spmd\\|global\\|if\\|otherwise\\|return\\|switch\\|try\\|while\\|tic\\|toc\\)\\>")
883 '(0 font-lock-keyword-face))
884 ;; The end keyword is only a keyword when not used as an array
885 ;; dereferencing part.
886 '("\\(^\\|[;,]\\)[ \t]*\\(end\\)\\b"
887 2 (if (matlab-valid-end-construct-p) font-lock-keyword-face nil))
888 ;; How about unreachable code? MUsT BE AFTER KEYWORDS in order to
889 ;; get double-highlighting.
890 '(matlab-find-unreachable-code
891 (1 'underline prepend) ;if part
892 (2 'underline prepend) ;end part
893 (3 'underline prepend) ;else part (if applicable)
894 (4 font-lock-comment-face prepend) ;commented out part.
895 )
896 ;; block comments need to be commented out too!
897 '(matlab-find-block-comments
898 (1 font-lock-comment-face prepend) ; commented out
899 (2 'underline prepend)
900 (3 'underline prepend) ;the comment parts
901 )
902 ;; Cell mode breaks get special treatment
903 '("^\\s-*\\(%%[^\n]*\n\\)" (1 matlab-cellbreak-face append))
904 ;; Highlight cross function variables
905 '(matlab-font-lock-cross-function-variables-match
906 (1 matlab-cross-function-variable-face prepend))
907 ;; Highlight nested function/end keywords
908 '(matlab-font-lock-nested-function-keyword-match
909 (0 matlab-nested-function-keyword-face prepend))
910 ;; The global keyword defines some variables. Mark them.
911 '("^\\s-*global\\s-+"
912 ("\\(\\w+\\)\\(\\s-*=[^,; \t\n]+\\|[, \t;]+\\|$\\)"
913 nil nil (1 font-lock-variable-name-face)))
914 ;; Handle graphics stuff
915 (list
916 (if (fboundp 'regexp-opt)
917 (concat "\\<\\(" (regexp-opt matlab-handle-graphics-list) "\\)\\>")
918 ;; The original regular expression for pre Emacs 20.1
919 "\\<\\(ax\\(es\\|is\\)\\|figure\\|get\\|image\\|li\\(ght\\|ne\\)\\|\
920 patch\\|s\\(et\\(\\|color\\|font\\)\\|urface\\)\\|text\\|\
921 ui\\(cont\\(ext\\(\\|menu\\)\\|rol\\)\\|menu\\|\
922 \\(toggle\\|push\\)tool\\|toolbar\\)\\)\\>")
923 '(0 font-lock-type-face))
924 )
925 "Expressions to highlight in MATLAB mode.")
926
927 (defconst matlab-function-arguments
928 "\\(([^)]*)\\)?\\s-*\\([,;\n%]\\|$\\)")
929
930 (defvar matlab-gaudy-font-lock-keywords
931 (append
932 matlab-font-lock-keywords
933 (list
934 ;; defining a function, a (possibly empty) list of assigned variables,
935 ;; function name, and an optional (possibly empty) list of input variables
936 (list (concat "^\\s-*\\(function\\)\\>[ \t\n.]*"
937 "\\(\\[[^]]*\\]\\|\\sw+\\)[ \t\n.]*"
938 "=[ \t\n.]*\\(\\sw+\\)[ \t\n.]*"
939 matlab-function-arguments)
940 '(1 font-lock-keyword-face append)
941 '(2 font-lock-variable-name-face append)
942 '(3 font-lock-function-name-face append))
943 ;; defining a function, a function name, and an optional (possibly
944 ;; empty) list of input variables
945 (list (concat "^\\s-*\\(function\\)[ \t\n.]+"
946 "\\(\\sw+\\)[ \t\n.]*"
947 matlab-function-arguments)
948 '(1 font-lock-keyword-face append)
949 '(2 font-lock-function-name-face append))
950 ;; Anchor on the function keyword, highlight params
951 (list (concat "^\\s-*function\\>[ \t\n.]*"
952 "\\(\\(\\[[^]]*\\]\\|\\sw+\\)[ \t\n.]*=[ \t\n.]*\\)?"
953 "\\sw+\\s-*(")
954 '("\\s-*\\(\\sw+\\)\\s-*[,)]" nil nil
955 (1 font-lock-variable-name-face)))
956 ;; I like variables for FOR loops
957 '("\\<\\(for\\|parfor\\)\\s-+\\(\\sw+\\)\\s-*=\\s-*\
958 \\(\\([^\n,;%(]+\\|([^\n%)]+)\\)+\\)"
959 (1 font-lock-keyword-face)
960 (2 font-lock-variable-name-face append)
961 (3 font-lock-reference-face append))
962 ;; Items after a switch statements are cool
963 '("\\<\\(case\\|switch\\)\\s-+\\({[^}\n]+}\\|[^,%\n]+\\)"
964 (1 font-lock-keyword-face) (2 font-lock-reference-face))
965 ;; How about a few matlab constants such as pi, infinity, and sqrt(-1)?
966 ;; The ^>> is in case I use this in an interactive mode someday
967 '("\\<\\(eps\\|pi\\|inf\\|Inf\\|NaN\\|nan\\|ans\\|i\\|j\\|^>>\\)\\>"
968 1 font-lock-reference-face)
969 '("\\<[0-9]\\.?\\(i\\|j\\)\\>" 1 font-lock-reference-face)
970 ;; Define these as variables since this is about as close
971 ;; as matlab gets to variables
972 (list (concat "\\<" matlab-indent-past-arg1-functions "\\s-*")
973 '("(\\s-*\\(\\w+\\)\\s-*\\(,\\|)\\)" nil nil
974 (1 font-lock-variable-name-face)))
975 ))
976 "Expressions to highlight in MATLAB mode.")
977
978 (defvar matlab-really-gaudy-font-lock-keywords
979 (append
980 matlab-gaudy-font-lock-keywords
981 (list
982 ;; Since it's a math language, how bout dem symbols?
983 '("\\([<>~]=?\\|\\.[/*^']\\|==\\|\\<xor\\>\\|[-!^&|*+\\/~:]\\)"
984 1 font-lock-type-face)
985 ;; How about references in the HELP text.
986 (list (concat "^" matlab-comment-line-s "\\s-*"
987 "\\(\\([A-Z]+\\s-*=\\s-+\\|\\[[^]]+]\\s-*=\\s-+\\|\\)"
988 "\\([A-Z][0-9A-Z]+\\)\\(([^)\n]+)\\| \\)\\)")
989 '(1 font-lock-reference-face prepend))
990 (list (concat "^" matlab-comment-line-s "\\s-*"
991 "See also\\s-+")
992 '("\\([A-Z][A-Z0-9]+\\)\\([,.]\\| and\\|$\\) *" nil nil
993 (1 font-lock-reference-face prepend)))
994 (list (concat "^" matlab-comment-line-s "\\s-*"
995 "\\(\\$" "Revision" "[^\n$]+\\$\\)")
996 '(1 font-lock-reference-face prepend))
997 ;; continuation ellipsis.
998 '("[^.]\\(\\.\\.\\.+\\)\\([^\n]*\\)" (1 'underline)
999 (2 font-lock-comment-face))
1000 ;; How about debugging statements?
1001 ;;'("\\<\\(db\\sw+\\)\\>" 1 'bold)
1002 (list
1003 (if (fboundp 'regexp-opt)
1004 (concat "\\<\\(" (regexp-opt matlab-debug-list) "\\)\\>")
1005 ;; pre-regexp-opt days.
1006 "\\<\\(db\\(c\\(lear\\|ont\\)\\|down\\|mex\\|quit\\|\
1007 st\\(a\\(ck\\|tus\\)\\|ep\\|op\\)\\|type\\|up\\)\\)\\>")
1008 '(0 'bold)))
1009 (if matlab-handle-simulink
1010 ;; Simulink functions, but only if the user wants it.
1011 (list (list (concat "\\<\\(\\([sg]et_param\\|sim\\([gs]et\\)?\\|"
1012 "\\(mld\\|ss\\)[A-Z]\\w+\\)\\|"
1013 "\\(new\\|open\\|close\\|save\\|find\\)_system\\|"
1014 "\\(add\\|delete\\|replace\\)_\\(block\\|line\\)\\|"
1015 "simulink\\|bd\\(root\\|close\\)"
1016 "\\)\\>")
1017 1 matlab-simulink-keyword-face))
1018 nil))
1019 "Expressions to highlight in MATLAB mode.")
1020
1021 (defvar matlab-shell-font-lock-keywords
1022 (list
1023 ;; How about Errors?
1024 '("^\\(Error in\\|Syntax error in\\)\\s-+==>\\s-+\\(.+\\)$"
1025 (1 font-lock-comment-face) (2 font-lock-string-face))
1026 ;; and line numbers
1027 '("^\\(On line [0-9]+\\)" 1 font-lock-comment-face)
1028 ;; User beep things
1029 '("\\(\\?\\?\\?[^\n]+\\)" 1 font-lock-comment-face)
1030 ;; Useful user commands, but not useful programming constructs
1031 '("\\<\\(demo\\|whatsnew\\|info\\|subscribe\\|help\\|doc\\|lookfor\\|what\
1032 \\|whos?\\|cd\\|clear\\|load\\|save\\|helpdesk\\|helpwin\\)\\>"
1033 1 font-lock-keyword-face)
1034 ;; Various notices
1035 '(" M A T L A B " 0 'underline)
1036 '("All Rights Reserved" 0 'italic)
1037 '("\\((c)\\s-+Copyright[^\n]+\\)" 1 font-lock-comment-face)
1038 '("\\(Version\\)\\s-+\\([^\n]+\\)"
1039 (1 font-lock-function-name-face) (2 font-lock-variable-name-face))
1040 )
1041 "Additional keywords used by MATLAB when reporting errors in interactive\
1042 mode.")
1043
1044 ;; Imenu support.
1045 (defvar matlab-imenu-generic-expression
1046 '((nil "^\\s-*function\\>[ \t\n.]*\\(\\(\\[[^]]*\\]\\|\\sw+\\)[ \t\n.]*\
1047 < =\[ \t\n.]*\\)?\\([a-zA-Z0-9_]+\\)" 3))
1048 "Expressions which find function headings in MATLAB M files.")
1049
1050
1051 ;;; MATLAB mode entry point ==================================================
1052
1053 ;; Debian change by Peter Galbraith: Customize `matlab-auto-mode' instead.
1054 ;; ;;;###autoload
1055 ;; (add-to-list 'auto-mode-alist '("\\.m$" . matlab-mode))
1056
1057 ;;;###autoload
1058 (defun matlab-mode ()
1059 "MATLAB(R) mode is a major mode for editing MATLAB dot-m files.
1060 \\<matlab-mode-map>
1061 Convenient editing commands are:
1062 \\[matlab-comment-region] - Comment/Uncomment out a region of code.
1063 \\[matlab-fill-comment-line] - Fill the current comment line.
1064 \\[matlab-fill-region] - Fill code and comments in region.
1065 \\[matlab-fill-paragraph] - Refill the current command or comment.
1066 \\[matlab-complete-symbol] - Symbol completion of matlab symbols\
1067 based on the local syntax.
1068 \\[matlab-indent-sexp] - Indent syntactic block of code.
1069
1070 Convenient navigation commands are:
1071 \\[matlab-beginning-of-command] - Move to the beginning of a command.
1072 \\[matlab-end-of-command] - Move to the end of a command.
1073 \\[matlab-beginning-of-defun] - Move to the beginning of a function.
1074 \\[matlab-end-of-defun] - Move do the end of a function.
1075 \\[matlab-forward-sexp] - Move forward over a syntactic block of code.
1076 \\[matlab-backward-sexp] - Move backwards over a syntactic block of code.
1077
1078 Convenient template insertion commands:
1079 \\[tempo-template-matlab-function] - Insert a function definition.
1080 \\[tempo-template-matlab-if] - Insert an IF END block.
1081 \\[tempo-template-matlab-for] - Insert a FOR END block.
1082 \\[tempo-template-matlab-switch] - Insert a SWITCH END statement.
1083 \\[matlab-insert-next-case] - Insert the next CASE condition in a SWITCH.
1084 \\[matlab-insert-end-block] - Insert a matched END statement. With \
1085 optional ARG, reindent.
1086 \\[matlab-stringify-region] - Convert plaintext in region to a string \
1087 with correctly quoted chars.
1088
1089 Variables:
1090 `matlab-indent-level' Level to indent blocks.
1091 `matlab-cont-level' Level to indent continuation lines.
1092 `matlab-cont-requires-ellipsis' Does your MATLAB support implied elipsis.
1093 `matlab-case-level' Level to unindent case statements.
1094 `matlab-indent-past-arg1-functions'
1095 Regexp of functions to indent past the first
1096 argument on continuation lines.
1097 `matlab-maximum-indents' List of maximum indents during lineups.
1098 `matlab-comment-column' Goal column for on-line comments.
1099 `fill-column' Column used in auto-fill.
1100 `matlab-indent-function-body' If non-nil, indents body of MATLAB functions.
1101 `matlab-functions-have-end' If non-nil, MATLAB functions terminate with end.
1102 `matlab-return-function' Customize RET handling with this function.
1103 `matlab-auto-fill' Non-nil, do auto-fill at startup.
1104 `matlab-fill-code' Non-nil, auto-fill code.
1105 `matlab-fill-strings' Non-nil, auto-fill strings.
1106 `matlab-verify-on-save-flag' Non-nil, enable code checks on save.
1107 `matlab-highlight-block-match-flag'
1108 Enable matching block begin/end keywords.
1109 `matlab-vers-on-startup' If t, show version on start-up.
1110 `matlab-handle-simulink' If t, enable simulink keyword highlighting.
1111
1112 All Key Bindings:
1113 \\{matlab-mode-map}"
1114 (interactive)
1115 (kill-all-local-variables)
1116 (use-local-map matlab-mode-map)
1117 (setq major-mode 'matlab-mode)
1118 (setq mode-name "MATLAB")
1119 (if (boundp 'whitespace-modes)
1120 (add-to-list 'whitespace-modes 'matlab-mode))
1121 (setq local-abbrev-table matlab-mode-abbrev-table)
1122 (set-syntax-table matlab-mode-syntax-table)
1123 (setq indent-tabs-mode nil)
1124 (make-local-variable 'indent-line-function)
1125 (setq indent-line-function 'matlab-indent-line)
1126 (make-local-variable 'paragraph-start)
1127 (setq paragraph-start (concat "^$\\|" page-delimiter))
1128 (make-local-variable 'paragraph-separate)
1129 (setq paragraph-separate paragraph-start)
1130 (make-local-variable 'paragraph-ignore-fill-prefix)
1131 (setq paragraph-ignore-fill-prefix t)
1132 (make-local-variable 'comment-start-skip)
1133 (setq comment-start-skip "%\\s-+")
1134 (make-local-variable 'comment-start)
1135 (setq comment-start "%")
1136 (make-local-variable 'page-delimiter)
1137 (setq page-delimiter "^\\(\f\\|%% \\)")
1138 (make-local-variable 'comment-column)
1139 (setq comment-column matlab-comment-column)
1140 (make-local-variable 'comment-indent-function)
1141 (setq comment-indent-function 'matlab-comment-indent)
1142 (make-local-variable 'add-log-current-defun-function)
1143 (setq add-log-current-defun-function 'matlab-current-defun)
1144 (make-local-variable 'fill-column)
1145 (setq fill-column default-fill-column)
1146 (make-local-variable 'auto-fill-function)
1147 (if matlab-auto-fill (setq auto-fill-function 'matlab-auto-fill))
1148 ;; Emacs 20 supports this variable. This lets users turn auto-fill
1149 ;; on and off and still get the right fill function.
1150 (make-local-variable 'normal-auto-fill-function)
1151 (setq normal-auto-fill-function 'matlab-auto-fill)
1152 (make-local-variable 'fill-prefix)
1153 (make-local-variable 'imenu-generic-expression)
1154 (setq imenu-generic-expression matlab-imenu-generic-expression)
1155 ;; Save hook for verifying src. This lets us change the name of
1156 ;; the function in `write-file' and have the change be saved.
1157 ;; It also lets us fix mistakes before a `save-and-go'.
1158 (make-local-variable 'write-contents-hooks)
1159 (add-hook 'write-contents-hooks 'matlab-mode-verify-fix-file-fn)
1160 ;; Tempo tags
1161 (make-local-variable 'tempo-local-tags)
1162 (setq tempo-local-tags (append matlab-tempo-tags tempo-local-tags))
1163 ;; give each file it's own parameter history
1164 (make-local-variable 'matlab-shell-save-and-go-history)
1165 (make-local-variable 'font-lock-defaults)
1166 (setq font-lock-defaults '((matlab-font-lock-keywords
1167 matlab-gaudy-font-lock-keywords
1168 matlab-really-gaudy-font-lock-keywords
1169 )
1170 t ; do not do string/comment highlighting
1171 nil ; keywords are case sensitive.
1172 ;; This puts _ as a word constituent,
1173 ;; simplifying our keywords significantly
1174 ((?_ . "w"))))
1175 (matlab-enable-block-highlighting 1)
1176 (if window-system (matlab-frame-init))
1177 ; If the buffer already has a function definition, figure out the correct
1178 ; settings for matlab-functions-have-end and matlab-indent-function.
1179 (goto-char (point-max))
1180 (when (eq matlab-indent-function-body 'guess)
1181 ;; Note: Compile warning below, but defined later in this file.
1182 (if (re-search-backward matlab-defun-regex nil t)
1183 (let ((beg (point))
1184 end ; filled in later
1185 (cc (current-column))
1186 (nf (let ((matlab-functions-have-end t))
1187 (condition-case nil
1188 (progn (matlab-forward-sexp) t)
1189 (error nil)))))
1190 (if nf (matlab-toggle-functions-have-end-minor-mode)) ;; observation trumps default
1191 (setq end (if nf (progn (forward-line 0) (point)) (point-max)))
1192 (goto-char beg)
1193 (catch 'done
1194 (while (progn (forward-line 1) (< (point) end))
1195 (if (looking-at "\\s-*\\(%\\|$\\)")
1196 nil ; go on to next line
1197 (looking-at "\\s-*")
1198 (goto-char (match-end 0))
1199 (setq matlab-indent-function-body (> (current-column) cc))
1200 (throw 'done nil)))))
1201 (if (and (bobp) ; the buffer is empty
1202 matlab-functions-have-end) ; user wants this by default
1203 (matlab-toggle-functions-have-end))))
1204 (if (or (featurep 'mlint)
1205 matlab-show-mlint-warnings
1206 matlab-highlight-cross-function-variables)
1207 ;; Some users may not feel like getting all the extra stuff
1208 ;; needed for mlint working. Do this only if we can get
1209 ;; mlint loaded ok.
1210 (condition-case nil
1211 (mlint-minor-mode
1212 (if (or matlab-show-mlint-warnings matlab-highlight-cross-function-variables)
1213 1
1214 0))
1215 ;; If there is an error loading the stuff, don't
1216 ;; continue.
1217 (error nil)))
1218 (goto-char (point-min))
1219 (run-hooks 'matlab-mode-hook)
1220 (if matlab-vers-on-startup (matlab-show-version)))
1221
1222 ;;; Utilities =================================================================
1223
1224 (defun matlab-show-version ()
1225 "Show the version number in the minibuffer."
1226 (interactive)
1227 (message "matlab-mode, version %s" matlab-mode-version))
1228
1229 (defun matlab-find-prev-line ()
1230 "Recurse backwards until a code line is found."
1231 (if (= -1 (forward-line -1)) nil
1232 (if (or (matlab-ltype-empty)
1233 (matlab-ltype-comm-ignore))
1234 (matlab-find-prev-line) t)))
1235
1236 (defun matlab-prev-line ()
1237 "Go to the previous line of code. Return nil if not found."
1238 (interactive)
1239 (let ((old-point (point)))
1240 (if (matlab-find-prev-line) t (goto-char old-point) nil)))
1241
1242 (defun matlab-uniquafy-list (lst)
1243 "Return a list that is a subset of LST where all elements are unique."
1244 (let ((nlst nil))
1245 (while lst
1246 (if (and (car lst) (not (member (car lst) nlst)))
1247 (setq nlst (cons (car lst) nlst)))
1248 (setq lst (cdr lst)))
1249 (nreverse nlst)))
1250
1251 ; Aki Vehtari <Aki.Vehtari@hut.fi> recommends this: (19.29 required)
1252 ;(require 'backquote)
1253 ;(defmacro matlab-navigation-syntax (&rest body)
1254 ; "Evaluate BODY with the matlab-mode-special-syntax-table"
1255 ; '(let ((oldsyntax (syntax-table)))
1256 ; (unwind-protect
1257 ; (progn
1258 ; (set-syntax-table matlab-mode-special-syntax-table)
1259 ; ,@body)
1260 ; (set-syntax-table oldsyntax))))
1261
1262 (defmacro matlab-navigation-syntax (&rest forms)
1263 "Set the current environment for syntax-navigation and execute FORMS."
1264 (list 'let '((oldsyntax (syntax-table))
1265 (case-fold-search nil))
1266 (list 'unwind-protect
1267 (list 'progn
1268 '(set-syntax-table matlab-mode-special-syntax-table)
1269 (cons 'progn forms))
1270 '(set-syntax-table oldsyntax))))
1271
1272 (put 'matlab-navigation-syntax 'lisp-indent-function 0)
1273 (add-hook 'edebug-setup-hook
1274 (lambda ()
1275 (def-edebug-spec matlab-navigation-syntax def-body)))
1276
1277 (defun matlab-up-list (count &optional restrict)
1278 "Move forwards or backwards up a list by COUNT.
1279 Optional argument RESTRICT is where to restrict the search."
1280 ;; MATLAB syntax table has no disabling strings or comments.
1281 (let ((dir (if (> 0 count) -1 +1))
1282 (origin (point))
1283 (ms nil))
1284 ;; Make count positive
1285 (setq count (* count dir))
1286 (if (= dir -1)
1287 (while (/= count 0)
1288 ;; Search till we find an unstrung paren object.
1289 (setq ms (re-search-backward "\\s(\\|\\s)" restrict t))
1290 (while (and (save-match-data (matlab-cursor-in-string-or-comment))
1291 (setq ms (re-search-backward "\\s(\\|\\s)" restrict t))))
1292 (if (not ms)
1293 (progn
1294 (goto-char origin)
1295 (error "Scan Error: List missmatch")))
1296 ;; View it's match.
1297 (let ((s (match-string 0)))
1298 (if (string-match "\\s(" s)
1299 (setq count (1- count))
1300 (setq count (1+ count)))))
1301 (error "Not implemented"))
1302 ms))
1303
1304 (defun matlab-valid-end-construct-p ()
1305 "Return non-nil if the end after point terminates a block.
1306 Return nil if it is being used to dereference an array."
1307 (let ((p (point))
1308 (err1 t))
1309 (condition-case nil
1310 (save-restriction
1311 ;; Restrict navigation only to the current command line
1312 (save-excursion
1313 (matlab-beginning-of-command)
1314 (narrow-to-region (point)
1315 (save-excursion
1316 (goto-char p)
1317 (matlab-point-at-eol))))
1318 ;; This used to add some sort of protection, but I don't know what
1319 ;; the condition was, or why the simple case doesn't handle it.
1320 ;;
1321 ;; The above replacement fixes a case where a continuation in an array
1322 ;; befuddles the indenter.
1323 ;; (progn ;;(matlab-end-of-command (point))
1324 ;; (end-of-line)
1325 ;; (if (> p (point))
1326 ;; (progn
1327 ;; (setq err1 nil)
1328 ;; (error)))
1329 ;; (point))))
1330 (save-excursion
1331 ;; beginning of param list
1332 (matlab-up-list -1)
1333 ;; backup over the parens. If that fails
1334 (condition-case nil
1335 (progn
1336 (forward-sexp 1)
1337 ;; If we get here, the END is inside parens, which is not a
1338 ;; valid location for the END keyword. As such it is being
1339 ;; used to dereference array parameters
1340 nil)
1341 ;; This error means that we have an unterminated paren
1342 ;; block, so this end is currently invalid.
1343 (error nil))))
1344 ;; an error means the list navigation failed, which also means we are
1345 ;; at the top-level
1346 (error err1))))
1347
1348 ;;; Regexps for MATLAB language ===============================================
1349
1350 ;; "-pre" means "partial regular expression"
1351 ;; "-if" and "-no-if" means "[no] Indent Function"
1352
1353 (defconst matlab-defun-regex "^\\(\\s-*function\\|classdef\\)[ \t.[]"
1354 "Regular expression defining the beginning of a MATLAB function.")
1355
1356 (defconst matlab-mcos-regexp "\\|classdef\\|properties\\|methods\\|enumeration"
1357 "Keywords which mark the beginning of mcos blocks.")
1358
1359 (defcustom matlab-block-indent-tic-toc-flag nil
1360 "*Non-nil means that tic,toc should indent like a if,end block.
1361 This variable should be set before loading matlab.el"
1362 :group 'matlab
1363 :type 'boolean)
1364
1365 (defconst matlab-block-beg-pre-if
1366 (if matlab-block-indent-tic-toc-flag
1367 (concat "function\\|parfor\\|spmd\\|for\\|while\\|if\\|switch\\|try\\|tic"
1368 matlab-mcos-regexp)
1369 (concat "function\\|parfor\\|spmd\\|for\\|while\\|if\\|switch\\|try"
1370 matlab-mcos-regexp))
1371 "Keywords which mark the beginning of an indented block.
1372 Includes function.")
1373
1374 (defconst matlab-block-beg-pre-no-if
1375 (if matlab-block-indent-tic-toc-flag
1376 (concat "parfor\\|for\\|spmd\\|while\\|if\\|switch\\|try\\|tic"
1377 matlab-mcos-regexp)
1378 (concat "parfor\\|for\\|spmd\\|while\\|if\\|switch\\|try"
1379 matlab-mcos-regexp))
1380 "Keywords which mark the beginning of an indented block.
1381 Excludes function.")
1382
1383 (defun matlab-block-beg-pre ()
1384 "Partial regular expression to recognize MATLAB block-begin keywords."
1385 (if matlab-functions-have-end
1386 matlab-block-beg-pre-if
1387 matlab-block-beg-pre-no-if))
1388
1389 (defconst matlab-block-mid-pre
1390 "elseif\\|else\\|catch"
1391 "Partial regular expression to recognize MATLAB mid-block keywords.")
1392
1393 (defconst matlab-block-end-pre-if
1394 (if matlab-block-indent-tic-toc-flag
1395 "end\\(function\\)?\\|function\\|\\(\\sw+\\s-*\\((.*)\\)?\\s-*=\\s-*\\)?toc"
1396 "end\\(function\\)?\\|function")
1397 "Partial regular expression to recognize MATLAB block-end keywords.")
1398
1399 (defconst matlab-block-end-pre-no-if
1400 (if matlab-block-indent-tic-toc-flag
1401 "end\\|\\(\\sw+\\s-*\\((.*)\\)?\\s-*=\\s-*\\)?toc"
1402 "end")
1403 "Partial regular expression to recognize MATLAB block-end keywords.")
1404
1405 (defun matlab-block-end-pre ()
1406 "Partial regular expression to recognize MATLAB block-end keywords."
1407 (if matlab-functions-have-end
1408 matlab-block-end-pre-if
1409 matlab-block-end-pre-no-if))
1410
1411 ;; Not used.
1412 ;;(defconst matlab-other-pre
1413 ;; "function\\|return"
1414 ;; "Partial regular express to recognize MATLAB non-block keywords.")
1415
1416 (defconst matlab-endless-blocks
1417 "case\\|otherwise"
1418 "Keywords which initialize new blocks, but don't have explicit ends.
1419 Thus, they are endless. A new case or otherwise will end a previous
1420 endless block, and and end will end this block, plus any outside normal
1421 blocks.")
1422
1423 (defun matlab-block-re ()
1424 "Regular expression for keywords which begin MATLAB blocks."
1425 (concat "\\(^\\|[;,]\\)\\s-*\\("
1426 (matlab-block-beg-pre) "\\|"
1427 matlab-block-mid-pre "\\|"
1428 (matlab-block-end-pre) "\\|"
1429 matlab-endless-blocks "\\)\\b"))
1430
1431 (defun matlab-block-scan-re ()
1432 "Expression used to scan over matching pairs of begin/ends."
1433 (concat "\\(^\\|[;,]\\)\\s-*\\("
1434 (matlab-block-beg-pre) "\\|"
1435 (matlab-block-end-pre) "\\)\\b"))
1436
1437 (defun matlab-block-beg-re ()
1438 "Expression used to find the beginning of a block."
1439 (concat "\\(" (matlab-block-beg-pre) "\\)"))
1440
1441 (defun matlab-block-mid-re ()
1442 "Expression used to find block center parts (like else)."
1443 (concat "\\(" matlab-block-mid-pre "\\)"))
1444
1445 (defun matlab-block-end-re ()
1446 "Expression used to end a block. Usually just `end'."
1447 (concat "\\(" (matlab-block-end-pre) "\\)"))
1448
1449 (defun matlab-block-end-no-function-re ()
1450 "Expression representing and end if functions are excluded."
1451 (concat "\\<\\(" matlab-block-end-pre-no-if "\\)\\>"))
1452
1453 (defun matlab-endless-blocks-re ()
1454 "Expression of block starters that do not have associated ends."
1455 (concat "\\(" matlab-endless-blocks "\\)"))
1456
1457 (defun matlab-match-function-re ()
1458 "Expression to match a function start line.
1459 There are no reliable numeric matches in this expression.
1460 Know that `match-end' of 0 is the end of the functin name."
1461 ;; old function was too unstable.
1462 ;;"\\(^function\\s-+\\)\\([^=\n]+=[ \t\n.]*\\)?\\(\\sw+\\)"
1463 (concat "\\(^\\s-*function\\b[ \t\n.]*\\)\\(\\(\\[[^]]*\\]\\|\\sw+\\)"
1464 "[ \t\n.]*=[ \t\n.]*\\|\\(\\)\\)\\(\\sw+\\)"))
1465
1466 (defconst matlab-cline-start-skip "[ \t]*%[ \t]*"
1467 "*The regular expression for skipping comment start.")
1468
1469 ;;; Lists for matlab keywords =================================================
1470
1471 (defvar matlab-keywords-solo
1472 '("break" "case" "else" "elseif" "end" "for" "parfor" "function" "if" "tic" "toc"
1473 "otherwise" "profile" "switch" "while" "try" "catch" "spmd")
1474 "Keywords that appear on a line by themselves.")
1475 (defvar matlab-keywords-return
1476 '("acos" "acosh" "acot" "acoth" "acsch" "asech" "asin" "asinh"
1477 "atan" "atan2" "atanh" "cos" "cosh" "coth" "csc" "csch" "exp"
1478 "log" "log10" "log2" "sec" "sech" "sin" "sinh" "tanh"
1479 "abs" "sign" "sqrt" )
1480 "List of MATLAB keywords that have return arguments.
1481 This list still needs lots of help.")
1482 (defvar matlab-keywords-boolean
1483 '("all" "any" "exist" "isempty" "isequal" "ishold" "isfinite" "isglobal"
1484 "isinf" "isletter" "islogical" "isnan" "isprime" "isreal" "isspace"
1485 "logical" "isa")
1486 "List of keywords that are typically used as boolean expressions.")
1487
1488 (defvar matlab-core-properties
1489 '("ButtonDownFcn" "Children" "Clipping" "CreateFcn" "DeleteFcn"
1490 "BusyAction" "HandleVisibility" "HitTest" "Interruptible"
1491 "Parent" "Selected" "SelectionHighlight" "Tag" "Type"
1492 "UIContextMenu" "UserData" "Visible")
1493 "List of properties belonging to all HG objects.")
1494
1495 (defvar matlab-property-lists
1496 '(("root" .
1497 ("CallbackObject" "Language" "CurrentFigure" "Diary" "DiaryFile"
1498 "Echo" "ErrorMessage" "Format" "FormatSpacing" "PointerLocation"
1499 "MonitorPositions"
1500 "PointerWindow" "Profile" "ProfileFile" "ProfileCount"
1501 "ProfileInterval" "RecursionLimit" "ScreenDepth" "ScreenSize"
1502 "ShowHiddenHandles" "TerminalHideGraphCommand" "TerminalOneWindow"
1503 "TerminalDimensions" "TerminalProtocol" "TerminalShowGraphCommand"
1504 "Units" "AutomaticFileUpdates" ))
1505 ("axes" .
1506 ("AmbientLightColor" "Box" "CameraPosition" "CameraPositionMode"
1507 "CameraTarget" "CameraTargetMode" "CameraUpVector"
1508 "CameraUpVectorMode" "CameraViewAngle" "CameraViewAngleMode" "CLim"
1509 "CLimMode" "Color" "CurrentPoint" "ColorOrder" "DataAspectRatio"
1510 "DataAspectRatioMode" "DrawMode" "FontAngle" "FontName" "FontSize"
1511 "FontUnits" "FontWeight" "GridLineStyle" "Layer" "LineStyleOrder"
1512 "LineWidth" "NextPlot" "PlotBoxAspectRatio" "PlotBoxAspectRatioMode"
1513 "Projection" "Position" "TickLength" "TickDir" "TickDirMode" "Title"
1514 "Units" "View" "XColor" "XDir" "XGrid" "XLabel" "XAxisLocation" "XLim"
1515 "XLimMode" "XScale" "XTick" "XTickLabel" "XTickLabelMode" "XTickMode"
1516 "YColor" "YDir" "YGrid" "YLabel" "YAxisLocation" "YLim" "YLimMode"
1517 "YScale" "YTick" "YTickLabel" "YTickLabelMode" "YTickMode" "ZColor"
1518 "ZDir" "ZGrid" "ZLabel" "ZLim" "ZLimMode" "ZScale" "ZTick"
1519 "ZTickLabel" "ZTickLabelMode" "ZTickMode"))
1520 ("figure" .
1521 ("BackingStore" "CloseRequestFcn" "Color" "Colormap"
1522 "CurrentAxes" "CurrentCharacter" "CurrentObject" "CurrentPoint"
1523 "Dithermap" "DithermapMode" "FixedColors" "IntegerHandle"
1524 "InvertHardcopy" "KeyPressFcn" "MenuBar" "MinColormap" "Name"
1525 "NextPlot" "NumberTitle" "PaperUnits" "PaperOrientation"
1526 "PaperPosition" "PaperPositionMode" "PaperSize" "PaperType"
1527 "Pointer" "PointerShapeCData" "PointerShapeHotSpot" "Position"
1528 "Renderer" "RendererMode" "Resize" "ResizeFcn" "SelectionType"
1529 "ShareColors" "Units" "WindowButtonDownFcn"
1530 "WindowButtonMotionFcn" "WindowButtonUpFcn" "WindowStyle"))
1531 ("image" . ("CData" "CDataMapping" "EraseMode" "XData" "YData"))
1532 ("light" . ("Position" "Color" "Style"))
1533 ("line" .
1534 ("Color" "EraseMode" "LineStyle" "LineWidth" "Marker" "LineSmoothing"
1535 "MarkerSize" "MarkerEdgeColor" "MarkerFaceColor" "XData" "YData"
1536 "ZData"))
1537 ("patch" .
1538 ("CData" "CDataMapping" "FaceVertexCData" "EdgeColor" "EraseMode"
1539 "FaceColor" "Faces" "LineStyle" "LineWidth" "Marker" "LineSmoothing"
1540 "MarkerEdgeColor" "MarkerFaceColor" "MarkerSize" "Vertices"
1541 "XData" "YData" "ZData" "FaceLighting" "EdgeLighting"
1542 "BackFaceLighting" "AmbientStrength" "DiffuseStrength"
1543 "SpecularStrength" "SpecularExponent" "SpecularColorReflectance"
1544 "VertexNormals" "NormalMode"))
1545 ("surface" .
1546 ("CData" "CDataMapping" "EdgeColor" "EraseMode" "FaceColor"
1547 "LineStyle" "LineWidth" "Marker" "MarkerEdgeColor" "LineSmoothing"
1548 "MarkerFaceColor" "MarkerSize" "MeshStyle" "XData" "YData"
1549 "ZData" "FaceLighting" "EdgeLighting" "BackFaceLighting"
1550 "AmbientStrength" "DiffuseStrength" "SpecularStrength"
1551 "SpecularExponent" "SpecularColorReflectance" "VertexNormals"
1552 "NormalMode"))
1553 ("text\\|title\\|xlabel\\|ylabel\\|zlabel" .
1554 ("Color" "EraseMode" "Editing" "Extent" "FontAngle" "FontName"
1555 "FontSize" "FontUnits" "FontWeight" "HorizontalAlignment"
1556 "BackgroundColor" "EdgeColor" "Margin"
1557 "Position" "Rotation" "String" "Units" "Interpreter"
1558 "VerticalAlignment"))
1559 ("uicontextmenu" . ("Callback"))
1560 ("uicontrol" .
1561 ("BackgroundColor" "Callback" "CData" "Enable" "Extent"
1562 "FontAngle" "FontName" "FontSize" "FontUnits" "FontWeight"
1563 "ForegroundColor" "HorizontalAlignment" "ListboxTop" "Max" "Min"
1564 "Position" "String" "Style" "SliderStep" "TooltipString" "Units"
1565 "Value"))
1566 ("uimenu" .
1567 ("Accelerator" "Callback" "Checked" "Enable" "ForegroundColor"
1568 "Label" "Position" "Separator"))
1569 ;; Flesh this out more later.
1570 ("uipushtool\\|uitoggletool\\|uitoolbar" .
1571 ("Cdata" "Callback" "Separator" "Visible"))
1572 )
1573 "List of property lists on a per object type basis.")
1574
1575 (defvar matlab-unknown-type-commands
1576 "[gs]et\\|findobj\\|waitfor"
1577 "Expression for commands that have unknown types.")
1578
1579 (defun matlab-all-known-properties ()
1580 "Return a list of all properties."
1581 (let ((lst matlab-core-properties)
1582 (tl matlab-property-lists))
1583 (while tl
1584 (setq lst (append lst (cdr (car tl)))
1585 tl (cdr tl)))
1586 (matlab-uniquafy-list lst)))
1587
1588 (defvar matlab-all-known-properties (matlab-all-known-properties)
1589 "List of all the known properties.")
1590
1591 (defmacro matlab-property-function ()
1592 "Regexp of all builtin functions that take property lists."
1593 '(let ((r matlab-unknown-type-commands)
1594 (tl matlab-property-lists))
1595 (while tl
1596 (setq r (concat r "\\|" (car (car tl)))
1597 tl (cdr tl)))
1598 r))
1599
1600 ;;; Navigation ===============================================================
1601
1602 (defvar matlab-scan-on-screen-only nil
1603 "When this is set to non-nil, then forward/backward sexp stops off screen.
1604 This is so the block highlighter doesn't gobble up lots of time when
1605 a block is not terminated.")
1606
1607 (defun matlab-backward-sexp (&optional autoend noerror)
1608 "Go backwards one balanced set of MATLAB expressions.
1609 If optional AUTOEND, then pretend we are at an end.
1610 If optional NOERROR, then we return t on success, and nil on failure.
1611 This assumes that expressions do not cross \"function\" at the left margin."
1612 (interactive "P")
1613 (matlab-navigation-syntax
1614 (if (and (not autoend)
1615 (save-excursion (backward-word 1)
1616 (or (not
1617 (and (looking-at
1618 (matlab-block-end-no-function-re))
1619 (matlab-valid-end-construct-p)))
1620 (matlab-cursor-in-string-or-comment))))
1621 ;; Go backwards one simple expression
1622 (forward-sexp -1)
1623 ;; otherwise go backwards recursively across balanced expressions
1624 ;; backup over our end
1625 (if (not autoend) (forward-word -1))
1626 (let ((done nil) (start (point)) (returnme t) (bound nil))
1627 (when (search-backward "\nfunction" nil t)
1628 (if (progn (forward-char 9) (looking-at "\\b"))
1629 (setq bound (- (point) 8)))
1630 (goto-char start))
1631 (while (and (not done)
1632 (or (not matlab-scan-on-screen-only)
1633 (pos-visible-in-window-p)))
1634 (if (re-search-backward (matlab-block-scan-re) bound t)
1635 (progn
1636 (goto-char (match-beginning 2))
1637 (if (looking-at (matlab-block-end-no-function-re))
1638 (if (or (matlab-cursor-in-string-or-comment)
1639 (not (matlab-valid-end-construct-p)))
1640 nil
1641 ;; we must skip the expression and keep searching
1642 (forward-word 1)
1643 (matlab-backward-sexp))
1644 (if (not (matlab-cursor-in-string-or-comment))
1645 (setq done t))))
1646 (goto-char start)
1647 (if noerror
1648 (setq returnme nil)
1649 (error "Unstarted END construct"))))
1650 returnme))))
1651
1652 (defun matlab-forward-sexp (&optional includeelse)
1653 "Go forward one balanced set of MATLAB expressions.
1654 Optional argument INCLUDEELSE will stop on ELSE if it matches the starting IF."
1655 (interactive "P")
1656 (let (p) ;; go to here if no error.
1657 (save-excursion ;; don't go anywhere if there is an error
1658 (matlab-navigation-syntax
1659 ;; skip over preceeding whitespace
1660 (skip-chars-forward " \t\n;")
1661 (if (or (not (looking-at (concat "\\("
1662 (matlab-block-beg-pre)
1663 "\\|"
1664 (matlab-block-mid-re)
1665 "\\)\\>")))
1666 (matlab-cursor-in-string-or-comment))
1667 ;; Go forwards one simple expression
1668 (forward-sexp 1)
1669 ;; otherwise go forwards recursively across balanced expressions
1670 (forward-word 1)
1671 (let ((done nil) (s nil)
1672 (expr-scan (if includeelse
1673 (matlab-block-re)
1674 (matlab-block-scan-re)))
1675 (expr-look (matlab-block-beg-pre)))
1676 (while (and (not done)
1677 (setq s (re-search-forward expr-scan nil t))
1678 (or (not matlab-scan-on-screen-only)
1679 (pos-visible-in-window-p)))
1680 (goto-char (match-beginning 2))
1681 (if (looking-at expr-look)
1682 (if (matlab-cursor-in-string-or-comment)
1683 (forward-word 1)
1684 ;; we must skip the expression and keep searching
1685 ;; NEVER EVER call with value of INCLUDEELSE
1686 (matlab-forward-sexp))
1687 (forward-word 1)
1688 (if (and (not (matlab-cursor-in-string-or-comment))
1689 (matlab-valid-end-construct-p))
1690 (setq done t))))
1691 (if (not s)
1692 (error "Unterminated block"))))
1693 (setq p (point)))) ;; really go here
1694 (goto-char p)))
1695
1696 (defun matlab-indent-sexp ()
1697 "Indent the syntactic block starting at point."
1698 (interactive)
1699 (indent-region (point) (save-excursion (matlab-forward-sexp) (point)) nil))
1700
1701 (defun matlab-beginning-of-enclosing-defun ()
1702 "Move cursor to beginning of enclosing function.
1703 If `matlab-functions-have-end', skip over functions with end."
1704 (catch 'done
1705 (let ((start (point))
1706 (beg nil))
1707 (while (re-search-backward matlab-defun-regex nil t)
1708 (setq beg (point))
1709 (condition-case nil
1710 (progn
1711 (matlab-forward-sexp)
1712 (if (> (point) start) (throw 'done beg)))
1713 (error (throw 'done beg)))
1714 (goto-char beg)))
1715 nil))
1716
1717 (defun matlab-beginning-of-defun ()
1718 "Go to the beginning of the current function."
1719 (interactive)
1720 (if matlab-functions-have-end
1721 (goto-char (or (matlab-beginning-of-enclosing-defun) (point-min)))
1722 (or (re-search-backward matlab-defun-regex nil t)
1723 (goto-char (point-min)))))
1724
1725 (defun matlab-end-of-defun ()
1726 "Go to the end of the current function."
1727 (interactive)
1728 (or (progn
1729 (if (looking-at matlab-defun-regex) (goto-char (match-end 0)))
1730 (if (re-search-forward matlab-defun-regex nil t)
1731 (progn (forward-line -1)
1732 t)))
1733 (goto-char (point-max))))
1734
1735 (defun matlab-current-defun ()
1736 "Return the name of the current function."
1737 (save-excursion
1738 (matlab-beginning-of-defun)
1739 (if (looking-at (matlab-match-function-re))
1740 (progn
1741 (goto-char (match-end 0))
1742 (current-word)))))
1743
1744 (defun matlab-beginning-of-command ()
1745 "Go to the beginning of an M command.
1746 Travels across continuations."
1747 (interactive)
1748 (beginning-of-line)
1749 (let ((p nil)
1750 ;; This restriction is a wild guess where to end reverse
1751 ;; searching for array continuations. The reason is that
1752 ;; matlab up list is very slow, and most people would never
1753 ;; put a blank line in a matrix. Either way, it's worth the
1754 ;; trade off to speed this up for large files.
1755 ;; This list of keywords is NOT meant to be comprehensive.
1756 (r (save-excursion
1757 (re-search-backward
1758 "^\\s-*\\(%\\|if\\|else\\(if\\)\\|while\\|\\(par\\)?for\\|$\\)\\>"
1759 nil t))))
1760 (while (and (or (save-excursion (and (matlab-prev-line)
1761 (matlab-lattr-cont)))
1762 (matlab-ltype-continued-comm)
1763 (setq p (matlab-lattr-array-cont r)))
1764 (save-excursion (beginning-of-line) (not (bobp))))
1765 (if p (goto-char p) (matlab-prev-line))
1766 (setq p nil))
1767 (back-to-indentation)))
1768
1769 (defun matlab-end-of-command (&optional beginning)
1770 "Go to the end of an M command.
1771 Optional BEGINNING is where the command starts from."
1772 (interactive)
1773 (while (and (or (matlab-lattr-cont)
1774 (save-excursion
1775 (forward-line 1)
1776 (or (matlab-ltype-continued-comm)
1777 (matlab-lattr-array-cont beginning))))
1778 ;; This hack is a short circuit. If a user did not
1779 ;; correctly end a matrix, this will short-circuit
1780 ;; as soon as somethng that would never appear in a matrix
1781 ;; becomes visible.
1782 (not (save-excursion
1783 (beginning-of-line)
1784 (looking-at (matlab-block-scan-re))))
1785 ;; If we hit the end of the buffer unexpectedly, this test
1786 ;; will fail and we'll avoid looping forever. (E.g., this
1787 ;; is triggered if a continuation line is the last one in
1788 ;; the buffer, and the line lacks the final newline.)
1789 (zerop (forward-line 1))))
1790 (end-of-line))
1791
1792
1793 ;;; Line types and attributes =================================================
1794
1795 (defun matlab-ltype-empty () ; blank line
1796 "Return t if current line is empty."
1797 (save-excursion
1798 (beginning-of-line)
1799 (looking-at "^[ \t]*$")))
1800
1801 (defun matlab-ltype-comm () ; comment line
1802 "Return t if current line is a MATLAB comment line.
1803 Return the symbol 'cellstart if it is a double %%."
1804 (save-excursion
1805 (beginning-of-line)
1806 (cond ((looking-at "[ \t]*%\\([^%]\\|$\\)")
1807 t)
1808 ((looking-at "[ \t]*%%")
1809 'cellstart)
1810 (t nil))))
1811
1812 (defun matlab-ltype-comm-ignore () ; comment out a region line
1813 "Return t if current line is a MATLAB comment region line."
1814 (save-excursion
1815 (beginning-of-line)
1816 (looking-at (concat "[ \t]*" matlab-comment-region-s))))
1817
1818 (defun matlab-ltype-help-comm ()
1819 "Return t if the current line is part of the MATLAB help comment."
1820 (save-excursion
1821 (if (not (matlab-ltype-comm))
1822 nil
1823 (while (and (matlab-ltype-comm) (not (bobp))
1824 (matlab-prev-line))
1825 (beginning-of-line))
1826 (matlab-ltype-function-definition))))
1827
1828 (defun matlab-ltype-endfunction-comm ()
1829 "Return t if the current line is an ENDFUNCTION style comment."
1830 (save-excursion
1831 (if (not (matlab-ltype-comm))
1832 nil
1833 (beginning-of-line)
1834 (if (looking-at "^[ \t]*%[ \t]*endfunction")
1835 t
1836 (while (and (or (matlab-ltype-comm)
1837 (matlab-ltype-empty))
1838 (not (eobp)))
1839 (forward-line 1))
1840 (matlab-ltype-function-definition)))))
1841
1842 (defun matlab-ltype-continued-comm ()
1843 "Return column of previous line's comment start, or nil."
1844 (save-excursion
1845 (beginning-of-line)
1846 (let ((commtype (matlab-ltype-comm)))
1847 (if (or (eq commtype 'cellstart) ;; Cells are not continuations from previous comments.
1848 (null commtype)
1849 (bobp))
1850 nil
1851 ;; We use forward-line and not matlab-prev-line because
1852 ;; we want blank lines to terminate this indentation method.
1853 (forward-line -1)
1854 (let ((col (matlab-lattr-comm)))
1855 (if col
1856 (progn
1857 (goto-char col)
1858 (current-column))
1859 nil))))))
1860
1861 (defun matlab-ltype-function-definition ()
1862 "Return t if the current line is a function definition."
1863 (save-excursion
1864 (beginning-of-line)
1865 (looking-at matlab-defun-regex)))
1866
1867 (defun matlab-ltype-code () ; line of code
1868 "Return t if current line is a MATLAB code line."
1869 (and (not (matlab-ltype-empty)) (not (matlab-ltype-comm))))
1870
1871 (defun matlab-lattr-comm () ; line has comment
1872 "Return t if current line contain a comment."
1873 (save-excursion (matlab-comment-on-line)))
1874
1875 (defun matlab-lattr-implied-continuation ()
1876 "Return non-nil if this line has implied continuation on the next.
1877 This is only useful for new versions of MATLAB where ... is optional."
1878 (when (not (matlab-lattr-comm))
1879 (let ((imp nil))
1880 (save-excursion
1881 (end-of-line)
1882 (skip-chars-backward " \t")
1883 ;; Test for oporator incompleteness.
1884 (setq imp
1885 (/= (point)
1886 ;; Careful, - means range in this expression.
1887 (progn (skip-chars-backward "-+=/*.^&~<>")
1888 (point))))
1889 (if (not imp)
1890 ;; Test for argument list incompleteness
1891 (condition-case nil
1892 (progn
1893 (end-of-line)
1894 (matlab-up-list -1)
1895 (setq imp (looking-at "(")))
1896 (error nil)))
1897 )
1898 imp)))
1899
1900 (defun matlab-lattr-cont () ; line has continuation
1901 "Return non-nil if current line ends in ... and optional comment.
1902 If `matlab-cont-requires-ellipsis' is nil, then we need to apply
1903 a heuristic to determine if this line would use continuation
1904 based on what it ends with."
1905 (save-excursion
1906 (beginning-of-line)
1907 (or
1908 ;; Here, if the line ends in ..., then it is what we are supposed to do.
1909 (and (re-search-forward "[^ \t.][ \t]*\\.\\.+[ \t]*\\(%.*\\)?$"
1910 (matlab-point-at-eol) t)
1911 (progn (goto-char (match-beginning 0))
1912 (not (matlab-cursor-in-comment))))
1913 ;; If the line doesn't end in ..., but we have optional ..., then
1914 ;; use this annoying heuristic.
1915 (and (null matlab-cont-requires-ellipsis)
1916 (matlab-lattr-implied-continuation))
1917 )))
1918
1919 (defun matlab-lattr-array-cont (&optional restrict)
1920 "Return non-nil if current line is in an array.
1921 If the entirety of the array is on this line, return nil.
1922 Optional option RESTRICT is the distrance to restrict the search."
1923 (condition-case nil
1924 (save-excursion
1925 (beginning-of-line)
1926 (matlab-up-list -1 restrict)
1927 (and (looking-at "[[{]") (point)))
1928 (error nil)))
1929
1930 (defun matlab-lattr-array-end ()
1931 "Return non-nil if the current line closes an array.
1932 by close, the first character is the end of an array."
1933 (save-excursion
1934 (back-to-indentation)
1935 (and (looking-at "[]}]") (matlab-lattr-array-cont))))
1936
1937 (defun matlab-lattr-block-cont (&optional eol)
1938 "Return a number representing the number of unterminated block constructs.
1939 This is any block, such as if or for, that doesn't have an END on this line.
1940 Optional EOL indicates a virtual end of line."
1941 (let ((v 0))
1942 (save-excursion
1943 (beginning-of-line)
1944 (save-restriction
1945 (narrow-to-region (point) (or eol (matlab-point-at-eol)))
1946 (matlab-navigation-syntax
1947 (while (re-search-forward (concat "\\<" (matlab-block-beg-re) "\\>")
1948 nil t)
1949 (if (matlab-cursor-in-string-or-comment)
1950 ;; Do nothing
1951 nil
1952 ;; Increment counter, move to end.
1953 (setq v (1+ v))
1954 (let ((p (point)))
1955 (forward-word -1)
1956 (condition-case nil
1957 (progn
1958 (matlab-forward-sexp)
1959 (setq v (1- v)))
1960 (error (goto-char p))))))
1961 v)))))
1962
1963 (defun matlab-lattr-middle-block-cont ()
1964 "Return the number of middle block continuations.
1965 This should be 1 or nil, and only true if the line starts with one of these
1966 special items."
1967 (save-excursion
1968 (back-to-indentation)
1969 (if (looking-at (concat (matlab-block-mid-re) "\\>"))
1970 (if (and (re-search-forward (matlab-block-end-pre)
1971 (matlab-point-at-eol)
1972 t)
1973 (matlab-valid-end-construct-p))
1974 ;; If there is an END, we still need to return non-nil,
1975 ;; but the number value is a net of 0.
1976 0
1977 1)
1978 nil)))
1979
1980 (defun matlab-lattr-endless-block-cont ()
1981 "Return the number of middle block continuations.
1982 This should be 1 or nil, and only true if the line starts with one of these
1983 special items."
1984 (save-excursion
1985 (back-to-indentation)
1986 (if (looking-at (concat (matlab-endless-blocks-re) "\\>"))
1987 1
1988 nil)))
1989
1990 (defun matlab-lattr-block-close (&optional start)
1991 "Return the number of closing block constructs.
1992 Argument START is where to start searching from."
1993 (let ((v 0))
1994 (save-excursion
1995 (when start (goto-char start))
1996 (save-restriction
1997 (narrow-to-region (save-excursion
1998 (matlab-beginning-of-command)
1999 (point))
2000 (matlab-point-at-eol))
2001 (goto-char (point-max))
2002 (while (and (re-search-backward (concat "\\<" (matlab-block-end-re) "\\>")
2003 nil t)
2004 (not (matlab-cursor-in-string-or-comment))
2005 (matlab-valid-end-construct-p))
2006 (setq v (1+ v))
2007 (let ((startmove (match-end 0))
2008 (nomove (point)))
2009 (condition-case nil
2010 (progn
2011 (matlab-backward-sexp t)
2012 (setq v (1- v)))
2013 (error (goto-char nomove)))
2014 ))
2015 ;; If we can't scoot back, do a cheat-test to see if there
2016 ;; is a matching else or elseif.
2017 (goto-char (point-min))
2018 (back-to-indentation)
2019 (if (looking-at (matlab-block-mid-re))
2020 (setq v (1- v)))
2021 ;; Return nil, or a number
2022 (if (<= v 0) nil v)))))
2023
2024 (defun matlab-lattr-local-end ()
2025 "Return t if this line begins with an end construct."
2026 (save-excursion
2027 (back-to-indentation)
2028 (and (looking-at (concat "\\<" (matlab-block-end-re) "\\>"))
2029 (matlab-valid-end-construct-p))))
2030
2031 (defun matlab-lattr-semantics (&optional prefix)
2032 "Return the semantics of the current position.
2033 Values are nil 'solo, 'value, and 'boolean. Boolean is a subset of
2034 value. nil means there is no semantic content (ie, string or comment.)
2035 If optional PREFIX, then return 'solo if that is the only thing on the
2036 line."
2037 (cond ;((matlab-cursor-in-string-or-comment)
2038 ;nil)
2039 ((or (matlab-ltype-empty)
2040 (and prefix (save-excursion
2041 (beginning-of-line)
2042 (looking-at (concat "\\s-*" prefix "\\s-*$")))))
2043 'solo)
2044 ((save-excursion
2045 (matlab-beginning-of-command)
2046 (looking-at "\\s-*\\(if\\|elseif\\|while\\)\\>"))
2047 'boolean)
2048 ((save-excursion
2049 (matlab-beginning-of-command)
2050 (looking-at (concat "\\s-*\\(" (matlab-property-function)
2051 "\\)\\>")))
2052 'property)
2053 (t
2054 'value)))
2055
2056 (defun matlab-function-called-at-point ()
2057 "Return a string representing the function called nearby point."
2058 (save-excursion
2059 (beginning-of-line)
2060 (cond ((looking-at "\\s-*\\([a-zA-Z]\\w+\\)[^=][^=]")
2061 (match-string 1))
2062 ((and (re-search-forward "=" (matlab-point-at-eol) t)
2063 (looking-at "\\s-*\\([a-zA-Z]\\w+\\)\\s-*[^=]"))
2064 (match-string 1))
2065 (t nil))))
2066
2067 (defun matlab-cursor-in-string-or-comment ()
2068 "Return t if the cursor is in a valid MATLAB comment or string."
2069 ;; comment and string depend on each other. Here is one test
2070 ;; that does both.
2071 (save-restriction
2072 (narrow-to-region (matlab-point-at-bol) (matlab-point-at-eol))
2073 (let ((p (1+ (point)))
2074 (returnme nil)
2075 (sregex (concat matlab-string-start-regexp "'")))
2076 (save-excursion
2077 (goto-char (point-min))
2078 (while (and (re-search-forward
2079 (concat "'\\|%\\|" (regexp-quote matlab-elipsis-string))
2080 nil t)
2081 (<= (point) p))
2082 (if (or (= ?% (preceding-char))
2083 (= ?. (preceding-char)))
2084 ;; Here we are in a comment for the rest of it.
2085 (progn
2086 (goto-char p)
2087 (setq returnme t))
2088 ;; Here, we could be a string start, or transpose...
2089 (if (or (= (current-column) 1)
2090 (save-excursion (forward-char -2)
2091 (looking-at sregex)))
2092 ;; a valid string start, find the end
2093 (let ((f (re-search-forward matlab-string-end-regexp nil t)))
2094 (if f
2095 (setq returnme (> (point) p))
2096 (setq returnme t)))
2097 ;; Ooops, a transpose, keep going.
2098 ))))
2099 returnme)))
2100
2101 (defun matlab-cursor-in-comment ()
2102 "Return t if the cursor is in a valid MATLAB comment."
2103 (save-match-data
2104 (save-restriction
2105 (narrow-to-region (matlab-point-at-bol) (matlab-point-at-eol))
2106 (save-excursion
2107 (let ((prev-match nil))
2108 (while (and (re-search-backward
2109 (concat "%\\|" (regexp-quote matlab-elipsis-string) "+")
2110 nil t)
2111 (not (matlab-cursor-in-string)))
2112 (setq prev-match (point)))
2113 (if (and prev-match (matlab-cursor-in-string))
2114 (goto-char prev-match))
2115 (and (looking-at (concat "%\\|"
2116 (regexp-quote matlab-elipsis-string)))
2117 (not (matlab-cursor-in-string))))))))
2118
2119 (defun matlab-cursor-in-string (&optional incomplete)
2120 "Return t if the cursor is in a valid MATLAB string.
2121 If the optional argument INCOMPLETE is non-nil, then return t if we
2122 are in what could be a an incomplete string."
2123 (let ((m (match-data))
2124 (returnme nil))
2125 (save-restriction
2126 (narrow-to-region (matlab-point-at-bol) (matlab-point-at-eol))
2127 (let ((p (1+ (point)))
2128
2129 (sregex (concat matlab-string-start-regexp "'"))
2130 (instring nil))
2131 (save-excursion
2132 ;; Comment hunters need strings to not call the comment
2133 ;; identifiers. Thus, this routines must be savvy of comments
2134 ;; without recursing to them.
2135 (goto-char (point-min))
2136 (while (or (and instring (looking-at "'"))
2137 (and (re-search-forward
2138 (concat "'\\|%\\|"
2139 (regexp-quote matlab-elipsis-string))
2140 nil t)
2141 (<= (point) p)
2142 ;; Short circuit to fix this.
2143 (progn (setq instring nil) t)))
2144 ;; The next line emulates re-search-foward
2145 (if instring (goto-char (match-end 0)))
2146 (if (or (= ?% (preceding-char))
2147 (= ?. (preceding-char)))
2148 ;; Here we are in a comment for the rest of it.
2149 ;; thus returnme is a force-false.
2150 (goto-char p)
2151 ;; Here, we could be in a string start, or transpose...
2152 (if (or (= (current-column) 1)
2153 instring
2154 (save-excursion (forward-char -2)
2155 (looking-at sregex)))
2156 ;; a valid string start, find the end
2157 (let ((f (re-search-forward matlab-string-end-regexp nil t)))
2158 (if (and (not f) incomplete)
2159 (setq returnme t)
2160 (setq returnme (> (point) p))
2161 (setq instring t)))
2162 ;; Ooops, a transpose, keep going.
2163 ))))))
2164 (set-match-data m)
2165 returnme))
2166
2167
2168 (defun matlab-comment-on-line ()
2169 "Place the cursor on the beginning of a valid comment on this line.
2170 If there isn't one, then return nil, point otherwise."
2171 (interactive)
2172 (let ((eol (matlab-point-at-eol))
2173 (p (point))
2174 (signal-error-on-buffer-boundary nil))
2175 (beginning-of-line)
2176 (while (and (re-search-forward "%" eol t)
2177 (save-excursion (forward-char -1) (matlab-cursor-in-string t))))
2178 (if (not (bolp)) (forward-char -1))
2179 (if (and (looking-at "%") (not (matlab-cursor-in-string t)))
2180 (point)
2181 (goto-char p)
2182 nil)))
2183
2184 ;;; Indent functions ==========================================================
2185
2186 (defun matlab-indent-line ()
2187 "Indent a line in `matlab-mode'."
2188 (interactive)
2189 (let ((i (matlab-calc-indent))
2190 (c (current-column)))
2191 (save-excursion
2192 (back-to-indentation)
2193 (if (= i (current-column))
2194 nil
2195 (beginning-of-line)
2196 (delete-horizontal-space)
2197 (indent-to i))
2198 ;; If line contains a comment, format it.
2199 (if () (if (matlab-lattr-comm) (matlab-comment))))
2200 (if (<= c i) (move-to-column i))))
2201
2202 (defun matlab-calc-indent ()
2203 "Return the appropriate indentation for this line as an integer."
2204 (interactive)
2205 ;; The first step is to find the current indentation.
2206 ;; This is defined to be zero if all previous lines are empty.
2207 (let* ((ci (save-excursion (if (not (matlab-prev-line))
2208 0
2209 (matlab-next-line-indentation))))
2210 (sem (matlab-calculate-indentation ci)))
2211 ;; simplistic
2212 (nth 1 sem)))
2213
2214 (defconst matlab-functions-have-end-should-be-true
2215 "This end closes a function definition.\nDo you want functions to have ends? "
2216 "Prompt the user about whether to change matlab-functions-have-end")
2217
2218 (defun matlab-calculate-indentation (current-indentation)
2219 "Calculate out the indentation of the current line.
2220 Return a list of descriptions for this line. Return format is:
2221 '(TYPE DEPTHNUMBER)
2222 where TYPE is one of (comment, code, function, blockstart, blockmid,
2223 blockendless, blockend) DEPTHNUMBER is how many characters to indent
2224 this line.
2225 Argument CURRENT-INDENTATION is what the previous line thinks
2226 this line's indentation should be. See `matlab-next-line-indentation'."
2227 (matlab-navigation-syntax
2228 (matlab-calculate-indentation-1 current-indentation)))
2229
2230 (defun matlab-calculate-indentation-1 (current-indentation)
2231 "Do the indentation work of `matlab-calculate-indentation'.
2232 Argument CURRENT-INDENTATION is what the previous line recommends for indentation."
2233 (let ((ci current-indentation)
2234 (tmp nil))
2235 (cond
2236 ;; COMMENTS
2237 ((matlab-ltype-comm)
2238 (cond
2239 ;; HELP COMMENT and COMMENT REGION
2240 ((or (matlab-ltype-help-comm)
2241 (matlab-ltype-comm-ignore))
2242 (list 'comment-help
2243 (save-excursion
2244 (matlab-beginning-of-defun)
2245 (current-indentation))))
2246 ;; COMMENT Continued From Previous Line
2247 ((setq tmp (matlab-ltype-continued-comm))
2248 (list 'comment tmp))
2249 ;; END FUNCTION COMMENT
2250 ((matlab-ltype-endfunction-comm)
2251 (list 'comment-endfunction 0))
2252 (t
2253 (list 'comment (+ ci matlab-comment-anti-indent)))))
2254 ;; FUNCTION DEFINITION
2255 ((matlab-ltype-function-definition)
2256 (if matlab-functions-have-end
2257 ;; A function line has intrinsic indentation iff function bodies are
2258 ;; not indented and the function line is nested within another function.
2259 (if (and (not matlab-indent-function-body)
2260 (save-excursion
2261 (beginning-of-line)
2262 (matlab-beginning-of-enclosing-defun)))
2263 (setq ci (+ ci matlab-indent-level))
2264 ;; If no intrinsic indentation, do not change from ci.
2265 )
2266 ;; If functions are not nested, functions go to left margin.
2267 (setq ci 0))
2268 (list 'function ci))
2269 ;; END keyword
2270 ((matlab-lattr-local-end)
2271 (let ((end-of-function
2272 (let ((matlab-functions-have-end t))
2273 (save-excursion
2274 (beginning-of-line)
2275 (matlab-backward-sexp t) ;; may throw "unstarted block" error
2276 (matlab-ltype-function-definition)))))
2277 (if end-of-function
2278 (if (or matlab-functions-have-end
2279 (if (yes-or-no-p matlab-functions-have-end-should-be-true)
2280 (setq matlab-functions-have-end t)
2281 (error "Unmatched end")))
2282 (if matlab-indent-function-body
2283 (setq ci (- ci matlab-indent-level))))
2284 ;; Next, see if this line starts with an end, and whether the
2285 ;; end is matched, and whether the line is blank up to the match.
2286 ;; If so, return the indentation of the match.
2287 (catch 'indent
2288 (save-excursion
2289 (when (progn (beginning-of-line)
2290 (and (looking-at "[ \t]*end\\b")
2291 (matlab-backward-sexp t t)))
2292 (let ((match (point)))
2293 (beginning-of-line)
2294 (looking-at "[ \t]*")
2295 (when (= match (match-end 0))
2296 (setq ci (- match (match-beginning 0)))
2297 (throw 'indent nil)))))
2298 ;; End of special case for end and match after "^[ \t]*".
2299 (setq ci (+ ci
2300 (* (1- (matlab-lattr-block-cont (point)))
2301 matlab-indent-level))))))
2302 (list 'blockend ci))
2303 ;; ELSE/CATCH keywords
2304 ((matlab-lattr-middle-block-cont)
2305 (let ((m (match-string 1)))
2306 (list 'blockmid
2307 (condition-case nil
2308 (save-excursion
2309 (beginning-of-line)
2310 (matlab-backward-sexp t)
2311 (if (matlab-ltype-function-definition) (error ""))
2312 (current-column))
2313 (error (error "Unmatched %s" m))))))
2314 ;; CASE/OTHERWISE keywords
2315 ((matlab-lattr-endless-block-cont)
2316 (list 'blockendless
2317 (condition-case nil
2318 (save-excursion
2319 (beginning-of-line)
2320 (matlab-backward-sexp t)
2321 (if (not (looking-at "switch\\>")) (error ""))
2322 (+ (current-column)
2323 (if (listp matlab-case-level)
2324 (car matlab-case-level)
2325 matlab-case-level)))
2326 (error (error "Unmatched case/otherwise part")))))
2327 ;; End of a MATRIX
2328 ((matlab-lattr-array-end)
2329 (list 'array-end (save-excursion
2330 (back-to-indentation)
2331 (matlab-up-list -1)
2332 (let* ((fc (following-char))
2333 (mi (assoc fc matlab-maximum-indents))
2334 (max (if mi (if (listp (cdr mi))
2335 (car (cdr mi)) (cdr mi))
2336 nil))
2337 (ind (if mi (if (listp (cdr mi))
2338 (cdr (cdr mi)) (cdr mi))
2339 nil)))
2340 ;; apply the maximum limits.
2341 (if (and ind (> (- (current-column) ci) max))
2342 (1- ind) ; decor
2343 (current-column))))))
2344 ;; Code lines
2345 ((save-excursion
2346 (beginning-of-line)
2347 (back-to-indentation)
2348 (= (point) (progn (matlab-beginning-of-command) (point))))
2349 ;; This means we are at the beginning of a command structure.
2350 ;; Always match up against the previous line.
2351 (list 'code ci))
2352 ;; Lines continued from previous statements.
2353 (t
2354 (list (if (matlab-ltype-empty) 'empty
2355 (if (matlab-lattr-array-cont) 'array-cont 'code))
2356 (condition-case nil
2357 ;; Line up with opening paren/brace/bracket
2358 (let ((boc (save-excursion
2359 (matlab-beginning-of-command)
2360 (point))))
2361 (save-excursion
2362 (beginning-of-line)
2363 (matlab-up-list -1)
2364 (if (> boc (point)) (error nil))
2365 ;; Ok, it MIGHT be that we are in a program
2366 ;; statement, and this particular command is an HG
2367 ;; statement that would look better if the
2368 ;; following lines lined up AFTER the first
2369 ;; argument. Lets look.
2370 (let ((parendepth (current-column)))
2371 (cond ((and (= (following-char) ?\( )
2372 (save-excursion
2373 (matlab-navigation-syntax
2374 (forward-word -1)
2375 (looking-at
2376 matlab-indent-past-arg1-functions)))
2377 (let ((start-paren (point)))
2378 (while
2379 (and
2380 (re-search-forward
2381 "," (matlab-point-at-eol) t)
2382 (save-excursion
2383 (matlab-up-list -1)
2384 (> (point) start-paren))))
2385 (if (and
2386 (= (preceding-char) ?,)
2387 ;; Don't bother if we hit the EOL.
2388 (not (looking-at
2389
2390 "\\s-*\\(\\.\\.\\.\\|$\\|)\\)")))
2391 t
2392 (move-to-column parendepth)
2393 nil)))
2394 (skip-chars-forward " \t")
2395 (if (> (- (current-column) parendepth)
2396 matlab-arg1-max-indent-length)
2397 (+ parendepth matlab-arg1-max-indent-length)
2398 (current-column)))
2399 (t
2400 (let* ((fc (following-char))
2401 (mi (assoc fc matlab-maximum-indents))
2402 (max (if mi
2403 (if (listp (cdr mi))
2404 (car (cdr mi)) (cdr mi))
2405 nil))
2406 (ind (if mi
2407 (if (listp (cdr mi))
2408 (cdr (cdr mi)) (cdr mi))
2409 nil)))
2410 (forward-char 1)
2411 (skip-chars-forward " \t")
2412 ;; If we are at the end of a line and
2413 ;; this open paren is there, then we
2414 ;; DONT want to indent to it. Use the
2415 ;; standard indent.
2416 (if (looking-at "\\.\\.\\.\\|$")
2417 ;; This could happen in another set
2418 ;; of matricies. Find a current
2419 ;; indentation based on the
2420 ;; previous line.
2421 (let ((cci (current-indentation)))
2422 (+ cci matlab-cont-level))
2423 ;; apply the maximum limits.
2424 (if (and ind (> (- (current-column) ci) max))
2425 (+ ci ind)
2426 (current-column)))))))))
2427 (error
2428 ;; Line up to an equals sign.
2429 (save-excursion
2430 (matlab-beginning-of-command)
2431 (while (and (re-search-forward "=" (matlab-point-at-eol) t)
2432 (matlab-cursor-in-string-or-comment)))
2433 (if (/= (preceding-char) ?=)
2434 (+ ci matlab-cont-level)
2435 (skip-chars-forward " \t")
2436 (let ((cc (current-column))
2437 (mi (assoc ?= matlab-maximum-indents)))
2438 (if (looking-at "\\.\\.\\.\\|$")
2439 ;; In this case, the user obviously wants the
2440 ;; indentation to be somewhere else.
2441 (+ ci (cdr (cdr mi)))
2442 ;; If the indent delta is greater than the max,
2443 ;; use the max + currenti
2444 (if (and mi (> (- cc ci) (if (listp (cdr mi))
2445 (car (cdr mi))
2446 (cdr mi))))
2447 (setq cc (+ ci (if (listp (cdr mi))
2448 (cdr (cdr mi))
2449 (cdr mi)))))
2450 cc))))))))
2451 )))
2452
2453 (defun matlab-next-line-indentation ()
2454 "Calculate the indentation for lines following this command line.
2455 Assume that the following line does not contribute its own indentation
2456 \(as it does in the case of nested functions in the following situations):
2457 o function---positive indentation when not indenting function bodies.
2458 o end---negative indentation except when the 'end' matches a function and
2459 not indenting function bodies.
2460 See `matlab-calculate-indentation'."
2461 (matlab-navigation-syntax
2462 (let ((startpnt (point-at-eol)))
2463 (save-excursion
2464 (matlab-beginning-of-command)
2465 (let ((cc (or (matlab-lattr-block-close startpnt) 0))
2466 (end (matlab-lattr-local-end))
2467 (bc (matlab-lattr-block-cont startpnt))
2468 (mc (matlab-lattr-middle-block-cont))
2469 (ec (matlab-lattr-endless-block-cont))
2470 (hc (and matlab-indent-function-body (matlab-ltype-help-comm)))
2471 (rc (and (/= 0 matlab-comment-anti-indent)
2472 (matlab-ltype-comm)
2473 (not (matlab-ltype-help-comm))
2474 (not (matlab-ltype-continued-comm))
2475 (not (matlab-ltype-endfunction-comm))))
2476 (ci (current-indentation)))
2477 ;; When the current point is on a line with a function, the value of bc will
2478 ;; reflect the function in a block count iff if matlab-functions-have-end is
2479 ;; true. However, if matlab-indent-function-body is false, there should be
2480 ;; no actual indentation, so bc needs to be decremented by 1. Similarly, if
2481 ;; on a line with an end that closes a function, bc needs to be decremented
2482 ;; by 1 if matlab-functions-have-end is true and matlab-indent-function-body
2483 ;; is false. However, just to be safe, indentation is not allowed to go
2484 ;; negative. Thus:
2485 (if matlab-functions-have-end
2486 (if (and
2487 (not matlab-indent-function-body)
2488 (or (matlab-ltype-function-definition)
2489 (and (matlab-lattr-local-end)
2490 (save-excursion
2491 (matlab-backward-sexp t)
2492 (looking-at "function\\b")))))
2493 (if (> bc 0)
2494 (setq bc (1- bc))
2495 (if (>= ci matlab-indent-level)
2496 (setq bc -1))))
2497 (if (and matlab-indent-function-body (matlab-ltype-function-definition))
2498 (setq bc (1+ bc))))
2499 ;; Remove 1 from the close count if there is an END on the beginning
2500 ;; of this line, since in that case, the unindent has already happened.
2501 (when end (setq cc (1- cc)))
2502 ;; Calculate the suggested indentation.
2503 (+ ci
2504 (* matlab-indent-level bc)
2505 (* matlab-indent-level (or mc 0))
2506 (* matlab-indent-level (- cc))
2507 (* (if (listp matlab-case-level)
2508 (cdr matlab-case-level) matlab-case-level)
2509 (or ec 0))
2510 (if hc matlab-indent-level 0)
2511 (if rc (- 0 matlab-comment-anti-indent) 0)
2512 ))))))
2513
2514 ;;; The return key ============================================================
2515
2516 (defcustom matlab-return-function 'matlab-indent-end-before-ret
2517 "Function to handle return key.
2518 Must be one of:
2519 'matlab-plain-ret
2520 'matlab-indent-after-ret
2521 'matlab-indent-end-before-ret
2522 'matlab-indent-before-ret"
2523 :group 'matlab
2524 :type '(choice (function-item matlab-plain-ret)
2525 (function-item matlab-indent-after-ret)
2526 (function-item matlab-indent-end-before-ret)
2527 (function-item matlab-indent-before-ret)))
2528
2529 (defun matlab-return ()
2530 "Handle carriage return in `matlab-mode'."
2531 (interactive)
2532 (matlab-semicolon-on-return)
2533 (funcall matlab-return-function))
2534
2535 (defun matlab-plain-ret ()
2536 "Vanilla new line."
2537 (interactive)
2538 (newline))
2539
2540 (defun matlab-indent-after-ret ()
2541 "Indent after new line."
2542 (interactive)
2543 (newline)
2544 (matlab-indent-line))
2545
2546 (defun matlab-indent-end-before-ret ()
2547 "Indent line if block end, start new line, and indent again."
2548 (interactive)
2549 (if (save-excursion
2550 (beginning-of-line)
2551 (looking-at (concat "^\\s-*\\(" (matlab-block-end-re)
2552 "\\|" (matlab-block-mid-re)
2553 "\\|" (matlab-endless-blocks-re)
2554 "\\|function\\)")))
2555 (matlab-indent-line))
2556 (newline)
2557 (matlab-indent-line))
2558
2559 (defun matlab-semicolon-on-return ()
2560 "If needed, add a semicolon at point automatically."
2561 (if matlab-return-add-semicolon
2562 (if (and (not (matlab-ltype-empty))
2563 (not (save-excursion
2564 (skip-chars-backward " \t;" (matlab-point-at-bol))
2565 (looking-at "\\s-*;")))
2566 (save-excursion
2567 (let ((p (point)))
2568 (matlab-end-of-command (point))
2569 (eq p (point))))
2570 (save-excursion
2571 (matlab-beginning-of-command)
2572 ;; Note: Compile warning below, but defined later.
2573 (not (looking-at matlab-quiesce-nosemi-regexp))))
2574 (insert ";"))
2575 ))
2576
2577 (defun matlab-indent-before-ret ()
2578 "Indent line, start new line, and indent again."
2579 (interactive)
2580 (matlab-indent-line)
2581 (newline)
2582 (matlab-indent-line))
2583
2584 (defun matlab-linefeed ()
2585 "Handle line feed in `matlab-mode'.
2586 Has effect of `matlab-return' with (not matlab-indent-before-return)."
2587 (interactive)
2588 (matlab-indent-line)
2589 (newline)
2590 (matlab-indent-line))
2591
2592 (defun matlab-comment-return ()
2593 "Handle carriage return for MATLAB comment line."
2594 (interactive)
2595 (cond
2596 ((matlab-ltype-comm)
2597 (matlab-set-comm-fill-prefix) (newline) (insert fill-prefix)
2598 (matlab-reset-fill-prefix) (matlab-indent-line))
2599 ((matlab-lattr-comm)
2600 (newline) (indent-to comment-column)
2601 (insert matlab-comment-on-line-s))
2602 (t
2603 (newline) (matlab-comment) (matlab-indent-line))))
2604
2605 (defun matlab-comm-from-prev ()
2606 "If the previous line is a comment-line then set up a comment on this line."
2607 (save-excursion
2608 ;; If the previous line is a comment-line then set the fill prefix from
2609 ;; the previous line and fill this line.
2610 (if (and (= 0 (forward-line -1)) (matlab-ltype-comm))
2611 (progn
2612 (matlab-set-comm-fill-prefix)
2613 (forward-line 1) (beginning-of-line)
2614 (delete-horizontal-space)
2615 (if (looking-at "%") (delete-char 1))
2616 (delete-horizontal-space)
2617 (insert fill-prefix)
2618 (matlab-reset-fill-prefix)))))
2619
2620 (defun matlab-electric-comment (arg)
2621 "Indent line and insert comment character.
2622 Argument ARG specifies how many %s to insert."
2623 (interactive "P")
2624 (self-insert-command (or arg 1))
2625 (when (matlab-ltype-comm)
2626 (matlab-indent-line)
2627 ;; The above seems to put the cursor on the %, not after it.
2628 (skip-chars-forward "%")))
2629
2630
2631 ;;; Comment management========================================================
2632
2633 (defun matlab-comment ()
2634 "Add a comment to the current line."
2635 (interactive)
2636 (cond ((matlab-ltype-empty) ; empty line
2637 (matlab-comm-from-prev)
2638 (if (matlab-lattr-comm)
2639 (skip-chars-forward " \t%")
2640 (insert matlab-comment-line-s)
2641 (matlab-indent-line)))
2642 ((matlab-ltype-comm) ; comment line
2643 (matlab-comm-from-prev)
2644 (skip-chars-forward " \t%"))
2645 ((matlab-lattr-comm) ; code line w/ comment
2646 (beginning-of-line)
2647 (re-search-forward "[^%]%[ \t]")
2648 (forward-char -2)
2649 (if (> (current-column) comment-column) (delete-horizontal-space))
2650 (if (< (current-column) comment-column) (indent-to comment-column))
2651 (skip-chars-forward "% \t"))
2652 (t ; code line w/o comment
2653 (end-of-line)
2654 (re-search-backward "[^ \t\n^]" 0 t)
2655 (forward-char)
2656 (delete-horizontal-space)
2657 (if (< (current-column) comment-column)
2658 (indent-to comment-column)
2659 (insert " "))
2660 (insert matlab-comment-on-line-s))))
2661
2662 (defun matlab-comment-line-break-function (&optional soft)
2663 "Break the current line, and if in a comment, continue it.
2664 Optional argument SOFT indicates that the newline is soft, and not hard."
2665 (interactive)
2666 (if (not (matlab-cursor-in-comment))
2667 (matlab-return)
2668 ;; Will the below fn work in old emacsen?
2669 (if soft (insert-and-inherit ?\n) (newline 1))
2670 (insert "% ")
2671 (matlab-indent-line)
2672 (end-of-line)))
2673
2674 (defun matlab-comment-indent ()
2675 "Indent a comment line in `matlab-mode'."
2676 (matlab-calc-indent))
2677
2678 (defun matlab-comment-region (beg-region end-region arg)
2679 "Comments every line in the region.
2680 Puts `matlab-comment-region-s' at the beginning of every line in the region.
2681 BEG-REGION and END-REGION are arguments which specify the region boundaries.
2682 With non-nil ARG, uncomments the region."
2683 (interactive "*r\nP")
2684 (let ((end-region-mark (make-marker)) (save-point (point-marker)))
2685 (set-marker end-region-mark end-region)
2686 (goto-char beg-region)
2687 (beginning-of-line)
2688 (if (not arg) ;comment the region
2689 (progn (insert matlab-comment-region-s)
2690 (while (and (= (forward-line 1) 0)
2691 (< (point) end-region-mark))
2692 (insert matlab-comment-region-s)))
2693 (let ((com (regexp-quote matlab-comment-region-s))) ;uncomment the region
2694 (if (looking-at com)
2695 (delete-region (point) (match-end 0)))
2696 (while (and (= (forward-line 1) 0)
2697 (< (point) end-region-mark))
2698 (if (looking-at com)
2699 (delete-region (point) (match-end 0))))))
2700 (goto-char save-point)
2701 (set-marker end-region-mark nil)
2702 (set-marker save-point nil)))
2703
2704 (defun matlab-uncomment-region (beg end)
2705 "Uncomment the current region if it is commented out.
2706 Argument BEG and END indicate the region to uncomment."
2707 (interactive "*r")
2708 (matlab-comment-region beg end t))
2709
2710 ;;; Filling ===================================================================
2711
2712 (defun matlab-set-comm-fill-prefix ()
2713 "Set the `fill-prefix' for the current (comment) line."
2714 (interactive)
2715 (if (matlab-lattr-comm)
2716 (setq fill-prefix
2717 (save-excursion
2718 (beginning-of-line)
2719 (let ((e (matlab-point-at-eol))
2720 (pf nil))
2721 (while (and (re-search-forward "%+[ \t]*\\($$$ \\)?" e t)
2722 (matlab-cursor-in-string)))
2723 (setq pf (match-string 0))
2724 (concat (make-string (- (current-column) (length pf)) ? )
2725 pf))))))
2726
2727 (defun matlab-set-comm-fill-prefix-post-code ()
2728 "Set the `fill-prefix' for the current post-code comment line."
2729 (interactive)
2730 (matlab-set-comm-fill-prefix))
2731
2732 (defun matlab-reset-fill-prefix ()
2733 "Reset the `fill-prefix'."
2734 (setq fill-prefix nil))
2735
2736 (defun matlab-find-convenient-line-break ()
2737 "For the current line, position the cursor where we want to break the line.
2738 Basically, spaces are best, then operators. Always less than `fill-column'
2739 unless we decide we can fudge the numbers. Return nil if this line should
2740 not be broken. This function will ONLY work on code."
2741 ;; First of all, if this is a continuation, then the user is
2742 ;; requesting that we don't mess with his stuff.
2743 (if (matlab-lattr-cont)
2744 nil
2745 (save-restriction
2746 (narrow-to-region (matlab-point-at-bol) (matlab-point-at-eol))
2747 ;; get ourselves onto the fill-column.
2748 (move-to-column fill-column)
2749 (let ((pos nil)
2750 (orig (point)))
2751 (or
2752 ;; Next, if we have a trailing comment, use that.
2753 (progn (setq pos (or (matlab-lattr-comm) (matlab-point-at-bol)))
2754 (goto-char pos)
2755 (if (and (> (current-column) (- fill-column matlab-fill-fudge))
2756 (< (current-column) (+ fill-column matlab-fill-fudge)))
2757 t
2758 (goto-char orig)
2759 nil))
2760 ;; Now, lets find the nearest space (after or before fill column)
2761 (let* ((after (save-excursion
2762 (re-search-forward "[ \t]" nil t)))
2763 (before (save-excursion
2764 (re-search-backward "[ \t]" nil t)))
2765 (afterd (- (or after (matlab-point-at-eol)) (point)))
2766 (befored (- (point) (or before (matlab-point-at-bol)))))
2767 ;; Here, if "before" is actually the beginning of our
2768 ;; indentation, then this is most obiously a bad place to
2769 ;; break our lines.
2770 (if before
2771 (save-excursion
2772 (goto-char before)
2773 (if (<= (point) (save-excursion
2774 (back-to-indentation)
2775 (point)))
2776 (setq before nil))))
2777 (cond ((and after
2778 (< afterd matlab-fill-fudge)
2779 (< afterd befored))
2780 (goto-char after)
2781 t)
2782 ((and before
2783 (< befored matlab-fill-fudge)
2784 (< befored afterd))
2785 (goto-char before)
2786 t)
2787 (t (goto-char orig)
2788 nil)))
2789 ;; Now, lets find the nearest backwards
2790 (progn
2791 (re-search-backward "\\(\\s-\\|\\s.\\)+" nil t)
2792 (while (and (looking-at "\\^\\|\\.\\|'")
2793 (re-search-backward "\\(\\s-\\|\\s.\\)+" nil t)))
2794 (if (or (not (looking-at "\\(\\s-\\|\\s.\\)+"))
2795 (<= (point) (save-excursion
2796 (back-to-indentation)
2797 (point))))
2798 (progn
2799 ;; We failed in our mission to find anything, or fell
2800 ;; of the edge of the earth. If we are out of
2801 ;; bounds, lets try again.
2802 (goto-char orig)
2803 (if (re-search-backward "\\s.+" nil t)
2804 t
2805 nil))
2806 ;; Ok, we have a good location to break. Check for column
2807 ;; and ref against nearest list ending to predict a possibly
2808 ;; better break point.
2809 (forward-char 1)
2810 (let ((okpos (current-column))
2811 (startlst (save-excursion
2812 (condition-case nil
2813 (matlab-up-list -1)
2814 (error nil))
2815 (if (save-excursion
2816 (forward-char -1)
2817 (looking-at "\\w"))
2818 (forward-word -1))
2819 (current-column)))
2820 (endlst (save-excursion
2821 (condition-case nil
2822 (matlab-up-list 1)
2823 (error nil))
2824 (current-column))))
2825 ;; When evaluating list fudge factores, breaking on the
2826 ;; edge of a list, or at the beginning of a function
2827 ;; call can be more valuable than breaking on a symbol
2828 ;; of a mid-sized list. As such, allow double-fudge
2829 ;; for lists.
2830 (cond
2831 ;; First, pick the end of a list.
2832 ((and (< endlst matlab-fill-fudge-hard-maximum)
2833 (<= endlst (+ fill-column matlab-fill-fudge))
2834 (or (<= (* matlab-fill-fudge 2) (- endlst okpos))
2835 (<= endlst fill-column))
2836 (save-excursion
2837 (move-to-column endlst)
2838 (not (looking-at "\\^"))))
2839 (move-to-column endlst)
2840 t)
2841 ;; Else, back up over this list and poke around
2842 ((>= (* 2 matlab-fill-fudge) (- okpos startlst))
2843 (move-to-column startlst)
2844 t)
2845 ;; Oh well, just do this symbol.
2846 (t (move-to-column okpos)
2847 t)))))
2848 ;; Well, this just sucks
2849 (progn (goto-char orig)
2850 nil))))))
2851
2852 (defun matlab-auto-fill ()
2853 "Do auto filling.
2854 Set variable `auto-fill-function' to this symbol to enable MATLAB style auto
2855 filling which will automatically insert `...' and the end of a line."
2856 (interactive)
2857 (let ((fill-prefix fill-prefix) ;; safe way of modifying fill-prefix.
2858 (fill-column (- fill-column
2859 (if matlab-fill-count-ellipsis-flag
2860 (save-excursion
2861 (move-to-column fill-column)
2862 (if (not (bobp))
2863 (forward-char -1))
2864 (if (matlab-cursor-in-string 'incomplete)
2865 4 3))
2866 0))))
2867 (if (> (current-column) fill-column)
2868 (cond
2869 ((matlab-ltype-comm-ignore)
2870 nil)
2871 ((or (matlab-ltype-comm)
2872 (and (save-excursion (move-to-column fill-column)
2873 (matlab-cursor-in-comment))
2874 (matlab-lattr-comm)))
2875 ;; If the whole line is a comment, do this.
2876 (matlab-set-comm-fill-prefix) (do-auto-fill)
2877 (matlab-reset-fill-prefix))
2878 ((and (matlab-ltype-code)
2879 (not (matlab-lattr-cont))
2880 matlab-fill-code)
2881 ;; If we are on a code line, we ellipsify before we fill.
2882 (let ((m (make-marker)))
2883 (move-marker m (point))
2884 (set-marker-insertion-type m t)
2885 (if (not (matlab-find-convenient-line-break))
2886 nil
2887 (if (not (save-excursion
2888 (forward-char -1)
2889 (matlab-cursor-in-string 'incomplete)))
2890 (progn
2891 (delete-horizontal-space)
2892 (insert " " matlab-elipsis-string "\n")
2893 (matlab-indent-line))
2894 (if matlab-fill-strings-flag
2895 (let ((pos (point))
2896 (pos2 nil))
2897 (while (and (re-search-backward "'" (point-at-bol) t)
2898 (progn (forward-char -1)
2899 (looking-at "''"))))
2900 (setq pos2 (point))
2901 ;; Check if there is already an opening bracket or if string is continued
2902 (if (or (looking-at "\\[")
2903 (save-excursion (skip-chars-backward " \t")
2904 (forward-char -1)
2905 (looking-at "\\["))
2906 (progn
2907 (beginning-of-line)
2908 (skip-chars-backward (concat " \t\n" matlab-elipsis-string))
2909 (if (> (point) (point-min))
2910 (progn
2911 (forward-char -1)
2912 (looking-at (concat "'\\s-*" matlab-elipsis-string))))))
2913 (goto-char pos)
2914 (goto-char pos2)
2915 (forward-char 1)
2916 (insert "[")
2917 (goto-char pos)
2918 (forward-char 1))
2919 ;(delete-horizontal-space)
2920 (skip-chars-forward " \t")
2921 (insert "' " matlab-elipsis-string "\n")
2922 (matlab-indent-line)
2923 (insert "'")
2924 ;; Re scan forward for the end of the string. Add an end bracket
2925 ;; if there isn't one already. Also add an apostrophe if necessary.
2926 (if (not (looking-at "'\\s-*]"))
2927 (save-excursion
2928 (if (not (re-search-forward "[^']'[^']" (line-end-position) t))
2929 (progn
2930 (end-of-line)
2931 (insert "']")
2932 (move-marker m (- (point) 2)))
2933 (forward-char -2)
2934 (if (not (looking-at "'\\s-*]"))
2935 (progn
2936 (forward-char 1)
2937 (insert "]"))))))
2938 ))))
2939 (goto-char m)))
2940 ))))
2941
2942 (defun matlab-join-comment-lines ()
2943 "Join current comment line to the next comment line."
2944 ;; New w/ V2.0: This used to join the previous line, but I could find
2945 ;; no editors that had a "join" that did that. I modified join to have
2946 ;; a behaviour I thought more inline with other editors.
2947 (interactive)
2948 (end-of-line)
2949 (if (looking-at "\n[ \t]*%")
2950 (replace-match " " t t nil)
2951 (error "No following comment to join with")))
2952
2953 (defun matlab-fill-region (beg-region end-region &optional justify-flag)
2954 "Fill the region between BEG-REGION and END-REGION.
2955 Non-nil JUSTIFY-FLAG means justify comment lines as well."
2956 (interactive "*r\nP")
2957 (let ((end-reg-mk (make-marker)))
2958 (set-marker end-reg-mk end-region)
2959 (goto-char beg-region)
2960 (beginning-of-line)
2961 (while (< (point) end-reg-mk)
2962 ;; This function must also leave the point at the end of the
2963 ;; justified line.
2964 (matlab-fill-paragraph justify-flag)
2965 (forward-line 1)
2966 (beginning-of-line))))
2967
2968 (defun matlab-fill-comment-line (&optional justify)
2969 "Fill the current comment line.
2970 With optional argument, JUSTIFY the comment as well."
2971 (interactive)
2972 (if (not (matlab-comment-on-line))
2973 (error "No comment to fill"))
2974 (beginning-of-line)
2975 ;; First, find the beginning of this comment...
2976 (while (and (looking-at matlab-cline-start-skip)
2977 (not (bobp)))
2978 (forward-line -1)
2979 (beginning-of-line))
2980 (if (not (looking-at matlab-cline-start-skip))
2981 (forward-line 1))
2982 ;; Now scan to the end of this comment so we have our outer bounds,
2983 ;; and narrow to that region.
2984 (save-restriction
2985 (narrow-to-region (point)
2986 (save-excursion
2987 (while (and (looking-at matlab-cline-start-skip)
2988 (not (save-excursion (end-of-line) (eobp))))
2989 (forward-line 1)
2990 (beginning-of-line))
2991 (if (not (looking-at matlab-cline-start-skip))
2992 (forward-line -1))
2993 (end-of-line)
2994 (point)))
2995 ;; Find the fill prefix...
2996 (matlab-comment-on-line)
2997 (looking-at "%[ \t]*")
2998 (let ((fill-prefix (concat (make-string (current-column) ? )
2999 (match-string 0))))
3000 (fill-region (point-min) (point-max) justify))))
3001
3002 (defun matlab-justify-line ()
3003 "Delete space on end of line and justify."
3004 (interactive)
3005 (save-excursion
3006 (end-of-line)
3007 (delete-horizontal-space)
3008 (justify-current-line)))
3009
3010 (defun matlab-fill-paragraph (arg)
3011 "When in a comment, fill the current paragraph.
3012 Paragraphs are always assumed to be in a comment.
3013 ARG is passed to `fill-paragraph' and will justify the text."
3014 (interactive "P")
3015 (cond ((or (matlab-ltype-comm)
3016 (and (matlab-cursor-in-comment)
3017 (not (matlab-lattr-cont))))
3018 ;; We are in a comment, lets fill the paragraph with some
3019 ;; nice regular expressions.
3020 ;; Cell start/end markers of %% also separate paragraphs
3021 (let ((paragraph-separate "%%\\|%[a-zA-Z]\\|%[ \t]*$\\|[ \t]*$")
3022 (paragraph-start "%[a-zA-Z]\\|%[ \t]*$\\|[ \t]*$")
3023 (paragraph-ignore-fill-prefix nil)
3024 (start (save-excursion (matlab-beginning-of-command)
3025 (if (looking-at "%%")
3026 (progn (end-of-line)
3027 (forward-char 1)))
3028 (point)))
3029 (end (save-excursion (matlab-end-of-command)
3030 (point)))
3031 (fill-prefix nil))
3032 (matlab-set-comm-fill-prefix)
3033 (save-restriction
3034 ;; Ben North fixed to handle comment at the end of
3035 ;; a buffer.
3036 (narrow-to-region start (min (point-max) (+ end 1)))
3037 (fill-paragraph arg))))
3038 ((matlab-ltype-code)
3039 ;; Ok, lets get the outer bounds of this command, then
3040 ;; completely refill it using the smart line breaking code.
3041 (save-restriction
3042 (narrow-to-region (save-excursion
3043 (matlab-beginning-of-command)
3044 (beginning-of-line)
3045 (point))
3046 (save-excursion
3047 (matlab-end-of-command)
3048 (point)))
3049 ;; Remove all line breaks
3050 (goto-char (point-min))
3051 (while (and (re-search-forward "$" nil t)
3052 (not (eobp)))
3053 (delete-horizontal-space)
3054 ;; Blow away continuation marks
3055 (if (matlab-lattr-cont)
3056 (progn
3057 (goto-char (match-beginning 0))
3058 (forward-char 1)
3059 (delete-region (point) (matlab-point-at-eol))))
3060 ;; Zap the CR
3061 (if (not (eobp)) (delete-char 1))
3062 ;; Clean up whitespace
3063 (delete-horizontal-space)
3064 ;; Clean up trailing comments
3065 (if (and (looking-at "% *")
3066 (matlab-cursor-in-comment))
3067 (progn
3068 (delete-char 1)
3069 (delete-horizontal-space)))
3070 (insert " "))
3071 ;; Now fill till we are done
3072 (goto-char (point-max))
3073 (while (or (> (current-column) (+ fill-column matlab-fill-fudge))
3074 (> (current-column) matlab-fill-fudge-hard-maximum))
3075 (if (= (point)
3076 (progn
3077 (matlab-auto-fill)
3078 (point)))
3079 (error "Fill algorith failed!"))
3080 (if arg (save-excursion
3081 (forward-line -1)
3082 (matlab-justify-line))))
3083 (if arg (save-excursion
3084 (forward-line -1)
3085 (matlab-justify-line)))))
3086 (t
3087 (message "Paragraph Fill not supported in this context."))))
3088
3089 ;;; Semantic text insertion and management ====================================
3090
3091 (defun matlab-find-recent-variable-list (prefix)
3092 "Return a list of most recent variables starting with PREFIX as a string.
3093 Reverse searches for the following are done first:
3094 1) Assignment
3095 2) if|for|while|switch <var>
3096 3) global variables
3097 4) function arguments.
3098 All elements are saved in a list, which is then uniqafied.
3099 If NEXT is non-nil, then the next element from the saved list is used.
3100 If the list is empty, then searches continue backwards through the code."
3101 (matlab-navigation-syntax
3102 (let* ((bounds (save-excursion
3103 (if (re-search-backward "^\\s-*function\\>" nil t)
3104 (match-beginning 0) (point-min))))
3105 (syms
3106 (append
3107 (save-excursion
3108 (let ((lst nil))
3109 (while (and
3110 (re-search-backward
3111 (concat "^\\s-*\\(" prefix "\\w+\\)\\s-*=")
3112 bounds t)
3113 (< (length lst) 10))
3114 (setq lst (cons (match-string 1) lst)))
3115 (nreverse lst)))
3116 (save-excursion
3117 (let ((lst nil))
3118 (while (and (re-search-backward
3119 (concat "\\<\\(" matlab-block-beg-pre-no-if
3120 "\\)\\s-+(?\\s-*\\(" prefix
3121 "\\w+\\)\\>")
3122 bounds t)
3123 (< (length lst) 10))
3124 (setq lst (cons (match-string 2) lst)))
3125 (nreverse lst)))
3126 (save-excursion
3127 (if (re-search-backward "^\\s-*global\\s-+" bounds t)
3128 (let ((lst nil) m e)
3129 (goto-char (match-end 0))
3130 (while (looking-at "\\(\\w+\\)\\([ \t]+\\|$\\)")
3131 (setq m (match-string 1)
3132 e (match-end 0))
3133 (if (equal 0 (string-match prefix m))
3134 (setq lst (cons m lst)))
3135 (goto-char e))
3136 (nreverse lst))))
3137 (save-excursion
3138 (if (and (re-search-backward "^\\s-*function\\>" bounds t)
3139 (re-search-forward "\\<\\(\\w+\\)("
3140 (matlab-point-at-eol) t))
3141 (let ((lst nil) m e)
3142 (while (looking-at "\\(\\w+\\)\\s-*[,)]\\s-*")
3143 (setq m (match-string 1)
3144 e (match-end 0))
3145 (if (equal 0 (string-match prefix m))
3146 (setq lst (cons m lst)))
3147 (goto-char e))
3148 (nreverse lst))))))
3149 (fl nil))
3150 (while syms
3151 (if (car syms) (setq fl (cons (car syms) fl)))
3152 (setq syms (cdr syms)))
3153 (matlab-uniquafy-list (nreverse fl)))))
3154
3155 (defvar matlab-most-recent-variable-list nil
3156 "Maintained by `matlab-find-recent-variable'.")
3157
3158 (defun matlab-find-recent-variable (prefix &optional next)
3159 "Return the most recently used variable starting with PREFIX as a string.
3160 See `matlab-find-recent-variable-list' for details.
3161 In NEXT is non-nil, than continue through the list of elements."
3162 (if next
3163 (let ((next (car matlab-most-recent-variable-list)))
3164 (setq matlab-most-recent-variable-list
3165 (cdr matlab-most-recent-variable-list))
3166 next)
3167 (let ((syms (matlab-find-recent-variable-list prefix))
3168 (first nil))
3169 (if (eq matlab-completion-technique 'complete)
3170 syms
3171 (setq first (car syms))
3172 (setq matlab-most-recent-variable-list (cdr syms))
3173 first))))
3174
3175 (defun matlab-find-user-functions-list (prefix)
3176 "Return a list of user defined functions that match PREFIX."
3177 (matlab-navigation-syntax
3178 (let ((syms
3179 (append
3180 (save-excursion
3181 (goto-char (point-min))
3182 (let ((lst nil))
3183 (while (re-search-forward "^\\s-*function\\>" nil t)
3184 (if (re-search-forward
3185 (concat "\\(" prefix "\\w+\\)\\s-*\\($\\|(\\)")
3186 (matlab-point-at-eol) t)
3187 (setq lst (cons (match-string 1) lst))))
3188 (nreverse lst)))
3189 (let ((lst nil)
3190 (files (directory-files
3191 default-directory nil
3192 (concat "^" prefix
3193 "[a-zA-Z][a-zA-Z0-9_]+\\.m$"))))
3194 (while files
3195 (setq lst (cons (progn (string-match "\\.m" (car files))
3196 (substring (car files) 0
3197 (match-beginning 0)))
3198 lst)
3199 files (cdr files)))
3200 lst)))
3201 (fl nil))
3202 (while syms
3203 (if (car syms) (setq fl (cons (car syms) fl)))
3204 (setq syms (cdr syms)))
3205 (matlab-uniquafy-list (nreverse fl)))))
3206
3207 (defvar matlab-user-function-list nil
3208 "Maintained by `matlab-find-user-functions'.")
3209
3210 (defun matlab-find-user-functions (prefix &optional next)
3211 "Return a user function that match PREFIX and return it.
3212 If optional argument NEXT is non-nil, then return the next found
3213 object."
3214 (if next
3215 (let ((next (car matlab-user-function-list)))
3216 (setq matlab-user-function-list (cdr matlab-user-function-list))
3217 next)
3218 (let ((syms (matlab-find-user-functions-list prefix))
3219 (first nil))
3220 (if (eq matlab-completion-technique 'complete)
3221 syms
3222 (setq first (car syms))
3223 (setq matlab-user-function-list (cdr syms))
3224 first))))
3225
3226 (defvar matlab-generic-list-placeholder nil
3227 "Maintained by `matalb-generic-list-expand'.
3228 Holds sub-lists of symbols left to be expanded.")
3229
3230 (defun matlab-generic-list-expand (list prefix &optional next)
3231 "Return an element from LIST that start with PREFIX.
3232 If optional NEXT argument is non nil, then the next element in the
3233 list is used. nil is returned if there are not matches."
3234 (if next
3235 (let ((next (car matlab-generic-list-placeholder)))
3236 (setq matlab-generic-list-placeholder
3237 (cdr matlab-generic-list-placeholder))
3238 next)
3239 (let ((re (concat "^" (regexp-quote prefix)))
3240 (first nil)
3241 (fl nil))
3242 (while list
3243 (if (string-match re (car list))
3244 (setq fl (cons (car list) fl)))
3245 (setq list (cdr list)))
3246 (setq fl (nreverse fl))
3247 (if (eq matlab-completion-technique 'complete)
3248 fl
3249 (setq first (car fl))
3250 (setq matlab-generic-list-placeholder (cdr fl))
3251 first))))
3252
3253 (defun matlab-solo-completions (prefix &optional next)
3254 "Return PREFIX matching elements for solo symbols.
3255 If NEXT then the next patch from the list is used."
3256 (matlab-generic-list-expand matlab-keywords-solo prefix next))
3257
3258 (defun matlab-value-completions (prefix &optional next)
3259 "Return PREFIX matching elements for value symbols.
3260 If NEXT then the next patch from the list is used."
3261 (matlab-generic-list-expand matlab-keywords-return prefix next))
3262
3263 (defun matlab-boolean-completions (prefix &optional next)
3264 "Return PREFIX matching elements for boolean symbols.
3265 If NEXT then the next patch from the list is used."
3266 (matlab-generic-list-expand matlab-keywords-boolean prefix next))
3267
3268 (defun matlab-property-completions (prefix &optional next)
3269 "Return PREFIX matching elements for property names in strings.
3270 If NEXT then the next property from the list is used."
3271 (let ((f (matlab-function-called-at-point))
3272 (lst matlab-property-lists)
3273 (foundlst nil)
3274 (expandto nil))
3275 ;; Look for this function. If it is a known function then we
3276 ;; can now use a subset of available properties!
3277 (while (and lst (not foundlst))
3278 (if (string= (car (car lst)) f)
3279 (setq foundlst (cdr (car lst))))
3280 (setq lst (cdr lst)))
3281 (if foundlst
3282 (setq foundlst (append foundlst matlab-core-properties))
3283 (setq foundlst matlab-all-known-properties))
3284 (setq expandto (matlab-generic-list-expand foundlst prefix next))
3285 ;; This looks to see if we have a singular completion. If so,
3286 ;; then return it, and also append the "'" to the end.
3287 (cond ((and (listp expandto) (= (length expandto) 1))
3288 (setq expandto (list (concat (car expandto) "'"))))
3289 ((stringp expandto)
3290 (setq expandto (concat expandto "'"))))
3291 expandto))
3292
3293 (defvar matlab-last-prefix nil
3294 "Maintained by `matlab-complete-symbol'.
3295 The prefix used for the first completion command.")
3296 (defvar matlab-last-semantic nil
3297 "Maintained by `matlab-complete-symbol'.
3298 The last type of semantic used while completing things.")
3299 (defvar matlab-completion-search-state nil
3300 "List of searching things we will be doing.")
3301
3302 (defun matlab-complete-symbol (&optional arg)
3303 "Complete a partially typed symbol in a MATLAB mode buffer.
3304 If the previously entered command was also `matlab-complete-symbol'
3305 then undo the last completion, and find a new one.
3306 The types of symbols tried are based on the semantics of the current
3307 cursor position. There are two types of symbols. For example, if the
3308 cursor is in an if statement, boolean style functions and symbols are
3309 tried first. If the line is blank, then flow control, or high level
3310 functions are tried first.
3311 The completion technique is controlled with `matlab-completion-technique'
3312 It defaults to incremental completion described above. If a
3313 completion list is preferred, then change this to 'complete. If you
3314 just want a completion list once, then use the universal argument ARG
3315 to change it temporarily."
3316 (interactive "P")
3317 (matlab-navigation-syntax
3318 (let* ((prefix (if (and (not (eq last-command 'matlab-complete-symbol))
3319 (member (preceding-char) '(? ?\t ?\n ?, ?\( ?\[ ?\')))
3320 ""
3321 (buffer-substring-no-properties
3322 (save-excursion (forward-word -1) (point))
3323 (point))))
3324 (sem (matlab-lattr-semantics prefix))
3325 (matlab-completion-technique
3326 (if arg (cond ((eq matlab-completion-technique 'complete)
3327 'increment)
3328 (t 'complete))
3329 matlab-completion-technique)))
3330 (if (not (eq last-command 'matlab-complete-symbol))
3331 (setq matlab-last-prefix prefix
3332 matlab-last-semantic sem
3333 matlab-completion-search-state
3334 (cond ((eq sem 'solo)
3335 '(matlab-solo-completions
3336 matlab-find-user-functions
3337 matlab-find-recent-variable))
3338 ((eq sem 'boolean)
3339 '(matlab-find-recent-variable
3340 matlab-boolean-completions
3341 matlab-find-user-functions
3342 matlab-value-completions))
3343 ((eq sem 'value)
3344 '(matlab-find-recent-variable
3345 matlab-find-user-functions
3346 matlab-value-completions
3347 matlab-boolean-completions))
3348 ((eq sem 'property)
3349 '(matlab-property-completions
3350 matlab-find-user-functions
3351 matlab-find-recent-variable
3352 matlab-value-completions))
3353 (t '(matlab-find-recent-variable
3354 matlab-find-user-functions
3355 matlab-value-completions
3356 matlab-boolean-completions)))))
3357 (cond
3358 ((eq matlab-completion-technique 'increment)
3359 (let ((r nil) (donext (eq last-command 'matlab-complete-symbol)))
3360 (while (and (not r) matlab-completion-search-state)
3361 (message "Expand with %S" (car matlab-completion-search-state))
3362 (setq r (funcall (car matlab-completion-search-state)
3363 matlab-last-prefix donext))
3364 (if (not r) (setq matlab-completion-search-state
3365 (cdr matlab-completion-search-state)
3366 donext nil)))
3367 (delete-region (point) (progn (forward-char (- (length prefix)))
3368 (point)))
3369 (if r
3370 (insert r)
3371 (insert matlab-last-prefix)
3372 (message "No completions."))))
3373 ((eq matlab-completion-technique 'complete)
3374 (let ((allsyms (apply 'append
3375 (mapcar (lambda (f) (funcall f prefix))
3376 matlab-completion-search-state))))
3377 (cond ((null allsyms)
3378 (message "No completions.")
3379 (ding))
3380 ((= (length allsyms) 1)
3381 (delete-region (point) (progn
3382 (forward-char (- (length prefix)))
3383 (point)))
3384 (insert (car allsyms)))
3385 ((= (length allsyms) 0)
3386 (message "No completions."))
3387 (t
3388 (let* ((al (mapcar (lambda (a) (list a)) allsyms))
3389 (c (try-completion prefix al)))
3390 ;; This completion stuff lets us expand as much as is
3391 ;; available to us. When the completion is the prefix
3392 ;; then we want to display all the strings we've
3393 ;; encountered.
3394 (if (and (stringp c) (not (string= prefix c)))
3395 (progn
3396 (delete-region
3397 (point)
3398 (progn (forward-char (- (length prefix)))
3399 (point)))
3400 (insert c))
3401 ;; `display-completion-list' does all the complex
3402 ;; ui work for us.
3403 (with-output-to-temp-buffer "*Completions*"
3404 (display-completion-list
3405 (matlab-uniquafy-list allsyms)))))))))))))
3406
3407 (defun matlab-insert-end-block (&optional reindent)
3408 "Insert and END block based on the current syntax.
3409 Optional argument REINDENT indicates if the specified block should be re-indented."
3410 (interactive "P")
3411 (if (not (matlab-ltype-empty)) (progn (end-of-line) (insert "\n")))
3412 (let ((valid t) (begin nil))
3413 (save-excursion
3414 (condition-case nil
3415 (progn
3416 (matlab-backward-sexp t)
3417 (setq begin (point)
3418 valid (buffer-substring-no-properties
3419 (point) (save-excursion
3420 (re-search-forward "[\n,;.]" nil t)
3421 (point)))))
3422 (error (setq valid nil))))
3423 (if (not valid)
3424 (error "No block to end")
3425 (insert "end")
3426 (if (stringp valid) (insert " % " valid))
3427 (matlab-indent-line)
3428 (if reindent (indent-region begin (point) nil)))))
3429
3430 (tempo-define-template
3431 "matlab-for"
3432 '("for " p "=" p "," > n>
3433 r> &
3434 "end" > %)
3435 "for"
3436 "Insert a MATLAB for statement"
3437 'matlab-tempo-tags
3438 )
3439
3440 (tempo-define-template
3441 "matlab-while"
3442 '("while (" p ")," > n>
3443 r> &
3444 "end" > %)
3445 "while"
3446 "Insert a MATLAB while statement"
3447 'matlab-tempo-tags
3448 )
3449
3450 (tempo-define-template
3451 "matlab-if"
3452 '("if " p > n
3453 r>
3454 "end" > n)
3455 "if"
3456 "Insert a MATLAB if statement"
3457 'matlab-tempo-tags
3458 )
3459
3460 (tempo-define-template
3461 "matlab-if-else"
3462 '("if " p > n
3463 r>
3464 "else" > n
3465 "end" > n)
3466 "if"
3467 "Insert a MATLAB if statement"
3468 'matlab-tempo-tags
3469 )
3470
3471 (tempo-define-template
3472 "matlab-try"
3473 '("try " > n
3474 r>
3475 "catch" > n
3476 p > n
3477 "end" > n)
3478 "try"
3479 "Insert a MATLAB try catch statement"
3480 'matlab-tempo-tags
3481 )
3482
3483 (tempo-define-template
3484 "matlab-switch"
3485 '("switch " p > n
3486 "otherwise" > n
3487 r>
3488 "end" > n)
3489 "switch"
3490 "Insert a MATLAB switch statement with region in the otherwise clause."
3491 'matlab-tempo-tags)
3492
3493 (defun matlab-insert-next-case ()
3494 "Insert a case statement inside this switch statement."
3495 (interactive)
3496 ;; First, make sure we are where we think we are.
3497 (let ((valid t))
3498 (save-excursion
3499 (condition-case nil
3500 (progn
3501 (matlab-backward-sexp t)
3502 (setq valid (looking-at "switch")))
3503 (error (setq valid nil))))
3504 (if (not valid)
3505 (error "Not in a switch statement")))
3506 (if (not (matlab-ltype-empty)) (progn (end-of-line) (insert "\n")))
3507 (indent-to 0)
3508 (insert "case ")
3509 (matlab-indent-line))
3510
3511 (tempo-define-template
3512 "matlab-function"
3513 '("function "
3514 (P "output argument(s): " output t)
3515 ;; Insert brackets only if there is more than one output argument
3516 (if (string-match "," (tempo-lookup-named 'output))
3517 '(l "[" (s output) "]")
3518 '(l (s output)))
3519 ;; Insert equal sign only if there is output argument(s)
3520 (if (= 0 (length (tempo-lookup-named 'output))) nil
3521 " = ")
3522 ;; The name of a function, as defined in the first line, should
3523 ;; be the same as the name of the file without .m extension
3524 (if (= 1 (count-lines 1 (point)))
3525 (tempo-save-named
3526 'fname
3527 (file-name-nondirectory (file-name-sans-extension
3528 (buffer-file-name))))
3529 '(l (P "function name: " fname t)))
3530 (tempo-lookup-named 'fname)
3531 "(" (P "input argument(s): ") ")" n
3532 "% " (upcase (tempo-lookup-named 'fname)) " - " (P "H1 line: ") n
3533 "% " p n
3534 (if matlab-functions-have-end
3535 '(l "end" n)))
3536 "function"
3537 "Insert a MATLAB function statement"
3538 'matlab-tempo-tags
3539 )
3540
3541 (defun matlab-stringify-region (begin end)
3542 "Put MATLAB 's around region, and quote all quotes in the string.
3543 Stringification allows you to type in normal MATLAB code, mark it, and
3544 then turn it into a MATLAB string that will output exactly what's in
3545 the region. BEGIN and END mark the region to be stringified."
3546 (interactive "r")
3547 (save-excursion
3548 (goto-char begin)
3549 (if (re-search-forward "\n" end t)
3550 (error
3551 "You may only stringify regions that encompass less than one line"))
3552 (let ((m (make-marker)))
3553 (move-marker m end)
3554 (goto-char begin)
3555 (insert "'")
3556 (while (re-search-forward "'" m t)
3557 (insert "'"))
3558 (goto-char m)
3559 (insert "'"))))
3560
3561 (defun matlab-ispell-strings-region (begin end)
3562 "Spell check valid strings in region with Ispell.
3563 Argument BEGIN and END mark the region boundary."
3564 (interactive "r")
3565 (require 'ispell)
3566 (save-excursion
3567 (goto-char begin)
3568 ;; Here we use the font lock function for finding strings.
3569 ;; Its cheap, fast, and accurate.
3570 (while (and (matlab-font-lock-string-match-normal end)
3571 (ispell-region (match-beginning 2) (match-end 2))))))
3572
3573 (defun matlab-ispell-strings ()
3574 "Spell check valid strings in the current buffer with Ispell.
3575 Calls `matlab-ispell-strings-region'"
3576 (interactive)
3577 (matlab-ispell-strings-region (point-min) (point-max)))
3578
3579 (defun matlab-ispell-comments (&optional arg)
3580 "Spell check comments in the current buffer with Ispell.
3581 Optional ARG means to only check the current comment."
3582 (interactive "P")
3583 (let ((beg (point-min))
3584 (end (point-max)))
3585 (if (and arg (matlab-ltype-comm))
3586 (setq beg (save-excursion (matlab-beginning-of-command) (point))
3587 end (save-excursion (matlab-end-of-command) (point))))
3588 (save-excursion
3589 (goto-char beg)
3590 (beginning-of-line)
3591 (while (and (matlab-font-lock-comment-match end)
3592 (ispell-region (match-beginning 1) (match-end 1)))))))
3593
3594 (defun matlab-generate-latex ()
3595 "Convert a MATLAB M file into a Latex document for printing.
3596 Author: Uwe Brauer oub@eucmos.sim.ucm.es
3597 Created: 14 Feb 2002"
3598 (interactive "*")
3599 (save-restriction
3600 (save-excursion
3601 (goto-char (point-min))
3602 (insert "\\documentclass[12pt]{report}\n
3603 \\usepackage{listings}
3604 \\lstloadlanguages{Matlab}
3605 \\lstset{language=Matlab,keywordstyle=\\bfseries,labelstep=1,escapechar=\\#}
3606 \\begin{document}
3607 \\begin{lstlisting}{}")
3608 (newline)
3609 (goto-char (point-max))
3610 (insert "\n\\end{lstlisting}\n\\end{document}")
3611 (widen)))
3612 (font-lock-mode nil)
3613 (LaTeX-mode)
3614 (font-lock-mode nil))
3615
3616
3617 ;;; Block highlighting ========================================================
3618
3619 (defvar matlab-block-highlighter-timer nil
3620 "The timer representing the block highlighter.")
3621
3622 (defun matlab-enable-block-highlighting (&optional arg)
3623 "Start or stop the block highlighter.
3624 Optional ARG is 1 to force enable, and -1 to disable.
3625 If ARG is nil, then highlighting is toggled."
3626 (interactive "P")
3627 (if (not (fboundp 'matlab-run-with-idle-timer))
3628 (setq matlab-highlight-block-match-flag nil))
3629 ;; Only do it if it's enabled.
3630 (if (not matlab-highlight-block-match-flag)
3631 nil
3632 ;; Use post command idle hook as a local hook to dissuade too much
3633 ;; cpu time while doing other things.
3634 ;;(make-local-hook 'post-command-hook)
3635 (if (not arg)
3636 (setq arg
3637 (if (member 'matlab-start-block-highlight-timer
3638 post-command-hook)
3639 -1 1)))
3640 (if (> arg 0)
3641 (add-hook 'post-command-hook 'matlab-start-block-highlight-timer)
3642 (remove-hook 'post-command-hook 'matlab-start-block-highlight-timer))))
3643
3644 (defvar matlab-block-highlight-overlay nil
3645 "The last highlighted overlay.")
3646 (make-variable-buffer-local 'matlab-block-highlight-overlay)
3647
3648 (defvar matlab-block-highlight-timer nil
3649 "Last started timer.")
3650 (make-variable-buffer-local 'matlab-block-highlight-timer)
3651
3652 (defun matlab-start-block-highlight-timer ()
3653 "Set up a one-shot timer if we are in MATLAB mode."
3654 (if (eq major-mode 'matlab-mode)
3655 (progn
3656 (if matlab-block-highlight-overlay
3657 (unwind-protect
3658 (matlab-delete-overlay matlab-block-highlight-overlay)
3659 (setq matlab-block-highlight-overlay nil)))
3660 (if matlab-block-highlight-timer
3661 (unwind-protect
3662 (matlab-cancel-timer matlab-block-highlight-timer)
3663 (setq matlab-block-highlight-timer nil)))
3664 (setq matlab-block-highlight-timer
3665 (matlab-run-with-idle-timer
3666 1 nil 'matlab-highlight-block-match
3667 (current-buffer))))))
3668
3669 (defun matlab-highlight-block-match (&optional buff-when-launched)
3670 "Highlight a matching block if available.
3671 BUFF-WHEN-LAUNCHED is the buffer that was active when the timer was set."
3672 (setq matlab-block-highlight-timer nil)
3673 (if (null buff-when-launched)
3674 ;; We were passed a null. This indicates an old version of XEmacs
3675 ;; so just turn the feature off
3676 (setq matlab-highlight-block-match-flag nil)
3677 ;; Only do neat stuff in the same buffer as the one we were
3678 ;; initialized from.
3679 (when (and buff-when-launched
3680 (eq buff-when-launched (current-buffer)))
3681 (let ((inhibit-quit nil) ;turn on G-g
3682 (matlab-scan-on-screen-only t))
3683 (if matlab-show-periodic-code-details-flag
3684 (matlab-show-line-info))
3685 (if (not (matlab-cursor-in-string-or-comment))
3686 (save-excursion
3687 (if (or (bolp)
3688 (looking-at "\\s-")
3689 (save-excursion (forward-char -1) (looking-at "\\s-")))
3690 nil
3691 (forward-word -1))
3692 (if (and (looking-at (concat (matlab-block-beg-re) "\\>"))
3693 (not (looking-at "function")))
3694 (progn
3695 ;; We scan forward...
3696 (matlab-forward-sexp)
3697 (backward-word 1)
3698 (if (not (looking-at matlab-block-end-pre-if))
3699 nil ;(message "Unterminated block, or end off screen.")
3700 (setq matlab-block-highlight-overlay
3701 (matlab-make-overlay (point)
3702 (progn (forward-word 1)
3703 (point))
3704 (current-buffer)))
3705 (matlab-overlay-put matlab-block-highlight-overlay
3706 'face 'matlab-region-face)))
3707 (if (and (looking-at (concat (matlab-block-end-pre) "\\>"))
3708 (not (looking-at "function"))
3709 (matlab-valid-end-construct-p))
3710 (progn
3711 ;; We scan backward
3712 (forward-word 1)
3713 (condition-case nil
3714 (progn
3715 (matlab-backward-sexp)
3716 (if (not (looking-at (matlab-block-beg-re)))
3717 nil ;(message "Unstarted block at cursor.")
3718 (setq matlab-block-highlight-overlay
3719 (matlab-make-overlay (point)
3720 (progn (forward-word 1)
3721 (point))
3722 (current-buffer)))
3723 (matlab-overlay-put matlab-block-highlight-overlay
3724 'face 'matlab-region-face)))
3725 (error (message "Unstarted block at cursor."))))
3726 ;; do nothing
3727 ))))))))
3728
3729
3730 ;;; M Block Folding with hideshow =============================================
3731
3732 (defun matlab-hideshow-forward-sexp-func (arg)
3733 "Move forward one sexp for hideshow.
3734 Argument ARG specifies the number of blocks to move forward."
3735 (beginning-of-line)
3736 (matlab-forward-sexp arg)
3737 )
3738
3739 (defun matlab-hideshow-adjust-beg-func (arg)
3740 "Adjust the beginning of a hideshow block.
3741 Argument ARG to make it happy."
3742 (end-of-line)
3743 (point)
3744 )
3745
3746 ;; Use this to enable hideshow in MATLAB.
3747 ;; It has not been tested by me enough.
3748
3749 ;; REMOVE PUSHNEW FROM THIS LINE
3750 ;;(pushnew (list 'matlab-mode
3751 ;; (matlab-block-beg-pre)
3752 ;; (matlab-block-end-pre)
3753 ;; "%"
3754 ;; 'matlab-hideshow-forward-sexp-func
3755 ;; 'matlab-hideshow-adjust-beg-func
3756 ;; )
3757 ;; hs-special-modes-alist :test 'equal)
3758
3759
3760 ;;; M Code verification & Auto-fix ============================================
3761
3762 (defun matlab-mode-verify-fix-file-fn ()
3763 "Verify the current buffer from `write-contents-hooks'."
3764 (if matlab-verify-on-save-flag
3765 (matlab-mode-verify-fix-file (> (point-max)
3766 matlab-block-verify-max-buffer-size)))
3767 ;; Always return nil.
3768 nil)
3769
3770 (defun matlab-mode-verify-fix-file (&optional fast)
3771 "Verify the current buffer satisfies all M things that might be useful.
3772 We will merely loop across a list of verifiers/fixers in
3773 `matlab-mode-verify-fix-functions'.
3774 If optional FAST is non-nil, do not perform usually lengthy checks."
3775 (interactive)
3776 (let ((p (point))
3777 (l matlab-mode-verify-fix-functions))
3778 (while l
3779 (funcall (car l) fast)
3780 (setq l (cdr l)))
3781 (goto-char p))
3782 (if (interactive-p)
3783 (message "Done.")))
3784
3785 (defun matlab-toggle-show-mlint-warnings ()
3786 "Toggle `matlab-show-mlint-warnings'."
3787 (interactive)
3788 (setq matlab-show-mlint-warnings (not matlab-show-mlint-warnings))
3789 (if matlab-highlight-cross-function-variables
3790 (if matlab-show-mlint-warnings
3791 (mlint-buffer) ; became true, recompute mlint info
3792 (mlint-clear-warnings)) ; became false, just remove hilighting
3793 (mlint-minor-mode))) ; change mlint mode altogether
3794
3795 (defun matlab-toggle-highlight-cross-function-variables ()
3796 "Toggle `matlab-highlight-cross-function-variables'."
3797 (interactive)
3798 (setq matlab-highlight-cross-function-variables
3799 (not matlab-highlight-cross-function-variables))
3800 (if matlab-show-mlint-warnings
3801 (if matlab-highlight-cross-function-variables
3802 (mlint-buffer) ; became true, recompute mlint info
3803 ; became false, just remove hilighting ...
3804 (mlint-clear-cross-function-variable-highlighting))
3805 (mlint-minor-mode))) ; change mlint mode altogether
3806
3807 ;;
3808 ;; Add more auto verify/fix functions here!
3809 ;;
3810 (defun matlab-mode-vf-functionname (&optional fast)
3811 "Verify/Fix the function name of this file.
3812 Optional argument FAST is ignored."
3813 (matlab-navigation-syntax
3814 (goto-char (point-min))
3815 (while (and (or (matlab-ltype-empty) (matlab-ltype-comm))
3816 (/= (matlab-point-at-eol) (point-max)))
3817 (forward-line 1))
3818 (let ((func nil)
3819 (bn (file-name-sans-extension
3820 (file-name-nondirectory (buffer-file-name)))))
3821 (if (looking-at (matlab-match-function-re))
3822 ;; The expression above creates too many numeric matches
3823 ;; to apply a known one to our function. We cheat by knowing that
3824 ;; match-end 0 is at the end of the function name. We can then go
3825 ;; backwards, and get the extents we need. Navigation syntax
3826 ;; lets us know that backward-word really covers the word.
3827 (let ((end (match-end 0))
3828 (begin (progn (goto-char (match-end 0))
3829 (forward-word -1)
3830 (point))))
3831 (setq func (buffer-substring begin end))
3832 (if (not (string= func bn))
3833 (if (not (matlab-mode-highlight-ask
3834 begin end
3835 "Function and file names are different. Fix?"))
3836 nil
3837 (goto-char begin)
3838 (delete-region begin end)
3839 (insert bn))))))))
3840
3841 (defun matlab-mode-vf-block-matches-forward (&optional fast)
3842 "Verify/Fix unterminated (or un-ended) blocks.
3843 This only checks block regions like if/end.
3844 Optional argument FAST causes this check to be skipped."
3845 (goto-char (point-min))
3846 (let ((go t)
3847 (expr (concat "\\<\\(" (matlab-block-beg-pre) "\\)\\>")))
3848 (matlab-navigation-syntax
3849 (while (and (not fast) go (re-search-forward expr nil t))
3850 (forward-word -1) ;back over the special word
3851 (let ((s (point)))
3852 (condition-case nil
3853 (if (and (not (matlab-cursor-in-string-or-comment))
3854 (not (looking-at "function")))
3855 (progn
3856 (matlab-forward-sexp)
3857 (forward-word -1)
3858 (if (not (looking-at
3859 (concat matlab-block-end-pre-no-if "\\>")))
3860 (setq go nil)))
3861 (forward-word 1))
3862 (error (setq go nil)))
3863 (if (and (not go) (goto-char s)
3864 (not (matlab-mode-highlight-ask
3865 (point) (save-excursion (forward-word 1) (point))
3866 "Unterminated block. Continue anyway?")))
3867 (error "Unterminated Block found!")))
3868 (message "Block-check: %d%%" (/ (/ (* 100 (point)) (point-max)) 2))))))
3869
3870 (defun matlab-mode-vf-block-matches-backward (&optional fast)
3871 "Verify/fix unstarted (or dangling end) blocks.
3872 Optional argument FAST causes this check to be skipped."
3873 (goto-char (point-max))
3874 (let ((go t) (expr (concat "\\<\\(" (matlab-block-end-no-function-re)
3875 "\\)\\>")))
3876 (matlab-navigation-syntax
3877 (while (and (not fast) go (re-search-backward expr nil t))
3878 (forward-word 1)
3879 (let ((s (point)))
3880 (condition-case nil
3881 (if (and (not (matlab-cursor-in-string-or-comment))
3882 (matlab-valid-end-construct-p))
3883 (matlab-backward-sexp)
3884 (backward-word 1))
3885 (error (setq go nil)))
3886 (if (and (not go) (goto-char s)
3887 (not (matlab-mode-highlight-ask
3888 (point) (save-excursion (backward-word 1) (point))
3889 "Unstarted block. Continue anyway?")))
3890 (error "Unstarted Block found!")))
3891 (message "Block-check: %d%%"
3892 (+ (/ (/ (* 100 (- (point-max) (point))) (point-max)) 2) 50))))))
3893
3894 ;;; Utility for verify/fix actions if you need to highlight
3895 ;; a section of the buffer for the user's approval.
3896 (defun matlab-mode-highlight-ask (begin end prompt)
3897 "Highlight from BEGIN to END while asking PROMPT as a yes-no question."
3898 (let ((mo (matlab-make-overlay begin end (current-buffer)))
3899 (ans nil))
3900 (condition-case nil
3901 (progn
3902 (matlab-overlay-put mo 'face 'matlab-region-face)
3903 (setq ans (y-or-n-p prompt))
3904 (matlab-delete-overlay mo))
3905 (quit (matlab-delete-overlay mo) (error "Quit")))
3906 ans))
3907
3908 ;;; Quiesce an M file to remove accidental display of ANS during a run.
3909 ;; Useful if you have random outputs and you don't know where they are from,
3910 ;; or before compiling to standalone where some functions now have outputs
3911 ;; that did not have outputs earlier.
3912 ;;
3913 ;; You probably don't want this as a default verify function
3914 (defvar matlab-quiesce-nosemi-regexp "\\s-*\\(function\\|parfor\\|for\\|spmd\\|while\\|try\\|catch\\|\
3915 switch\\|otherwise\\|case\\|break\\|if\\|else\\|end\\|return\\|disp\\|\
3916 $\\|%\\)"
3917 "Regular expression used to detect if a semicolon is needed at the end of a line.")
3918
3919 (defun matlab-mode-vf-quiesce-buffer (&optional fast)
3920 "Find all commands that do not end in ;, and add one.
3921 This has the effect of removing any extraneous output that may not be
3922 desired. Optional argument FAST is not used."
3923 (interactive)
3924 (save-excursion
3925 (push-mark)
3926 (goto-char (point-min))
3927 (let ((msgpos 0) (dir .2))
3928 (while (not (save-excursion (end-of-line) (eobp)))
3929 (message (aref [ "Scanning o...." "Scanning .o..." "Scanning ..o.."
3930 "Scanning ...o." "Scanning ....o" ] (floor msgpos)))
3931 (setq msgpos (+ msgpos dir))
3932 (if (or (> msgpos 5) (< msgpos 0)) (setq dir (- dir)
3933 msgpos (+ (* 2 dir) msgpos)))
3934 (matlab-end-of-command (point))
3935 (if (matlab-cursor-in-comment)
3936 (progn
3937 (matlab-comment-on-line)
3938 (skip-chars-backward " \t")))
3939 (if (and (not (= (preceding-char) ?\;))
3940 (not (matlab-cursor-in-string t))
3941 (not (save-excursion
3942 (beginning-of-line)
3943 (looking-at matlab-quiesce-nosemi-regexp))))
3944 (let ((p (point)))
3945 (skip-chars-backward " \t")
3946 (if (/= p (point))
3947 (progn
3948 (delete-region p (point))
3949 (forward-line -1))
3950 (if (matlab-mode-highlight-ask (point) (+ 1 (point))
3951 "Add Semi colon here? ")
3952 (insert ";")))))
3953 (forward-line 1))))
3954 (message "Scanning .... done"))
3955
3956
3957
3958 ;;; V19 stuff =================================================================
3959
3960 (defvar matlab-mode-menu-keymap nil
3961 "Keymap used in MATLAB mode to provide a menu.")
3962
3963 (defun matlab-frame-init ()
3964 "Initialize Emacs 19+ menu system."
3965 (interactive)
3966 ;; make a menu keymap
3967 (easy-menu-define
3968 matlab-mode-menu
3969 matlab-mode-map
3970 "MATLAB menu"
3971 '("MATLAB"
3972 ["Start MATLAB" matlab-shell (not (matlab-with-emacs-link)) ]
3973 ["Save and go" matlab-shell-save-and-go t]
3974 ["Run Region" matlab-shell-run-region t]
3975 ["Run Cell" matlab-shell-run-cell t]
3976 ["Version" matlab-show-version t]
3977 "----"
3978 ["Find M file" matlab-find-file-on-path t]
3979 ["Show M-Lint Warnings" matlab-toggle-show-mlint-warnings
3980 :active (and (locate-library "mlint") (fboundp 'mlint-minor-mode))
3981 :style toggle :selected matlab-show-mlint-warnings
3982 ]
3983 ("Auto Fix"
3984 ["Verify/Fix source" matlab-mode-verify-fix-file t]
3985 ["Spell check strings" matlab-ispell-strings t]
3986 ["Spell check comments" matlab-ispell-comments t]
3987 ["Quiesce source" matlab-mode-vf-quiesce-buffer t]
3988 )
3989 ("Navigate"
3990 ["Beginning of Command" matlab-beginning-of-command t]
3991 ["End of Command" matlab-end-of-command t]
3992 ["Forward Block" matlab-forward-sexp t]
3993 ["Backward Block" matlab-backward-sexp t]
3994 ["Beginning of Function" matlab-beginning-of-defun t]
3995 ["End of Function" matlab-end-of-defun t])
3996 ("Format"
3997 ["Justify Line" matlab-justify-line t]
3998 ["Fill Region" matlab-fill-region t]
3999 ["Fill Comment Paragraph" matlab-fill-paragraph
4000 (save-excursion (matlab-comment-on-line))]
4001 ["Join Comment" matlab-join-comment-lines
4002 (save-excursion (matlab-comment-on-line))]
4003 ["Comment Region" matlab-comment-region t]
4004 ["Uncomment Region" matlab-uncomment-region t]
4005 ["Indent Synactic Block" matlab-indent-sexp])
4006 ("Insert"
4007 ["Complete Symbol" matlab-complete-symbol t]
4008 ["Comment" matlab-comment t]
4009 ["if end" tempo-template-matlab-if t]
4010 ["if else end" tempo-template-matlab-if-else t]
4011 ["for end" tempo-template-matlab-for t]
4012 ["switch otherwise end" tempo-template-matlab-switch t]
4013 ["Next case" matlab-insert-next-case t]
4014 ["try catch end" tempo-template-matlab-try t]
4015 ["while end" tempo-template-matlab-while t]
4016 ["End of block" matlab-insert-end-block t]
4017 ["Function" tempo-template-matlab-function t]
4018 ["Stringify Region" matlab-stringify-region t]
4019 )
4020 ("Customize"
4021 ; ["Auto Fill Counts Elipsis"
4022 ; (lambda () (setq matlab-fill-count-ellipsis-flag
4023 ; (not matlab-fill-count-ellipsis-flag)))
4024 ; :style toggle :selected 'matlab-fill-count-ellipsis-flag]
4025 ["Indent Function Body"
4026 (setq matlab-indent-function-body (not matlab-indent-function-body))
4027 :style toggle :selected matlab-indent-function-body]
4028 ["Functions Have end"
4029 matlab-toggle-functions-have-end
4030 :style toggle :selected matlab-functions-have-end]
4031 ["Verify File on Save"
4032 (setq matlab-verify-on-save-flag (not matlab-verify-on-save-flag))
4033 :style toggle :selected matlab-verify-on-save-flag]
4034 ["Auto Fill does Code"
4035 (setq matlab-fill-code (not matlab-fill-code))
4036 :style toggle :selected matlab-fill-code ]
4037 ["Periodic Code Details"
4038 (setq matlab-show-periodic-code-details-flag
4039 (not matlab-show-periodic-code-details-flag))
4040 :style toggle :selected matlab-show-periodic-code-details-flag ]
4041 ["Highlight Matching Blocks"
4042 (matlab-enable-block-highlighting)
4043 :style toggle :selected (member 'matlab-start-block-highlight-timer
4044 post-command-hook) ]
4045 ["Highlight Cross-Function Variables"
4046 matlab-toggle-highlight-cross-function-variables
4047 :active (locate-library "mlint")
4048 :style toggle :selected matlab-highlight-cross-function-variables
4049 ]
4050 ["Add Needed Semicolon on RET"
4051 (setq matlab-return-add-semicolon (not matlab-return-add-semicolon))
4052 :style toggle :selected matlab-return-add-semicolon
4053 ]
4054 ["Customize" (customize-group 'matlab)
4055 (and (featurep 'custom) (fboundp 'custom-declare-variable))
4056 ]
4057 )
4058 "----"
4059 ["Run M Command" matlab-shell-run-command (matlab-shell-active-p)]
4060 ["Describe Command" matlab-shell-describe-command (matlab-shell-active-p)]
4061 ["Describe Variable" matlab-shell-describe-variable (matlab-shell-active-p)]
4062 ["Command Apropos" matlab-shell-apropos (matlab-shell-active-p)]
4063 ["Topic Browser" matlab-shell-topic-browser (matlab-shell-active-p)]
4064 ))
4065 (easy-menu-add matlab-mode-menu matlab-mode-map))
4066
4067 ;;; MATLAB shell =============================================================
4068
4069 (defgroup matlab-shell nil
4070 "MATLAB shell mode."
4071 :prefix "matlab-shell-"
4072 :group 'matlab)
4073
4074 (defcustom matlab-shell-command "matlab"
4075 "*The name of the command to be run which will start the MATLAB process."
4076 :group 'matlab-shell
4077 :type 'string)
4078
4079 (defcustom matlab-shell-command-switches '("-nodesktop")
4080 "*Command line parameters run with `matlab-shell-command'.
4081 Command switches are a list of strings. Each entry is one switch."
4082 :group 'matlab-shell
4083 :type '(list :tag "Switch: "))
4084
4085 (defcustom matlab-shell-echoes t
4086 "*If `matlab-shell-command' echoes input."
4087 :group 'matlab-shell
4088 :type 'boolean)
4089
4090 (defvar matlab-shell-running-matlab-version nil
4091 "The version of MATLAB running in the current `matlab-shell' buffer.")
4092 (defvar matlab-shell-running-matlab-release nil
4093 "The release of MATLAB running in the curbrent `matlab-shell' buffer.")
4094 (defvar matlab-shell-use-emacs-toolbox
4095 (let ((dir (expand-file-name "toolbox/emacsinit.m"
4096 (file-name-directory (locate-library "matlab")))))
4097 (file-exists-p dir))
4098 "Add the `matlab-shell' MATLAB toolbox to the MATLAB path on startup.")
4099 (defvar matlab-shell-emacsclient-command "emacsclient -n"
4100 "The command to use as an external editor for MATLAB.
4101 Using emacsclient allows the currently running Emacs to also be the
4102 external editor for MATLAB.")
4103
4104 (defcustom matlab-shell-history-file "~/.matlab/%s/history.m"
4105 "*Location of the history file.
4106 A %s is replaced with the MATLAB version release number, such as R12.
4107 This file is read to initialize the comint input ring.")
4108
4109 (defcustom matlab-shell-input-ring-size 32
4110 "*Number of history elements to keep."
4111 :group 'matlab-shell
4112 :type 'integer)
4113
4114 (defcustom matlab-shell-enable-gud-flag t
4115 "*Non-nil means to use GUD mode when running the MATLAB shell."
4116 :group 'matlab-shell
4117 :type 'boolean)
4118
4119 (defcustom matlab-shell-mode-hook nil
4120 "*List of functions to call on entry to MATLAB shell mode."
4121 :group 'matlab-shell
4122 :type 'hook)
4123
4124 (defcustom matlab-shell-ask-MATLAB-for-completions t
4125 "When Non-nil, ask MATLAB for a completion list.
4126 When nil, just complete file names. (The original behavior.)
4127 At this time, MATLAB based completion can be slow if there are
4128 a lot of possible answers."
4129 :group 'matlab-shell
4130 :type 'boolean)
4131
4132 (defvar matlab-shell-buffer-name "MATLAB"
4133 "Name used to create `matlab-shell' mode buffers.
4134 This name will have *'s surrounding it.")
4135
4136 (defun matlab-shell-active-p ()
4137 "Return t if the MATLAB shell is active."
4138 (if (get-buffer (concat "*" matlab-shell-buffer-name "*"))
4139 (save-excursion
4140 (set-buffer (concat "*" matlab-shell-buffer-name "*"))
4141 (if (comint-check-proc (current-buffer))
4142 (current-buffer)))))
4143
4144 (defvar matlab-shell-mode-map ()
4145 "Keymap used in `matlab-shell-mode'.")
4146
4147 (defvar matlab-shell-font-lock-keywords-1
4148 (append matlab-font-lock-keywords matlab-shell-font-lock-keywords)
4149 "Keyword symbol used for font-lock mode.")
4150
4151 (defvar matlab-shell-font-lock-keywords-2
4152 (append matlab-shell-font-lock-keywords-1 matlab-gaudy-font-lock-keywords)
4153 "Keyword symbol used for gaudy font-lock symbols.")
4154
4155 (defvar matlab-shell-font-lock-keywords-3
4156 (append matlab-shell-font-lock-keywords-2
4157 matlab-really-gaudy-font-lock-keywords)
4158 "Keyword symbol used for really gaudy font-lock symbols.")
4159
4160 (defvar matlab-prompt-seen nil
4161 "Track visibility of MATLAB prompt in MATLAB Shell.")
4162
4163 (eval-when-compile (require 'gud) (require 'comint) (require 'shell))
4164
4165 ;;;###autoload
4166 (defun matlab-shell ()
4167 "Create a buffer with MATLAB running as a subprocess.
4168
4169 MATLAB shell cannot work on the MS Windows platform because MATLAB is not
4170 a console application."
4171 (interactive)
4172 ;; MATLAB shell does not work by default on the Windows platform. Only
4173 ;; permit it's operation when the shell command string is different from
4174 ;; the default value. (True when the engine program is running.)
4175 (if (and (or (eq window-system 'pc) (eq window-system 'w32))
4176 (string= matlab-shell-command "matlab"))
4177 (error "MATLAB cannot be run as a inferior process. \
4178 Try C-h f matlab-shell RET"))
4179
4180 (require 'shell)
4181 (require 'gud)
4182
4183 ;; Make sure this is safe...
4184 (if (and matlab-shell-enable-gud-flag (fboundp 'gud-def))
4185 ;; We can continue using GUD
4186 nil
4187 (message "Sorry, your emacs cannot use the MATLAB Shell GUD features.")
4188 (setq matlab-shell-enable-gud-flag nil))
4189
4190 (switch-to-buffer (concat "*" matlab-shell-buffer-name "*"))
4191 (if (matlab-shell-active-p)
4192 nil
4193 ;; Clean up crufty state
4194 (kill-all-local-variables)
4195 ;; Build keymap here in case someone never uses comint mode
4196 (if matlab-shell-mode-map
4197 ()
4198 (setq matlab-shell-mode-map
4199 (let ((km (make-sparse-keymap 'matlab-shell-mode-map)))
4200 (if (fboundp 'set-keymap-parent)
4201 (set-keymap-parent km comint-mode-map)
4202 ;; 19.31 doesn't have set-keymap-parent
4203 (setq km (nconc km comint-mode-map)))
4204 (substitute-key-definition 'next-error 'matlab-shell-last-error
4205 km global-map)
4206 (define-key km [(control h) (control m)]
4207 matlab-help-map)
4208 (define-key km "\C-c." 'matlab-find-file-on-path)
4209 (define-key km [(tab)] 'matlab-shell-tab)
4210 (define-key km [(control up)]
4211 'comint-previous-matching-input-from-input)
4212 (define-key km [(control down)]
4213 'comint-next-matching-input-from-input)
4214 (define-key km [up]
4215 'matlab-shell-previous-matching-input-from-input)
4216 (define-key km [down]
4217 'matlab-shell-next-matching-input-from-input)
4218 (define-key km [(control return)] 'comint-kill-input)
4219 (define-key km "\C-?"
4220 'matlab-shell-delete-backwards-no-prompt)
4221 (define-key km [(backspace)]
4222 'matlab-shell-delete-backwards-no-prompt)
4223 km)))
4224 (switch-to-buffer
4225 (apply 'make-comint matlab-shell-buffer-name matlab-shell-command
4226 nil matlab-shell-command-switches))
4227
4228 (setq shell-dirtrackp t)
4229 (comint-mode)
4230
4231 (if matlab-shell-enable-gud-flag
4232 (progn
4233 (gud-mode)
4234 (make-local-variable 'matlab-prompt-seen)
4235 (setq matlab-prompt-seen nil)
4236 (make-local-variable 'gud-marker-filter)
4237 (setq gud-marker-filter 'gud-matlab-marker-filter)
4238 (make-local-variable 'gud-find-file)
4239 (setq gud-find-file 'gud-matlab-find-file)
4240
4241 (set-process-filter (get-buffer-process (current-buffer))
4242 'gud-filter)
4243 (set-process-sentinel (get-buffer-process (current-buffer))
4244 'gud-sentinel)
4245 (gud-set-buffer))
4246 ;; What to do when there is no GUD
4247 ;(set-process-filter (get-buffer-process (current-buffer))
4248 ; 'matlab-shell-process-filter)
4249 )
4250
4251 ;; Comint and GUD both try to set the mode. Now reset it to
4252 ;; matlab mode.
4253 (matlab-shell-mode)))
4254
4255 (defcustom matlab-shell-logo
4256 (if (fboundp 'locate-data-file)
4257 ;; Starting from XEmacs 20.4 use locate-data-file
4258 (locate-data-file "matlab.xpm")
4259 (expand-file-name "matlab.xpm" data-directory))
4260 "*The MATLAB logo file."
4261 :group 'matlab-shell
4262 :type '(choice (const :tag "None" nil)
4263 (file :tag "File" "")))
4264
4265
4266 (defun matlab-shell-hack-logo (str)
4267 "Replace the text logo with a real logo.
4268 STR is passed from the commint filter."
4269 (when (string-match "< M A T L A B >" str)
4270 (save-excursion
4271 (when (re-search-backward "^[ \t]+< M A T L A B (R) >" (point-min) t)
4272 (delete-region (match-beginning 0) (match-end 0))
4273 (insert (make-string 16 ? ))
4274 (set-extent-begin-glyph (make-extent (point) (point))
4275 (make-glyph matlab-shell-logo))))
4276 ;; Remove this function from `comint-output-filter-functions'
4277 (remove-hook 'comint-output-filter-functions
4278 'matlab-shell-hack-logo))
4279
4280 )
4281
4282 (defun matlab-shell-version-scrape (str)
4283 "Scrape the MATLAB Version from the MATLAB startup text.
4284 Argument STR is the string to examine for version information."
4285 (when (string-match "\\(Version\\)\\s-+\\([.0-9]+\\)\\s-+(\\(R[.0-9]+[ab]?\\))" str)
4286 ;; Extract the release number
4287 (setq matlab-shell-running-matlab-version
4288 (match-string 2 str)
4289 matlab-shell-running-matlab-release
4290 (match-string 3 str))
4291 ;; Now get our history loaded
4292 (setq comint-input-ring-file-name
4293 (format matlab-shell-history-file matlab-shell-running-matlab-release))
4294 (if (fboundp 'comint-read-input-ring)
4295 (comint-read-input-ring t))
4296 ;; Remove the scrape from our list of things to do.
4297 (remove-hook 'comint-output-filter-functions
4298 'matlab-shell-version-scrape)))
4299
4300 (defun matlab-shell-mode ()
4301 "Run MATLAB as a subprocess in an Emacs buffer.
4302
4303 This mode will allow standard Emacs shell commands/completion to occur
4304 with MATLAB running as an inferior process. Additionally, this shell
4305 mode is integrated with `matlab-mode', a major mode for editing M
4306 code.
4307
4308 > From an M file buffer:
4309 \\<matlab-mode-map>
4310 \\[matlab-shell-save-and-go] - Save the current M file, and run it in a \
4311 MATLAB shell.
4312
4313 > From Shell mode:
4314 \\<matlab-shell-mode-map>
4315 \\[matlab-shell-last-error] - find location of last MATLAB runtime error \
4316 in the offending M file.
4317
4318 > From an M file, or from Shell mode:
4319 \\<matlab-mode-map>
4320 \\[matlab-shell-run-command] - Run COMMAND and show result in a popup buffer.
4321 \\[matlab-shell-describe-variable] - Show variable contents in a popup buffer.
4322 \\[matlab-shell-describe-command] - Show online documentation for a command \
4323 in a popup buffer.
4324 \\[matlab-shell-apropos] - Show output from LOOKFOR command in a popup buffer.
4325 \\[matlab-shell-topic-browser] - Topic browser using HELP.
4326
4327 > Keymap:
4328 \\{matlab-mode-map}"
4329 (setq major-mode 'matlab-shell-mode
4330 mode-name "M-Shell"
4331 comint-prompt-regexp "^\\(K\\|EDU\\)?>> *"
4332 comint-delimiter-argument-list (list [ 59 ]) ; semi colon
4333 comint-dynamic-complete-functions '(comint-replace-by-expanded-history)
4334 comint-process-echoes matlab-shell-echoes
4335 )
4336 (require 'shell)
4337 (if (fboundp 'shell-directory-tracker)
4338 (add-hook 'comint-input-filter-functions 'shell-directory-tracker))
4339 ;; Add a spiffy logo if we are running XEmacs
4340 (if (and (string-match "XEmacs" emacs-version)
4341 (stringp matlab-shell-logo)
4342 (file-readable-p matlab-shell-logo))
4343 (add-hook 'comint-output-filter-functions 'matlab-shell-hack-logo))
4344 ;; Add a version scraping logo identification filter.
4345 (add-hook 'comint-output-filter-functions 'matlab-shell-version-scrape)
4346 ;; Add pseudo html-renderer
4347 (add-hook 'comint-output-filter-functions 'matlab-shell-render-html-anchor nil t)
4348 (add-hook 'comint-output-filter-functions 'matlab-shell-render-errors-as-anchor nil t)
4349
4350 (make-local-variable 'comment-start)
4351 (setq comment-start "%")
4352 (use-local-map matlab-shell-mode-map)
4353 (set-syntax-table matlab-mode-syntax-table)
4354 (make-local-variable 'font-lock-defaults)
4355 (setq font-lock-defaults '((matlab-shell-font-lock-keywords-1
4356 matlab-shell-font-lock-keywords-2
4357 matlab-shell-font-lock-keywords-3)
4358 t nil ((?_ . "w"))))
4359 (set (make-local-variable 'comint-input-ring-size)
4360 matlab-shell-input-ring-size)
4361 (set (make-local-variable 'comint-input-ring-file-name)
4362 (format matlab-shell-history-file "R12"))
4363 (if (fboundp 'comint-read-input-ring)
4364 (comint-read-input-ring t))
4365 (make-local-variable 'gud-marker-acc)
4366 (easy-menu-define
4367 matlab-shell-menu
4368 matlab-shell-mode-map
4369 "MATLAB shell menu"
4370 '("MATLAB"
4371 ["Goto last error" matlab-shell-last-error t]
4372 "----"
4373 ["Stop On Errors" matlab-shell-dbstop-error t]
4374 ["Don't Stop On Errors" matlab-shell-dbclear-error t]
4375 "----"
4376 ["Run Command" matlab-shell-run-command t]
4377 ["Describe Variable" matlab-shell-describe-variable t]
4378 ["Describe Command" matlab-shell-describe-command t]
4379 ["Lookfor Command" matlab-shell-apropos t]
4380 ["Topic Browser" matlab-shell-topic-browser t]
4381 "----"
4382 ["Demos" matlab-shell-demos t]
4383 ["Close Current Figure" matlab-shell-close-current-figure t]
4384 ["Close Figures" matlab-shell-close-figures t]
4385 "----"
4386 ["Customize" (customize-group 'matlab-shell)
4387 (and (featurep 'custom) (fboundp 'custom-declare-variable))
4388 ]
4389 ["Exit" matlab-shell-exit t]))
4390 (easy-menu-add matlab-shell-menu matlab-shell-mode-map)
4391
4392 (if matlab-shell-enable-gud-flag
4393 (progn
4394 (gud-def gud-break "dbstop at %l in %f" "\C-b" "Set breakpoint at current line.")
4395 (gud-def gud-remove "dbclear at %l in %f" "\C-d" "Remove breakpoint at current line")
4396 (gud-def gud-step "dbstep in" "\C-s" "Step one source line, possibly into a function.")
4397 (gud-def gud-next "dbstep %p" "\C-n" "Step over one source line.")
4398 (gud-def gud-cont "dbcont" "\C-r" "Continue with display.")
4399 (gud-def gud-finish "dbquit" "\C-f" "Finish executing current function.")
4400 (gud-def gud-up "dbup %p" "<" "Up N stack frames (numeric arg).")
4401 (gud-def gud-down "dbdown %p" ">" "Down N stack frames (numeric arg).")
4402 (gud-def gud-print "%e" "\C-p" "Evaluate M expression at point.")
4403 (if (fboundp 'gud-make-debug-menu)
4404 (gud-make-debug-menu))
4405 (if (fboundp 'gud-overload-functions)
4406 (gud-overload-functions
4407 '((gud-massage-args . gud-matlab-massage-args)
4408 (gud-marker-filter . gud-matlab-marker-filter)
4409 (gud-find-file . gud-matlab-find-file))))
4410 ;; XEmacs doesn't seem to have this concept already. Oh well.
4411 (setq gud-marker-acc nil)
4412 ;; XEmacs has problems w/ this variable. Set it here.
4413 (set-marker comint-last-output-start (point-max))
4414 ))
4415 (run-hooks 'matlab-shell-mode-hook)
4416 (matlab-show-version)
4417 )
4418
4419 (defvar gud-matlab-marker-regexp-prefix "error:\\|opentoline"
4420 "A prefix to scan for to know if output might be scarfed later.")
4421
4422 ;; The regular expression covers the following form:
4423 ;; Errors: Error in ==> <filename>
4424 ;; On line # ==> <command_name>
4425 ;; Syntax: Syntax error in ==> <filename>
4426 ;; On line # ==> <sample-text>
4427 ;; Warning: In <filename> at line # <stuff>
4428 (defvar gud-matlab-error-regexp
4429 (concat "\\(Error in ==>\\|Syntax error in ==>\\|In\\) "
4430 "\\([-@.a-zA-Z_0-9/ \\\\:]+\\).*[\n ][Oa][nt]\\(?: line\\)? "
4431 "\\([0-9]+\\) ?")
4432 "Regular expression finding where an error occurred.")
4433
4434 (defvar matlab-shell-html-map (make-sparse-keymap))
4435 (if (string-match "XEmacs" emacs-version)
4436 (define-key matlab-shell-html-map [button2] 'matlab-shell-html-click)
4437 (define-key matlab-shell-html-map [mouse-2] 'matlab-shell-html-click))
4438
4439 (defvar matlab-anchor-beg "<a href=\"\\([^\"]+\\)\">"
4440 "Beginning of html anchor.")
4441
4442 (defvar matlab-anchor-end "</a>"
4443 "End of html anchor.")
4444
4445 (defun matlab-shell-render-html-anchor (str)
4446 "Render html anchors inserted into the MATLAB shell buffer.
4447 Argument STR is the text for the anchor."
4448 (if (string-match matlab-anchor-end str)
4449 (save-excursion
4450 (while (re-search-backward matlab-anchor-beg nil t)
4451 (let* ((anchor-beg-start (match-beginning 0))
4452 (anchor-beg-finish (match-end 0))
4453 (anchor-text (match-string 1))
4454 (anchor-end-finish (search-forward matlab-anchor-end))
4455 (anchor-end-start (match-beginning 0))
4456 (o (matlab-make-overlay anchor-beg-finish anchor-end-start)))
4457 (matlab-overlay-put o 'mouse-face 'highlight)
4458 (matlab-overlay-put o 'face 'underline)
4459 (matlab-overlay-put o 'matlab-url anchor-text)
4460 (matlab-overlay-put o 'keymap matlab-shell-html-map)
4461 (delete-region anchor-end-start anchor-end-finish)
4462 (delete-region anchor-beg-start anchor-beg-finish)
4463 ))))
4464 )
4465
4466 (defvar matlab-shell-error-stack-start "^{\\?\\?\\?\\s-"
4467 "Regexp for the start of a stack from an error.
4468 These error stacks are for MATLAB version R2009a or so.
4469 Disable this if anchors are ever supported.")
4470
4471 (defvar matlab-shell-error-stack-end "^}\\s-*$"
4472 "Regexp for the start of a stack from an error.
4473 These error stacks are for MATLAB version R2009a or so.
4474 Disable this if anchors are ever supported.")
4475
4476 (defun matlab-shell-render-errors-as-anchor (str)
4477 "Detect non-url errors, and treat them as if they were url anchors.
4478 Argument STR is the text that might have errors in it."
4479 (when (string-match matlab-shell-error-stack-end str)
4480 (save-excursion
4481 (when (re-search-backward matlab-shell-error-stack-start nil t)
4482 (let ((groupend nil)
4483 (first nil))
4484 (save-excursion
4485 (setq groupend (re-search-forward matlab-shell-error-stack-end))
4486 )
4487 ;; We have found an error stack to investigate.
4488 (while (re-search-forward gud-matlab-error-regexp nil t)
4489 (let* ((err-start (match-beginning 0))
4490 (err-end (match-end 0))
4491 (err-text (match-string 0))
4492 (err-file (match-string 2))
4493 (err-line (match-string 3))
4494 (o (matlab-make-overlay err-start err-end))
4495 (url (concat "opentoline('" err-file "'," err-line ",0)"))
4496 )
4497 (matlab-overlay-put o 'mouse-face 'highlight)
4498 (matlab-overlay-put o 'face 'underline)
4499 ;; The url will recycle opentoline code.
4500 (matlab-overlay-put o 'matlab-url url)
4501 (matlab-overlay-put o 'keymap matlab-shell-html-map)
4502 ;; Keep track of the very first error in this error stack.
4503 ;; It will represent the "place to go" for "go-to-last-error".
4504 (matlab-overlay-put o 'first-in-error-stack first)
4505 (when (not first) (setq first url))
4506 ))
4507
4508 )))))
4509
4510 (defvar gud-matlab-marker-regexp-1 "^K>>"
4511 "Regular expression for finding a file line-number.")
4512
4513 (defvar gud-matlab-marker-regexp-2
4514 (concat "^> In \\(" matlab-anchor-beg
4515 "\\|\\)\\([-.a-zA-Z0-9_>/@]+\\) \\((\\w+) \\|\\)at line \\([0-9]+\\)[ \n]+")
4516 "Regular expression for finding a file line-number.
4517 Please note: The leading > character represents the current stack frame, so if
4518 there are several frames, this makes sure we pick the right one to popup.")
4519
4520 (defun gud-matlab-massage-args (file args)
4521 "Argument massager for starting matlab file.
4522 I don't think I have to do anything, but I'm not sure.
4523 FILE is ignored, and ARGS is returned."
4524 args)
4525
4526 (defun gud-matlab-marker-filter (string)
4527 "Filters STRING for the Unified Debugger based on MATLAB output."
4528 (if matlab-prompt-seen
4529 nil
4530 (when (string-match ">> " string)
4531 (if matlab-shell-use-emacs-toolbox
4532 ;; Use our local toolbox directory.
4533 (process-send-string
4534 (get-buffer-process gud-comint-buffer)
4535 (format "addpath('%s','-begin'); rehash; emacsinit('%s');\n"
4536 (expand-file-name "toolbox"
4537 (file-name-directory
4538 (locate-library "matlab")))
4539 matlab-shell-emacsclient-command))
4540 ;; User doesn't want to use our fancy toolbox directory
4541 (process-send-string
4542 (get-buffer-process gud-comint-buffer)
4543 "if usejava('jvm'), \
4544 com.mathworks.services.Prefs.setBooleanPref('EditorGraphicalDebugging', false); \
4545 end\n"
4546 ))
4547 ;; Mark that we've seen at least one prompt.
4548 (setq matlab-prompt-seen t)
4549 ))
4550 (let ((garbage (concat "\\(" (regexp-quote "\C-g") "\\|"
4551 (regexp-quote "\C-h") "\\|"
4552 (regexp-quote "\033[H0") "\\|"
4553 (regexp-quote "\033[H\033[2J") "\\|"
4554 (regexp-quote "\033H\033[2J") "\\)")))
4555 (while (string-match garbage string)
4556 (if (= (aref string (match-beginning 0)) ?\C-g)
4557 (beep t))
4558 (setq string (replace-match "" t t string))))
4559 (setq gud-marker-acc (concat gud-marker-acc string))
4560 (let ((output "") (frame nil))
4561
4562 (when (not frame)
4563 (when (string-match gud-matlab-marker-regexp-1 gud-marker-acc)
4564 (when (not frame)
4565 ;; If there is a debug prompt, and no frame currently set,
4566 ;; go find one.
4567 (let ((url gud-marker-acc)
4568 ef el)
4569 (cond
4570 ((string-match "^error:\\(.*\\),\\([0-9]+\\),\\([0-9]+\\)$" url)
4571 (setq ef (substring url (match-beginning 1) (match-end 1))
4572 el (substring url (match-beginning 2) (match-end 2)))
4573 )
4574 ((string-match "opentoline('\\([^']+\\)',\\([0-9]+\\),\\([0-9]+\\))" url)
4575 (setq ef (substring url (match-beginning 1) (match-end 1))
4576 el (substring url (match-beginning 2) (match-end 2)))
4577 )
4578 )
4579 (when ef
4580 (setq frame (cons ef (string-to-number el)))))))
4581 )
4582
4583 (if (and (not frame)
4584 (string-match gud-matlab-marker-regexp-prefix gud-marker-acc)
4585 (not (string-match "^K?>>" gud-marker-acc))
4586 )
4587 ;; We could be collecting something. Wait for a while.
4588 nil
4589 ;; Finish off this part of the output. None of our special stuff
4590 ;; ends with a \n, so display those as they show up...
4591 (while (string-match "^[^\n]*\n" gud-marker-acc)
4592 (setq output (concat output (substring gud-marker-acc 0 (match-end 0)))
4593 gud-marker-acc (substring gud-marker-acc (match-end 0))))
4594
4595 (setq output (concat output gud-marker-acc)
4596 gud-marker-acc "")
4597 ;; Check our output for a prompt, and existence of a frame.
4598 ;; If t his is true, throw out the debug arrow stuff.
4599 (if (and (string-match "^>> $" output)
4600 gud-last-last-frame)
4601 (progn
4602 (setq overlay-arrow-position nil
4603 gud-last-last-frame nil
4604 gud-overlay-arrow-position nil)
4605 (sit-for 0)
4606 )))
4607
4608 (if frame (setq gud-last-frame frame))
4609
4610 ;;(message "[%s] [%s]" output gud-marker-acc)
4611
4612 output))
4613
4614 (defun gud-matlab-find-file (f)
4615 "Find file F when debugging frames in MATLAB."
4616 (save-excursion
4617 (let* ((realfname (if (string-match "\\.\\(p\\)$" f)
4618 (progn
4619 (aset f (match-beginning 1) ?m)
4620 f)
4621 f))
4622 (buf (find-file-noselect realfname)))
4623 (set-buffer buf)
4624 (if (fboundp 'gud-make-debug-menu)
4625 (gud-make-debug-menu))
4626 buf)))
4627
4628 (defun matlab-shell-next-matching-input-from-input (n)
4629 "Get the Nth next matching input from for the command line."
4630 (interactive "p")
4631 (matlab-shell-previous-matching-input-from-input (- n)))
4632
4633 (defun matlab-shell-previous-matching-input-from-input (n)
4634 "Get the Nth previous matching input from for the command line."
4635 (interactive "p")
4636 (if (comint-after-pmark-p)
4637 (if (memq last-command '(matlab-shell-previous-matching-input-from-input
4638 matlab-shell-next-matching-input-from-input))
4639 ;; This hack keeps the cycling working well.
4640 (let ((last-command 'comint-previous-matching-input-from-input))
4641 (comint-next-matching-input-from-input (- n)))
4642 ;; first time.
4643 (comint-next-matching-input-from-input (- n)))
4644
4645 ;; If somewhere else, just move around.
4646 (previous-line n)))
4647
4648 (defun matlab-shell-delete-backwards-no-prompt (&optional arg)
4649 "Delete one char backwards without destroying the matlab prompt.
4650 Optional argument ARG describes the number of chars to delete."
4651 (interactive "P")
4652 (let ((promptend (save-excursion
4653 (beginning-of-line)
4654 (if (looking-at "K?>> ")
4655 (match-end 0)
4656 (point))))
4657 (numchars (if (integerp arg) (- arg) -1)))
4658 (if (<= promptend (+ (point) numchars))
4659 (delete-char numchars)
4660 (error "Beginning of line"))))
4661
4662 (defun matlab-shell-completion-list (str)
4663 "Get a list of completions from MATLAB.
4664 STR is a substring to complete."
4665 (save-excursion
4666 (let* ((msbn (matlab-shell-buffer-barf-not-running))
4667 (cmd (concat "matlabMCRprocess = com.mathworks.jmi.MatlabMCR\n"
4668 "matlabMCRprocess.mtFindAllTabCompletions('"
4669 str "'), clear('matlabMCRprocess');"))
4670 (comint-scroll-show-maximum-output nil)
4671 output
4672 (completions nil))
4673 (set-buffer msbn)
4674 (if (not (matlab-on-prompt-p))
4675 (error "MATLAB shell must be non-busy to do that"))
4676 (setq output (matlab-shell-collect-command-output cmd))
4677 ;; Debug
4678 (string-match "ans =" output)
4679 (setq output (substring output (match-end 0)))
4680 ;; Parse the output string.
4681 (while (string-match "'" output)
4682 ;; Hack off the preceeding quote
4683 (setq output (substring output (match-end 0)))
4684 (string-match "'" output)
4685 ;; we are making a completion list, so that is a list of lists.
4686 (setq completions (cons (list (substring output 0 (match-beginning 0)))
4687 completions)
4688 output (substring output (match-end 0))))
4689 ;; Return them
4690 (nreverse completions))))
4691
4692 (defun matlab-shell-which-fcn (fcn)
4693 "Get the location of FCN's M file.
4694 Returns an alist: ( LOCATION . BUILTINFLAG )
4695 LOCATION is a string indicating where it is, and BUILTINFLAG is
4696 non-nil if FCN is a builtin."
4697 (save-excursion
4698 (let* ((msbn (matlab-shell-buffer-barf-not-running))
4699 (cmd (concat "which " fcn))
4700 (comint-scroll-show-maximum-output nil)
4701 output
4702 builtin
4703 )
4704 (set-buffer msbn)
4705 (if (not (matlab-on-prompt-p))
4706 (error "MATLAB shell must be non-busy to do that"))
4707 (setq output (matlab-shell-collect-command-output cmd))
4708 ;; BUILT-IN
4709 (cond
4710 ((string-match "built-in (\\([^)]+\\))" output)
4711 (cons (concat (substring output (match-beginning 1) (match-end 1))
4712 ".m")
4713 t))
4714 ;; Error
4715 ((string-match "not found" output)
4716 nil)
4717 ;; JUST AN M FILE
4718 (t
4719 (string-match "$" output)
4720 (cons (substring output 0 (match-beginning 0)) nil))))))
4721
4722 (defun matlab-shell-matlabroot ()
4723 "Get the location of of this shell's root.
4724 Returns a string path to the root of the executing MATLAB."
4725 (save-excursion
4726 (let* ((msbn (matlab-shell-buffer-barf-not-running))
4727 (cmd "disp(matlabroot)")
4728 (comint-scroll-show-maximum-output nil)
4729 output
4730 builtin
4731 )
4732 (set-buffer msbn)
4733
4734 (if (and (boundp 'matlab-shell-matlabroot-run)
4735 matlab-shell-matlabroot-run)
4736 matlab-shell-matlabroot-run
4737 ;; If we haven't cache'd it, calculate it now.
4738
4739 (if (not (matlab-on-prompt-p))
4740 (error "MATLAB shell must be non-busy to do that"))
4741 (setq output (matlab-shell-collect-command-output cmd))
4742
4743 (string-match "$" output)
4744 (substring output 0 (match-beginning 0))))))
4745
4746
4747 (defun matlab-shell-tab ()
4748 "Send [TAB] to the currently running matlab process and retrieve completion."
4749 (interactive)
4750 (if (not matlab-shell-ask-MATLAB-for-completions)
4751 (call-interactively 'comint-dynamic-complete-filename)
4752 (if (not (matlab-on-prompt-p))
4753 (error "Completions not available"))
4754 (if nil
4755 ;; For older versions of MATLAB that don't have TAB
4756 ;; completion.
4757 (call-interactively 'comint-dynamic-complete-filename)
4758 ;; Save the old command
4759 (goto-char (point-max))
4760 (let ((inhibit-field-text-motion t))
4761 (beginning-of-line))
4762 (re-search-forward comint-prompt-regexp)
4763 (let* ((lastcmd (buffer-substring (point) (matlab-point-at-eol)))
4764 (tempcmd lastcmd)
4765 (completions nil)
4766 (limitpos nil))
4767 ;; search for character which limits completion, and limit command to it
4768 (setq limitpos
4769 (if (string-match ".*\\([( /[,;=']\\)" lastcmd)
4770 (1+ (match-beginning 1))
4771 0))
4772 (setq lastcmd (substring lastcmd limitpos))
4773 ;; Whack the old command so we can insert it back later.
4774 (delete-region (+ (point) limitpos) (matlab-point-at-eol))
4775 ;; double every single quote
4776 (while (string-match "[^']\\('\\)\\($\\|[^']\\)" tempcmd)
4777 (setq tempcmd (replace-match "''" t t tempcmd 1)))
4778 ;; collect the list
4779 (setq completions (matlab-shell-completion-list tempcmd))
4780 (goto-char (point-max))
4781 (if (eq (length completions) 1)
4782 ;; If there is only one, then there is an obvious thing to do.
4783 (progn
4784 (insert (car (car completions)))
4785 ;; kill completions buffer if still visible
4786 (when (get-buffer "*Completions*")
4787 (delete-windows-on "*Completions*")))
4788 (let ((try (try-completion lastcmd completions)))
4789 ;; Insert in a good completion.
4790 (cond ((or (eq try nil) (eq try t)
4791 (and (stringp try)
4792 (string= try lastcmd)))
4793 (insert lastcmd)
4794 (with-output-to-temp-buffer "*Completions*"
4795 (display-completion-list (mapcar 'car completions) lastcmd)))
4796 ((stringp try)
4797 (insert try)
4798 (when (get-buffer "*Completions*")
4799 (delete-windows-on "*Completions*")))
4800 (t
4801 (insert lastcmd))))
4802 )))))
4803
4804
4805 ;;; MATLAB mode Shell commands ================================================
4806
4807 (defun matlab-show-matlab-shell-buffer ()
4808 "Switch to the buffer containing the matlab process."
4809 (interactive)
4810 (let ((msbn (concat "*" matlab-shell-buffer-name "*")))
4811 (if (get-buffer msbn)
4812 (switch-to-buffer-other-window msbn)
4813 (message "There is not an active MATLAB process."))))
4814
4815 (defvar matlab-shell-save-and-go-history '("()")
4816 "Keep track of parameters passed to the MATLAB shell.")
4817
4818 (defun matlab-shell-add-to-input-history (string)
4819 "Add STRING to the input-ring and run `comint-input-filter-functions' on it.
4820 Similar to `comint-send-input'."
4821 (if (and (funcall comint-input-filter string)
4822 (or (null comint-input-ignoredups)
4823 (not (ring-p comint-input-ring))
4824 (ring-empty-p comint-input-ring)
4825 (not (string-equal (ring-ref comint-input-ring 0) string))))
4826 (ring-insert comint-input-ring string))
4827 (run-hook-with-args 'comint-input-filter-functions
4828 (concat string "\n"))
4829 (if (boundp 'comint-save-input-ring-index);only bound in GNU emacs
4830 (setq comint-save-input-ring-index comint-input-ring-index))
4831 (setq comint-input-ring-index nil))
4832
4833 (defun matlab-shell-save-and-go ()
4834 "Save this M file, and evaluate it in a MATLAB shell."
4835 (interactive)
4836 (if (not (eq major-mode 'matlab-mode))
4837 (error "Save and go is only useful in a MATLAB buffer!"))
4838 (if (not (buffer-file-name (current-buffer)))
4839 (call-interactively 'write-file))
4840 (let ((fn-name (file-name-sans-extension
4841 (file-name-nondirectory (buffer-file-name))))
4842 (msbn (concat "*" matlab-shell-buffer-name "*"))
4843 (param ""))
4844 (save-buffer)
4845 ;; Do we need parameters?
4846 (if (save-excursion
4847 (goto-char (point-min))
4848 (end-of-line)
4849 (forward-sexp -1)
4850 (looking-at "([a-zA-Z]"))
4851 (setq param (read-string "Parameters: "
4852 (car matlab-shell-save-and-go-history)
4853 'matlab-shell-save-and-go-history)))
4854 (if (matlab-with-emacs-link)
4855 ;; Execute the current file in MATLAB
4856 (matlab-eei-run)
4857
4858 ;; No buffer? Make it!
4859 (if (not (get-buffer msbn)) (matlab-shell))
4860 ;; Ok, now fun the function in the matlab shell
4861 (if (get-buffer-window msbn t)
4862 (select-window (get-buffer-window msbn t))
4863 (switch-to-buffer (concat "*" matlab-shell-buffer-name "*")))
4864
4865 (let ((cmd (concat fn-name " " param)))
4866 (matlab-shell-add-to-input-history cmd)
4867 (matlab-shell-send-string (concat cmd "\n"))))))
4868
4869 (defun matlab-shell-run-region (beg end)
4870 "Run region from BEG to END and display result in MATLAB shell.
4871 This command requires an active MATLAB shell."
4872 (interactive "r")
4873 (if (> beg end) (let (mid) (setq mid beg beg end end mid)))
4874 (let ((command (let ((str (concat (buffer-substring-no-properties beg end)
4875 "\n")))
4876 (while (string-match "\n\\s-*\n" str)
4877 (setq str (concat (substring str 0 (match-beginning 0))
4878 "\n"
4879 (substring str (match-end 0)))))
4880 str))
4881 (msbn nil)
4882 (lastcmd)
4883 (inhibit-field-text-motion t))
4884 (if (matlab-with-emacs-link)
4885 ;; Run the region w/ Emacs Link
4886 (matlab-eei-eval-region beg end)
4887
4888 (save-excursion
4889 (setq msbn (matlab-shell-buffer-barf-not-running))
4890 (set-buffer msbn)
4891 (if (not (matlab-on-prompt-p))
4892 (error "MATLAB shell must be non-busy to do that"))
4893 ;; Save the old command
4894 (beginning-of-line)
4895 (re-search-forward comint-prompt-regexp)
4896 (setq lastcmd (buffer-substring (point) (matlab-point-at-eol)))
4897 (delete-region (point) (matlab-point-at-eol))
4898 ;; We are done error checking, run the command.
4899 (matlab-shell-send-string command)
4900 (insert lastcmd))
4901 (set-buffer msbn)
4902 (goto-char (point-max))
4903 (display-buffer msbn))
4904 ))
4905
4906 (defun matlab-shell-run-cell ()
4907 "Run the cell the cursor is in."
4908 (interactive)
4909 (let ((start (save-excursion (forward-page -1)
4910 (if (looking-at "function")
4911 (error "You are not in a cell. Try `matlab-shell-save-and-go' instead"))
4912 (when (matlab-ltype-comm)
4913 ;; Skip over starting comment from the current cell.
4914 (matlab-end-of-command 1)
4915 (end-of-line)
4916 (forward-char 1))
4917 (point)))
4918 (end (save-excursion (forward-page 1)
4919 (when (matlab-ltype-comm)
4920 (beginning-of-line)
4921 (forward-char -1))
4922 (point))))
4923 (matlab-shell-run-region start end)))
4924
4925 (defun matlab-shell-run-region-or-line ()
4926 "Run region from BEG to END and display result in MATLAB shell.
4927 pIf region is not active run the current line.
4928 This command requires an active MATLAB shell."
4929 (interactive)
4930 (if (and transient-mark-mode mark-active)
4931 (matlab-shell-run-region (mark) (point))
4932 (matlab-shell-run-region (matlab-point-at-bol) (matlab-point-at-eol))))
4933
4934
4935 ;;; MATLAB Shell Commands =====================================================
4936
4937 (defun matlab-read-word-at-point ()
4938 "Get the word closest to point, but do not change position.
4939 Has a preference for looking backward when not directly on a symbol.
4940 Snatched and hacked from dired-x.el"
4941 (let ((word-chars "a-zA-Z0-9_")
4942 (bol (matlab-point-at-bol))
4943 (eol (matlab-point-at-eol))
4944 start)
4945 (save-excursion
4946 ;; First see if just past a word.
4947 (if (looking-at (concat "[" word-chars "]"))
4948 nil
4949 (skip-chars-backward (concat "^" word-chars "{}()\[\]") bol)
4950 (if (not (bobp)) (backward-char 1)))
4951 (if (numberp (string-match (concat "[" word-chars "]")
4952 (char-to-string (following-char))))
4953 (progn
4954 (skip-chars-backward word-chars bol)
4955 (setq start (point))
4956 (skip-chars-forward word-chars eol))
4957 (setq start (point))) ; If no found, return empty string
4958 (buffer-substring start (point)))))
4959
4960 (defun matlab-read-line-at-point ()
4961 "Get the line under point, if command line."
4962 (if (eq major-mode 'matlab-shell-mode)
4963 (save-excursion
4964 (let ((inhibit-field-text-motion t))
4965 (beginning-of-line)
4966 (if (not (looking-at (concat comint-prompt-regexp)))
4967 ""
4968 (search-forward-regexp comint-prompt-regexp)
4969 (buffer-substring (point) (matlab-point-at-eol)))))
4970 (save-excursion
4971 ;; In matlab buffer, find all the text for a command.
4972 ;; so back over until there is no more continuation.
4973 (while (save-excursion (forward-line -1) (matlab-lattr-cont))
4974 (forward-line -1))
4975 ;; Go forward till there is no continuation
4976 (beginning-of-line)
4977 (let ((start (point)))
4978 (while (matlab-lattr-cont) (forward-line 1))
4979 (end-of-line)
4980 (buffer-substring start (point))))))
4981
4982 (defun matlab-non-empty-lines-in-string (str)
4983 "Return number of non-empty lines in STR."
4984 (let ((count 0)
4985 (start 0))
4986 (while (string-match "^.+$" str start)
4987 (setq count (1+ count)
4988 start (match-end 0)))
4989 count))
4990
4991 (defun matlab-output-to-temp-buffer (buffer output)
4992 "Print output to temp buffer, or a message if empty string.
4993 BUFFER is the buffer to output to, and OUTPUT is the text to insert."
4994 (let ((lines-found (matlab-non-empty-lines-in-string output)))
4995 (cond ((= lines-found 0)
4996 (message "(MATLAB command completed with no output)"))
4997 ((= lines-found 1)
4998 (string-match "^.+$" output)
4999 (message (substring output (match-beginning 0)(match-end 0))))
5000 (t (with-output-to-temp-buffer buffer (princ output))
5001 (save-excursion
5002 (set-buffer buffer)
5003 (matlab-shell-help-mode))))))
5004
5005 (defun matlab-shell-run-command (command)
5006 "Run COMMAND and display result in a buffer.
5007 This command requires an active MATLAB shell."
5008 (interactive (list (read-from-minibuffer
5009 "MATLAB command line: "
5010 (cons (matlab-read-line-at-point) 0))))
5011 (let ((doc (matlab-shell-collect-command-output command)))
5012 (matlab-output-to-temp-buffer "*MATLAB Help*" doc)))
5013
5014 (defun matlab-shell-describe-variable (variable)
5015 "Get the contents of VARIABLE and display them in a buffer.
5016 This uses the WHOS (MATLAB 5) command to find viable commands.
5017 This command requires an active MATLAB shell."
5018 (interactive (list (read-from-minibuffer
5019 "MATLAB variable: "
5020 (cons (matlab-read-word-at-point) 0))))
5021 (let ((doc (matlab-shell-collect-command-output (concat "whos " variable))))
5022 (matlab-output-to-temp-buffer "*MATLAB Help*" doc)))
5023
5024 (defun matlab-shell-describe-command (command)
5025 "Describe COMMAND textually by fetching it's doc from the MATLAB shell.
5026 This uses the lookfor command to find viable commands.
5027 This command requires an active MATLAB shell."
5028 (interactive
5029 (let ((fn (matlab-function-called-at-point))
5030 val)
5031 (setq val (read-string (if fn
5032 (format "Describe function (default %s): " fn)
5033 "Describe function: ")))
5034 (if (string= val "") (list fn) (list val))))
5035 (let ((doc (matlab-shell-collect-command-output (concat "help " command))))
5036 (matlab-output-to-temp-buffer "*MATLAB Help*" doc)))
5037
5038 (defun matlab-shell-apropos (matlabregex)
5039 "Look for any active commands in MATLAB matching MATLABREGEX.
5040 This uses the lookfor command to find viable commands."
5041 (interactive (list (read-from-minibuffer
5042 "MATLAB command subexpression: "
5043 (cons (matlab-read-word-at-point) 0))))
5044 (let ((ap (matlab-shell-collect-command-output
5045 (concat "lookfor " matlabregex))))
5046 (matlab-output-to-temp-buffer "*MATLAB Apropos*" ap)))
5047
5048 (defun matlab-on-prompt-p ()
5049 "Return t if we MATLAB can accept input."
5050 (save-excursion
5051 (let ((inhibit-field-text-motion t))
5052 (goto-char (point-max))
5053 (beginning-of-line)
5054 (looking-at comint-prompt-regexp))))
5055
5056 (defun matlab-on-empty-prompt-p ()
5057 "Return t if we MATLAB is on an empty prompt."
5058 (save-excursion
5059 (let ((inhibit-field-text-motion t))
5060 (goto-char (point-max))
5061 (beginning-of-line)
5062 (looking-at (concat comint-prompt-regexp "\\s-*$")))))
5063
5064 (defun matlab-shell-buffer-barf-not-running ()
5065 "Return a running MATLAB buffer iff it is currently active."
5066 (or (matlab-shell-active-p)
5067 (error "You need to run the command `matlab-shell' to do that!")))
5068
5069 (defun matlab-shell-collect-command-output (command)
5070 "If there is a MATLAB shell, run the MATLAB COMMAND and return it's output.
5071 It's output is returned as a string with no face properties. The text output
5072 of the command is removed from the MATLAB buffer so there will be no
5073 indication that it ran."
5074 (let ((msbn (matlab-shell-buffer-barf-not-running))
5075 (pos nil)
5076 (str nil)
5077 (lastcmd)
5078 (inhibit-field-text-motion t))
5079 (save-excursion
5080 (set-buffer msbn)
5081 (if (not (matlab-on-prompt-p))
5082 (error "MATLAB shell must be non-busy to do that"))
5083 ;; Save the old command
5084 (goto-char (point-max))
5085 (beginning-of-line)
5086 (re-search-forward comint-prompt-regexp)
5087 (setq lastcmd (buffer-substring (point) (matlab-point-at-eol)))
5088 (delete-region (point) (matlab-point-at-eol))
5089 ;; We are done error checking, run the command.
5090 (setq pos (point))
5091 (comint-send-string (get-buffer-process (current-buffer))
5092 (concat command "\n"))
5093 ;;(message "MATLAB ... Executing command.")
5094 (goto-char (point-max))
5095 (while (or (>= (+ pos (string-width command)) (point)) (not (matlab-on-empty-prompt-p)))
5096 (accept-process-output (get-buffer-process (current-buffer)))
5097 (goto-char (point-max))
5098 ;;(message "MATLAB reading...")
5099 )
5100 ;;(message "MATLAB reading...done")
5101 (save-excursion
5102 (goto-char pos)
5103 (beginning-of-line)
5104 (setq str (buffer-substring-no-properties (save-excursion
5105 (goto-char pos)
5106 (beginning-of-line)
5107 (forward-line 1)
5108 (point))
5109 (save-excursion
5110 (goto-char (point-max))
5111 (beginning-of-line)
5112 (point))))
5113 (delete-region pos (point-max)))
5114 (insert lastcmd))
5115 str))
5116
5117 (defun matlab-shell-send-string (string)
5118 "Send STRING to the currently running matlab process."
5119 (if (not matlab-shell-echoes)
5120 (let ((proc (get-buffer-process (current-buffer))))
5121 (goto-char (point-max))
5122 (insert string)
5123 (set-marker (process-mark proc) (point))))
5124 (comint-send-string (get-buffer-process (current-buffer)) string))
5125
5126 (defun matlab-url-at (p)
5127 "Return the matlab-url overlay at P, or nil."
5128 (let ((url nil) (o (matlab-overlays-at p)))
5129 (while (and o (not url))
5130 (setq url (matlab-overlay-get (car o) 'matlab-url)
5131 o (cdr o)))
5132 url))
5133
5134 (defun matlab-url-stack-top-at (p)
5135 "Return the matlab-url overlay at P, or nil."
5136 (let ((url nil) (o (matlab-overlays-at p)))
5137 (while (and o (not url))
5138 (setq url (or (matlab-overlay-get (car o) 'first-in-error-stack)
5139 (matlab-overlay-get (car o) 'matlab-url))
5140 o (cdr o)))
5141 url))
5142
5143 (defun matlab-shell-previous-matlab-url (&optional stacktop)
5144 "Find a previous occurrence of an overlay with a MATLAB URL.
5145 If STACKTOP is non-nil, then also get the top of some stack, which didn't
5146 show up in reverse order."
5147 (save-excursion
5148 (let ((url nil) (o nil) (p (point)))
5149 (while (and (not url)
5150 (setq p (matlab-previous-overlay-change p))
5151 (not (eq p (point-min))))
5152 (setq url
5153 (if stacktop
5154 (matlab-url-stack-top-at p)
5155 (matlab-url-at p))))
5156 url)))
5157
5158 (defun matlab-find-other-window-file-line-column (ef el ec &optional debug)
5159 "Find file EF in other window and to go line EL and 1-basec column EC.
5160 If DEBUG is non-nil, then setup GUD debugging features."
5161 (cond ((file-exists-p ef)
5162 nil);; keep ef the same
5163 ((file-exists-p (concat ef ".m"))
5164 (setq ef (concat ef ".m"))) ;; Displayed w/out .m?
5165 ((string-match ">" ef)
5166 (setq ef (concat (substring ef 0 (match-beginning 0)) ".m")))
5167 )
5168 (find-file-other-window ef)
5169 (goto-line (string-to-number el))
5170 (when debug
5171 (setq gud-last-frame (cons (buffer-file-name) (string-to-number el)))
5172 (gud-display-frame))
5173 (setq ec (string-to-number ec))
5174 (if (> ec 0) (forward-char (1- ec))))
5175
5176 (defun matlab-find-other-window-via-url (url &optional debug)
5177 "Find other window using matlab URL and optionally set DEBUG cursor."
5178 (cond ((string-match "^error:\\(.*\\),\\([0-9]+\\),\\([0-9]+\\)$" url)
5179 (let ((ef (substring url (match-beginning 1) (match-end 1)))
5180 (el (substring url (match-beginning 2) (match-end 2)))
5181 (ec (substring url (match-beginning 3) (match-end 3))))
5182 (matlab-find-other-window-file-line-column ef el ec debug)))
5183 ((string-match "opentoline('\\([^']+\\)',\\([0-9]+\\),\\([0-9]+\\))" url)
5184 (let ((ef (substring url (match-beginning 1) (match-end 1)))
5185 (el (substring url (match-beginning 2) (match-end 2)))
5186 (ec (substring url (match-beginning 3) (match-end 3))))
5187 (matlab-find-other-window-file-line-column ef el ec debug)))
5188 ((string-match "^matlab: *\\(.*\\)$" url)
5189 (process-send-string
5190 (get-buffer-process gud-comint-buffer)
5191 (concat (substring url (match-beginning 1) (match-end 1)) "\n")))))
5192
5193 (defun matlab-shell-last-error ()
5194 "In the MATLAB interactive buffer, find the last MATLAB error, and go there.
5195 To reference old errors, put the cursor just after the error text."
5196 (interactive)
5197 (catch 'done
5198 (let ((url (matlab-shell-previous-matlab-url t)))
5199 (if url
5200 (progn (matlab-find-other-window-via-url url) (throw 'done nil))
5201 (save-excursion
5202 (end-of-line) ;; In case we are before the linenumber 1998/06/05 16:54sk
5203 (if (not (re-search-backward gud-matlab-error-regexp nil t))
5204 (error "No errors found!"))
5205 (let ((ef (buffer-substring-no-properties
5206 (match-beginning 2) (match-end 2)))
5207 (el (buffer-substring-no-properties
5208 (match-beginning 3) (match-end 3))))
5209 (matlab-find-other-window-file-line-column ef el 0)))))))
5210
5211 (defun matlab-shell-html-click (e)
5212 "Go to the error at the location of event E."
5213 (interactive "e")
5214 (mouse-set-point e)
5215 (let ((url (matlab-url-at (point))))
5216 (if url (matlab-find-other-window-via-url url))))
5217
5218 (defun matlab-shell-dbstop-error ()
5219 "Stop on errors."
5220 (interactive)
5221 (comint-send-string (get-buffer-process (current-buffer))
5222 "dbstop if error\n"))
5223
5224 (defun matlab-shell-dbclear-error ()
5225 "Don't stop on errors."
5226 (interactive)
5227 (comint-send-string (get-buffer-process (current-buffer))
5228 "dbclear if error\n"))
5229
5230 (defun matlab-shell-demos ()
5231 "MATLAB demos."
5232 (interactive)
5233 (comint-send-string (get-buffer-process (current-buffer)) "demo\n"))
5234
5235 (defun matlab-shell-close-figures ()
5236 "Close any open figures."
5237 (interactive)
5238 (comint-send-string (get-buffer-process (current-buffer)) "close all\n"))
5239
5240 (defun matlab-shell-close-current-figure ()
5241 "Close current figure."
5242 (interactive)
5243 (comint-send-string (get-buffer-process (current-buffer)) "delete(gcf)\n"))
5244
5245 (defun matlab-shell-exit ()
5246 "Exit MATLAB shell."
5247 (interactive)
5248 (comint-send-string (get-buffer-process (current-buffer)) "exit\n")
5249 (kill-buffer nil))
5250
5251
5252 ;;; matlab-shell based Topic Browser and Help =================================
5253
5254 (defcustom matlab-shell-topic-mode-hook nil
5255 "*MATLAB shell topic hook."
5256 :group 'matlab-shell
5257 :type 'hook)
5258
5259 (defvar matlab-shell-topic-current-topic nil
5260 "The currently viewed topic in a MATLAB shell topic buffer.")
5261
5262 (defun matlab-shell-topic-browser ()
5263 "Create a topic browser by querying an active MATLAB shell using HELP.
5264 Maintain state in our topic browser buffer."
5265 (interactive)
5266 ;; Reset topic browser if it doesn't exist.
5267 (if (not (get-buffer "*MATLAB Topic*"))
5268 (setq matlab-shell-topic-current-topic nil))
5269 (let ((b (get-buffer-create "*MATLAB Topic*")))
5270 (switch-to-buffer b)
5271 (if (string= matlab-shell-topic-current-topic "")
5272 nil
5273 (matlab-shell-topic-mode)
5274 (matlab-shell-topic-browser-create-contents ""))))
5275
5276 (defvar matlab-shell-topic-mouse-face-keywords
5277 '(;; These are subtopic fields...
5278 ("^\\(\\w+/\\w+\\)[ \t]+-" 1 font-lock-reference-face)
5279 ;; These are functions...
5280 ("^[ \t]+\\(\\w+\\)[ \t]+-" 1 font-lock-function-name-face)
5281 ;; Here is a See Also line...
5282 ("[ \t]+See also "
5283 ("\\(\\w+\\)\\([,.]\\| and\\|$\\) *" nil nil (1 font-lock-reference-face))))
5284 "These are keywords we also want to put mouse-faces on.")
5285
5286 (defvar matlab-shell-topic-font-lock-keywords
5287 (append matlab-shell-topic-mouse-face-keywords
5288 '(("^[^:\n]+:$" 0 font-lock-keyword-face)
5289 ;; These are subheadings...
5290 ("^[ \t]+\\([^.\n]+[a-zA-Z.]\\)$" 1 'underline)
5291 ))
5292 "Keywords useful for highlighting a MATLAB TOPIC buffer.")
5293
5294 (defvar matlab-shell-help-font-lock-keywords
5295 (append matlab-shell-topic-mouse-face-keywords
5296 '(;; Function call examples
5297 ("[ \t]\\([A-Z]+\\)\\s-*=\\s-*\\([A-Z]+[0-9]*\\)("
5298 (1 font-lock-variable-name-face)
5299 (2 font-lock-function-name-face))
5300 ("[ \t]\\([A-Z]+[0-9]*\\)("
5301 (1 font-lock-function-name-face))
5302 ;; Parameters: Not very accurate, unfortunately.
5303 ("[ \t]\\([A-Z]+[0-9]*\\)("
5304 ("'?\\(\\w+\\)'?\\([,)]\\) *" nil nil
5305 (1 font-lock-variable-name-face))
5306 )
5307 ;; Reference uppercase words
5308 ("\\<\\([A-Z]+[0-9]*\\)\\>" 1 font-lock-reference-face)))
5309 "Keywords for regular help buffers.")
5310
5311 ;; View-major-mode is an emacs20 thing. This gives us a small compatibility
5312 ;; layer.
5313 (if (not (fboundp 'view-major-mode)) (defalias 'view-major-mode 'view-mode))
5314
5315 (define-derived-mode matlab-shell-help-mode
5316 view-major-mode "M-Help"
5317 "Major mode for viewing MATLAB help text.
5318 Entry to this mode runs the normal hook `matlab-shell-help-mode-hook'.
5319
5320 Commands:
5321 \\{matlab-shell-help-mode-map}"
5322 (make-local-variable 'font-lock-defaults)
5323 (setq font-lock-defaults '((matlab-shell-help-font-lock-keywords)
5324 t nil ((?_ . "w"))))
5325 ;; This makes sure that we really enter font lock since
5326 ;; kill-all-local-variables is not used by old view-mode.
5327 (and (boundp 'global-font-lock-mode) global-font-lock-mode
5328 (not font-lock-mode) (font-lock-mode 1))
5329 (easy-menu-add matlab-shell-help-mode-menu matlab-shell-help-mode-map)
5330 (matlab-shell-topic-mouse-highlight-subtopics)
5331 )
5332
5333 (define-key matlab-shell-help-mode-map [return] 'matlab-shell-topic-choose)
5334 (define-key matlab-shell-help-mode-map "t" 'matlab-shell-topic-browser)
5335 (define-key matlab-shell-help-mode-map "q" 'bury-buffer)
5336 (define-key matlab-shell-help-mode-map
5337 [(control h) (control m)] matlab-help-map)
5338 (if (string-match "XEmacs" emacs-version)
5339 (define-key matlab-shell-help-mode-map [button2] 'matlab-shell-topic-click)
5340 (define-key matlab-shell-help-mode-map [mouse-2] 'matlab-shell-topic-click))
5341
5342 (easy-menu-define
5343 matlab-shell-help-mode-menu matlab-shell-help-mode-map
5344 "MATLAB shell topic menu"
5345 '("MATLAB Help"
5346 ["Describe This Command" matlab-shell-topic-choose t]
5347 "----"
5348 ["Describe Command" matlab-shell-describe-command t]
5349 ["Describe Variable" matlab-shell-describe-variable t]
5350 ["Command Apropos" matlab-shell-apropos t]
5351 ["Topic Browser" matlab-shell-topic-browser t]
5352 "----"
5353 ["Exit" bury-buffer t]))
5354
5355 (define-derived-mode matlab-shell-topic-mode
5356 matlab-shell-help-mode "M-Topic"
5357 "Major mode for browsing MATLAB HELP topics.
5358 The output of the MATLAB command HELP with no parameters creates a listing
5359 of known help topics at a given installation. This mode parses that listing
5360 and allows selecting a topic and getting more help for it.
5361 Entry to this mode runs the normal hook `matlab-shell-topic-mode-hook'.
5362
5363 Commands:
5364 \\{matlab-shell-topic-mode-map}"
5365 (setq font-lock-defaults '((matlab-shell-topic-font-lock-keywords)
5366 t t ((?_ . "w"))))
5367 (if (string-match "XEmacs" emacs-version)
5368 (setq mode-motion-hook 'matlab-shell-topic-highlight-line))
5369 (easy-menu-add matlab-shell-topic-mode-menu matlab-shell-topic-mode-map)
5370 )
5371
5372 (easy-menu-define
5373 matlab-shell-topic-mode-menu matlab-shell-topic-mode-map
5374 "MATLAB shell topic menu"
5375 '("MATLAB Topic"
5376 ["Select This Topic" matlab-shell-topic-choose t]
5377 ["Top Level Topics" matlab-shell-topic-browser t]
5378 "----"
5379 ["Exit" bury-buffer t]))
5380
5381 (defun matlab-shell-topic-browser-create-contents (subtopic)
5382 "Fill in a topic browser with the output from SUBTOPIC."
5383 (toggle-read-only -1)
5384 (erase-buffer)
5385 (insert (matlab-shell-collect-command-output (concat "help " subtopic)))
5386 (goto-char (point-min))
5387 (forward-line 1)
5388 (delete-region (point-min) (point))
5389 (setq matlab-shell-topic-current-topic subtopic)
5390 (if (not (string-match "XEmacs" emacs-version))
5391 (matlab-shell-topic-mouse-highlight-subtopics))
5392 (toggle-read-only 1)
5393 )
5394
5395 (defun matlab-shell-topic-click (e)
5396 "Click on an item in a MATLAB topic buffer we want more information on.
5397 Must be bound to event E."
5398 (interactive "e")
5399 (mouse-set-point e)
5400 (matlab-shell-topic-choose))
5401
5402 (defun matlab-shell-topic-choose ()
5403 "Choose the topic to expand on that is under the cursor.
5404 This can fill the topic buffer with new information. If the topic is a
5405 command, use `matlab-shell-describe-command' instead of changing the topic
5406 buffer."
5407 (interactive)
5408 (let ((topic nil) (fun nil) (p (point)))
5409 (save-excursion
5410 (beginning-of-line)
5411 (if (looking-at "^\\w+/\\(\\w+\\)[ \t]+-")
5412 (setq topic (match-string 1))
5413 (if (looking-at "^[ \t]+\\(\\(\\w\\|_\\)+\\)[ \t]+-")
5414 (setq fun (match-string 1))
5415 (if (and (not (looking-at "^[ \t]+See also"))
5416 (not (save-excursion (forward-char -2)
5417 (looking-at ",$"))))
5418 (error "You did not click on a subtopic, function or reference")
5419 (goto-char p)
5420 (forward-word -1)
5421 (if (not (looking-at "\\(\\(\\w\\|_\\)+\\)\\([.,]\\| and\\|\n\\)"))
5422 (error "You must click on a reference")
5423 (setq topic (match-string 1)))))))
5424 (message "Opening item %s..." (or topic fun))
5425 (if topic
5426 (matlab-shell-topic-browser-create-contents (downcase topic))
5427 (matlab-shell-describe-command fun))
5428 ))
5429
5430 (defun matlab-shell-topic-mouse-highlight-subtopics ()
5431 "Put a `mouse-face' on all clickable targets in this buffer."
5432 (save-excursion
5433 (let ((el matlab-shell-topic-mouse-face-keywords))
5434 (while el
5435 (goto-char (point-min))
5436 (while (re-search-forward (car (car el)) nil t)
5437 (let ((cd (car (cdr (car el)))))
5438 (if (numberp cd)
5439 (put-text-property (match-beginning cd) (match-end cd)
5440 'mouse-face 'highlight)
5441 (while (re-search-forward (car cd) nil t)
5442 (put-text-property (match-beginning (car (nth 3 cd)))
5443 (match-end (car (nth 3 cd)))
5444 'mouse-face 'highlight)))))
5445 (setq el (cdr el))))))
5446
5447 (defun matlab-shell-topic-highlight-line (event)
5448 "A value of `mode-motion-hook' which will highlight topics under the mouse.
5449 EVENT is the user mouse event."
5450 ;; XEMACS only function
5451 (let* ((buffer (event-buffer event))
5452 (point (and buffer (event-point event))))
5453 (if (and buffer (not (eq buffer mouse-grabbed-buffer)))
5454 (save-excursion
5455 (save-window-excursion
5456 (set-buffer buffer)
5457 (mode-motion-ensure-extent-ok event)
5458 (if (not point)
5459 (detach-extent mode-motion-extent)
5460 (goto-char point)
5461 (end-of-line)
5462 (setq point (point))
5463 (beginning-of-line)
5464 (if (or (looking-at "^\\w+/\\(\\w+\\)[ \t]+-")
5465 (looking-at "^[ \t]+\\(\\(\\w\\|_\\)+\\)[ \t]+-"))
5466 (set-extent-endpoints mode-motion-extent (point) point)
5467 (detach-extent mode-motion-extent))))))))
5468
5469
5470 ;;; M File path stuff =========================================================
5471
5472 (defun matlab-mode-determine-mfile-path ()
5473 "Create the path in `matlab-mode-install-path'."
5474 (let ((path (file-name-directory matlab-shell-command)))
5475 ;; if we don't have a path, find the MATLAB executable on our path.
5476 (if (not path)
5477 (let ((pl exec-path))
5478 (while (and pl (not path))
5479 (if (and (file-exists-p (concat (car pl) "/" matlab-shell-command))
5480 (not (car (file-attributes (concat (car pl) "/"
5481 matlab-shell-command)))))
5482 (setq path (car pl)))
5483 (setq pl (cdr pl)))))
5484 (if (not path)
5485 nil
5486 ;; When we find the path, we need to massage it to identify where
5487 ;; the M files are that we need for our completion lists.
5488 (if (string-match "/bin$" path)
5489 (setq path (substring path 0 (match-beginning 0))))
5490 ;; Everything stems from toolbox (I think)
5491 (setq path (concat path "/toolbox/")))
5492 path))
5493
5494 (defcustom matlab-mode-install-path (list (matlab-mode-determine-mfile-path))
5495 "Base path pointing to the locations of all the m files used by matlab.
5496 All directories under each element of `matlab-mode-install-path' are
5497 checked, so only top level toolbox directories need be added.
5498 Paths should be added in the order in which they should be searched."
5499 :group 'matlab-shell
5500 :type '(repeat (string :tag "Path: ")))
5501
5502 (defun matlab-find-file-under-path (path filename)
5503 "Return the pathname or nil of PATH under FILENAME."
5504 (if (file-exists-p (concat path filename))
5505 (concat path filename)
5506 (let ((dirs (if (file-directory-p path)
5507 ;; Not checking as a directory first fails on XEmacs
5508 ;; Stelios Kyriacou <kyriacou@cbmv.jhu.edu>
5509 (directory-files path t nil t)))
5510 (found nil))
5511 (while (and dirs (not found))
5512 (if (and (car (file-attributes (car dirs)))
5513 ;; require directory readable
5514 (file-readable-p (car dirs))
5515 ;; don't redo our path names
5516 (not (string-match "/\\.\\.?$" (car dirs)))
5517 ;; don't find files in object directories.
5518 (not (string-match "@" (car dirs))))
5519 (setq found
5520 (matlab-find-file-under-path (concat (car dirs) "/")
5521 filename)))
5522 (setq dirs (cdr dirs)))
5523 found)))
5524
5525 (defun matlab-find-file-on-path (filename)
5526 "Find FILENAME on the current MATLAB path.
5527 The MATLAB path is determined by `matlab-mode-install-path' and the
5528 current directory. You must add user-installed paths into
5529 `matlab-mode-install-path' if you would like to have them included."
5530 (interactive
5531 (list
5532 (let ((default (matlab-read-word-at-point)))
5533 (if default
5534 (let ((s (read-string (concat "File (default " default "): "))))
5535 (if (string= s "") default s))
5536 (read-string "File: ")))))
5537 (if (string= filename "")
5538 (error "You must specify an M file"))
5539 (if (not (string-match "\\.m$" filename))
5540 (setq filename (concat filename ".m")))
5541 (let ((fname nil)
5542 (dirs matlab-mode-install-path))
5543 (if (file-exists-p (concat default-directory filename))
5544 (setq fname (concat default-directory filename)))
5545 (while (and (not fname) dirs)
5546 (if (stringp (car dirs))
5547 (progn
5548 (message "Searching for %s in %s" filename (car dirs))
5549 (setq fname (matlab-find-file-under-path (car dirs) filename))))
5550 (setq dirs (cdr dirs)))
5551 (if fname (find-file fname)
5552 (error "File %s not found on any known paths. \
5553 Check `matlab-mode-install-path'" filename))))
5554
5555 (defun matlab-find-file-click (e)
5556 "Find the file clicked on with event E on the current path."
5557 (interactive "e")
5558 (mouse-set-point e)
5559 (let ((f (matlab-read-word-at-point)))
5560 (if (not f) (error "To find an M file, click on a word"))
5561 (matlab-find-file-on-path f)))
5562
5563
5564 ;;; matlab-mode debugging =====================================================
5565
5566 (defun matlab-show-line-info ()
5567 "Display type and attributes of current line. Used in debugging."
5568 (interactive)
5569 (let ((msg "line-info:")
5570 (indent (matlab-calculate-indentation (current-indentation)))
5571 (nexti (matlab-next-line-indentation)))
5572 (setq msg (concat msg
5573 " Line type: " (symbol-name (car indent))
5574 " This Line: " (int-to-string (nth 1 indent))
5575 " Next Line: " (int-to-string nexti)))
5576 (if (matlab-lattr-cont)
5577 (setq msg (concat msg " w/cont")))
5578 (if (matlab-lattr-comm)
5579 (setq msg (concat msg " w/comm")))
5580 (message msg)))
5581
5582 (provide 'matlab)
5583
5584 ;;; matlab.el ends here