diff options
| author | Jim Blandy | 1989-10-31 15:59:53 +0000 |
|---|---|---|
| committer | Jim Blandy | 1989-10-31 15:59:53 +0000 |
| commit | 0d20f9a04efa7cfbe205e4967b6797b89fc64fe7 (patch) | |
| tree | 787af4d2117afe2886996c45c40451f7406fe4fb | |
| parent | 89758ab855a9a8a64f36d986da39767ebdc9ac76 (diff) | |
| download | emacs-0d20f9a04efa7cfbe205e4967b6797b89fc64fe7.tar.gz emacs-0d20f9a04efa7cfbe205e4967b6797b89fc64fe7.zip | |
Initial revision
| -rw-r--r-- | lisp/electric.el | 181 | ||||
| -rw-r--r-- | lisp/emulation/mlsupport.el | 405 | ||||
| -rw-r--r-- | lisp/grow-vers.el | 30 | ||||
| -rw-r--r-- | lisp/inc-vers.el | 43 | ||||
| -rw-r--r-- | lisp/loadup.el | 140 | ||||
| -rw-r--r-- | lisp/mail/rmailmsc.el | 45 | ||||
| -rw-r--r-- | lisp/mail/rnews.el | 979 | ||||
| -rw-r--r-- | lisp/mail/rnewspost.el | 390 | ||||
| -rw-r--r-- | lisp/mail/undigest.el | 105 | ||||
| -rw-r--r-- | lisp/mim-syntax.el | 91 | ||||
| -rw-r--r-- | lisp/misc.el | 51 | ||||
| -rw-r--r-- | lisp/netunam.el | 152 | ||||
| -rw-r--r-- | lisp/sun-curs.el | 207 | ||||
| -rw-r--r-- | lisp/sun-fns.el | 630 | ||||
| -rw-r--r-- | lisp/sun-keys.el | 71 | ||||
| -rw-r--r-- | lisp/term/sun-mouse.el | 668 | ||||
| -rw-r--r-- | lisp/term/sup-mouse.el | 207 | ||||
| -rw-r--r-- | lisp/vmsproc.el | 138 | ||||
| -rw-r--r-- | lisp/vmsx.el | 137 | ||||
| -rw-r--r-- | lisp/x-menu.el | 145 |
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. | ||
| 302 | 0 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. | ||
| 22 | This may be a list of file names separated by commas. | ||
| 23 | If 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. | ||
| 55 | While composing the reply, use \\[mail-yank-original] to yank the original | ||
| 56 | message into it." | ||
| 57 | t) | ||
| 58 | |||
| 59 | (autoload 'news-mail-other-window "rnewspost" | ||
| 60 | "Send mail in another window. | ||
| 61 | While composing the message, use \\[mail-yank-original] to yank the | ||
| 62 | original 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. | ||
| 71 | While composing the reply, use \\[mail-yank-original] to yank the original | ||
| 72 | message into it." | ||
| 73 | t) | ||
| 74 | |||
| 75 | (defvar news-group-hook-alist nil | ||
| 76 | "Alist of (GROUP-REGEXP . HOOK) pairs. | ||
| 77 | Just before displaying a message, each HOOK is called | ||
| 78 | if 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 | ||
| 104 | known 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 | ||
| 110 | formatting 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 | ||
| 116 | associated 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. | ||
| 119 | Not 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. | ||
| 148 | A gap is a sequence of missing messages between two messages that exist. | ||
| 149 | An 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 | ||
| 186 | delete groups. | ||
| 187 | You can reply to articles posted and send articles to any group. | ||
| 188 | |||
| 189 | Type \\[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, | ||
| 258 | and 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 | ||
| 271 | are 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. | ||
| 309 | New readers can find additional help in newsgroup: news.announce.newusers . | ||
| 310 | All normal editing commands are turned off. | ||
| 311 | Instead, these commands are available: | ||
| 312 | |||
| 313 | . move point to front of this news article (same as Meta-<). | ||
| 314 | Space scroll to next screen of this news article. | ||
| 315 | Delete scroll down previous page of this news article. | ||
| 316 | n move to next news article, possibly next group. | ||
| 317 | p move to previous news article, possibly previous group. | ||
| 318 | j jump to news article specified by numeric position. | ||
| 319 | M-j jump to news group. | ||
| 320 | M-n goto next news group. | ||
| 321 | M-p goto previous news group. | ||
| 322 | l list all the news groups with current status. | ||
| 323 | ? print this help message. | ||
| 324 | C-c C-r caesar rotate all letters by 13 places in the article's body (rot13). | ||
| 325 | g get new USENET news. | ||
| 326 | f post a reply article to USENET. | ||
| 327 | a post an original news article. | ||
| 328 | A add a newsgroup. | ||
| 329 | o save the current article in the named file (append if file exists). | ||
| 330 | C-o output this message to a Unix-format mail file (append it). | ||
| 331 | c \"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) | ||
| 334 | t show all the headers this news article originally had. | ||
| 335 | q quit reading news after updating .newsrc file. | ||
| 336 | e exit updating .newsrc file. | ||
| 337 | m mail a news article. Same as C-x 4 m. | ||
| 338 | x update last message seen to be the current message. | ||
| 339 | r mail a reply to this news article. Like m but initializes some fields. | ||
| 340 | u unsubscribe from current newsgroup. | ||
| 341 | U 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> | ||
| 388 | to 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. | ||
| 541 | Negative ARG moves backward. | ||
| 542 | If 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. | ||
| 562 | With no arg or arg of 1, move one message | ||
| 563 | and move to previous newsgroup if at beginning. | ||
| 564 | A 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; | ||
| 600 | one 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. | ||
| 752 | The arg must be in slashified format. | ||
| 753 | Using 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) | ||
| 904 | Good for hanging on to a message that might or might not be | ||
| 905 | automatically deleted." | ||
| 906 | (interactive "P | ||
| 907 | FName 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. | ||
| 958 | Used to encode/decode possibly offensive messages (commonly in net.jokes). | ||
| 959 | With prefix arg, specifies the number of places to rotate each letter forward. | ||
| 960 | Mail 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. | ||
| 71 | First-time posters are asked to please read the articles in newsgroup: | ||
| 72 | news.announce.newusers . | ||
| 73 | Like Text Mode but with these additional commands: | ||
| 74 | |||
| 75 | C-c C-s news-inews (post the message) C-c C-c news-inews | ||
| 76 | C-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: | ||
| 80 | C-c C-y news-reply-yank-original (insert current message, in NEWS). | ||
| 81 | C-c C-q mail-fill-yanked-message (fill what was yanked). | ||
| 82 | C-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). | ||
| 112 | Puts point before the text and mark after. | ||
| 113 | Indents each nonblank line ARG spaces (default 3). | ||
| 114 | Just \\[universal-argument] as argument means don't indent | ||
| 115 | and 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. | ||
| 129 | RFC 850 constrains the Newsgroups: field to be a comma separated list of valid | ||
| 130 | newsgroups names at your site: | ||
| 131 | Newsgroups: 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. | ||
| 139 | One usually requests followups to only one newsgroup. | ||
| 140 | RFC 850 constrains the Followup-To: field to be a comma separated list of valid | ||
| 141 | newsgroups names at your site, that are also in the Newsgroups: field: | ||
| 142 | Newsgroups: news.misc,comp.misc,rec.misc,misc.misc,soc.misc | ||
| 143 | Followup-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. | ||
| 155 | Create the field if none. Without this field the posting goes to all of | ||
| 156 | USENET. 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. | ||
| 166 | Used as an aid to the news reader, it can contain a few, well selected keywords | ||
| 167 | identifying 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. | ||
| 174 | Used as an aid to the news reader, it can contain a succinct | ||
| 175 | summary (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 | ||
| 187 | news-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. | ||
| 251 | While composing the reply, use \\[news-reply-yank-original] to yank the | ||
| 252 | original 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. | ||
| 279 | While composing the followup, use \\[news-reply-yank-original] to yank the | ||
| 280 | original 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. | ||
| 358 | Type \\[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. | ||
| 387 | While composing the message, use \\[news-reply-yank-original] to yank the | ||
| 388 | original 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. | ||
| 24 | Leaves 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. | ||
| 26 | Points 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. | ||
| 78 | Answers 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. | ||
| 23 | Copy ARG characters, but not past the end of that line. | ||
| 24 | If no argument given, copy the entire rest of the line. | ||
| 25 | The 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. | ||
| 26 | By 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. | ||
| 36 | Used 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. | ||
| 40 | Has 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. | ||
| 44 | Optional second arg NODE is a string specifying a particular nodename; | ||
| 45 | if supplied and not nil, PASSWORD applies to only that node. | ||
| 46 | Optional 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. | ||
| 63 | First argument NODE is the network node for the remote machine. | ||
| 64 | Second optional argument USER is the user name to use on that machine. | ||
| 65 | If called interactively, the user name is prompted for. | ||
| 66 | Third 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 | ||
| 69 | cause 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. | ||
| 100 | NODE 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. | ||
| 65 | If ICON is nil, switch to the system default cursor, | ||
| 66 | Otherwise, 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. | ||
| 115 | If mouse is in same WINDOW but at different X or Y than when | ||
| 116 | mouse-drag-move-point was last executed, set the mark at mouse | ||
| 117 | and 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. | ||
| 148 | The resulting region is put in the sun-window stuff buffer. | ||
| 149 | Left or right Paren syntax marks an s-expression. | ||
| 150 | Clicking at the end of a line marks the line including a trailing newline. | ||
| 151 | If 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. | ||
| 188 | See 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. | ||
| 197 | See 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. | ||
| 205 | See 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. | ||
| 215 | See 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. | ||
| 223 | See 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. | ||
| 247 | Consecutive 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. | ||
| 252 | If mouse-move-point is performed after the first or second click, | ||
| 253 | the next click will do a yank, etc. Except for a possible mouse-move-point, | ||
| 254 | this 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 | ||
| 311 | relative 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. | ||
| 474 | To 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: | ||
| 48 | CCommand 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. | ||
| 40 | Set 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. | ||
| 44 | The cursor is deemed to be in the right edge scrollbar if it is this near the | ||
| 45 | right edge, and more than two chars past the end of the indicated line. | ||
| 46 | Setting 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. | ||
| 61 | MOUSE-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. | ||
| 71 | The atom `double' is used with a button designator to denote a double click. | ||
| 72 | Two button chords are denoted by listing the two buttons. | ||
| 73 | See 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. | ||
| 78 | See define-mouse for a description of MOUSE-EVENT-LIST and DEF. | ||
| 79 | Note that if MOUSE-EVENT-LIST has a local definition in the current buffer, | ||
| 80 | that 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. | ||
| 86 | See define-mouse for a description of the arguments. | ||
| 87 | The definition goes in the current buffer's local mousemap. | ||
| 88 | Normally 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. | ||
| 100 | nil 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. | ||
| 115 | Just 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 | ||
| 191 | YESMINI says to include the minibuffer as a window. | ||
| 192 | This 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. | ||
| 205 | Handles 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. | ||
| 229 | Expecting to read a hit, which is a list: (button x y delta). | ||
| 230 | A form bound to button by define-mouse is found by mouse-lookup. | ||
| 231 | The variables: *mouse-window*, *mouse-x*, *mouse-y* are bound. | ||
| 232 | If 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), | ||
| 234 | the form is eval'ed; if the form is neither of these, it is an error. | ||
| 235 | Returns 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), | ||
| 282 | but 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. | ||
| 331 | Returns 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. | ||
| 359 | Returns 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). | ||
| 437 | Returns 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, | ||
| 447 | where 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, | ||
| 458 | based 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 | ||
| 463 | currently 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. | ||
| 478 | If 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, | ||
| 507 | where 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. | ||
| 570 | Each 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. | ||
| 576 | See 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 | ||
| 582 | of MENU. MENU (or its symbol-value) should be a menu defined by defmenu. | ||
| 583 | A menu ITEM is a (STRING . FORM) pair; | ||
| 584 | the FORM associated with the selected STRING is evaluated, | ||
| 585 | and the resulting value is returned. Generally these FORMs are | ||
| 586 | evaluated for their side-effects rather than their values. | ||
| 587 | If the selected form is a menu or a symbol whose value is a menu, | ||
| 588 | then 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 | ||
| 590 | is 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, | ||
| 597 | and returns a cons of the two numbers in returned escape sequence. | ||
| 598 | That is it returns (cons <car> <cdr>) from \"\\E[n;<car>;<cdr>t\". | ||
| 599 | CODE 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 | ||
| 639 | into 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, | ||
| 655 | you don't want to suspend (there is no way to resume), | ||
| 656 | just 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 | ||
| 53 | executes the mouse commands. | ||
| 54 | |||
| 55 | L move point * |---- These apply for mouse click in a window. | ||
| 56 | 2L delete word | | ||
| 57 | 3L copy word | If sup-mouse-fast-select-window is nil, | ||
| 58 | C move point and yank * | just selects that window. | ||
| 59 | 2C yank pop | | ||
| 60 | R set mark * | | ||
| 61 | 2R delete region | | ||
| 62 | 3R copy region | | ||
| 63 | |||
| 64 | on 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. | ||
| 173 | Upon 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. | ||
| 187 | X 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. | ||
| 194 | X 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 | ||
| 54 | the buffer *COMMAND*. Within this buffer, use C-m to send | ||
| 55 | the last line to the subprocess or to bring another line to | ||
| 56 | the 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 | ||
| 106 | the spawned subprocess. Otherwise brings back current | ||
| 107 | line 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 | ||
| 54 | the buffer *COMMAND*. Within this buffer, use C-m to send | ||
| 55 | the last line to the subprocess or to bring another line to | ||
| 56 | the 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 | |||
| 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 | ||
| 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 | ||
| 105 | the spawned subprocess. Otherwise brings back current | ||
| 106 | line 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. | ||
| 28 | These menus are implemented entirely in Lisp; popup menus, implemented | ||
| 29 | with 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 | ||
| 51 | menu 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 | ||
| 62 | object." | ||
| 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. | ||
| 70 | Following a sequence of calls to x-menu-add-item, a call to x-menu-compute | ||
| 71 | should be performed before the menu will be made available to the user. | ||
| 72 | |||
| 73 | BINDING should be a function of one argument, which is the numerical | ||
| 74 | button/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 | ||
| 87 | before 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 | ||
| 98 | a menu is modified before it is made available to the user. | ||
| 99 | |||
| 100 | This 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)) | ||