aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJim Blandy1989-10-31 15:59:53 +0000
committerJim Blandy1989-10-31 15:59:53 +0000
commit0d20f9a04efa7cfbe205e4967b6797b89fc64fe7 (patch)
tree787af4d2117afe2886996c45c40451f7406fe4fb
parent89758ab855a9a8a64f36d986da39767ebdc9ac76 (diff)
downloademacs-0d20f9a04efa7cfbe205e4967b6797b89fc64fe7.tar.gz
emacs-0d20f9a04efa7cfbe205e4967b6797b89fc64fe7.zip
Initial revision
-rw-r--r--lisp/electric.el181
-rw-r--r--lisp/emulation/mlsupport.el405
-rw-r--r--lisp/grow-vers.el30
-rw-r--r--lisp/inc-vers.el43
-rw-r--r--lisp/loadup.el140
-rw-r--r--lisp/mail/rmailmsc.el45
-rw-r--r--lisp/mail/rnews.el979
-rw-r--r--lisp/mail/rnewspost.el390
-rw-r--r--lisp/mail/undigest.el105
-rw-r--r--lisp/mim-syntax.el91
-rw-r--r--lisp/misc.el51
-rw-r--r--lisp/netunam.el152
-rw-r--r--lisp/sun-curs.el207
-rw-r--r--lisp/sun-fns.el630
-rw-r--r--lisp/sun-keys.el71
-rw-r--r--lisp/term/sun-mouse.el668
-rw-r--r--lisp/term/sup-mouse.el207
-rw-r--r--lisp/vmsproc.el138
-rw-r--r--lisp/vmsx.el137
-rw-r--r--lisp/x-menu.el145
20 files changed, 4815 insertions, 0 deletions
diff --git a/lisp/electric.el b/lisp/electric.el
new file mode 100644
index 00000000000..be992c60f0d
--- /dev/null
+++ b/lisp/electric.el
@@ -0,0 +1,181 @@
1;; electric -- Window maker and Command loop for `electric' modes.
2;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3;; Principal author K. Shane Hartman
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 1, or (at your option)
10;; any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs; see the file COPYING. If not, write to
19;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20
21
22(provide 'electric) ; zaaaaaaap
23
24;; perhaps this should be in subr.el...
25(defun shrink-window-if-larger-than-buffer (window)
26 (save-excursion
27 (set-buffer (window-buffer window))
28 (let ((w (selected-window)) ;save-window-excursion can't win
29 (buffer-file-name buffer-file-name)
30 (p (point))
31 (n 0)
32 (window-min-height 0)
33 (buffer-read-only nil)
34 (modified (buffer-modified-p))
35 (buffer (current-buffer)))
36 (unwind-protect
37 (progn
38 (select-window window)
39 (goto-char (point-min))
40 (while (pos-visible-in-window-p (point-max))
41 ;; defeat file locking... don't try this at home, kids!
42 (setq buffer-file-name nil)
43 (insert ?\n) (setq n (1+ n)))
44 (if (> n 0) (shrink-window (1- n))))
45 (delete-region (point-min) (point))
46 (set-buffer-modified-p modified)
47 (goto-char p)
48 (select-window w)
49 ;; Make sure we unbind buffer-read-only
50 ;; with the proper current buffer.
51 (set-buffer buffer)))))
52
53;; This loop is the guts for non-standard modes which retain control
54;; until some event occurs. It is a `do-forever', the only way out is to
55;; throw. It assumes that you have set up the keymap, window, and
56;; everything else: all it does is read commands and execute them -
57;; providing error messages should one occur (if there is no loop
58;; function - which see). The required argument is a tag which should
59;; expect a value of nil if the user decides to punt. The
60;; second argument is a prompt string (defaults to "->"). Given third
61;; argument non-nil, it INHIBITS quitting unless the user types C-g at
62;; toplevel. This is so user can do things like C-u C-g and not get
63;; thrown out. Fourth argument, if non-nil, should be a function of two
64;; arguments which is called after every command is executed. The fifth
65;; argument, if provided, is the state variable for the function. If the
66;; loop-function gets an error, the loop will abort WITHOUT throwing
67;; (moral: use unwind-protect around call to this function for any
68;; critical stuff). The second argument for the loop function is the
69;; conditions for any error that occurred or nil if none.
70
71(defun Electric-command-loop (return-tag
72 &optional prompt inhibit-quit
73 loop-function loop-state)
74 (if (not prompt) (setq prompt "->"))
75 (let (cmd (err nil))
76 (while t
77 (setq cmd (read-key-sequence (if (stringp prompt)
78 prompt (funcall prompt))))
79 (setq last-command-char (aref cmd (1- (length cmd)))
80 this-command (key-binding cmd)
81 cmd this-command)
82 (if (or (prog1 quit-flag (setq quit-flag nil))
83 (= last-input-char ?\C-g))
84 (progn (setq unread-command-char -1
85 prefix-arg nil)
86 ;; If it wasn't cancelling a prefix character, then quit.
87 (if (or (= (length (this-command-keys)) 1)
88 (not inhibit-quit)) ; safety
89 (progn (ding)
90 (message "Quit")
91 (throw return-tag nil))
92 (setq cmd nil))))
93 (setq current-prefix-arg prefix-arg)
94 (if cmd
95 (condition-case conditions
96 (progn (command-execute cmd)
97 (if (or (prog1 quit-flag (setq quit-flag nil))
98 (= last-input-char ?\C-g))
99 (progn (setq unread-command-char -1)
100 (if (not inhibit-quit)
101 (progn (ding)
102 (message "Quit")
103 (throw return-tag nil))
104 (ding)))))
105 (buffer-read-only (if loop-function
106 (setq err conditions)
107 (ding)
108 (message "Buffer is read-only")
109 (sit-for 2)))
110 (beginning-of-buffer (if loop-function
111 (setq err conditions)
112 (ding)
113 (message "Beginning of Buffer")
114 (sit-for 2)))
115 (end-of-buffer (if loop-function
116 (setq err conditions)
117 (ding)
118 (message "End of Buffer")
119 (sit-for 2)))
120 (error (if loop-function
121 (setq err conditions)
122 (ding)
123 (message "Error: %s"
124 (if (eq (car conditions) 'error)
125 (car (cdr conditions))
126 (prin1-to-string conditions)))
127 (sit-for 2))))
128 (ding))
129 (if loop-function (funcall loop-function loop-state err))))
130 (ding)
131 (throw return-tag nil))
132
133;; This function is like pop-to-buffer, sort of.
134;; The algorithm is
135;; If there is a window displaying buffer
136;; Select it
137;; Else if there is only one window
138;; Split it, selecting the window on the bottom with height being
139;; the lesser of max-height (if non-nil) and the number of lines in
140;; the buffer to be displayed subject to window-min-height constraint.
141;; Else
142;; Switch to buffer in the current window.
143;;
144;; Then if max-height is nil, and not all of the lines in the buffer
145;; are displayed, grab the whole screen.
146;;
147;; Returns selected window on buffer positioned at point-min.
148
149(defun Electric-pop-up-window (buffer &optional max-height)
150 (let* ((win (or (get-buffer-window buffer) (selected-window)))
151 (buf (get-buffer buffer))
152 (one-window (one-window-p t))
153 (pop-up-windows t)
154 (target-height)
155 (lines))
156 (if (not buf)
157 (error "Buffer %s does not exist" buffer)
158 (save-excursion
159 (set-buffer buf)
160 (setq lines (count-lines (point-min) (point-max)))
161 (setq target-height
162 (min (max (if max-height (min max-height (1+ lines)) (1+ lines))
163 window-min-height)
164 (save-window-excursion
165 (delete-other-windows)
166 (1- (window-height (selected-window)))))))
167 (cond ((and (eq (window-buffer win) buf))
168 (select-window win))
169 (one-window
170 (goto-char (window-start win))
171 (pop-to-buffer buffer)
172 (setq win (selected-window))
173 (enlarge-window (- target-height (window-height win))))
174 (t
175 (switch-to-buffer buf)))
176 (if (and (not max-height)
177 (> target-height (window-height (selected-window))))
178 (progn (goto-char (window-start win))
179 (enlarge-window (- target-height (window-height win)))))
180 (goto-char (point-min))
181 win)))
diff --git a/lisp/emulation/mlsupport.el b/lisp/emulation/mlsupport.el
new file mode 100644
index 00000000000..14e7a3c9557
--- /dev/null
+++ b/lisp/emulation/mlsupport.el
@@ -0,0 +1,405 @@
1;; Run-time support for mocklisp code.
2;; Copyright (C) 1985 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20
21(provide 'mlsupport)
22
23(defmacro ml-defun (&rest defs)
24 (list 'ml-defun-1 (list 'quote defs)))
25
26(defun ml-defun-1 (args)
27 (while args
28 (fset (car (car args)) (cons 'mocklisp (cdr (car args))))
29 (setq args (cdr args))))
30
31(defmacro declare-buffer-specific (&rest vars)
32 (cons 'progn (mapcar (function (lambda (var) (list 'make-variable-buffer-local (list 'quote var)))) vars)))
33
34(defun ml-set-default (varname value)
35 (set-default (intern varname) value))
36
37; Lossage: must make various things default missing args to the prefix arg
38; Alternatively, must make provide-prefix-argument do something hairy.
39
40(defun >> (val count) (lsh val (- count)))
41(defun novalue () nil)
42
43(defun ml-not (arg) (if (zerop arg) 1 0))
44
45(defun provide-prefix-arg (arg form)
46 (funcall (car form) arg))
47
48(defun define-keymap (name)
49 (fset (intern name) (make-keymap)))
50
51(defun ml-use-local-map (name)
52 (use-local-map (intern (concat name "-map"))))
53
54(defun ml-use-global-map (name)
55 (use-global-map (intern (concat name "-map"))))
56
57(defun local-bind-to-key (name key)
58 (or (current-local-map)
59 (use-local-map (make-keymap)))
60 (define-key (current-local-map)
61 (if (integerp key)
62 (if (>= key 128)
63 (concat (char-to-string meta-prefix-char)
64 (char-to-string (- key 128)))
65 (char-to-string key))
66 key)
67 (intern name)))
68
69(defun bind-to-key (name key)
70 (define-key global-map (if (integerp key) (char-to-string key) key)
71 (intern name)))
72
73(defun ml-autoload (name file)
74 (autoload (intern name) file))
75
76(defun ml-define-string-macro (name defn)
77 (fset (intern name) defn))
78
79(defun push-back-character (char)
80 (setq unread-command-char char))
81
82(defun to-col (column)
83 (indent-to column 0))
84
85(defmacro is-bound (&rest syms)
86 (cons 'and (mapcar (function (lambda (sym) (list 'boundp (list 'quote sym)))) syms)))
87
88(defmacro declare-global (&rest syms)
89 (cons 'progn (mapcar (function (lambda (sym) (list 'defvar sym nil))) syms)))
90
91(defmacro error-occurred (&rest body)
92 (list 'condition-case nil (cons 'progn (append body '(nil))) '(error t)))
93
94(defun return-prefix-argument (value)
95 (setq prefix-arg value))
96
97(defun ml-prefix-argument ()
98 (if (null current-prefix-arg) 1
99 (if (listp current-prefix-arg) (car current-prefix-arg)
100 (if (eq current-prefix-arg '-) -1
101 current-prefix-arg))))
102
103(defun ml-print (varname)
104 (interactive "vPrint variable: ")
105 (if (boundp varname)
106 (message "%s => %s" (symbol-name varname) (symbol-value varname))
107 (message "%s has no value" (symbol-name varname))))
108
109(defun ml-set (str val) (set (intern str) val))
110
111(defun ml-message (&rest args) (message "%s" (apply 'concat args)))
112
113(defun kill-to-end-of-line ()
114 (ml-prefix-argument-loop
115 (if (eolp)
116 (kill-region (point) (1+ (point)))
117 (kill-region (point) (if (search-forward ?\n nil t)
118 (1- (point)) (point-max))))))
119
120(defun set-auto-fill-hook (arg)
121 (setq auto-fill-function (intern arg)))
122
123(defun auto-execute (function pattern)
124 (if (/= (aref pattern 0) ?*)
125 (error "Only patterns starting with * supported in auto-execute"))
126 (setq auto-mode-alist (cons (cons (concat "\\." (substring pattern 1)
127 "$")
128 function)
129 auto-mode-alist)))
130
131(defun move-to-comment-column ()
132 (indent-to comment-column))
133
134(defun erase-region ()
135 (delete-region (point) (mark)))
136
137(defun delete-region-to-buffer (bufname)
138 (copy-to-buffer bufname (point) (mark))
139 (delete-region (point) (mark)))
140
141(defun copy-region-to-buffer (bufname)
142 (copy-to-buffer bufname (point) (mark)))
143
144(defun append-region-to-buffer (bufname)
145 (append-to-buffer bufname (point) (mark)))
146
147(defun prepend-region-to-buffer (bufname)
148 (prepend-to-buffer bufname (point) (mark)))
149
150(defun delete-next-character ()
151 (delete-char (ml-prefix-argument)))
152
153(defun delete-next-word ()
154 (delete-region (point) (progn (forward-word (ml-prefix-argument)) (point))))
155
156(defun delete-previous-word ()
157 (delete-region (point) (progn (backward-word (ml-prefix-argument)) (point))))
158
159(defun delete-previous-character ()
160 (delete-backward-char (ml-prefix-argument)))
161
162(defun forward-character ()
163 (forward-char (ml-prefix-argument)))
164
165(defun backward-character ()
166 (backward-char (ml-prefix-argument)))
167
168(defun ml-newline ()
169 (newline (ml-prefix-argument)))
170
171(defun ml-next-line ()
172 (next-line (ml-prefix-argument)))
173
174(defun ml-previous-line ()
175 (previous-line (ml-prefix-argument)))
176
177(defun delete-to-kill-buffer ()
178 (kill-region (point) (mark)))
179
180(defun narrow-region ()
181 (narrow-to-region (point) (mark)))
182
183(defun ml-newline-and-indent ()
184 (let ((column (current-indentation)))
185 (newline (ml-prefix-argument))
186 (indent-to column)))
187
188(defun newline-and-backup ()
189 (open-line (ml-prefix-argument)))
190
191(defun quote-char ()
192 (quoted-insert (ml-prefix-argument)))
193
194(defun ml-current-column ()
195 (1+ (current-column)))
196
197(defun ml-current-indent ()
198 (1+ (current-indentation)))
199
200(defun region-around-match (&optional n)
201 (set-mark (match-beginning n))
202 (goto-char (match-end n)))
203
204(defun region-to-string ()
205 (buffer-substring (min (point) (mark)) (max (point) (mark))))
206
207(defun use-abbrev-table (name)
208 (let ((symbol (intern (concat name "-abbrev-table"))))
209 (or (boundp symbol)
210 (define-abbrev-table symbol nil))
211 (symbol-value symbol)))
212
213(defun define-hooked-local-abbrev (name exp hook)
214 (define-local-abbrev name exp (intern hook)))
215
216(defun define-hooked-global-abbrev (name exp hook)
217 (define-global-abbrev name exp (intern hook)))
218
219(defun case-word-lower ()
220 (ml-casify-word 'downcase-region))
221
222(defun case-word-upper ()
223 (ml-casify-word 'upcase-region))
224
225(defun case-word-capitalize ()
226 (ml-casify-word 'capitalize-region))
227
228(defun ml-casify-word (fun)
229 (save-excursion
230 (forward-char 1)
231 (forward-word -1)
232 (funcall fun (point)
233 (progn (forward-word (ml-prefix-argument))
234 (point)))))
235
236(defun case-region-lower ()
237 (downcase-region (point) (mark)))
238
239(defun case-region-upper ()
240 (upcase-region (point) (mark)))
241
242(defun case-region-capitalize ()
243 (capitalize-region (point) (mark)))
244
245(defvar saved-command-line-args nil)
246
247(defun argc ()
248 (or saved-command-line-args
249 (setq saved-command-line-args command-line-args
250 command-line-args ()))
251 (length command-line-args))
252
253(defun argv (i)
254 (or saved-command-line-args
255 (setq saved-command-line-args command-line-args
256 command-line-args ()))
257 (nth i saved-command-line-args))
258
259(defun invisible-argc ()
260 (length (or saved-command-line-args
261 command-line-args)))
262
263(defun invisible-argv (i)
264 (nth i (or saved-command-line-args
265 command-line-args)))
266
267(defun exit-emacs ()
268 (interactive)
269 (condition-case ()
270 (exit-recursive-edit)
271 (error (kill-emacs))))
272
273;; Lisp function buffer-size returns total including invisible;
274;; mocklisp wants just visible.
275(defun ml-buffer-size ()
276 (- (point-max) (point-min)))
277
278(defun previous-command ()
279 last-command)
280
281(defun beginning-of-window ()
282 (goto-char (window-start)))
283
284(defun end-of-window ()
285 (goto-char (window-start))
286 (vertical-motion (- (window-height) 2)))
287
288(defun ml-search-forward (string)
289 (search-forward string nil nil (ml-prefix-argument)))
290
291(defun ml-re-search-forward (string)
292 (re-search-forward string nil nil (ml-prefix-argument)))
293
294(defun ml-search-backward (string)
295 (search-backward string nil nil (ml-prefix-argument)))
296
297(defun ml-re-search-backward (string)
298 (re-search-backward string nil nil (ml-prefix-argument)))
299
300(defvar use-users-shell 1
301 "Mocklisp compatibility variable; 1 means use shell from SHELL env var.
3020 means use /bin/sh.")
303
304(defvar use-csh-option-f 1
305 "Mocklisp compatibility variable; 1 means pass -f when calling csh.")
306
307(defun filter-region (command)
308 (let ((shell (if (/= use-users-shell 0) shell-file-name "/bin/sh"))
309 (csh (equal (file-name-nondirectory shell) "csh")))
310 (call-process-region (point) (mark) shell t t nil
311 (if (and csh use-csh-option-f) "-cf" "-c")
312 (concat "exec " command))))
313
314(defun execute-monitor-command (command)
315 (let ((shell (if (/= use-users-shell 0) shell-file-name "/bin/sh"))
316 (csh (equal (file-name-nondirectory shell) "csh")))
317 (call-process shell nil t t
318 (if (and csh use-csh-option-f) "-cf" "-c")
319 (concat "exec " command))))
320
321(defun use-syntax-table (name)
322 (set-syntax-table (symbol-value (intern (concat name "-syntax-table")))))
323
324(defun line-to-top-of-window ()
325 (recenter (1- (ml-prefix-argument))))
326
327(defun ml-previous-page (&optional arg)
328 (let ((count (or arg (ml-prefix-argument))))
329 (while (> count 0)
330 (scroll-down nil)
331 (setq count (1- count)))
332 (while (< count 0)
333 (scroll-up nil)
334 (setq count (1+ count)))))
335
336(defun ml-next-page ()
337 (previous-page (- (ml-prefix-argument))))
338
339(defun page-next-window (&optional arg)
340 (let ((count (or arg (ml-prefix-argument))))
341 (while (> count 0)
342 (scroll-other-window nil)
343 (setq count (1- count)))
344 (while (< count 0)
345 (scroll-other-window '-)
346 (setq count (1+ count)))))
347
348(defun ml-next-window ()
349 (select-window (next-window)))
350
351(defun ml-previous-window ()
352 (select-window (previous-window)))
353
354(defun scroll-one-line-up ()
355 (scroll-up (ml-prefix-argument)))
356
357(defun scroll-one-line-down ()
358 (scroll-down (ml-prefix-argument)))
359
360(defun split-current-window ()
361 (split-window (selected-window)))
362
363(defun last-key-struck () last-command-char)
364
365(defun execute-mlisp-line (string)
366 (eval (read string)))
367
368(defun move-dot-to-x-y (x y)
369 (goto-char (window-start (selected-window)))
370 (vertical-motion (1- y))
371 (move-to-column (1- x)))
372
373(defun ml-modify-syntax-entry (string)
374 (let ((i 5)
375 (len (length string))
376 (datastring (substring string 0 2)))
377 (if (= (aref string 0) ?\-)
378 (aset datastring 0 ?\ ))
379 (if (= (aref string 2) ?\{)
380 (if (= (aref string 4) ?\ )
381 (aset datastring 0 ?\<)
382 (error "Two-char comment delimiter: use modify-syntax-entry directly")))
383 (if (= (aref string 3) ?\})
384 (if (= (aref string 4) ?\ )
385 (aset datastring 0 ?\>)
386 (error "Two-char comment delimiter: use modify-syntax-entry directly")))
387 (while (< i len)
388 (modify-syntax-entry (aref string i) datastring)
389 (setq i (1+ i))
390 (if (and (< i len)
391 (= (aref string i) ?\-))
392 (let ((c (aref string (1- i)))
393 (lim (aref string (1+ i))))
394 (while (<= c lim)
395 (modify-syntax-entry c datastring)
396 (setq c (1+ c)))
397 (setq i (+ 2 i)))))))
398
399
400
401(defun ml-substr (string from to)
402 (let ((length (length string)))
403 (if (< from 0) (setq from (+ from length)))
404 (if (< to 0) (setq to (+ to length)))
405 (substring string from (+ from to))))
diff --git a/lisp/grow-vers.el b/lisp/grow-vers.el
new file mode 100644
index 00000000000..bf55146c6a6
--- /dev/null
+++ b/lisp/grow-vers.el
@@ -0,0 +1,30 @@
1;; Load this file to add a new level (starting at zero)
2;; to the Emacs version number recorded in version.el.
3;; Copyright (C) 1985 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 1, or (at your option)
10;; any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs; see the file COPYING. If not, write to
19;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20
21
22(insert-file-contents "lisp/version.el")
23
24(re-search-forward "emacs-version \"[0-9.]*")
25(insert ".0")
26
27;; Delete the share-link with the current version
28;; so that we do not alter the current version.
29(delete-file "lisp/version.el")
30(write-region (point-min) (point-max) "lisp/version.el" nil 'nomsg)
diff --git a/lisp/inc-vers.el b/lisp/inc-vers.el
new file mode 100644
index 00000000000..13a4fb17e80
--- /dev/null
+++ b/lisp/inc-vers.el
@@ -0,0 +1,43 @@
1;; Load this file to increment the recorded Emacs version number.
2;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20
21(insert-file-contents "../lisp/version.el")
22
23(re-search-forward "emacs-version \"[^\"]*[0-9]+\"")
24(forward-char -1)
25(save-excursion
26 (save-restriction
27 (narrow-to-region (point)
28 (progn (skip-chars-backward "0-9") (point)))
29 (goto-char (point-min))
30 (let ((version (read (current-buffer))))
31 (delete-region (point-min) (point-max))
32 (prin1 (1+ version) (current-buffer)))))
33(skip-chars-backward "^\"")
34(message "New Emacs version will be %s"
35 (buffer-substring (point)
36 (progn (skip-chars-forward "^\"") (point))))
37
38
39(write-region (point-min) (point-max) "../lisp/version.el" nil 'nomsg)
40(erase-buffer)
41(set-buffer-modified-p nil)
42
43(kill-emacs)
diff --git a/lisp/loadup.el b/lisp/loadup.el
new file mode 100644
index 00000000000..9447c74891d
--- /dev/null
+++ b/lisp/loadup.el
@@ -0,0 +1,140 @@
1;;Load up standardly loaded Lisp files for Emacs.
2;; This is loaded into a bare Emacs to make a dumpable one.
3;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 1, or (at your option)
10;; any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs; see the file COPYING. If not, write to
19;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20
21
22(load "subr")
23(garbage-collect)
24(load "loaddefs.el") ;Don't get confused if someone compiled loaddefs by mistake.
25(garbage-collect)
26(load "simple")
27(garbage-collect)
28(load "help")
29(garbage-collect)
30(load "files")
31(garbage-collect)
32(load "indent")
33(load "window")
34(load "paths.el") ;Don't get confused if someone compiled paths by mistake.
35(garbage-collect)
36(load "startup")
37(load "lisp")
38(garbage-collect)
39(load "page")
40(load "register")
41(garbage-collect)
42(load "paragraphs")
43(load "lisp-mode")
44(garbage-collect)
45(load "text-mode")
46(load "fill")
47(garbage-collect)
48(load "c-mode")
49(garbage-collect)
50(load "isearch")
51(garbage-collect)
52(load "replace")
53(if (eq system-type 'vax-vms)
54 (progn
55 (garbage-collect)
56 (load "vmsproc")))
57(garbage-collect)
58(load "abbrev")
59(garbage-collect)
60(load "buff-menu")
61(if (eq system-type 'vax-vms)
62 (progn
63 (garbage-collect)
64 (load "vms-patch")))
65(if (fboundp 'atan) ; preload some constants and
66 (progn ; floating pt. functions if
67 (garbage-collect) ; we have float support.
68 (load "float-sup")))
69
70;If you want additional libraries to be preloaded and their
71;doc strings kept in the DOC file rather than in core,
72;you may load them with a "site-load.el" file.
73;But you must also cause them to be scanned when the DOC file
74;is generated. For VMS, you must edit ../etc/makedoc.com.
75;For other systems, you must edit ../src/ymakefile.
76(if (load "site-load" t)
77 (garbage-collect))
78
79(load "version.el") ;Don't get confused if someone compiled version.el by mistake.
80
81;; Note: all compiled Lisp files loaded above this point
82;; must be among the ones parsed by make-docfile
83;; to construct DOC. Any that are not processed
84;; for DOC will not have doc strings in the dumped Emacs.
85
86(message "Finding pointers to doc strings...")
87(if (fboundp 'dump-emacs)
88 (let ((name emacs-version))
89 (while (string-match "[^-+_.a-zA-Z0-9]+" name)
90 (setq name (concat (downcase (substring name 0 (match-beginning 0)))
91 "-"
92 (substring name (match-end 0)))))
93 (copy-file (expand-file-name "../etc/DOC")
94 (concat (expand-file-name "../etc/DOC-") name)
95 t)
96 (Snarf-documentation (concat "DOC-" name)))
97 (Snarf-documentation "DOC"))
98(message "Finding pointers to doc strings...done")
99
100;Note: You can cause additional libraries to be preloaded
101;by writing a site-init.el that loads them.
102;See also "site-load" above.
103(load "site-init" t)
104(garbage-collect)
105
106(if (or (equal (nth 3 command-line-args) "dump")
107 (equal (nth 4 command-line-args) "dump"))
108 (if (eq system-type 'vax-vms)
109 (progn
110 (message "Dumping data as file temacs.dump")
111 (dump-emacs "temacs.dump" "temacs")
112 (kill-emacs))
113 (let ((name (concat "emacs-" emacs-version)))
114 (while (string-match "[^-+_.a-zA-Z0-9]+" name)
115 (setq name (concat (downcase (substring name 0 (match-beginning 0)))
116 "-"
117 (substring name (match-end 0)))))
118 (message "Dumping under names xemacs and %s" name))
119 (condition-case ()
120 (delete-file "xemacs")
121 (file-error nil))
122 (dump-emacs "xemacs" "temacs")
123 ;; Recompute NAME now, so that it isn't set when we dump.
124 (let ((name (concat "emacs-" emacs-version)))
125 (while (string-match "[^-+_.a-zA-Z0-9]+" name)
126 (setq name (concat (downcase (substring name 0 (match-beginning 0)))
127 "-"
128 (substring name (match-end 0)))))
129 (add-name-to-file "xemacs" name t))
130 (kill-emacs)))
131
132;; Avoid error if user loads some more libraries now.
133(setq purify-flag nil)
134
135;; For machines with CANNOT_DUMP defined in config.h,
136;; this file must be loaded each time Emacs is run.
137;; So run the startup code now.
138
139(or (fboundp 'dump-emacs)
140 (eval top-level))
diff --git a/lisp/mail/rmailmsc.el b/lisp/mail/rmailmsc.el
new file mode 100644
index 00000000000..c57b15c4c3a
--- /dev/null
+++ b/lisp/mail/rmailmsc.el
@@ -0,0 +1,45 @@
1;; Copyright (C) 1985 Free Software Foundation, Inc.
2
3;; This file is part of GNU Emacs.
4
5;; GNU Emacs is free software; you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
7;; the Free Software Foundation; either version 1, or (at your option)
8;; any later version.
9
10;; GNU Emacs is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13;; GNU General Public License for more details.
14
15;; You should have received a copy of the GNU General Public License
16;; along with GNU Emacs; see the file COPYING. If not, write to
17;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18
19
20(defun set-rmail-inbox-list (file-name)
21 "Set the inbox list of the current RMAIL file to FILE-NAME.
22This may be a list of file names separated by commas.
23If FILE-NAME is empty, remove any inbox list."
24 (interactive "sSet mailbox list to (comma-separated list of filenames): ")
25 (save-excursion
26 (let ((names (rmail-parse-file-inboxes))
27 (standard-output nil))
28 (if (or (not names)
29 (y-or-n-p (concat "Replace "
30 (mapconcat 'identity names ", ")
31 "? ")))
32 (let ((buffer-read-only nil))
33 (widen)
34 (goto-char (point-min))
35 (search-forward "\n\^_")
36 (re-search-backward "^Mail" nil t)
37 (forward-line 0)
38 (if (looking-at "Mail:")
39 (delete-region (point)
40 (progn (forward-line 1)
41 (point))))
42 (if (not (string= file-name ""))
43 (insert "Mail: " file-name "\n"))))))
44 (setq rmail-inbox-list (rmail-parse-file-inboxes))
45 (rmail-show-message rmail-current-message))
diff --git a/lisp/mail/rnews.el b/lisp/mail/rnews.el
new file mode 100644
index 00000000000..64b98ca407b
--- /dev/null
+++ b/lisp/mail/rnews.el
@@ -0,0 +1,979 @@
1;;; USENET news reader for gnu emacs
2;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;; Created Sun Mar 10,1985 at 21:35:01 ads and sundar@hernes.ai.mit.edu
21;; Should do the point pdl stuff sometime
22;; finito except pdl.... Sat Mar 16,1985 at 06:43:44
23;; lets keep the summary stuff out until we get it working ..
24;; sundar@hermes.ai.mit.edu Wed Apr 10,1985 at 16:32:06
25;; hack slash maim. mly@prep.ai.mit.edu Thu 18 Apr, 1985 06:11:14
26;; modified to correct reentrance bug, to not bother with groups that
27;; received no new traffic since last read completely, to find out
28;; what traffic a group has available much more quickly when
29;; possible, to do some completing reads for group names - should
30;; be much faster...
31;; KING@KESTREL.arpa, Thu Mar 13 09:03:28 1986
32;; made news-{next,previous}-group skip groups with no new messages; and
33;; added checking for unsubscribed groups to news-add-news-group
34;; tower@prep.ai.mit.edu Jul 18 1986
35;; bound rmail-output to C-o; and changed header-field commands binding to
36;; agree with the new C-c C-f usage in sendmail
37;; tower@prep Sep 3 1986
38;; added news-rotate-buffer-body
39;; tower@prep Oct 17 1986
40;; made messages more user friendly, cleanuped news-inews
41;; move posting and mail code to new file rnewpost.el
42;; tower@prep Oct 29 1986
43;; added caesar-region, rename news-caesar-buffer-body, hacked accordingly
44;; tower@prep Nov 21 1986
45;; added (provide 'rnews) tower@prep 22 Apr 87
46(provide 'rnews)
47(require 'mail-utils)
48
49(autoload 'rmail-output "rmailout"
50 "Append this message to Unix mail file named FILE-NAME."
51 t)
52
53(autoload 'news-reply "rnewspost"
54 "Compose and post a reply to the current article on USENET.
55While composing the reply, use \\[mail-yank-original] to yank the original
56message into it."
57 t)
58
59(autoload 'news-mail-other-window "rnewspost"
60 "Send mail in another window.
61While composing the message, use \\[mail-yank-original] to yank the
62original message into it."
63 t)
64
65(autoload 'news-post-news "rnewspost"
66 "Begin editing a new USENET news article to be posted."
67 t)
68
69(autoload 'news-mail-reply "rnewspost"
70 "Mail a reply to the author of the current article.
71While composing the reply, use \\[mail-yank-original] to yank the original
72message into it."
73 t)
74
75(defvar news-group-hook-alist nil
76 "Alist of (GROUP-REGEXP . HOOK) pairs.
77Just before displaying a message, each HOOK is called
78if its GROUP-REGEXP matches the current newsgroup name.")
79
80(defvar rmail-last-file (expand-file-name "~/mbox.news"))
81
82;Now in paths.el.
83;(defvar news-path "/usr/spool/news/"
84; "The root directory below which all news files are stored.")
85
86(defvar news-startup-file "$HOME/.newsrc" "Contains ~/.newsrc")
87(defvar news-certification-file "$HOME/.news-dates" "Contains ~/.news-dates")
88
89;; random headers that we decide to ignore.
90(defvar news-ignored-headers
91 "^Path:\\|^Posting-Version:\\|^Article-I.D.:\\|^Expires:\\|^Date-Received:\\|^References:\\|^Control:\\|^Xref:\\|^Lines:\\|^Posted:\\|^Relay-Version:\\|^Message-ID:\\|^Nf-ID:\\|^Nf-From:\\|^Approved:\\|^Sender:"
92 "All random fields within the header of a message.")
93
94(defvar news-mode-map nil)
95(defvar news-read-first-time-p t)
96;; Contains the (dotified) news groups of which you are a member.
97(defvar news-user-group-list nil)
98
99(defvar news-current-news-group nil)
100(defvar news-current-group-begin nil)
101(defvar news-current-group-end nil)
102(defvar news-current-certifications nil
103 "An assoc list of a group name and the time at which it is
104known that the group had no new traffic")
105(defvar news-current-certifiable nil
106 "The time when the directory we are now working on was written")
107
108(defvar news-message-filter nil
109 "User specifiable filter function that will be called during
110formatting of the news file")
111
112;(defvar news-mode-group-string "Starting-Up"
113; "Mode line group name info is held in this variable")
114(defvar news-list-of-files nil
115 "Global variable in which we store the list of files
116associated with the current newsgroup")
117(defvar news-list-of-files-possibly-bogus nil
118 "variable indicating we only are guessing at which files are available.
119Not currently used.")
120
121;; association list in which we store lists of the form
122;; (pointified-group-name (first last old-last))
123(defvar news-group-article-assoc nil)
124
125(defvar news-current-message-number 0 "Displayed Article Number")
126(defvar news-total-current-group 0 "Total no of messages in group")
127
128(defvar news-unsubscribe-groups ())
129(defvar news-point-pdl () "List of visited news messages.")
130(defvar news-no-jumps-p t)
131(defvar news-buffer () "Buffer into which news files are read.")
132
133(defmacro news-push (item ref)
134 (list 'setq ref (list 'cons item ref)))
135
136(defmacro news-cadr (x) (list 'car (list 'cdr x)))
137(defmacro news-cdar (x) (list 'cdr (list 'car x)))
138(defmacro news-caddr (x) (list 'car (list 'cdr (list 'cdr x))))
139(defmacro news-cadar (x) (list 'car (list 'cdr (list 'car x))))
140(defmacro news-caadr (x) (list 'car (list 'car (list 'cdr x))))
141(defmacro news-cdadr (x) (list 'cdr (list 'car (list 'cdr x))))
142
143(defmacro news-wins (pfx index)
144 (` (file-exists-p (concat (, pfx) "/" (int-to-string (, index))))))
145
146(defvar news-max-plausible-gap 2
147 "* In an rnews directory, the maximum possible gap size.
148A gap is a sequence of missing messages between two messages that exist.
149An empty file does not contribute to a gap -- it ends one.")
150
151(defun news-find-first-and-last (prefix base)
152 (and (news-wins prefix base)
153 (cons (news-find-first-or-last prefix base -1)
154 (news-find-first-or-last prefix base 1))))
155
156(defmacro news-/ (a1 a2)
157;; a form of / that guarantees that (/ -1 2) = 0
158 (if (zerop (/ -1 2))
159 (` (/ (, a1) (, a2)))
160 (` (if (< (, a1) 0)
161 (- (/ (- (, a1)) (, a2)))
162 (/ (, a1) (, a2))))))
163
164(defun news-find-first-or-last (pfx base dirn)
165 ;; first use powers of two to find a plausible ceiling
166 (let ((original-dir dirn))
167 (while (news-wins pfx (+ base dirn))
168 (setq dirn (* dirn 2)))
169 (setq dirn (news-/ dirn 2))
170 ;; Then use a binary search to find the high water mark
171 (let ((offset (news-/ dirn 2)))
172 (while (/= offset 0)
173 (if (news-wins pfx (+ base dirn offset))
174 (setq dirn (+ dirn offset)))
175 (setq offset (news-/ offset 2))))
176 ;; If this high-water mark is bogus, recurse.
177 (let ((offset (* news-max-plausible-gap original-dir)))
178 (while (and (/= offset 0) (not (news-wins pfx (+ base dirn offset))))
179 (setq offset (- offset original-dir)))
180 (if (= offset 0)
181 (+ base dirn)
182 (news-find-first-or-last pfx (+ base dirn offset) original-dir)))))
183
184(defun rnews ()
185"Read USENET news for groups for which you are a member and add or
186delete groups.
187You can reply to articles posted and send articles to any group.
188
189Type \\[describe-mode] once reading news to get a list of rnews commands."
190 (interactive)
191 (let ((last-buffer (buffer-name)))
192 (make-local-variable 'rmail-last-file)
193 (switch-to-buffer (setq news-buffer (get-buffer-create "*news*")))
194 (news-mode)
195 (setq news-buffer-save last-buffer)
196 (setq buffer-read-only nil)
197 (erase-buffer)
198 (setq buffer-read-only t)
199 (set-buffer-modified-p t)
200 (sit-for 0)
201 (message "Getting new USENET news...")
202 (news-set-mode-line)
203 (news-get-certifications)
204 (news-get-new-news)))
205
206(defun news-group-certification (group)
207 (cdr-safe (assoc group news-current-certifications)))
208
209
210(defun news-set-current-certifiable ()
211 ;; Record the date that corresponds to the directory you are about to check
212 (let ((file (concat news-path
213 (string-subst-char ?/ ?. news-current-news-group))))
214 (setq news-current-certifiable
215 (nth 5 (file-attributes
216 (or (file-symlink-p file) file))))))
217
218(defun news-get-certifications ()
219 ;; Read the certified-read file from last session
220 (save-excursion
221 (save-window-excursion
222 (setq news-current-certifications
223 (car-safe
224 (condition-case var
225 (let*
226 ((file (substitute-in-file-name news-certification-file))
227 (buf (find-file-noselect file)))
228 (and (file-exists-p file)
229 (progn
230 (switch-to-buffer buf 'norecord)
231 (unwind-protect
232 (read-from-string (buffer-string))
233 (kill-buffer buf)))))
234 (error nil)))))))
235
236(defun news-write-certifications ()
237 ;; Write a certification file.
238 ;; This is an assoc list of group names with doubletons that represent
239 ;; mod times of the directory when group is read completely.
240 (save-excursion
241 (save-window-excursion
242 (with-output-to-temp-buffer
243 "*CeRtIfIcAtIoNs*"
244 (print news-current-certifications))
245 (let ((buf (get-buffer "*CeRtIfIcAtIoNs*")))
246 (switch-to-buffer buf)
247 (write-file (substitute-in-file-name news-certification-file))
248 (kill-buffer buf)))))
249
250(defun news-set-current-group-certification ()
251 (let ((cgc (assoc news-current-news-group news-current-certifications)))
252 (if cgc (setcdr cgc news-current-certifiable)
253 (news-push (cons news-current-news-group news-current-certifiable)
254 news-current-certifications))))
255
256(defun news-set-minor-modes ()
257 "Creates a minor mode list that has group name, total articles,
258and attribute for current article."
259 (setq news-minor-modes (list (cons 'foo
260 (concat news-current-message-number
261 "/"
262 news-total-current-group
263 (news-get-attribute-string)))))
264 ;; Detect Emacs versions 18.16 and up, which display
265 ;; directly from news-minor-modes by using a list for mode-name.
266 (or (boundp 'minor-mode-alist)
267 (setq minor-modes news-minor-modes)))
268
269(defun news-set-message-counters ()
270 "Scan through current news-groups filelist to figure out how many messages
271are there. Set counters for use with minor mode display."
272 (if (null news-list-of-files)
273 (setq news-current-message-number 0)))
274
275(if news-mode-map
276 nil
277 (setq news-mode-map (make-keymap))
278 (suppress-keymap news-mode-map)
279 (define-key news-mode-map "." 'beginning-of-buffer)
280 (define-key news-mode-map " " 'scroll-up)
281 (define-key news-mode-map "\177" 'scroll-down)
282 (define-key news-mode-map "n" 'news-next-message)
283 (define-key news-mode-map "c" 'news-make-link-to-message)
284 (define-key news-mode-map "p" 'news-previous-message)
285 (define-key news-mode-map "j" 'news-goto-message)
286 (define-key news-mode-map "q" 'news-exit)
287 (define-key news-mode-map "e" 'news-exit)
288 (define-key news-mode-map "\ej" 'news-goto-news-group)
289 (define-key news-mode-map "\en" 'news-next-group)
290 (define-key news-mode-map "\ep" 'news-previous-group)
291 (define-key news-mode-map "l" 'news-list-news-groups)
292 (define-key news-mode-map "?" 'describe-mode)
293 (define-key news-mode-map "g" 'news-get-new-news)
294 (define-key news-mode-map "f" 'news-reply)
295 (define-key news-mode-map "m" 'news-mail-other-window)
296 (define-key news-mode-map "a" 'news-post-news)
297 (define-key news-mode-map "r" 'news-mail-reply)
298 (define-key news-mode-map "o" 'news-save-item-in-file)
299 (define-key news-mode-map "\C-o" 'rmail-output)
300 (define-key news-mode-map "t" 'news-show-all-headers)
301 (define-key news-mode-map "x" 'news-force-update)
302 (define-key news-mode-map "A" 'news-add-news-group)
303 (define-key news-mode-map "u" 'news-unsubscribe-current-group)
304 (define-key news-mode-map "U" 'news-unsubscribe-group)
305 (define-key news-mode-map "\C-c\C-r" 'news-caesar-buffer-body))
306
307(defun news-mode ()
308 "News Mode is used by M-x rnews for reading USENET Newsgroups articles.
309New readers can find additional help in newsgroup: news.announce.newusers .
310All normal editing commands are turned off.
311Instead, these commands are available:
312
313. move point to front of this news article (same as Meta-<).
314Space scroll to next screen of this news article.
315Delete scroll down previous page of this news article.
316n move to next news article, possibly next group.
317p move to previous news article, possibly previous group.
318j jump to news article specified by numeric position.
319M-j jump to news group.
320M-n goto next news group.
321M-p goto previous news group.
322l list all the news groups with current status.
323? print this help message.
324C-c C-r caesar rotate all letters by 13 places in the article's body (rot13).
325g get new USENET news.
326f post a reply article to USENET.
327a post an original news article.
328A add a newsgroup.
329o save the current article in the named file (append if file exists).
330C-o output this message to a Unix-format mail file (append it).
331c \"copy\" (actually link) current or prefix-arg msg to file.
332 warning: target directory and message file must be on same device
333 (UNIX magic)
334t show all the headers this news article originally had.
335q quit reading news after updating .newsrc file.
336e exit updating .newsrc file.
337m mail a news article. Same as C-x 4 m.
338x update last message seen to be the current message.
339r mail a reply to this news article. Like m but initializes some fields.
340u unsubscribe from current newsgroup.
341U unsubscribe from specified newsgroup."
342 (interactive)
343 (kill-all-local-variables)
344 (make-local-variable 'news-read-first-time-p)
345 (setq news-read-first-time-p t)
346 (make-local-variable 'news-current-news-group)
347; (setq news-current-news-group "??")
348 (make-local-variable 'news-current-group-begin)
349 (setq news-current-group-begin 0)
350 (make-local-variable 'news-current-message-number)
351 (setq news-current-message-number 0)
352 (make-local-variable 'news-total-current-group)
353 (make-local-variable 'news-buffer-save)
354 (make-local-variable 'version-control)
355 (setq version-control 'never)
356 (make-local-variable 'news-point-pdl)
357; This breaks it. I don't have time to figure out why. -- RMS
358; (make-local-variable 'news-group-article-assoc)
359 (setq major-mode 'news-mode)
360 (if (boundp 'minor-mode-alist)
361 ;; Emacs versions 18.16 and up.
362 (setq mode-name '("NEWS" news-minor-modes))
363 ;; Earlier versions display minor-modes via a special mechanism.
364 (setq mode-name "NEWS"))
365 (news-set-mode-line)
366 (set-syntax-table text-mode-syntax-table)
367 (use-local-map news-mode-map)
368 (setq local-abbrev-table text-mode-abbrev-table)
369 (run-hooks 'news-mode-hook))
370
371(defun string-subst-char (new old string)
372 (let (index)
373 (setq old (regexp-quote (char-to-string old))
374 string (substring string 0))
375 (while (setq index (string-match old string))
376 (aset string index new)))
377 string)
378
379;; update read message number
380(defmacro news-update-message-read (ngroup nno)
381 (list 'setcar
382 (list 'news-cdadr
383 (list 'assoc ngroup 'news-group-article-assoc))
384 nno))
385
386(defun news-parse-range (number-string)
387 "Parse string representing range of numbers of he form <a>-<b>
388to a list (a . b)"
389 (let ((n (string-match "-" number-string)))
390 (if n
391 (cons (string-to-int (substring number-string 0 n))
392 (string-to-int (substring number-string (1+ n))))
393 (setq n (string-to-int number-string))
394 (cons n n))))
395
396;(defun is-in (elt lis)
397; (catch 'foo
398; (while lis
399; (if (equal (car lis) elt)
400; (throw 'foo t)
401; (setq lis (cdr lis))))))
402
403(defun news-get-new-news ()
404 "Get new USENET news, if there is any for the current user."
405 (interactive)
406 (if (not (null news-user-group-list))
407 (news-update-newsrc-file))
408 (setq news-group-article-assoc ())
409 (setq news-user-group-list ())
410 (message "Looking up %s file..." news-startup-file)
411 (let ((file (substitute-in-file-name news-startup-file))
412 (temp-user-groups ()))
413 (save-excursion
414 (let ((newsrcbuf (find-file-noselect file))
415 start end endofline tem)
416 (set-buffer newsrcbuf)
417 (goto-char 0)
418 (while (search-forward ": " nil t)
419 (setq end (point))
420 (beginning-of-line)
421 (setq start (point))
422 (end-of-line)
423 (setq endofline (point))
424 (setq tem (buffer-substring start (- end 2)))
425 (let ((range (news-parse-range
426 (buffer-substring end endofline))))
427 (if (assoc tem news-group-article-assoc)
428 (message "You are subscribed twice to %s; I ignore second"
429 tem)
430 (setq temp-user-groups (cons tem temp-user-groups)
431 news-group-article-assoc
432 (cons (list tem (list (car range)
433 (cdr range)
434 (cdr range)))
435 news-group-article-assoc)))))
436 (kill-buffer newsrcbuf)))
437 (setq temp-user-groups (nreverse temp-user-groups))
438 (message "Prefrobnicating...")
439 (switch-to-buffer news-buffer)
440 (setq news-user-group-list temp-user-groups)
441 (while (and temp-user-groups
442 (not (news-read-files-into-buffer
443 (car temp-user-groups) nil)))
444 (setq temp-user-groups (cdr temp-user-groups)))
445 (if (null temp-user-groups)
446 (message "No news is good news.")
447 (message ""))))
448
449(defun news-list-news-groups ()
450 "Display all the news groups to which you belong."
451 (interactive)
452 (with-output-to-temp-buffer "*Newsgroups*"
453 (save-excursion
454 (set-buffer standard-output)
455 (insert
456 "News Group Msg No. News Group Msg No.\n")
457 (insert
458 "------------------------- -------------------------\n")
459 (let ((temp news-user-group-list)
460 (flag nil))
461 (while temp
462 (let ((item (assoc (car temp) news-group-article-assoc)))
463 (insert (car item))
464 (indent-to (if flag 52 20))
465 (insert (int-to-string (news-cadr (news-cadr item))))
466 (if flag
467 (insert "\n")
468 (indent-to 33))
469 (setq temp (cdr temp) flag (not flag))))))))
470
471;; Mode line hack
472(defun news-set-mode-line ()
473 "Set mode line string to something useful."
474 (setq mode-line-process
475 (concat " "
476 (if (integerp news-current-message-number)
477 (int-to-string news-current-message-number)
478 "??")
479 "/"
480 (if (integerp news-current-group-end)
481 (int-to-string news-current-group-end)
482 news-current-group-end)))
483 (setq mode-line-buffer-identification
484 (concat "NEWS: "
485 news-current-news-group
486 ;; Enough spaces to pad group name to 17 positions.
487 (substring " "
488 0 (max 0 (- 17 (length news-current-news-group))))))
489 (set-buffer-modified-p t)
490 (sit-for 0))
491
492(defun news-goto-news-group (gp)
493 "Takes a string and goes to that news group."
494 (interactive (list (completing-read "NewsGroup: "
495 news-group-article-assoc)))
496 (message "Jumping to news group %s..." gp)
497 (news-select-news-group gp)
498 (message "Jumping to news group %s... done." gp))
499
500(defun news-select-news-group (gp)
501 (let ((grp (assoc gp news-group-article-assoc)))
502 (if (null grp)
503 (error "Group %s not subscribed to" gp)
504 (progn
505 (news-update-message-read news-current-news-group
506 (news-cdar news-point-pdl))
507 (news-read-files-into-buffer (car grp) nil)
508 (news-set-mode-line)))))
509
510(defun news-goto-message (arg)
511 "Goes to the article ARG in current newsgroup."
512 (interactive "p")
513 (if (null current-prefix-arg)
514 (setq arg (read-no-blanks-input "Go to article: " "")))
515 (news-select-message arg))
516
517(defun news-select-message (arg)
518 (if (stringp arg) (setq arg (string-to-int arg)))
519 (let ((file (concat news-path
520 (string-subst-char ?/ ?. news-current-news-group)
521 "/" arg)))
522 (if (file-exists-p file)
523 (let ((buffer-read-only ()))
524 (if (= arg
525 (or (news-cadr (memq (news-cdar news-point-pdl) news-list-of-files))
526 0))
527 (setcdr (car news-point-pdl) arg))
528 (setq news-current-message-number arg)
529 (news-read-in-file file)
530 (news-set-mode-line))
531 (error "Article %d nonexistent" arg))))
532
533(defun news-force-update ()
534 "updates the position of last article read in the current news group"
535 (interactive)
536 (setcdr (car news-point-pdl) news-current-message-number)
537 (message "Updated to %d" news-current-message-number))
538
539(defun news-next-message (arg)
540 "Move ARG messages forward within one newsgroup.
541Negative ARG moves backward.
542If ARG is 1 or -1, moves to next or previous newsgroup if at end."
543 (interactive "p")
544 (let ((no (+ arg news-current-message-number)))
545 (if (or (< no news-current-group-begin)
546 (> no news-current-group-end))
547 (cond ((= arg 1)
548 (news-set-current-group-certification)
549 (news-next-group))
550 ((= arg -1)
551 (news-previous-group))
552 (t (error "Article out of range")))
553 (let ((plist (news-get-motion-lists
554 news-current-message-number
555 news-list-of-files)))
556 (if (< arg 0)
557 (news-select-message (nth (1- (- arg)) (car (cdr plist))))
558 (news-select-message (nth (1- arg) (car plist))))))))
559
560(defun news-previous-message (arg)
561 "Move ARG messages backward in current newsgroup.
562With no arg or arg of 1, move one message
563and move to previous newsgroup if at beginning.
564A negative ARG means move forward."
565 (interactive "p")
566 (news-next-message (- arg)))
567
568(defun news-move-to-group (arg)
569 "Given arg move forward or backward to a new newsgroup."
570 (let ((cg news-current-news-group))
571 (let ((plist (news-get-motion-lists cg news-user-group-list))
572 ngrp)
573 (if (< arg 0)
574 (or (setq ngrp (nth (1- (- arg)) (news-cadr plist)))
575 (error "No previous news groups"))
576 (or (setq ngrp (nth arg (car plist)))
577 (error "No more news groups")))
578 (news-select-news-group ngrp))))
579
580(defun news-next-group ()
581 "Moves to the next user group."
582 (interactive)
583; (message "Moving to next group...")
584 (news-move-to-group 0)
585 (while (null news-list-of-files)
586 (news-move-to-group 0)))
587; (message "Moving to next group... done.")
588
589(defun news-previous-group ()
590 "Moves to the previous user group."
591 (interactive)
592; (message "Moving to previous group...")
593 (news-move-to-group -1)
594 (while (null news-list-of-files)
595 (news-move-to-group -1)))
596; (message "Moving to previous group... done.")
597
598(defun news-get-motion-lists (arg listy)
599 "Given a msgnumber/group this will return a list of two lists;
600one for moving forward and one for moving backward."
601 (let ((temp listy)
602 (result ()))
603 (catch 'out
604 (while temp
605 (if (equal (car temp) arg)
606 (throw 'out (cons (cdr temp) (list result)))
607 (setq result (nconc (list (car temp)) result))
608 (setq temp (cdr temp)))))))
609
610;; miscellaneous io routines
611(defun news-read-in-file (filename)
612 (erase-buffer)
613 (let ((start (point)))
614 (insert-file-contents filename)
615 (news-convert-format)
616 ;; Run each hook that applies to the current newsgroup.
617 (let ((hooks news-group-hook-alist))
618 (while hooks
619 (goto-char start)
620 (if (string-match (car (car hooks)) news-group-name)
621 (funcall (cdr (car hooks))))
622 (setq hooks (cdr hooks))))
623 (goto-char start)
624 (forward-line 1)
625 (if (eobp)
626 (message "(Empty file?)")
627 (goto-char start))))
628
629(defun news-convert-format ()
630 (save-excursion
631 (save-restriction
632 (let* ((start (point))
633 (end (condition-case ()
634 (progn (search-forward "\n\n") (point))
635 (error nil)))
636 has-from has-date)
637 (cond (end
638 (narrow-to-region start end)
639 (goto-char start)
640 (setq has-from (search-forward "\nFrom:" nil t))
641 (cond ((and (not has-from) has-date)
642 (goto-char start)
643 (search-forward "\nDate:")
644 (beginning-of-line)
645 (kill-line) (kill-line)))
646 (news-delete-headers start)
647 (goto-char start)))))))
648
649(defun news-show-all-headers ()
650 "Redisplay current news item with all original headers"
651 (interactive)
652 (let (news-ignored-headers
653 (buffer-read-only ()))
654 (erase-buffer)
655 (news-set-mode-line)
656 (news-read-in-file
657 (concat news-path
658 (string-subst-char ?/ ?. news-current-news-group)
659 "/" (int-to-string news-current-message-number)))))
660
661(defun news-delete-headers (pos)
662 (goto-char pos)
663 (and (stringp news-ignored-headers)
664 (while (re-search-forward news-ignored-headers nil t)
665 (beginning-of-line)
666 (delete-region (point)
667 (progn (re-search-forward "\n[^ \t]")
668 (forward-char -1)
669 (point))))))
670
671(defun news-exit ()
672 "Quit news reading session and update the .newsrc file."
673 (interactive)
674 (if (y-or-n-p "Do you really wanna quit reading news ? ")
675 (progn (message "Updating %s..." news-startup-file)
676 (news-update-newsrc-file)
677 (news-write-certifications)
678 (message "Updating %s... done" news-startup-file)
679 (message "Now do some real work")
680 (and (fboundp 'bury-buffer) (bury-buffer (current-buffer)))
681 (switch-to-buffer news-buffer-save)
682 (setq news-user-group-list ()))
683 (message "")))
684
685(defun news-update-newsrc-file ()
686 "Updates the .newsrc file in the users home dir."
687 (let ((newsrcbuf (find-file-noselect
688 (substitute-in-file-name news-startup-file)))
689 (tem news-user-group-list)
690 group)
691 (save-excursion
692 (if (not (null news-current-news-group))
693 (news-update-message-read news-current-news-group
694 (news-cdar news-point-pdl)))
695 (set-buffer newsrcbuf)
696 (while tem
697 (setq group (assoc (car tem) news-group-article-assoc))
698 (if (= (news-cadr (news-cadr group)) (news-caddr (news-cadr group)))
699 nil
700 (goto-char 0)
701 (if (search-forward (concat (car group) ": ") nil t)
702 (kill-line nil)
703 (insert (car group) ": \n") (backward-char 1))
704 (insert (int-to-string (car (news-cadr group))) "-"
705 (int-to-string (news-cadr (news-cadr group)))))
706 (setq tem (cdr tem)))
707 (while news-unsubscribe-groups
708 (setq group (assoc (car news-unsubscribe-groups)
709 news-group-article-assoc))
710 (goto-char 0)
711 (if (search-forward (concat (car group) ": ") nil t)
712 (progn
713 (backward-char 2)
714 (kill-line nil)
715 (insert "! " (int-to-string (car (news-cadr group)))
716 "-" (int-to-string (news-cadr (news-cadr group))))))
717 (setq news-unsubscribe-groups (cdr news-unsubscribe-groups)))
718 (save-buffer)
719 (kill-buffer (current-buffer)))))
720
721
722(defun news-unsubscribe-group (group)
723 "Removes you from newgroup GROUP."
724 (interactive (list (completing-read "Unsubscribe from group: "
725 news-group-article-assoc)))
726 (news-unsubscribe-internal group))
727
728(defun news-unsubscribe-current-group ()
729 "Removes you from the newsgroup you are now reading."
730 (interactive)
731 (if (y-or-n-p "Do you really want to unsubscribe from this group ? ")
732 (news-unsubscribe-internal news-current-news-group)))
733
734(defun news-unsubscribe-internal (group)
735 (let ((tem (assoc group news-group-article-assoc)))
736 (if tem
737 (progn
738 (setq news-unsubscribe-groups (cons group news-unsubscribe-groups))
739 (news-update-message-read group (news-cdar news-point-pdl))
740 (if (equal group news-current-news-group)
741 (news-next-group))
742 (message ""))
743 (error "Not subscribed to group: %s" group))))
744
745(defun news-save-item-in-file (file)
746 "Save the current article that is being read by appending to a file."
747 (interactive "FSave item in file: ")
748 (append-to-file (point-min) (point-max) file))
749
750(defun news-get-pruned-list-of-files (gp-list end-file-no)
751 "Given a news group it finds all files in the news group.
752The arg must be in slashified format.
753Using ls was found to be too slow in a previous version."
754 (let
755 ((answer
756 (and
757 (not (and end-file-no
758 (equal (news-set-current-certifiable)
759 (news-group-certification gp-list))
760 (setq news-list-of-files nil
761 news-list-of-files-possibly-bogus t)))
762 (let* ((file-directory (concat news-path
763 (string-subst-char ?/ ?. gp-list)))
764 tem
765 (last-winner
766 (and end-file-no
767 (news-wins file-directory end-file-no)
768 (news-find-first-or-last file-directory end-file-no 1))))
769 (setq news-list-of-files-possibly-bogus t news-list-of-files nil)
770 (if last-winner
771 (progn
772 (setq news-list-of-files-possibly-bogus t
773 news-current-group-end last-winner)
774 (while (> last-winner end-file-no)
775 (news-push last-winner news-list-of-files)
776 (setq last-winner (1- last-winner)))
777 news-list-of-files)
778 (if (or (not (file-directory-p file-directory))
779 (not (file-readable-p file-directory)))
780 nil
781 (setq news-list-of-files
782 (condition-case error
783 (directory-files file-directory)
784 (file-error
785 (if (string= (nth 2 error) "permission denied")
786 (message "Newsgroup %s is read-protected"
787 gp-list)
788 (signal 'file-error (cdr error)))
789 nil)))
790 (setq tem news-list-of-files)
791 (while tem
792 (if (or (not (string-match "^[0-9]*$" (car tem)))
793 ;; dont get confused by directories that look like numbers
794 (file-directory-p
795 (concat file-directory "/" (car tem)))
796 (<= (string-to-int (car tem)) end-file-no))
797 (setq news-list-of-files
798 (delq (car tem) news-list-of-files)))
799 (setq tem (cdr tem)))
800 (if (null news-list-of-files)
801 (progn (setq news-current-group-end 0)
802 nil)
803 (setq news-list-of-files
804 (mapcar 'string-to-int news-list-of-files))
805 (setq news-list-of-files (sort news-list-of-files '<))
806 (setq news-current-group-end
807 (elt news-list-of-files
808 (1- (length news-list-of-files))))
809 news-list-of-files)))))))
810 (or answer (progn (news-set-current-group-certification) nil))))
811
812(defun news-read-files-into-buffer (group reversep)
813 (let* ((files-start-end (news-cadr (assoc group news-group-article-assoc)))
814 (start-file-no (car files-start-end))
815 (end-file-no (news-cadr files-start-end))
816 (buffer-read-only nil))
817 (setq news-current-news-group group)
818 (setq news-current-message-number nil)
819 (setq news-current-group-end nil)
820 (news-set-mode-line)
821 (news-get-pruned-list-of-files group end-file-no)
822 (news-set-mode-line)
823 ;; @@ should be a lot smarter than this if we have to move
824 ;; @@ around correctly.
825 (setq news-point-pdl (list (cons (car files-start-end)
826 (news-cadr files-start-end))))
827 (if (null news-list-of-files)
828 (progn (erase-buffer)
829 (setq news-current-group-end end-file-no)
830 (setq news-current-group-begin end-file-no)
831 (setq news-current-message-number end-file-no)
832 (news-set-mode-line)
833; (message "No new articles in " group " group.")
834 nil)
835 (setq news-current-group-begin (car news-list-of-files))
836 (if reversep
837 (setq news-current-message-number news-current-group-end)
838 (if (> (car news-list-of-files) end-file-no)
839 (setcdr (car news-point-pdl) (car news-list-of-files)))
840 (setq news-current-message-number news-current-group-begin))
841 (news-set-message-counters)
842 (news-set-mode-line)
843 (news-read-in-file (concat news-path
844 (string-subst-char ?/ ?. group)
845 "/"
846 (int-to-string
847 news-current-message-number)))
848 (news-set-message-counters)
849 (news-set-mode-line)
850 t)))
851
852(defun news-add-news-group (gp)
853 "Resubscribe to or add a USENET news group named GROUP (a string)."
854; @@ (completing-read ...)
855; @@ could be based on news library file ../active (slightly facist)
856; @@ or (expensive to compute) all directories under the news spool directory
857 (interactive "sAdd news group: ")
858 (let ((file-dir (concat news-path (string-subst-char ?/ ?. gp))))
859 (save-excursion
860 (if (null (assoc gp news-group-article-assoc))
861 (let ((newsrcbuf (find-file-noselect
862 (substitute-in-file-name news-startup-file))))
863 (if (file-directory-p file-dir)
864 (progn
865 (switch-to-buffer newsrcbuf)
866 (goto-char 0)
867 (if (search-forward (concat gp "! ") nil t)
868 (progn
869 (message "Re-subscribing to group %s." gp)
870 ;;@@ news-unsubscribe-groups isn't being used
871 ;;(setq news-unsubscribe-groups
872 ;; (delq gp news-unsubscribe-groups))
873 (backward-char 2)
874 (delete-char 1)
875 (insert ":"))
876 (progn
877 (message
878 "Added %s to your list of newsgroups." gp)
879 (end-of-buffer)
880 (insert gp ": 1-1\n")))
881 (search-backward gp nil t)
882 (let (start end endofline tem)
883 (search-forward ": " nil t)
884 (setq end (point))
885 (beginning-of-line)
886 (setq start (point))
887 (end-of-line)
888 (setq endofline (point))
889 (setq tem (buffer-substring start (- end 2)))
890 (let ((range (news-parse-range
891 (buffer-substring end endofline))))
892 (setq news-group-article-assoc
893 (cons (list tem (list (car range)
894 (cdr range)
895 (cdr range)))
896 news-group-article-assoc))))
897 (save-buffer)
898 (kill-buffer (current-buffer)))
899 (message "Newsgroup %s doesn't exist." gp)))
900 (message "Already subscribed to group %s." gp)))))
901
902(defun news-make-link-to-message (number newname)
903 "Forges a link to an rnews message numbered number (current if no arg)
904Good for hanging on to a message that might or might not be
905automatically deleted."
906 (interactive "P
907FName to link to message: ")
908 (add-name-to-file
909 (concat news-path
910 (string-subst-char ?/ ?. news-current-news-group)
911 "/" (if number
912 (prefix-numeric-value number)
913 news-current-message-number))
914 newname))
915
916;;; caesar-region written by phr@prep.ai.mit.edu Nov 86
917;;; modified by tower@prep Nov 86
918(defun caesar-region (&optional n)
919 "Caesar rotation of region by N, default 13, for decrypting netnews."
920 (interactive (if current-prefix-arg ; Was there a prefix arg?
921 (list (prefix-numeric-value current-prefix-arg))
922 (list nil)))
923 (cond ((not (numberp n)) (setq n 13))
924 ((< n 0) (setq n (- 26 (% (- n) 26))))
925 (t (setq n (% n 26)))) ;canonicalize N
926 (if (not (zerop n)) ; no action needed for a rot of 0
927 (progn
928 (if (or (not (boundp 'caesar-translate-table))
929 (/= (aref caesar-translate-table ?a) (+ ?a n)))
930 (let ((i 0) (lower "abcdefghijklmnopqrstuvwxyz") upper)
931 (message "Building caesar-translate-table...")
932 (setq caesar-translate-table (make-vector 256 0))
933 (while (< i 256)
934 (aset caesar-translate-table i i)
935 (setq i (1+ i)))
936 (setq lower (concat lower lower) upper (upcase lower) i 0)
937 (while (< i 26)
938 (aset caesar-translate-table (+ ?a i) (aref lower (+ i n)))
939 (aset caesar-translate-table (+ ?A i) (aref upper (+ i n)))
940 (setq i (1+ i)))
941 (message "Building caesar-translate-table... done")))
942 (let ((from (region-beginning))
943 (to (region-end))
944 (i 0) str len)
945 (setq str (buffer-substring from to))
946 (setq len (length str))
947 (while (< i len)
948 (aset str i (aref caesar-translate-table (aref str i)))
949 (setq i (1+ i)))
950 (goto-char from)
951 (kill-region from to)
952 (insert str)))))
953
954;;; news-caesar-buffer-body written by paul@media-lab.mit.edu Wed Oct 1, 1986
955;;; hacked further by tower@prep.ai.mit.edu
956(defun news-caesar-buffer-body (&optional rotnum)
957 "Caesar rotates all letters in the current buffer by 13 places.
958Used to encode/decode possibly offensive messages (commonly in net.jokes).
959With prefix arg, specifies the number of places to rotate each letter forward.
960Mail and USENET news headers are not rotated."
961 (interactive (if current-prefix-arg ; Was there a prefix arg?
962 (list (prefix-numeric-value current-prefix-arg))
963 (list nil)))
964 (save-excursion
965 (let ((buffer-status buffer-read-only))
966 (setq buffer-read-only nil)
967 ;; setup the region
968 (set-mark (if (progn (goto-char (point-min))
969 (search-forward
970 (concat "\n"
971 (if (equal major-mode 'news-mode)
972 ""
973 mail-header-separator)
974 "\n") nil t))
975 (point)
976 (point-min)))
977 (goto-char (point-max))
978 (caesar-region rotnum)
979 (setq buffer-read-only buffer-status))))
diff --git a/lisp/mail/rnewspost.el b/lisp/mail/rnewspost.el
new file mode 100644
index 00000000000..adb65e6f3ab
--- /dev/null
+++ b/lisp/mail/rnewspost.el
@@ -0,0 +1,390 @@
1;;; USENET news poster/mailer for GNU Emacs
2;; Copyright (C) 1985, 1986, 1987 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;; moved posting and mail code from rnews.el
21;; tower@prep.ai.mit.edu Wed Oct 29 1986
22;; brought posting code almost up to the revision of RFC 850 for News 2.11
23;; - couldn't see handling the special meaning of the Keyword: poster
24;; - not worth the code space to support the old A news Title: (which
25;; Subject: replaced) and Article-I.D.: (which Message-ID: replaced)
26;; tower@prep Nov 86
27;; changed C-c C-r key-binding due to rename of news-caesar-buffer-body
28;; tower@prep 21 Nov 86
29;; added (require 'rnews) tower@prep 22 Apr 87
30;; restricted call of news-show-all-headers in news-post-news & news-reply
31;; tower@prep 28 Apr 87
32;; commented out Posting-Front-End to save USENET bytes tower@prep Jul 31 87
33;; commented out -n and -t args in news-inews tower@prep 15 Oct 87
34(require 'sendmail)
35(require 'rnews)
36
37;Now in paths.el.
38;(defvar news-inews-program "inews"
39; "Function to post news.")
40
41;; Replying and posting news items are done by these functions.
42;; imported from rmail and modified to work with rnews ...
43;; Mon Mar 25,1985 at 03:07:04 ads@mit-hermes.
44;; this is done so that rnews can operate independently from rmail.el and
45;; sendmail and dosen't have to autoload these functions.
46;;
47;;; >> Nuked by Mly to autoload those functions again, as the duplication of
48;;; >> code was making maintenance too difficult.
49
50(defvar news-reply-mode-map () "Mode map used by news-reply.")
51
52(or news-reply-mode-map
53 (progn
54 (setq news-reply-mode-map (make-keymap))
55 (define-key news-reply-mode-map "\C-c?" 'describe-mode)
56 (define-key news-reply-mode-map "\C-c\C-f\C-d" 'news-reply-distribution)
57 (define-key news-reply-mode-map "\C-c\C-f\C-k" 'news-reply-keywords)
58 (define-key news-reply-mode-map "\C-c\C-f\C-n" 'news-reply-newsgroups)
59 (define-key news-reply-mode-map "\C-c\C-f\C-f" 'news-reply-followup-to)
60 (define-key news-reply-mode-map "\C-c\C-f\C-s" 'mail-subject)
61 (define-key news-reply-mode-map "\C-c\C-f\C-a" 'news-reply-summary)
62 (define-key news-reply-mode-map "\C-c\C-r" 'news-caesar-buffer-body)
63 (define-key news-reply-mode-map "\C-c\C-w" 'news-reply-signature)
64 (define-key news-reply-mode-map "\C-c\C-y" 'news-reply-yank-original)
65 (define-key news-reply-mode-map "\C-c\C-q" 'mail-fill-yanked-message)
66 (define-key news-reply-mode-map "\C-c\C-c" 'news-inews)
67 (define-key news-reply-mode-map "\C-c\C-s" 'news-inews)))
68
69(defun news-reply-mode ()
70 "Major mode for editing news to be posted on USENET.
71First-time posters are asked to please read the articles in newsgroup:
72 news.announce.newusers .
73Like Text Mode but with these additional commands:
74
75C-c C-s news-inews (post the message) C-c C-c news-inews
76C-c C-f move to a header field (and create it if there isn't):
77 C-c C-f C-n move to Newsgroups: C-c C-f C-s move to Subj:
78 C-c C-f C-f move to Followup-To: C-c C-f C-k move to Keywords:
79 C-c C-f C-d move to Distribution: C-c C-f C-a move to Summary:
80C-c C-y news-reply-yank-original (insert current message, in NEWS).
81C-c C-q mail-fill-yanked-message (fill what was yanked).
82C-c C-r caesar rotate all letters by 13 places in the article's body (rot13)."
83 (interactive)
84 ;; require...
85 (or (fboundp 'mail-setup) (load "sendmail"))
86 (kill-all-local-variables)
87 (make-local-variable 'mail-reply-buffer)
88 (setq mail-reply-buffer nil)
89 (set-syntax-table text-mode-syntax-table)
90 (use-local-map news-reply-mode-map)
91 (setq local-abbrev-table text-mode-abbrev-table)
92 (setq major-mode 'news-reply-mode)
93 (setq mode-name "News")
94 (make-local-variable 'paragraph-separate)
95 (make-local-variable 'paragraph-start)
96 (setq paragraph-start (concat "^" mail-header-separator "$\\|"
97 paragraph-start))
98 (setq paragraph-separate (concat "^" mail-header-separator "$\\|"
99 paragraph-separate))
100 (run-hooks 'text-mode-hook 'news-reply-mode-hook))
101
102(defvar news-reply-yank-from
103 "Save From: field for news-reply-yank-original."
104 "")
105
106(defvar news-reply-yank-message-id
107 "Save Message-Id: field for news-reply-yank-original."
108 "")
109
110(defun news-reply-yank-original (arg)
111 "Insert the message being replied to, if any (in rmail).
112Puts point before the text and mark after.
113Indents each nonblank line ARG spaces (default 3).
114Just \\[universal-argument] as argument means don't indent
115and don't delete any header fields."
116 (interactive "P")
117 (mail-yank-original arg)
118 (exchange-point-and-mark)
119 (run-hooks 'news-reply-header-hook))
120
121(defvar news-reply-header-hook
122 '(lambda ()
123 (insert "In article " news-reply-yank-message-id
124 " " news-reply-yank-from " writes:\n\n"))
125 "Hook for inserting a header at the top of a yanked message.")
126
127(defun news-reply-newsgroups ()
128 "Move point to end of Newsgroups: field.
129RFC 850 constrains the Newsgroups: field to be a comma separated list of valid
130newsgroups names at your site:
131Newsgroups: news.misc,comp.misc,rec.misc"
132 (interactive)
133 (expand-abbrev)
134 (goto-char (point-min))
135 (mail-position-on-field "Newsgroups"))
136
137(defun news-reply-followup-to ()
138 "Move point to end of Followup-To: field. Create the field if none.
139One usually requests followups to only one newsgroup.
140RFC 850 constrains the Followup-To: field to be a comma separated list of valid
141newsgroups names at your site, that are also in the Newsgroups: field:
142Newsgroups: news.misc,comp.misc,rec.misc,misc.misc,soc.misc
143Followup-To: news.misc,comp.misc,rec.misc"
144 (interactive)
145 (expand-abbrev)
146 (or (mail-position-on-field "Followup-To" t)
147 (progn (mail-position-on-field "newsgroups")
148 (insert "\nFollowup-To: ")))
149 ;; @@ could do a completing read based on the Newsgroups: field to
150 ;; @@ fill in the Followup-To: field
151)
152
153(defun news-reply-distribution ()
154 "Move point to end of Distribution: optional field.
155Create the field if none. Without this field the posting goes to all of
156USENET. The field is used to restrict the posting to parts of USENET."
157 (interactive)
158 (expand-abbrev)
159 (mail-position-on-field "Distribution")
160 ;; @@could do a completing read based on the news library file:
161 ;; @@ ../distributions to fill in the field.
162 )
163
164(defun news-reply-keywords ()
165 "Move point to end of Keywords: optional field. Create the field if none.
166Used as an aid to the news reader, it can contain a few, well selected keywords
167identifying the message."
168 (interactive)
169 (expand-abbrev)
170 (mail-position-on-field "Keywords"))
171
172(defun news-reply-summary ()
173 "Move point to end of Summary: optional field. Create the field if none.
174Used as an aid to the news reader, it can contain a succinct
175summary (abstract) of the message."
176 (interactive)
177 (expand-abbrev)
178 (mail-position-on-field "Summary"))
179
180(defun news-reply-signature ()
181 "The inews program appends ~/.signature automatically."
182 (interactive)
183 (message "~/.signature will be appended automatically."))
184
185(defun news-setup (to subject in-reply-to newsgroups replybuffer)
186 "Setup the news reply or posting buffer with the proper headers and in
187news-reply-mode."
188 (setq mail-reply-buffer replybuffer)
189 (let ((mail-setup-hook nil))
190 (if (null to)
191 ;; this hack is needed so that inews wont be confused by
192 ;; the fcc: and bcc: fields
193 (let ((mail-self-blind nil)
194 (mail-archive-file-name nil))
195 (mail-setup to subject in-reply-to nil replybuffer nil)
196 (beginning-of-line)
197 (kill-line 1)
198 (goto-char (point-max)))
199 (mail-setup to subject in-reply-to nil replybuffer nil))
200 ;;;(mail-position-on-field "Posting-Front-End")
201 ;;;(insert (emacs-version))
202 (goto-char (point-max))
203 (if (let ((case-fold-search t))
204 (re-search-backward "^Subject:" (point-min) t))
205 (progn (beginning-of-line)
206 (insert "Newsgroups: " (or newsgroups "") "\n")
207 (if (not newsgroups)
208 (backward-char 1)
209 (goto-char (point-max)))))
210 (run-hooks 'news-setup-hook)))
211
212(defun news-inews ()
213 "Send a news message using inews."
214 (interactive)
215 (let* (newsgroups subject
216 (case-fold-search nil))
217 (save-excursion
218 (save-restriction
219 (goto-char (point-min))
220 (search-forward (concat "\n" mail-header-separator "\n"))
221 (narrow-to-region (point-min) (point))
222 (setq newsgroups (mail-fetch-field "newsgroups")
223 subject (mail-fetch-field "subject")))
224 (widen)
225 (goto-char (point-min))
226 (run-hooks 'news-inews-hook)
227 (goto-char (point-min))
228 (search-forward (concat "\n" mail-header-separator "\n"))
229 (replace-match "\n\n")
230 (goto-char (point-max))
231 ;; require a newline at the end for inews to append .signature to
232 (or (= (preceding-char) ?\n)
233 (insert ?\n))
234 (message "Posting to USENET...")
235 (call-process-region (point-min) (point-max)
236 news-inews-program nil 0 nil
237 "-h") ; take all header lines!
238 ;@@ setting of subject and newsgroups still needed?
239 ;"-t" subject
240 ;"-n" newsgroups
241 (message "Posting to USENET... done")
242 (goto-char (point-min)) ;restore internal header separator
243 (search-forward "\n\n")
244 (replace-match (concat "\n" mail-header-separator "\n"))
245 (set-buffer-modified-p nil))
246 (and (fboundp 'bury-buffer) (bury-buffer))))
247
248;@@ shares some code with news-reply and news-post-news
249(defun news-mail-reply ()
250 "Mail a reply to the author of the current article.
251While composing the reply, use \\[news-reply-yank-original] to yank the
252original message into it."
253 (interactive)
254 (let (from cc subject date to reply-to
255 (buffer (current-buffer)))
256 (save-restriction
257 (narrow-to-region (point-min) (progn (goto-line (point-min))
258 (search-forward "\n\n")
259 (- (point) 1)))
260 (setq from (mail-fetch-field "from")
261 subject (mail-fetch-field "subject")
262 reply-to (mail-fetch-field "reply-to")
263 date (mail-fetch-field "date"))
264 (setq to from)
265 (pop-to-buffer "*mail*")
266 (mail nil
267 (if reply-to reply-to to)
268 subject
269 (let ((stop-pos (string-match " *at \\| *@ \\| *(\\| *<" from)))
270 (concat (if stop-pos (substring from 0 stop-pos) from)
271 "'s message of "
272 date))
273 nil
274 buffer))))
275
276;@@ the guts of news-reply and news-post-news should be combined. -tower
277(defun news-reply ()
278 "Compose and post a reply (aka a followup) to the current article on USENET.
279While composing the followup, use \\[news-reply-yank-original] to yank the
280original message into it."
281 (interactive)
282 (if (y-or-n-p "Are you sure you want to followup to all of USENET? ")
283 (let (from cc subject date to followup-to newsgroups message-of
284 references distribution message-id
285 (buffer (current-buffer)))
286 (save-restriction
287 (and (not (= 0 (buffer-size))) ;@@real problem is non-existence of
288 ;@@ of article file
289 (equal major-mode 'news-mode) ;@@ if rmail-mode,
290 ;@@ should show full headers
291 (progn
292 (news-show-all-headers) ;@@ should save/restore header state,
293 ;@@ but rnews.el lacks support
294 (narrow-to-region (point-min) (progn (goto-char (point-min))
295 (search-forward "\n\n")
296 (- (point) 1)))))
297 (setq from (mail-fetch-field "from")
298 news-reply-yank-from from
299 ;; @@ not handling old Title: field
300 subject (mail-fetch-field "subject")
301 date (mail-fetch-field "date")
302 followup-to (mail-fetch-field "followup-to")
303 newsgroups (or followup-to
304 (mail-fetch-field "newsgroups"))
305 references (mail-fetch-field "references")
306 ;; @@ not handling old Article-I.D.: field
307 distribution (mail-fetch-field "distribution")
308 message-id (mail-fetch-field "message-id")
309 news-reply-yank-message-id message-id)
310 (pop-to-buffer "*post-news*")
311 (news-reply-mode)
312 (if (and (buffer-modified-p)
313 (not
314 (y-or-n-p "Unsent article being composed; erase it? ")))
315 ()
316 (progn
317 (erase-buffer)
318 (and subject
319 (progn (if (string-match "\\`Re: " subject)
320 (while (string-match "\\`Re: " subject)
321 (setq subject (substring subject 4))))
322 (setq subject (concat "Re: " subject))))
323 (and from
324 (progn
325 (let ((stop-pos
326 (string-match " *at \\| *@ \\| *(\\| *<" from)))
327 (setq message-of
328 (concat
329 (if stop-pos (substring from 0 stop-pos) from)
330 "'s message of "
331 date)))))
332 (news-setup
333 nil
334 subject
335 message-of
336 newsgroups
337 buffer)
338 (if followup-to
339 (progn (news-reply-followup-to)
340 (insert followup-to)))
341 (if distribution
342 (progn
343 (mail-position-on-field "Distribution")
344 (insert distribution)))
345 (mail-position-on-field "References")
346 (if references
347 (insert references))
348 (if (and references message-id)
349 (insert " "))
350 (if message-id
351 (insert message-id))
352 (goto-char (point-max))))))
353 (message "")))
354
355;@@ the guts of news-reply and news-post-news should be combined. -tower
356(defun news-post-news ()
357 "Begin editing a new USENET news article to be posted.
358Type \\[describe-mode] once editing the article to get a list of commands."
359 (interactive)
360 (if (y-or-n-p "Are you sure you want to post to all of USENET? ")
361 (let ((buffer (current-buffer)))
362 (save-restriction
363 (and (not (= 0 (buffer-size))) ;@@real problem is non-existence of
364 ;@@ of article file
365 (equal major-mode 'news-mode) ;@@ if rmail-mode,
366 ;@@ should show full headers
367 (progn
368 (news-show-all-headers) ;@@ should save/restore header state,
369 ;@@ but rnews.el lacks support
370 (narrow-to-region (point-min) (progn (goto-char (point-min))
371 (search-forward "\n\n")
372 (- (point) 1)))))
373 (setq news-reply-yank-from (mail-fetch-field "from")
374 ;; @@ not handling old Article-I.D.: field
375 news-reply-yank-message-id (mail-fetch-field "message-id")))
376 (pop-to-buffer "*post-news*")
377 (news-reply-mode)
378 (if (and (buffer-modified-p)
379 (not (y-or-n-p "Unsent article being composed; erase it? ")))
380 () ;@@ not saving point from last time
381 (progn (erase-buffer)
382 (news-setup () () () () buffer))))
383 (message "")))
384
385(defun news-mail-other-window ()
386 "Send mail in another window.
387While composing the message, use \\[news-reply-yank-original] to yank the
388original message into it."
389 (interactive)
390 (mail-other-window nil nil nil nil nil (current-buffer)))
diff --git a/lisp/mail/undigest.el b/lisp/mail/undigest.el
new file mode 100644
index 00000000000..583251e990f
--- /dev/null
+++ b/lisp/mail/undigest.el
@@ -0,0 +1,105 @@
1;; "RMAIL" mail reader for Emacs.
2;; Copyright (C) 1985, 1986 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;; note Interent RFP934
21
22(defun undigestify-rmail-message ()
23 "Break up a digest message into its constituent messages.
24Leaves original message, deleted, before the undigestified messages."
25 (interactive)
26 (widen)
27 (let ((buffer-read-only nil)
28 (msg-string (buffer-substring (rmail-msgbeg rmail-current-message)
29 (rmail-msgend rmail-current-message))))
30 (goto-char (rmail-msgend rmail-current-message))
31 (narrow-to-region (point) (point))
32 (insert msg-string)
33 (narrow-to-region (point-min) (1- (point-max))))
34 (let ((error t)
35 (buffer-read-only nil))
36 (unwind-protect
37 (progn
38 (save-restriction
39 (goto-char (point-min))
40 (delete-region (point-min)
41 (progn (search-forward "\n*** EOOH ***\n")
42 (point)))
43 (insert "\^_\^L\n0, unseen,,\n*** EOOH ***\n")
44 (narrow-to-region (point)
45 (point-max))
46 (let* ((fill-prefix "")
47 (case-fold-search t)
48 (digest-name
49 (mail-strip-quoted-names
50 (or (save-restriction
51 (search-forward "\n\n")
52 (narrow-to-region (point-min) (point))
53 (goto-char (point-max))
54 (or (mail-fetch-field "Reply-To")
55 (mail-fetch-field "To")
56 (mail-fetch-field "Apparently-To")
57 (mail-fetch-field "From")))
58 (error "Message is not a digest")))))
59 (save-excursion
60 (goto-char (point-max))
61 (skip-chars-backward " \t\n")
62 (let ((count 10) found)
63 ;; compensate for broken un*x digestifiers. Sigh Sigh.
64 (while (and (> count 0) (not found))
65 (forward-line -1)
66 (setq count (1- count))
67 (if (looking-at (concat "End of.*Digest.*\n"
68 (regexp-quote "*********") "*"
69 "\\(\n------*\\)*"))
70 (setq found t)))
71 (if (not found) (error "Message is not a digest"))))
72 (re-search-forward (concat "^" (make-string 55 ?-) "-*\n*"))
73 (replace-match "\^_\^L\n0, unseen,,\n*** EOOH ***\n")
74 (save-restriction
75 (narrow-to-region (point)
76 (progn (search-forward "\n\n")
77 (point)))
78 (if (mail-fetch-field "To") nil
79 (goto-char (point-min))
80 (insert "To: " digest-name "\n")))
81 (while (re-search-forward
82 (concat "\n\n" (make-string 27 ?-) "-*\n*")
83 nil t)
84 (replace-match "\n\n\^_\^L\n0, unseen,,\n*** EOOH ***\n")
85 (save-restriction
86 (if (looking-at "End ")
87 (insert "To: " digest-name "\n\n")
88 (narrow-to-region (point)
89 (progn (search-forward "\n\n"
90 nil 'move)
91 (point))))
92 (if (mail-fetch-field "To") nil
93 (goto-char (point-min))
94 (insert "To: " digest-name "\n"))))))
95 (setq error nil)
96 (message "Message successfully undigestified")
97 (let ((n rmail-current-message))
98 (rmail-forget-messages)
99 (rmail-show-message n)
100 (rmail-delete-forward)))
101 (cond (error
102 (narrow-to-region (point-min) (1+ (point-max)))
103 (delete-region (point-min) (point-max))
104 (rmail-show-message rmail-current-message))))))
105
diff --git a/lisp/mim-syntax.el b/lisp/mim-syntax.el
new file mode 100644
index 00000000000..c9a95b50f2f
--- /dev/null
+++ b/lisp/mim-syntax.el
@@ -0,0 +1,91 @@
1;; Syntax checker for Mim (MDL).
2;; Copyright (C) 1985 Free Software Foundation, Inc.
3;; Principal author K. Shane Hartman
4
5;; This file is part of GNU Emacs.
6
7;; GNU Emacs is free software; you can redistribute it and/or modify
8;; it under the terms of the GNU General Public License as published by
9;; the Free Software Foundation; either version 1, or (at your option)
10;; any later version.
11
12;; GNU Emacs is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15;; GNU General Public License for more details.
16
17;; You should have received a copy of the GNU General Public License
18;; along with GNU Emacs; see the file COPYING. If not, write to
19;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
20
21
22(require 'mim-mode)
23
24(defun slow-syntax-check-mim ()
25 "Check Mim syntax slowly.
26Points out the context of the error, if the syntax is incorrect."
27 (interactive)
28 (message "checking syntax...")
29 (let ((stop (point-max)) point-stack current last-bracket whoops last-point)
30 (save-excursion
31 (goto-char (point-min))
32 (while (and (not whoops)
33 (re-search-forward "\\s(\\|\\s)\\|\"\\|[\\]" stop t))
34 (setq current (preceding-char))
35 (cond ((= current ?\")
36 (condition-case nil
37 (progn (re-search-forward "[^\\]\"")
38 (setq current nil))
39 (error (setq whoops (point)))))
40 ((= current ?\\)
41 (condition-case nil (forward-char 1) (error nil)))
42 ((= (char-syntax current) ?\))
43 (if (or (not last-bracket)
44 (not (= (logand (lsh (aref (syntax-table) last-bracket) -8)
45 ?\177)
46 current)))
47 (setq whoops (point))
48 (setq last-point (car point-stack))
49 (setq last-bracket (if last-point (char-after (1- last-point))))
50 (setq point-stack (cdr point-stack))))
51 (t
52 (if last-point (setq point-stack (cons last-point point-stack)))
53 (setq last-point (point))
54 (setq last-bracket current)))))
55 (cond ((not (or whoops last-point))
56 (message "Syntax correct"))
57 (whoops
58 (goto-char whoops)
59 (cond ((equal current ?\")
60 (error "Unterminated string"))
61 ((not last-point)
62 (error "Extraneous %s" (char-to-string current)))
63 (t
64 (error "Mismatched %s with %s"
65 (save-excursion
66 (setq whoops (1- (point)))
67 (goto-char (1- last-point))
68 (buffer-substring (point)
69 (min (progn (end-of-line) (point))
70 whoops)))
71 (char-to-string current)))))
72 (t
73 (goto-char last-point)
74 (error "Unmatched %s" (char-to-string last-bracket))))))
75
76(defun fast-syntax-check-mim ()
77 "Checks Mim syntax quickly.
78Answers correct or incorrect, cannot point out the error context."
79 (interactive)
80 (save-excursion
81 (goto-char (point-min))
82 (let (state)
83 (while (and (not (eobp))
84 (equal (car (setq state (parse-partial-sexp (point) (point-max) 0)))
85 0)))
86 (if (equal (car state) 0)
87 (message "Syntax correct")
88 (error "Syntax incorrect")))))
89
90
91
diff --git a/lisp/misc.el b/lisp/misc.el
new file mode 100644
index 00000000000..db7b3f223b5
--- /dev/null
+++ b/lisp/misc.el
@@ -0,0 +1,51 @@
1;; Basic editing commands for Emacs
2;; Copyright (C) 1989 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20
21(defun copy-from-above-command (&optional arg)
22 "Copy characters from previous nonblank line, starting just above point.
23Copy ARG characters, but not past the end of that line.
24If no argument given, copy the entire rest of the line.
25The characters copied are inserted in the buffer before point."
26 (interactive "P")
27 (let ((cc (current-column))
28 n
29 (string ""))
30 (save-excursion
31 (beginning-of-line)
32 (backward-char 1)
33 (skip-chars-backward "\ \t\n")
34 (move-to-column cc)
35 ;; Default is enough to copy the whole rest of the line.
36 (setq n (if arg (prefix-numeric-value arg) (point-max)))
37 ;; If current column winds up in middle of a tab,
38 ;; copy appropriate number of "virtual" space chars.
39 (if (< cc (current-column))
40 (if (= (preceding-char) ?\t)
41 (progn
42 (setq string (make-string (min n (- (current-column) cc)) ?\ ))
43 (setq n (- n (min n (- (current-column) cc)))))
44 ;; In middle of ctl char => copy that whole char.
45 (backward-char 1)))
46 (setq string (concat string
47 (buffer-substring
48 (point)
49 (min (save-excursion (end-of-line) (point))
50 (+ n (point)))))))
51 (insert string)))
diff --git a/lisp/netunam.el b/lisp/netunam.el
new file mode 100644
index 00000000000..44d828729ef
--- /dev/null
+++ b/lisp/netunam.el
@@ -0,0 +1,152 @@
1;; HP-UX RFA Commands
2;; Copyright (C) 1988 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;;; Author: cph@zurich.ai.mit.edu
21
22;;; $Header: netunam.el,v 1.3 88/12/21 16:32:23 GMT cph Exp $
23
24(defconst rfa-node-directory "/net/"
25 "Directory in which RFA network special files are stored.
26By HP convention, this is \"/net/\".")
27
28(defvar rfa-default-node nil
29 "If not nil, this is the name of the default RFA network special file.")
30
31(defvar rfa-password-memoize-p t
32 "If non-nil, remember login user's passwords after they have been entered.")
33
34(defvar rfa-password-alist '()
35 "An association from node-name strings to password strings.
36Used if `rfa-password-memoize-p' is non-nil.")
37
38(defvar rfa-password-per-node-p t
39 "If nil, login user uses same password on all machines.
40Has no effect if `rfa-password-memoize-p' is nil.")
41
42(defun rfa-set-password (password &optional node user)
43 "Add PASSWORD to the RFA password database.
44Optional second arg NODE is a string specifying a particular nodename;
45 if supplied and not nil, PASSWORD applies to only that node.
46Optional third arg USER is a string specifying the (remote) user whose
47 password this is; if not supplied this defaults to (user-login-name)."
48 (if (not user) (setq user (user-login-name)))
49 (let ((node-entry (assoc node rfa-password-alist)))
50 (if node-entry
51 (let ((user-entry (assoc user (cdr node-entry))))
52 (if user-entry
53 (rplacd user-entry password)
54 (rplacd node-entry
55 (nconc (cdr node-entry)
56 (list (cons user password))))))
57 (setq rfa-password-alist
58 (nconc rfa-password-alist
59 (list (list node (cons user password))))))))
60
61(defun rfa-open (node &optional user password)
62 "Open a network connection to a server using remote file access.
63First argument NODE is the network node for the remote machine.
64Second optional argument USER is the user name to use on that machine.
65 If called interactively, the user name is prompted for.
66Third optional argument PASSWORD is the password string for that user.
67 If not given, this is filled in from the value of
68`rfa-password-alist', or prompted for. A prefix argument of - will
69cause the password to be prompted for even if previously memoized."
70 (interactive
71 (list (read-file-name "rfa-open: " rfa-node-directory rfa-default-node t)
72 (read-string "user-name: " (user-login-name))))
73 (let ((node
74 (and (or rfa-password-per-node-p
75 (not (equal user (user-login-name))))
76 node)))
77 (if (not password)
78 (setq password
79 (let ((password
80 (cdr (assoc user (cdr (assoc node rfa-password-alist))))))
81 (or (and (not current-prefix-arg) password)
82 (rfa-password-read
83 (format "password for user %s%s: "
84 user
85 (if node (format " on node \"%s\"" node) ""))
86 password))))))
87 (let ((result
88 (sysnetunam (expand-file-name node rfa-node-directory)
89 (concat user ":" password))))
90 (if (interactive-p)
91 (if result
92 (message "Opened network connection to %s as %s" node user)
93 (error "Unable to open network connection")))
94 (if (and rfa-password-memoize-p result)
95 (rfa-set-password password node user))
96 result))
97
98(defun rfa-close (node)
99 "Close a network connection to a server using remote file access.
100NODE is the network node for the remote machine."
101 (interactive
102 (list (read-file-name "rfa-close: " rfa-node-directory rfa-default-node t)))
103 (let ((result (sysnetunam (expand-file-name node rfa-node-directory) "")))
104 (cond ((not (interactive-p)) result)
105 ((not result) (error "Unable to close network connection"))
106 (t (message "Closed network connection to %s" node)))))
107
108(defun rfa-password-read (prompt default)
109 (let ((rfa-password-accumulator (or default "")))
110 (read-from-minibuffer prompt
111 (and default
112 (let ((copy (concat default))
113 (index 0)
114 (length (length default)))
115 (while (< index length)
116 (aset copy index ?.)
117 (setq index (1+ index)))
118 copy))
119 rfa-password-map)
120 rfa-password-accumulator))
121
122(defvar rfa-password-map nil)
123(if (not rfa-password-map)
124 (let ((char ? ))
125 (setq rfa-password-map (make-keymap))
126 (while (< char 127)
127 (define-key rfa-password-map (char-to-string char)
128 'rfa-password-self-insert)
129 (setq char (1+ char)))
130 (define-key rfa-password-map "\C-g"
131 'abort-recursive-edit)
132 (define-key rfa-password-map "\177"
133 'rfa-password-rubout)
134 (define-key rfa-password-map "\n"
135 'exit-minibuffer)
136 (define-key rfa-password-map "\r"
137 'exit-minibuffer)))
138
139(defvar rfa-password-accumulator nil)
140
141(defun rfa-password-self-insert ()
142 (interactive)
143 (setq rfa-password-accumulator
144 (concat rfa-password-accumulator
145 (char-to-string last-command-char)))
146 (insert ?.))
147
148(defun rfa-password-rubout ()
149 (interactive)
150 (delete-char -1)
151 (setq rfa-password-accumulator
152 (substring rfa-password-accumulator 0 -1)))
diff --git a/lisp/sun-curs.el b/lisp/sun-curs.el
new file mode 100644
index 00000000000..f290e1b3a76
--- /dev/null
+++ b/lisp/sun-curs.el
@@ -0,0 +1,207 @@
1;; Cursor definitions for Sun windows
2;; Copyright (C) 1987 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;;;
21;;; Added some more cursors and moved the hot spots
22;;; Cursor defined by 16 pairs of 16-bit numbers
23;;;
24;;; 9-dec-86 Jeff Peck, Sun Microsystems Inc. <peck@sun.com>
25
26(provide 'sm-cursors)
27
28(defvar sc::cursors nil "List of known cursors")
29
30(defmacro defcursor (name x y string)
31 (if (not (memq name sc::cursors))
32 (setq sc::cursors (cons name sc::cursors)))
33 (list 'defconst name (list 'vector x y string)))
34
35;;; push should be defined in common lisp, but if not use this:
36;(defmacro push (v l)
37; "The ITEM is evaluated and consed onto LIST, a list-valued atom"
38; (list 'setq l (list 'cons v l)))
39
40;;;
41;;; The standard default cursor
42;;;
43(defcursor sc:right-arrow 15 0
44 (concat '(0 1 0 3 0 7 0 15 0 31 0 63 0 127 0 15
45 0 27 0 25 0 48 0 48 0 96 0 96 0 192 0 192)))
46
47;;(sc:set-cursor sc:right-arrow)
48
49(defcursor sc:fat-left-arrow 0 8
50 (concat '(1 0 3 0 7 0 15 0 31 0 63 255 127 255 255 255
51 255 255 127 255 63 255 31 0 15 0 7 0 3 0 1 0)))
52
53(defcursor sc:box 8 8
54 (concat '(15 252 8 4 8 4 8 4 8 4 8 4 8 4 8 4
55 8 132 8 4 8 4 8 4 8 4 8 4 8 4 15 252)))
56
57(defcursor sc:hourglass 8 8
58 (concat "\177\376\100\002\040\014\032\070"
59 "\017\360\007\340\003\300\001\200"
60 "\001\200\002\100\005\040\010\020"
61 "\021\210\043\304\107\342\177\376"))
62
63(defun sc:set-cursor (icon)
64 "Change the Sun mouse cursor to ICON.
65If ICON is nil, switch to the system default cursor,
66Otherwise, ICON should be a vector or the name of a vector of [x y 32-chars]"
67 (interactive "XIcon Name: ")
68 (if (symbolp icon) (setq icon (symbol-value icon)))
69 (sun-change-cursor-icon icon))
70
71(make-local-variable '*edit-icon*)
72(make-variable-buffer-local 'icon-edit)
73(setq-default icon-edit nil)
74(or (assq 'icon-edit minor-mode-alist)
75 (push '(icon-edit " IconEdit") minor-mode-alist))
76
77(defun sc:edit-cursor (icon)
78 "convert icon to rectangle, edit, and repack"
79 (interactive "XIcon Name: ")
80 (if (not icon) (setq icon (sc::menu-choose-cursor (selected-window) 1 1)))
81 (if (symbolp icon) (setq icon (symbol-value icon)))
82 (if (get-buffer "icon-edit") (kill-buffer "icon-edit"))
83 (switch-to-buffer "icon-edit")
84 (local-set-mouse '(text right) 'sc::menu-function)
85 (local-set-mouse '(text left) '(sc::pic-ins-at-mouse 32))
86 (local-set-mouse '(text middle) '(sc::pic-ins-at-mouse 64))
87 (local-set-mouse '(text left middle) 'sc::hotspot)
88 (sc::display-icon icon)
89 (picture-mode)
90 (setq icon-edit t) ; for mode line display
91)
92
93(defun sc::pic-ins-at-mouse (char)
94 "Picture insert char at mouse location"
95 (mouse-move-point *mouse-window* (min 15 *mouse-x*) (min 15 *mouse-y*))
96 (move-to-column-force (1+ (min 15 (current-column))))
97 (delete-char -1)
98 (insert char)
99 (sc::goto-hotspot))
100
101(defun sc::menu-function (window x y)
102 (sun-menu-evaluate window (1+ x) y sc::menu))
103
104(defmenu sc::menu
105 ("Cursor Menu")
106 ("Pack & Use" sc::pack-buffer-to-cursor)
107 ("Pack to Icon" sc::pack-buffer-to-icon
108 (sc::menu-choose-cursor *menu-window* *menu-x* *menu-y*))
109 ("New Icon" call-interactively 'sc::make-cursor)
110 ("Edit Icon" sc:edit-cursor
111 (sc::menu-choose-cursor *menu-window* *menu-x* *menu-y*))
112 ("Set Cursor" sc:set-cursor
113 (sc::menu-choose-cursor *menu-window* *menu-x* *menu-y*))
114 ("Reset Cursor" sc:set-cursor nil)
115 ("Help". sc::edit-icon-help-menu)
116 ("Quit" sc::quit-edit)
117 )
118
119(defun sc::quit-edit ()
120 (interactive)
121 (bury-buffer (current-buffer))
122 (switch-to-buffer (other-buffer) 'no-record))
123
124(defun sc::make-cursor (symbol)
125 (interactive "SIcon Name: ")
126 (eval (list 'defcursor symbol 0 0 ""))
127 (sc::pack-buffer-to-icon (symbol-value symbol)))
128
129(defmenu sc::edit-icon-help-menu
130 ("Simple Icon Editor")
131 ("Left => CLEAR")
132 ("Middle => SET")
133 ("L & M => HOTSPOT")
134 ("Right => MENU"))
135
136(defun sc::edit-icon-help ()
137 (message "Left=> CLEAR Middle=> SET Left+Middle=> HOTSPOT Right=> MENU"))
138
139(defun sc::pack-buffer-to-cursor ()
140 (sc::pack-buffer-to-icon *edit-icon*)
141 (sc:set-cursor *edit-icon*))
142
143(defun sc::menu-choose-cursor (window x y)
144 "Presents a menu of cursor names, and returns one or nil"
145 (let ((curs sc::cursors)
146 (items))
147 (while curs
148 (push (sc::menu-item-for-cursor (car curs)) items)
149 (setq curs (cdr curs)))
150 (push (list "Choose Cursor") items)
151 (setq menu (menu-create items))
152 (sun-menu-evaluate window x y menu)))
153
154(defun sc::menu-item-for-cursor (cursor)
155 "apply function to selected cursor"
156 (list (symbol-name cursor) 'quote cursor))
157
158(defun sc::hotspot (window x y)
159 (aset *edit-icon* 0 x)
160 (aset *edit-icon* 1 y)
161 (sc::goto-hotspot))
162
163(defun sc::goto-hotspot ()
164 (goto-line (1+ (aref *edit-icon* 1)))
165 (move-to-column (aref *edit-icon* 0)))
166
167(defun sc::display-icon (icon)
168 (setq *edit-icon* (copy-sequence icon))
169 (let ((string (aref *edit-icon* 2))
170 (index 0))
171 (while (< index 32)
172 (let ((char (aref string index))
173 (bit 128))
174 (while (> bit 0)
175 (insert (sc::char-at-bit char bit))
176 (setq bit (lsh bit -1))))
177 (if (eq 1 (% index 2)) (newline))
178 (setq index (1+ index))))
179 (sc::goto-hotspot))
180
181(defun sc::char-at-bit (char bit)
182 (if (> (logand char bit) 0) "@" " "))
183
184(defun sc::pack-buffer-to-icon (icon)
185 "Pack 16 x 16 field into icon string"
186 (goto-char (point-min))
187 (aset icon 0 (aref *edit-icon* 0))
188 (aset icon 1 (aref *edit-icon* 1))
189 (aset icon 2 (mapconcat 'sc::pack-one-line "1234567890123456" ""))
190 (sc::goto-hotspot)
191 )
192
193(defun sc::pack-one-line (dummy)
194 (let* (char chr1 chr2)
195 (setq char 0 chr1 (mapconcat 'sc::pack-one-char "12345678" "") chr1 char)
196 (setq char 0 chr2 (mapconcat 'sc::pack-one-char "12345678" "") chr2 char)
197 (forward-line 1)
198 (concat (char-to-string chr1) (char-to-string chr2))
199 ))
200
201(defun sc::pack-one-char (dummy)
202 "pack following char into char, unless eolp"
203 (if (or (eolp) (char-equal (following-char) 32))
204 (setq char (lsh char 1))
205 (setq char (1+ (lsh char 1))))
206 (if (not (eolp))(forward-char)))
207
diff --git a/lisp/sun-fns.el b/lisp/sun-fns.el
new file mode 100644
index 00000000000..b2ca59203f6
--- /dev/null
+++ b/lisp/sun-fns.el
@@ -0,0 +1,630 @@
1;; Subroutines of Mouse handling for Sun windows
2;; Copyright (C) 1987 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;;; Submitted Mar. 1987, Jeff Peck
21;;; Sun Microsystems Inc. <peck@sun.com>
22;;; Conceived Nov. 1986, Stan Jefferson,
23;;; Computer Science Lab, SRI International.
24;;; GoodIdeas Feb. 1987, Steve Greenbaum
25;;; & UpClicks Reasoning Systems, Inc.
26;;;
27(provide 'sun-fns)
28(require 'sun-mouse)
29;;;
30;;; Functions for manipulating via the mouse and mouse-map definitions
31;;; for accessing them. Also definitons of mouse menus.
32;;; This file you should freely modify to reflect you personal tastes.
33;;;
34;;; First half of file defines functions to implement mouse commands,
35;;; Don't delete any of those, just add what ever else you need.
36;;; Second half of file defines mouse bindings, do whatever you want there.
37
38;;;
39;;; Mouse Functions.
40;;;
41;;; These functions follow the sun-mouse-handler convention of being called
42;;; with three arguements: (window x-pos y-pos)
43;;; This makes it easy for a mouse executed command to know where the mouse is.
44;;; Use the macro "eval-in-window" to execute a function
45;;; in a temporarily selected window.
46;;;
47;;; If you have a function that must be called with other arguments
48;;; bind the mouse button to an s-exp that contains the necessary parameters.
49;;; See "minibuffer" bindings for examples.
50;;;
51(defconst cursor-pause-milliseconds 300
52 "*Number of milliseconds to display alternate cursor (usually the mark)")
53
54(defun indicate-region (&optional pause)
55 "Bounce cursor to mark for cursor-pause-milliseconds and back again"
56 (or pause (setq pause cursor-pause-milliseconds))
57 (let ((point (point)))
58 (goto-char (mark))
59 (sit-for-millisecs pause)
60 ;(update-display)
61 ;(sleep-for-millisecs pause)
62 (goto-char point)))
63
64
65;;;
66;;; Text buffer operations
67;;;
68(defun mouse-move-point (window x y)
69 "Move point to mouse cursor."
70 (select-window window)
71 (move-to-loc x y)
72 (if (memq last-command ; support the mouse-copy/delete/yank
73 '(mouse-copy mouse-delete mouse-yank-move))
74 (setq this-command 'mouse-yank-move))
75 )
76
77(defun mouse-set-mark (window x y)
78 "Set mark at mouse cursor."
79 (eval-in-window window ;; use this to get the unwind protect
80 (let ((point (point)))
81 (move-to-loc x y)
82 (set-mark (point))
83 (goto-char point)
84 (indicate-region)))
85 )
86
87(defun mouse-set-mark-and-select (window x y)
88 "Set mark at mouse cursor, and select that window."
89 (select-window window)
90 (mouse-set-mark window x y)
91 )
92
93(defun mouse-set-mark-and-stuff (w x y)
94 "Set mark at mouse cursor, and put region in stuff buffer."
95 (mouse-set-mark-and-select w x y)
96 (sun-select-region (region-beginning) (region-end)))
97
98;;;
99;;; Simple mouse dragging stuff: marking with button up
100;;;
101
102(defvar *mouse-drag-window* nil)
103(defvar *mouse-drag-x* -1)
104(defvar *mouse-drag-y* -1)
105
106(defun mouse-drag-move-point (window x y)
107 "Move point to mouse cursor, and allow dragging."
108 (mouse-move-point window x y)
109 (setq *mouse-drag-window* window
110 *mouse-drag-x* x
111 *mouse-drag-y* y))
112
113(defun mouse-drag-set-mark-stuff (window x y)
114 "The up click handler that goes with mouse-drag-move-point.
115If mouse is in same WINDOW but at different X or Y than when
116mouse-drag-move-point was last executed, set the mark at mouse
117and put the region in the stuff buffer."
118 (if (and (eq *mouse-drag-window* window)
119 (not (and (equal *mouse-drag-x* x)
120 (equal *mouse-drag-y* y))))
121 (mouse-set-mark-and-stuff window x y)
122 (setq this-command last-command)) ; this was just an upclick no-op.
123 )
124
125(defun mouse-select-or-drag-move-point (window x y)
126 "Select window if not selected, otherwise do mouse-drag-move-point."
127 (if (eq (selected-window) window)
128 (mouse-drag-move-point window x y)
129 (mouse-select-window window x y)))
130
131;;;
132;;; esoteria:
133;;;
134(defun mouse-exch-pt-and-mark (window x y)
135 "Exchange point and mark."
136 (select-window window)
137 (exchange-point-and-mark)
138 )
139
140(defun mouse-call-kbd-macro (window x y)
141 "Invokes last keyboard macro at mouse cursor."
142 (mouse-move-point window x y)
143 (call-last-kbd-macro)
144 )
145
146(defun mouse-mark-thing (window x y)
147 "Set point and mark to text object using syntax table.
148The resulting region is put in the sun-window stuff buffer.
149Left or right Paren syntax marks an s-expression.
150Clicking at the end of a line marks the line including a trailing newline.
151If it doesn't recognize one of these it marks the character at point."
152 (mouse-move-point window x y)
153 (if (eobp) (open-line 1))
154 (let* ((char (char-after (point)))
155 (syntax (char-syntax char)))
156 (cond
157 ((eq syntax ?w) ; word.
158 (forward-word 1)
159 (set-mark (point))
160 (forward-word -1))
161 ;; try to include a single following whitespace (is this a good idea?)
162 ;; No, not a good idea since inconsistent.
163 ;;(if (eq (char-syntax (char-after (mark))) ?\ )
164 ;; (set-mark (1+ (mark))))
165 ((eq syntax ?\( ) ; open paren.
166 (mark-sexp 1))
167 ((eq syntax ?\) ) ; close paren.
168 (forward-char 1)
169 (mark-sexp -1)
170 (exchange-point-and-mark))
171 ((eolp) ; mark line if at end.
172 (set-mark (1+ (point)))
173 (beginning-of-line 1))
174 (t ; mark character
175 (set-mark (1+ (point)))))
176 (indicate-region)) ; display region boundary.
177 (sun-select-region (region-beginning) (region-end))
178 )
179
180(defun mouse-kill-thing (window x y)
181 "Kill thing at mouse, and put point there."
182 (mouse-mark-thing window x y)
183 (kill-region-and-unmark (region-beginning) (region-end))
184 )
185
186(defun mouse-kill-thing-there (window x y)
187 "Kill thing at mouse, leave point where it was.
188See mouse-mark-thing for a description of the objects recognized."
189 (eval-in-window window
190 (save-excursion
191 (mouse-mark-thing window x y)
192 (kill-region (region-beginning) (region-end))))
193 )
194
195(defun mouse-save-thing (window x y &optional quiet)
196 "Put thing at mouse in kill ring.
197See mouse-mark-thing for a description of the objects recognized."
198 (mouse-mark-thing window x y)
199 (copy-region-as-kill (region-beginning) (region-end))
200 (if (not quiet) (message "Thing saved"))
201 )
202
203(defun mouse-save-thing-there (window x y &optional quiet)
204 "Put thing at mouse in kill ring, leave point as is.
205See mouse-mark-thing for a description of the objects recognized."
206 (eval-in-window window
207 (save-excursion
208 (mouse-save-thing window x y quiet))))
209
210;;;
211;;; Mouse yanking...
212;;;
213(defun mouse-copy-thing (window x y)
214 "Put thing at mouse in kill ring, yank to point.
215See mouse-mark-thing for a description of the objects recognized."
216 (setq last-command 'not-kill) ;Avoids appending to previous kills.
217 (mouse-save-thing-there window x y t)
218 (yank)
219 (setq this-command 'yank))
220
221(defun mouse-move-thing (window x y)
222 "Kill thing at mouse, yank it to point.
223See mouse-mark-thing for a description of the objects recognized."
224 (setq last-command 'not-kill) ;Avoids appending to previous kills.
225 (mouse-kill-thing-there window x y)
226 (yank)
227 (setq this-command 'yank))
228
229(defun mouse-yank-at-point (&optional window x y)
230 "Yank from kill-ring at point; then cycle thru kill ring."
231 (if (eq last-command 'yank)
232 (let ((before (< (point) (mark))))
233 (delete-region (point) (mark))
234 (rotate-yank-pointer 1)
235 (insert (car kill-ring-yank-pointer))
236 (if before (exchange-point-and-mark)))
237 (yank))
238 (setq this-command 'yank))
239
240(defun mouse-yank-at-mouse (window x y)
241 "Yank from kill-ring at mouse; then cycle thru kill ring."
242 (mouse-move-point window x y)
243 (mouse-yank-at-point window x y))
244
245(defun mouse-save/delete/yank (&optional window x y)
246 "Context sensitive save/delete/yank.
247Consecutive clicks perform as follows:
248 * first click saves region to kill ring,
249 * second click kills region,
250 * third click yanks from kill ring,
251 * subsequent clicks cycle thru kill ring.
252If mouse-move-point is performed after the first or second click,
253the next click will do a yank, etc. Except for a possible mouse-move-point,
254this command is insensitive to mouse location."
255 (cond
256 ((memq last-command '(mouse-delete yank mouse-yank-move)) ; third+ click
257 (mouse-yank-at-point))
258 ((eq last-command 'mouse-copy) ; second click
259 (kill-region (region-beginning) (region-end))
260 (setq this-command 'mouse-delete))
261 (t ; first click
262 (copy-region-as-kill (region-beginning) (region-end))
263 (message "Region saved")
264 (setq this-command 'mouse-copy))
265 ))
266
267
268(defun mouse-split-horizontally (window x y)
269 "Splits the window horizontally at mouse cursor."
270 (eval-in-window window (split-window-horizontally (1+ x))))
271
272(defun mouse-split-vertically (window x y)
273 "Split the window vertically at the mouse cursor."
274 (eval-in-window window (split-window-vertically (1+ y))))
275
276(defun mouse-select-window (window x y)
277 "Selects the window, restoring point."
278 (select-window window))
279
280(defun mouse-delete-other-windows (window x y)
281 "Deletes all windows except the one mouse is in."
282 (delete-other-windows window))
283
284(defun mouse-delete-window (window x y)
285 "Deletes the window mouse is in."
286 (delete-window window))
287
288(defun mouse-undo (window x y)
289 "Invokes undo in the window mouse is in."
290 (eval-in-window window (undo)))
291
292;;;
293;;; Scroll operations
294;;;
295
296;;; The move-to-window-line is used below because otherwise
297;;; scrolling a non-selected process window with the mouse, after
298;;; the process has written text past the bottom of the window,
299;;; gives an "End of buffer" error, and then scrolls. The
300;;; move-to-window-line seems to force recomputing where things are.
301(defun mouse-scroll-up (window x y)
302 "Scrolls the window upward."
303 (eval-in-window window (move-to-window-line 1) (scroll-up nil)))
304
305(defun mouse-scroll-down (window x y)
306 "Scrolls the window downward."
307 (eval-in-window window (scroll-down nil)))
308
309(defun mouse-scroll-proportional (window x y)
310 "Scrolls the window proportionally corresponding to window
311relative X divided by window width."
312 (eval-in-window window
313 (if (>= x (1- (window-width)))
314 ;; When x is maximun (equal to or 1 less than window width),
315 ;; goto end of buffer. We check for this special case
316 ;; becuase the calculated goto-char often goes short of the
317 ;; end due to roundoff error, and we often really want to go
318 ;; to the end.
319 (goto-char (point-max))
320 (progn
321 (goto-char (+ (point-min) ; For narrowed regions.
322 (* x (/ (- (point-max) (point-min))
323 (1- (window-width))))))
324 (beginning-of-line))
325 )
326 (what-cursor-position) ; Report position.
327 ))
328
329(defun mouse-line-to-top (window x y)
330 "Scrolls the line at the mouse cursor up to the top."
331 (eval-in-window window (scroll-up y)))
332
333(defun mouse-top-to-line (window x y)
334 "Scrolls the top line down to the mouse cursor."
335 (eval-in-window window (scroll-down y)))
336
337(defun mouse-line-to-bottom (window x y)
338 "Scrolls the line at the mouse cursor to the bottom."
339 (eval-in-window window (scroll-up (+ y (- 2 (window-height))))))
340
341(defun mouse-bottom-to-line (window x y)
342 "Scrolls the bottom line up to the mouse cursor."
343 (eval-in-window window (scroll-down (+ y (- 2 (window-height))))))
344
345(defun mouse-line-to-middle (window x y)
346 "Scrolls the line at the mouse cursor to the middle."
347 (eval-in-window window (scroll-up (- y -1 (/ (window-height) 2)))))
348
349(defun mouse-middle-to-line (window x y)
350 "Scrolls the line at the middle to the mouse cursor."
351 (eval-in-window window (scroll-up (- (/ (window-height) 2) y 1))))
352
353
354;;;
355;;; main emacs menu.
356;;;
357(defmenu expand-menu
358 ("Vertically" mouse-expand-vertically *menu-window*)
359 ("Horizontally" mouse-expand-horizontally *menu-window*))
360
361(defmenu delete-window-menu
362 ("This One" delete-window *menu-window*)
363 ("All Others" delete-other-windows *menu-window*))
364
365(defmenu mouse-help-menu
366 ("Text Region"
367 mouse-help-region *menu-window* *menu-x* *menu-y* 'text)
368 ("Scrollbar"
369 mouse-help-region *menu-window* *menu-x* *menu-y* 'scrollbar)
370 ("Modeline"
371 mouse-help-region *menu-window* *menu-x* *menu-y* 'modeline)
372 ("Minibuffer"
373 mouse-help-region *menu-window* *menu-x* *menu-y* 'minibuffer)
374 )
375
376(defmenu emacs-quit-menu
377 ("Suspend" suspend-emacstool)
378 ("Quit" save-buffers-kill-emacs))
379
380(defmenu emacs-menu
381 ("Emacs Menu")
382 ("Stuff Selection" sun-yank-selection)
383 ("Expand" . expand-menu)
384 ("Delete Window" . delete-window-menu)
385 ("Previous Buffer" mouse-select-previous-buffer *menu-window*)
386 ("Save Buffers" save-some-buffers)
387 ("List Directory" list-directory nil)
388 ("Dired" dired nil)
389 ("Mouse Help" . mouse-help-menu)
390 ("Quit" . emacs-quit-menu))
391
392(defun emacs-menu-eval (window x y)
393 "Pop-up menu of editor commands."
394 (sun-menu-evaluate window (1+ x) (1- y) 'emacs-menu))
395
396(defun mouse-expand-horizontally (window)
397 (eval-in-window window
398 (enlarge-window 4 t)
399 (update-display) ; Try to redisplay, since can get confused.
400 ))
401
402(defun mouse-expand-vertically (window)
403 (eval-in-window window (enlarge-window 4)))
404
405(defun mouse-select-previous-buffer (window)
406 "Switch buffer in mouse window to most recently selected buffer."
407 (eval-in-window window (switch-to-buffer (other-buffer))))
408
409;;;
410;;; minibuffer menu
411;;;
412(defmenu minibuffer-menu
413 ("Minibuffer" message "Just some miscellanous minibuffer commands")
414 ("Stuff" sun-yank-selection)
415 ("Do-It" exit-minibuffer)
416 ("Abort" abort-recursive-edit)
417 ("Suspend" suspend-emacs))
418
419(defun minibuffer-menu-eval (window x y)
420 "Pop-up menu of commands."
421 (sun-menu-evaluate window x (1- y) 'minibuffer-menu))
422
423(defun mini-move-point (window x y)
424 ;; -6 is good for most common cases
425 (mouse-move-point window (- x 6) 0))
426
427(defun mini-set-mark-and-stuff (window x y)
428 ;; -6 is good for most common cases
429 (mouse-set-mark-and-stuff window (- x 6) 0))
430
431
432;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
433;;; Buffer-mode Mouse commands
434;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
435
436(defun Buffer-at-mouse (w x y)
437 "Calls Buffer-menu-buffer from mouse click."
438 (save-window-excursion
439 (mouse-move-point w x y)
440 (beginning-of-line)
441 (Buffer-menu-buffer t)))
442
443(defun mouse-buffer-bury (w x y)
444 "Bury the indicated buffer."
445 (bury-buffer (Buffer-at-mouse w x y))
446 )
447
448(defun mouse-buffer-select (w x y)
449 "Put the indicated buffer in selected window."
450 (switch-to-buffer (Buffer-at-mouse w x y))
451 (list-buffers)
452 )
453
454(defun mouse-buffer-delete (w x y)
455 "mark indicated buffer for delete"
456 (save-window-excursion
457 (mouse-move-point w x y)
458 (Buffer-menu-delete)
459 ))
460
461(defun mouse-buffer-execute (w x y)
462 "execute buffer-menu selections"
463 (save-window-excursion
464 (mouse-move-point w x y)
465 (Buffer-menu-execute)
466 ))
467
468(defun enable-mouse-in-buffer-list ()
469 "Call this to enable mouse selections in *Buffer List*
470 LEFT puts the indicated buffer in the selected window.
471 MIDDLE buries the indicated buffer.
472 RIGHT marks the indicated buffer for deletion.
473 MIDDLE-RIGHT deletes the marked buffers.
474To unmark a buffer marked for deletion, select it with LEFT."
475 (save-window-excursion
476 (list-buffers) ; Initialize *Buffer List*
477 (set-buffer "*Buffer List*")
478 (local-set-mouse '(text middle) 'mouse-buffer-bury)
479 (local-set-mouse '(text left) 'mouse-buffer-select)
480 (local-set-mouse '(text right) 'mouse-buffer-delete)
481 (local-set-mouse '(text middle right) 'mouse-buffer-execute)
482 )
483 )
484
485
486;;;*******************************************************************
487;;;
488;;; Global Mouse Bindings.
489;;;
490;;; There is some sense to this mouse binding madness:
491;;; LEFT and RIGHT scrolls are inverses.
492;;; SHIFT makes an opposite meaning in the scroll bar.
493;;; SHIFT is an alternative to DOUBLE (but double chords do not exist).
494;;; META makes the scrollbar functions work in the text region.
495;;; MIDDLE operates the mark
496;;; LEFT operates at point
497
498;;; META commands are generally non-destructive,
499;;; SHIFT is a little more dangerous.
500;;; CONTROL is for the really complicated ones.
501
502;;; CONTROL-META-SHIFT-RIGHT gives help on that region.
503
504;;;
505;;; Text Region mousemap
506;;;
507;; The basics: Point, Mark, Menu, Sun-Select:
508(global-set-mouse '(text left) 'mouse-drag-move-point)
509(global-set-mouse '(text up left) 'mouse-drag-set-mark-stuff)
510(global-set-mouse '(text shift left) 'mouse-exch-pt-and-mark)
511(global-set-mouse '(text double left) 'mouse-exch-pt-and-mark)
512
513(global-set-mouse '(text middle) 'mouse-set-mark-and-stuff)
514
515(global-set-mouse '(text right) 'emacs-menu-eval)
516(global-set-mouse '(text shift right) '(sun-yank-selection))
517(global-set-mouse '(text double right) '(sun-yank-selection))
518
519;; The Slymoblics multi-command for Save, Kill, Copy, Move:
520(global-set-mouse '(text shift middle) 'mouse-save/delete/yank)
521(global-set-mouse '(text double middle) 'mouse-save/delete/yank)
522
523;; Save, Kill, Copy, Move Things:
524;; control-left composes with control middle/right to produce copy/move
525(global-set-mouse '(text control middle ) 'mouse-save-thing-there)
526(global-set-mouse '(text control right ) 'mouse-kill-thing-there)
527(global-set-mouse '(text control left) 'mouse-yank-at-point)
528(global-set-mouse '(text control middle left) 'mouse-copy-thing)
529(global-set-mouse '(text control right left) 'mouse-move-thing)
530(global-set-mouse '(text control right middle) 'mouse-mark-thing)
531
532;; The Universal mouse help command (press all buttons):
533(global-set-mouse '(text shift control meta right) 'mouse-help-region)
534(global-set-mouse '(text double control meta right) 'mouse-help-region)
535
536;;; Meta in Text Region is like meta version in scrollbar:
537(global-set-mouse '(text meta left) 'mouse-line-to-top)
538(global-set-mouse '(text meta shift left) 'mouse-line-to-bottom)
539(global-set-mouse '(text meta double left) 'mouse-line-to-bottom)
540(global-set-mouse '(text meta middle) 'mouse-line-to-middle)
541(global-set-mouse '(text meta shift middle) 'mouse-middle-to-line)
542(global-set-mouse '(text meta double middle) 'mouse-middle-to-line)
543(global-set-mouse '(text meta control middle) 'mouse-split-vertically)
544(global-set-mouse '(text meta right) 'mouse-top-to-line)
545(global-set-mouse '(text meta shift right) 'mouse-bottom-to-line)
546(global-set-mouse '(text meta double right) 'mouse-bottom-to-line)
547
548;; Miscellaneous:
549(global-set-mouse '(text meta control left) 'mouse-call-kbd-macro)
550(global-set-mouse '(text meta control right) 'mouse-undo)
551
552;;;
553;;; Scrollbar mousemap.
554;;; Are available in the Scrollbar Region, or with Meta Text (or Meta Scrollbar)
555;;;
556(global-set-mouse '(scrollbar left) 'mouse-line-to-top)
557(global-set-mouse '(scrollbar shift left) 'mouse-line-to-bottom)
558(global-set-mouse '(scrollbar double left) 'mouse-line-to-bottom)
559
560(global-set-mouse '(scrollbar middle) 'mouse-line-to-middle)
561(global-set-mouse '(scrollbar shift middle) 'mouse-middle-to-line)
562(global-set-mouse '(scrollbar double middle) 'mouse-middle-to-line)
563(global-set-mouse '(scrollbar control middle) 'mouse-split-vertically)
564
565(global-set-mouse '(scrollbar right) 'mouse-top-to-line)
566(global-set-mouse '(scrollbar shift right) 'mouse-bottom-to-line)
567(global-set-mouse '(scrollbar double right) 'mouse-bottom-to-line)
568
569(global-set-mouse '(scrollbar meta left) 'mouse-line-to-top)
570(global-set-mouse '(scrollbar meta shift left) 'mouse-line-to-bottom)
571(global-set-mouse '(scrollbar meta double left) 'mouse-line-to-bottom)
572(global-set-mouse '(scrollbar meta middle) 'mouse-line-to-middle)
573(global-set-mouse '(scrollbar meta shift middle) 'mouse-middle-to-line)
574(global-set-mouse '(scrollbar meta double middle) 'mouse-middle-to-line)
575(global-set-mouse '(scrollbar meta control middle) 'mouse-split-vertically)
576(global-set-mouse '(scrollbar meta right) 'mouse-top-to-line)
577(global-set-mouse '(scrollbar meta shift right) 'mouse-bottom-to-line)
578(global-set-mouse '(scrollbar meta double right) 'mouse-bottom-to-line)
579
580;; And the help menu:
581(global-set-mouse '(scrollbar shift control meta right) 'mouse-help-region)
582(global-set-mouse '(scrollbar double control meta right) 'mouse-help-region)
583
584;;;
585;;; Modeline mousemap.
586;;;
587;;; Note: meta of any single button selects window.
588
589(global-set-mouse '(modeline left) 'mouse-scroll-up)
590(global-set-mouse '(modeline meta left) 'mouse-select-window)
591
592(global-set-mouse '(modeline middle) 'mouse-scroll-proportional)
593(global-set-mouse '(modeline meta middle) 'mouse-select-window)
594(global-set-mouse '(modeline control middle) 'mouse-split-horizontally)
595
596(global-set-mouse '(modeline right) 'mouse-scroll-down)
597(global-set-mouse '(modeline meta right) 'mouse-select-window)
598
599;;; control-left selects this window, control-right deletes it.
600(global-set-mouse '(modeline control left) 'mouse-delete-other-windows)
601(global-set-mouse '(modeline control right) 'mouse-delete-window)
602
603;; in case of confusion, just select it:
604(global-set-mouse '(modeline control left right)'mouse-select-window)
605
606;; even without confusion (and without the keyboard) select it:
607(global-set-mouse '(modeline left right) 'mouse-select-window)
608
609;; And the help menu:
610(global-set-mouse '(modeline shift control meta right) 'mouse-help-region)
611(global-set-mouse '(modeline double control meta right) 'mouse-help-region)
612
613;;;
614;;; Minibuffer Mousemap
615;;; Demonstrating some variety:
616;;;
617(global-set-mouse '(minibuffer left) 'mini-move-point)
618
619(global-set-mouse '(minibuffer middle) 'mini-set-mark-and-stuff)
620
621(global-set-mouse '(minibuffer shift middle) '(select-previous-complex-command))
622(global-set-mouse '(minibuffer double middle) '(select-previous-complex-command))
623(global-set-mouse '(minibuffer control middle) '(next-complex-command 1))
624(global-set-mouse '(minibuffer meta middle) '(previous-complex-command 1))
625
626(global-set-mouse '(minibuffer right) 'minibuffer-menu-eval)
627
628(global-set-mouse '(minibuffer shift control meta right) 'mouse-help-region)
629(global-set-mouse '(minibuffer double control meta right) 'mouse-help-region)
630
diff --git a/lisp/sun-keys.el b/lisp/sun-keys.el
new file mode 100644
index 00000000000..59fba2a5791
--- /dev/null
+++ b/lisp/sun-keys.el
@@ -0,0 +1,71 @@
1;;;
2;;; Support (cleanly) for Sun function keys. Provides help facilities,
3;;; better diagnostics, etc.
4;;;
5;;; To use: make sure your .ttyswrc binds 'F1' to <ESC> * F1 <CR> and so on.
6;;; load this lot from your start_up
7;;;
8;;;
9;;; Copyright (C) 1986 Free Software Foundation, Inc.
10;;;
11;;; This file is part of GNU Emacs.
12
13;; GNU Emacs is free software; you can redistribute it and/or modify
14;; it under the terms of the GNU General Public License as published by
15;; the Free Software Foundation; either version 1, or (at your option)
16;; any later version.
17
18;; GNU Emacs is distributed in the hope that it will be useful,
19;; but WITHOUT ANY WARRANTY; without even the implied warranty of
20;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21;; GNU General Public License for more details.
22
23;; You should have received a copy of the GNU General Public License
24;; along with GNU Emacs; see the file COPYING. If not, write to
25;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
26;;;
27;;; Batten@uk.ac.bham.multics (Ian G. Batten)
28;;;
29
30(defun sun-function-keys-dispatch (arg)
31 "Dispatcher for function keys."
32 (interactive "p")
33 (let* ((key-stroke (read t))
34 (command (assq key-stroke sun-function-keys-command-list)))
35 (cond (command (funcall (cdr command) arg))
36 (t (error "Unbound function key %s" key-stroke)))))
37
38(defvar sun-function-keys-command-list
39 '((F1 . sun-function-keys-describe-bindings)
40 (R8 . previous-line) ; arrow keys
41 (R10 . backward-char)
42 (R12 . forward-char)
43 (R14 . next-line)))
44
45(defun sun-function-keys-bind-key (arg1 arg2)
46 "Bind a specified key."
47 (interactive "xFunction Key Cap Label:
48CCommand To Use:")
49 (setq sun-function-keys-command-list
50 (cons (cons arg1 arg2) sun-function-keys-command-list)))
51
52(defun sun-function-keys-describe-bindings (arg)
53 "Describe the function key bindings we're running"
54 (interactive)
55 (with-output-to-temp-buffer "*Help*"
56 (sun-function-keys-write-bindings
57 (sort (copy-sequence sun-function-keys-command-list)
58 '(lambda (x y) (string-lessp (car x) (car y)))))))
59
60(defun sun-function-keys-write-bindings (list)
61 (cond ((null list)
62 t)
63 (t
64 (princ (format "%s: %s\n"
65 (car (car list))
66 (cdr (car list))))
67 (sun-function-keys-write-bindings (cdr list)))))
68
69(global-set-key "\e*" 'sun-function-keys-dispatch)
70
71(make-variable-buffer-local 'sun-function-keys-command-list)
diff --git a/lisp/term/sun-mouse.el b/lisp/term/sun-mouse.el
new file mode 100644
index 00000000000..bed2b416c1f
--- /dev/null
+++ b/lisp/term/sun-mouse.el
@@ -0,0 +1,668 @@
1;; Mouse handling for Sun windows
2;; Copyright (C) 1987 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;;; Jeff Peck, Sun Microsystems, Jan 1987.
21;;; Original idea by Stan Jefferson
22
23(provide 'sun-mouse)
24
25;;;
26;;; Modelled after the GNUEMACS keymap interface.
27;;;
28;;; User Functions:
29;;; make-mousemap, copy-mousemap,
30;;; define-mouse, global-set-mouse, local-set-mouse,
31;;; use-global-mousemap, use-local-mousemap,
32;;; mouse-lookup, describe-mouse-bindings
33;;;
34;;; Options:
35;;; extra-click-wait, scrollbar-width
36;;;
37
38(defvar extra-click-wait 150
39 "*Number of milliseconds to wait for an extra click.
40Set this to zero if you don't want chords or double clicks.")
41
42(defvar scrollbar-width 5
43 "*The character width of the scrollbar.
44The cursor is deemed to be in the right edge scrollbar if it is this near the
45right edge, and more than two chars past the end of the indicated line.
46Setting to nil limits the scrollbar to the edge or vertical dividing bar.")
47
48;;;
49;;; Mousemaps
50;;;
51(defun make-mousemap ()
52 "Returns a new mousemap."
53 (cons 'mousemap nil))
54
55(defun copy-mousemap (mousemap)
56 "Return a copy of mousemap."
57 (copy-alist mousemap))
58
59(defun define-mouse (mousemap mouse-list def)
60 "Args MOUSEMAP, MOUSE-LIST, DEF. Define MOUSE-LIST in MOUSEMAP as DEF.
61MOUSE-LIST is a list of atoms specifing a mouse hit according to these rules:
62 * One of these atoms specifies the active region of the definition.
63 text, scrollbar, modeline, minibuffer
64 * One or two or these atoms specify the button or button combination.
65 left, middle, right, double
66 * Any combination of these atoms specify the active shift keys.
67 control, shift, meta
68 * With a single unshifted button, you can add
69 up
70 to indicate an up-click.
71The atom `double' is used with a button designator to denote a double click.
72Two button chords are denoted by listing the two buttons.
73See sun-mouse-handler for the treatment of the form DEF."
74 (mousemap-set (mouse-list-to-mouse-code mouse-list) mousemap def))
75
76(defun global-set-mouse (mouse-list def)
77 "Give MOUSE-EVENT-LIST a local definition of DEF.
78See define-mouse for a description of MOUSE-EVENT-LIST and DEF.
79Note that if MOUSE-EVENT-LIST has a local definition in the current buffer,
80that local definition will continue to shadow any global definition."
81 (interactive "xMouse event: \nxDefinition: ")
82 (define-mouse current-global-mousemap mouse-list def))
83
84(defun local-set-mouse (mouse-list def)
85 "Give MOUSE-EVENT-LIST a local definition of DEF.
86See define-mouse for a description of the arguments.
87The definition goes in the current buffer's local mousemap.
88Normally buffers in the same major mode share a local mousemap."
89 (interactive "xMouse event: \nxDefinition: ")
90 (if (null current-local-mousemap)
91 (setq current-local-mousemap (make-mousemap)))
92 (define-mouse current-local-mousemap mouse-list def))
93
94(defun use-global-mousemap (mousemap)
95 "Selects MOUSEMAP as the global mousemap."
96 (setq current-global-mousemap mousemap))
97
98(defun use-local-mousemap (mousemap)
99 "Selects MOUSEMAP as the local mousemap.
100nil for MOUSEMAP means no local mousemap."
101 (setq current-local-mousemap mousemap))
102
103
104;;;
105;;; Interface to the Mouse encoding defined in Emacstool.c
106;;;
107;;; Called when mouse-prefix is sent to emacs, additional
108;;; information is read in as a list (button x y time-delta)
109;;;
110;;; First, some generally useful functions:
111;;;
112
113(defun logtest (x y)
114 "True if any bits set in X are also set in Y.
115Just like the Common Lisp function of the same name."
116 (not (zerop (logand x y))))
117
118
119;;;
120;;; Hit accessors.
121;;;
122
123(defconst sm::ButtonBits 7) ; Lowest 3 bits.
124(defconst sm::ShiftmaskBits 56) ; Second lowest 3 bits (56 = 63 - 7).
125(defconst sm::DoubleBits 64) ; Bit 7.
126(defconst sm::UpBits 128) ; Bit 8.
127
128;;; All the useful code bits
129(defmacro sm::hit-code (hit)
130 (` (nth 0 (, hit))))
131;;; The button, or buttons if a chord.
132(defmacro sm::hit-button (hit)
133 (` (logand sm::ButtonBits (nth 0 (, hit)))))
134;;; The shift, control, and meta flags.
135(defmacro sm::hit-shiftmask (hit)
136 (` (logand sm::ShiftmaskBits (nth 0 (, hit)))))
137;;; Set if a double click (but not a chord).
138(defmacro sm::hit-double (hit)
139 (` (logand sm::DoubleBits (nth 0 (, hit)))))
140;;; Set on button release (as opposed to button press).
141(defmacro sm::hit-up (hit)
142 (` (logand sm::UpBits (nth 0 (, hit)))))
143;;; Screen x position.
144(defmacro sm::hit-x (hit) (list 'nth 1 hit))
145;;; Screen y position.
146(defmacro sm::hit-y (hit) (list 'nth 2 hit))
147;;; Millisconds since last hit.
148(defmacro sm::hit-delta (hit) (list 'nth 3 hit))
149
150(defmacro sm::hit-up-p (hit) ; A predicate.
151 (` (not (zerop (sm::hit-up (, hit))))))
152
153;;;
154;;; Loc accessors. for sm::window-xy
155;;;
156(defmacro sm::loc-w (loc) (list 'nth 0 loc))
157(defmacro sm::loc-x (loc) (list 'nth 1 loc))
158(defmacro sm::loc-y (loc) (list 'nth 2 loc))
159
160(defmacro eval-in-buffer (buffer &rest forms)
161 "Macro to switches to BUFFER, evaluates FORMS, returns to original buffer."
162 ;; When you don't need the complete window context of eval-in-window
163 (` (let ((StartBuffer (current-buffer)))
164 (unwind-protect
165 (progn
166 (set-buffer (, buffer))
167 (,@ forms))
168 (set-buffer StartBuffer)))))
169
170(put 'eval-in-buffer 'lisp-indent-function 1)
171
172;;; this is used extensively by sun-fns.el
173;;;
174(defmacro eval-in-window (window &rest forms)
175 "Switch to WINDOW, evaluate FORMS, return to original window."
176 (` (let ((OriginallySelectedWindow (selected-window)))
177 (unwind-protect
178 (progn
179 (select-window (, window))
180 (,@ forms))
181 (select-window OriginallySelectedWindow)))))
182(put 'eval-in-window 'lisp-indent-function 1)
183
184;;;
185;;; handy utility, generalizes window_loop
186;;;
187
188;;; It's a macro (and does not evaluate its arguments).
189(defmacro eval-in-windows (form &optional yesmini)
190 "Switches to each window and evaluates FORM. Optional argument
191YESMINI says to include the minibuffer as a window.
192This is a macro, and does not evaluate its arguments."
193 (` (let ((OriginallySelectedWindow (selected-window)))
194 (unwind-protect
195 (while (progn
196 (, form)
197 (not (eq OriginallySelectedWindow
198 (select-window
199 (next-window nil (, yesmini)))))))
200 (select-window OriginallySelectedWindow)))))
201(put 'eval-in-window 'lisp-indent-function 0)
202
203(defun move-to-loc (x y)
204 "Move cursor to window location X, Y.
205Handles wrapped and horizontally scrolled lines correctly."
206 (move-to-window-line y)
207 ;; window-line-end expects this to return the window column it moved to.
208 (let ((cc (current-column))
209 (nc (move-to-column
210 (if (zerop (window-hscroll))
211 (+ (current-column)
212 (min (- (window-width) 2) ; To stay on the line.
213 x))
214 (+ (window-hscroll) -1
215 (min (1- (window-width)) ; To stay on the line.
216 x))))))
217 (- nc cc)))
218
219
220(defun minibuffer-window-p (window)
221 "True iff this WINDOW is minibuffer."
222 (= (screen-height)
223 (nth 3 (window-edges window)) ; The bottom edge.
224 ))
225
226
227(defun sun-mouse-handler (&optional hit)
228 "Evaluates the function or list associated with a mouse hit.
229Expecting to read a hit, which is a list: (button x y delta).
230A form bound to button by define-mouse is found by mouse-lookup.
231The variables: *mouse-window*, *mouse-x*, *mouse-y* are bound.
232If the form is a symbol (symbolp), it is funcall'ed with *mouse-window*,
233*mouse-x*, and *mouse-y* as arguments; if the form is a list (listp),
234the form is eval'ed; if the form is neither of these, it is an error.
235Returns nil."
236 (interactive)
237 (if (null hit) (setq hit (sm::combined-hits)))
238 (let ((loc (sm::window-xy (sm::hit-x hit) (sm::hit-y hit))))
239 (let ((*mouse-window* (sm::loc-w loc))
240 (*mouse-x* (sm::loc-x loc))
241 (*mouse-y* (sm::loc-y loc))
242 (mouse-code (mouse-event-code hit loc)))
243 (let ((form (eval-in-buffer (window-buffer *mouse-window*)
244 (mouse-lookup mouse-code))))
245 (cond ((null form)
246 (if (not (sm::hit-up-p hit)) ; undefined up hits are ok.
247 (error "Undefined mouse event: %s"
248 (prin1-to-string
249 (mouse-code-to-mouse-list mouse-code)))))
250 ((symbolp form)
251 (setq this-command form)
252 (funcall form *mouse-window* *mouse-x* *mouse-y*))
253 ((listp form)
254 (setq this-command (car form))
255 (eval form))
256 (t
257 (error "Mouse action must be symbol or list, but was: %s"
258 form))))))
259 ;; Don't let 'sun-mouse-handler get on last-command,
260 ;; since this function should be transparent.
261 (if (eq this-command 'sun-mouse-handler)
262 (setq this-command last-command))
263 ;; (message (prin1-to-string this-command)) ; to see what your buttons did
264 nil)
265
266(defun sm::combined-hits ()
267 "Read and return next mouse-hit, include possible double click"
268 (let ((hit1 (mouse-hit-read)))
269 (if (not (sm::hit-up-p hit1)) ; Up hits dont start doubles or chords.
270 (let ((hit2 (mouse-second-hit extra-click-wait)))
271 (if hit2 ; we cons'd it, we can smash it.
272 ; (setf (sm::hit-code hit1) (logior (sm::hit-code hit1) ...))
273 (setcar hit1 (logior (sm::hit-code hit1)
274 (sm::hit-code hit2)
275 (if (= (sm::hit-button hit1)
276 (sm::hit-button hit2))
277 sm::DoubleBits 0))))))
278 hit1))
279
280(defun mouse-hit-read ()
281 "Read mouse-hit list from keyboard. Like (read 'read-char),
282but that uses minibuffer, and mucks up last-command."
283 (let ((char-list nil) (char nil))
284 (while (not (equal 13 ; Carriage return.
285 (prog1 (setq char (read-char))
286 (setq char-list (cons char char-list))))))
287 (read (mapconcat 'char-to-string (nreverse char-list) ""))
288 ))
289
290;;; Second Click Hackery....
291;;; if prefix is not mouse-prefix, need a way to unread the char...
292;;; or else have mouse flush input queue, or else need a peek at next char.
293
294;;; There is no peek, but since one character can be unread, we only
295;;; have to flush the queue when the command after a mouse click
296;;; starts with mouse-prefix1 (see below).
297;;; Something to do later: We could buffer the read commands and
298;;; execute them ourselves after doing the mouse command (using
299;;; lookup-key ??).
300
301(defvar mouse-prefix1 24 ; C-x
302 "First char of mouse-prefix. Used to detect double clicks and chords.")
303
304(defvar mouse-prefix2 0 ; C-@
305 "Second char of mouse-prefix. Used to detect double clicks and chords.")
306
307
308(defun mouse-second-hit (hit-wait)
309 "Returns the next mouse hit occurring within HIT-WAIT milliseconds."
310 (if (sit-for-millisecs hit-wait) nil ; No input within hit-wait millisecs.
311 (let ((pc1 (read-char)))
312 (if (or (not (equal pc1 mouse-prefix1))
313 (sit-for-millisecs 3)) ; a mouse prefix will have second char
314 (progn (setq unread-command-char pc1) ; Can get away with one unread.
315 nil) ; Next input not mouse event.
316 (let ((pc2 (read-char)))
317 (if (not (equal pc2 mouse-prefix2))
318 (progn (setq unread-command-char pc1) ; put back the ^X
319;;; Too bad can't do two: (setq unread-command-char (list pc1 pc2))
320 (ding) ; user will have to retype that pc2.
321 nil) ; This input is not a mouse event.
322 ;; Next input has mouse prefix and is within time limit.
323 (let ((new-hit (mouse-hit-read))) ; Read the new hit.
324 (if (sm::hit-up-p new-hit) ; Ignore up events when timing.
325 (mouse-second-hit (- hit-wait (sm::hit-delta new-hit)))
326 new-hit ; New down hit within limit, return it.
327 ))))))))
328
329(defun sm::window-xy (x y)
330 "Find window containing screen coordinates X and Y.
331Returns list (window x y) where x and y are relative to window."
332 (or
333 (catch 'found
334 (eval-in-windows
335 (let ((we (window-edges (selected-window))))
336 (let ((le (nth 0 we))
337 (te (nth 1 we))
338 (re (nth 2 we))
339 (be (nth 3 we)))
340 (if (= re (screen-width))
341 ;; include the continuation column with this window
342 (setq re (1+ re)))
343 (if (= be (screen-height))
344 ;; include partial line at bottom of screen with this window
345 ;; id est, if window is not multple of char size.
346 (setq be (1+ be)))
347
348 (if (and (>= x le) (< x re)
349 (>= y te) (< y be))
350 (throw 'found
351 (list (selected-window) (- x le) (- y te))))))
352 t)) ; include minibuffer in eval-in-windows
353 ;;If x,y from a real mouse click, we shouldn't get here.
354 (list nil x y)
355 ))
356
357(defun sm::window-region (loc)
358 "Parse LOC into a region symbol.
359Returns one of (text scrollbar modeline minibuffer)"
360 (let ((w (sm::loc-w loc))
361 (x (sm::loc-x loc))
362 (y (sm::loc-y loc)))
363 (let ((right (1- (window-width w)))
364 (bottom (1- (window-height w))))
365 (cond ((minibuffer-window-p w) 'minibuffer)
366 ((>= y bottom) 'modeline)
367 ((>= x right) 'scrollbar)
368 ;; far right column (window seperator) is always a scrollbar
369 ((and scrollbar-width
370 ;; mouse within scrollbar-width of edge.
371 (>= x (- right scrollbar-width))
372 ;; mouse a few chars past the end of line.
373 (>= x (+ 2 (window-line-end w x y))))
374 'scrollbar)
375 (t 'text)))))
376
377(defun window-line-end (w x y)
378 "Return WINDOW column (ignore X) containing end of line Y"
379 (eval-in-window w (save-excursion (move-to-loc (screen-width) y))))
380
381;;;
382;;; The encoding of mouse events into a mousemap.
383;;; These values must agree with coding in emacstool:
384;;;
385(defconst sm::keyword-alist
386 '((left . 1) (middle . 2) (right . 4)
387 (shift . 8) (control . 16) (meta . 32) (double . 64) (up . 128)
388 (text . 256) (scrollbar . 512) (modeline . 1024) (minibuffer . 2048)
389 ))
390
391(defun mouse-event-code (hit loc)
392 "Maps MOUSE-HIT and LOC into a mouse-code."
393;;;Region is a code for one of text, modeline, scrollbar, or minibuffer.
394 (logior (sm::hit-code hit)
395 (mouse-region-to-code (sm::window-region loc))))
396
397(defun mouse-region-to-code (region)
398 "Returns partial mouse-code for specified REGION."
399 (cdr (assq region sm::keyword-alist)))
400
401(defun mouse-list-to-mouse-code (mouse-list)
402 "Map a MOUSE-LIST to a mouse-code."
403 (apply 'logior
404 (mapcar (function (lambda (x)
405 (cdr (assq x sm::keyword-alist))))
406 mouse-list)))
407
408(defun mouse-code-to-mouse-list (mouse-code)
409 "Map a MOUSE-CODE to a mouse-list."
410 (apply 'nconc (mapcar
411 (function (lambda (x)
412 (if (logtest mouse-code (cdr x))
413 (list (car x)))))
414 sm::keyword-alist)))
415
416(defun mousemap-set (code mousemap value)
417 (let* ((alist (cdr mousemap))
418 (assq-result (assq code alist)))
419 (if assq-result
420 (setcdr assq-result value)
421 (setcdr mousemap (cons (cons code value) alist)))))
422
423(defun mousemap-get (code mousemap)
424 (cdr (assq code (cdr mousemap))))
425
426(defun mouse-lookup (mouse-code)
427 "Look up MOUSE-EVENT and return the definition. nil means undefined."
428 (or (mousemap-get mouse-code current-local-mousemap)
429 (mousemap-get mouse-code current-global-mousemap)))
430
431;;;
432;;; I (jpeck) don't understand the utility of the next four functions
433;;; ask Steven Greenbaum <froud@kestrel>
434;;;
435(defun mouse-mask-lookup (mask list)
436 "Args MASK (a bit mask) and LIST (a list of (code . form) pairs).
437Returns a list of elements of LIST whose code or'ed with MASK is non-zero."
438 (let ((result nil))
439 (while list
440 (if (logtest mask (car (car list)))
441 (setq result (cons (car list) result)))
442 (setq list (cdr list)))
443 result))
444
445(defun mouse-union (l l-unique)
446 "Return the union of list of mouse (code . form) pairs L and L-UNIQUE,
447where L-UNIQUE is considered to be union'ized already."
448 (let ((result l-unique))
449 (while l
450 (let ((code-form-pair (car l)))
451 (if (not (assq (car code-form-pair) result))
452 (setq result (cons code-form-pair result))))
453 (setq l (cdr l)))
454 result))
455
456(defun mouse-union-first-prefered (l1 l2)
457 "Return the union of lists of mouse (code . form) pairs L1 and L2,
458based on the code's, with preference going to elements in L1."
459 (mouse-union l2 (mouse-union l1 nil)))
460
461(defun mouse-code-function-pairs-of-region (region)
462 "Return a list of (code . function) pairs, where each code is
463currently set in the REGION."
464 (let ((mask (mouse-region-to-code region)))
465 (mouse-union-first-prefered
466 (mouse-mask-lookup mask (cdr current-local-mousemap))
467 (mouse-mask-lookup mask (cdr current-global-mousemap))
468 )))
469
470;;;
471;;; Functions for DESCRIBE-MOUSE-BINDINGS
472;;; And other mouse documentation functions
473;;; Still need a good procedure to print out a help sheet in readable format.
474;;;
475
476(defun one-line-doc-string (function)
477 "Returns first line of documentation string for FUNCTION.
478If there is no documentation string, then the string
479\"No documentation\" is returned."
480 (while (consp function) (setq function (car function)))
481 (let ((doc (documentation function)))
482 (if (null doc)
483 "No documentation."
484 (string-match "^.*$" doc)
485 (substring doc 0 (match-end 0)))))
486
487(defun print-mouse-format (binding)
488 (princ (car binding))
489 (princ ": ")
490 (mapcar (function
491 (lambda (mouse-list)
492 (princ mouse-list)
493 (princ " ")))
494 (cdr binding))
495 (terpri)
496 (princ " ")
497 (princ (one-line-doc-string (car binding)))
498 (terpri)
499 )
500
501(defun print-mouse-bindings (region)
502 "Prints mouse-event bindings for REGION."
503 (mapcar 'print-mouse-format (sm::event-bindings region)))
504
505(defun sm::event-bindings (region)
506 "Returns an alist of (function . (mouse-list1 ... mouse-listN)) for REGION,
507where each mouse-list is bound to the function in REGION."
508 (let ((mouse-bindings (mouse-code-function-pairs-of-region region))
509 (result nil))
510 (while mouse-bindings
511 (let* ((code-function-pair (car mouse-bindings))
512 (current-entry (assoc (cdr code-function-pair) result)))
513 (if current-entry
514 (setcdr current-entry
515 (cons (mouse-code-to-mouse-list (car code-function-pair))
516 (cdr current-entry)))
517 (setq result (cons (cons (cdr code-function-pair)
518 (list (mouse-code-to-mouse-list
519 (car code-function-pair))))
520 result))))
521 (setq mouse-bindings (cdr mouse-bindings))
522 )
523 result))
524
525(defun describe-mouse-bindings ()
526 "Lists all current mouse-event bindings."
527 (interactive)
528 (with-output-to-temp-buffer "*Help*"
529 (princ "Text Region") (terpri)
530 (princ "---- ------") (terpri)
531 (print-mouse-bindings 'text) (terpri)
532 (princ "Modeline Region") (terpri)
533 (princ "-------- ------") (terpri)
534 (print-mouse-bindings 'modeline) (terpri)
535 (princ "Scrollbar Region") (terpri)
536 (princ "--------- ------") (terpri)
537 (print-mouse-bindings 'scrollbar)))
538
539(defun describe-mouse-briefly (mouse-list)
540 "Print a short description of the function bound to MOUSE-LIST."
541 (interactive "xDescibe mouse list briefly: ")
542 (let ((function (mouse-lookup (mouse-list-to-mouse-code mouse-list))))
543 (if function
544 (message "%s runs the command %s" mouse-list function)
545 (message "%s is undefined" mouse-list))))
546
547(defun mouse-help-menu (function-and-binding)
548 (cons (prin1-to-string (car function-and-binding))
549 (menu-create ; Two sub-menu items of form ("String" . nil)
550 (list (list (one-line-doc-string (car function-and-binding)))
551 (list (prin1-to-string (cdr function-and-binding)))))))
552
553(defun mouse-help-region (w x y &optional region)
554 "Displays a menu of mouse functions callable in this region."
555 (let* ((region (or region (sm::window-region (list w x y))))
556 (mlist (mapcar (function mouse-help-menu)
557 (sm::event-bindings region)))
558 (menu (menu-create (cons (list (symbol-name region)) mlist)))
559 (item (sun-menu-evaluate w 0 y menu))
560 )))
561
562;;;
563;;; Menu interface functions
564;;;
565;;; use defmenu, because this interface is subject to change
566;;; really need a menu-p, but we use vectorp and the context...
567;;;
568(defun menu-create (items)
569 "Functional form for defmenu, given a list of ITEMS returns a menu.
570Each ITEM is a (STRING . VALUE) pair."
571 (apply 'vector items)
572 )
573
574(defmacro defmenu (menu &rest itemlist)
575 "Defines MENU to be a menu, the ITEMS are (STRING . VALUE) pairs.
576See sun-menu-evaluate for interpretation of ITEMS."
577 (list 'defconst menu (funcall 'menu-create itemlist))
578 )
579
580(defun sun-menu-evaluate (*menu-window* *menu-x* *menu-y* menu)
581 "Display a pop-up menu in WINDOW at X Y and evaluate selected item
582of MENU. MENU (or its symbol-value) should be a menu defined by defmenu.
583 A menu ITEM is a (STRING . FORM) pair;
584the FORM associated with the selected STRING is evaluated,
585and the resulting value is returned. Generally these FORMs are
586evaluated for their side-effects rather than their values.
587 If the selected form is a menu or a symbol whose value is a menu,
588then it is displayed and evaluated as a pullright menu item.
589 If the the FORM of the first ITEM is nil, the STRING of the item
590is used as a label for the menu, i.e. it's inverted and not selectible."
591
592 (if (symbolp menu) (setq menu (symbol-value menu)))
593 (eval (sun-menu-internal *menu-window* *menu-x* *menu-y* 4 menu)))
594
595(defun sun-get-frame-data (code)
596 "Sends the tty-sub-window escape sequence CODE to terminal,
597and returns a cons of the two numbers in returned escape sequence.
598That is it returns (cons <car> <cdr>) from \"\\E[n;<car>;<cdr>t\".
599CODE values: 13 = Tool-Position, 14 = Size-in-Pixels, 18 = Size-in-Chars."
600 (send-string-to-terminal (concat "\033[" (int-to-string code) "t"))
601 (let (char str x y)
602 (while (not (equal 116 (setq char (read-char)))) ; #\t = 116
603 (setq str (cons char str)))
604 (setq str (mapconcat 'char-to-string (nreverse str) ""))
605 (string-match ";[0-9]*" str)
606 (setq y (substring str (1+ (match-beginning 0)) (match-end 0)))
607 (setq str (substring str (match-end 0)))
608 (string-match ";[0-9]*" str)
609 (setq x (substring str (1+ (match-beginning 0)) (match-end 0)))
610 (cons (string-to-int y) (string-to-int x))))
611
612(defun sm::font-size ()
613 "Returns font size in pixels: (cons Ysize Xsize)"
614 (let ((pix (sun-get-frame-data 14)) ; returns size in pixels
615 (chr (sun-get-frame-data 18))) ; returns size in chars
616 (cons (/ (car pix) (car chr)) (/ (cdr pix) (cdr chr)))))
617
618(defvar sm::menu-kludge-x nil
619 "Cached frame-to-window X-Offset for sm::menu-kludge")
620(defvar sm::menu-kludge-y nil
621 "Cached frame-to-window Y-Offset for sm::menu-kludge")
622
623(defun sm::menu-kludge ()
624 "If sunfns.c uses <Menu_Base_Kludge> this function must be here!"
625 (or sm::menu-kludge-y
626 (let ((fs (sm::font-size)))
627 (setq sm::menu-kludge-y (+ 8 (car fs)) ; a title line and borders
628 sm::menu-kludge-x 4))) ; best values depend on .defaults/Menu
629 (let ((wl (sun-get-frame-data 13))) ; returns frame location
630 (cons (+ (car wl) sm::menu-kludge-y)
631 (+ (cdr wl) sm::menu-kludge-x))))
632
633;;;
634;;; Function interface to selection/region
635;;; primative functions are defined in sunfns.c
636;;;
637(defun sun-yank-selection ()
638 "Set mark and yank the contents of the current sunwindows selection
639into the current buffer at point."
640 (interactive "*")
641 (set-mark-command nil)
642 (insert-string (sun-get-selection)))
643
644(defun sun-select-region (beg end)
645 "Set the sunwindows selection to the region in the current buffer."
646 (interactive "r")
647 (sun-set-selection (buffer-substring beg end)))
648
649;;;
650;;; Support for emacstool
651;;; This closes the window instead of stopping emacs.
652;;;
653(defun suspend-emacstool (&optional stuffstring)
654 "If running under as a detached process emacstool,
655you don't want to suspend (there is no way to resume),
656just close the window, and wait for reopening."
657 (interactive)
658 (run-hooks 'suspend-hook)
659 (if stuffstring (send-string-to-terminal stuffstring))
660 (send-string-to-terminal "\033[2t") ; To close EmacsTool window.
661 (run-hooks 'suspend-resume-hook))
662;;;
663;;; initialize mouse maps
664;;;
665
666(make-variable-buffer-local 'current-local-mousemap)
667(setq-default current-local-mousemap nil)
668(defvar current-global-mousemap (make-mousemap))
diff --git a/lisp/term/sup-mouse.el b/lisp/term/sup-mouse.el
new file mode 100644
index 00000000000..d03b009136d
--- /dev/null
+++ b/lisp/term/sup-mouse.el
@@ -0,0 +1,207 @@
1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
2;; ;;
3;; File: sup-mouse.el ;;
4;; Author: Wolfgang Rupprecht ;;
5;; Created: Fri Nov 21 19:22:22 1986 ;;
6;; Contents: supdup mouse support for lisp machines ;;
7;; ;;
8;; (from code originally written by John Robinson@bbn for the bitgraph) ;;
9;; ;;
10;; $Log$ ;;
11;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
12
13;; GNU Emacs code for lambda/supdup mouse
14;; Copyright (C) Free Software Foundation 1985, 1986
15
16;; This file is part of GNU Emacs.
17
18;; GNU Emacs 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 1, or (at your option)
21;; any later version.
22
23;; GNU Emacs 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;;; User customization option:
33
34(defvar sup-mouse-fast-select-window nil
35 "*Non-nil for mouse hits to select new window, then execute; else just select.")
36
37(defconst mouse-left 0)
38(defconst mouse-center 1)
39(defconst mouse-right 2)
40
41(defconst mouse-2left 4)
42(defconst mouse-2center 5)
43(defconst mouse-2right 6)
44
45(defconst mouse-3left 8)
46(defconst mouse-3center 9)
47(defconst mouse-3right 10)
48
49;;; Defuns:
50
51(defun sup-mouse-report ()
52 "This function is called directly by the mouse, it parses and
53executes the mouse commands.
54
55 L move point * |---- These apply for mouse click in a window.
562L delete word |
573L copy word | If sup-mouse-fast-select-window is nil,
58 C move point and yank * | just selects that window.
592C yank pop |
60 R set mark * |
612R delete region |
623R copy region |
63
64on modeline on \"scroll bar\" in minibuffer
65 L scroll-up line to top execute-extended-command
66 C proportional goto-char line to middle mouse-help
67 R scroll-down line to bottom eval-expression"
68
69 (interactive)
70 (let*
71;; expect a string of <esc>:<buttons>;<x-pos>;<y-pos>c
72 ((buttons (sup-get-tty-num ?\;))
73 (x (sup-get-tty-num ?\;))
74 (y (sup-get-tty-num ?c))
75 (window (sup-pos-to-window x y))
76 (edges (window-edges window))
77 (old-window (selected-window))
78 (in-minibuf-p (eq y (1- (screen-height))))
79 (same-window-p (and (not in-minibuf-p) (eq window old-window)))
80 (in-modeline-p (eq y (1- (nth 3 edges))))
81 (in-scrollbar-p (>= x (1- (nth 2 edges)))))
82 (setq x (- x (nth 0 edges)))
83 (setq y (- y (nth 1 edges)))
84
85; (error "mouse-hit %d %d %d" buttons x y) ;;;; debug
86
87 (cond (in-modeline-p
88 (select-window window)
89 (cond ((= buttons mouse-left)
90 (scroll-up))
91 ((= buttons mouse-right)
92 (scroll-down))
93 ((= buttons mouse-center)
94 (goto-char (/ (* x
95 (- (point-max) (point-min)))
96 (1- (window-width))))
97 (beginning-of-line)
98 (what-cursor-position)))
99 (select-window old-window))
100 (in-scrollbar-p
101 (select-window window)
102 (scroll-up
103 (cond ((= buttons mouse-left)
104 y)
105 ((= buttons mouse-right)
106 (+ y (- 2 (window-height))))
107 ((= buttons mouse-center)
108 (/ (+ 2 y y (- (window-height))) 2))
109 (t
110 0)))
111 (select-window old-window))
112 (same-window-p
113 (cond ((= buttons mouse-left)
114 (sup-move-point-to-x-y x y))
115 ((= buttons mouse-2left)
116 (sup-move-point-to-x-y x y)
117 (kill-word 1))
118 ((= buttons mouse-3left)
119 (sup-move-point-to-x-y x y)
120 (save-excursion
121 (copy-region-as-kill
122 (point) (progn (forward-word 1) (point))))
123 (setq this-command 'yank)
124 )
125 ((= buttons mouse-right)
126 (push-mark)
127 (sup-move-point-to-x-y x y)
128 (exchange-point-and-mark))
129 ((= buttons mouse-2right)
130 (push-mark)
131 (sup-move-point-to-x-y x y)
132 (kill-region (mark) (point)))
133 ((= buttons mouse-3right)
134 (push-mark)
135 (sup-move-point-to-x-y x y)
136 (copy-region-as-kill (mark) (point))
137 (setq this-command 'yank))
138 ((= buttons mouse-center)
139 (sup-move-point-to-x-y x y)
140 (setq this-command 'yank)
141 (yank))
142 ((= buttons mouse-2center)
143 (yank-pop 1))
144 )
145 )
146 (in-minibuf-p
147 (cond ((= buttons mouse-right)
148 (call-interactively 'eval-expression))
149 ((= buttons mouse-left)
150 (call-interactively 'execute-extended-command))
151 ((= buttons mouse-center)
152 (describe-function 'sup-mouse-report)); silly self help
153 ))
154 (t ;in another window
155 (select-window window)
156 (cond ((not sup-mouse-fast-select-window))
157 ((= buttons mouse-left)
158 (sup-move-point-to-x-y x y))
159 ((= buttons mouse-right)
160 (push-mark)
161 (sup-move-point-to-x-y x y)
162 (exchange-point-and-mark))
163 ((= buttons mouse-center)
164 (sup-move-point-to-x-y x y)
165 (setq this-command 'yank)
166 (yank))
167 ))
168 )))
169
170
171(defun sup-get-tty-num (term-char)
172 "Read from terminal until TERM-CHAR is read, and return intervening number.
173Upon non-numeric not matching TERM-CHAR signal an error."
174 (let
175 ((num 0)
176 (char (read-char)))
177 (while (and (>= char ?0)
178 (<= char ?9))
179 (setq num (+ (* num 10) (- char ?0)))
180 (setq char (read-char)))
181 (or (eq term-char char)
182 (error "Invalid data format in mouse command"))
183 num))
184
185(defun sup-move-point-to-x-y (x y)
186 "Position cursor in window coordinates.
187X and Y are 0-based character positions in the window."
188 (move-to-window-line y)
189 (move-to-column x)
190 )
191
192(defun sup-pos-to-window (x y)
193 "Find window corresponding to screen coordinates.
194X and Y are 0-based character positions on the screen."
195 (let ((edges (window-edges))
196 (window nil))
197 (while (and (not (eq window (selected-window)))
198 (or (< y (nth 1 edges))
199 (>= y (nth 3 edges))
200 (< x (nth 0 edges))
201 (>= x (nth 2 edges))))
202 (setq window (next-window window))
203 (setq edges (window-edges window))
204 )
205 (or window (selected-window))
206 )
207 )
diff --git a/lisp/vmsproc.el b/lisp/vmsproc.el
new file mode 100644
index 00000000000..b4451a40ad0
--- /dev/null
+++ b/lisp/vmsproc.el
@@ -0,0 +1,138 @@
1;; Run asynchronous VMS subprocesses under Emacs
2;; Copyright (C) 1986 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;; Written by Mukesh Prasad.
21
22(defvar display-subprocess-window nil
23 "If non-nil, the suprocess window is displayed whenever input is received.")
24
25(defvar command-prefix-string "$ "
26 "String to insert to distinguish commands entered by user.")
27
28(defvar subprocess-running nil)
29(defvar command-mode-map nil)
30
31(if command-mode-map
32 nil
33 (setq command-mode-map (make-sparse-keymap))
34 (define-key command-mode-map "\C-m" 'command-send-input)
35 (define-key command-mode-map "\C-u" 'command-kill-line))
36
37(defun subprocess-input (name str)
38 "Handles input from a subprocess. Called by Emacs."
39 (if display-subprocess-window
40 (display-buffer subprocess-buf))
41 (let ((old-buffer (current-buffer)))
42 (set-buffer subprocess-buf)
43 (goto-char (point-max))
44 (insert str)
45 (insert ?\n)
46 (set-buffer old-buffer)))
47
48(defun subprocess-exit (name)
49 "Called by Emacs upon subprocess exit."
50 (setq subprocess-running nil))
51
52(defun start-subprocess ()
53 "Spawns an asynchronous subprocess with output redirected to
54the buffer *COMMAND*. Within this buffer, use C-m to send
55the last line to the subprocess or to bring another line to
56the end."
57 (if subprocess-running
58 (return t))
59 (setq subprocess-buf (get-buffer-create "*COMMAND*"))
60 (save-excursion
61 (set-buffer subprocess-buf)
62 (use-local-map command-mode-map))
63 (setq subprocess-running (spawn-subprocess 1 'subprocess-input
64 'subprocess-exit))
65 ;; Initialize subprocess so it doesn't panic and die upon
66 ;; encountering the first error.
67 (and subprocess-running
68 (send-command-to-subprocess 1 "ON SEVERE_ERROR THEN CONTINUE")))
69
70(defun subprocess-command-to-buffer (command buffer)
71 "Execute COMMAND and redirect output into BUFFER."
72 (let (cmd args)
73 (setq cmd (substring command 0 (string-match " " command)))
74 (setq args (substring command (string-match " " command)))
75 (call-process cmd nil buffer nil "*dcl*" args)))
76;BUGS: only the output up to the end of the first image activation is trapped.
77; (if (not subprocess-running)
78; (start-subprocess))
79; (save-excursion
80; (set-buffer buffer)
81; (let ((output-filename (concat "SYS$SCRATCH:OUTPUT-FOR-"
82; (getenv "USER") ".LISTING")))
83; (while (file-exists-p output-filename)
84; (delete-file output-filename))
85; (define-logical-name "SYS$OUTPUT" (concat output-filename "-NEW"))
86; (send-command-to-subprocess 1 command)
87; (send-command-to-subprocess 1 (concat
88; "RENAME " output-filename
89; "-NEW " output-filename))
90; (while (not (file-exists-p output-filename))
91; (sleep-for 1))
92; (define-logical-name "SYS$OUTPUT" nil)
93; (insert-file output-filename)
94; (delete-file output-filename))))
95
96(defun subprocess-command ()
97 "Starts asynchronous subprocess if not running and switches to its window."
98 (interactive)
99 (if (not subprocess-running)
100 (start-subprocess))
101 (and subprocess-running
102 (progn (pop-to-buffer subprocess-buf) (goto-char (point-max)))))
103
104(defun command-send-input ()
105 "If at last line of buffer, sends the current line to
106the spawned subprocess. Otherwise brings back current
107line to the last line for resubmission."
108 (interactive)
109 (beginning-of-line)
110 (let ((current-line (buffer-substring (point)
111 (progn (end-of-line) (point)))))
112 (if (eobp)
113 (progn
114 (if (not subprocess-running)
115 (start-subprocess))
116 (if subprocess-running
117 (progn
118 (beginning-of-line)
119 (send-command-to-subprocess 1 current-line)
120 (if command-prefix-string
121 (progn (beginning-of-line) (insert command-prefix-string)))
122 (next-line 1))))
123 ;; else -- if not at last line in buffer
124 (end-of-buffer)
125 (backward-char)
126 (next-line 1)
127 (if (string-equal command-prefix-string
128 (substring current-line 0 (length command-prefix-string)))
129 (insert (substring current-line (length command-prefix-string)))
130 (insert current-line)))))
131
132(defun command-kill-line()
133 "Kills the current line. Used in command mode."
134 (interactive)
135 (beginning-of-line)
136 (kill-line))
137
138(define-key esc-map "$" 'subprocess-command)
diff --git a/lisp/vmsx.el b/lisp/vmsx.el
new file mode 100644
index 00000000000..a68c6de3796
--- /dev/null
+++ b/lisp/vmsx.el
@@ -0,0 +1,137 @@
1;; Run asynchronous VMS subprocesses under Emacs
2;; Copyright (C) 1986 Free Software Foundation, Inc.
3
4;; This file is part of GNU Emacs.
5
6;; GNU Emacs is free software; you can redistribute it and/or modify
7;; it under the terms of the GNU General Public License as published by
8;; the Free Software Foundation; either version 1, or (at your option)
9;; any later version.
10
11;; GNU Emacs is distributed in the hope that it will be useful,
12;; but WITHOUT ANY WARRANTY; without even the implied warranty of
13;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14;; GNU General Public License for more details.
15
16;; You should have received a copy of the GNU General Public License
17;; along with GNU Emacs; see the file COPYING. If not, write to
18;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
19
20;; Written by Mukesh Prasad.
21
22(defvar display-subprocess-window nil
23 "If non-nil, the suprocess window is displayed whenever input is received.")
24
25(defvar command-prefix-string "$ "
26 "String to insert to distinguish commands entered by user.")
27
28(defvar subprocess-running nil)
29(defvar command-mode-map nil)
30
31(if command-mode-map
32 nil
33 (setq command-mode-map (make-sparse-keymap))
34 (define-key command-mode-map "\C-m" 'command-send-input)
35 (define-key command-mode-map "\C-u" 'command-kill-line))
36
37(defun subprocess-input (name str)
38 "Handles input from a subprocess. Called by Emacs."
39 (if display-subprocess-window
40 (display-buffer subprocess-buf))
41 (let ((old-buffer (current-buffer)))
42 (set-buffer subprocess-buf)
43 (goto-char (point-max))
44 (insert str)
45 (insert ?\n)
46 (set-buffer old-buffer)))
47
48(defun subprocess-exit (name)
49 "Called by Emacs upon subprocess exit."
50 (setq subprocess-running nil))
51
52(defun start-subprocess ()
53 "Spawns an asynchronous subprocess with output redirected to
54the buffer *COMMAND*. Within this buffer, use C-m to send
55the last line to the subprocess or to bring another line to
56the end."
57 (if subprocess-running
58 (return t))
59 (setq subprocess-buf (get-buffer-create "*COMMAND*"))
60 (save-excursion
61 (set-buffer subprocess-buf)
62 (use-local-map command-mode-map))
63 (setq subprocess-running (spawn-subprocess 1 'subprocess-input
64 'subprocess-exit))
65 ;; Initialize subprocess so it doesn't panic and die upon
66 ;; encountering the first error.
67 (and subprocess-running
68 (send-command-to-subprocess 1 "ON SEVERE_ERROR THEN CONTINUE")))
69
70(defvar subprocess-command-to-buffer-tmpdir "SYS$SCRATCH:"
71 "*Put temporary files from subprocess-command-to-buffer here.")
72
73(defun subprocess-command-to-buffer (command buffer)
74 "Execute command and redirect output into buffer.
75
76BUGS: only the output up to the end of the first image activation is trapped."
77 (if (not subprocess-running)
78 (start-subprocess))
79 (save-excursion
80 (set-buffer buffer)
81 (let ((output-filename
82 (concat subprocess-command-to-buffer-tmpdir
83 "OUTPUT-FOR-" (getenv "USER") ".LISTING")))
84 (while (file-attributes output-filename)
85 (delete-file output-filename))
86 (send-command-to-subprocess 1 (concat "DEFINE/USER SYS$OUTPUT "
87 output-filename "-NEW"))
88 (send-command-to-subprocess 1 command)
89 (send-command-to-subprocess 1 (concat "RENAME " output-filename
90 "-NEW " output-filename))
91 (while (not (file-attributes output-filename))
92 (sleep-for 2))
93 (insert-file output-filename))))
94
95(defun subprocess-command ()
96 "Starts asynchronous subprocess if not running and switches to its window."
97 (interactive)
98 (if (not subprocess-running)
99 (start-subprocess))
100 (and subprocess-running
101 (progn (pop-to-buffer subprocess-buf) (goto-char (point-max)))))
102
103(defun command-send-input ()
104 "If at last line of buffer, sends the current line to
105the spawned subprocess. Otherwise brings back current
106line to the last line for resubmission."
107 (interactive)
108 (beginning-of-line)
109 (let ((current-line (buffer-substring (point)
110 (progn (end-of-line) (point)))))
111 (if (eobp)
112 (progn
113 (if (not subprocess-running)
114 (start-subprocess))
115 (if subprocess-running
116 (progn
117 (beginning-of-line)
118 (send-command-to-subprocess 1 current-line)
119 (if command-prefix-string
120 (progn (beginning-of-line) (insert command-prefix-string)))
121 (next-line 1))))
122 ;; else -- if not at last line in buffer
123 (end-of-buffer)
124 (backward-char)
125 (next-line 1)
126 (if (string-equal command-prefix-string
127 (substring current-line 0 (length command-prefix-string)))
128 (insert (substring current-line (length command-prefix-string)))
129 (insert current-line)))))
130
131(defun command-kill-line()
132 "Kills the current line. Used in command mode."
133 (interactive)
134 (beginning-of-line)
135 (kill-line))
136
137(define-key esc-map "$" 'subprocess-command)
diff --git a/lisp/x-menu.el b/lisp/x-menu.el
new file mode 100644
index 00000000000..878dde0dc5e
--- /dev/null
+++ b/lisp/x-menu.el
@@ -0,0 +1,145 @@
1;; Copyright (C) 1986 Free Software Foundation, Inc.
2
3;; This file is part of GNU Emacs.
4
5;; GNU Emacs is free software; you can redistribute it and/or modify
6;; it under the terms of the GNU General Public License as published by
7;; the Free Software Foundation; either version 1, or (at your option)
8;; any later version.
9
10;; GNU Emacs is distributed in the hope that it will be useful,
11;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13;; GNU General Public License for more details.
14
15;; You should have received a copy of the GNU General Public License
16;; along with GNU Emacs; see the file COPYING. If not, write to
17;; the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
18
19
20(defmacro caar (conscell)
21 (list 'car (list 'car conscell)))
22
23(defmacro cdar (conscell)
24 (list 'cdr (list 'car conscell)))
25
26(defun x-menu-mode ()
27 "Major mode for creating permanent menus for use with X.
28These menus are implemented entirely in Lisp; popup menus, implemented
29with x-popup-menu, are implemented using XMenu primitives."
30 (make-local-variable 'x-menu-items-per-line)
31 (make-local-variable 'x-menu-item-width)
32 (make-local-variable 'x-menu-items-alist)
33 (make-local-variable 'x-process-mouse-hook)
34 (make-local-variable 'x-menu-assoc-buffer)
35 (setq buffer-read-only t)
36 (setq truncate-lines t)
37 (setq x-process-mouse-hook 'x-menu-pick-entry)
38 (setq mode-line-buffer-identification '("MENU: %32b")))
39
40(defvar x-menu-max-width 0)
41(defvar x-menu-items-per-line 0)
42(defvar x-menu-item-width 0)
43(defvar x-menu-items-alist nil)
44(defvar x-menu-assoc-buffer nil)
45
46(defvar x-menu-item-spacing 1
47 "*Minimum horizontal spacing between objects in a permanent X menu.")
48
49(defun x-menu-create-menu (name)
50 "Create a permanent X menu. Returns an item which should be used as a
51menu object whenever referring to the menu."
52 (let ((old (current-buffer))
53 (buf (get-buffer-create name)))
54 (set-buffer buf)
55 (x-menu-mode)
56 (setq x-menu-assoc-buffer old)
57 (set-buffer old)
58 buf))
59
60(defun x-menu-change-associated-buffer (menu buffer)
61 "Change associated buffer of MENU to BUFFER. BUFFER should be a buffer
62object."
63 (let ((old (current-buffer)))
64 (set-buffer menu)
65 (setq x-menu-assoc-buffer buffer)
66 (set-buffer old)))
67
68(defun x-menu-add-item (menu item binding)
69 "Adds to MENU an item with name ITEM, associated with BINDING.
70Following a sequence of calls to x-menu-add-item, a call to x-menu-compute
71should be performed before the menu will be made available to the user.
72
73BINDING should be a function of one argument, which is the numerical
74button/key code as defined in x-menu.el."
75 (let ((old (current-buffer))
76 elt)
77 (set-buffer menu)
78 (if (setq elt (assoc item x-menu-items-alist))
79 (rplacd elt binding)
80 (setq x-menu-items-alist (append x-menu-items-alist
81 (list (cons item binding)))))
82 (set-buffer old)
83 item))
84
85(defun x-menu-delete-item (menu item)
86 "Deletes from MENU the item named ITEM. x-menu-compute should be called
87before the menu is made available to the user."
88 (let ((old (current-buffer))
89 elt)
90 (set-buffer menu)
91 (if (setq elt (assoc item x-menu-items-alist))
92 (rplaca elt nil))
93 (set-buffer old)
94 item))
95
96(defun x-menu-activate (menu)
97 "Computes all necessary parameters for MENU. This must be called whenever
98a menu is modified before it is made available to the user.
99
100This also creates the menu itself."
101 (let ((buf (current-buffer)))
102 (pop-to-buffer menu)
103 (let (buffer-read-only)
104 (setq x-menu-max-width (1- (screen-width)))
105 (setq x-menu-item-width 0)
106 (let (items-head
107 (items-tail x-menu-items-alist))
108 (while items-tail
109 (if (caar items-tail)
110 (progn (setq items-head (cons (car items-tail) items-head))
111 (setq x-menu-item-width
112 (max x-menu-item-width
113 (length (caar items-tail))))))
114 (setq items-tail (cdr items-tail)))
115 (setq x-menu-items-alist (reverse items-head)))
116 (setq x-menu-item-width (+ x-menu-item-spacing x-menu-item-width))
117 (setq x-menu-items-per-line
118 (max 1 (/ x-menu-max-width x-menu-item-width)))
119 (erase-buffer)
120 (let ((items-head x-menu-items-alist))
121 (while items-head
122 (let ((items 0))
123 (while (and items-head
124 (<= (setq items (1+ items)) x-menu-items-per-line))
125 (insert (format (concat "%"
126 (int-to-string x-menu-item-width) "s")
127 (caar items-head)))
128 (setq items-head (cdr items-head))))
129 (insert ?\n)))
130 (shrink-window (max 0
131 (- (window-height)
132 (1+ (count-lines (point-min) (point-max))))))
133 (goto-char (point-min)))
134 (pop-to-buffer buf)))
135
136(defun x-menu-pick-entry (position event)
137 "Internal function for dispatching on mouse/menu events"
138 (let* ((x (min (1- x-menu-items-per-line)
139 (/ (current-column) x-menu-item-width)))
140 (y (- (count-lines (point-min) (point))
141 (if (zerop (current-column)) 0 1)))
142 (item (+ x (* y x-menu-items-per-line)))
143 (litem (cdr (nth item x-menu-items-alist))))
144 (and litem (funcall litem event)))
145 (pop-to-buffer x-menu-assoc-buffer))