summaryrefslogtreecommitdiff
path: root/web/c_cpp/cweb/cweb.el
blob: c243f35b2e44900466acf371bea28d9c8ae0f0e8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
;; This file contains extensions to GNU-Emacs, to wit:
; (1) some WEB-oriented functions that are also of general use
; (2) changes to the GNU-distributed TeX mode
; (3) definitions of simple WEB and CWEB modes

; To use: Put this in your EMACS-lisp library and say (load-library "cweb")
; in your .emacs init file.

; Contributed by Don Knuth, July 1990

;; OK, here's part (1): some WEB-oriented functions whose main purpose is
; to maintain a stack of module names that are "pending" as you are writing
; a program. When you first think of a module that needs to be written later,
; put it into the pending list (by typing CTL-Z instead of @> after the
; name). Later you can say CTL-\ to retrieve a pending name (and if
; you want to cycle through the pending names, ESC-y after CTL-\ will
; do it, just as ESC-y works after a yank).
; After you've said CTL-\, the current region is the name just removed from
; the pending list. If you change your mind, you can put it back again by
; saying ESC-\. If you had put it into the pending list by mistake, you
; can get rid of it by using the normal CTL-W operation (kill-region).
; The following code binds the new commands to CTL-Z, CTL-\, and ESC-\
; in all modes. You may prefer other bindings, of course.
; CTL-Z is normally "suspend emacs", but it is best not used when emacs
; has its own window as it usually does nowadays; if you need the
; old CTL-Z, you might rather bind it to CTL-X CTL-Z.
; CTL-\ is normally undefined.
; ESC-\ is normally "delete space", but ESC-space DEL does that easily too.

(defvar pending-list nil
 "List of strings (usually WEB module names) still pending.")

(defun into-pending-list (beg end)
 "Copy region into pending-list."
 (interactive "r")
 (indicate-region)
 (setq pending-list (cons (buffer-substring beg end) pending-list)))

(defun new-module-name-pending ()
 "Insert @> to complete a module name, then put it into pending-list."
 (interactive)
 (insert "@>")
 (push-mark)
 (if (search-backward "@<" nil t)
     (progn
       (exchange-point-and-mark)
       (into-pending-list (point) (mark))
       )
   (message "There's no @< to begin the module name!")))
