Guest blog post: Quick-start guide to using Emacs for CFEngine

Posted by Jeff Carlson
August 26, 2022

This guide is designed for the novice user of CFEngine who wishes to explore the power of Emacs while developing CFEngine policy files – and will introduce the use of some Emacs features and plugins along the way.

There are two types of editors available in the Unix and Linux world: line and visual. Examples of line editors are ed and sed. These allow you to edit a file one line at a time.

Examples of visual editors are vi, nano and Emacs. These are also known as full-screen editors. They display as much of the entire file being edited as will fit on the screen at a time.

Emacs is unique among visual editors because it is capable of operating in both GUI (using Gtk widgets) and console or terminal modes. If you are working in a graphical environment, simply running emacs at the command line will start in GUI mode. If you are running in a non-graphical environment, such as from within PuTTY, it will start in terminal mode. If you wish to start terminal mode from within a GUI environment, run emacs -nw.

Emacs is more than just an editor; it is a complete programming language and interpreter for that language. Emacs consists of a Lisp interpreter written in C, but most of it is written in Emacs-Lisp, called elisp. Emacs implements modes written in elisp. There are two types of modes, major and minor.

Major modes are essentially programs that Emacs runs. The most common of these is Fundamental mode, which implements the basic text editor. Other programming modes are extensions of Fundamental mode. There is a major mode for CFEngine called cfengine3-mode.

You can think of minor modes as plugins or features that run along side of major modes. You can only run one major mode at a time but multiple minor modes can be active at the same time.

There are minor modes which alter the Emacs key bindings to work like other editors, such as vi. This tutorial will use only standard Emacs key bindings. If you are interested in vi-style key bindings, please investigate viper-mode, evil-mode, Spacemacs1 , or Doom Emacs on your own.

Emacs Key Bindings

To start Emacs, either start it from your operating system’s application menu or type emacs at a command prompt. This will start a GUI window of Emacs if you are operating in a GUI environment as discussed above.

Emacs modes are not like regular and insert modes in vi. Emacs is always in insert mode; there is no regular mode like in vi. Therefore, it is necessary to hit special keys in Emacs to perform other functions. These are Control, Alt, Shift, and Super (most commonly the Windows key). Here are the conventions used to display these keys:

Symbol Meaning
C-x Control + x
M-x Meta + x
S-x Shift + x
s-x Super + x

Wait! What is meta? Once upon a time, not every keyboard had Alt keys, but there might have been a meta key. And if the keyboard had neither, it likely had an Escape key. So, if you see a key combination that is M-something, either hold down Alt while hitting that other key, or hit Escape and then the other key. Sometimes it is necessary to use Escape instead of Alt, in particular when using SSH to access machines with different key mappings.

S-x is Shift + x. This will only result in an upper case X being printed. You may find other key combinations that require shift, like C-%, which is C-S-5 (Control + Shift + 5). This starts the query-replace function, otherwise known as search and replace string.

Once started, you will see some information about Emacs. No file will be open. If you started Emacs from the command line with emacs <filename>, it will begin with that file open. You can specify multiple files.

Emacs is capable of opening multiple files at a time. Each file is opened in a buffer. Emacs can also hold buffers which are not associated with a file.

To visit a file, use C-x C-f. That is, hold down Control and hit x and while still holding down Control hit f. This will prompt you for a file name. The file does not have to exist. You can use tab-completion if the file does already exist. By default, Emacs will start looking for files in the directory where it was started, most likely your $HOME directory.

When you are done editing a file, save it with C-x C-s. Why do the commands to visit and save files start with C-x? Think of C-x as the “extra functions” prefix. C-f on its own moves the cursor forward one character. C-s on its own starts the search function within the buffer.

To exit Emacs, use C-x C-c. But you don’t exit Emacs every time you finish editing a file. Most of us Emacs users start it when we log in and just close buffers when we finish editing a file. To do this, just use C-x k. That’s hold down Control and hit x, release Control and then hit k. You will be prompted for the buffer name to close, and it defaults to the current buffer. Emacs will remain open and you can open another file with C-x C-f.

To switch between buffers, use C-x b. By default, it will attempt to switch back to the most previously used buffer. You can type in any other buffer name, with Tab key completion. You can also type the name of a non-existent buffer to create a new one not associated with a file. There is a buffer named *scratch* which you can use to store notes or even evaluate Lisp commands (which is beyond the scope of this document). Buffers not associated with files, like the *scratch* buffer, are not saved when Emacs exits.

Now for some generic movement. C-f moves the cursor forward one character, like the right arrow. C-b moves it back like the left arrow. C-p moves to the previous line like the up arrow. C-n moves to the next line like the down arrow. C-a moves to the beginning of the line like the home key. C-e moves to the end of the line like the end key. C-v moves a page down like the page-down key. And M-v moves a page up like, you guessed it, the page-up key. Why use all these funny Control key combos when arrow keys exist? Because it is more ergonomic to keep your hands in the home row of the keyboard than to constantly move them around.

C-d will delete the character under the cursor. M-d will delete the rest of the word at the cursor. C-k will delete from the cursor to the end of the line. If the cursor is at the beginning of the line, C-k will delete the whole line. Backspace will delete the character behind the cursor. C-backspace will delete from the cursor to the beginning of the current word.

