Mercurial > hg > xemacs-beta
comparison lisp/hyperbole/hactypes.el @ 0:376386a54a3c r19-14
Import from CVS: tag r19-14
author | cvs |
---|---|
date | Mon, 13 Aug 2007 08:45:50 +0200 |
parents | |
children | 4103f0995bd7 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:376386a54a3c |
---|---|
1 ;;!emacs | |
2 ;; | |
3 ;; FILE: hactypes.el | |
4 ;; SUMMARY: Default action types for Hyperbole. | |
5 ;; USAGE: GNU Emacs Lisp Library | |
6 ;; KEYWORDS: extensions, hypermedia | |
7 ;; | |
8 ;; AUTHOR: Bob Weiner | |
9 ;; ORG: Brown U. | |
10 ;; | |
11 ;; ORIG-DATE: 23-Sep-91 at 20:34:36 | |
12 ;; LAST-MOD: 28-Oct-95 at 02:33:45 by Bob Weiner | |
13 ;;; ************************************************************************ | |
14 ;;; Other required Elisp libraries | |
15 ;;; ************************************************************************ | |
16 | |
17 (mapcar 'require '(hbut hpath hargs hact hmail)) | |
18 | |
19 ;;; ************************************************************************ | |
20 ;;; Standard Hyperbole action types | |
21 ;;; ************************************************************************ | |
22 | |
23 (defact annot-bib (key) | |
24 "Follows internal ref KEY within an annotated bibliography, delimiters=[]." | |
25 (interactive "sReference key (no []): ") | |
26 (let ((opoint (point))) | |
27 (goto-char 1) | |
28 (if (re-search-forward | |
29 (concat "^[*]*[ \t]*\\\[" (ebut:key-to-label key) "\\\]") nil t) | |
30 (progn | |
31 (beginning-of-line) | |
32 (delete-other-windows) | |
33 (split-window-vertically nil) | |
34 (goto-char opoint)) | |
35 (beep)) | |
36 (goto-char opoint))) | |
37 | |
38 (defact completion () | |
39 "Inserts completion at point into minibuffer or other window. | |
40 Unless at end of buffer or if completion has already been inserted, then | |
41 deletes completions window." | |
42 (interactive) | |
43 (if (eobp) | |
44 (progn (bury-buffer nil) | |
45 (delete-window)) | |
46 (hargs:completion))) | |
47 | |
48 (defact eval-elisp (lisp-expr) | |
49 "Evaluates a Lisp expression LISP-EXPR." | |
50 (interactive "xLisp to eval: ") | |
51 (eval lisp-expr)) | |
52 | |
53 (defact exec-kbd-macro (kbd-macro &optional repeat-count) | |
54 "Executes KBD-MACRO REPEAT-COUNT times. | |
55 KBD-MACRO may be a string of editor command characters, a function symbol or | |
56 nil to use the last defined keyboard macro. | |
57 Optional REPEAT-COUNT nil means execute once, zero means repeat until | |
58 error." | |
59 (interactive | |
60 (let (macro repeat) | |
61 (setq macro (intern-soft | |
62 (hargs:read-match | |
63 "Unquoted macro name or nil for last one defined: " | |
64 obarray (function | |
65 (lambda (sym) | |
66 (and (fboundp sym) | |
67 (stringp (hypb:indirect-function sym))))) | |
68 nil "nil" 'symbol))) | |
69 (cond ((fboundp macro)) | |
70 ((null last-kbd-macro) | |
71 (hypb:error | |
72 "(exec-kbd-macro): Define a keyboard macro first.")) | |
73 (t (fset 'zzz last-kbd-macro) | |
74 (setq macro 'zzz))) | |
75 (save-excursion | |
76 (let ((standard-output (get-buffer-create "*macro-def*"))) | |
77 (unwind-protect | |
78 (progn (set-buffer standard-output) | |
79 (setq buffer-read-only nil) | |
80 (erase-buffer) | |
81 (insert-kbd-macro macro) | |
82 (goto-char (point-min)) | |
83 (setq macro (car (cdr (cdr (read (current-buffer))))))) | |
84 (kill-buffer standard-output)))) | |
85 (fmakunbound 'zzz) | |
86 (setq repeat (hargs:read "Repeat count: " | |
87 (function | |
88 (lambda (repeat) | |
89 (or (null repeat) | |
90 (and (integerp repeat) (>= repeat 0))))) | |
91 1)) | |
92 (list macro repeat))) | |
93 (if (interactive-p) | |
94 nil | |
95 (or (and kbd-macro (or (stringp kbd-macro) | |
96 (and (symbolp kbd-macro) (fboundp kbd-macro)))) | |
97 (hypb:error "(exec-kbd-macro): Bad macro: %s" kbd-macro)) | |
98 (or (null repeat-count) (and (integerp repeat-count) (<= 0 repeat-count)) | |
99 (hypb:error "(exec-kbd-macro): Bad repeat count: %s" repeat-count))) | |
100 (execute-kbd-macro kbd-macro repeat-count)) | |
101 | |
102 ;;; Support next two actypes on systems which use the 'comint' shell package | |
103 ;;; rather than Emacs V18 shell.el. | |
104 ;;; | |
105 (if (or hyperb:lemacs-p hyperb:emacs19-p) | |
106 (require 'comint)) | |
107 (and (fboundp 'comint-send-input) (not (fboundp 'shell-send-input)) | |
108 (fset 'shell-send-input 'comint-send-input)) | |
109 (and (fboundp 'comint-kill-output) (not (fboundp 'kill-output-from-shell)) | |
110 (fset 'kill-output-from-shell 'comint-kill-output)) | |
111 (and (fboundp 'comint-show-output) (not (fboundp 'show-output-from-shell)) | |
112 (fset 'show-output-from-shell 'comint-show-output)) | |
113 | |
114 (defact exec-shell-cmd (shell-cmd &optional internal-cmd kill-prev) | |
115 "Executes a SHELL-CMD string asynchronously. | |
116 Optional non-nil second argument INTERNAL-CMD means do not display the shell | |
117 command line executed. Optional non-nil third argument KILL-PREV means | |
118 kill last output to shell buffer before executing SHELL-CMD." | |
119 (interactive | |
120 (let ((default (car defaults)) | |
121 (default1 (nth 1 defaults)) | |
122 (default2 (nth 2 defaults))) | |
123 (list (hargs:read "Shell cmd: " | |
124 (function | |
125 (lambda (cmd) (not (string= cmd "")))) | |
126 default "Enter a shell command." 'string) | |
127 (y-or-n-p (format "Omit cmd from output (default = %s): " | |
128 default1)) | |
129 (y-or-n-p (format "Kill prior cmd's output (default = %s): " | |
130 default2))))) | |
131 (let ((buf-name "*Hypb Shell*") | |
132 (owind (selected-window))) | |
133 (unwind-protect | |
134 (progn | |
135 (if (not (hpath:ange-ftp-p default-directory)) | |
136 (setq shell-cmd | |
137 (concat "cd " default-directory "; " shell-cmd))) | |
138 (if (not (get-buffer buf-name)) | |
139 (save-excursion | |
140 ;; Ensure shell displays in other window unless in the | |
141 ;; OO-Browser, then use selected window. | |
142 (if (br-in-browser) | |
143 nil | |
144 (if (= (length (hypb:window-list)) 1) | |
145 (split-window-vertically)) | |
146 (other-window 1)) | |
147 (if (eq (minibuffer-window) (selected-window)) | |
148 (other-window 1)) | |
149 (shell) (rename-buffer buf-name) | |
150 (setq last-input-start (point-marker) | |
151 last-input-end (point-marker)) | |
152 (if (fboundp 'comint-kill-output) | |
153 (setq comint-last-input-start last-input-start | |
154 comint-last-input-end last-input-end) | |
155 ))) | |
156 (or (equal (buffer-name (current-buffer)) buf-name) | |
157 (if (br-in-browser) (switch-to-buffer buf-name) | |
158 (pop-to-buffer buf-name))) | |
159 (goto-char (point-max)) | |
160 (and kill-prev last-input-end | |
161 (not (equal last-input-start last-input-end)) | |
162 (kill-output-from-shell)) | |
163 (insert shell-cmd) | |
164 (shell-send-input) | |
165 (show-output-from-shell) | |
166 (or internal-cmd (scroll-down 1))) | |
167 (select-window owind)))) | |
168 | |
169 (defact exec-window-cmd (shell-cmd) | |
170 "Executes an external window-based SHELL-CMD string asynchronously." | |
171 (interactive | |
172 (let ((default (car defaults))) | |
173 (list (hargs:read "Shell cmd: " | |
174 (function | |
175 (lambda (cmd) (not (string= cmd "")))) | |
176 default "Enter a shell command." 'string)))) | |
177 (let ((buf-name "*Hypb Shell*") | |
178 (cmd (if (hpath:ange-ftp-p default-directory) | |
179 (concat "(" shell-cmd ") &") | |
180 (concat "(cd " default-directory "; " shell-cmd ") &"))) | |
181 (msg (format "Executing: %s" shell-cmd)) | |
182 (shell-buf)) | |
183 (message msg) | |
184 (save-excursion | |
185 (save-window-excursion | |
186 (if (not (get-buffer buf-name)) | |
187 (progn (save-excursion | |
188 (save-window-excursion | |
189 (shell) | |
190 (setq shell-buf (current-buffer)))) | |
191 (message msg) | |
192 ;; Wait for shell to startup before sending it input. | |
193 (sit-for 1) | |
194 (set-buffer shell-buf) | |
195 (rename-buffer buf-name) | |
196 (setq last-input-start (point-marker) | |
197 last-input-end (point-marker)) | |
198 (if (fboundp 'comint-kill-output) | |
199 (setq comint-last-input-start last-input-start | |
200 comint-last-input-end last-input-end) | |
201 ))) | |
202 (or (equal (buffer-name (current-buffer)) buf-name) | |
203 (set-buffer buf-name)) | |
204 (goto-char (point-max)) | |
205 (insert cmd) | |
206 (shell-send-input))) | |
207 (message msg))) | |
208 | |
209 (defact hyp-config (&optional out-buf) | |
210 "Inserts Hyperbole configuration info at end of optional OUT-BUF or current." | |
211 (hypb:configuration out-buf)) | |
212 | |
213 (defact hyp-request (&optional out-buf) | |
214 "Inserts Hyperbole mail list request help into optional OUT-BUF or current." | |
215 (save-excursion | |
216 (and out-buf (set-buffer out-buf)) | |
217 (goto-char (point-max)) | |
218 (delete-blank-lines) (delete-blank-lines) | |
219 (insert "Use one of the following formats on your subject line:\n | |
220 Subject: Subscribe <joe@any.com> (Joe Williams). | |
221 Subject: Unsubscribe <joe@any.com>. | |
222 | |
223 To change your address, first unsubscribe by sending an unsubscribe | |
224 request from your old address. Then subscribe by sending a subscribe | |
225 request from your new address. | |
226 | |
227 Possible mail lists are: | |
228 hyperbole - discussion of Hyperbole | |
229 hyperbole-announce - Hyperbole announcements only\n"))) | |
230 | |
231 (defact hyp-source (buf-str-or-file) | |
232 "Displays a buffer or file from a line beginning with 'hbut:source-prefix'." | |
233 (interactive | |
234 (list (prin1-to-string (get-buffer-create | |
235 (read-buffer "Buffer to link to: "))))) | |
236 (if (stringp buf-str-or-file) | |
237 (cond ((string-match "\\`#<buffer \"?\\([^ \n\"]+\\)\"?>" buf-str-or-file) | |
238 (pop-to-buffer (substring buf-str-or-file | |
239 (match-beginning 1) (match-end 1)))) | |
240 (t (hpath:find-other-window buf-str-or-file))) | |
241 (hypb:error "(hyp-source): Non-string argument: %s" buf-str-or-file))) | |
242 | |
243 (defact link-to-buffer-tmp (buffer) | |
244 "Displays a BUFFER in another window. | |
245 Link is generally only good for current Emacs session. | |
246 Use 'link-to-file' instead for a permanent link." | |
247 (interactive "bBuffer to link to: ") | |
248 (if (or (stringp buffer) (bufferp buffer)) | |
249 (pop-to-buffer buffer) | |
250 (hypb:error "(link-to-buffer-tmp): Not a current buffer: %s" buffer))) | |
251 | |
252 (defact link-to-directory (directory) | |
253 "Displays a DIRECTORY in Dired mode in another window." | |
254 (interactive "DDirectory to link to: ") | |
255 (hpath:find-other-window directory)) | |
256 | |
257 (defact link-to-ebut (key-file key) | |
258 "Performs action given by another button, specified by KEY-FILE and KEY." | |
259 (interactive | |
260 (let (but-file but-lbl) | |
261 (while (cond ((setq but-file | |
262 (read-file-name | |
263 "File of button to link to: " nil nil t)) | |
264 (if (string= but-file "") | |
265 (progn (beep) t))) | |
266 ((not (file-readable-p but-file)) | |
267 (message "(link-to-ebut): You cannot read '%s'." | |
268 but-file) | |
269 (beep) (sit-for 3)))) | |
270 (list but-file | |
271 (progn | |
272 (find-file-noselect but-file) | |
273 (while (string= "" (setq but-lbl | |
274 (hargs:read-match | |
275 "Button to link to: " | |
276 (ebut:alist but-file) | |
277 nil nil nil 'ebut))) | |
278 (beep)) | |
279 (ebut:label-to-key but-lbl))))) | |
280 (or (interactive-p) | |
281 (setq key-file (hpath:validate (hpath:substitute-value key-file)))) | |
282 (let ((but (ebut:get key (find-file-noselect key-file)))) | |
283 (if but (hbut:act but) | |
284 (hypb:error "(link-to-ebut): No button '%s' in '%s'." (ebut:key-to-label key) | |
285 key-file)))) | |
286 | |
287 (defact link-to-elisp-doc (func-symbol) | |
288 "Displays documentation for FUNC-SYMBOL." | |
289 (interactive "aFunction to display doc for: ") | |
290 (cond ((not (symbolp func-symbol)) | |
291 (hypb:error "(link-to-elisp-doc): '%s' not a symbol." | |
292 func-symbol)) | |
293 ((not (fboundp func-symbol)) | |
294 (hypb:error "(link-to-elisp-doc): '%s' not defined as a function." | |
295 func-symbol)) | |
296 ((not (documentation func-symbol)) | |
297 (hypb:error "(link-to-elisp-doc): '%s' has no documentation." | |
298 func-symbol)) | |
299 ((describe-function func-symbol)))) | |
300 | |
301 (defact link-to-file (path &optional point) | |
302 "Displays a PATH in another window scrolled to optional POINT. | |
303 With POINT, buffer is displayed with POINT at the top of the window." | |
304 (interactive | |
305 (let ((prev-reading-p hargs:reading-p)) | |
306 (unwind-protect | |
307 (let* ((default (car defaults)) | |
308 (hargs:reading-p 'file) | |
309 (path (read-file-name "Path to link to: " default default)) | |
310 (path-buf (get-file-buffer path))) | |
311 (if path-buf | |
312 (save-excursion | |
313 (set-buffer path-buf) | |
314 (setq hargs:reading-p 'character) | |
315 (if (y-or-n-p | |
316 (format "y = Display at present position (line %d); n = no position: " | |
317 (count-lines 1 (point)))) | |
318 (list path (point)) | |
319 (list path))) | |
320 (list path))) | |
321 (setq hargs:reading-p prev-reading-p)))) | |
322 (and (hpath:find-other-window path) | |
323 (integerp point) | |
324 (progn (goto-char (min (point-max) point)) | |
325 (recenter 0)))) | |
326 | |
327 (defact link-to-file-line (path line-num) | |
328 "Displays a PATH in another window scrolled to LINE-NUM." | |
329 (interactive "fPath to link to: \nnDisplay at line number: ") | |
330 (and (setq path (smart-tags-file-path path)) | |
331 (hpath:find-other-window path) | |
332 (integerp line-num) | |
333 (progn (widen) | |
334 (goto-line line-num)))) | |
335 | |
336 (defact link-to-Info-node (node) | |
337 "Displays an Info NODE in another window. | |
338 NODE must be a string of the form `(file)nodename'." | |
339 (interactive "+IInfo (file)nodename to link to: ") | |
340 (require 'info) | |
341 (if (and (stringp node) (string-match "^(\\([^\)]+\\))\\(.*\\)" node)) | |
342 (let ((nodename (substring node (match-beginning 2) (match-end 2))) | |
343 (file (hpath:absolute-to | |
344 (substring node (match-beginning 1) (match-end 1)) | |
345 (if (boundp 'Info-directory-list) | |
346 Info-directory-list | |
347 Info-directory)))) | |
348 (if (and file (setq file (hpath:substitute-value file))) | |
349 (let ((wind (get-buffer-window "*info*"))) | |
350 (if wind (select-window wind) | |
351 (pop-to-buffer (other-buffer))) | |
352 (info) (Info-goto-node (concat "(" file ")" nodename))) | |
353 (hypb:error "(link-to-Info-node): Bad node spec: '%s'" node))))) | |
354 | |
355 (defact link-to-kcell (file cell-ref) | |
356 "Displays FILE with kcell given by CELL-REF at the top of the window. | |
357 See documentation for 'kcell:ref-to-id' for valid cell-ref formats. | |
358 | |
359 If FILE is nil, the current buffer is used. | |
360 If CELL-REF is nil, the first cell in the view is shown." | |
361 (interactive "fKotl file to link to: \n+KKcell to link to: ") | |
362 (require 'kfile) | |
363 (cond ((and (stringp cell-ref) (= ?| (aref cell-ref 0))) | |
364 ;; Activate view spec in current window. | |
365 (kotl-mode:goto-cell cell-ref)) | |
366 ((if file | |
367 (hpath:find-other-window file) | |
368 (pop-to-buffer (current-buffer) t)) | |
369 (if cell-ref | |
370 (kotl-mode:goto-cell cell-ref) | |
371 (kotl-mode:beginning-of-buffer)) | |
372 (recenter 0)))) | |
373 | |
374 (defact link-to-mail (mail-msg-id &optional mail-file) | |
375 "Displays mail msg with MAIL-MSG-ID from optional MAIL-FILE in other window. | |
376 See documentation for the variable 'hmail:init-function' for information on | |
377 how to specify a mail reader to use." | |
378 (interactive "+MMail Msg: ") | |
379 (if (not (fboundp 'rmail:msg-to-p)) | |
380 (hypb:error "(link-to-mail): Invoke mail reader before trying to follow a mail link.") | |
381 (if (and (listp mail-msg-id) (null mail-file)) | |
382 (setq mail-file (car (cdr mail-msg-id)) | |
383 mail-msg-id (car mail-msg-id))) | |
384 (let ((wind (selected-window)) | |
385 (wconfig (current-window-configuration))) | |
386 (other-window 1) | |
387 (if (eq wind (selected-window)) | |
388 (progn (split-window-vertically nil) (other-window 1))) | |
389 ;; Initialize user-specified mail reader if need be. | |
390 (if (and (symbolp hmail:init-function) | |
391 (fboundp hmail:init-function) | |
392 (listp (symbol-function hmail:init-function)) | |
393 (eq 'autoload (car (symbol-function hmail:init-function)))) | |
394 (funcall hmail:init-function)) | |
395 (if (rmail:msg-to-p mail-msg-id mail-file) | |
396 nil | |
397 ;; Couldn't find message, restore old window config, report error | |
398 (set-window-configuration wconfig) | |
399 (hypb:error "(link-to-mail): No msg '%s' in file \"%s\"." | |
400 mail-msg-id mail-file))))) | |
401 | |
402 (defact link-to-regexp-match (regexp n source &optional buffer-p) | |
403 "Finds REGEXP's Nth occurrence in SOURCE and displays location at window top. | |
404 SOURCE is a pathname unless optional BUFFER-P is non-nil, then SOURCE must be | |
405 a buffer name or buffer. | |
406 Returns t if found, signals an error if not." | |
407 (interactive "sRegexp to match: \nnOccurrence number: \nfFile to search: ") | |
408 (let ((orig-src source)) | |
409 (if buffer-p | |
410 (if (stringp source) | |
411 (setq source (get-buffer source))) | |
412 ;; Source is a pathname. | |
413 (if (not (stringp source)) | |
414 (hypb:error | |
415 "(link-to-regexp-match): Source parameter is not a filename: '%s'" | |
416 orig-src) | |
417 (setq source (find-file-noselect (hpath:substitute-value source))))) | |
418 (if (not (bufferp source)) | |
419 (hypb:error | |
420 "(link-to-regexp-match): Invalid source parameter: '%s'" orig-src) | |
421 (switch-to-buffer-other-window source) | |
422 (widen) | |
423 (goto-char (point-min)) | |
424 (if (re-search-forward regexp nil t n) | |
425 (progn (beginning-of-line) (recenter 0) t) | |
426 (hypb:error | |
427 "(link-to-regexp-match): Pattern not found: '%s'" regexp))))) | |
428 | |
429 (defact link-to-rfc (rfc-num) | |
430 "Retrieves and displays an Internet rfc given by RFC-NUM. | |
431 RFC-NUM may be a string or an integer. Requires ange-ftp or efs for | |
432 remote retrievals." | |
433 (interactive "nRFC number to retrieve: ") | |
434 (if (or (stringp rfc-num) (integerp rfc-num)) | |
435 (hpath:find-other-window (hpath:rfc rfc-num)))) | |
436 | |
437 (defact link-to-string-match (string n source &optional buffer-p) | |
438 "Finds STRING's Nth occurrence in SOURCE and displays location at window top. | |
439 SOURCE is a pathname unless optional BUFFER-P is non-nil, then SOURCE must be | |
440 a buffer name or buffer. | |
441 Returns t if found, nil if not." | |
442 (interactive "sString to match: \nnOccurrence number: \nfFile to search: ") | |
443 (funcall (actype:action 'link-to-regexp-match) | |
444 (regexp-quote string) n source buffer-p)) | |
445 | |
446 (defact man-show (topic) | |
447 "Displays man page on TOPIC, which may be of the form <command>(<section>)." | |
448 (interactive "sManual topic: ") | |
449 (manual-entry topic)) | |
450 | |
451 (defact rfc-toc (&optional buf-name opoint) | |
452 "Computes and displays summary of an Internet rfc in BUF-NAME. | |
453 Assumes point has already been moved to start of region to summarize. | |
454 Optional OPOINT is point to return to in BUF-NAME after displaying summary." | |
455 (interactive) | |
456 (if buf-name | |
457 (cond ((get-buffer buf-name) | |
458 (switch-to-buffer buf-name)) | |
459 ((let ((buf (get-file-buffer buf-name))) | |
460 (if buf | |
461 (progn (switch-to-buffer (setq buf-name buf)) | |
462 t)))) | |
463 (t (if opoint (goto-char opoint)) | |
464 (hypb:error "(rfc-toc): Invalid buffer name: %s" buf-name)))) | |
465 (let ((sect-regexp "^[ \t]*[1-9][0-9]*\\.[0-9.]*[ \t]+[^ \t\n]")) | |
466 (occur sect-regexp) | |
467 (set-buffer "*Occur*") | |
468 (rename-buffer (format "*%s toc*" buf-name)) | |
469 (re-search-forward "^[ ]*[0-9]+:" nil t) | |
470 (beginning-of-line) | |
471 (delete-region (point-min) (point)) | |
472 (insert "Contents of " (buffer-name occur-buffer) ":\n") | |
473 (set-buffer-modified-p nil) | |
474 (set-buffer buf-name) | |
475 (if opoint (goto-char opoint)))) | |
476 | |
477 (defact text-toc (section) | |
478 "Jumps to the text file SECTION referenced by a table of contents entry at point." | |
479 (interactive "sGo to section named: ") | |
480 (if (stringp section) | |
481 (progn | |
482 (actypes::link-to-regexp-match | |
483 (concat "^\\*+[ \t]*" (regexp-quote section)) | |
484 1 (current-buffer) t) | |
485 (while (and (= (forward-line -1) 0) | |
486 (looking-at "[ \t]*[-=][-=]"))) | |
487 (forward-line 1) | |
488 (recenter 0)))) | |
489 | |
490 (provide 'hactypes) |