forked from oantolin/embark
-
Notifications
You must be signed in to change notification settings - Fork 0
/
embark.texi
729 lines (611 loc) · 31.5 KB
/
embark.texi
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
\input texinfo @c -*- texinfo -*-
@c %**start of header
@setfilename embark.info
@settitle Embark: Emacs Mini-Buffer Actions Rooted in Keymaps
@documentencoding UTF-8
@documentlanguage en
@c %**end of header
@dircategory Emacs
@direntry
* Embark: (embark). Emacs Mini-Buffer Actions Rooted in Keymaps.
@end direntry
@finalout
@titlepage
@title Embark: Emacs Mini-Buffer Actions Rooted in Keymaps
@author Omar Antolín Camarena
@end titlepage
@contents
@ifnottex
@node Top
@top Embark: Emacs Mini-Buffer Actions Rooted in Keymaps
@end ifnottex
@menu
* Breaking news::
* Overview::
* Configuration::
* Embark, Marginalia and Consult: Embark Marginalia and Consult.
@detailmenu
--- The Detailed Node Listing ---
Overview
* Acting on targets::
* Working with sets of possible targets::
* Switching to a different command without losing what you've typed::
Configuration
* Quick start::
* Showing a reminder of available actions::
* Quitting the minibuffer after an action::
* Allowing the target to be edited before acting on it::
* Running some setup after injecting the target::
* Creating your own keymaps::
* Defining actions for new categories of targets::
Defining actions for new categories of targets
* New minibuffer target example - tab-bar tabs::
* New target example in regular buffers - short Wikipedia links::
@end detailmenu
@end menu
@node Breaking news
@chapter Breaking news
(That is, news about things breaking!)
@itemize
@item
The command @samp{embark-act-noexit} has been removed and a variable
@samp{embark-quit-after-action} now controls whether @samp{embark-act} quits the
minibuffer or not. (Also note that the word ``exit'' in
@samp{embark-act-noexit} was used incorrectly according to Emacs's
terminology: exiting the minibuffer means accepting the input,
like when you press @samp{RET}; and what @samp{embark-act-noexit} did was more
like pressing @samp{C-g} which Emacs calls aborting or quitting.)
@item
If a recent update to Embark made it stop working with certain
@uref{https://github.com/minad/consult/, Consult} commands, just install and load the new embark-consult
package (available on Melpa). In addition to the prior
functionality for Consult, this package also contains an
@samp{embark-consult-preview-at-point} that triggers a Consult preview
for the entry at point in an auto-updating Embark Collect buffer,
and an @samp{embark-consult-preview-minor-mode} to run the Consult
preview automatically as you move around the collect buffer.
@lisp
(use-package embark-consult
:ensure t
:after (embark consult)
:demand t ; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
:hook
(embark-collect-mode . embark-consult-preview-minor-mode))
@end lisp
@item
The ``occur'' subsystem has been overhauled and renamed ``collect''.
There are aliases for the old command and variable names with
``occur'' in them, but those will be gone in a couple of months. So
please update your configuration.
(The ``occur'' name came from @samp{ivy-occur} but since both @samp{occur} and
@samp{helm-occur} use @samp{occur} in a different sense, and @samp{occur} is obviously
older than @samp{ivy-occur}, I decided to avoid the @samp{embark-occur} name.
The new @samp{embark-collect} name is much more self-explanatory too.)
@item
The system for configuring targets and candidate collections has
been greatly simplified, so if you wrote your own target finders
or candidate collectors, you will need to tweak them to return
@samp{(cons type previous-return-value)}. This change means separate
classifiers are no longer needed (or supported!).
@item
If you are already an Embark user and an update caused you to lose
the package and symbol actions, install @uref{https://github.com/minad/marginalia, Marginalia}, activate
@samp{marginalia-mode} and you should be good to go. If you want to read
more about these changes see @uref{https://github.com/oantolin/embark#embark-marginalia-and-consult, the last section}.
@end itemize
@node Overview
@chapter Overview
@menu
* Acting on targets::
* Working with sets of possible targets::
* Switching to a different command without losing what you've typed::
@end menu
@node Acting on targets
@section Acting on targets
This package provides a sort of right-click contextual menu for Emacs,
accessed through the @samp{embark-act} command (which you should bind to a
convenient key), offering you relevant @emph{actions} to use on a @emph{target}
determined by the context:
@itemize
@item
In the minibuffer, the target is the current best completion
candidate.
@item
In the @samp{*Completions*} buffer the target is the completion at point.
@item
In a regular buffer, the target is the region if active, or else the
file, symbol or URL at point.
@end itemize
The type of actions offered depend on the type of the target:
@itemize
@item
For files you get offered actions like deleting, copying,
renaming, visiting in another window, running a shell command on the
file, etc.
@item
For buffers the actions include switching to or killing the buffer.
@item
For package names the actions include installing, removing or
visiting the homepage.
@end itemize
If you want a reminder of which actions are available after running
@samp{embark-act} type @samp{C-h} which will prompt you for an action with
completion, and remind you of the keybindings.
Everything is easily configurable: determining the current target,
classifying it, and deciding which actions are offered for each type
in the classification. The above introduction just mentions part of
the default configuration.
Configuring which actions are offered for a type is particularly easy
and requires no programming: the variable @samp{embark-keymap-alist}
associates target types with variables containing keymaps, and those
keymaps containing bindings for the actions. (To examine the
available categories and their associated keymaps, you can use @samp{C-h v
embark-keymap-alist} or customize that variable.) For example, in the
default configuration the type @samp{file} is associated with the symbol
@samp{embark-file-keymap}. That symbol names a keymap with single-letter
keybindings for common Emacs file commands, for instance @samp{c} is bound
to @samp{copy-file}. This means that if you are in the minibuffer after
running a command that prompts for a file, such as @samp{find-file} or
@samp{rename-file}, you can copy a file by running @samp{embark-act} and then
pressing @samp{c}.
These action keymaps are very convenient but not strictly necessary
when using @samp{embark-act}: you can use any command that reads from the
minibuffer as an action and the target of the action will be inserted
at the first minibuffer prompt. After running @samp{embark-act} all of your
keybindings and even @samp{execute-extended-command} can be used to run a
command. For example, if you want to replace all occurrences of the
symbol at point, just use @samp{M-%} as the action, there is no need to bind
@samp{query-replace} in one of Embark's keymaps. Also, those action keymaps
are normal Emacs keymaps and you should feel free to bind in them
whatever commands you find useful as actions and want to be available
through convenient bindings.
The actions in @samp{embark-general-map} are available no matter what type
of completion you are in the middle of. By default this includes
bindings to save the current candidate in the kill ring and to insert
the current candidate in the previously selected buffer (the buffer
that was current when you executed a command that opened up the
minibuffer).
Emacs's minibuffer completion system includes metadata indicating the
@emph{category} of what is being completed. For example, @samp{find-file}'s
metadata indicates a category of @samp{file} and @samp{switch-to-buffer}'s metadata
indicates a category of @samp{buffer}. Embark has the related notion of the
@emph{type} of a target for actions, and by default when category metadata
is present it is taken to be the type of minibuffer completion
candidates when used as targets. Emacs commands often do not set
useful category metadata so the @uref{https://github.com/minad/marginalia, Marginalia} package, which supplies
this missing metadata, is highly recommended for use with Embark.
Embark's default configuration has actions for the following target
types: files, buffers, symbols, packages, URLs, bookmarks, and as a
somewhat special case, actions for when the region is active. You can
read about the @uref{https://github.com/oantolin/embark/wiki/Default-Actions, default actions and their keybindings} on the GitHub
project wiki.
@node Working with sets of possible targets
@section Working with sets of possible targets
Besides acting individually on targets, Embark lets you work
collectively on a set of target @emph{candidates}. For example, while you
are in the minibuffer the candidates are simply the possible
completions of your input. Embark provides three commands to work on
candidate sets:
@itemize
@item
The @samp{embark-collect-snapshot} command produces a buffer listing all
the current candidates, for you to peruse and run actions on at your
leisure. The candidates can be viewed in a grid or as a list showing
additional annotations.
@item
The @samp{embark-collect-live} variant of @samp{embark-collect-snapshot} produces
``live'' Embark Collect buffers, meaning they auto-update as the set
of candidates changes. Most users of visual completion UIs such as
Icomplete, Selectrum or Ivy will probably either not want to use
this, to avoid seeing double, or to configure their completion UI to
hide while using @samp{embark-collect-live}. See the Embark wiki for @uref{https://github.com/oantolin/embark/wiki/Additional-Configuration#pause-selectrum-while-using-embark-collect-live, sample
configuration for Selectrum}.
@item
The @samp{embark-export} command tries to open a buffer in an appropriate
major mode for the set of candidates. If the candidates are files
export produces a Dired buffer; if they are buffers, you get an
Ibuffer buffer; and if they are packages you get a buffer in
package menu mode.
There is also support for exporting a list of grep results to an
honest grep-mode buffer, on which you can even use @uref{https://github.com/mhayashi1120/Emacs-wgrep, wgrep} if you
wish. In order to make use of this exporter you will need a command
that prompts you in the minibuffer for a grep result line. In the
near future you will be able to configure Emacs 28 to use
@samp{xref-show-definitions-completing-read} as the value of
@samp{xref-show-xrefs-function} and @samp{xref-show-definitions-function}. With
that configuration, @samp{project-find-regexp}, for example, with use the
minibuffer to offers search results. Additionally, today, you can
use the grepping commands from the @uref{https://github.com/minad/consult/, Consult} package, @samp{consult-grep},
@samp{consult-git-grep} or @samp{consult-ripgrep}.
@end itemize
These are always available as ``actions'' (although they do not act on
just the current target but on all candidates) for @samp{embark-act} and are
bound to @samp{S}, @samp{L} and @samp{E}, respectively, in @samp{embark-general-map}. This means
that you do not have to bind your own key bindings for these
(although you can, of course), just a key binding for @samp{embark-act}.
@node Switching to a different command without losing what you've typed
@section Switching to a different command without losing what you've typed
Embark also has the @samp{embark-become} command which is useful for when
you run a command, start typing at the minibuffer and realize you
meant a different command. The most common case for me is that I run
@samp{switch-to-buffer}, start typing a buffer name and realize I haven't
opened the file I had in mind yet! I'll use this situation as a
running example to illustrate @samp{embark-become}. When this happens I can,
of course, press @samp{C-g} and then run @samp{find-file} and open the file, but
this requires retyping the portion of the file name you already
typed. This process can be streamlined with @samp{embark-become}: will still
in the @samp{switch-to-buffer} you can run @samp{embark-become} and effectively
make the @samp{switch-to-buffer} command become @samp{find-file} for this run.
You can bind @samp{embark-become} to a key in @samp{minibuffer-local-map}, but it is
also available as an action under the letter @samp{B} (uppercase), so you
don't need a binding if you already have one for @samp{embark-act}. So,
assuming I have @samp{embark-act} bound to, say, @samp{C-S-a}, once I realize I
haven't open the file I can type @samp{C-S-a B C-x C-f} to have
@samp{switch-to-buffer} become @samp{find-file} without losing what I have already
typed in the minibuffer.
But for even more convenience, @samp{embark-become} offers shorter key
bindings for commands you are likely to want the current command to
become. When you use @samp{embark-become} it looks for the current command in
all keymaps named in the list @samp{embark-become-keymaps} and then activates
all keymaps that contain it. For example, the default value of
@samp{embark-become-keymaps} contains a keymap @samp{embark-become-file+buffer-map}
with bindings for several commands related to files and buffers, in
particular, it binds @samp{switch-to-buffer} to @samp{b} and @samp{find-file} to @samp{f}. So when
I accidentally try to switch to a buffer for a file I haven't opened
yet, @samp{embark-become} finds that the command I ran, @samp{switch-to-buffer}, is
in the keymap @samp{embark-become-file+buffer-map}, so it activates that
keymap (and any others that also contain a binding for
@samp{switch-to-buffer}). The end result is that I can type @samp{C-S-a B f} to
switch to @samp{find-file}.
@node Configuration
@chapter Configuration
@menu
* Quick start::
* Showing a reminder of available actions::
* Quitting the minibuffer after an action::
* Allowing the target to be edited before acting on it::
* Running some setup after injecting the target::
* Creating your own keymaps::
* Defining actions for new categories of targets::
@end menu
@node Quick start
@section Quick start
The easiest way to install Embark is from Melpa. It is highly
recommended to also install @uref{https://github.com/minad/marginalia, Marginalia}, so that Embark can offer you
preconfigured actions in more contexts. For @samp{use-package} users that
add Melpa to their @samp{package-archives}, the following is a very
reasonable starting configuration:
@lisp
(use-package marginalia
:ensure t
:config
(marginalia-mode))
(use-package embark
:ensure t
:bind
("C-S-a" . embark-act)) ; pick some comfortable binding
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:ensure t
:after (embark consult)
:demand t ; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
:hook
(embark-collect-mode . embark-consult-preview-minor-mode))
@end lisp
Other Embark commands such as @samp{embark-become}, @samp{embark-collect-snapshot},
@samp{embark-collect-live}, @samp{embark-export} can be run through @samp{embark-act} as
actions bound to @samp{B}, @samp{S}, @samp{L}, @samp{E} respectively, and thus don't really need
a dedicated key binding, but feel free to bind them directly if you
so wish. If you do choose to bind them directly, you'll probably want
to bind them in @samp{minibuffer-local-map}, since they are most useful in
the minibuffer (in fact, @samp{embark-become} only works in the minibuffer).
Embark needs to know what your minibuffer completion system considers
to be the list of candidates and which one is the current one. Embark
works out of the box if you use Emacs's default tab completion, the
built-in @samp{icomplete-mode} or @samp{fido-mode}, or the third-party packages
@uref{https://github.com/raxod502/selectrum/, Selectrum} or @uref{https://github.com/abo-abo/swiper, Ivy}.
If you are a @uref{https://emacs-helm.github.io/helm/, Helm} or @uref{https://github.com/abo-abo/swiper, Ivy} user you are unlikely to want Embark since
those packages include comprehensive functionality for acting on
minibuffer completion candidates. (Embark does come with Ivy
integration despite this.)
@node Showing a reminder of available actions
@section Showing a reminder of available actions
If you want a reminder of which actions are available after running
@samp{embark-act}, use @samp{embark-keymap-help}, which is bound to @samp{C-h} in all of
Embark's action keymaps. That command will prompt you for the name of
an action with completion (but feel free to enter a command not among
the offered candidates!), and will also remind you of the keybindings.
You can press @samp{@@} at the prompt and then one of the keybindings to enter
the name of the corresponding action.
If you find you prefer entering actions that way, you can configure
embark to always prompt you for actions by setting the variable
@samp{embark-prompter} to @samp{embark-completing-read-prompter}.
If you want to see the actions and their key bindings, but want to
use the keybindings rather than completing the command name, you can
install @uref{https://github.com/justbur/emacs-which-key, which-key} and configure Embark as follows:
@lisp
(setq embark-action-indicator
(lambda (map)
(which-key--show-keymap "Embark" map nil nil 'no-paging)
#'which-key--hide-popup-ignore-command)
embark-become-indicator embark-action-indicator)
@end lisp
@node Quitting the minibuffer after an action
@section Quitting the minibuffer after an action
By default, if you call @samp{embark-act} from the minibuffer it quits the
minibuffer after performing the action. You can change this by setting
the customizable variable @samp{embark-quit-after-action} to @samp{nil}. That
variable controls whether or not @samp{embark-act} quits the minibuffer when
you call it without a prefix argument, and you can select the opposite
behavior to what the variable says by calling @samp{embark-act} with @samp{C-u}.
Note that both the variable @samp{embark-quit-after-action} and @samp{C-u} have no
effect when you call @samp{embark-act} outside the minibuffer.
Having @samp{embark-act} @emph{not} quit the minibuffer can be useful to turn
commands into little ``thing managers''. For example, you can use
@samp{find-file} as a little file manager or @samp{describe-package} as a little
package manager: you can run those commands, perform a series of
actions, and then quit the command.
If you find yourself using the quitting and non-quitting variants of
@samp{embark-act} about equally often, you may prefer to have separate
commands for them instead of a single command that you call with @samp{C-u}
half the time. You could, for example, keep the default exiting
behavior of @samp{embark-act} and define a non-quitting version as follows:
@lisp
(defun embark-act-noquit ()
"Run action but don't quit the minibuffer afterwards."
(interactive)
(let ((embark-quit-after-action nil))
(embark-act)))
@end lisp
When @samp{embark-act} quits the minibuffer it uses the @samp{embark-quit} command
to do so, this command quits the minibuffer but keeps the window
configuration intact. Normally pressing @samp{C-g} in the minibuffer restores
the window configuration from before opening the minibuffer, this can
be annoying if you used some actions that spawn new windows, such as
@samp{find-file-other-window}. (This is not specific to Embark, if you use
recursive minibuffers you probably noticed this behavior already.) If
you usually want to preserve your windows when exiting the minibuffer,
you may want to bind @samp{embark-quit} to @samp{C-g} in @samp{minibuffer-local-map}.
@node Allowing the target to be edited before acting on it
@section Allowing the target to be edited before acting on it
By default, for most commands @samp{embark} inserts the target of the action
into the next minibuffer prompt and ``presses @samp{RET}'' for you, accepting
the target as is.
For some commands this might be undesirable, either for safety
(because a command is ``hard to undo'', like @samp{delete-file} or
@samp{kill-buffer}), or because further input is required next to the target
(like when using @samp{shell-command}: the target is the file and you still
need to enter a shell command to run on it, at the same prompt). You
can add such commands to the @samp{embark-allow-edit-commands} variable
(which by default already contains the examples mentioned, and a few
others as well).
Now, automatically pressing @samp{RET} for most commands is only the default.
If you set the variable @samp{embark-allow-edit-default} to @samp{t}, then @samp{embark}
will instead give you a chance to edit the target before acting upon
it, for all commands except those listed in @samp{embark-skip-edit-commands}.
@node Running some setup after injecting the target
@section Running some setup after injecting the target
You can customize what happens after the target is inserted at the
minibuffer prompt of an action. There is a hook, @samp{embark-setup-hook},
that is run by default after injecting the target into the minibuffer.
This hook can be overridden for specific action commands by associating
the command to the desired overriding hook in @samp{embark-setup-overrides}.
For example, consider using @samp{shell-command} as an action during file
completion. It would be useful to insert a space before the target
file name and to leave the point at the beginning, so you can
immediately type the shell command. That's why in @samp{embark}'s default
configuration there is an entry in @samp{embark-setup-overrides} associating
@samp{shell-command} to @samp{embark--shell-prep}, a simple helper command that
quotes all the spaces in the file name, inserts an extra space at the
beginning of the line and leaves point to the left of it.
@node Creating your own keymaps
@section Creating your own keymaps
All internal keymaps are defined with a helper macro
@samp{embark-define-keymap} that you can use to define your own keymaps,
whether they are for new categories in @samp{embark-keymap-alist} or for any
other purpose! For example a simple version of the file action keymap
could be defined as follows:
@lisp
(embark-define-keymap embark-file-map
"Example keymap with a few file actions"
("d" delete-file)
("r" rename-file)
("c" copy-file))
@end lisp
Remember also that these action keymaps are perfectly normal Emacs
keymaps, and do not need to be created with this helper macro. You
can use the built-in @samp{define-key}, or your favorite external package
such as @samp{bind-key} or @samp{general.el} to manage them.
@node Defining actions for new categories of targets
@section Defining actions for new categories of targets
It is easy to configure Embark to provide actions for new types of
targets, either in the minibuffer or outside it. I present below two
very detailed examples of how to do this. At several points I'll
explain more than one way to proceed, typically with the easiest
option first. I include the alternative options since there will be
similar situations where the easiest option is not available.
@menu
* New minibuffer target example - tab-bar tabs::
* New target example in regular buffers - short Wikipedia links::
@end menu
@node New minibuffer target example - tab-bar tabs
@subsection New minibuffer target example - tab-bar tabs
Say you use the new @uref{https://www.gnu.org/software/emacs/manual/html_node/emacs/Tab-Bars.html, tab bars} from Emacs 27 and you want Embark to
offer tab-specific actions when you use the tab-bar-mode commands
that mention tabs by name. You would need to: (1) make sure Embark
knows those commands deal with tabs, (2) define a keymap for tab
actions and configure Embark so it knows that's the keymap you want.
@enumerate
@item
Telling Embark about commands that prompt for tabs by name
For step (1), it would be great if the @samp{tab-bar-mode} commands reported
the completion category @samp{tab} when asking you for a tab with
completion. (All built-in Emacs commands that prompt for file names,
for example, do have metadata indicating that they want a @samp{file}.) They
do not, unfortunately, and I will describe a couple of ways to deal
with this.
Maybe the easiest thing is to configure @uref{https://github.com/minad/marginalia, Marginalia} to enhance those
commands. All of the @samp{tab-bar-*-tab-by-name} commands have the words
``tab by name'' in the minibuffer prompt, so you can use:
@lisp
(add-to-list 'marginalia-prompt-categories '("tab by name" . tab))
@end lisp
That's it! But in case you are ever in a situation where you don't
already have commands that prompt for the targets you want, I'll
describe how writing your own command with appropriate @samp{category}
metadata looks:
@lisp
(defun my-select-tab-by-name (tab)
(interactive
(list
(let ((tab-list (or (mapcar #'(lambda (tab) (cdr (assq 'name tab)))
(tab-bar-tabs))
(user-error "No tabs found"))))
(completing-read
"Tabs: "
(lambda (string predicate action)
(if (eq action 'metadata)
'(metadata (category . tab))
(complete-with-action action tab-list string predicate)))))))
(tab-bar-select-tab-by-name tab))
@end lisp
As you can see, the built-in support for setting the category
metadatum is not very easy to use or pretty to look at. To help with
this I recommend the @samp{consult--read} function from the excellent
@uref{https://github.com/minad/consult/, Consult} package. With that function we can rewrite the command as
follows:
@lisp
(defun my-select-tab-by-name (tab)
(interactive
(list
(let ((tab-list (or (mapcar #'(lambda (tab) (cdr (assq 'name tab)))
(tab-bar-tabs))
(user-error "No tabs found"))))
(consult--read "Tabs: " tab-list
:category 'tab))))
(tab-bar-select-tab-by-name tab))
@end lisp
Much nicer! No matter how you define the @samp{my-select-tab-by-name}
command, the first approach with Marginalia and prompt detection has
the following advantages: you get the @samp{tab} category for all the
@samp{tab-bar-*-bar-by-name} commands at once, also, you enhance built-in
commands, instead of defining new ones.
@item
Defining and configuring a keymap for tab actions
Let's say we want to offer select, rename and close actions for tabs
(in addition to Embark general actions, such as saving the tab name to
the kill-ring, which you get for free). Then this will do:
@lisp
(embark-define-keymap embark-tab-actions
"Keymap for actions for tab-bar tabs (when mentioned by name)."
("s" tab-bar-select-tab-by-name)
("r" tab-bar-rename-tab-by-name)
("k" tab-bar-close-tab-by-name))
(add-to-list 'embark-keymap-alist '(tab . embark-tab-actions))
@end lisp
What if after using this for a while you feel closing the tab
without confirmation is dangerous? You have a couple of options:
@enumerate
@item
You can keep using the @samp{tab-bar-close-tab-by-name} command, but no
longer let Embark press @samp{RET} for you:
@lisp
(add-to-list 'embark-allow-edit-commands 'tab-bar-close-tab-by-name)
@end lisp
@item
You can write your own command that prompts for confirmation and
use that instead of @samp{tab-bar-close-tab-by-name} in the above keymap:
@lisp
(defun my-confirm-close-tab-by-name (tab)
(interactive "sTab to close: ")
(when (y-or-n-p (format "Close tab '%s'? " tab))
(tab-bar-close-tab-by-name tab)))
@end lisp
Notice that this is a command you can also use directly from @samp{M-x}
independently of Embark. Using it from @samp{M-x} leaves something to be
desired, though, since you don't get completion for the tab names.
You can fix this if you wish as described in the previous section.
@end enumerate
@end enumerate
@node New target example in regular buffers - short Wikipedia links
@subsection New target example in regular buffers - short Wikipedia links
Say you want to teach embark to treat text of the form
@samp{wikipedia:Gary_Kasparov} in any regular buffer as a link to Wikipedia,
with actions to open the Wikipedia page in eww or an external browser
or to save the URL of the page in the kill-ring. We can take
advantage of the actions that Embark has preconfigured for URLs, so
all we need to do is teach Embark that @samp{wikipedia:Gary_Kasparov} stands
for the URL @samp{https://en.wikipedia.org/wiki/Garry_Kasparov}.
You can be as fancy as you want with the recognized syntax. Here, to
keep the example simple, I'll assume the link matches the regexp
@samp{wikipedia:[[:alnum:]_]+}. We will write a function that looks for a
match surrounding point, and returns the pair @samp{(cons 'url
actual-url-of-the-page)}.
@lisp
(defun my-short-wikipedia-link ()
"Target a link at point of the form wikipedia:Page_Name."
(save-excursion
(let* ((beg (progn (skip-chars-backward "[:alnum:]_:") (point)))
(end (progn (skip-chars-forward "[:alnum:]_:") (point)))
(str (buffer-substring-no-properties beg end)))
(save-match-data
(when (string-match "wikipedia:\\([[:alnum:]_]+\\)" str)
(cons 'url (format "https://en.wikipedia.org/wiki/%s"
(match-string 1 str))))))))
(add-to-list 'embark-target-finders 'my-short-wikipedia-link)
@end lisp
@node Embark Marginalia and Consult
@chapter Embark, Marginalia and Consult
Some changes were made to Embark, to better cooperate with the
@uref{https://github.com/minad/marginalia, Marginalia} and @uref{https://github.com/minad/consult, Consult} packages, and prior to being submitted to
MELPA@. Neither of those packages is a dependency of Embark, but
Marginalia is highly recommended, for reasons explained in the rest
of this section
Embark comes with actions for symbols (commands, functions, variables
with actions such as finding the definition, looking up the
documentation, evaluating, etc.) in the @samp{embark-symbol-map} keymap, and
for packages (actions like install, delete, browse url, etc.) in the
@samp{embark-package-keymap}.
Unfortunately Embark no longer automatically offers you these keymaps
when relevant, because many built-in Emacs commands don't report
accurate category metadata. For example, a command like
@samp{describe-package}, which reads a package name from the minibuffer,
does not have metadata indicating so.
Previously Embark had functions to supply this missing metadata, but
they have been moved to Marginalia, which augments many Emacs command
to report accurate category metadata. Simply activating
@samp{marginalia-mode} allows Embark to offer you the package and symbol
actions when appropriate again.
All annotation functions have been removed from Embark and moved to
Marginalia (where they have been improved!). Embark used these old
annotation functions for the list view in Embark Collect buffers.
@itemize
@item
If you install Marginalia and activate @samp{marginalia-mode}, the list
view in Embark Collect buffers will use the Marginalia annotations
automatically.
@item
If you don't install Marginalia, you will see only the annotations
that come with Emacs (such as keybindings in @samp{M-x}, or the unicode
characters in @samp{C-x 8 RET}).
@end itemize
Other small changes:
@itemize
@item
If you have Consult installed and call @samp{embark-collect-snapshot} from
@samp{consult-line}, @samp{consult-mark} or @samp{consult-outline}, you will notice the
Embark Collect buffer starts in list view by default. Similarly,
you'll notice that the @samp{consult-yank} family of commands start out in
list view with zebra stripes, so you can easily tell where
multi-line kill-ring entries start and end.
@item
The function @samp{embark-open-externally} has been removed following the
policy of avoiding overlap with Consult. If you used that action,
add @uref{https://github.com/minad/consult/blob/373498acb76b9395e5e590fb8e39f671a9363cd7/consult.el#L707, the small function} to your configuration or install Consult and
use @samp{consult-file-externally}.
@end itemize
@bye