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.
-
Spacemacs conveniently provides a CFEngine layer ↩︎
-
Jeff Carlson’s YASnippet library for CFEngine https://github.com/jeffcarlson72/emacs-yasnippet-cfengine3-mode ↩︎