|
|
1.1 root 1: ;; Note: use
2: ;; (autoload 'icon-mode "icon" nil t)
3: ;; (setq auto-mode-alist (cons '("\\.icn$" . icon-mode) auto-mode-alist))
4: ;; if not permanently installed in your emacs
5:
6: ;; Icon code editing commands for Emacs
7: ;; from c-mode.el 13-Apr-88 Chris Smith; bugs to convex!csmith
8: ;; Copyright (C) 1988 Free Software Foundation, Inc.
9:
10: ;; This file is part of GNU Emacs.
11:
12: ;; GNU Emacs is free software; you can redistribute it and/or modify
13: ;; it under the terms of the GNU General Public License as published by
14: ;; the Free Software Foundation; either version 1, or (at your option)
15: ;; any later version.
16:
17: ;; GNU Emacs is distributed in the hope that it will be useful,
18: ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19: ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20: ;; GNU General Public License for more details.
21:
22: ;; You should have received a copy of the GNU General Public License
23: ;; along with GNU Emacs; see the file COPYING. If not, write to
24: ;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
25:
26:
27: (defvar icon-mode-abbrev-table nil
28: "Abbrev table in use in Icon-mode buffers.")
29: (define-abbrev-table 'icon-mode-abbrev-table ())
30:
31: (defvar icon-mode-map ()
32: "Keymap used in Icon mode.")
33: (if icon-mode-map
34: ()
35: (setq icon-mode-map (make-sparse-keymap))
36: (define-key icon-mode-map "{" 'electric-icon-brace)
37: (define-key icon-mode-map "}" 'electric-icon-brace)
38: (define-key icon-mode-map "\e\C-h" 'mark-icon-function)
39: (define-key icon-mode-map "\e\C-a" 'beginning-of-icon-defun)
40: (define-key icon-mode-map "\e\C-e" 'end-of-icon-defun)
41: (define-key icon-mode-map "\e\C-q" 'indent-icon-exp)
42: (define-key icon-mode-map "\177" 'backward-delete-char-untabify)
43: (define-key icon-mode-map "\t" 'icon-indent-command))
44:
45: (defvar icon-mode-syntax-table nil
46: "Syntax table in use in Icon-mode buffers.")
47:
48: (if icon-mode-syntax-table
49: ()
50: (setq icon-mode-syntax-table (make-syntax-table))
51: (modify-syntax-entry ?\\ "\\" icon-mode-syntax-table)
52: (modify-syntax-entry ?# "<" icon-mode-syntax-table)
53: (modify-syntax-entry ?\n ">" icon-mode-syntax-table)
54: (modify-syntax-entry ?$ "." icon-mode-syntax-table)
55: (modify-syntax-entry ?/ "." icon-mode-syntax-table)
56: (modify-syntax-entry ?* "." icon-mode-syntax-table)
57: (modify-syntax-entry ?+ "." icon-mode-syntax-table)
58: (modify-syntax-entry ?- "." icon-mode-syntax-table)
59: (modify-syntax-entry ?= "." icon-mode-syntax-table)
60: (modify-syntax-entry ?% "." icon-mode-syntax-table)
61: (modify-syntax-entry ?< "." icon-mode-syntax-table)
62: (modify-syntax-entry ?> "." icon-mode-syntax-table)
63: (modify-syntax-entry ?& "." icon-mode-syntax-table)
64: (modify-syntax-entry ?| "." icon-mode-syntax-table)
65: (modify-syntax-entry ?\' "\"" icon-mode-syntax-table))
66:
67: (defconst icon-indent-level 4
68: "*Indentation of Icon statements with respect to containing block.")
69: (defconst icon-brace-imaginary-offset 0
70: "*Imagined indentation of a Icon open brace that actually follows a statement.")
71: (defconst icon-brace-offset 0
72: "*Extra indentation for braces, compared with other text in same context.")
73: (defconst icon-continued-statement-offset 4
74: "*Extra indent for lines not starting new statements.")
75: (defconst icon-continued-brace-offset 0
76: "*Extra indent for substatements that start with open-braces.
77: This is in addition to icon-continued-statement-offset.")
78:
79: (defconst icon-auto-newline nil
80: "*Non-nil means automatically newline before and after braces,
81: and after colons and semicolons, inserted in C code.")
82:
83: (defconst icon-tab-always-indent t
84: "*Non-nil means TAB in Icon mode should always reindent the current line,
85: regardless of where in the line point is when the TAB command is used.")
86:
87: (defun icon-mode ()
88: "Major mode for editing Icon code.
89: Expression and list commands understand all Icon brackets.
90: Tab indents for Icon code.
91: Paragraphs are separated by blank lines only.
92: Delete converts tabs to spaces as it moves back.
93: \\{icon-mode-map}
94: Variables controlling indentation style:
95: icon-tab-always-indent
96: Non-nil means TAB in Icon mode should always reindent the current line,
97: regardless of where in the line point is when the TAB command is used.
98: icon-auto-newline
99: Non-nil means automatically newline before and after braces
100: inserted in Icon code.
101: icon-indent-level
102: Indentation of Icon statements within surrounding block.
103: The surrounding block's indentation is the indentation
104: of the line on which the open-brace appears.
105: icon-continued-statement-offset
106: Extra indentation given to a substatement, such as the
107: then-clause of an if or body of a while.
108: icon-continued-brace-offset
109: Extra indentation given to a brace that starts a substatement.
110: This is in addition to icon-continued-statement-offset.
111: icon-brace-offset
112: Extra indentation for line if it starts with an open brace.
113: icon-brace-imaginary-offset
114: An open brace following other text is treated as if it were
115: this far to the right of the start of its line.
116:
117: Turning on Icon mode calls the value of the variable icon-mode-hook with no args,
118: if that value is non-nil."
119: (interactive)
120: (kill-all-local-variables)
121: (use-local-map icon-mode-map)
122: (setq major-mode 'icon-mode)
123: (setq mode-name "Icon")
124: (setq local-abbrev-table icon-mode-abbrev-table)
125: (set-syntax-table icon-mode-syntax-table)
126: (make-local-variable 'paragraph-start)
127: (setq paragraph-start (concat "^$\\|" page-delimiter))
128: (make-local-variable 'paragraph-separate)
129: (setq paragraph-separate paragraph-start)
130: (make-local-variable 'indent-line-function)
131: (setq indent-line-function 'icon-indent-line)
132: (make-local-variable 'require-final-newline)
133: (setq require-final-newline t)
134: (make-local-variable 'comment-start)
135: (setq comment-start "# ")
136: (make-local-variable 'comment-end)
137: (setq comment-end "")
138: (make-local-variable 'comment-column)
139: (setq comment-column 32)
140: (make-local-variable 'comment-start-skip)
141: (setq comment-start-skip "# *")
142: (make-local-variable 'comment-indent-hook)
143: (setq comment-indent-hook 'icon-comment-indent)
144: (run-hooks 'icon-mode-hook))
145:
146: ;; This is used by indent-for-comment
147: ;; to decide how much to indent a comment in Icon code
148: ;; based on its context.
149: (defun icon-comment-indent ()
150: (if (looking-at "^#")
151: 0 ;Existing comment at bol stays there.
152: (save-excursion
153: (skip-chars-backward " \t")
154: (max (1+ (current-column)) ;Else indent at comment column
155: comment-column)))) ; except leave at least one space.
156:
157: (defun electric-icon-brace (arg)
158: "Insert character and correct line's indentation."
159: (interactive "P")
160: (let (insertpos)
161: (if (and (not arg)
162: (eolp)
163: (or (save-excursion
164: (skip-chars-backward " \t")
165: (bolp))
166: (if icon-auto-newline
167: (progn (icon-indent-line) (newline) t)
168: nil)))
169: (progn
170: (insert last-command-char)
171: (icon-indent-line)
172: (if icon-auto-newline
173: (progn
174: (newline)
175: ;; (newline) may have done auto-fill
176: (setq insertpos (- (point) 2))
177: (icon-indent-line)))
178: (save-excursion
179: (if insertpos (goto-char (1+ insertpos)))
180: (delete-char -1))))
181: (if insertpos
182: (save-excursion
183: (goto-char insertpos)
184: (self-insert-command (prefix-numeric-value arg)))
185: (self-insert-command (prefix-numeric-value arg)))))
186:
187: (defun icon-indent-command (&optional whole-exp)
188: (interactive "P")
189: "Indent current line as Icon code, or in some cases insert a tab character.
190: If icon-tab-always-indent is non-nil (the default), always indent current line.
191: Otherwise, indent the current line only if point is at the left margin
192: or in the line's indentation; otherwise insert a tab.
193:
194: A numeric argument, regardless of its value,
195: means indent rigidly all the lines of the expression starting after point
196: so that this line becomes properly indented.
197: The relative indentation among the lines of the expression are preserved."
198: (if whole-exp
199: ;; If arg, always indent this line as Icon
200: ;; and shift remaining lines of expression the same amount.
201: (let ((shift-amt (icon-indent-line))
202: beg end)
203: (save-excursion
204: (if icon-tab-always-indent
205: (beginning-of-line))
206: (setq beg (point))
207: (forward-sexp 1)
208: (setq end (point))
209: (goto-char beg)
210: (forward-line 1)
211: (setq beg (point)))
212: (if (> end beg)
213: (indent-code-rigidly beg end shift-amt "#")))
214: (if (and (not icon-tab-always-indent)
215: (save-excursion
216: (skip-chars-backward " \t")
217: (not (bolp))))
218: (insert-tab)
219: (icon-indent-line))))
220:
221: (defun icon-indent-line ()
222: "Indent current line as Icon code.
223: Return the amount the indentation changed by."
224: (let ((indent (calculate-icon-indent nil))
225: beg shift-amt
226: (case-fold-search nil)
227: (pos (- (point-max) (point))))
228: (beginning-of-line)
229: (setq beg (point))
230: (cond ((eq indent nil)
231: (setq indent (current-indentation)))
232: ((eq indent t)
233: (setq indent (calculate-icon-indent-within-comment)))
234: ((looking-at "[ \t]*#")
235: (setq indent 0))
236: (t
237: (skip-chars-forward " \t")
238: (if (listp indent) (setq indent (car indent)))
239: (cond ((and (looking-at "else\\b")
240: (not (looking-at "else\\s_")))
241: (setq indent (save-excursion
242: (icon-backward-to-start-of-if)
243: (current-indentation))))
244: ((or (= (following-char) ?})
245: (looking-at "end\\b"))
246: (setq indent (- indent icon-indent-level)))
247: ((= (following-char) ?{)
248: (setq indent (+ indent icon-brace-offset))))))
249: (skip-chars-forward " \t")
250: (setq shift-amt (- indent (current-column)))
251: (if (zerop shift-amt)
252: (if (> (- (point-max) pos) (point))
253: (goto-char (- (point-max) pos)))
254: (delete-region beg (point))
255: (indent-to indent)
256: ;; If initial point was within line's indentation,
257: ;; position after the indentation. Else stay at same point in text.
258: (if (> (- (point-max) pos) (point))
259: (goto-char (- (point-max) pos))))
260: shift-amt))
261:
262: (defun calculate-icon-indent (&optional parse-start)
263: "Return appropriate indentation for current line as Icon code.
264: In usual case returns an integer: the column to indent to.
265: Returns nil if line starts inside a string, t if in a comment."
266: (save-excursion
267: (beginning-of-line)
268: (let ((indent-point (point))
269: (case-fold-search nil)
270: state
271: containing-sexp
272: toplevel)
273: (if parse-start
274: (goto-char parse-start)
275: (setq toplevel (beginning-of-icon-defun)))
276: (while (< (point) indent-point)
277: (setq parse-start (point))
278: (setq state (parse-partial-sexp (point) indent-point 0))
279: (setq containing-sexp (car (cdr state))))
280: (cond ((or (nth 3 state) (nth 4 state))
281: ;; return nil or t if should not change this line
282: (nth 4 state))
283: ((and containing-sexp
284: (/= (char-after containing-sexp) ?{))
285: ;; line is expression, not statement:
286: ;; indent to just after the surrounding open.
287: (goto-char (1+ containing-sexp))
288: (current-column))
289: (t
290: ;; Statement level. Is it a continuation or a new statement?
291: ;; Find previous non-comment character.
292: (if toplevel
293: (progn (icon-backward-to-noncomment (point-min))
294: (if (icon-is-continuation-line)
295: icon-continued-statement-offset 0))
296: (if (null containing-sexp)
297: (progn (beginning-of-icon-defun)
298: (setq containing-sexp (point))))
299: (goto-char indent-point)
300: (icon-backward-to-noncomment containing-sexp)
301: ;; Now we get the answer.
302: (if (icon-is-continuation-line)
303: ;; This line is continuation of preceding line's statement;
304: ;; indent icon-continued-statement-offset more than the
305: ;; first line of the statement.
306: (progn
307: (icon-backward-to-start-of-continued-exp containing-sexp)
308: (+ icon-continued-statement-offset (current-column)
309: (if (save-excursion (goto-char indent-point)
310: (skip-chars-forward " \t")
311: (eq (following-char) ?{))
312: icon-continued-brace-offset 0)))
313: ;; This line starts a new statement.
314: ;; Position following last unclosed open.
315: (goto-char containing-sexp)
316: ;; Is line first statement after an open-brace?
317: (or
318: ;; If no, find that first statement and indent like it.
319: (save-excursion
320: (if (looking-at "procedure\\s ")
321: (forward-sexp 3)
322: (forward-char 1))
323: (while (progn (skip-chars-forward " \t\n")
324: (looking-at "#"))
325: ;; Skip over comments following openbrace.
326: (forward-line 1))
327: ;; The first following code counts
328: ;; if it is before the line we want to indent.
329: (and (< (point) indent-point)
330: (current-column)))
331: ;; If no previous statement,
332: ;; indent it relative to line brace is on.
333: ;; For open brace in column zero, don't let statement
334: ;; start there too. If icon-indent-level is zero,
335: ;; use icon-brace-offset + icon-continued-statement-offset instead.
336: ;; For open-braces not the first thing in a line,
337: ;; add in icon-brace-imaginary-offset.
338: (+ (if (and (bolp) (zerop icon-indent-level))
339: (+ icon-brace-offset icon-continued-statement-offset)
340: icon-indent-level)
341: ;; Move back over whitespace before the openbrace.
342: ;; If openbrace is not first nonwhite thing on the line,
343: ;; add the icon-brace-imaginary-offset.
344: (progn (skip-chars-backward " \t")
345: (if (bolp) 0 icon-brace-imaginary-offset))
346: ;; here we are
347: (current-indentation))))))))))
348:
349: (defun icon-is-continuation-line ()
350: (let* ((ch (preceding-char))
351: (ch-syntax (char-syntax ch)))
352: (if (eq ch-syntax ?w)
353: (assoc (buffer-substring
354: (progn (forward-word -1) (point))
355: (progn (forward-word 1) (point)))
356: '(("do") ("dynamic") ("else") ("initial") ("link")
357: ("local") ("of") ("static") ("then")))
358: (not (memq ch '(0 ?\; ?\} ?\{ ?\) ?\] ?\" ?\' ?\n))))))
359:
360: (defun icon-backward-to-noncomment (lim)
361: (let (opoint stop)
362: (while (not stop)
363: (skip-chars-backward " \t\n\f" lim)
364: (setq opoint (point))
365: (beginning-of-line)
366: (if (and (search-forward "#" opoint 'move)
367: (< lim (point)))
368: (forward-char -1)
369: (setq stop t)))))
370:
371: (defun icon-backward-to-start-of-continued-exp (lim)
372: (if (memq (preceding-char) '(?\) ?\]))
373: (forward-sexp -1))
374: (while (icon-is-continued-line)
375: (end-of-line 0))
376: (beginning-of-line)
377: (if (<= (point) lim)
378: (goto-char (1+ lim)))
379: (skip-chars-forward " \t"))
380:
381: (defun icon-is-continued-line ()
382: (save-excursion
383: (end-of-line 0)
384: (icon-is-continuation-line)))
385:
386: (defun icon-backward-to-start-of-if (&optional limit)
387: "Move to the start of the last ``unbalanced'' if."
388: (or limit (setq limit (save-excursion (beginning-of-icon-defun) (point))))
389: (let ((if-level 1)
390: (case-fold-search nil))
391: (while (not (zerop if-level))
392: (backward-sexp 1)
393: (cond ((looking-at "else\\b")
394: (setq if-level (1+ if-level)))
395: ((looking-at "if\\b")
396: (setq if-level (1- if-level)))
397: ((< (point) limit)
398: (setq if-level 0)
399: (goto-char limit))))))
400:
401: (defun mark-icon-function ()
402: "Put mark at end of Icon function, point at beginning."
403: (interactive)
404: (push-mark (point))
405: (end-of-icon-defun)
406: (push-mark (point))
407: (beginning-of-line 0)
408: (beginning-of-icon-defun))
409:
410: (defun beginning-of-icon-defun ()
411: "Go to the start of the enclosing procedure; return t if at top level."
412: (interactive)
413: (if (re-search-backward "^procedure\\s \\|^end[ \t\n]" (point-min) 'move)
414: (looking-at "e")
415: t))
416:
417: (defun end-of-icon-defun ()
418: (interactive)
419: (if (not (bobp)) (forward-char -1))
420: (re-search-forward "\\(\\s \\|^\\)end\\(\\s \\|$\\)" (point-max) 'move)
421: (forward-word -1)
422: (forward-line 1))
423:
424: (defun indent-icon-exp ()
425: "Indent each line of the Icon grouping following point."
426: (interactive)
427: (let ((indent-stack (list nil))
428: (contain-stack (list (point)))
429: (case-fold-search nil)
430: restart outer-loop-done inner-loop-done state ostate
431: this-indent last-sexp
432: at-else at-brace at-do
433: (opoint (point))
434: (next-depth 0))
435: (save-excursion
436: (forward-sexp 1))
437: (save-excursion
438: (setq outer-loop-done nil)
439: (while (and (not (eobp)) (not outer-loop-done))
440: (setq last-depth next-depth)
441: ;; Compute how depth changes over this line
442: ;; plus enough other lines to get to one that
443: ;; does not end inside a comment or string.
444: ;; Meanwhile, do appropriate indentation on comment lines.
445: (setq innerloop-done nil)
446: (while (and (not innerloop-done)
447: (not (and (eobp) (setq outer-loop-done t))))
448: (setq ostate state)
449: (setq state (parse-partial-sexp (point) (progn (end-of-line) (point))
450: nil nil state))
451: (setq next-depth (car state))
452: (if (and (car (cdr (cdr state)))
453: (>= (car (cdr (cdr state))) 0))
454: (setq last-sexp (car (cdr (cdr state)))))
455: (if (or (nth 4 ostate))
456: (icon-indent-line))
457: (if (or (nth 3 state))
458: (forward-line 1)
459: (setq innerloop-done t)))
460: (if (<= next-depth 0)
461: (setq outer-loop-done t))
462: (if outer-loop-done
463: nil
464: (if (/= last-depth next-depth)
465: (setq last-sexp nil))
466: (while (> last-depth next-depth)
467: (setq indent-stack (cdr indent-stack)
468: contain-stack (cdr contain-stack)
469: last-depth (1- last-depth)))
470: (while (< last-depth next-depth)
471: (setq indent-stack (cons nil indent-stack)
472: contain-stack (cons nil contain-stack)
473: last-depth (1+ last-depth)))
474: (if (null (car contain-stack))
475: (setcar contain-stack (or (car (cdr state))
476: (save-excursion (forward-sexp -1)
477: (point)))))
478: (forward-line 1)
479: (skip-chars-forward " \t")
480: (if (eolp)
481: nil
482: (if (and (car indent-stack)
483: (>= (car indent-stack) 0))
484: ;; Line is on an existing nesting level.
485: ;; Lines inside parens are handled specially.
486: (if (/= (char-after (car contain-stack)) ?{)
487: (setq this-indent (car indent-stack))
488: ;; Line is at statement level.
489: ;; Is it a new statement? Is it an else?
490: ;; Find last non-comment character before this line
491: (save-excursion
492: (setq at-else (looking-at "else\\W"))
493: (setq at-brace (= (following-char) ?{))
494: (icon-backward-to-noncomment opoint)
495: (if (icon-is-continuation-line)
496: ;; Preceding line did not end in comma or semi;
497: ;; indent this line icon-continued-statement-offset
498: ;; more than previous.
499: (progn
500: (icon-backward-to-start-of-continued-exp (car contain-stack))
501: (setq this-indent
502: (+ icon-continued-statement-offset (current-column)
503: (if at-brace icon-continued-brace-offset 0))))
504: ;; Preceding line ended in comma or semi;
505: ;; use the standard indent for this level.
506: (if at-else
507: (progn (icon-backward-to-start-of-if opoint)
508: (setq this-indent (current-indentation)))
509: (setq this-indent (car indent-stack))))))
510: ;; Just started a new nesting level.
511: ;; Compute the standard indent for this level.
512: (let ((val (calculate-icon-indent
513: (if (car indent-stack)
514: (- (car indent-stack))))))
515: (setcar indent-stack
516: (setq this-indent val))))
517: ;; Adjust line indentation according to its contents
518: (if (or (= (following-char) ?})
519: (looking-at "end\\b"))
520: (setq this-indent (- this-indent icon-indent-level)))
521: (if (= (following-char) ?{)
522: (setq this-indent (+ this-indent icon-brace-offset)))
523: ;; Put chosen indentation into effect.
524: (or (= (current-column) this-indent)
525: (progn
526: (delete-region (point) (progn (beginning-of-line) (point)))
527: (indent-to this-indent)))
528: ;; Indent any comment following the text.
529: (or (looking-at comment-start-skip)
530: (if (re-search-forward comment-start-skip (save-excursion (end-of-line) (point)) t)
531: (progn (indent-for-comment) (beginning-of-line))))))))))
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.