(global-set-key "\C-z" 'new-module-name-pending)

(defun pop-pending-list (arg)
 "Remove first element of pending-list and insert it as current region.
With argument, put point at left; otherwise point will follow the insertion.
Say \\[new-yank-pop] to replace this by another element of the list.
Say \\[into-pending-list] to put it back in the list."
 (interactive "*P")
 (if (consp pending-list)
     (progn
       (push-mark (point))
       (insert (car pending-list))
       (setq pending-list (cdr pending-list))
       (if arg
           (exchange-point-and-mark)))
   (message "Nothing is pending.")
   (setq this-command nil)))
(global-set-key "\C-\\" 'pop-pending-list)
(global-set-key "\M-\\" 'into-pending-list)

(defun new-yank-pop (arg)
 "If previous command was \\[pop-pending-list], pop a different string;
otherwise do an ordinary Meta-y."
 (interactive "*p")
 (if (eq last-command 'pop-pending-list)
     (let (xch)
       (setq xch (< (point) (mark)))
       (setq pending-list (append pending-list
                                 (list (buffer-substring (point) (mark)))))
       (delete-region (point) (mark))
       (setq this-command 'pop-pending-list)
       (pop-pending-list xch))
   (yank-pop arg)))
(global-set-key "\M-y" 'new-yank-pop)

(defun indicate-region ()
  "Bounce cursor to mark and back again"
  (let ((point-save (point)))
    (unwind-protect
        (progn (goto-char (mark))
               (sit-for 0 300)) ;; wait 300 milliseconds
      (goto-char point-save))))

; I prefer to change the standard copy-region command to the following,
; which gives me visual feedback about what I've copied to the kill ring:
(defun indicate-and-copy-region (beg end)
  "Indicate current region, then copy it to the kill ring."
  (interactive "r")(indicate-region)(copy-region-as-kill beg end))
(global-set-key "\M-w" 'indicate-and-copy-region)

; Here's another convenient command, bound to the usually unused ESC-".
(defun ditto (arg)
  "Copy ARG characters from the line above."
  (interactive "*p")
  (let (ch)
    (while (> arg 0)
      (setq temporary-goal-column (current-column))
      (save-excursion
        (previous-line 1)
        (setq ch (following-char)))
      (insert ch)
      (setq arg (1- arg)))))
(global-set-key "\M-\"" 'ditto)
; If "ditto" suddenly fails to work, you have probably set goal-column
; inadvertently. To unset it, say C-u C-x C-n.

;; OK, here's part (2): Changes to TeX mode.
; The WEB modes below are very much like TeX mode, but some improvements were
; desirable in TeX mode:
; I made newline act as it does in indented-text mode, since this
; works nicely for both TeX and WEB (Pascal or C code).
; I made RET check for unmatched delimiters if it ends a paragraph.
; Otherwise TeX mode remains as it was before.

(setq TeX-mode-map (make-sparse-keymap))
(define-key TeX-mode-map "\C-c\C-k" 'TeX-kill-job)
(define-key TeX-mode-map "\C-c\C-l" 'TeX-recenter-output-buffer)
(define-key TeX-mode-map "\C-c\C-q" 'TeX-show-print-queue)
(define-key TeX-mode-map "\C-c\C-p" 'TeX-print)
(define-key TeX-mode-map "\"" 'TeX-insert-quote)
(define-key TeX-mode-map "\e}" 'up-list)
(define-key TeX-mode-map "\e{" 'TeX-insert-braces)
(define-key TeX-mode-map "\C-c\C-r" 'TeX-region)
(define-key TeX-mode-map "\C-c\C-b" 'TeX-buffer)
(define-key TeX-mode-map "\C-c\C-f" 'TeX-close-LaTeX-block)
(define-key TeX-mode-map "\r" 'TeX-newline)
(define-key TeX-mode-map "\t" 'indent-relative)
(setq TeX-mode-hook '(lambda ()
  (make-local-variable 'indent-line-function)
  (setq indent-line-function 'indent-relative-maybe)))

(defun TeX-newline (arg)
"If previous character is newline and no ARG, check for unbalanced braces
and/or dollar signs in previous paragraph. If ARG is \\[universal-argument],
do a single newline; otherwise do ordinary newline."
 (interactive "*P")
 (if (and (eq (preceding-char) ?\n) (not arg))
     (TeX-check-paragraph)
   (if (listp arg)
       (newline)
     (newline arg))))

(defun TeX-check-paragraph ()
"Insert a newline following a newline, breaking a paragraph for TeX.
Check for mismatched delimiters in paragraph being terminated."
  (interactive)
  (if (TeX-validate-paragraph
           (save-excursion
             (search-backward "\n\n" nil 'move)
             (point))
           (point))
      (insert ?\n)
    (insert ?\n)
    (error "Mismatched delimiters in that paragraph?")))

;; and now, part (3): WEB and CWEB modes.
; These are like plain TeX mode except that the automatic conversion of
; " to `` or '' is disabled. (Personally I never liked that feature anyway,
; since it's easy to get used to typing `` and ''. In WEB modes, the
; feature soon becomes intolerable, unless you never use string constants!)
; Another thing distinguishing WEB mode from TeX is ESC-p and ESC-n, to
; move to previous or next module. These keys are usually unbound, except
; when processing email.

(defun forward-module (arg)
"Advance past next WEB module beginning; with ARG, repeat ARG times."
 (interactive "p")
 (move-to-module arg))
(defun backward-module (arg)
"Advance to previous WEB module beginning; with ARG, repeat ARG times."
 (interactive "p")
 (move-to-module (- arg)))
(defun move-to-module (arg)
 (while (> arg 0)
   (re-search-forward "@ \\|@\\*\\|@\n")
   (setq arg (1- arg)))
 (while (< arg 0)
   (re-search-backward "@ \\|@\\*\\|@\n")
   (setq arg (1+ arg))))

(defun web-mode ()
  "Major mode like TeX mode plus \\[forward-module] and \\[backward-module]
for relative module movement. The automatic \" feature is disabled."
  (interactive)
  (plain-tex-mode)
  (local-set-key "\M-n" 'forward-module)
  (local-set-key "\M-p" 'backward-module)
  (local-set-key "\"" 'self-insert-command)
  (setq mode-name "WEB")
  (setq major-mode 'web-mode)
  (run-hooks 'web-mode-hook))
(setq auto-mode-alist (cons '("\\.web$" . web-mode) auto-mode-alist))

(defun cweb-mode ()
  "Major mode like TeX mode plus \\[forward-module] and \\[backward-module]
for relative module movement. The automatic \" feature is disabled."
  (interactive)
  (plain-tex-mode)
  (local-set-key "\M-n" 'forward-module)
  (local-set-key "\M-p" 'backward-module)
  (local-set-key "\"" 'self-insert-command)
  (setq comment-start nil)
  (modify-syntax-entry ?% "@")
  (setq mode-name "CWEB")
  (setq major-mode 'cweb-mode)
  (setq tex-fontify-script nil) ;; needed in GNU Emacs version 22?
  (run-hooks 'cweb-mode-hook))
(setq auto-mode-alist (cons '("\\.w$" . cweb-mode) auto-mode-alist))
(setq auto-mode-alist (cons '("\\.ch$" . cweb-mode) auto-mode-alist))