-
Notifications
You must be signed in to change notification settings - Fork 11
/
hui-mouse.el
2255 lines (2008 loc) · 87.9 KB
/
hui-mouse.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
;;; hui-mouse.el --- Use key or mouse key for many functions, e.g. GNU Hyperbole menus -*- lexical-binding: t; -*-
;;
;; Author: Bob Weiner
;;
;; Orig-Date: 04-Feb-89
;; Last-Mod: 17-Nov-24 at 12:01:54 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
;; Copyright (C) 1991-2024 Free Software Foundation, Inc.
;; See the "HY-COPY" file for license information.
;;
;; This file is part of GNU Hyperbole.
;;; Commentary:
;;
;; This code is machine independent. It works best with a pointing device
;; but may also be used from a keyboard. When used with a pointing device it
;; requires an Emacs command that sets point to the location of the pointing
;; device's cursor.
;;
;; If you want to use your shift-middle mouse button to select Hyperbole menu
;; items and Hyperbole buttons, follow these instructions.
;;
;; If you plan to use a mouse only with the X window system or macOS and you
;; want to use the shift-middle and shift-right buttons, you need not do any
;; mouse configuration. Your Emacs executable must have been built so as to
;; include the mouse support files for your window system, however. These
;; are in the Emacs "src" directory: for X - "x*.c", for macOS - "ns*.c".
;;
;; To use a different mouse key or a different window system, modify the
;; mouse key bindings in "hmouse-sh.el".
;;
;; Using the Action Mouse Key to browse through and delete files from Dired
;; listings is exceptionally nice, just as it is when reading mail.
;;; Code:
;;; ************************************************************************
;;; Other required Elisp libraries
;;; ************************************************************************
(require 'ert-results nil t) ;; Optional Action Key support in ERT result buffers
;; Library in next line (for code optionally used in `smart-eol') uses
;; `repeat-map' which was not added to the "repeat.el" library in Emacs 27.1,
;; so don't use if it fails to load properly.
(ignore-errors (require 'hsys-flymake))
(require 'hload-path)
(require 'hsys-xref)
(require 'hsys-org)
(require 'hbut)
(unless (fboundp 'smart-info)
(require 'hmouse-info))
(unless (fboundp 'smart-c-at-tag-p)
(require 'hmouse-tag))
(require 'imenu)
(eval-when-compile
(require 'eieio)) ;; magit uses this and thus smart-magit does
(eval-when-compile (require 'tar-mode))
;;; ************************************************************************
;;; Public declarations
;;; ************************************************************************
;; Functions from optional, external ert-results package
(declare-function ert-results-filter "ext:ert-results")
(declare-function ert-results-filter-status-p "ext:ert-results")
(declare-function ert-results-display "ext:ert-results")
(declare-function ert-results-hide "ext:ert-results")
(declare-function ert-results-show "ext:ert-results")
(declare-function ert-results-toggle "ext:ert-results")
(declare-function ert-results-describe-test-at-point "ext:ert-results")
;; Hyperbole functions and keymap for `flymake-mode'
(declare-function hsys-flymake-get-issue-at-position "hsys-flymake")
;; Functions from Hyperbole's abstract mail and news interface.
;; See "hmail.el"
(declare-function lmail:delete "hmail")
(declare-function lmail:undelete "hmail")
(declare-function rmail:msg-prev "hmail")
(declare-function lmail:goto "hmail")
(declare-function lmail:expunge "hmail")
(declare-function rmail:msg-next "hmail")
(declare-function lmail:undelete-all "hmail")
;; Functions and variables from the helm package
(declare-function helm-get-actions-from-current-source "ext:helm-core")
(declare-function helm-get-default-action "ext:helm-core")
(defvar helm-selection-point)
;; Functions from Hyperbole's HyRolo and Koutliner
(declare-function hyrolo-edit-entry "hyrolo")
(declare-function hyrolo-hdr-in-p "hyrolo")
(declare-function hyrolo-hdr-to-first-line-p "hyrolo")
(declare-function kotl-mode:eobp "kotl-mode")
(declare-function kotl-mode:eolp "kotl-mode")
;; Emacs functions
(declare-function tar-flag-deleted "tar")
(declare-function tar-unflag "tar")
(declare-function tar-extract-other-window "tar")
(declare-function tar-expunge "tar")
(declare-function outline-invisible-in-p "hyperbole")
(declare-function Custom-newline "cus-edit")
(declare-function Custom-buffer-done "cus-edit")
;;; ************************************************************************
;;; Public variables
;;; ************************************************************************
(defvar hmouse-set-point-command nil
"*Command that sets point to the mouse cursor position.")
(defun action-key-error ()
"If in Org mode and Hyperbole shares {M-RET}, run `org-meta-return'.
In other context signal an error."
(if (and (funcall hsys-org-mode-function)
(hsys-org-meta-return-shared-p))
(hact 'hsys-org-meta-return)
(hypb:error "(Hyperbole Action Key): No action defined for this context; try another location")))
(defun assist-key-error ()
"If in Org mode and Hyperbole shares {M-RET}, run `org-meta-return'.
In other context, signal an error."
(if (and (funcall hsys-org-mode-function)
(hsys-org-meta-return-shared-p))
(hact 'hsys-org-meta-return)
(hypb:error "(Hyperbole Assist Key): No action defined for this context; try another location")))
(defcustom action-key-default-function #'action-key-error
"*Function run by the Action Key in an unspecified context.
Set it to `hyperbole' if you want it to display the Hyperbole minibuffer menu."
:type 'function
:group 'hyperbole-keys)
(defcustom assist-key-default-function #'assist-key-error
"*Function run by the Assist Key in an unspecified context.
Set it to `hkey-summarize' if you want it to display a summary of
Smart Key behavior."
:type 'function
:group 'hyperbole-keys)
(defcustom action-key-modeline-buffer-id-function #'dired-jump
"*Function to call for Action Key clicks on the buf id portion of a modeline.
Its default value is `dired-jump'; set it to `smart-treemacs-modeline'
to use the Treemacs file manager package instead."
:type 'function
:group 'hyperbole-keys)
(defcustom action-key-eol-function #'smart-scroll-up
"*Function run by the Action Key at the end of a line.
Its default value is `smart-scroll-up'. To disable it, set it to
#\\='ignore."
:type 'function
:group 'hyperbole-keys)
(defcustom assist-key-eol-function #'smart-scroll-down
"*Function run by the Assist Key at the end of a line.
Its default value is `smart-scroll-down'. To disable it, set it to
#\\='ignore."
:type 'function
:group 'hyperbole-keys)
;;; ************************************************************************
;;; Public declarations
;;; ************************************************************************
(declare-function todotxt-archive "ext:todotxt")
(declare-function todotxt-bury "ext:todotxt")
(declare-function todotxt-complete-toggle "ext:todotxt")
(declare-function todotxt-edit-item "ext:todotxt")
(declare-function magit-current-section "magit-selection")
(declare-function magit-diff-visit-file "etx:magit-diff")
(declare-function magit-diff-visit-file--internal "etx:magit-diff")
(declare-function magit-file-at-point "etx:magit-git")
(declare-function magit-section-cycle-diffs "etx:magit-diff")
(declare-function magit-section-cycle-global "etx:magit-selection")
(declare-function magit-section-hide "etx:magit-selection")
(declare-function magit-section-show "etx:magit-selection")
(defvar magit-root-section)
(defvar magit-display-buffer-function)
(declare-function -flatten "ext:dash")
(declare-function imenu--make-index-alist "imenu")
(declare-function image-dired-thumbnail-display-external "image-dired")
(declare-function image-dired-display-thumbnail-original-image "image-dired")
(declare-function image-dired-mouse-select-thumbnail "image-dired")
(declare-function helm-action-window "ext:helm-lib")
(declare-function helm-buffer-get "ext:helm-lib")
(declare-function helm-get-selection "ext:helm")
(declare-function helm-mark-current-line "ext:helm")
(declare-function helm-next-line "ext:helm")
(declare-function helm-pos-candidate-separator-p "ext:helm")
(declare-function helm-pos-header-line-p "ext:helm")
(declare-function helm-resume "ext:helm")
(declare-function helm-window "ext:helm-lib")
(declare-function with-helm-buffer "ext:helm-lib")
(defvar helm-action-buffer)
(defvar helm-alive-p)
(defvar helm-buffer)
(defvar helm-saved-action)
(declare-function ibuffer-mark-for-delete "ibuffer")
(declare-function ibuffer-unmark-forward "ibuffer")
(declare-function ibuffer-unmark-all "ibuffer")
(declare-function ibuffer-do-view "ibuffer")
(declare-function ibuffer-mark-forward "ibuffer")
(declare-function ibuffer-do-kill-on-deletion-marks "ibuffer")
(declare-function ibuffer-get-marked-buffers "ibuffer")
(declare-function ibuffer-current-buffer "ibuffer")
(declare-function br-buffer-menu-select "ext:br")
(declare-function gnus-topic-read-group "gnus-topic")
(declare-function company-show-doc-buffer "ext:company")
(declare-function company-quickhelp-manual-begin "ext:company-quickhelp")
(declare-function company-show-location "ext:company")
(declare-function company-select-mouse "ext:company")
(declare-function unix-apropos-get-man "ext:man-apropos")
;;; ************************************************************************
;;; Hyperbole context-sensitive keys dispatch table
;;; ************************************************************************
(defvar hkey-value nil
"Communicates a value between a Smart Key predicate and its actions.")
(defvar hkey-alist
'(
;; Company completion mode
((and (boundp 'company-active-map)
(memq company-active-map (current-minor-mode-maps)))
. ((smart-company-to-definition) . (smart-company-help)))
;;
;; Treemacs hierarchical file manager
((eq major-mode 'treemacs-mode)
. ((smart-treemacs) . (smart-treemacs)))
;;
;; dired-sidebar-mode
((eq major-mode 'dired-sidebar-mode)
. ((smart-dired-sidebar) . (smart-dired-sidebar)))
;;
((and (eq major-mode 'ert-results-mode)
(featurep 'ert-results)
(setq hkey-value (ert-results-filter-status-p)))
. ((smart-ert-results hkey-value) . (smart-ert-results-assist hkey-value)))
;;
;; Handle Emacs push buttons in buffers
((and (fboundp 'button-at) (button-at (point)))
. ((smart-push-button nil (mouse-event-p last-command-event))
. (smart-push-button-help nil (mouse-event-p last-command-event))))
;;
;; If in the minibuffer and reading an argument with vertico
;; run the vertico command on {M-RET} which accepts the first
;; line of minibuffer input, rather than any candidate.
((and hargs:reading-type
(> (minibuffer-depth) 0)
(eq (selected-window) (minibuffer-window))
(not (bound-and-true-p ivy-mode))
(and (bound-and-true-p vertico-mode)
;; Is vertico prompting for an argument?
(vertico--command-p nil (current-buffer))))
. ((vertico-exit-input) . (vertico-exit-input)))
;;
;; If in the minibuffer and reading an argument (aside from
;; with vertico or ivy), accept argument or give completion help.
((and hargs:reading-type
(> (minibuffer-depth) 0)
(eq (selected-window) (minibuffer-window))
(not (bound-and-true-p ivy-mode))
(not (and (bound-and-true-p vertico-mode)
;; Is vertico prompting for an argument?
(vertico--command-p nil (current-buffer))))
(not (eq hargs:reading-type 'hmenu))
(not (smart-helm-alive-p)))
. ((funcall (key-binding (kbd "RET"))) . (smart-completion-help)))
;;
;; If reading a Hyperbole menu item or a Hyperbole completion-based
;; argument, allow selection of an item at point.
((and (> (minibuffer-depth) 0) (setq hkey-value (hargs:at-p)))
. ((hargs:select-p hkey-value) . (hargs:select-p hkey-value 'assist)))
;;
;; If reading a Hyperbole menu item and nothing is selected, just return.
;; Or if in a helm session with point in the minibuffer, quit the
;; session and activate the selected item.
((and (> (minibuffer-depth) 0)
(eq (selected-window) (minibuffer-window))
(or (eq hargs:reading-type 'hmenu)
(smart-helm-alive-p)))
. ((funcall (key-binding (kbd "RET"))) . (funcall (key-binding (kbd "RET")))))
;;
;; If at the end of a line (eol), invoke the associated Smart Key handler EOL handler.
((and (smart-eolp)
(not (and (funcall hsys-org-mode-function)
(not (equal hsys-org-enable-smart-keys t)))))
. ((funcall action-key-eol-function) . (funcall assist-key-eol-function)))
;;
;; Handle any Org mode-specific contexts but give priority to Hyperbole
;; buttons prior to cycling Org headlines
((and (not (hyperb:stack-frame '(smart-org)))
(let ((hrule:action #'actype:identity))
(smart-org)))
. ((smart-org) . (smart-org)))
;;
;; The ID-edit package supports rapid killing, copying, yanking and
;; display management. It is available only as a part of InfoDock.
;; It is not included with Hyperbole.
((and (boundp 'id-edit-mode) id-edit-mode
(not buffer-read-only)
(not (smart-helm-alive-p)))
. ((id-edit-yank) . (id-edit-yank)))
;;
;; If in an xref buffer on a listing of matching identifier lines, go to
;; the source line referenced by the current entry.
((hsys-xref-item-at-point)
. ((xref-goto-xref) . (xref-show-location-at-point)))
;;
;; The Smart Menu system is an attractive in-buffer menu system
;; that works on any display system that supports Emacs. It
;; predates Emacs' menu systems; it is a part of InfoDock.
;; It is not included with Hyperbole but is compatible with the
;; Smart Keys.
;;
;; This selects or gives help for a menu item.
((eq major-mode 'smart-menu-mode)
. ((smart-menu-select) . (smart-menu-help)))
;;
((derived-mode-p 'dired-mode)
. ((smart-dired) . (smart-dired-assist)))
;;
((string-prefix-p "magit-" (symbol-name major-mode))
. ((smart-magit) . (smart-magit-assist)))
;;
;; If on a Hyperbole button, perform action or give help.
((hbut:at-p)
. ((hui:hbut-act 'hbut:current) . (hui:hbut-help 'hbut:current)))
;;
;; This potentially displays a Smart Menu.
((and (fboundp 'smart-menu-choose-menu)
(setq hkey-value (and hkey-always-display-menu
(smart-menu-choose-menu)))
(not (and (get-buffer-window *smart-menu-buffer*)
(eq hkey-value *smart-menu-curr*))))
. ((smart-menu hkey-value)
. (smart-menu hkey-value)))
;;
;; View minor mode
((if (boundp 'view-minor-mode) view-minor-mode)
. ((cond ((last-line-p)
(view-quit))
((pos-visible-in-window-p (point-max))
(goto-char (point-max)))
(t (scroll-up)))
. (scroll-down)))
;;
;; Direct access selection of helm-major-mode completions
((setq hkey-value (and (or (eq major-mode 'helm-major-mode)
(and (featurep 'helm) (equal helm-action-buffer (buffer-name))))
(or (eolp)
(smart-helm-at-header)
(smart-helm-line-has-action))))
. ((smart-helm) . (smart-helm-assist)))
;;
;; Support the OO-Browser when available. It is a separate Emacs
;; package not included with Hyperbole. Within an OO-Browser
;; OOBR-FTR buffer, an *Implementors* listing buffer, or an
;; Element signatures listing buffer of the OO-Browser, display
;; the associated element.
((or (string-equal (buffer-name) "*Implementors*")
(string-match "-Elements\\'" (buffer-name))
(and (boundp 'br-feature-tags-file)
(stringp br-feature-tags-file)
(equal br-feature-tags-file buffer-file-name)))
. ((smart-element) . (hkey-help)))
;;
;; View major mode
((eq major-mode 'view-mode) .
((View-scroll-lines-forward) . (View-scroll-lines-backward)))
;;
;; Select or select-and-kill a markup pair (e.g. hmtl tags), list,
;; array/vector, set, function, comment or string that begins or
;; ends at point. For markup pairs, point must be at the first
;; character of the opening or closing tag.
((hui-select-at-delimited-thing-p)
. ((hui-select-delimited-thing) . (progn (hui-select-delimited-thing)
(hmouse-kill-region))))
;;
;; If the prior test failed and point is at the start or end of an
;; sexpression, mark it for editing or kill it (assist key). This
;; only handles the special case where point is just after the
;; closing delimiter and not at an end-of-line, so this may be
;; removed someday.
((hui-select-at-delimited-sexp-p)
. ((hui-select-mark-delimited-sexp)
. (progn (hui-select-mark-delimited-sexp) (hmouse-kill-region))))
;;
((eq major-mode 'occur-mode)
. ((occur-mode-goto-occurrence) . (occur-mode-goto-occurrence)))
;;
((eq major-mode 'moccur-mode)
. ((moccur-mode-goto-occurrence) . (moccur-mode-goto-occurrence)))
((eq major-mode 'amoccur-mode)
. ((amoccur-mode-goto-occurrence) . (amoccur-mode-goto-occurrence)))
;;
((eq major-mode 'kotl-mode)
. ((kotl-mode:action-key) . (kotl-mode:assist-key)))
;;
;; If in the flymake linter list of issues buffer, jump to or show issue at point
((eq major-mode 'flymake-diagnostics-buffer-mode)
. ((flymake-goto-diagnostic (point)) . (flymake-show-diagnostic (point) t)))
;;
;; Rdb-mode supports direct selection and viewing of in-memory relational
;; databases. Rdb-mode is available as a part of InfoDock.
;; It is not included with Hyperbole.
((eq major-mode 'rdb-mode)
. ((rdb:action-key) . (rdb:assist-key)))
;;
;; Restore window config and hide help buffer when click at buffer end.
((if (= (point) (point-max))
(string-match "^\\*Help\\|Help\\*$" (buffer-name)))
. ((hkey-help-hide) . (hkey-help-hide)))
;;
;; Handle widgets in Custom-mode
((eq major-mode 'Custom-mode)
. ((smart-custom) . (smart-custom-assist)))
;;
;; Emacs bookmarks menu (bookmark.el)
((eq major-mode 'bookmark-bmenu-mode)
. ((bookmark-jump (bookmark-bmenu-bookmark) (hpath:display-buffer-function))
.
;; Below we want the Assist Key to show what the Action Key does.
(hkey-help)))
;;
;; Pages directory listing mode (page-ext.el)
((eq major-mode 'pages-directory-mode)
. ((pages-directory-goto) . (pages-directory-goto)))
;;
;; Python files - ensure this comes before Imenu for more advanced
;; definition lookups
((and (or (and (derived-mode-p '(python-mode python-ts-mode)) buffer-file-name)
(and (featurep 'hsys-org) (hsys-org-mode-p)
(equal (hsys-org-get-value :language) "python"))
(let ((case-fold-search))
(string-match "\\`\\([ *]?Pydoc[: ]\\|\\*?Python\\)" (buffer-name))))
(setq hkey-value (smart-python-at-tag-p)))
. ((smart-python hkey-value) . (smart-python hkey-value 'next-tag)))
;;
((and (memq major-mode '(c-mode c-ts-mode))
buffer-file-name (smart-c-at-tag-p))
. ((smart-c) . (smart-c nil 'next-tag)))
;;
((and (memq major-mode '(c++-mode c++-ts-mode)) buffer-file-name
;; Don't use smart-c++-at-tag-p here since it will prevent #include
;; lines from matching.
(smart-c-at-tag-p))
. ((smart-c++) . (smart-c++ nil 'next-tag)))
;;
((and (eq major-mode 'asm-mode)
buffer-file-name (smart-asm-at-tag-p))
. ((smart-asm) . (smart-asm nil 'next-tag)))
;;
((setq hkey-value nil
hkey-value
(or (when (smart-lisp-mode-p)
(or (setq hkey-value (smart-lisp-at-load-expression-p))
(smart-lisp-at-tag-p)))
;; Tightly limit Lisp matches in change-log-mode but
;; only call this if hkey-value is true since
;; otherwise, already know there is no tag at point.
(when hkey-value
(smart-lisp-at-change-log-tag-p))))
. ((smart-lisp) . (smart-lisp 'show-doc)))
;;
;;
((and (memq major-mode '(java-mode java-ts-mode)) buffer-file-name
(or (smart-java-at-tag-p)
;; Also handle Java @see cross-references.
(looking-at "@see[ \t]+")
(save-excursion
(and (re-search-backward "[@\n\r\f]" nil t)
(looking-at "@see[ \t]+")))))
. ((smart-java) . (smart-java nil 'next-tag)))
;;
((and (memq major-mode '(html-mode javascript-mode js-mode js-ts-mode js2-mode js3-mode web-mode))
buffer-file-name
(smart-javascript-at-tag-p))
. ((smart-javascript) . (smart-javascript nil 'next-tag)))
;;
((and (eq major-mode 'objc-mode) buffer-file-name
(smart-objc-at-tag-p))
. ((smart-objc) . (smart-objc nil 'next-tag)))
;;
;; Imenu listing in GNU Emacs
((smart-imenu-item-at-p)
. ((smart-imenu-display-item-where (car hkey-value) (cdr hkey-value)) .
(imenu-choose-buffer-index)))
;;
((and (memq major-mode '(fortran-mode f90-mode))
buffer-file-name (smart-fortran-at-tag-p))
. ((smart-fortran) . (smart-fortran nil 'next-tag)))
;;
((eq major-mode 'calendar-mode)
. ((smart-calendar) . (smart-calendar-assist)))
;;
;; Part of InfoDock
((eq major-mode 'unix-apropos-mode)
. ((smart-apropos) . (smart-apropos-assist)))
;;
((eq major-mode 'outline-mode)
. ((smart-outline) . (smart-outline-assist)))
;;
((eq major-mode 'Info-mode)
. ((smart-info) . (smart-info-assist)))
;;
((if (boundp 'hmail:reader)
(or (eq major-mode hmail:reader)
(eq major-mode hmail:lister)))
. ((smart-hmail) . (smart-hmail-assist)))
;;
((eq major-mode 'gnus-group-mode)
(smart-gnus-group) . (smart-gnus-group-assist))
;;
((eq major-mode 'gnus-summary-mode)
. ((smart-gnus-summary) . (smart-gnus-summary-assist)))
;;
((eq major-mode 'gnus-article-mode)
. ((smart-gnus-article) . (smart-gnus-article-assist)))
;;
((eq major-mode 'Buffer-menu-mode)
. ((smart-buffer-menu) . (smart-buffer-menu-assist)))
;;
((eq major-mode 'ibuffer-mode)
. ((smart-ibuffer-menu) . (smart-ibuffer-menu-assist)))
;;
((eq major-mode 'tar-mode)
. ((smart-tar) . (smart-tar-assist)))
;;
;; Follow references in man pages.
((setq hkey-value (smart-man-entry-ref))
. ((smart-man-display hkey-value) . (smart-man-display hkey-value)))
;;
((eq major-mode 'w3-mode)
. ((w3-follow-link) . (w3-goto-last-buffer)))
;;
;; Future Hyperbole mode, not yet released
;; ((eq major-mode 'hynote-mode)
;; . ((smart-hynote) . (smart-hynote-assist)))
;;
((eq major-mode 'hyrolo-mode)
. ((smart-hyrolo) . (smart-hyrolo-assist)))
;;
((eq major-mode 'image-dired-thumbnail-mode)
. ((smart-image-dired-thumbnail) . (smart-image-dired-thumbnail-assist)))
;;
;; Gomoku game
((eq major-mode 'gomoku-mode)
. ((gomoku-human-plays) . (gomoku-human-takes-back)))
;;
;; Support the OO-Browser when available. It is a separate Emacs
;; package not included with Hyperbole. Hyperbole supplies a stub
;; `br-in-browser' test for use here.
((or (br-in-browser) (eq major-mode 'br-mode))
. ((smart-br-dispatch) . (smart-br-assist-dispatch)))
;;
;; Outline minor mode is on and usable.
((and (boundp 'outline-minor-mode) outline-minor-mode)
. ((smart-outline) . (smart-outline-assist)))
;;
;; Todotxt
((eq major-mode 'todotxt-mode)
. ((smart-todotxt) . (smart-todotxt-assist)))
;;
;; Any other programming modes not specially supported
;; Use xref which supports various Language Servers
((setq hkey-value (smart-prog-at-tag-p))
. ((smart-prog-tag hkey-value) . (smart-prog-tag hkey-value))))
"Alist of predicates and form-conses for the Action and Assist Keyboard Keys.
Each element is: (PREDICATE-FORM . (ACTION-KEY-FORM . ASSIST-KEY-FORM)).
When the Action or Assist Key is pressed, the first or second form,
respectively, associated with the first non-nil predicate is evaluated.
See also `hmouse-alist' for a superset of this list utilized by the
Action and Assist Mouse Keys.")
;;; ************************************************************************
;;; driver code
;;; ************************************************************************
(require 'hargs)
(defvar hmouse-alist hkey-alist
"Alist of predicates and form-conses for the Action and Assist Mouse Keys.
When the Action Mouse Key or Assist Mouse Key is pressed, the first or second
form, respectively, associated with the first non-nil predicate is
evaluated.
The function `hmouse-alist-add-window-handlers' adds the mouse context
handlers to this variable.
The `hkey-alist' variable is the subset of this alist used by the
smart keyboard keys.")
;; This must be required after hmouse-alist is defined in this file
;; since this will recursively require hmouse-drv which requires
;; hui-window when being compiled and that library requires that
;; hmouse-alist be defined.
(require 'hmouse-key)
;; This next library adds drag actions to `hmouse-alist'.
(require 'hui-window)
;;; ************************************************************************
;;; support code
;;; ************************************************************************
;; The `load' line below loads any local Smart Key function definitions.
;; The public distribution contains none. You may leave it commented out if
;; you prefer.
;; (load "smart-local" t)
;;; ************************************************************************
;;; Required Init functions
;;; ************************************************************************
(defun first-line-p ()
"Return t if point is on the first line of the buffer."
(save-excursion (beginning-of-line) (bobp)))
(defun last-line-p ()
"Return t if point is on the last line of the buffer."
(save-excursion (end-of-line) (smart-eobp)))
(defun smart-completion-help ()
"Offer completion help for current minibuffer argument, if any."
(when (where-is-internal 'minibuffer-completion-help (current-local-map))
(minibuffer-completion-help)))
;;; ************************************************************************
;;; smart-buffer-menu functions
;;; ************************************************************************
(defun smart-buffer-menu-no-marks ()
"Display this line's buffer in this window.
Bury the buffer menu unless other buffers are marked. If buffer
menu items are marked, return nil, else t."
(let* ((this-buffer (Buffer-menu-buffer t))
(menu-buffer (current-buffer))
(others (delq this-buffer (Buffer-menu-marked-buffers t))))
(unless others
(switch-to-buffer this-buffer)
(unless (eq menu-buffer this-buffer)
(bury-buffer menu-buffer))
t)))
(defun smart-buffer-menu ()
"Use a single key or mouse key to manipulate `buffer-menu' entries.
Invoked via a key press when in `Buffer-menu-mode. It assumes that its
caller has already checked that the key was pressed in an appropriate buffer
and has moved the cursor there.
If key is pressed:
(1) on the first column of an entry, the selected buffer is marked for
display;
(2) on the second column of an entry, the selected buffer is marked to be
saved;
(3) anywhere else within an entry line, all saves and deletes are done, and
selected buffers are displayed, including the one just clicked on (if
within the OO-Browser user interface, only the selected buffer is
displayed);
(4) on or after the last line in the buffer, all saves and deletes are done."
(interactive)
(cond ((last-line-p) (Buffer-menu-execute))
((bolp) (Buffer-menu-mark))
((save-excursion
(goto-char (1- (point)))
(bolp))
(Buffer-menu-save))
((br-in-browser) (br-buffer-menu-select))
((smart-buffer-menu-no-marks))
(t (Buffer-menu-select))))
(defun smart-buffer-menu-assist ()
"Use assist key or mouse assist key to manipulate `buffer-menu' entries.
Invoked via an assist key press when in `Buffer-menu-mode'. It assumes that its
caller has already checked that the assist key was pressed in an appropriate
buffer and has moved the cursor there.
If assist key is pressed:
(1) on the first or second column of an entry, the selected buffer is unmarked
for display and for saving or deletion;
(2) anywhere else within an entry line, the selected buffer is marked for
deletion;
(3) on or after the last line in the buffer, all display, save, and delete
marks on all entries are undone."
(interactive)
(cond ((last-line-p) (progn (list-buffers) (forward-line 3)))
((bolp) (Buffer-menu-unmark))
((save-excursion
(goto-char (1- (point)))
(bolp))
(Buffer-menu-unmark))
(t (Buffer-menu-delete))))
;;; ************************************************************************
;;; smart-ibuffer-menu functions
;;; ************************************************************************
(defun smart-ibuffer-menu-no-marks ()
"Display this line's buffer in this window.
Bury the buffer menu unless other buffers are marked. If buffer
menu items are marked, return nil, else t."
(let* ((this-buffer (ibuffer-current-buffer t))
(menu-buffer (current-buffer))
(others (delq this-buffer (ibuffer-get-marked-buffers))))
(unless others
(switch-to-buffer this-buffer)
(unless (eq menu-buffer this-buffer)
(bury-buffer menu-buffer))
t)))
(defun smart-ibuffer-menu ()
"Use a single key or mouse key to manipulate ibuffer entries.
Invoked via a key press when in ibuffer-mode. It assumes that
its caller has already checked that the key was pressed in an
appropriate buffer and has moved the cursor there.
If key is pressed:
(1) on the first or second column of an entry, the selected buffer is
marked for display;
(2) anywhere else within an entry line, all saves and deletes are done, and
selected buffers are displayed, including the one just clicked on (if
within the OO-Browser user interface, only the selected buffer is
displayed);
(3) on the first or last line in the buffer, all deletes are done."
(interactive)
(cond ((or (first-line-p) (last-line-p))
(ibuffer-do-kill-on-deletion-marks))
((or (bolp) (save-excursion
(goto-char (1- (point)))
(bolp)))
(ibuffer-mark-forward nil nil 1))
((br-in-browser) (br-buffer-menu-select))
((smart-ibuffer-menu-no-marks))
(t (ibuffer-do-view))))
(defun smart-ibuffer-menu-assist ()
"Use assist key or mouse assist key to manipulate `buffer-menu' entries.
Invoked via an assist key press when in ibuffer-mode. It assumes that
its caller has already checked that the assist key was pressed in an
appropriate buffer and has moved the cursor there.
If assist key is pressed:
(1) on the first or second column of an entry, the selected buffer is unmarked
for display or deletion;
(2) anywhere else within an entry line, the selected buffer is marked for
deletion;
(3) on the first or last line in the buffer, all display, save, and delete
marks on all entries are undone."
(interactive)
(cond ((or (first-line-p) (last-line-p))
(if (fboundp 'ibuffer-unmark-all-marks)
(ibuffer-unmark-all-marks)
(ibuffer-unmark-all 0)))
((or (bolp) (save-excursion
(goto-char (1- (point)))
(bolp)))
(ibuffer-unmark-forward nil nil 1))
(t (ibuffer-mark-for-delete nil nil 1))))
;;; ************************************************************************
;;; smart-custom and widget functions
;;; ************************************************************************
(defun smart-custom ()
"Use a single key or mouse key to manipulate customizable settings.
Invoked via a key press when in `Custom-mode'. It assumes that
its caller has already checked that the key was pressed in an
appropriate buffer and has moved the cursor there.
If key is pressed:
(1) on the last line of the buffer, exit Custom mode, potentially
prompting to save any changes;
(2) at the end of any other line, scroll the window down down a windowful;
(3) if a mouse event on a widget, activate the widget or display a menu;
(4) anywhere else, execute the command bound to {RETURN}."
(interactive)
(cond ((last-line-p) (Custom-buffer-done))
((eolp) (smart-scroll-up))
((mouse-event-p last-command-event)
(widget-button-click action-key-release-args))
;; Handle widgets in Custom-mode
(t (Custom-newline (point)))))
(defun smart-custom-assist ()
"Use an assist key or mouse assist key to manipulate customizable settings.
Invoked via a key press when in `Custom-mode'. It assumes that
its caller has already checked that the key was pressed in an
appropriate buffer and has moved the cursor there.
If key is pressed:
(1) on the last line of the buffer, exit Custom mode, potentially
prompting to save any changes;
(2) at the end of any other line, scroll the window down down a windowful;
(3) if a mouse event on a widget, activate the widget or display a menu;
(4) anywhere else, execute the command bound to {RETURN}."
(interactive)
(cond ((last-line-p) (Custom-buffer-done))
((eolp) (smart-scroll-down))
((mouse-event-p last-command-event)
(widget-button-click action-key-release-args))
;; Handle widgets in Custom-mode
(t (Custom-newline (point)))))
;;; ************************************************************************
;;; smart-calendar functions
;;; ************************************************************************
(defun smart-calendar ()
"Use a single key or mouse key to manipulate the scrolling calendar.
Invoked via a key press when in `calendar-mode'. It assumes that its
caller has already checked that the key was pressed in an appropriate buffer
and has moved the cursor there.
If key is pressed:
(1) at the end of the buffer, the calendar is scrolled forward 3 months;
(2) to the left of any dates on a calendar line, the calendar is scrolled
backward 3 months;
(3) on a date, the diary entries for the date, if any, are displayed."
(interactive)
(cond ((smart-eobp) (calendar-cursor-to-nearest-date)
(calendar-scroll-left-three-months 1))
((< (current-column) 5) (calendar-cursor-to-nearest-date)
(calendar-scroll-right-three-months 1))
(t (calendar-cursor-to-nearest-date)
(diary-view-entries 1))))
(defun smart-calendar-assist ()
"Use the assist key or mouse assist key to manipulate the scrolling calendar.
Invoked via an assist key press when in `calendar-mode'. It assumes that its
caller has already checked that the assist key was pressed in an appropriate
buffer and has moved the cursor there.
If assist key is pressed:
(1) at the end of the buffer, the calendar is scrolled backward 3 months;
(2) to the left of any dates on a calendar line, the calendar is scrolled
forward 3 months;
(3) anywhere else, all dates with marking diary entries are marked in the
calendar window."
(interactive)
(cond ((smart-eobp) (calendar-cursor-to-nearest-date)
(calendar-scroll-right-three-months 1))
((< (current-column) 5) (calendar-cursor-to-nearest-date)
(calendar-scroll-left-three-months 1))
(t (diary-mark-entries))))
;;; ************************************************************************
;;; smart-company mode functions
;;; ************************************************************************
;; These functions are called from hkey-alist when keyboard Smart Keys
;; are used. For mouse keys, they are bound to local keys in
;; company-mode's minor mode map.
(defun smart-company-to-definition (event)
"Action Key binding for `company-mode' completions to show item definition.
Use left mouse key, RET or TAB key to select a completion and exit."
(interactive "e")
(when (mouse-event-p last-command-event)
(company-select-mouse event))
(company-show-location))
(defun smart-company-help (event)
"Assist Key binding for `company-mode' completions popup to show item doc."
(interactive "e")
(when (mouse-event-p last-command-event)
(company-select-mouse event))
(if (featurep 'company-quickhelp)
(company-quickhelp-manual-begin)
(company-show-doc-buffer)))
;;; ************************************************************************
;;; smart-dired functions
;;; ************************************************************************
(defun smart-dired-pathname-up-to-point (&optional no-default)
"Return the part of the pathname up through point, else current directory.
Use for direct selection of an ancestor directory of the
Dired directory at point, if any.
With optional NO-DEFAULT, do not default to current directory
path; instead return nil."
(interactive)
(when (not (derived-mode-p 'dired-mode))
(error "(smart-dired-pathname-up-to-point): Called from non-dired buffer, '%s'"
(buffer-name)))
(if (dired-get-subdir) ;; On a dired directory line
(save-excursion
(re-search-forward "[/:\n\r\t\f]" (line-end-position) t)
(buffer-substring-no-properties
(if (and (not (bobp)) (= (preceding-char) ?/))
(point)
(1- (point)))
(progn (beginning-of-line)
(skip-syntax-forward "-")
(point))))
(unless no-default
(expand-file-name default-directory))))
(defun smart-dired ()
"Use a single key or mouse key to manipulate directory entries.
Invoked via a key press when in `dired-mode'. It assumes that its
caller has already checked that the key was pressed in an appropriate buffer
and has moved the cursor there.
If key is pressed:
(1) within an entry line, the selected file/directory is displayed
for editing, normally in another window but if an entry has been dragged
for display in another window, then this entry is displayed in the current
window (DisplayHere minor mode is shown in the mode-line; use {g}
to disable it)
(2) on a Dired header line (other than the end of line):
(a) within the leading whitespace, then if any deletes are to be
performed, they are executed after user verification; otherwise,
nothing is done;
(b) otherwise, Dired is run in another window on the ancestor directory
of the current directory path up through the location of point;
if point is on the first character, then the / root directory
is used.
(3) on or after the last line in the buffer, this Dired invocation is quit."
(interactive)
(cond ((save-excursion
(forward-line 0)
(looking-at dired-subdir-regexp))
(cond ((and (looking-at "\\s-")
(save-excursion
(skip-syntax-backward "-"))
(bolp))
;; In whitespace at beginning of a directory header line, perform deletes.
(if (save-excursion
(goto-char (point-min))
(re-search-forward "^D" nil t))
(cond ;; For Tree-dired compatibility
((fboundp 'dired-do-flagged-delete)
(dired-do-flagged-delete))
((fboundp 'dired-do-deletions)
(dired-do-deletions))
(t (error "(smart-dired): No Dired expunge function")))))
(t (hpath:find (smart-dired-pathname-up-to-point)))))
((last-line-p) (quit-window))
(t (hpath:find (or (dired-get-filename nil t) "")))))
(defun smart-dired-assist ()
"Use a single assist key or mouse assist key to manipulate directory entries.
Invoked via an assist key press when in `dired-mode'. It assumes that its
caller has already checked that the assist key was pressed in an appropriate
buffer and has moved the cursor there.
If assist key is pressed:
(1) on a `~' character, all backup files in the directory are marked for
deletion;
(2) on a `#' character, all auto-save files in the directory are marked for
deletion;
(3) anywhere else within an entry line, the current entry is marked for
deletion;
(4) on or after the last line in the buffer, all delete marks on all entries
are undone."
(interactive)
(cond ((or (last-line-p) (and (first-line-p) (eolp)))
(dired-unmark-all-files ?D)
(goto-char (point-max)))
((looking-at "~") (dired-flag-backup-files))
((looking-at "#") (dired-flag-auto-save-files))