When I first tried using Emacs it was to play with Orgmode. I loved Orgmode but being a staunch vim user I really struggled with the key bindings. Ultimately my first attempt to use Orgmode fell by the wayside.

When I learned about evil mode I gave it another go. I stumbled my way through just enough to get evil-mode working and Orgmode became much more usable. I still primarily interacted with Orgmode via direct files. I didn't make use of the agenda other than for searching. I only used Emacs for Orgmode.

Spacemacs is now my primary editor.

For a vim user coming to spacemacs I found this document very helpful. https://spin.atomicobject.com/2016/08/30/introduction-to-spacemacs/

I maintain my spacemacs config in an org file and the configuration snippets are tangled out to ~/.spacemacs.

dotspacemacs/layers

These are the layers that I use. I tend to run on develop branch and update at no particular interval.

 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
;; -*- mode: emacs-lisp -*-
;; This file is loaded by Spacemacs at startup.
;; It must be stored in your home directory.

(defun dotspacemacs/layers ()
  "Configuration Layers declaration.
You should not put any user code in this function besides modifying the variable
values."
  (setq-default
   ;; Base distribution to use. This is a layer contained in the directory
   ;; `+distribution'. For now available distributions are `spacemacs-base'
   ;; or `spacemacs'. (default 'sb-asynpacemacs)
   dotspacemacs-distribution 'spacemacs
   ;; Lazy installation of layers (i.e. layers are installed only when a file
   ;; with a supported type is opened). Possible values are `all', `unused'
   ;; and `nil'. `unused' will lazy install only unused layers (i.e. layers
   ;; not listed in variable `dotspacemacs-configuration-layers'), `all' will
   ;; lazy install any layer that support lazy installation even the layers
   ;; listed in `dotspacemacs-configuration-layers'. `nil' disable the lazy
   ;; installation feature and you have to explicitly list a layer in the
   ;; variable `dotspacemacs-configuration-layers' to install it.
   ;; (default 'unused)
   dotspacemacs-enable-lazy-installation 'unused
   ;; If non-nil then Spacemacs will ask for confirmation before installing
   ;; a layer lazily. (default t)
   dotspacemacs-ask-for-lazy-installation t
   ;; If non-nil layers with lazy install support are lazy installed.
   ;; List of additional paths where to look for configuration layers.
   ;; Paths must have a trailing slash (i.e. `~/.mycontribs/')
   dotspacemacs-configuration-layer-path '()
   ;; List of configuration layers to load.
   dotspacemacs-configuration-layers
   '(
     ;; ----------------------------------------------------------------
     ;; Example of useful layers you may want to use right away.
     ;; Uncomment some layer names and press <SPC f e R> (Vim style) or
     ;; <M-m f e R> (Emacs style) to install them.
     ;; ----------------------------------------------------------------
The defautl heading that comes from the wizard

Completion (Ivy)

I have started to prefer ivy over helm. It seems significantly snappier. I don't seem to miss much from helm. Some of the auto complete for helm took frequncy into account I think, but its easy enough to be more specific in trade for the speed.

1
     helm

Language Support

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  ;; Languages
  emacs-lisp
  cfengine
  (shell :variables
         shell-default-shell 'eshell)
  sql
  php
  markdown
  html
  syntax-checking
  yaml
  python

Org-mode

I pretty much live in org-mode. I keep my personal journal with the excellent org-journal package. I do my presentations with org-reveal, and much more config down in dotspacemacs/user-config.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
     (org :variables
          org-enable-org-journal-support t
          org-journal-dir "~/org/journal/"
          org-journal-file-format "%Y-%m-%d"
          org-journal-date-prefix "#+TITLE: "
          org-journal-date-format "%A, %B %d %Y"
          org-journal-time-prefix "* "
          org-journal-time-format ""
          org-want-todo-bindings t
          org-enable-reveal-js-support t)

     (org-jira :variables
               jiralib-url "https://tracker.mender.io:443"
               org-jira-working-dir "~/.org-jira")

Spell Checking

Werd Spell checking is nice, and auto completion will pop up correction suggestions when the insertion point is on a misspelled word.

1
2
     (spell-checking :variables
                     enable-flyspell-auto-completion t)

Email (mu4e)

mu4e must be installed on the system for this to work. I started using mu4e while I was running Ubuntu 16.04. 0.9.11 (the version readily available) worked fine while I got started with a single account.

1
2
3
4
5
6
7
8
9
  (mu4e :variables
       mu4e-update-interval 300
       mu4e-view-show-images t
       mu4e-view-show-addresses t
       mu4e-maildir "~/Maildir"
       user-mail-address "nick.anderson@cfengine.com"
       user-full-nam "Nick Anderson"
       mu4e-get-mail-command "mbsync -a"
       mu4e-html2text-command "html2text -utf8 -width 72")

I am currently running Ubuntu 16.10 which has mu4e 0.9.16 available in the default repos. 0.9.16 adds Contexts as the reccomended way to handle multiple acccounts. I am configuring contexts in dotspacemacs/user-config.

How can I apply format=flowed to my outgoing messages, enabling receiving clients that support this feature to reflow my paragraphs? Plain text emails with Content-Type: text/plain; format=flowed can be reflowed (i.e. line endings removed, paragraphs refilled) by receiving clients that support this standard. Clients that don’t support this, show them as is, which means this feature is truly non-invasive.

Here’s an explanatory blog post which also shows why this is a desirable feature: https://mathiasbynens.be/notes/gmail-plain-text (if you don’t have it, your mails mostly look quite bad especially on mobile devices) and here’s the RFC with all the details: http://www.ietf.org/rfc/rfc2646.txt.

Since version 0.9.17, mu4e send emails with format=flowed by setting

(setq mu4e-compose-format-flowed t)

in your Emacs init file (~/.emacs or ~/.emacs.d/init.el). The transformation of your message into the proper format is done at the time of sending. In order to happen properly, you should write each paragraph of your message of as a long line (i.e. without carriage return). If you introduce unwanted newlines in your paragraph, use M-q to reformat it as a single line.

If you want to send the message with paragraphs on single lines but without format=flowed (because, say, the receiver does not understand the latter as it is the case for Google or Github), use M-x use-hard-newlines (to turn use-hard-newlines off) or uncheck the box format=flowed in the Text menu when composing a message.

Useful tools

1
2
      ;; For managing may single file notes
      deft
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
     ;;auto-completion
     (auto-completion :variables
                          auto-completion-enable-snippets-in-popup t)

     git
     github
     ;; better-defaults
     ;; markdown
     ;; org
     ;; (shell :variables
     ;;        shell-default-height 30
     ;;        shell-default-position 'bottom)
     ;; spell-checking
     ;; syntax-checking
     ;; version-control
     )
End of dotspacemacs-configuration-layers

Additional Packages

1
2
3
4
5
   ;; List of additional packages that will be installed without being
   ;; wrapped in a layer. If you need some configuration for these
   ;; packages, then consider creating a layer. You can also put the
   ;; configuration in `dotspacemacs/user-config'.
   dotspacemacs-additional-packages '(emacs-easy-hugo password-store request bbdb kanban ox-jira json-mode calfw calfw-gcal systemd ob-async)

END dotspacemacs/layers

-I disable magithub because I keep getting API errors and it asks me if I want to work offline-. I am still trying to learn magit by itself so better to have something that doesn't nag at me constantly before trying to improve my workflow integration with github specifically.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
   ;; A list of packages that cannot be updated.
   dotspacemacs-frozen-packages '()
   ;; A list of packages that will not be installed and loaded.
   dotspacemacs-excluded-packages '()
   ;; Defines the behaviour of Spacemacs when installing packages.
   ;; Possible values are `used-only', `used-but-keep-unused' and `all'.
   ;; `used-only' installs only explicitly used packages and uninstall any
   ;; unused packages as well as their unused dependencies.
   ;; `used-but-keep-unused' installs only the used packages but won't uninstall
   ;; them if they become unused. `all' installs *all* packages supported by
   ;; Spacemacs and never uninstall them. (default is `used-only')
   dotspacemacs-install-packages 'used-only))
The end of the default dotspacemacs/layers

dotspacemacs/init

 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
(defun dotspacemacs/init ()
  "Initialization function.
This function is called at the very startup of Spacemacs initialization
before layers configuration.
You should not put any user code in there besides modifying the variable
values."
  ;; This setq-default sexp is an exhaustive list of all the supported
  ;; spacemacs settings.
  (setq-default
   ;; If non nil ELPA repositories are contacted via HTTPS whenever it's
   ;; possible. Set it to nil if you have no way to use HTTPS in your
   ;; environment, otherwise it is strongly recommended to let it set to t.
   ;; This variable has no effect if Emacs is launched with the parameter
   ;; `--insecure' which forces the value of this variable to nil.
   ;; (default t)
   dotspacemacs-elpa-https t
   ;; Maximum allowed time in seconds to contact an ELPA repository.
   dotspacemacs-elpa-timeout 5
   ;; If non nil then spacemacs will check for updates at startup
   ;; when the current branch is not `develop'. Note that checking for
   ;; new versions works via git commands, thus it calls GitHub services
   ;; whenever you start Emacs. (default nil)
   dotspacemacs-check-for-update nil
   ;; If non-nil, a form that evaluates to a package directory. For example, to
   ;; use different package directories for different Emacs versions, set this
   ;; to `emacs-version'.
   dotspacemacs-elpa-subdirectory nil
   ;; One of `vim', `emacs' or `hybrid'.
   ;; `hybrid' is like `vim' except that `insert state' is replaced by the
   ;; `hybrid state' with `emacs' key bindings. The value can also be a list
   ;; with `:variables' keyword (similar to layers). Check the editing styles
   ;; section of the documentation for details on available variables.
   ;; (default 'vim)
   dotspacemacs-editing-style 'vim
   ;; If non nil output loading progress in `*Messages*' buffer. (default nil)
   dotspacemacs-verbose-loading nil
   ;; Specify the startup banner. Default value is `official', it displays
   ;; the official spacemacs logo. An integer value is the index of text
   ;; banner, `random' chooses a random text banner in `core/banners'
   ;; directory. A string value must be a path to an image format supported
   ;; by your Emacs build.
   ;; If the value is nil then no banner is displayed. (default 'official)
   ;;dotspacemacs-startup-banner 'official
   dotspacemacs-startup-banner nil
   ;; List of items to show in startup buffer or an association list of
   ;; the form `(list-type . list-size)`. If nil then it is disabled.
   ;; Possible values for list-type are:
   ;; `recents' `bookmarks' `projects' `agenda' `todos'."
   ;; List sizes may be nil, in which case
   ;; `spacemacs-buffer-startup-lists-length' takes effect.
   ;;dotspacemacs-startup-lists '((recents . 5)
   ;;                             (projects . 7))
   dotspacemacs-startup-lists '((recents . 10)
                                (projects . 10))
   ;; True if the home buffer should respond to resize events.
   dotspacemacs-startup-buffer-responsive t
   ;; Default major mode of the scratch buffer (default `text-mode')
   dotspacemacs-scratch-mode 'text-mode

Theme

1
2
3
4
5
   ;; List of themes, the first of the list is loaded when spacemacs starts.
   ;; Press <SPC> T n to cycle to the next theme in the list (works great
   ;; with 2 themes variants, one dark and one light)
   dotspacemacs-themes '(solarized-dark
                         solarized-light)

More Defaults

A better font? http://www.tutysara.net/posts/2016/09/03/good-font-for-spacemacs/

  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
  ;; If non nil the cursor color matches the state color in GUI Emacs.
  dotspacemacs-colorize-cursor-according-to-state t
  ;; Default font, or prioritized list of fonts. `powerline-scale' allows to
  ;; quickly tweak the mode-line size to make separators look not too crappy.
  dotspacemacs-default-font '("Source Code Pro"
                              :size 20 
                              :weight normal
                              :width normal
                              :powerline-scale 1.1)

  ;; The leader key
  dotspacemacs-leader-key "SPC"
  ;; The key used for Emacs commands (M-x) (after pressing on the leader key).
  ;; (default "SPC")
  dotspacemacs-emacs-command-key "SPC"
  ;; The key used for Vim Ex commands (default ":")
  dotspacemacs-ex-command-key ":"
  ;; The leader key accessible in `emacs state' and `insert state'
  ;; (default "M-m")
  dotspacemacs-emacs-leader-key "M-m"
  ;; Major mode leader key is a shortcut key which is the equivalent of
  ;; pressing `<leader> m`. Set it to `nil` to disable it. (default ",")
  dotspacemacs-major-mode-leader-key ","
  ;; Major mode leader key accessible in `emacs state' and `insert state'.
  ;; (default "C-M-m")
  dotspacemacs-major-mode-emacs-leader-key "C-M-m"
  ;; These variables control whether separate commands are bound in the GUI to
  ;; the key pairs C-i, TAB and C-m, RET.
  ;; Setting it to a non-nil value, allows for separate commands under <C-i>
  ;; and TAB or <C-m> and RET.
  ;; In the terminal, these pairs are generally indistinguishable, so this only
  ;; works in the GUI. (default nil)
  dotspacemacs-distinguish-gui-tab nil
  ;; If non nil `Y' is remapped to `y$' in Evil states. (default nil)
  dotspacemacs-remap-Y-to-y$ nil
  ;; If non-nil, the shift mappings `<' and `>' retain visual state if used
  ;; there. (default t)
  dotspacemacs-retain-visual-state-on-shift t
  ;; If non-nil, J and K move lines up and down when in visual mode.
  ;; (default nil)
  dotspacemacs-visual-line-move-text nil
  ;; If non nil, inverse the meaning of `g' in `:substitute' Evil ex-command.
  ;; (default nil)
  dotspacemacs-ex-substitute-global nil
  ;; Name of the default layout (default "Default")
  dotspacemacs-default-layout-name "Default"
  ;; If non nil the default layout name is displayed in the mode-line.
  ;; (default nil)
  dotspacemacs-display-default-layout nil
  ;; If non nil then the last auto saved layouts are resume automatically upon
  ;; start. (default nil)
  dotspacemacs-auto-resume-layouts nil
  ;; Size (in MB) above which spacemacs will prompt to open the large file
  ;; literally to avoid performance issues. Opening a file literally means that
  ;; no major mode or minor modes are active. (default is 1)
  dotspacemacs-large-file-size 1
  ;; Location where to auto-save files. Possible values are `original' to
  ;; auto-save the file in-place, `cache' to auto-save the file to another
  ;; file stored in the cache directory and `nil' to disable auto-saving.
  ;; (default 'cache)
  dotspacemacs-auto-save-file-location 'cache
  ;; Maximum number of rollback slots to keep in the cache. (default 5)
  dotspacemacs-max-rollback-slots 5
  ;; If non nil, `helm' will try to minimize the space it uses. (default nil)
  dotspacemacs-helm-resize nil
  ;; if non nil, the helm header is hidden when there is only one source.
  ;; (default nil)
  dotspacemacs-helm-no-header nil
  ;; define the position to display `helm', options are `bottom', `top',
  ;; `left', or `right'. (default 'bottom)
  dotspacemacs-helm-position 'bottom
  ;; Controls fuzzy matching in helm. If set to `always', force fuzzy matching
  ;; in all non-asynchronous sources. If set to `source', preserve individual
  ;; source settings. Else, disable fuzzy matching in all sources.
  ;; (default 'always)
  dotspacemacs-helm-use-fuzzy 'always
  ;; If non nil the paste micro-state is enabled. When enabled pressing `p`
  ;; several times cycle between the kill ring content. (default nil)
  dotspacemacs-enable-paste-transient-state nil
  ;; Which-key delay in seconds. The which-key buffer is the popup listing
  ;; the commands bound to the current keystroke sequence. (default 0.4)
  dotspacemacs-which-key-delay 0.4
  ;; Which-key frame position. Possible values are `right', `bottom' and
  ;; `right-then-bottom'. right-then-bottom tries to display the frame to the
  ;; right; if there is insufficient space it displays it at the bottom.
  ;; (default 'bottom)
  dotspacemacs-which-key-position 'bottom
  ;; Control where `switch-to-buffer' displays the buffer. If nil,
  ;; `switch-to-buffer' displays the buffer in the current window even if
  ;; another same-purpose window is available. If non nil, `switch-to-buffer'
  ;; displays the buffer in a same-purpose window even if the buffer can be
  ;; displayed in the current window. (default nil)
  dotspacemacs-switch-to-buffer-prefers-purpose nil
  ;; If non nil a progress bar is displayed when spacemacs is loading. This
  ;; may increase the boot time on some systems and emacs builds, set it to
  ;; nil to boost the loading time. (default t)
  dotspacemacs-loading-progress-bar t
  ;; If non nil the frame is fullscreen when Emacs starts up. (default nil)
  ;; (Emacs 24.4+ only)
  dotspacemacs-fullscreen-at-startup nil
  ;; If non nil `spacemacs/toggle-fullscreen' will not use native fullscreen.
  ;; Use to disable fullscreen animations in OSX. (default nil)
  dotspacemacs-fullscreen-use-non-native nil
  ;; If non nil the frame is maximized when Emacs starts up.
  ;; Takes effect only if `dotspacemacs-fullscreen-at-startup' is nil.
  ;; (default nil) (Emacs 24.4+ only)
  dotspacemacs-maximized-at-startup nil
  ;; A value from the range (0..100), in increasing opacity, which describes
  ;; the transparency level of a frame when it's active or selected.
  ;; Transparency can be toggled through `toggle-transparency'. (default 90)
  dotspacemacs-active-transparency 90
  ;; A value from the range (0..100), in increasing opacity, which describes
  ;; the transparency level of a frame when it's inactive or deselected.
  ;; Transparency can be toggled through `toggle-transparency'. (default 90)
  dotspacemacs-inactive-transparency 90
  ;; If non nil show the titles of transient states. (default t)
  dotspacemacs-show-transient-state-title t
  ;; If non nil show the color guide hint for transient state keys. (default t)
  dotspacemacs-show-transient-state-color-guide t
  ;; If non nil unicode symbols are displayed in the mode line. (default t)
  dotspacemacs-mode-line-unicode-symbols t
  ;; If non nil smooth scrolling (native-scrolling) is enabled. Smooth
  ;; scrolling overrides the default behavior of Emacs which recenters point
  ;; when it reaches the top or bottom of the screen. (default t)
  dotspacemacs-smooth-scrolling t
  ;; If non nil line numbers are turned on in all `prog-mode' and `text-mode'
  ;; derivatives. If set to `relative', also turns on relative line numbers.
  ;; (default nil)
  dotspacemacs-line-numbers nil
  ;; Code folding method. Possible values are `evil' and `origami'.
  ;; (default 'evil)
  dotspacemacs-folding-method 'evil
  ;; If non-nil smartparens-strict-mode will be enabled in programming modes.
  ;; (default nil)
  dotspacemacs-smartparens-strict-mode nil
  ;; If non-nil pressing the closing parenthesis `)' key in insert mode passes
  ;; over any automatically added closing parenthesis, bracket, quote, etc…
  ;; This can be temporary disabled by pressing `C-q' before `)'. (default nil)
  dotspacemacs-smart-closing-parenthesis nil
  ;; Select a scope to highlight delimiters. Possible values are `any',
  ;; `current', `all' or `nil'. Default is `all' (highlight any scope and
  ;; emphasis the current one). (default 'all)
  dotspacemacs-highlight-delimiters 'all
  ;; If non nil, advise quit functions to keep server open when quitting.
  ;; (default nil)
  dotspacemacs-persistent-server nil
  ;; List of search tool executable names. Spacemacs uses the first installed
  ;; tool of the list. Supported tools are `rg', `ag', `pt', `ack' and `grep'.
  ;; (default '("rg" "ag" "pt" "ack" "grep"))
  dotspacemacs-search-tools '("rg" "ag" "pt" "ack" "grep")
  ;; The default package repository used if no explicit repository has been
  ;; specified with an installed package.
  ;; Not used for now. (default nil)
  dotspacemacs-default-package-repository nil

Whitespace Cleanup

1
2
3
4
5
6
   ;; Delete whitespace while saving buffer. Possible values are `all'
   ;; to aggressively delete empty line and long sequences of whitespace,
   ;; `trailing' to delete only the whitespace at end of lines, `changed'to
   ;; delete only whitespace for changed lines or `nil' to disable cleanup.
   ;; (default nil)
   dotspacemacs-whitespace-cleanup nil
1
   ))
End of whitespace dotspacemacs/init

dotspacemcacs/user-init

1
2
3
4
5
6
7
(defun dotspacemacs/user-init ()
  "Initialization function for user code.
It is called immediately after `dotspacemacs/init', before layer configuration
executes.
 This function is mostly useful for variables that need to be set
before packages are loaded. If you are unsure, you should try in setting them in
`dotspacemacs/user-config' first."

Functions for executing cfengine src blocks

 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
(add-to-list 'load-path "~/src/ob-cfengine3/")
(require 'ob-cfengine3)

;;  ;;(defvar org-babel-tangle-lang-exts)
;;  ;;(add-to-list 'org-babel-tangle-lang-exts '("cfengine3" . "cf"))
;;
;;  (defconst org-babel-header-args:cfengine3
;;    '((use-locks . :any)))
;;
;;  (defvar org-babel-cfengine3-command "/var/cfengine/bin/cf-agent"
;;    "Name of command to use for executing cfengine policy.")
;;
;;  (defvar org-babel-cfengine3-command-options "--no-lock"
;;    "Option string that should be passed to the agent. Note that
;;    --file will be appended to the options.")
;;
;;  (defvar org-babel-cfengine3-file-control-stdlib "body file control{ inputs => { '$(sys.libdir)/stdlib.cf' };}\n"
;;    "File control body to include the standard libriary from
;;    $(sys.libdir). It is usefult to inject into an example source
;;    block before execution.")
;;
;;  (defun org-babel-execute:cfengine3 (body params)
;;    "Actuate a block of CFEngine 3 policy.
;;    This function is called by `org-babel-execute-src-block'.
;;
;;    A temporary file is constructed containing
;;    `org-babel-cfengine3-file-control-stdlib and the body of the src
;;    block. `org-babel-cfengine3-command' is used to execute the
;;    temporary file."
;;
;;      (let* ((temporary-file-directory ".")
;;             (use-locks (and (assoc :use-locks params) (not (string= "no" (cdr (assoc :use-locks params))))))
;;      (tempfile (make-temp-file "cfengine3-")))
;;        (with-temp-file tempfile
;;          ;; Include the standard library automatically
;;          ;; TODO Make this conditional
;;          (insert org-babel-cfengine3-file-control-stdlib)
;;          (insert body))
;;        (unwind-protect
;;        (shell-command-to-string
;;        ;;(format "cf-agent -Kf %s" tempfile))
;;        (concat
;;          org-babel-cfengine3-command
;;          " "
;;          (when use-locks "--no-lock ")
;;          org-babel-cfengine3-command-options
;;          " "
;;          (format " --file %s" tempfile)))
;;      (delete-file tempfile))))
;;  ;; (provide ob-cfengine3)

CFEngine

1
2
3
4
5
    (defun nickanderson/cfengine-policy-perms ()
      "Save `buffer-file-name' for the owners eyes only (600/u+rw,go-a)"
      (save-excursion
        (set-file-modes buffer-file-name #o600)
        (message (concat "Made " buffer-file-name " accessibly only by the owner (600)."))))
nickanderson/cfengine-policy-perms

Function to add unique ID to each entry

I have this function so that I can add a unique id to each entry in the file. It can be obnoxious but my property drawers are folded so its not that intrusive, and it does allow for linking to a nodes unique id so that links can remain working after re-filing entries into different files. Sometimes I have a save hook configured to run this.

1
2
3
4
5
  (defun my/org-add-ids-to-headlines-in-file ()
    "Add ID properties to all headlines in the current file which
     do not already have one."
    (interactive)
    (org-map-entries 'org-id-get-create))

END of dotspacemacs/user-init

1
  )

dotspacemacs/user-config

This is where the bulk of my custom config lives.

1
2
3
4
5
6
7
(defun dotspacemacs/user-config ()
  "Configuration function for user code.
This function is called at the very end of Spacemacs initialization after
layers configuration.
This is the place where most of your configurations should be done. Unless it is
explicitly specified that a variable should be set before a package is loaded,
you should place your code here."

IRC

In October of 2017 I started using ERC for my IRC needs. Previously I used irssi inside of a tmux session. I miss the mobile notifications I had setup for irssi, and I miss the always connected agent, but it's much easier to move text inside emacs than from an external console.

Probably with some effort I could replace the functionality of irssinotifier and have some kind of bounder.

 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
  ;; IRC via ERC

  ;; Log channel history
  (setq erc-log-channels-directory "~/.erc/logs/")
  ;; I like to see the timestamps in the channel
  ;(setq erc-hide-timestamps t)
  ;; If this is not disabled, it can cause lots of duplication in log data
  (setq erc-log-insert-log-on-open nil)
  (setq erc-save-buffer-on-part nil
        erc-save-queries-on-quit nil
        erc-log-write-after-send t
        erc-log-write-after-insert t)
  (add-hook 'erc-insert-post-hook 'erc-save-buffer-in-logs)

  ; Don't prompt me for a password, I store it in ~/authinfo.gpg
  (setq erc-prompt-for-nickserv-password nil)

  ; Explicitly enable autojoin, even though its on by default.
  (erc-autojoin-mode 1)

  ; Autojoin my favorite channels
  ; Important that freenode is not irc.freenode.net or it wont match and autojoin wont occur
  (setq erc-autojoin-channels-alist
        '(("freenode.net" "#cfengine" "##cfengine-novartis-rudder" "#cfengine-dev", "org-mode")))

  ; Automatically connect to my irc networks and identify myself
  (erc :server "irc.freenode.net" :port 6667 :nick "nickanderson")

Org-mode

Org-mode is the killer app for emacs. Checkout the details of the org layer by typing SPC h l org. The org-layer has support for org-buillets, org-pomodoro, org-download, and org-projectile.

I have an open pull request to add org-journal support.

The org layer documentation states:

Since version 0.104, spacemacs uses the org version from the org ELPA repository instead of the one shipped with emacs. Then, any org related code should not be loaded before dotspacemacs/user-config, otherwise both versions will be loaded and will conflict.

Because of autoloading, calling to org functions will trigger the loading up of the org shipped with emacs which will induce conflicts. One way to avoid conflict is to wrap your org config code in a with-eval-after-load block like this:

1
  (with-eval-after-load 'org

But I get errors when I try and use that. Somewhere along the way I picked up this different style:

1
2
3
  (spacemacs|use-package-add-hook org-mode
    :post-config
    (progn

Configure TODO Keywords

This sets up quick access to TODO states. I definitely use TODO and DONE but I haven't really found my flow with any other states so this gets messed with from time to time.

1
2
3
4
  ;; TODO Keywords
  (setq org-todo-keywords
        (quote ((sequence "TODO(t)" "IN_PROGRESS(i)" "|" "DONE(d)")
                (sequence "WAITING(w@/)" "DELEGATED(D)" "HOLD(h@/)" "|" "CANCELLED(c@/)"))))

I like these fancy utf characters in the TODO keywords, but it could complicate manual editing and I would need to fix all my existing keywords first. Keeping it here in case I get a wild hair someday.

1
2
3
4
  ;; TODO Keywords
  (setq org-todo-keywords
        (quote ((sequence "☛ TODO(t)" "IN_PROGRESS(i)" "|" "✔ DONE(d)")
                (sequence "⚑ WAITING(w@/)" "HOLD(h@/)" "|" "✘ CANCELLED(c@/)"))))

Fast TODO selection

This enables fast todo selection to bring up the menu of TODO keywords when pressing t on a headline.

1
  (setq org-use-fast-todo-selection t)

Babel Languages

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  (org-babel-do-load-languages
   'org-babel-load-languages
   '(
      (shell . t)
      (python . t)
      (ruby . t)
      (ditaa . t)
      (perl . t)))
  ;; Blocks with :async will be executed asynchronously
  (require 'ob-async)
  ;; 2017-07-30 ob-async-org-babel-execute-src block no longer needs to be added to the hook.
  ;;(addto-list 'org-ctrl-c-ctrl-c-hook 'ob-async-org-babel-execute-src-block)
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
  (org-babel-do-load-languages
   'org-babel-load-languages
   '(
     (sh . t)
     (cfengine3 . t)
     (python . t)
     (ruby . t)
     (ditaa . t)
     (perl . t)
     ))
1
2
3
4
5
6
7
  (defadvice org-babel-execute-src-block (around load-language nil activate)
    "Load language if needed"
    (let ((language (org-element-property :language (org-element-at-point))))
      (unless (cdr (assoc (intern language) org-babel-load-languages))
        (add-to-list 'org-babel-load-languages (cons (intern language) t))
        (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages))
      ad-do-it))
Load org-bable languages on demand (https://emacs.stackexchange.com/questions/20577/org-babel-load-all-languages-on-demand)

Agenda

I consider myself quite unorganized. At least inside my head it feels that way. Org mode really helps me because it can search across multiple files. So I can have as many different files as I like for different projects or clients and then I can search across all of them for something using the agenda view. This specifies each of your org files, or the directories to be searched for org files.

I might want to add the deft directory so that my searches cover those notes as well.

1
2
3
  ;; Set the org-agenda files
  (setq org-agenda-files
    '("~/org" "~/org/cfengine" "~/.org-jira"))
1
2
3
  ;; It's hard to see them (at least with the default color). Also this is a
  ;; reccomended change to speed up the agenda (not that it's too slow for me).
  (setq org-agenda-dim-blocked-tasks nil)
1
  (setq org-tags-match-list-sublevels 'indented)
Indent agenda children todos (only in tag and tag-todo searches).
1
  (setq org-agenda-prefix-format '"%b")
Show breadcrumbs in the agenda

Clocktables

Use hours for clocktable summaries and show the current clock time in the modeline.

1
2
  (setq spaceline-org-clock-p t)
  (setq org-time-clocksum-format (quote (:hours "%d" :require-hours t :minutes ":%02d" :require-minutes t)))

Hyperlink abbreviations

I link to several issue tracking systems frequently, and link abbreviations make it much nicer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  ;; Link abbreviations http://orgmode.org/manual/Link-abbreviations.html#Link-abbreviations
  ;; This makes it easy to create links in org files to common urls
  ;; Note: The actual link is not stored in the text, only when rendered
  ;; Usage: [[zendesk:2753]] or [[redmine:7481][My text]]
  (setq org-link-abbrev-alist
        '(("zendesk" . "https://cfengine.zendesk.com/agent/tickets/")
          ("redmine" . "https://dev.cfengine.com/issues/")
          ("core-pr" . "https://github.com/cfengine/core/pull/")
          ("mpf-pr" . "https://github.com/cfengine/masterfiles/pull/")
          ("core-commit" . "https://github.com/cfengine/core/commit/")
          ("mpf-commit" . "https://github.com/cfengine/masterfiles/commit/")
          ("jira" . "https://tracker.mender.io/browse/")))

Journal

To enable org-journal in the org layer I need to define org-enable-org-journal-support when I enable the layer. If not the org-journal package won't be installed.

1
2
3
  (setq-default dotspacemacs-configuration-layers '(
    (org :variables
         org-enable-org-journal-support t)))

The default is ~/Documents/journal/ but I prefer to keep my journal inside my org directory for now.

I now set this when i load the layer.

1
    (setq org-journal-dir "~/org/journal/")

I find the default journal file names hard to read and prefer some visual separation.

Note: I would prefer to have them named with a .org extension but I found that broke the calendar search functionality.

I now set this when I load the layer

1
2
3
4
    ;; Warning: setting org-journal-file-format to include a file extension
    ;; like "%Y-%m-%d.org" breaks calender search functionality.

    (setq org-journal-file-format "%Y-%m-%d")

I like my org files to start off with a Title with a human readable day so that they might look nice if I ever decide to export them.

I now set this when I load the layer

1
2
    (setq org-journal-date-prefix "#+TITLE: ")
    (setq org-journal-date-format "%A, %B %d %Y")

The default entry is a second level heading (=** =). But since I start with a Title instead of a first level heading I like to bump this back out. Additionally I really dislike the timestamps being inserted at the beginning of each entry. Perhaps for a worklog journal I would like it a bit more.

I now set this when I load the layer.

1
2
    (setq org-journal-time-prefix "* ")
    (setq org-journal-time-format "")

Notes (deft)

I like to use #+Title as the first line in note files.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
  (setq deft-default-extension "org")
  (setq deft-extensions '("org"))
  (setq deft-directory "~/org/notes")
  (setq deft-recursive t)
  (setq deft-use-filename-as-title nil)
  (setq deft-use-filter-string-for-filename t)
  (setq deft-file-naming-rules '((noslash . "-")
                                 (nospace . "-")
                                 (case-fn . downcase)))
  (setq deft-text-mode 'org-mode)
  (setq deft-org-mode-title-prefix t)

Images   ATTACH

I now do the majority of my writing in org-mode. Sometimes I include images. This makes them render in-line by default. I might switch this back off. It's nice but I have found it makes navigating documents more difficult when images are displayed inline.

1
2
3
  ; Enable automatic inline image rendering
  ; http://orgmode.org/manual/In_002dbuffer-settings.html
  (setq org-startup-with-inline-images t)

org-download provides functions for capturing and automatically inserting a screenshot. I didn't like the directories it would create so I figure that using the normal org attach machinery will keep things tidy.

1
  (setq-default org-download-method 'attach)

Note:

  • ATTR_HTML: :width x can be used to control the image rendering within org as well.
  • Pressing C-c C-c while point is on DOWNLOADED will cause a refresh and the image will resize.
data/d1/8bf31e-9e06-4ec4-be2b-2e47adb6d7b0/screenshot_2016-09-23_13-32-43.png

Drag and drop images into org-mode can be useful.

data/d1/8bf31e-9e06-4ec4-be2b-2e47adb6d7b0/CFEngine_New_Logo-01-1_2016-09-23_13-43-18.jpg

Capturing

I use the TODO capture all the time. All of the captured TODOs goto the same place and then I re-file them (Rarely, but I'm trying to get better about it. There is a slight pain factor involved at times when a single org file gets up to 30K lines) into other files later on. Note that I clock time during the capture and then automatically resume the previously clocked task when I am done capturing.

I keep trying other templates.

 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
      ;; I picked up this neat trick from the Venerable Sacha Chua
      (defvar my/org-meeting-template "** %u Meeting about %^{something}
  CREATED: %U

  ,*Attendees:*

   - [X] Nick Anderson
   - [ ] %?


  ,*Agenda:*
   -
   -

  ,*Notes:*


  " "Meeting Template")

       (defvar my/org-contact-capture-template "* %(org-contacts-template-name)
  CREATED: %U
  :PROPERTIES:
  :EMAIL: %(org-contacts-template-email)
  :END:")


       (defvar my/org-capture-support "** TODO [#A] [[zendesk:%^{ISSUE}]]: %^{DESCRIPTION} %^G\n\n%?\n")

       (defvar my/org-respond-email-capture-template "** TODO [#B] Respond to %:from on %:subject\nSCHEDULED: %t\n%U\n%a\n\n")


      ;; Configure custom capture templates
      (setq org-capture-templates
          `(;; Note the backtick here, it's required so that the defvar based tempaltes will work!
            ;;http://comments.gmane.org/gmane.emacs.orgmode/106890

            ("t" "To-do" entry (file+headline "~/org/refile.org" "Tasks")
             "** TODO %^{Task Description}\nCreated From: %a\n" :clock-in t :clock-resume t :prepend t)

            ("s" "Support" entry (file+headline "~/org/refile.org" "Tasks")
             ,my/org-capture-support :clock-in t :clock-resume t)

            ("r" "Respond to Email" entry (file+headline "~/org/refile.org" "Tasks")
             ,my/org-respond-email-capture-template :clock-in t :clock-resume t)

            ("c" "Contact" entry (file "~/org/x-files.org") ,my/org-contact-capture-template)

            ("m" "Meeting" entry (file+headline "~/org/refile.org" "Meeting Notes")
             ,my/org-meeting-template :prepend t :clock-in t :clock-resume t)
    ))

Refiling

When I refile, I want to be able to go up to 5 levels deep. Probably I could take this down a notch or two. Usually I am only filing 1 or 2 levels deep.

1
2
  ;; Set refile locations to whats in org-agenda
  (setq org-refile-targets (quote ((org-agenda-files :maxlevel . 5))))

Indention

I picked this up from a co-worker. Before I started using this setting I was managing whitespace indentation inside my org files. Now its all indented automatically but the source itself is not indented. This really makes org-mode feel like more of an application than working in free form text. Slightly more of a word processor feel.

1
2
3
4
  ;; Keep the indentation well structured by. OMG this is a must have. Makes
  ;; it feel less like editing a big text file and more like a purpose built
  ;; editor for org mode that forces the indentation.
  (setq org-startup-indented t)

Exporting

My primary authoring tool is org. Being able to easily export to other formats is amazing.

1
  (setq org-export-backends '(org html ascii md jira))
1
2
  (require `ox-jira)
  (require `ox-md)

Publishing

You can export sets of files using the publishing functionality. I use this to export my notes for colleagues to be able to access. I publish my notes in multiple formats because different strokes for different folks.

 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
    (setq org-publish-project-alist
          '(
            ("cfengine-html"
             :base-directory "~/org/cfengine/"
             :base-extension "org"
             :publishing-directory "~/CFEngine/Google Drive/nicks_org"
             :recursive t
             :publishing-function org-html-publish-to-html
             :headline-levels 4
             :autopreamble t)
            ("cfengine-org"
             :base-directory "~/org/cfengine/"
             :base-extension "org"
             :publishing-directory "~/CFEngine/Google Drive/nicks_org"
             :recursive t
             :publishing-function org-org-publish-to-org
             :headline-levels 4
             :autopreamble t)
            ("cfengine-pdf"
             :base-directory "~/org/cfengine/"
             :base-extension "org"
             :publishing-directory "~/CFEngine/Google Drive/nicks_org"
             :recursive nil
             :publishing-function org-latex-publish-to-pdf
             :headline-levels 4
             :autopreamble t)
            ("cfengine-txt"
             :base-directory "~/org/cfengine/"
             :base-extension "org"
             :publishing-directory "~/CFEngine/Google Drive/nicks_org"
             :recursive t
             :publishing-function org-ascii-publish-to-utf8
             :headline-levels 4
             :autopreamble t)
  ))

END of Org

And here we close out with-eval-after-load 'org

1
  )

Blogging via Hugo

I switched from wordpress to hugo for my blog. I really wanted a to move to a static site generator and Hugo can nativly parse org formatted source files.

The easy-hugo package makes creating new posts with easy-hugo-newpost, previewing the blog with easy=hugo=preview, and publishing the blog with easy-hugo-publish convenient. The easy-hugo mode doesn't really work well inside spacemacs yet.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
  ; Hugo Static Site Generator
  ;; Use org-mode syntax by default
  (setq easy-hugo-default-ext ".org")
  ;; Location of my hugo dir
  (setq easy-hugo-basedir "~/src/blog/hugo-export/")
  ;; Site url
  (setq easy-hugo-url "http://cmdln.org")
  (setq easy-hugo-previewtime "300")
  (define-key global-map (kbd "C-c C-e") 'easy-hugo)
  ;; Deployment Related
  (setq easy-hugo-sshdomain "direct.cmdln.org")
  (setq easy-hugo-root "/home/cmdln/public_html/")

CFEngine

I am constantly working with CFEngine. These customizations improve my life.

CFEngine complains if files are writable by other users. This function is used to set permissions on CFEngine policy files correctly as they are edited.

1
2
3
4
5
6
  (with-eval-after-load 'cfengine
    '(progn
       (add-hook 'cfengine3-mode-hook
                 (lambda ()
                   (linum-mode 1)
                   (add-hook 'after-save-hook 'nickanderson/cfengine-policy-perms nil 'make-it-local)))))
progn (add-hook (quote cfengine3-mode-hook) (lambda nil (linum-mode 1) (add-hook (quote after-save-hook) (quote nickanderson/cfengine-policy-perms) nil (quote make-it-local))))
1
2
3
4
       (add-hook 'cfengine3-mode-hook
                 (lambda ()
                   (linum-mode 1)
                   (add-hook 'after-save-hook 'nickanderson/cfengine-policy-perms nil 'make-it-local)))
(lambda nil (linum-mode 1) (add-hook (quote after-save-hook) (quote nickanderson/cfengine-policy-perms) nil (quote make-it-local))) eldoc-mode

I like line numbers when I am doing policy.

Turn on line numbers for cfengine3-mode and set permissions of saved files to owner only. The Masterfiles Policy Framework restricts policy file permissions down by default, this helps to stay in line with those defaults, additionally it helps to avoid errors when testing locally.

> $ cf-agent -Kf ./example.cf
  error: File ./example.cf (owner 1000) is writable by others (security exception)

Zooming

Add these keys in to support familiar zooming of text with Ctrl+ and Ctrl-.

1
2
3
  ;; Familiar zooming with Ctrl+ and Ctrl-r
  (define-key global-map (kbd "C-+") 'text-scale-increase)
  (define-key global-map (kbd "C--") 'text-scale-decrease)

mu4e (Email)

All of my email accounts are currently hosted on google infrastructure (ewww i know). At any rate, changing the filename when moving messages is very important for mbsync to work correctly. Without this config option mbsync will begin to throw errors during sync.

1
2
  (require 'mu4e)
  (setq mu4e-change-filenames-when-moving t)

Since mu4e 0.9.16 which I have begun using the builtin contexts to help manage multiple email accounts.

 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
  (setq mu4e-contexts
        `(
          ,(make-mu4e-context
            :name "work"
            :enter-func (lambda () (mu4e-message "Switch to the CFEngine context"))
            ;; leave-fun not defined
            :match-func (lambda (msg)
                          (when msg
                            (mu4e-message-contact-field-matches msg
                                                                :to "nick.anderson@northern.tech")))
            :vars '(
              (setq mu4e-maildir-shortcuts
                    '( "/INBOX" . ?i)
                    ( "/[Gmail].Sent Mail" . ?s )
                    ( "/[Gmail].All Mail" . ?a )
                    ( "/[Gmail].Drafts" . ?d )
                    ( "/[Gmail].Trash" . ?t ))
              ( user-mail-address	     . "nick.anderson@northern.tech" )
              ( mu4e-sent-folder . "/CFEngine/[Gmail].Sent Mail" )
              ( mu4e-drafts-folder . "/CFEngine/[Gmail].Drafts" )
              ( mu4e-trash-folder . "/CFEngine/[Gmail].Trash" )
              ( mu4e-refile-folder . "/CFEngine/[Gmail].All Mail" )
		          ( user-full-name	    . "Nick Anderson" )
              ;; get-mail-command set to true because mail sync is happening via external processes but we still need to re-index the mailstore to realize the updates
              ( mu4e-get-mail-command . "true" )
              ( mu4e-update-interval . "300" )
              ( mu4e-view-show-images . "t" )
              ( mu4e-view-show-addresses . "t" )
              ( mu4e-compose-format-flowed . "t" )
		          ( mu4e-compose-signature . (concat "Nick Anderson\n"
		                                             "Doer of things, CFEngine\n"))))


          ,(make-mu4e-context
            :name "personal"
            :enter-func (lambda () (mu4e-message "Switch to the nick@cmdln.org context"))
            ;; leave-func not defined
            :match-func (lambda (msg)
                          (when msg
                            (mu4e-message-contact-field-matches msg
                                                                :to "nick@cmdln.org")))
            :vars '(
                    ( user-mail-address	     . "nick@cmdln.org"  )
                    ( user-full-name	    . "Nick Anderson" )
                    (mu4e-sent-folder . "/nick-at-cmdln/[Gmail].Sent Mail")
                    (mu4e-drafts-folder . "/nick-at-cmdln/[Gmail].Drafts")
                    (mu4e-trash-folder . "/nick-at-cmdln/[Gmail].Trash")
                    (mu4e-refile-folder . "/nick-at-cmdln/[Gmail].All Mail")
                    ( mu4e-get-mail-command . "true" )
                    ( mu4e-update-interval . "300" )
                    ( mu4e-view-show-images . "t" )
                    ( mu4e-view-show-addresses . "t" )
                    ( mu4e-compose-signature .
                                             (concat
                                              "Nick Anderson\n"
                                              ""))))
          ))

END of dotspacemacs/user-config

1
  )

Custom set variables and faces

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
  ;; Do not write anything past this comment. This is where Emacs will
  ;; auto-generate custom variable definitions.
  (custom-set-variables
   ;; custom-set-variables was added by Custom.
   ;; If you edit it by hand, you could mess it up, so be careful.
   ;; Your init file should contain only one such instance.
   ;; If there is more than one, they won't work right.
   '(org-id-link-to-org-use-id t)
   '(send-mail-function (quote smtpmail-send-it))
   '(smtpmail-smtp-server "localhost")
   '(smtpmail-smtp-service 25))
  (custom-set-faces
   ;; custom-set-faces was added by Custom.
   ;; If you edit it by hand, you could mess it up, so be careful.
   ;; Your init file should contain only one such instance.
   ;; If there is more than one, they won't work right.
   )