Normally, the position of the cursor is called the point. Hit C-space and move the cursor. The position where the cursor started is called the mark, and wherever you have moved the cursor is still called the point. If you have transient-mark-mode enabled, the region between the point and the mark should be highlighted. In more recent versions of Emacs, this is the default so you should see what you have marked. To cut this text, hit C-w, but to just copy it, hit M-w. When you do this, the copied or cut text is stored on the kill-ring. To get it back, or paste it, you use the yank command. To start yanking text off the kill-ring, first hit C-y. This yanks the most recent item on the kill-ring. To yank something else off the kill-ring, use M-y. This yanks the second item off the kill-ring, replacing the first item yanked. The kill-ring defaults to holding 60 items. Items deleted with C-k, M-d or C-backspace are also stored on the kill-ring, but not single characters erased with C-d or backspace.

Finally, some important keys you will frequently need. To cancel from the middle of anything, use C-g. And to undo things, use C-/. If you mess up, thinking that undo is C-z, that just puts Emacs in the background, possibly minimizing it. From the terminal, use the fg command, from a GUI it’s probably docked on one of your panels and Alt-Tab should bring it back.

Editing CFEngine Policy with Emacs

At the bottom of the screen in Emacs you will see the mode-line. It tells you what file you have open and what mode you are in. The blank under that is called the mini-buffer, which is where Emacs prompts you for file names and other information.

Emacs may not start in cfengine3-mode when you open a file ending in .cf. To put Emacs in cfengine3-mode, hit M-x then enter cfengine3-mode in the mini-buffer. You should be able to Tab-complete this.

Editing CFEngine policy files in cfengine3-mode is helpful because Emacs will handle indentation for you and highlight parts of the syntax.

I am going to show you how to write CFEngine policy in Emacs using the YASnippet extension and a library I wrote for it. YASnippet means “yet another snippet” and is an extension which inserts templates where requested. My library provides these templates specific to CFEngine 3.

M-x allows you to enter Emacs commands into the mini-buffer. Such commands include changing modes and starting certain functions.

First, make sure Emacs’s package cache is up to date with M-x package-refresh-contents. Next, install YASnippet with M-x package-install yasnippet.

Open a terminal on your computer. Clone my snippet library from my GitHub repository2.

git clone https://github.com/jeffcarlson72/emacs-yasnippet-cfengine3-mode.git

mkdir -p .emacs.d/snippets
mv emacs-yasippet-cfengine3-mode .emacs.d/snippets/cfengine3-mode

Now turn on YASnippet in Emacs with M-x yasnippet-mode. Load the CFEngine 3 snippets with M-x yas/reload-all. Make sure you are in a new cfengine3-mode buffer with C-x C-f example.cf followed by M-x cfengine3-mode. Let’s insert the first template. We want to make an agent type bundle so start by typing the word “agent” followed by the Tab key. Name your bundle “main” by typing that where the string is highlighted. You should see the following.

bundle agent main
{
  meta:
  vars:
  defaults:
  classes:
  users:
  files:
  packages:
  guest_environments:
  methods:
  processes:
  services:
  commands:
  storage:
  databases:
  reports:
}

What you have is a template for an agent bundle with all the promise types valid for agent bundles, in standard execution order. You can leave the promise types blank, it will not cause an error. Now, move the cursor below the promise type for files:, hit the Enter key, type the word “files” one more time and hit Tab. You will expand the template for a “files” type promise. Name the promiser (which is highlighted) to “/tmp/test.”

"/tmp/test"
action
classes
comment
depends_on
handle
if
ifvarclass
meta
unless
with
acl
changes
copy_from
create
delete
depth_search
edit_defaults
edit_line
edit_template
edit_template_string
edit_xml
file_select
file_type
link_from
move_obstructions
pathtype
perms
rename
repository
template_data
template_method
touch
transformer

What you see is every optional property for a files-promise, first the common properties in alphabetical order, then all the files-specific properties in alphabetical order. Move the cursor to the end of a property and hit Tab, it will expand with a hash-rocket and possibly any default values which might be body types, booleans, or other common answers. Be sure to add commas or semicolons at the ends of lines where necessary. Delete any template lines which are not needed for this promise. Let’s just create a blank file for this example.

"/tmp/test"
  create => "true",
  perms => mog("0644", "root", "root");

When you hit Tab after “create,” YASnippet prompted you with the values of true or false. And when you hit Tab after perms, YASnippet prompted you with all the perms body names from the masterfiles policy framework library. When you hit Tab after mog, YASnippet prompted you for the mode, owner, and group of this file.

Conclusion

In this tutorial you have seen some basic usage of the Emacs editor. You have learned to open, save, and close files as well as how to change modes and buffers within Emacs. You have learned how to delete, copy, and paste text within an Emacs buffer.

Also, you have seen how to install an external package from Emacs’s default package repository, which is called ELPA. Then you set up the YASnippet package to edit your CFEngine policy files with ease.

To continue using Emacs, run the tutorial with C-h t which will show you many more Emacs keybindings and explain concepts in more depth. You should look into configuring your own Emacs init file so that files ending in .cf automatically start in cfengine3-mode and so that YASnippet loads all snippets at startup.

I personally believe that Emacs is the most powerful editor on Earth and I use it to write all of my own CFEngine policy as well as just about everything else I need to write on a computer.


  1. Spacemacs conveniently provides a CFEngine layer ↩︎

  2. Jeff Carlson’s YASnippet library for CFEngine https://github.com/jeffcarlson72/emacs-yasnippet-cfengine3-mode ↩︎