Action Groups are groups of action entries that an Emacs user can create, save, name and access quickly. In a general sense these actions are any automation that a user can imagine to help with his activities. The user instantiates these automations as action entries which are a specific instances of some action from the current collection of actions. Actions can be as simple as finding a commonly used file in a buffer, to more complex like executing a previously defined keyboard macro, to very complex like an unimaginable whopper defined by a user created Action Template. Action Templates are an extensibility feature of Action Groups and allows the user to easily create new actions, Agroups supplies a useful predefined collection of actions created with Action Templates.
A collection of action entries is called an action group. Typically the
user associates each action group with a concentrated activity such as a
project. Each entry of an action group is associated with a specific
instance of an action. A group itself is actually an entry associated
with a special action called
group so that a group entry can be
yet another group itself. This implies that groups can have subgroups
and subgroups can have subgroups and so on. This gives the user
structured organizational capabilities.
The Action Groups facility was designed to allow easy and fast creation of groups and entries to help automate an Emacs user's work. At the same time it was designed to allow fast execution of the entries. To this end a user can use the Emacs completion facility to execute entries or key bindings or a combination of both.
In essence Action Groups are just this simple. But this description is pretty abstract, so let's do some concrete things with Action Groups to see what they are all about. It is important to go through these sections in the order presented since each depends on the previous.
This document assumes that the user has bound the
command to a keystroke. For example a common thing to do is bind
agroups to something like the keystroke
can be done by placing the following in your ~/.emacs file
(global-unset-key "\C-z") (global-set-key "\C-z\C-a" 'agroups)
Note that this example removes the binding of
C-z and makes
C-z a prefix key. This is not too serious since the Emacs
default key-binding of
C-z is the same as
user is free to bind the
agroups command to what ever he likes,
but for the purpose of illustration this document uses
Now for the must read first stuff. Since the
command and all bindings within a specific user's Agroups are
completely customizable there is a need in this document to use some
abbreviations for some of the functions bound. In particular Agroups
provides a few meta keys that allows a user to escape from the usual
Agroups entry selection. There will be more of a description of meta
keys later but for now we just list these abbreviations and their
meaning. In this table
= means "the binding of"
KA = the
agroupscommand key (eg. C-zC-a) KO = the Agroups meta operation key (default RET) KG = the Agroups meta group key (default TAB) KC = the Agroups meta completion key (default SPC)
This document and Agroups itself use the standard abbreviations of RET for the Return or Enter key on a keyboard, TAB for the Tab key and SPC for the Space Bar key.
We gave as illustration a default binding of
agroups. We abbreviate this binding as KA in this document
regardless if it is bound to some other key combination. Note from
the above that automatic default bindings in Agroups for KO, KG and KC
are respectively RET, TAB and SPC. You will see in another section
that the user can change these bindings to suit his preferences. So
if we had bound
C-zC-a to the
agroups command and
settled for the default bindings then "KA KO" would be interpreted as
C-z C-a RET.
But having settled this we will no longer refer to these specific meta
key bindings, we will simply just say KA KO KG and KC. So for example
if we say "KA a" it means have
agroups execute action "a" in
current group. And "KA KG g a" means execute action "a" in group "g".
We will say more on meta keys later but it is important to read this
section first so that there is no confusion where these abbreviations
To use Action Groups you must first load the `agroups.elc' file. See the Emacs Users Guide for how to compile the `agroups.el' and then load the compiled .elc file.
The Emacs user can execute Action Groups by giving the command
agroups is bound to a keystroke since
it combines nicely with other keystrokes for user actions. We will use
the abbreviations KA KO KG and KC mentioned above, See section Must Read First.
This section assumes that you do not have an existing Agroups save file, by default `~/.agroups'. So if you happen to have a save file at this point for some reason move it temporarily out of the way.
The first thing that we will look at is what Agroups gives you as a default set of groups. First let's just try entering simply KA. After doing this you should see in the minibuffer
This is the default action of Agroups. It is asking you to select an entry in the current group for execution. But since we haven't created any entries yet let's now try an Agroups operation by entering KO. Recall that from the previous section that by default KO is bound to RET. You should now see in the minibuffer
If you screwed up somewhere you can always abort any Agroups processing by typing C-g. Try aborting and then get back to the "Select operation:" prompt by entering again "KA KO". At this point it is waiting for an Agroups operation entry. If you enter KO again you should see a list of all Agroups operations come up in the Agroups buffer called "*Agroups*". And if you keep entering KO the Agroups buffer will scroll until it gets to the end and then wrap and scroll and so on. Try this and note that one of the operations in the Agroups buffer is the line
Display current group entries (keys: d)
In all Agroups entry displays including operations, group entries and groups this entry format is the same. It is the entry id followed by keys, if any, in parentheses. If the keys are there it means that you can select this entry with these keys. So let's abort again with C-g and then enter
KA KO d
and note that this a lowercase "d". You should then see in the Agroups buffer
Group: global (keys: .)
This is telling you that the current group id is "global" and that it has no entries. When you were looking at the list of operations you might have noticed the line
Display top level groups (keys: D)
So let's try that with
KA KO D
and note that this an uppercase "D". Now you should see in the Agroups buffer
Top level groups (C marks current persistent, c marks current) C global (keys: .) zzzap (keys: !)
This displays all existing groups. When you first try to execute an Agroups command and you don't have an Agroups save file it creates one for you and automatically creates two groups in that file: one with an id of "global" and one with an id of "zzzap". Note that in this display the "global" group is marked with a "C" on the left. This indicates that "global" is the current group and that is consistent with what we saw in the previous group entries display which was supposed to display the current group.
The "global" group is a complementary group that Agroups starts you off with and is also used for examples in this document. After you know how to use Agroups and create your own groups you are free to remove this group. However you may want to keep it as a place to put entries that you don't think belong in any other group. However the group with the id "zzzap", which we refer to as the zzzap group, can never be removed. Oddly enough you can change the id and keys of the zzzap group but never remove the group itself. The reason for this is that the zzzap group has a special significance in Agroups. There is no way to delete an entry in Agroups, you can only move entries around. Instead of deleting an entry you simply move it to the zzzap group. There is an operation to purge entries from the zzzap group which is explained in the Zzzap Group section, See section Zzzap Group.
Now that we know some simple navigation in Agroups let's create an
entry. Every entry in an Agroups group represents some action. For
example an action could be a previously defined keyboard macro. Perhaps
the simplest action might be simply finding a commonly used file, so
let's start with that. First bring some file into a buffer with the
usual Emacs command
find-file (by default C-xC-f). Now, while in
that buffer enter
KA KO a f
You should then see in the minibuffer
Enter entry id:
In all cases where Agroups prompts for an id the user has the option of just hitting RET in which case Agroups generates a reasonable id for that entry or to type some more descriptive id. For the sake of this example let's do the latter and type the id
My commonly used file
and then type RET. Now you should see
Enter Accelerator Keys () :
Agroups is now asking for the keys of the id/keys pair mentioned above. These are called Accelerator Keys since a user always has the option of choosing none in which case to select the entry later they type in the id manually or use the Emacs completion facility or they can choose a sequence of keystrokes here which accelerates making the selection later by just entering those keystrokes. Even if the user chooses some accelerator keys he can later still also use completion to select this entry so it never hurts to have accelerator keys. For the sake of this example we will type in the keys "f1" and then RET to complete the entry. This should pop-up the Agroups buffer with the following
Added entry (marked by m) to group: global m My commonly used file (keys: f 1)
In the previous section we displayed the current group and saw no entries, so now we should see one. So enter "KA KO d" and the Agroups buffer should display
Group: global (keys: .) My commonly used file (keys: f 1)
Now let's try to execute this new action entry. First kill the buffer we
brought up to create this entry. You can do this with the
kill-buffer command (by default C-x k). Then try "KA f 1". It
should bring the file back into a buffer.
Now that we've created an entry in the "global" group let's create one of our own groups. We do this by entering "KA KO G" (notice, that is a capital "G") and should see in the minibuffer
Enter a group id:
For the sake of this example let's give it the id "test" and then accelerator key "t". After this you should see two things. The minibuffer displays
Current group: test
and the Agroups pop-up buffer displays
Top level groups (C marks current persistent, c marks current) C global (keys: .) c test (keys: t) zzzap (keys: !)
You could see the same thing by entering "KA KO D" as before. This display shows two things. First that the test group has been added and second that the lowercase c on the left shows that this newly created group becomes the current group which is consistent with what the minibuffer says.
Now let's create an entry in this new group. This time let's create a slightly more complex action that will do a meaningless thing just for illustration. We will create a keyboard macro that goes to a junk buffer and puts trash in it. To do this type the following
C-x ( C-x b junk trash C-x )
This will create the keyboard macro. If you want, you can test the keyboard macro by killing the junk buffer and then typing "C-x e". This should bring up a junk buffer with trash in it.
Now let's create an Agroups entry in our test group with this keyboard macro. To do this enter
KA KO a k
You should then see the prompt
How keyboard macro will execute 0 = Will just execute 1 = Will execute if user says yes 2 = Will load into last keyboard macro
We simply want a keyboard macro that will just execute when we select this action, so just hit RET here to choose the default 0 choice. When it asks for the id give "put trash in a junk buffer" and for keys "j". After this you should see in the Agroups buffer
Added entry (marked by m) to group: test m put trash in a junk buffer (keys: j)
You now have a persistent copy of this keyboard macro so that anytime the test group is the current group you can enter "KA j" and you should have a junk buffer with trash. Kill the junk buffer again and try it.
By now it should be apparent that there is always a Current Group. Actually there is always a Current Persistent Group and a Current Group. This allows you to have a current group that you work on for some time and then easily switch to another group and when done, revert back. However if all that you want to do is a single operation or action entry in some other than current group that is easy to do as well.
If you are following the subsections in this introduction sequentially as was recommended you should now have a test group with one entry
Group: test (keys: t) put trash in a junk buffer (keys: j)
and a global group with one entry
Group: global (keys: .) My commonly used file (keys: f 1)
The current group is test but let's say that we want to just execute the action "My commonly used file" in the group global without making global the current group. You can execute any operation or action in any other group using the group meta binding that we described above as KG, which at this point should be bound to TAB. In essence the group you choose after a KG temporarily becomes the current group.
So first let's display the contents of the global group without making it current. You can do this by entering
KA KG . KO d
And now let's execute the "My commonly used file" action in the global group with
KA KG . f 1
Executing operations in other groups is not just convenient but functional as well. For example let's move the "My commonly used file" entry in the global group into our current test group. Do this by entering
KA KG . KO m f 1 t
Upon doing this successfully you should see the following in the Agroups buffer
Moved entry (marked by m) to group: test m My commonly used file (keys: f 1) put trash in a junk buffer (keys: j)
This "cross group" capability of KG is Agroups way of making a single pattern for any operation between groups and subgroups.
There is only one more meta binding left to try. That is the meta binding called completion that we described as KC, which at this point should be bound to SPC. SPC was chosen as the default binding for KC since that is the standard keystroke used for the Emacs completion facility. Also, KC introduces the Emacs completion facility in the context for any operation, group or entry the user is considering executing.
As a simple example, above we executed the "put trash in a junk buffer" with keys
We could have executed it with completion
KA KC SPC put SPC RET
Actually, Agroups tries to be intelligent here and it disambiguates keys typing versus id completion typing. So in this case you could do the same completion without the KC by entering
KA put SPC RET
KA p RET
In fact you could choose to never use keys at all and do literally everything using completion. Although, it is pretty difficult to beat accelerator keys in terms of making executing automations optimal,
As we mentioned in a previous section there are two notions of the Current Group. When a group is the Current Persistent group then the next time you enter Emacs that group will be the Current Group. But you can use this to conveniently make another group the Current Group, do some work in that group and then revert back to the Persistent Current Group.
At this point if you have been following the instructions then when you do "KA KO D" you should see
Top level groups (C marks current persistent, c marks current) global (keys: .) C test (keys: t) zzzap (keys: !)
as we have seen previously. The C is marking the Current Persistent group. That is, if you exit Emacs and restart you should see the same since the test group being Current Persistent is saved in your Agroups save file. The fact that there is just one C means that it is not only the Current Persistent Group but also the Current Group. To understand this better let's make the global group the Current Group by entering
KA KG . KO c
Now do a "KA KO D" you should see
Top level groups (C marks current persistent, c marks current) c global (keys: .) C test (keys: t) zzzap (keys: !)
The lowercase c is showing that the global group is now the Current Group and the uppercase C is showing that the test group is now the Current Persistent Group. What this means is that all operations and selections you do now will be done in the global group but if you were to restart Emacs, the test group will become the Current Group again along with being the Current Persistent Group. A this point you could have entered
KA KO C-c
which means revert back to the Current Persistent Group as the Current Group. In other words the C marked test group would revert back to becoming the Current Group. But instead let's enter
KA KO C
which makes the global group the Current Persistent and Current Group. So now if you do a "KA KO D" you should see just one C again but now it is on the global group. But for the next section let's go back to having the test group being the Current Persistent and Current Group. Do this by entering
KA KG t KO C
The C operation says make the group you specify the Current Persistent and the Current Group.
Once you create entries and groups it is easy to edit the components of them. As an example let's edit the entry "My commonly used file" that we moved to our test group in the previous section. Make sure that our test group is the current group with "KA KG t KO c". Suppose that you want to change the id of our entry to "My one commonly used file" and change the keys to be just "1". First change the keys by entering
KA KO e f 1
Lets make a temporary (probably wrong) assumption that the file you
picked for the id "My commonly used file" in the test group was
/home/me/MyFile. Then you should then see the following in the
This entry is in group: test id: My commonly used file keys: f 1 action: file object: This is a template based entry with slot values: File path specification: /home/me/MyFile
This displays all of the components of the entry: id, keys, action, and object. All entries (including groups) have this same form. You can easily remember what these components mean with the saying that ties them all together in the Entry Components section, See section Entry Components.
At the same time that this entry is displayed in the Agroups buffer you are prompted in the minibuffer to select which of these components to edit
Enter to edit: id: i, keys: k, object: RET, exit: SPC:
For now we want to edit the keys component so enter "k". And now you should see the familiar prompt
Enter Accelerator Keys () :
So just enter "1" for the accelerator keys followed by a RET and now you should see what we just saw re-displayed in the Agroups buffer
This entry is in group: test id: My commonly used file keys: 1 action: file object: This is a template based entry with slot values: File path specification: /home/me/MyFile
and note that the keys now just has "1". Now lets edit the id by entering
KA KO e 1
Note that now we are saying edit the entry with keys "1". After entering the above(1) at the component prompt enter "i" for id which should pop up the following in the Agroups buffer
---- Edit or enter below and type C-cC-c when done ---- My commonly used file
This is the standard way to edit ids and objects. You are given a
buffer with the contents of the id or object slot value and may edit
the buffer until you have what you want. It is permissible to leave
this buffer and do any other Emacs commands and then return to this
buffer. When you are though editing in this buffer type
as it says at the top of the buffer. At that point the edited entry
will replace the old entry and be made persistent.
So edit this buffer to read instead
---- Edit or enter below and type C-cC-c when done ---- My one commonly used file
C-cC-c. If you do a "KA KO d" you should now see
Group: test (keys: t) My one commonly used file (keys: 1) put trash in a junk buffer (keys: j)
You can edit the components of the current group in a similar way by entering (with an uppercase "E")
KA KO E
For the next section edit the id of the current group test so that its id is "Test" with an uppercase "T". Now do "KA KO d" again and you should see as a result
Group: Test (keys: t) My one commonly used file (keys: 1) put trash in a junk buffer (keys: j)
Once you start creating lots of actions you may want to organize them
into subgroups. Subgroups can have subgroups and so on. This
organizational structure is similar to file directories. Subgroups are
identical to top level groups. In fact you can promote a subgroup to a
top level group and vice versa. The only difference is that a subgroup
is a group that is an entry in another group. And a group is identical
to an entry. It has the same form of entry components that we saw in
the previous section, See section Editing entries once created. Its action
group and its object is the entries it contains. The action
group means select one of my entries and then execute that.
To get a clearer picture of this let's create a subgroup in our newly renamed group Test. Imagine that our newly renamed entry "My one commonly used file" is now only one of many files that we want to bring up easily and we don't want to mix files with other kind of actions. So let's create a subgroup called "Files" and put "My one commonly used file" into it for starters. Make sure that the current group is Test. We first create the subgroup by entering
KA KO g
Again, like any other new entry Agroups will prompt you for an id and keys. Make the id "Files" and keys "f". Now if you enter "KA KO d" you should see the following
Group: test (keys: t) Files (keys: f) My one commonly used file (keys: 1) put trash in a junk buffer (keys: j)
Now lets move our file action into the new subgroup. Do this by entering
KA KO m 1
At this point Agroups prompts you for the target group. Since we want to move this into a subgroup of our current group we enter "t". Normally this would mean move our entry into the Test group itself, but since we now have a subgroup in our Test group we get the following prompt that gives us a choice of the Test group itself or a subgroup of this group
There are subgroups in this group: Test 0 = Select this group as target group 1 = Select a subgroup of this group as target group
and in the minibuffer
Choose target (default 0):
For the target choose "1". And then to
enter "f" which should pop-up
Moved entry (marked by m) to group: Files m My one commonly used file (keys: 1)
Note that we could have done this move a lot easier using a current group local move See section Local moves.
Now if you enter "KA KO d" you will see
Group: Test (keys: t) Files (keys: f) put trash in a junk buffer (keys: j)
Since a subgroup is just another entry whose action is on its object, being its group of entries, you can also perform any operation on that group object. Consequently you can display the entries of the subgroup with
KA KO f KO d
Which should pop-up
Group: Files (keys: f) My one commonly used file (keys: 1)
The concept of automation is important to the philosophy of Action Groups. What we mean by automation is that when you hit a button or key it automatically does something for you that would ordinarily require a lot of work and recall on your part. It seems obvious that automations save time and make life more pleasant. What is not obvious is how to make automations easy to create, manipulate and trigger.
Agroups tries to achieve this non-obvious task. Keyboard macros in Emacs are a good example of how to make automations easy to create and execute. Action Groups is a more encompassing type of automation tool where specific actions have a purpose similar to keyboard macros. In fact, an action can be a keyboard macro. The action is the unit of automation. An action group provides an organizational unit for collections of action instances called entries. In developing Action Groups the following criteria are important
The current Agroups addresses these criteria point by point as follows:
Action Groups started off as a sort of experiment in activity flow automation that eventually evolved into something called Action Stacks that allowed you to stack up your automations like a stacks of notes on your desk. Although you could access any entry in a stack quickly this paradigm turns out to be too simple since activity flow tends to be more randomly structured while at the same time hierarchically structured. In another dimension it needed to be easy to quickly switch between different groups of activities and easy to evolve groups of actions during activity flow. This implied a complete rethink and rewrite of Action Stacks into what is called here Action Groups. Action Groups however is still considered an experiment and suggestions of improvements or philosophy are welcome.
Go to the first, previous, next, last section, table of contents.