aboutsummaryrefslogtreecommitdiffstats
path: root/lisp/progmodes
diff options
context:
space:
mode:
authorRichard M. Stallman1996-04-21 01:39:51 +0000
committerRichard M. Stallman1996-04-21 01:39:51 +0000
commit8ca3cd44629036e51f108e0e82cdd3c8a6778e1d (patch)
tree9b8a5ae4371533733898d18bc0458a8c217c4f84 /lisp/progmodes
parentc80718ccb9e66011245253acb3c7df2c6199bfec (diff)
downloademacs-8ca3cd44629036e51f108e0e82cdd3c8a6778e1d.tar.gz
emacs-8ca3cd44629036e51f108e0e82cdd3c8a6778e1d.zip
(simula-tab-always-indent, simula-indent-level)
(simula-substatement-offset, simula-continued-statement-offset) (simula-label-offset, simula-if-indent, simula-inspect-indent) (simula-electric-indent, simula-abbrev-keyword, simula-abbrev-stdproc): Added default constants. (simula-emacs-features): new constant to hold information on which flavor if emacs is running (from cc-mode.el). (simula-mode-menu): Menu definition for Lucid Emacs (simula-mode-map): Bound new command simula-indent-exp to C-M-q and added lots of commands to [menu-bar]. (simula-popup-menu): New function for Lucid menus. (simula-keep-region-active): New function for Lucid menus. (simula-indent-exp): New command that indents a whole expression. (simula-indent-line): New strategies for finding the right amount to indent. (simula-skip-comment-backward): Added optional parameter stop-at-end to stop at the first END statement. (simula-expand-stdproc): Added abbrev expansion to verbatim copy of abbrev table, same for function simula-expand-keyword. (simula-search-backward): Added Doc string, and lots of error checking. (simula-search-forward): Added Doc string, and lots of error checking. Added hilit19 config code. (simula-version): New variable and function to report value. (simula-submit-bug-report): New function to submit bug report.
Diffstat (limited to 'lisp/progmodes')
-rw-r--r--lisp/progmodes/simula.el592
1 files changed, 492 insertions, 100 deletions
diff --git a/lisp/progmodes/simula.el b/lisp/progmodes/simula.el
index 45cb24b331d..6661a109bb5 100644
--- a/lisp/progmodes/simula.el
+++ b/lisp/progmodes/simula.el
@@ -1,10 +1,11 @@
1;;; simula.el --- SIMULA 87 code editing commands for Emacs 1;;; simula.el --- SIMULA 87 code editing commands for Emacs
2 2
3;; Copyright (C) 1992 Free Software Foundation, Inc. 3;; Copyright (C) 1994 Hans Henrik Eriksen
4;; Copyright (C) 1992, 1994 Free Software Foundation, Inc.
4 5
5;; Author: Hans Henrik Eriksen <hhe@ifi.uio.no> 6;; Author: Hans Henrik Eriksen <hhe@ifi.uio.no>
6;; Maintainer: simula-mode@ifi.uio.no 7;; Maintainer: simula-mode@ifi.uio.no
7;; Version: 0.992 8;; Version: 0.994
8;; Adapted-By: ESR 9;; Adapted-By: ESR
9;; Keywords: languages 10;; Keywords: languages
10 11
@@ -37,50 +38,92 @@
37 38
38;;; Code: 39;;; Code:
39 40
40(provide 'simula-mode) 41
42(defconst simula-tab-always-indent-default nil
43 "Non-nil means TAB in SIMULA mode should always reindent the current line.
44Otherwise TAB indents only when point is within
45the run of whitespace at the beginning of the line.")
41 46
42(defconst simula-tab-always-indent nil 47(defvar simula-tab-always-indent simula-tab-always-indent-default
43 "*Non-nil means TAB in SIMULA mode should always reindent the current line. 48 "*Non-nil means TAB in SIMULA mode should always reindent the current line.
44Otherwise TAB indents only when point is within 49Otherwise TAB indents only when point is within
45the run of whitespace at the beginning of the line.") 50the run of whitespace at the beginning of the line.")
46 51
47(defconst simula-indent-level 3 52(defconst simula-indent-level-default 3
53 "Indentation of SIMULA statements with respect to containing block.")
54
55(defvar simula-indent-level simula-indent-level-default
48 "*Indentation of SIMULA statements with respect to containing block.") 56 "*Indentation of SIMULA statements with respect to containing block.")
49 57
50(defconst simula-substatement-offset 3 58(defconst simula-substatement-offset-default 3
59 "Extra indentation after DO, THEN, ELSE, WHEN and OTHERWISE.")
60
61(defvar simula-substatement-offset simula-substatement-offset-default
51 "*Extra indentation after DO, THEN, ELSE, WHEN and OTHERWISE.") 62 "*Extra indentation after DO, THEN, ELSE, WHEN and OTHERWISE.")
52 63
53(defconst simula-continued-statement-offset 3 64(defconst simula-continued-statement-offset-default 3
65 "Extra indentation for lines not starting a statement or substatement.
66If value is a list, each line in a multipleline continued statement
67will have the car of the list extra indentation with respect to
68the previous line of the statement.")
69
70(defvar simula-continued-statement-offset simula-continued-statement-offset-default
54 "*Extra indentation for lines not starting a statement or substatement. 71 "*Extra indentation for lines not starting a statement or substatement.
55If value is a list, each line in a multipleline continued statement 72If value is a list, each line in a multipleline continued statement
56will have the car of the list extra indentation with respect to 73will have the car of the list extra indentation with respect to
57the previous line of the statement.") 74the previous line of the statement.")
58 75
59(defconst simula-label-offset -4711 76(defconst simula-label-offset-default -4711
77 "Offset of SIMULA label lines relative to usual indentation.")
78
79(defvar simula-label-offset simula-label-offset-default
60 "*Offset of SIMULA label lines relative to usual indentation.") 80 "*Offset of SIMULA label lines relative to usual indentation.")
61 81
62(defconst simula-if-indent '(0 . 0) 82(defconst simula-if-indent-default '(0 . 0)
83 "Extra indentation of THEN and ELSE with respect to the starting IF.
84Value is a cons cell, the car is extra THEN indentation and the cdr
85extra ELSE indentation. IF after ELSE is indented as the starting IF.")
86
87(defvar simula-if-indent simula-if-indent-default
63 "*Extra indentation of THEN and ELSE with respect to the starting IF. 88 "*Extra indentation of THEN and ELSE with respect to the starting IF.
64Value is a cons cell, the car is extra THEN indentation and the cdr 89Value is a cons cell, the car is extra THEN indentation and the cdr
65extra ELSE indentation. IF after ELSE is indented as the starting IF.") 90extra ELSE indentation. IF after ELSE is indented as the starting IF.")
66 91
67(defconst simula-inspect-indent '(0 . 0) 92(defconst simula-inspect-indent-default '(0 . 0)
93 "Extra indentation of WHEN and OTHERWISE with respect to the INSPECT.
94Value is a cons cell, the car is extra WHEN indentation
95and the cdr extra OTHERWISE indentation.")
96
97(defvar simula-inspect-indent simula-inspect-indent-default
68 "*Extra indentation of WHEN and OTHERWISE with respect to the INSPECT. 98 "*Extra indentation of WHEN and OTHERWISE with respect to the INSPECT.
69Value is a cons cell, the car is extra WHEN indentation 99Value is a cons cell, the car is extra WHEN indentation
70and the cdr extra OTHERWISE indentation.") 100and the cdr extra OTHERWISE indentation.")
71 101
72(defconst simula-electric-indent nil 102(defconst simula-electric-indent-default nil
103 "Non-nil means `simula-indent-line' function may reindent previous line.")
104
105(defvar simula-electric-indent simula-electric-indent-default
73 "*Non-nil means `simula-indent-line' function may reindent previous line.") 106 "*Non-nil means `simula-indent-line' function may reindent previous line.")
74 107
75(defconst simula-abbrev-keyword 'upcase 108(defconst simula-abbrev-keyword-default 'upcase
109 "Specify how to convert case for SIMULA keywords.
110Value is one of the symbols `upcase', `downcase', `capitalize',
111(as in) `abbrev-table' or nil if they should not be changed.")
112
113(defvar simula-abbrev-keyword simula-abbrev-keyword-default
76 "*Specify how to convert case for SIMULA keywords. 114 "*Specify how to convert case for SIMULA keywords.
77Value is one of the symbols `upcase', `downcase', `capitalize', 115Value is one of the symbols `upcase', `downcase', `capitalize',
78\(as in) `abbrev-table' or nil if they should not be changed.") 116(as in) `abbrev-table' or nil if they should not be changed.")
117
118(defconst simula-abbrev-stdproc-default 'abbrev-table
119 "Specify how to convert case for standard SIMULA procedure and class names.
120Value is one of the symbols `upcase', `downcase', `capitalize',
121(as in) `abbrev-table', or nil if they should not be changed.")
79 122
80(defconst simula-abbrev-stdproc 'abbrev-table 123(defvar simula-abbrev-stdproc simula-abbrev-stdproc-default
81 "*Specify how to convert case for standard SIMULA procedure and class names. 124 "*Specify how to convert case for standard SIMULA procedure and class names.
82Value is one of the symbols `upcase', `downcase', `capitalize', 125Value is one of the symbols `upcase', `downcase', `capitalize',
83\(as in) `abbrev-table', or nil if they should not be changed.") 126(as in) `abbrev-table', or nil if they should not be changed.")
84 127
85(defvar simula-abbrev-file nil 128(defvar simula-abbrev-file nil
86 "*File with extra abbrev definitions for use in SIMULA mode. 129 "*File with extra abbrev definitions for use in SIMULA mode.
@@ -91,6 +134,55 @@ for SIMULA mode to function correctly.")
91(defvar simula-mode-syntax-table nil 134(defvar simula-mode-syntax-table nil
92 "Syntax table in SIMULA mode buffers.") 135 "Syntax table in SIMULA mode buffers.")
93 136
137; The following function is taken from cc-mode.el,
138; it determines the flavor of the Emacs running
139(defconst simula-emacs-features
140 (let ((major (and (boundp 'emacs-major-version)
141 emacs-major-version))
142 (minor (and (boundp 'emacs-minor-version)
143 emacs-minor-version))
144 flavor comments)
145 ;; figure out version numbers if not already discovered
146 (and (or (not major) (not minor))
147 (string-match "\\([0-9]+\\).\\([0-9]+\\)" emacs-version)
148 (setq major (string-to-int (substring emacs-version
149 (match-beginning 1)
150 (match-end 1)))
151 minor (string-to-int (substring emacs-version
152 (match-beginning 2)
153 (match-end 2)))))
154 (if (not (and major minor))
155 (error "Cannot figure out the major and minor version numbers."))
156 ;; calculate the major version
157 (cond
158 ((= major 18) (setq major 'v18)) ;Emacs 18
159 ((= major 4) (setq major 'v18)) ;Epoch 4
160 ((= major 19) (setq major 'v19 ;Emacs 19
161 flavor (if (string-match "Lucid" emacs-version)
162 'Lucid 'FSF)))
163 ;; I don't know
164 (t (error "Cannot recognize major version number: %s" major)))
165 (list major flavor comments))
166 "A list of features extant in the Emacs you are using.
167There are many flavors of Emacs out there, each with different
168features supporting those needed by simula-mode. Here's the current
169supported list, along with the values for this variable:
170
171 Emacs 19: (v19 FSF 1-bit)
172 Vanilla Emacs 18/Epoch 4: (v18 no-dual-comments)
173 Emacs 18/Epoch 4 (patch2): (v18 8-bit)
174 Lucid Emacs 19: (v19 Lucid 8-bit).")
175
176(defvar simula-mode-menu
177 '(["Report Bug" simula-submit-bug-report t]
178 ["Indent Line" simula-indent-line t]
179 ["Backward Statement" simula-previous-statement t]
180 ["Forward Statement" simula-next-statement t]
181 ["Backward Up Level" simula-backward-up-level t]
182 ["Forward Down Statement" simula-forward-down-level t]
183 )
184 "Lucid Emacs menu for SIMULA mode.")
185
94(if simula-mode-syntax-table 186(if simula-mode-syntax-table
95 () 187 ()
96 (setq simula-mode-syntax-table (copy-syntax-table (standard-syntax-table))) 188 (setq simula-mode-syntax-table (copy-syntax-table (standard-syntax-table)))
@@ -123,7 +215,65 @@ for SIMULA mode to function correctly.")
123 ;(define-key simula-mode-map "\C-c\C-h" 'simula-standard-help) 215 ;(define-key simula-mode-map "\C-c\C-h" 'simula-standard-help)
124 (define-key simula-mode-map "\177" 'backward-delete-char-untabify) 216 (define-key simula-mode-map "\177" 'backward-delete-char-untabify)
125 (define-key simula-mode-map ":" 'simula-electric-label) 217 (define-key simula-mode-map ":" 'simula-electric-label)
126 (define-key simula-mode-map "\t" 'simula-indent-command)) 218 (define-key simula-mode-map "\e\C-q" 'simula-indent-exp)
219 (define-key simula-mode-map "\t" 'simula-indent-command)
220 ;; Emacs 19 defines menus in the mode map
221 (if (memq 'FSF simula-emacs-features)
222 (progn
223 (define-key simula-mode-map [menu-bar] (make-sparse-keymap))
224
225 (define-key simula-mode-map [menu-bar simula]
226 (cons "SIMULA" (make-sparse-keymap "SIMULA")))
227 (define-key simula-mode-map [menu-bar simula bug-report]
228 '("Submit Bug Report" . simula-submit-bug-report))
229 (define-key simula-mode-map [menu-bar simula separator-indent]
230 '("--"))
231 (define-key simula-mode-map [menu-bar simula indent-exp]
232 '("Indent Expression" . simula-indent-exp))
233 (define-key simula-mode-map [menu-bar simula indent-line]
234 '("Indent Line" . simula-indent-command))
235 (define-key simula-mode-map [menu-bar simula separator-navigate]
236 '("--"))
237 (define-key simula-mode-map [menu-bar simula backward-stmt]
238 '("Previous Statement" . simula-previous-statement))
239 (define-key simula-mode-map [menu-bar simula forward-stmt]
240 '("Next Statement" . simula-next-statement))
241 (define-key simula-mode-map [menu-bar simula backward-up]
242 '("Backward Up Level" . simula-backward-up-level))
243 (define-key simula-mode-map [menu-bar simula forward-down]
244 '("Forward Down Statement" . simula-forward-down-level))
245
246 (put 'simula-next-statement 'menu-enable '(not (eobp)))
247 (put 'simula-previous-statement 'menu-enable '(not (bobp)))
248 (put 'simula-forward-down-level 'menu-enable '(not (eobp)))
249 (put 'simula-backward-up-level 'menu-enable '(not (bobp)))
250 (put 'simula-indent-command 'menu-enable '(not buffer-read-only))
251 (put 'simula-indent-exp 'menu-enable '(not buffer-read-only))))
252
253 ;; RMS: mouse-3 should not select this menu. mouse-3's global
254 ;; definition is useful in SIMULA mode and we should not interfere
255 ;; with that. The menu is mainly for beginners, and for them,
256 ;; the menubar requires less memory than a special click.
257 ;; in Lucid Emacs, we want the menu to popup when the 3rd button is
258 ;; hit. In 19.10 and beyond this is done automatically if we put
259 ;; the menu on mode-popup-menu variable, see c-common-init [cc-mode.el]
260 (if (memq 'Lucid simula-emacs-features)
261 (if (not (boundp 'mode-popup-menu))
262 (define-key simula-mode-map 'button3 'simula-popup-menu))))
263
264;; menus for Lucid
265(defun simula-popup-menu (e)
266 "Pops up the SIMULA menu."
267 (interactive "@e")
268 (popup-menu (cons (concat mode-name " Mode Commands") simula-mode-menu))
269 (simula-keep-region-active))
270
271;; active regions, and auto-newline/hungry delete key
272(defun simula-keep-region-active ()
273 ;; do whatever is necessary to keep the region active in
274 ;; Lucid. ignore byte-compiler warnings you might see
275 (and (boundp 'zmacs-region-stays)
276 (setq zmacs-region-stays t)))
127 277
128(defvar simula-mode-abbrev-table nil 278(defvar simula-mode-abbrev-table nil
129 "Abbrev table in SIMULA mode buffers") 279 "Abbrev table in SIMULA mode buffers")
@@ -180,8 +330,8 @@ at all."
180 (setq mode-name "SIMULA") 330 (setq mode-name "SIMULA")
181 (make-local-variable 'comment-column) 331 (make-local-variable 'comment-column)
182 (setq comment-column 40) 332 (setq comment-column 40)
183 (make-local-variable 'end-comment-column) 333; (make-local-variable 'end-comment-column)
184 (setq end-comment-column 75) 334; (setq end-comment-column 75)
185 (set-syntax-table simula-mode-syntax-table) 335 (set-syntax-table simula-mode-syntax-table)
186 (make-local-variable 'paragraph-start) 336 (make-local-variable 'paragraph-start)
187 (setq paragraph-start "[ \t]*$\\|\\f") 337 (setq paragraph-start "[ \t]*$\\|\\f")
@@ -213,6 +363,27 @@ at all."
213 (run-hooks 'simula-mode-hook)) 363 (run-hooks 'simula-mode-hook))
214 364
215 365
366(defun simula-indent-exp ()
367 "Indent SIMULA expression following point."
368 (interactive)
369 (let ((here (point))
370 (simula-electric-indent nil)
371 end)
372 (simula-skip-comment-forward)
373 (if (eobp)
374 (goto-char here)
375 (unwind-protect
376 (progn
377 (simula-next-statement 1)
378 (setq end (point-marker))
379 (simula-previous-statement 1)
380 (beginning-of-line)
381 (while (< (point) end)
382 (if (not (looking-at "[ \t]*$"))
383 (simula-indent-line))
384 (forward-line 1)))
385 (and end (set-marker end nil))))))
386
216 387
217(defun simula-indent-line () 388(defun simula-indent-line ()
218 "Indent this line as SIMULA code. 389 "Indent this line as SIMULA code.
@@ -221,27 +392,26 @@ If `simula-electric-indent' is non-nil, indent previous line if necessary."
221 (indent (simula-calculate-indent)) 392 (indent (simula-calculate-indent))
222 (case-fold-search t)) 393 (case-fold-search t))
223 (unwind-protect 394 (unwind-protect
224 (progn 395 (if simula-electric-indent
225 ;; 396 (progn
226 ;; manually expand abbrev on last line, if any 397 ;;
227 ;; 398 ;; manually expand abbrev on last line, if any
228 (end-of-line 0) 399 ;;
229 (expand-abbrev) 400 (end-of-line 0)
230 ;; now maybe we should reindent that line 401 (expand-abbrev)
231 (if simula-electric-indent 402 ;; now maybe we should reindent that line
232 (progn 403 (beginning-of-line)
233 (beginning-of-line) 404 (skip-chars-forward " \t\f")
234 (skip-chars-forward " \t\f") 405 (if (and
235 (if (and 406 (looking-at
236 (looking-at 407 "\\(end\\|if\\|then\\|else\\|when\\|otherwise\\)\\>")
237 "\\(end\\|if\\|then\\|else\\|when\\|otherwise\\)\\>") 408 (not (simula-context)))
238 (not (simula-context))) 409 ;; yes - reindent
239 ;; yes - reindent 410 (let ((post-indent (simula-calculate-indent)))
240 (let ((post-indent (simula-calculate-indent))) 411 (if (eq (current-indentation) post-indent)
241 (if (eq (current-indentation) post-indent) 412 ()
242 () 413 (delete-horizontal-space)
243 (delete-horizontal-space) 414 (indent-to post-indent))))))
244 (indent-to post-indent)))))))
245 (goto-char (- (point-max) origin)) 415 (goto-char (- (point-max) origin))
246 (if (eq (current-indentation) indent) 416 (if (eq (current-indentation) indent)
247 (back-to-indentation) 417 (back-to-indentation)
@@ -364,14 +534,22 @@ The relative indentation among the lines of the statement are preserved."
364 (cond 534 (cond
365 ((memq (preceding-char) '(?d ?D)) 535 ((memq (preceding-char) '(?d ?D))
366 (setq return-value 2) 536 (setq return-value 2)
367 (while (and (memq (preceding-char) '(?d ?D)) (not return-value)) 537 (while (and (re-search-forward
368 (while (and (re-search-forward 538 ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>\\|^%"
369 ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>\\|^%" 539 origin 'move)
370 origin 'move) 540 ;; found another END?
371 (eq (preceding-char) ?%)) 541 (or (memq (preceding-char) '(?d ?D))
372 (beginning-of-line 2))) 542 ;; if directive, skip line
373 (if (looking-at "[ \t\n\f]*\\(;\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>\\)") 543 (and (eq (preceding-char) ?%)
374 (setq return-value nil))) 544 (beginning-of-line 2))
545 ;; found other keyword, out of END comment
546 (setq return-value nil))))
547 (if (and (eq (char-syntax (preceding-char)) ?w)
548 (eq (char-syntax (following-char)) ?w))
549 (save-excursion
550 (backward-word 1)
551 (if (looking-at "end\\>\\|else\\>\\|otherwise\\>\\|when\\>")
552 (setq return-value nil)))))
375 ((memq (preceding-char) '(?! ?t ?T)) 553 ((memq (preceding-char) '(?! ?t ?T))
376 ; skip comment 554 ; skip comment
377 (setq return-value 0) 555 (setq return-value 0)
@@ -406,10 +584,11 @@ The relative indentation among the lines of the statement are preserved."
406 (let ((origin (- (point-max) (point))) 584 (let ((origin (- (point-max) (point)))
407 (case-fold-search t) 585 (case-fold-search t)
408 ;; don't mix a label with an assignment operator := :- 586 ;; don't mix a label with an assignment operator := :-
409 ;; therefore look at next typed character... 587 ;; therefore take a peek at next typed character...
410 (next-char (setq unread-command-events (list (read-event)))) 588 (next-char (read-event)))
411 (com-char last-command-char))
412 (unwind-protect 589 (unwind-protect
590 (setq unread-command-events (append unread-command-events
591 (list next-char)))
413 ;; Problem: find out if character just read is a command char 592 ;; Problem: find out if character just read is a command char
414 ;; that would insert something after ':' making it a label. 593 ;; that would insert something after ':' making it a label.
415 ;; At least \n, \r (and maybe \t) falls into this category. 594 ;; At least \n, \r (and maybe \t) falls into this category.
@@ -516,6 +695,7 @@ If COUNT is negative, move forward instead."
516 (case-fold-search t) 695 (case-fold-search t)
517 (origin (point))) 696 (origin (point)))
518 (condition-case () 697 (condition-case ()
698 ;;
519 (progn 699 (progn
520 (simula-skip-comment-backward) 700 (simula-skip-comment-backward)
521 (if (memq (preceding-char) '(?n ?N)) 701 (if (memq (preceding-char) '(?n ?N))
@@ -524,7 +704,8 @@ If COUNT is negative, move forward instead."
524 (if (not (looking-at "\\<begin\\>")) 704 (if (not (looking-at "\\<begin\\>"))
525 (backward-word -1))) 705 (backward-word -1)))
526 (if (eq (preceding-char) ?\;) 706 (if (eq (preceding-char) ?\;)
527 (backward-char 1))) 707 (backward-char 1))
708 )
528 (while (and (natnump (setq count (1- count))) 709 (while (and (natnump (setq count (1- count)))
529 (setq status (simula-search-backward 710 (setq status (simula-search-backward
530 ";\\|\\<begin\\>" nil 'move)))) 711 ";\\|\\<begin\\>" nil 'move))))
@@ -564,7 +745,7 @@ If COUNT is negative, move backward instead."
564 (quit (progn (goto-char origin) (signal 'quit nil))))))) 745 (quit (progn (goto-char origin) (signal 'quit nil)))))))
565 746
566 747
567(defun simula-skip-comment-backward () 748(defun simula-skip-comment-backward (&optional stop-at-end)
568 "Search towards bob to find first char that is outside a comment." 749 "Search towards bob to find first char that is outside a comment."
569 (interactive) 750 (interactive)
570 (catch 'simula-out 751 (catch 'simula-out
@@ -574,7 +755,9 @@ If COUNT is negative, move backward instead."
574 (if (eq (preceding-char) ?\;) 755 (if (eq (preceding-char) ?\;)
575 (save-excursion 756 (save-excursion
576 (backward-char 1) 757 (backward-char 1)
577 (setq context (simula-context))) 758 (setq context (simula-context))
759 (if (and stop-at-end (eq context 2))
760 (setq context nil)))
578 (setq context (simula-context))) 761 (setq context (simula-context)))
579 (cond 762 (cond
580 ((memq context '(nil 3 4)) 763 ((memq context '(nil 3 4))
@@ -591,9 +774,10 @@ If COUNT is negative, move backward instead."
591 (while (and (re-search-backward "!\\|\\<comment\\>") 774 (while (and (re-search-backward "!\\|\\<comment\\>")
592 (memq (simula-context) '(0 1))))) 775 (memq (simula-context) '(0 1)))))
593 ((eq context 1) 776 ((eq context 1)
594 (end-of-line 0) 777 (beginning-of-line)
595 (if (bobp) 778 (if (bobp)
596 (throw 'simula-out nil))) 779 (throw 'simula-out nil)
780 (backward-char)))
597 ((eq context 2) 781 ((eq context 2)
598 ;; an END-comment must belong to an END 782 ;; an END-comment must belong to an END
599 (re-search-backward "\\<end\\>") 783 (re-search-backward "\\<end\\>")
@@ -610,6 +794,8 @@ If COUNT is negative, move backward instead."
610 (catch 'simula-out 794 (catch 'simula-out
611 (while t 795 (while t
612 (skip-chars-forward " \t\n\f") 796 (skip-chars-forward " \t\n\f")
797 ;; BUG: the following (0 2) branches don't take into account intermixing
798 ;; directive lines
613 (cond 799 (cond
614 ((looking-at "!\\|\\<comment\\>") 800 ((looking-at "!\\|\\<comment\\>")
615 (search-forward ";" nil 'move)) 801 (search-forward ";" nil 'move))
@@ -666,6 +852,11 @@ If COUNT is negative, move backward instead."
666 (prog1 852 (prog1
667 (current-column) 853 (current-column)
668 (goto-char origin))) 854 (goto-char origin)))
855 ((eq where 1)
856 ;;
857 ;; Directive. Always 0.
858 ;;
859 0)
669 ;; 860 ;;
670 ;; Detect missing string delimiters 861 ;; Detect missing string delimiters
671 ;; 862 ;;
@@ -722,7 +913,7 @@ If COUNT is negative, move backward instead."
722 (looking-at "[a-z0-9_]*[ \t\f]*:[^-=]")) 913 (looking-at "[a-z0-9_]*[ \t\f]*:[^-=]"))
723 (setq indent simula-label-offset))) 914 (setq indent simula-label-offset)))
724 ;; find line with non-comment text 915 ;; find line with non-comment text
725 (simula-skip-comment-backward) 916 (simula-skip-comment-backward 'dont-skip-end)
726 (if (and found-end 917 (if (and found-end
727 (not (eq (preceding-char) ?\;)) 918 (not (eq (preceding-char) ?\;))
728 (if (memq (preceding-char) '(?N ?n)) 919 (if (memq (preceding-char) '(?N ?n))
@@ -933,7 +1124,14 @@ If COUNT is negative, move backward instead."
933 (cond 1124 (cond
934 ((eq simula-abbrev-stdproc 'upcase) (upcase-word -1)) 1125 ((eq simula-abbrev-stdproc 'upcase) (upcase-word -1))
935 ((eq simula-abbrev-stdproc 'downcase) (downcase-word -1)) 1126 ((eq simula-abbrev-stdproc 'downcase) (downcase-word -1))
936 ((eq simula-abbrev-stdproc 'capitalize) (capitalize-word -1))))) 1127 ((eq simula-abbrev-stdproc 'capitalize) (capitalize-word -1))
1128 ((eq simula-abbrev-stdproc 'abbrev-table)
1129 ;; If not in lowercase, expansions are always capitalized.
1130 ;; We then want to replace with the exact expansion.
1131 (if (equal (symbol-name last-abbrev) last-abbrev-text)
1132 ()
1133 (downcase-word -1)
1134 (expand-abbrev))))))
937 1135
938 1136
939(defun simula-expand-keyword () 1137(defun simula-expand-keyword ()
@@ -942,7 +1140,12 @@ If COUNT is negative, move backward instead."
942 (cond 1140 (cond
943 ((eq simula-abbrev-keyword 'upcase) (upcase-word -1)) 1141 ((eq simula-abbrev-keyword 'upcase) (upcase-word -1))
944 ((eq simula-abbrev-keyword 'downcase) (downcase-word -1)) 1142 ((eq simula-abbrev-keyword 'downcase) (downcase-word -1))
945 ((eq simula-abbrev-keyword 'capitalize) (capitalize-word -1))))) 1143 ((eq simula-abbrev-keyword 'capitalize) (capitalize-word -1))
1144 ((eq simula-abbrev-stdproc 'abbrev-table)
1145 (if (equal (symbol-name last-abbrev) last-abbrev-text)
1146 ()
1147 (downcase-word -1)
1148 (expand-abbrev))))))
946 1149
947 1150
948(defun simula-electric-keyword () 1151(defun simula-electric-keyword ()
@@ -1007,48 +1210,125 @@ If COUNT is negative, move backward instead."
1007 (quit (goto-char (- (point-max) pos)))))))) 1210 (quit (goto-char (- (point-max) pos))))))))
1008 1211
1009 1212
1010(defun simula-search-backward (string &optional limit move) 1213(defun simula-search-backward (regexp &optional bound noerror)
1011 (setq string (concat string "\\|\\<end\\>")) 1214 "Search backward from point for regular expression REGEXP, ignoring matches
1012 (let (level) 1215found inside SIMULA comments, string literals, and BEGIN..END blocks.
1013 (catch 'simula-out 1216Set point to the end of the occurrence found, and return point.
1014 (while (re-search-backward string limit move) 1217An optional second argument BOUND bounds the search, it is a buffer position.
1015 (if (simula-context) 1218The match found must not extend after that position. Optional third argument
1016 () 1219NOERROR, if t, means if fail just return nil (no error).
1017 (if (looking-at "\\<end\\>") 1220If not nil and not t, move to limit of search and return nil."
1018 (progn 1221 (let (begin end context (comb-regexp (concat regexp "\\|\\<end\\>"))
1019 (setq level 0) 1222 match (start-point (point)))
1020 (while (natnump level) 1223 (catch 'simula-backward
1021 (re-search-backward "\\<begin\\>\\|\\<end\\>") 1224 (while (re-search-backward comb-regexp bound 1)
1022 (if (simula-context) 1225 ;; We have a match, check SIMULA context at match-beginning
1023 () 1226 ;; to see if we are outside comments etc.
1024 (setq level (if (memq (following-char) '(?b ?B)) 1227 ;; Set MATCH to t if we found a true match,
1025 (1- level) 1228 ;; set MATCH to 'BLOCK if we found a BEGIN..END block,
1026 (1+ level)))))) 1229 ;; else set MATCH to nil.
1027 (throw 'simula-out t))))))) 1230 (save-match-data
1028 1231 (setq context (simula-context))
1029 1232 (cond
1030(defun simula-search-forward (string &optional limit move) 1233 ((eq context nil)
1031 (setq string (concat string "\\|\\<begin\\>")) 1234 (setq match (if (looking-at regexp) t 'BLOCK)))
1032 (let (level) 1235;;; A comment-ending semicolon is part of the comment, and shouldn't match.
1033 (catch 'exit 1236;;; ((eq context 0)
1034 (while (re-search-forward string limit move) 1237;;; (setq match (if (eq (following-char) ?\;) t nil)))
1035 (goto-char (match-beginning 0)) 1238 ((eq context 2)
1036 (if (simula-context) 1239 (setq match (if (and (looking-at regexp)
1037 (goto-char (1- (match-end 0))) 1240 (looking-at ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>"))
1038 (if (looking-at "\\<begin\\>") 1241 t
1039 (progn 1242 (if (looking-at "\\<end\\>") 'BLOCK nil))))
1040 (goto-char (1- (match-end 0))) 1243 (t (setq match nil))))
1041 (setq level 0) 1244 ;; Exit if true match
1042 (while (natnump level) 1245 (if (eq match t) (throw 'simula-backward (point)))
1043 (re-search-forward "\\<begin\\>\\|\\<end\\>") 1246 (if (eq match 'BLOCK)
1044 (backward-word 1) 1247 ;; We found the END of a block
1045 (if (not (simula-context)) 1248 (let ((level 0))
1046 (setq level (if (memq (following-char) '(?e ?E)) 1249 (while (natnump level)
1047 (1- level) 1250 (if (re-search-backward "\\<begin\\>\\|\\<end\\>" bound 1)
1048 (1+ level)))) 1251 (let ((context (simula-context)))
1049 (backward-word -1))) 1252 ;; We found a BEGIN -> decrease level count
1050 (goto-char (1- (match-end 0))) 1253 (cond ((and (eq context nil)
1051 (throw 'exit t))))))) 1254 (memq (following-char) '(?b ?B)))
1255 (setq level (1- level)))
1256 ;; END -> increase level count
1257 ((and (memq context '(nil 2))
1258 (memq (following-char) '(?e ?E)))
1259 (setq level (1+ level)))))
1260 ;; Block search failed. Action depends on noerror.
1261 (if (or (not noerror) (eq noerror t))
1262 (goto-char start-point))
1263 (if (not noerror)
1264 (signal 'search-failed (list regexp)))
1265 (throw 'simula-backward nil))))))
1266 ;; Search failed. Action depends on noerror.
1267 (if (or (not noerror) (eq noerror t))
1268 (goto-char start-point))
1269 (if noerror
1270 nil
1271 (signal 'search-failed (list regexp))))))
1272
1273
1274(defun simula-search-forward (regexp &optional bound noerror)
1275 "Search forward from point for regular expression REGEXP, ignoring matches
1276found inside SIMULA comments, string literals, and BEGIN..END blocks.
1277Set point to the end of the occurrence found, and return point.
1278An optional second argument BOUND bounds the search, it is a buffer position.
1279The match found must not extend after that position. Optional third argument
1280NOERROR, if t, means if fail just return nil (no error).
1281If not nil and not t, move to limit of search and return nil."
1282 (let (begin end context (comb-regexp (concat regexp "\\|\\<begin\\>"))
1283 match (start-point (point)))
1284 (catch 'simula-forward
1285 (while (re-search-forward comb-regexp bound 1)
1286 ;; We have a match, check SIMULA context at match-beginning
1287 ;; to see if we are outside comments.
1288 ;; Set MATCH to t if we found a true match,
1289 ;; set MATCH to 'BLOCK if we found a BEGIN..END block,
1290 ;; else set MATCH to nil.
1291 (save-match-data
1292 (save-excursion
1293 (goto-char (match-beginning 0))
1294 (setq context (simula-context))
1295 (cond
1296 ((not context)
1297 (setq match (if (looking-at regexp) t 'BLOCK)))
1298;;; A comment-ending semicolon is part of the comment, and shouldn't match.
1299;;; ((eq context 0)
1300;;; (setq match (if (eq (following-char) ?\;) t nil)))
1301 ((eq context 2)
1302 (setq match (if (and (looking-at regexp)
1303 (looking-at ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>")) t nil)))
1304 (t (setq match nil)))))
1305 ;; Exit if true match
1306 (if (eq match t) (throw 'simula-forward (point)))
1307 (if (eq match 'BLOCK)
1308 ;; We found the BEGINning of a block
1309 (let ((level 0))
1310 (while (natnump level)
1311 (if (re-search-forward "\\<begin\\>\\|\\<end\\>" bound 1)
1312 (let ((context (simula-context)))
1313 ;; We found a BEGIN -> increase level count
1314 (cond ((eq context nil) (setq level (1+ level)))
1315 ;; END -> decrease level count
1316 ((and (eq context 2)
1317 ;; Don't match BEGIN inside END comment
1318 (memq (preceding-char) '(?d ?D)))
1319 (setq level (1- level)))))
1320 ;; Block search failed. Action depends on noerror.
1321 (if (or (not noerror) (eq noerror t))
1322 (goto-char start-point))
1323 (if (not noerror)
1324 (signal 'search-failed (list regexp)))
1325 (throw 'simula-forward nil))))))
1326 ;; Search failed. Action depends on noerror.
1327 (if (or (not noerror) (eq noerror t))
1328 (goto-char start-point))
1329 (if noerror
1330 nil
1331 (signal 'search-failed (list regexp))))))
1052 1332
1053 1333
1054(defun simula-install-standard-abbrevs () 1334(defun simula-install-standard-abbrevs ()
@@ -1288,4 +1568,116 @@ If COUNT is negative, move backward instead."
1288 ("when" "WHEN" simula-electric-keyword) 1568 ("when" "WHEN" simula-electric-keyword)
1289 ("while" "WHILE" simula-expand-keyword)))) 1569 ("while" "WHILE" simula-expand-keyword))))
1290 1570
1571(if (and (fboundp 'hilit-set-mode-patterns)
1572 (boundp 'hilit-patterns-alist)
1573 (not (assoc 'simula-mode hilit-patterns-alist)))
1574 (hilit-set-mode-patterns
1575 'simula-mode
1576 '(
1577 ("^%\\([ \t\f].*\\)?$" nil comment)
1578 ("^%include\\>" nil include)
1579 ("\"[^\"\n]*\"\\|'.'\\|'![0-9]+!'" nil string)
1580 ("\\<\\(ACTIVATE\\|AFTER\\|AND\\|ARRAY\\|AT\\|BEFORE\\|BEGIN\\|BOOLEAN\\|CHARACTER\\|CLASS\\|DELAY\\|DO\\|ELSE\\|END\\|EQ\\|EQV\\|EXTERNAL\\|FALSE\\|FOR\\|GE\\|GO\\|GOTO\\|GT\\|HIDDEN\\|IF\\|IMP\\|IN\\|INNER\\|INSPECT\\|INTEGER\\|IS\\|LABEL\\|LE\\|LONG\\|LT\\|NAME\\|NE\\|NEW\\|NONE\\|NOT\\|NOTEXT\\|OR\\|OTHERWISE\\|PRIOR\\|PROCEDURE\\|PROTECTED\\|QUA\\|REACTIVATE\\|REAL\\|REF\\|SHORT\\|STEP\\|SWITCH\\|TEXT\\|THEN\\|THIS\\|TO\\|TRUE\\|UNTIL\\|VALUE\\|VIRTUAL\\|WHEN\\|WHILE\\)\\>" nil keyword)
1581 ("!\\|\\<COMMENT\\>" ";" comment))
1582 nil 'case-insensitive))
1583
1584(setq simula-find-comment-point -1
1585 simula-find-comment-context nil)
1586
1587;; function used by hilit19
1588(defun simula-find-next-comment-region (param)
1589 "Return region (start end) cons of comment after point, or NIL"
1590 (let (start end)
1591 ;; This function is called repeatedly, check if point is
1592 ;; where we left it in the last call
1593 (if (not (eq simula-find-comment-point (point)))
1594 (setq simula-find-comment-point (point)
1595 simula-find-comment-context (simula-context)))
1596 ;; loop as long as we haven't found the end of a comment
1597 (if (memq simula-find-comment-context '(0 1 2))
1598 (setq start (point))
1599 (if (re-search-forward "\\<end\\>\\|!\\|\"\\|'\\|^%\\|\\<comment\\>"
1600 nil 'move)
1601 (let ((previous-char (preceding-char)))
1602 (cond
1603 ((memq previous-char '(?d ?D))
1604 (setq start (point)
1605 simula-find-comment-context 2))
1606 ((memq previous-char '(?t ?T ?\!))
1607 (setq start (point)
1608 simula-find-comment-context 0))
1609 ((eq previous-char ?%)
1610 (setq start (point)
1611 simula-find-comment-context 0))))))
1612 ;; BUG: the following (0 2) branches don't take into account intermixing
1613 ;; directive lines
1614 (cond
1615 ((eq simula-find-comment-context 0)
1616 (search-forward ";" nil 'move))
1617 ((eq simula-find-comment-context 1)
1618 (beginning-of-line 2))
1619 ((eq simula-find-comment-context 2)
1620 (re-search-forward ";\\|\\<end\\>\\|\\<else\\>\\|\\<otherwise\\>\\|\\<when\\>\\" (point-max) 'move)))
1621 (if start
1622 (setq end (point)))
1623 ;; save point for later calls to this function
1624 (setq simula-find-comment-point (if end (point) -1))
1625 (and end (cons start end))))
1626
1627(if (not (fboundp 'save-match-data))
1628 (defmacro save-match-data (&rest body)
1629 "Execute the BODY forms, restoring the global value of the match data."
1630 (let ((original (make-symbol "match-data")))
1631 (list
1632 'let (list (list original '(match-data)))
1633 (list 'unwind-protect
1634 (cons 'progn body)
1635 (list 'store-match-data original))))))
1636
1637
1638;; defuns for submitting bug reports
1639
1640(defconst simula-version "0.994"
1641 "simula-mode version number.")
1642(defconst simula-mode-help-address "simula-mode@ifi.uio.no"
1643 "Address accepting submission of simula-mode bug reports.")
1644
1645(defun simula-version ()
1646 "Echo the current version of simula-mode in the minibuffer."
1647 (interactive)
1648 (message "Using simula-mode version %s" simula-version)
1649 (simula-keep-region-active))
1650
1651;; get reporter-submit-bug-report when byte-compiling
1652(and (fboundp 'eval-when-compile)
1653 (eval-when-compile
1654 (require 'reporter)))
1655
1656(defun simula-submit-bug-report ()
1657 "Submit via mail a bug report on simula-mode."
1658 (interactive)
1659 (and
1660 (y-or-n-p "Do you want to submit a report on simula-mode? ")
1661 (require 'reporter)
1662 (reporter-submit-bug-report
1663 simula-mode-help-address
1664 (concat "simula-mode " simula-version)
1665 (list
1666 ;; report only the vars that affect indentation
1667 'simula-emacs-features
1668 'simula-indent-level
1669 'simula-substatement-offset
1670 'simula-continued-statement-offset
1671 'simula-label-offset
1672 'simula-if-indent
1673 'simula-inspect-indent
1674 'simula-electric-indent
1675 'simula-abbrev-keyword
1676 'simula-abbrev-stdproc
1677 'simula-abbrev-file
1678 'simula-tab-always-indent
1679 ))))
1680
1681(provide 'simula-mode)
1682
1291;;; simula.el ends here 1683;;; simula.el ends here