Go to the first, previous, next, last section, table of contents.

Introduction to Action Groups


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.

Must Read First

This document assumes that the user has bound the agroups command to a keystroke. For example a common thing to do is bind agroups to something like the keystroke C-zC-a. This 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 C-xC-z. The user is free to bind the agroups command to what ever he likes, but for the purpose of illustration this document uses C-zC-a.

Now for the must read first stuff. Since the agroups 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 agroups command 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 C-zC-a for 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 typing 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 are used.

Trying Action Groups from Scratch

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. Typically 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

Select entry:

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

Select operation:

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


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


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.

Creating our first action Entry

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.

Creating our first Group

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.

Performing cross group operations

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.

Using completion on Agroups ids

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

KA j

We could have executed it with completion


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


or even


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,

Making a group the Current or Current Persistent

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


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


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


The C operation says make the group you specify the Current Persistent and the Current Group.

Editing entries once created

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 Agroups buffer

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:

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:

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 C-cC-c 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

and type 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")


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)

Creating subgroups for organization

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 is 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


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

Select group:

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)

Philosophy of Action Groups

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

  1. Entries and groups must be easy to create, edit, move around and manipulate.
  2. Entries must be easy to execute.
  3. Entries and groups must automatically be made persistent.
  4. A group should be as much like an entry as possible.
  5. Some mechanism must be provided to make it easy for a user to define new action types.

The current Agroups addresses these criteria point by point as follows:

  1. Agroups operations were designed to be few, powerful, combinatorial and executed exactly the same way that action entries are executed. This design make some operations see rather odd, for example the simple move operation serves to move both groups and entries and also serves to delete, replace and copy or clone groups and entries depending on the move targets. But this makes the design simpler and also when you get used to it makes it easier in that you only have to remember how to move entries.
  2. Action entries can be bound to any keystroke easily and interactively and entries can also always be selected by using Emacs completion.
  3. Agroups has a save file and changes are automatically saved there. Usually a user does not have to think about what is happening here.
  4. Most operations that can be applied to entries, can in turn be applied to groups. A group can be an entry in a group and hence, one can organize subgroup trees.
  5. Agroups tries to achieve this with what it calls action templates that allow everything about any given automation pattern to be easily specified and the variable parts of the pattern are automatically asked for from the user when a template instance in requested by the user.

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.