Initial Commit
[packages] / xemacs-packages / hyperbole / hui-mouse.el
1 ;;; hui-mouse.el --- Use key or mouse key for many functions, e.g. Hypb menus.
2
3 ;; Copyright (C) 1989-1995, 2006, 2008 Free Software Foundation, Inc.
4 ;; Developed with support from Motorola Inc.
5
6 ;; Author: Bob Weiner, Brown U.
7 ;; Maintainer: Mats Lidell <matsl@contactor.se>
8 ;; Keywords: hypermedia, mouse
9
10 ;; This file is part of GNU Hyperbole.
11
12 ;; GNU Hyperbole is free software; you can redistribute it and/or
13 ;; modify it under the terms of the GNU General Public License as
14 ;; published by the Free Software Foundation; either version 3, or (at
15 ;; your option) any later version.
16
17 ;; GNU Hyperbole is distributed in the hope that it will be useful,
18 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
19 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20 ;; General Public License for more details.
21
22 ;; You should have received a copy of the GNU General Public License
23 ;; along with GNU Emacs; see the file COPYING.  If not, write to the
24 ;; Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
25 ;; Boston, MA 02110-1301, USA.
26
27 ;;; Commentary:
28 ;;
29 ;;  This code is machine independent.  It works best with a pointing device but
30 ;;  may also be used from a keyboard.  When used with a pointing device it
31 ;;  requires an Emacs command that sets point to the location of the pointing
32 ;;  device's cursor.
33 ;;
34 ;;  If you want to use your shift-middle mouse button to select Hyperbole menu
35 ;;  items and Hyperbole buttons, follow these instructions.
36 ;;
37 ;;  If you plan to use a mouse only with X windows (Lucid Emacs, GNU Emacs
38 ;;  19, or Epoch), NEXTSTEP, SunView, Apollo's DM, and you want to use the
39 ;;  shift-middle and shift-right buttons, you need not do any mouse
40 ;;  configuration.  Your Emacs executable must have been built so as to
41 ;;  include the mouse support files for your window system, however.  These
42 ;;  are in the Emacs "src" directory: for X "x*.c", for SunView "sunfns.c",
43 ;;  and for Apollo DM "apollo.c" and "apollo.el".
44 ;;
45 ;;  To use a different mouse key or a different window system, modify the
46 ;;  mouse key bindings in "hmouse-key.el".
47 ;;
48 ;; Using the Action Mouse Key to browse through and delete files from
49 ;; Dired listings is exceptionally nice, just as it is when reading mail.
50 ;;
51
52 ;;; Code:
53
54 ;;;
55 ;;; Public variables
56 ;;;
57
58 (defvar hmouse-set-point-command nil
59   "*Command that sets point to mouse cursor position.")
60
61 (defvar action-key-default-function 'hui:menu
62   "*Symbol name of function run by the Action Key in an unspecified context.")
63
64 (defvar assist-key-default-function 'hkey-summarize
65   "*Symbol name of function run by the Assist Key in an unspecified context.")
66
67 ;;;
68 ;;; Hyperbole context-sensitive keys dispatch table
69 ;;;
70
71 (defvar hkey-value nil
72   "Communicates a value between a Smart Key predicate and its actions.")
73
74 (defvar hkey-alist
75   '(
76     ;;
77     ;; If click in the minibuffer and reading an argument,
78     ;; accept argument or give completion help.
79     ((and (> (minibuffer-depth) 0)
80           (eq (selected-window) (minibuffer-window))
81           (not (eq hargs:reading-p 'hmenu))) .
82      ((exit-minibuffer) . (smart-completion-help)))
83     ;;
84     ;; If reading a Hyperbole menu item or a Hyperbole completion-based
85     ;; argument, allow selection of an item at point.
86     ((if (> (minibuffer-depth) 0) (setq hkey-value (hargs:at-p))) .
87      ((hargs:select-p hkey-value) .
88       (hargs:select-p hkey-value 'assist)))
89     ;;
90     ((if (not (eobp))
91           (or (eolp) (if selective-display
92                          (= (following-char) ?\^M)))) .
93      ((smart-scroll-up) . (smart-scroll-down)))
94     ;;
95     ((eq major-mode 'smart-menu-mode) . 
96      ((smart-menu-select) . (smart-menu-help)))
97     ;;
98     ;; If on a Hyperbole button, perform action or give help.
99     ((if (fboundp 'hbut:at-p) (or (hbut:at-p) (hbut:label-p))) .
100      ((hui:hbut-act 'hbut:current) . (hui:hbut-help 'hbut:current)))
101     ;;
102     ;; The Smart Menu system provides menus within Emacs running on a dumb
103     ;; terminal.  It is part of InfoDock and is not available separately.
104     ((and (fboundp 'smart-menu-choose-menu)
105           (setq hkey-value (and hkey-always-display-menu
106                                 (smart-menu-choose-menu)))
107           (not (and (get-buffer-window *smart-menu-buffer*)
108                     (eq hkey-value *smart-menu-curr*)))) .
109      ((smart-menu hkey-value) .
110       (smart-menu hkey-value)))
111     ;;
112     ;;
113     ;; View minor mode
114     ((if (boundp 'view-minor-mode) 
115          (and view-minor-mode (not (eq major-mode 'Manual-mode)))) .
116      ((cond ((last-line-p)
117              (view-quit))
118             ((pos-visible-in-window-p (point-max))
119              (goto-char (point-max)))
120             (t (scroll-up))) .
121       (scroll-down)))
122     ;;
123     ;; View major mode
124     ((eq major-mode 'view-mode) .
125      ((View-scroll-lines-forward) . (View-scroll-lines-backward)))
126     ;;
127     ((eq major-mode 'kotl-mode) . 
128      ((kotl-mode:action-key) . (kotl-mode:help-key)))
129     ;;
130     ;; Support direct selection and viewing on in-memory relational databases.
131     ;; Rdb-mode has not been publicly released.
132     ;; It is not included with Hyperbole.
133     ((eq major-mode 'rdb-mode) . ((smart-rdb) . (smart-rdb-assist)))
134     ;;
135     ;; Restore window config and hide help buffer when click at buffer end.
136     ((if (= (point) (point-max)) (string-match "Help\\(\\|:.*\\)\\*$" (buffer-name))) .
137      ((hkey-help-hide) . (hkey-help-hide)))
138     ;;
139     ;; Support the OO-Browser, a part of InfoDock, XEmacs, and soon to be a
140     ;; part of Emacs.
141     ((or (br-in-browser) (eq major-mode 'br-mode)) .
142      ((smart-br-dispatch) . (smart-br-assist-dispatch)))
143     ;;
144     ((and (memq major-mode '(c-mode c++-c-mode))
145           buffer-file-name (setq hkey-value (smart-c-at-tag-p))) .
146      ((smart-c) . (smart-c nil 'next-tag)))
147     ;;
148     ((and (eq major-mode 'asm-mode)
149           buffer-file-name (setq hkey-value (smart-asm-at-tag-p))) .
150      ((smart-asm) . (smart-asm nil 'next-tag)))
151     ;;
152     ((if (smart-lisp-mode-p) (smart-lisp-at-tag-p)) .
153      ((smart-lisp) . (smart-lisp 'next-tag)))
154     ;;
155     ((and (eq major-mode 'c++-mode) buffer-file-name
156           ;; Don't use smart-c++-at-tag-p here since it will prevent #include
157           ;; lines from matching.
158           (setq hkey-value (smart-c-at-tag-p))) .
159      ( ;; Only fboundp if OO-Browser has been loaded.
160       (if (fboundp 'c++-to-definition)
161           (smart-c++-oobr) (smart-c++)) .
162       (if (fboundp 'c++-to-definition)
163           (smart-c++-oobr)
164         (smart-c++ nil 'next-tag))))
165     ;;
166     ((and (eq major-mode 'objc-mode) buffer-file-name
167           (setq hkey-value (smart-objc-at-tag-p))) .
168      ( ;; Only fboundp if OO-Browser has been loaded.
169       (if (fboundp 'objc-to-definition)
170           (smart-objc-oobr) (smart-objc)) .
171       (if (fboundp 'objc-to-definition)
172           (smart-objc-oobr)
173         (smart-objc nil 'next-tag))))
174     ;;
175     ((and (eq major-mode 'fortran-mode)
176           buffer-file-name (setq hkey-value (smart-fortran-at-tag-p))) .
177      ((smart-fortran) . (smart-fortran nil 'next-tag)))
178     ;;
179     ((eq major-mode 'occur-mode) .
180      ((occur-mode-goto-occurrence) . (occur-mode-goto-occurrence)))
181     ;;
182     ((eq major-mode 'moccur-mode) .
183      ((moccur-mode-goto-occurrence) . (moccur-mode-goto-occurrence)))
184     ;;
185     ((eq major-mode 'calendar-mode) .
186      ((smart-calendar) . (smart-calendar-assist)))
187     ;;
188     ((eq major-mode 'unix-apropos-mode) .
189      ((smart-apropos) . (smart-apropos-assist)))
190     ;;
191     ((eq major-mode 'outline-mode) .
192      ((smart-outline) . (smart-outline-assist)))
193     ;;
194     ((eq major-mode 'Info-mode) .
195      ((smart-info) .  (smart-info-assist)))
196     ;;
197     ((if (boundp 'hmail:reader)
198          (or (eq major-mode hmail:reader)
199              (eq major-mode hmail:lister))) .
200      ((smart-hmail) . (smart-hmail-assist)))
201     ;;
202     ((eq major-mode 'gnus-group-mode)
203      (smart-gnus-group) . (smart-gnus-group-assist))
204     ;;
205     ((eq major-mode 'gnus-summary-mode)
206      (smart-gnus-summary) . (smart-gnus-summary-assist))
207     ;;
208     ((eq major-mode 'gnus-article-mode)
209      (smart-gnus-article) . (smart-gnus-article-assist))
210     ;;
211     ((eq major-mode 'Buffer-menu-mode) .
212      ((smart-buffer-menu) . (smart-buffer-menu-assist)))
213     ;;
214     ((eq major-mode 'ibuffer-mode) .
215      ((smart-ibuffer-menu) . (smart-ibuffer-menu-assist)))
216     ;;
217     ((eq major-mode 'dired-mode) . 
218      ((smart-dired) . (smart-dired-assist)))
219     ;;
220     ((eq major-mode 'tar-mode) . 
221      ((smart-tar) . (smart-tar-assist)))
222     ;;
223     ;; Follow references in man pages.
224     ((setq hkey-value (smart-man-entry-ref)) .
225      ((smart-man-display hkey-value) .
226       (smart-man-display hkey-value)))
227     ;;
228     ((eq major-mode 'w3-mode) . 
229      ((w3-follow-link) . (w3-goto-last-buffer)))
230     ;;
231     ((if (boundp 'rolo-display-buffer)
232          (equal (buffer-name) rolo-display-buffer)) .
233      ((smart-wrolo) . (smart-wrolo-assist)))
234     ;;
235     ;; Gomoku game
236     ((eq major-mode 'gomoku-mode) . 
237      ((gomoku-human-plays) . (gomoku-human-takes-back)))
238     ;;
239     ;: Change log mode
240     ((eq major-mode 'change-log-mode) .
241      ((smart-change-log) . (smart-change-log)))
242     ;;
243     ;; Bookmark mode
244     ((eq major-mode 'bookmark-bmenu-mode) .
245      ((smart-bookmark-menu) . (smart-bookmark-menu-assist)))
246     ;;
247     ;; Outline minor mode is on and usable.
248     (selective-display .
249      ((smart-outline) . (smart-outline-assist)))
250     )
251   "Alist of predicates and form-conses for Action and Assist Keys.
252 When the Action or Assist Key is pressed, the first or second form,
253 respectively, associated with the first non-nil predicate is evaluated.")
254
255 ;;;
256 ;;; driver code
257 ;;;
258
259 ;; The following autoload is needed if another subsystem besides
260 ;; Hyperbole uses this mouse handling code.
261 (autoload 'var:append "hvar" "Append to a list variable." nil)
262
263 (require 'hargs)
264 (require 'hmouse-key)
265 (if hyperb:window-system
266     (progn
267       (defvar hmouse-alist hkey-alist
268         "Alist of predicates and form-conses for context-sensitive smart key mouse actions.
269 When the action-key or the assist-key is pressed, the first or
270 second form, respectively, associated with the first non-nil predicate is
271 evaluated.")
272       (load "hui-window")))
273
274 ;;;
275 ;;; support code
276 ;;;
277
278 ;; The 'load' line below loads any local Smart Key function definitions.
279 ;; The public distribution contains none.  You may leave it commented out if
280 ;; you prefer.
281 ;; (load "smart-local" t)
282
283 ;;;
284 ;;; Required Init functions
285 ;;;
286
287 (defun first-line-p ()
288   "Returns true if point is on the first line of the buffer."
289   (save-excursion (beginning-of-line) (bobp)))
290
291 (defun last-line-p ()
292   "Returns true if point is on the last line of the buffer."
293   (save-excursion (end-of-line) (eobp)))
294
295 (defun smart-completion-help ()
296   "Offer completion help for current minibuffer argument, if any."
297   (if (where-is-internal 'minibuffer-completion-help (current-local-map))
298       (minibuffer-completion-help)))
299
300 (defun smart-symlink-expand (path)
301   "Returns referent for possible symbolic link, PATH."
302   (if (not (fboundp 'symlink-referent))
303       path
304     (let ((start 0) (len (length path)) (ref) (part))
305       (while (and (< start len) (setq part (string-match "/[^/]*" path start)))
306         (setq part (concat ref
307                            (substring path start (setq start (match-end 0))))
308               ref (symlink-referent part)))
309       ref)))
310
311 ;;;
312 ;;; smart-buffer-menu functions
313 ;;;
314
315 (defun smart-buffer-menu (&optional in-browser)
316   "Uses a single key or mouse key to manipulate buffer-menu entries.
317
318 Invoked via a key press when in Buffer-menu-mode.  It assumes that its
319 caller has already checked that the key was pressed in an appropriate buffer
320 and has moved the cursor there.
321
322 Optional non-nil IN-BROWSER indicates use within the OO-Browser.
323
324 If key is pressed:
325  (1) on the first column of an entry, the selected buffer is marked for
326      display; 
327  (2) on the second column of an entry, the selected buffer is marked to be
328      saved;
329  (3) anywhere else within an entry line, all saves and deletes are done, and
330      selected buffers are displayed, including the one just clicked on (if
331      IN-BROWSER, only the selected buffer is displayed);
332  (4) on or after the last line in the buffer, all saves and deletes are done."
333
334   (interactive)
335   (cond ((last-line-p) (Buffer-menu-execute))
336         ((bolp) (Buffer-menu-mark))
337         ((save-excursion
338              (goto-char (1- (point)))
339              (bolp))
340          (Buffer-menu-save))
341         (in-browser (br-buffer-menu-select))
342         (t (Buffer-menu-select))))
343
344 (defun smart-buffer-menu-assist ()
345   "Uses a single assist-key or mouse assist-key to manipulate buffer-menu entries.
346
347 Invoked via an assist-key press when in Buffer-menu-mode.  It assumes that its
348 caller has already checked that the assist-key was pressed in an appropriate
349 buffer and has moved the cursor there.
350
351 If assist-key is pressed:
352  (1) on the first or second column of an entry, the selected buffer is unmarked
353      for display and for saving or deletion; 
354  (2) anywhere else within an entry line, the selected buffer is marked for
355      deletion;
356  (3) on or after the last line in the buffer, all display, save, and delete
357      marks on all entries are undone."
358
359   (interactive)
360   (cond ((last-line-p) (progn (list-buffers) (forward-line 3)))
361         ((bolp) (Buffer-menu-unmark))
362         ((save-excursion
363              (goto-char (1- (point)))
364              (bolp))
365          (Buffer-menu-unmark))
366         (t (Buffer-menu-delete))))
367
368 ;;;
369 ;;; smart-ibuffer-menu functions
370 ;;;
371
372 (defun smart-ibuffer-menu (&optional in-browser)
373   "Uses a single key or mouse key to manipulate ibuffer entries.
374
375 Invoked via a key press when in ibuffer-mode.  It assumes that its
376 caller has already checked that the key was pressed in an appropriate buffer
377 and has moved the cursor there.
378
379 Optional non-nil IN-BROWSER indicates use within the OO-Browser.
380
381 If key is pressed:
382  (1) on the first or second column of an entry, the selected buffer is
383      marked for display;
384  (3) anywhere else within an entry line, all selected buffers are
385      displayed, including the one just clicked on (if IN-BROWSER, only
386      the selected buffer is displayed);
387  (4) on or after the last line in the buffer, all deletes are done."
388
389   (interactive)
390   (cond ((last-line-p) (progn (ibuffer-do-kill-on-deletion-marks)))
391         ((first-line-p) (progn (ibuffer-filter-disable)))
392         ((bolp) (ibuffer-mark-forward 1))
393         ((save-excursion
394              (goto-char (1- (point)))
395              (bolp))
396          (ibuffer-mark-forward 1))
397         (in-browser (br-buffer-menu-select))  
398         (t (ibuffer-do-view))))
399
400 (defun smart-ibuffer-menu-assist ()
401   "Uses a single assist-key or mouse assist-key to manipulate buffer-menu entries.
402
403 Invoked via an assist-key press when in ibuffer-mode.  It assumes that
404 its caller has already checked that the assist-key was pressed in an
405 appropriate buffer and has moved the cursor there.
406
407 If assist-key is pressed:
408  (1) on the first or second column of an entry, the selected buffer is unmarked
409      for display or deletion; 
410  (2) anywhere else within an entry line, the selected buffer is marked for
411      deletion;
412  (3) on or after the last line in the buffer, all display, save, and delete
413      marks on all entries are undone."
414
415   (interactive)
416   (cond ((last-line-p) (ibuffer-unmark-all 0))
417         ((bolp) (ibuffer-unmark-forward 1))
418         ((save-excursion
419              (goto-char (1- (point)))
420              (bolp))
421          (ibuffer-unmark-forward 1))
422         (t (ibuffer-mark-for-delete 1))))
423
424 ;;;
425 ;;; smart-calendar functions
426 ;;;
427
428 (defun smart-calendar ()
429   "Uses a single key or mouse key to manipulate the scrolling calendar.
430
431 Invoked via a key press when in calendar-mode.  It assumes that its
432 caller has already checked that the key was pressed in an appropriate buffer
433 and has moved the cursor there.
434
435 If key is pressed:
436  (1) at the end of the buffer, the calendar is scrolled forward 3 months;
437  (2) to the left of any dates on a calendar line, the calendar is scrolled
438      backward 3 months;
439  (3) on a date, the diary entries for the date, if any, are displayed."
440
441   (interactive)
442   (cond ((eobp) (calendar-cursor-to-nearest-date)
443          (scroll-calendar-left-three-months 1))
444         ((< (current-column) 5) (calendar-cursor-to-nearest-date)
445          (scroll-calendar-right-three-months 1))
446         (t (calendar-cursor-to-nearest-date)
447            (view-diary-entries 1))))
448
449 (defun smart-calendar-assist ()
450   "Uses a single assist-key or mouse assist-key to manipulate the scrolling calendar.
451
452 Invoked via an assist-key press when in calendar-mode.  It assumes that its
453 caller has already checked that the assist-key was pressed in an appropriate
454 buffer and has moved the cursor there.
455
456 If assist-key is pressed:
457  (1) at the end of the buffer, the calendar is scrolled backward 3 months;
458  (2) to the left of any dates on a calendar line, the calendar is scrolled
459      forward 3 months;
460  (3) anywhere else, all dates with marking diary entries are marked in the
461      calendar window."
462
463   (interactive)
464   (cond ((eobp) (calendar-cursor-to-nearest-date)
465          (scroll-calendar-right-three-months 1))
466         ((< (current-column) 5) (calendar-cursor-to-nearest-date)
467          (scroll-calendar-left-three-months 1))
468         (t (mark-diary-entries))))
469
470
471 ;;;
472 ;;; smart-dired functions
473 ;;;
474
475 (defun smart-dired ()
476   "Uses a single key or mouse key to manipulate directory entries.
477
478 Invoked via a key press when in dired-mode.  It assumes that its
479 caller has already checked that the key was pressed in an appropriate buffer
480 and has moved the cursor there.
481
482 If key is pressed:
483  (1) within an entry line, the selected file/directory is displayed for
484      editing in the other window;
485  (2) on or after the last line in the buffer, if any deletes are to be
486      performed, they are executed after user verification, otherwise, this
487      dired invocation is quit."
488
489   (interactive)
490   (cond ((last-line-p)
491          (let (flagged)
492            (save-excursion
493              (goto-char 1)
494              (setq flagged (re-search-forward "^D" nil t)))
495            (if flagged
496                (cond ((fboundp 'dired-do-deletions)
497                       (dired-do-deletions))
498                      ;; For Tree-dired compatibility
499                      ((fboundp 'dired-do-flagged-delete)
500                       (dired-do-flagged-delete))
501                      (t (error "(smart-dired): No Dired expunge function.")))
502              (quit-window))))
503         (t (hpath:find-other-window (dired-get-filename)))))
504
505 (defun smart-dired-assist ()
506   "Uses a single assist-key or mouse assist-key to manipulate directory entries.
507
508 Invoked via an assist-key press when in dired-mode.  It assumes that its
509 caller has already checked that the assist-key was pressed in an appropriate
510 buffer and has moved the cursor there.
511
512 If assist-key is pressed:
513  (1) on a '~' character, all backup files in the directory are marked for
514      deletion;
515  (2) on a '#' character, all auto-save files in the directory are marked for
516      deletion;
517  (3) anywhere else within an entry line, the current entry is marked for
518      deletion;
519  (4) on or after the last line in the buffer, all delete marks on all entries
520      are undone."
521
522   (interactive)
523   (cond ((last-line-p)
524          (dired-unmark-all-files dired-del-marker))
525         ((looking-at "~") (dired-flag-backup-files))
526         ((looking-at "#") (dired-flag-auto-save-files))
527         (t (if (fboundp 'dired-flag-file-deleted) (dired-flag-file-deleted 1) (dired-flag-file-deletion 1)))))
528
529 ;;;
530 ;;; smart-gnus functions
531 ;;;
532
533 (defun smart-gnus-group ()
534   "Uses a key or mouse key to move through Gnus Newsgroup listings.
535 Invoked via a key press when in gnus-group-mode.  It assumes that its caller
536 has already checked that the key was pressed in an appropriate buffer and has
537 moved the cursor to the selected buffer.
538
539 If key is pressed within:
540  (1) a GNUS-GROUP line, that newsgroup is read. If gnus-topic-mode is
541      active topics are expanded and collapsed as well on a key press;
542  (2) to the left of any GNUS-GROUP line, on any of the whitespace, the current
543      group is unsubscribed or resubscribed;
544  (3) at the end of the GNUS-GROUP buffer, after all lines, checks for new
545      news."
546
547   (interactive)
548   (cond ((last-line-p) (gnus-group-get-new-news))
549         ((progn (skip-chars-backward " U") (bolp))
550          (gnus-group-unsubscribe-current-group))
551         ((gnus-topic-mode-p) (gnus-topic-read-group))
552         (t (gnus-group-read-group))))
553
554 (defun smart-gnus-group-assist ()
555   "Uses an assist-key or assist-mouse key to move through Gnus Newsgroup listings.
556 Invoked via an assist-key press when in gnus-group-mode.  It assumes that its
557 caller has already checked that the key was pressed in an appropriate buffer
558 and has moved the cursor to the selected buffer.
559
560 If key is pressed within:
561  (1) a GNUS-GROUP line, that newsgroup is read;
562  (2) to the left of any GNUS-GROUP line, on any of the whitespace, the user is
563      prompted for a group name to subscribe or unsubscribe to;
564  (3) at the end of the GNUS-GROUP buffer, after all lines, quits from the
565      newsreader."
566
567   (interactive)
568   (cond ((last-line-p) (gnus-group-exit))
569         ((progn (skip-chars-backward " U") (bolp))
570          (call-interactively 'gnus-group-unsubscribe-group))
571         (t (gnus-group-read-group nil))))
572
573 (defun smart-gnus-summary ()
574   "Uses a key or mouse key to move through Gnus News article listings.
575 Invoked via a key press when in gnus-summary-mode.  It assumes that its caller
576 has already checked that the key was pressed in an appropriate buffer and has
577 moved the cursor to the selected buffer.
578
579 If key is pressed within:
580  (1) to the left of an article number, that article is marked as unread;
581  (2) a GNUS-SUMMARY line, that article is read, marked deleted, and scrolled
582      forward;
583  (3) at the end of the GNUS-SUMMARY buffer, the next undeleted article
584      is read or the next group is entered."
585
586   (interactive)
587   (cond ((last-line-p)
588          (if gnus-current-article
589              (progn (goto-char (point-min))
590                     (re-search-forward
591                       (format "^.[ ]+%d:" gnus-current-article) nil t)
592                     (setq this-command 'gnus-summary-next-page)
593                     (call-interactively 'gnus-summary-next-page))
594            (goto-char (point-min))
595            (setq this-command 'gnus-summary-first-unread-article)
596            (call-interactively 'gnus-summary-first-unread-article)))
597         ((save-excursion (skip-chars-backward " D") (bolp))
598          (gnus-summary-mark-as-unread-forward 1))
599         (t (setq this-command 'gnus-summary-next-page)
600            (call-interactively 'gnus-summary-next-page))))
601
602 (defun smart-gnus-summary-assist ()
603   "Uses an assist-key or assist-mouse key to move through Gnus News articles.
604 Invoked via an assist-key press when in gnus-summary-mode.  It assumes that its
605 caller has already checked that the key was pressed in an appropriate buffer
606 and has moved the cursor to the selected buffer.
607
608 If key is pressed within:
609  (1) to the left of an article number, that article is marked as unread;
610  (2) a GNUS-SUMMARY line, that article is read and scrolled backward;
611  (3) at the end of the GNUS-SUMMARY buffer, the summary is exited, the user
612      is returned to group mode."
613
614   (interactive)
615   (cond ((last-line-p)
616          (setq this-command 'gnus-summary-prev-page)
617          (call-interactively 'gnus-summary-exit))
618         ((save-excursion (skip-chars-backward " D") (bolp))
619          (gnus-summary-mark-as-unread-backward 1))
620         (t (setq this-command 'gnus-summary-prev-page)
621            (call-interactively 'gnus-summary-prev-page))))
622
623 (defun smart-gnus-article ()
624   "Uses a key or mouse key to move through Gnus netnews articles.
625
626 Invoked via a key press when in gnus-article-mode.
627 It assumes that its caller has already checked that the key was pressed in an
628 appropriate buffer and has moved the cursor to the selected buffer.
629
630 If key is pressed within:
631  (1) the first line or end of an article, the next unread message is displayed;
632  (2) the first line of an Info cross reference, the reference is followed;
633  (3) anywhere else, the window is scrolled up a windowful."
634   (interactive)
635   (cond ((or (last-line-p) (and (not (eolp)) (first-line-p)))
636          (unwind-protect
637              (progn (set-buffer gnus-summary-buffer)
638                     (setq this-command 'gnus-summary-next-unread-article)
639                     (gnus-summary-next-unread-article)
640                     (gnus-summary-goto-subject gnus-current-article)
641                     )
642            (let ((artic (get-buffer-window gnus-article-buffer)))
643              (if artic (select-window artic)))))
644         ((and (not (eolp)) (Info-handle-in-note)))
645         ((gnus-article-press-button))
646         (t (smart-scroll-up))))
647
648 (defun smart-gnus-article-assist ()
649   "Uses an assist-key or mouse assist-key to move through Gnus netnews articles.
650
651 Invoked via an assist-key press when ing nus-article-mode.
652 It assumes that its caller has already checked that the assist-key was pressed in
653 an appropriate buffer and has moved the cursor to the selected buffer.
654
655 If assist-key is pressed within:
656  (1) the first line or end of an article, the previous message is displayed;
657  (2) the first line of an Info cross reference, the reference is followed;
658  (3) anywhere else, the window is scrolled down a windowful."
659   (interactive)
660   (cond ((or (last-line-p) (and (not (eolp)) (first-line-p)))
661          (unwind-protect
662              (progn (set-buffer gnus-summary-buffer)
663                     (setq this-command 'gnus-summary-prev-article)
664                     (gnus-summary-prev-article nil)
665                     (gnus-summary-goto-subject gnus-current-article)
666                     )
667            (let ((artic (get-buffer-window gnus-summary-buffer)))
668              (if artic (select-window artic)))))
669         ((and (not (eolp)) (Info-handle-in-note)))
670         (t (smart-scroll-down))))
671
672 ;;;
673 ;;; smart-hmail functions
674 ;;;
675
676 (defun smart-hmail ()
677   "Uses a key or mouse key to move through e-mail messages and summaries.
678
679 Invoked via a key press when in hmail:reader or hmail:lister mode.
680 It assumes that its caller has already checked that the key was pressed in an
681 appropriate buffer and has moved the cursor to the selected buffer.
682
683 If key is pressed within:
684  (1) a msg buffer, within the first line or at the end of a message,
685      the next undeleted message is displayed;
686  (2) a msg buffer within the first line of an Info cross reference, the
687      reference is followed;
688  (3) anywhere else in a msg buffer, the window is scrolled up a windowful; 
689  (4) a msg summary buffer on a header entry, the message corresponding to
690      the header is displayed in the msg window;
691  (5) a msg summary buffer, on or after the last line, the messages marked
692      for deletion are expunged."
693
694   (interactive)
695   ;;
696   ;; Branch on buffer type
697   ;;
698   (cond ((eq major-mode hmail:reader)
699          (cond ((or (last-line-p) (and (not (eolp)) (first-line-p)))
700                 (rmail:msg-next))
701                ((and (not (eolp)) (Info-handle-in-note)))
702                ((smart-scroll-up))))
703         ;;
704         ;; Assume are in msg summary buffer
705         ;;
706         ((last-line-p) (lmail:expunge))
707         (t (lmail:goto))))
708
709 (defun smart-hmail-assist ()
710   "Uses an assist key or mouse key to move through e-mail messages and summaries.
711
712 Invoked via an assist key press when in hmail:reader or hmail:lister mode.
713 It assumes that its caller has already checked that the assist-key was pressed in
714 an appropriate buffer and has moved the cursor to the selected buffer.
715
716 If assist-key is pressed within:
717  (1) a msg buffer, within the first line or at the end of a message,
718      the previous undeleted message is displayed;
719  (2) a msg buffer within the first line of an Info cross reference, the
720      reference is followed;
721  (3) anywhere else in a msg buffer, the window is scrolled down a windowful; 
722  (4) a msg summary buffer on a header entry, the message corresponding to
723      the header is marked as deleted;
724  (5) a msg summary buffer, on or after the last line, all messages are
725      marked undeleted."
726
727   (interactive)
728   ;;
729   ;; Branch on buffer type
730   ;;
731   (cond ((eq major-mode hmail:reader)
732          (cond ((or (last-line-p) (and (not (eolp)) (first-line-p)))
733                 (rmail:msg-prev))
734                ((and (not (eolp)) (Info-handle-in-note)))
735                ((smart-scroll-down))))
736         ;;
737         ;; Assume are in msg summary buffer
738         ;;
739         ((last-line-p) (lmail:undelete-all))
740         (t (lmail:delete))))
741
742
743 ;;;
744 ;;; smart-info functions
745 ;;;
746 ;;; Autoloaded in "hyperbole.el".
747
748 ;;;
749 ;;; smart-man functions
750 ;;;
751
752 ;; "unix-apropos.el" is a publicly available Emacs Lisp package that
753 ;; allows man page browsing from apropos listings.  "superman.el" is a
754 ;; newer, much more complete package that you would probably prefer at
755 ;; this point, but there is no Smart Key apropos support for it.  There
756 ;; is smart key support within the man page buffers it produces, however.
757 ;;
758
759 (defun smart-apropos ()
760   "Moves through UNIX man apropos listings by using one key or mouse key.
761
762 Invoked via a key press when in unix-apropos-mode.  It assumes that
763 its caller has already checked that the key was pressed in an appropriate
764 buffer and has moved the cursor to the selected buffer.
765
766 If key is pressed:
767  (1) on a UNIX man apropos entry, the man page for that entry is displayed in
768      another window;
769  (2) on or after the last line, the buffer in the other window is scrolled up
770      a windowful."
771
772   (interactive)
773   (if (last-line-p)
774       (scroll-other-window)
775     (unix-apropos-get-man)))
776
777 (defun smart-apropos-assist ()
778   "Moves through UNIX man apropos listings by using one assist-key or mouse assist-key.
779
780 Invoked via an assist-key press when in unix-apropos-mode.  It assumes that
781 its caller has already checked that the assist-key was pressed in an appropriate
782 buffer and has moved the cursor to the selected buffer.
783
784 If assist-key is pressed:
785  (1) on a UNIX man apropos entry, the man page for that entry is displayed in
786      another window;
787  (2) on or after the last line, the buffer in the other window is scrolled down
788      a windowful."
789
790   (interactive)
791   (if (last-line-p)
792       (scroll-other-window (- 3 (window-height)))
793     (unix-apropos-get-man)))
794
795 (defun smart-man-display (lisp-form)
796   "Evaluates LISP-FORM returned from 'smart-man-entry-ref' to display a man page."
797   (eval lisp-form))
798
799 (defun smart-man-follow-xref ()
800   "Get `manual-entry' from the cross-reference under the mouse."
801   (let* ((p (point))
802          (extent (and p (extent-at p (current-buffer) 'highlight)))
803          (data (and extent (extent-property extent 'man))))
804     (if (eq (car-safe data) 'Manual-follow-xref)
805         data)))
806
807 (defun smart-man-entry-ref ()
808   "Returns form which displays referenced manual entry that point is on or nil.
809 Handles references in sections: NAME, SEE ALSO, or PACKAGES USED.  Also can
810 display C routine definitions selected in a man page, see
811 'smart-man-c-routine-ref'.
812
813 Man page buffer must either have an attached file or else a `man-path'
814 local variable containing its pathname."
815   (interactive)
816   (let ((ref ""))
817     (if (not (or (if (string-match "Manual Entry\\|\\*man \\|Man: "
818                                    (buffer-name (current-buffer)))
819                      (progn (and (boundp 'man-path) man-path
820                                  (setq ref (smart-symlink-expand man-path)))
821                             t))
822                  (if buffer-file-name
823                      (string-match "/man/" (setq ref (smart-symlink-expand
824                                                       buffer-file-name))))))
825         (setq ref nil)
826       (or (setq ref (or (smart-man-file-ref)
827                         (smart-man-c-routine-ref)))
828           (save-excursion
829             (let ((opoint (point))
830                   (case-fold-search))
831               (and
832                (re-search-backward "^[.A-Z]" nil t)
833                (looking-at
834                 "\\(\\.SH[ \t]+\\)?\\(SEE ALSO\\|NAME\\|PACKAGES USED\\)")
835                (progn (goto-char opoint)
836                       (skip-chars-backward "-_a-zA-Z0-9?.(")
837                       (let ((start (point)))
838                         (skip-chars-forward "-_a-zA-Z0-9?.()")
839                         (setq ref (buffer-substring start (point)))
840                         ;; Leave only one char within ref parens
841                         (if ref
842                             (if (string-match "(\\(.\\)\\(.+\\))" ref)
843                                 (setq ref (concat (substring ref 0 (match-end 1))
844                                                   "\)"))))
845                         )))))))
846     (cond ((and hyperb:xemacs-p (setq xref (smart-man-follow-xref))) xref)
847           ((equal ref "") nil)
848           ((stringp ref) (list 'manual-entry ref))
849           (t ref))))
850
851 (defun smart-man-c-routine-ref ()
852   "Returns form to jump to def of C function whose name is at point, if any.
853 Valid sections within the man page are: ROUTINES, MACROS or FUNCTIONS.
854 Uses (smart-tags-file) function to determine etags file from which to
855 locate the definition.
856
857 Returns etags file name if point is on an identifier in the appropriate
858 section and the jump is done, otherwise, returns nil."
859   (let ((ref)
860         (opoint (point))
861         (case-fold-search))
862     (save-excursion
863       (and (re-search-backward "^[.A-Z]" nil t)
864            (looking-at "^\\(FUNCTIONS\\|ROUTINES\\|MACROS\\)[ \t\n]")
865            (progn (goto-char opoint)
866                   (skip-chars-backward "_~<>:a-zA-Z0-9(")
867                   (if (or (looking-at "\\([_~<>:a-zA-Z0-9]+\\)[ \t\n]*(")
868                           (looking-at "\\([_~<:A-Z][_<>:A-Z0-9]+\\)"))
869                       (setq ref (buffer-substring
870                                  (match-beginning 1) (match-end 1))
871                             )))))
872     (if ref
873         (let ((tags-file-name
874                (smart-tags-file (if (and (boundp 'man-path) man-path)
875                                     man-path
876                                   default-directory))))
877           (and (file-exists-p tags-file-name)
878                (file-readable-p tags-file-name)
879                (list 'let (list (list 'tags-file-name tags-file-name))
880                      (list (if (br-in-browser)
881                                'find-tag 'find-tag-other-window)
882                            ref)))))))
883
884 (defun smart-man-file-ref ()
885   "Returns form to eval to display file whose name point is on, within a FILES man page section.
886 If not on a file name, returns nil."
887   (let ((ref)
888         (opoint (point))
889         (case-fold-search))
890     (save-excursion
891       (and (re-search-backward "^[.A-Z]" nil t)
892            (looking-at "^FILES[ \t\n]")
893              (progn (goto-char opoint)
894                     (skip-chars-backward "^ \t")
895                     (if (looking-at "/[^ \t\n]+")
896                         (setq ref (buffer-substring
897                                    (match-beginning 0) (match-end 0))
898                               )))))
899     (if ref
900         (list (if (br-in-browser)
901                   'find-file 'find-file-other-window)
902               ref))))
903
904 ;;;
905 ;;; smart-outline functions
906 ;;;
907
908 ;; The functions in this section require InfoDock's version of outline.el
909 ;; in order to work properly.
910
911 (defvar smart-outline-cut nil
912   "Non-nil means outline region was cut and is ready to be pasted at point.")
913
914 (let ((proc
915         '((lambda ()
916             (make-local-variable 'smart-outline-cut)
917             ;; Non-nil means outline region was cut and is available to be
918             ;; pasted at point.
919             (setq smart-outline-cut nil)
920             ))))
921   (if (boundp 'outline-mode-map)
922       (eval proc)
923     (var:append 'outline-mode-hook proc)))
924
925 (defun smart-outline ()
926   "Collapses, expands, and moves outline entries.
927 Invoked via a key press when in outline-mode.  It assumes that
928 its caller has already checked that the key was pressed in an appropriate
929 buffer and has moved the cursor to the selected buffer.
930
931 If key is pressed:
932  (1) after an outline heading has been cut via the Action Key, then paste the
933      cut heading at point;
934  (2) at the end of buffer, show all buffer text 
935  (3) at the beginning of a heading line, cut the headings subtree from the
936      buffer;
937  (4) on a header line but not at the beginning or end, if headings subtree is
938      hidden then show it, otherwise hide it;
939  (5) anywhere else, scroll up a windowful."
940
941   (interactive)
942   (cond (smart-outline-cut
943          (setq smart-outline-cut nil) (yank))
944         ((eobp) (show-all))
945         ((and (bolp) (looking-at outline-regexp))
946          (setq smart-outline-cut t)
947          (kill-region
948           (point)
949           (or (outline-get-next-sibling)
950               ;; Skip past start of current entry
951               (progn (re-search-forward outline-regexp nil t)
952                      (smart-outline-to-entry-end t (outline-level))))))
953
954         ((or (eolp) (zerop (save-excursion (beginning-of-line)
955                                            (outline-level))))
956          (smart-scroll-up))
957         ;; On an outline header line but not at the start/end of line.
958         ((smart-outline-subtree-hidden-p)
959          (show-subtree))
960         (t (hide-subtree))))
961
962
963 (defun smart-outline-assist ()
964   "Collapses, expands, and moves outline entries.
965 Invoked via an assist-key press when in outline-mode.  It assumes that
966 its caller has already checked that the assist-key was pressed in an appropriate
967 buffer and has moved the cursor to the selected buffer.
968
969 If assist-key is pressed:
970  (1) after an outline heading has been cut via the action-key, allow multiple
971      pastes throughout the buffer (last paste should be done with the Action Key,
972      not the Assist Key);
973  (2) at the end of buffer, hide all bodies in buffer;
974  (3) at the beginning of a heading line, cut the current heading (sans
975      subtree) from the buffer;
976  (4) on a header line but not at the beginning or end, if heading body is
977      hidden then show it, otherwise hide it;
978  (5) anywhere else, scroll down a windowful."
979
980   (interactive)
981   (cond (smart-outline-cut (yank))
982         ((eobp) (hide-body ))
983         ((and (bolp) (looking-at outline-regexp))
984          (setq smart-outline-cut t)
985          (kill-region (point) 
986                       ;; Skip past start of current entry
987                       (progn (re-search-forward outline-regexp nil t)
988                              (smart-outline-to-entry-end
989                               nil (outline-level)))))
990         ((or (eolp) (zerop (save-excursion (beginning-of-line)
991                                            (outline-level))))
992          (smart-scroll-down))
993         ;; On an outline header line but not at the start/end of line.
994         ((smart-outline-subtree-hidden-p)
995          (show-entry))
996         (t (hide-entry))))
997
998 (defun smart-outline-to-entry-end
999   (&optional include-sub-entries curr-entry-level)
1000   "Goes to end of whole entry if optional INCLUDE-SUB-ENTRIES is non-nil.
1001 CURR-ENTRY-LEVEL is an integer representing the length of the current level
1002 string which matched to 'outline-regexp'.  If INCLUDE-SUB-ENTRIES is nil,
1003 CURR-ENTRY-LEVEL is not needed."
1004   (let (next-entry-exists)
1005     (while (and (setq next-entry-exists
1006                       (re-search-forward outline-regexp nil t))
1007                 include-sub-entries
1008                 (save-excursion
1009                   (beginning-of-line)
1010                   (> (outline-level)
1011                      curr-entry-level))))
1012     (if next-entry-exists
1013         (progn (beginning-of-line) (point))
1014       (goto-char (point-max)))))
1015
1016 (defun smart-outline-subtree-hidden-p ()
1017   "Returns t if at least initial subtree of heading is hidden, else nil."
1018   (save-excursion
1019     (if (re-search-forward "[\n\^M]" nil t) (= (preceding-char) ?\^M))))
1020
1021 ;;;
1022 ;;; smart-tar functions
1023 ;;;
1024
1025 (defun smart-tar ()
1026   "Uses a single key or mouse key to manipulate tar file entries.
1027
1028 Invoked via a key press when in tar-mode.  It assumes that its
1029 caller has already checked that the key was pressed in an appropriate buffer
1030 and has moved the cursor there.
1031
1032 If key is pressed:
1033  (1) within an entry line, the selected file/directory is displayed for
1034      editing in the other window;
1035  (2) on or after the last line in the buffer, if any deletes are to be
1036      performed, they are executed after user verification, otherwise, this
1037      tar file browser is quit."
1038
1039   (interactive)
1040   (cond ((last-line-p)
1041          (let (flagged)
1042            (save-excursion
1043              (goto-char 1)
1044              (setq flagged (re-search-forward "^D" nil t)))
1045            (if flagged
1046                (tar-expunge)
1047              (kill-buffer nil))))
1048         (t (tar-extract-other-window))))
1049
1050 (defun smart-tar-assist ()
1051   "Uses a single assist-key or mouse assist-key to manipulate tar file entries.
1052
1053 Invoked via an assist-key press when in dired-mode.  It assumes that its
1054 caller has already checked that the assist-key was pressed in an appropriate
1055 buffer and has moved the cursor there.
1056
1057 If assist-key is pressed:
1058  (1) on an entry line, the current entry is marked for deletion;
1059  (2) on or after the last line in the buffer, all delete marks on all entries
1060      are undone."
1061
1062   (interactive)
1063   (cond ((last-line-p)
1064          (tar-unflag (- (count-lines (point-min) (point-max))))
1065          (goto-char (point-max)))
1066         (t (tar-flag-deleted 1))))
1067
1068 ;;;
1069 ;;; smart-wrolo functions
1070 ;;;
1071
1072 (defun smart-wrolo ()
1073   "In wrolo match buffer, edits current entry.
1074 Uses one key or mouse key.
1075
1076 Invoked via a key press when in the 'rolo-display-buffer'.  It assumes that
1077 its caller has already checked that the key was pressed in an appropriate
1078 buffer and has moved the cursor to the selected buffer."
1079   (interactive)
1080   (rolo-edit-entry))
1081
1082 (fset 'smart-wrolo-assist 'smart-wrolo)
1083
1084 ;;; Smart change log functions
1085 (defun smart-change-log ()
1086   "In Change Log buffers."
1087   (save-excursion
1088     (and
1089      (re-search-backward "^\\s-+\\*\\s-+")
1090      (looking-at "^\\s-+\\*\\s-+\\(.*?\\)\\(:\\|\\s-+(\\)")
1091      (hact 'link-to-file (buffer-substring (match-beginning 1) (match-end 1))))))
1092
1093 ;;; smart-bookmark-menu functions
1094 (defun smart-bookmark-menu ()
1095   "Uses a single key or mouse key to manipulate bookmark entries.
1096
1097 Invoked via a key press when in bookmark-bmenu-mode.  It assumes that its
1098 caller has already checked that the key was pressed in an appropriate buffer
1099 and has moved the cursor there.
1100
1101 If key is pressed:
1102  (1) on the first column of an entry, the selected buffer is marked for
1103      display; 
1104  (2) on the second column of an entry, the selected buffer is marked to be
1105      saved;
1106  (3) anywhere else within an entry line, all saves and deletes are done, and
1107      selected buffers are displayed, including the one just clicked on.
1108  (4) on or after the last line in the buffer, all saves and deletes are done."
1109
1110   (interactive)
1111   (cond ((last-line-p) (bookmark-bmenu-execute-deletions))
1112         ((bolp) (bookmark-bmenu-mark))
1113         ((save-excursion
1114              (goto-char (1- (point)))
1115              (bolp))
1116          (if (looking-at "\\*") 
1117              (bookmark-bmenu-show-annotation)
1118            (bookmark-bmenu-edit-annotation)))
1119         (t (bookmark-bmenu-select))))
1120
1121 (defun smart-bookmark-menu-assist ()
1122   "Uses a single assist-key or mouse assist-key to manipulate buffer-menu entries.
1123
1124 Invoked via an assist-key press when in bookmark-bmenu-mode.  It assumes that its
1125 caller has already checked that the assist-key was pressed in an appropriate
1126 buffer and has moved the cursor there.
1127
1128 If assist-key is pressed:
1129  (1) on the first or second column of an entry, the selected buffer is unmarked
1130      for display and for saving or deletion; 
1131  (2) anywhere else within an entry line, the selected buffer is marked for
1132      deletion;
1133  (3) on or after the last line in the buffer, all display, save, and delete
1134      marks on all entries are undone."
1135
1136   (interactive)
1137   (cond ((last-line-p) (bookmark-bmenu-quit))
1138         ((bolp) (bookmark-bmenu-unmark))
1139         ((save-excursion
1140              (goto-char (1- (point)))
1141              (bolp))
1142          (bookmark-bmenu-edit-annotation))
1143         (t (bookmark-bmenu-delete))))
1144
1145 (provide 'hui-mouse)
1146
1147 ;;; hui-mouse.el ends here