Spacemacs is referred for its evil integration, space-based bindings, and community contributed layers that collect, configure, and integrate groups of packages.
For how much they add to Emacs, motivations for personal layers are largely undocumented.
I introduce layers then discuss benefits, approaches, and gotchas with layer-based configurations.
I've migrated my entire
dotspacemacs/user-config into personal layers - now 6
lines vs 1,500.
See https://github.com/ekaschalk/.spacemacs.d for my viewer-friendly configuration .
This section is not a replacement for http://spacemacs.org/doc/LAYERS.html.
Layers are directories containing up to 5 files and possibly additional packages.
In load order:
Layer dependencies to load first.
Packages added or configured by the layer.
(setq my-layer-packages '(a-pkg (github-pkg :location (recipe :fetcher github :repo "github-user/repo-name")) (my-pkg :location local)))
Owned Packages: A layer owns a package if it defines
layer-name/init-pkg-name. All packages not defined in
dotspacemacs/additional/packagesshould have one and only one owner. It calls
use-package. Common options are
:initfor before load config,
:iffor loading if eg. a certain OS or executable is installed,
:afterfor enforcing load order, and
:defer tfor deferred loading.
(defun display/init-pretty-outlines () (use-package pretty-outlines :after outshine :config (progn (add-hook 'outline-mode-hook 'pretty-outline-set-display-table) (add-hook 'outline-minor-mode-hook 'pretty-outline-set-display-table) (add-hook 'emacs-lisp-mode-hook 'pretty-outline-add-bullets))))
Unowned Packages: A layer that does not own a package can configure it with
(defun config/pre-init-neotree () (evil-global-set-key 'normal (kbd "M-p") 'neotree-find-project-root)) (defun config/post-init-neotree () (setq neo-theme 'icons))
Local Packages: Personal packages at
Package agnostic functions belong here.
(defmacro with-face (STR &rest PROPS) "Return STR propertized with PROPS." `(propertize ,STR 'face (list ,@PROPS)))
Guarding against particular packages being installed:
(when (configuration-layer/package-usedp 'some-pkg) (defun my-func ()))
;; python/config.el (defvar python-tab-width 4 "Tab width value for python buffers") ;; init.el in dotspacemacs-configuration-layers (python :variables python-tab-width 2)
Configuration defined here will be loaded before the package init functions are executed. Layer dependencies are actually loaded prior to config.el.
This can be used for eg. setting theme updates with the
(setq theming-modifications `((solarized-dark (avy-background-face :foreground "#586e75") (font-lock-doc-face :foreground "#2aa198")) (solarized-light ...)))
(global-set-key (kbd "M-d") 'spacemacs/delete-window) ;; Evil will be loaded (evil-define-key '(normal visual motion) outline-minor-mode-map "gh" 'outline-up-heading)
While any organization can be used, I recommend at most these 5 layers covering common needs.
A Macros/Base Layer
A base layer that all personal layers inherit packages, macros, and common
functions from with
dash-functional and define
with-face, and other useful
All packages and their configuration and key-bindings that don't fit into any neat grouping.
When any package's init gets large, consider a local package. I maintain my
org-mode setup separately in a local
Anything, excluding spacemacs toggles, can be setup here. For instance:
(setq config-packages '(evil ...)) (defun config/post-init-evil () (setq evil-escape-key-sequence "jk") (setq evil-escape-unordered-key-sequence "true") (advice-add 'evil-ex-search-next :after 'config/scroll-to-center-advice) (advice-add 'evil-ex-search-previous :after 'config/scroll-to-center-advice))
I recommend this layer own all additional packages except themes, see gotchas.
Theme updates and display packages like
Due to how Spacemacs loads themes, I highly recommend declaring the
theming layer a dependency for theme updates. It is much more efficient should
you configure multiple themes, like light and dark versions, and as it is a
layer, it will be loaded prior to
config.el for proper code isolation.
I integrate and configure my local pretty packages here:
pretty-code : Program with custom ligatures and symbols, see <a href='/post/prettify-mode/'>mathematical notation in emacs</a>
pretty-eshell : Customize eshell information and faces, see <a href='/post/custom-eshell/'>making eshell your own</a>
pretty-fonts : All the icons and Fira Code ligature integration.
pretty-magit : Commit leaders, see <a href='/post/pretty-magit/'>pretty magit - integrating commit leaders</a>
pretty-outlines : Fancy outline bullets and ellipsis, see <a href='/post/outline-bullets/'>fancy outline bullets</a>
I find it useful to separate programming language configuration out from the config layer, though it is not necessary.
All personal packages that aren't display related I maintain in a single personal layer. This is only relevant if you write your own packages.
I setup my blogging and outline-jump packages here.
Layers must be declared in your
dotspacemacs-configuration-layers to take effect.
I've organized my layers into several sections:
(defvar dotspacemacs/layers/local '((macros :location local) (config :location local) (display :location local) (langs :location local) (personal :location local)) "Local layers housed in '~/.spacemacs.d/layers'.") (defvar dotspacemacs/layers/core '(better-defaults git org ...) "Layers I consider core to Spacemacs") (defvar dotspacemacs/layers/langs '(emacs-lisp ...) "Programming and markup language layers") (defvar dotspacemacs/layers/extra '(gnus graphviz ...) "Miscellaneous layers") (defun dotspacemacs/layers () (setq-default dotspacemacs-configuration-layer-path '("~/.spacemacs.d/layers/") dotspacemacs-configuration-layers (append dotspacemacs/layers/core dotspacemacs/layers/langs dotspacemacs/layers/extra dotspacemacs/layers/local) ...))
Migrating was mostly painless. However when things go wrong you lose access to your setup, an annoying development cycle. I encountered several Spacemacs idiosyncrasies to be aware of when using layers to replace my user-config.
Non-obvious errors to avoid:
The naming scheme of
setq layer-name-packages and
defun layer-name/init-pkg-name is strict.
Beware when refactoring that you adjust the layer name accordingly. Failure to
do so will result in the package's configuration not being loaded or in the case
of ownership, not being installed, rather than a direct error.
Some toggles like
spacemacs/toggle-highlight-long-lines-globally-on do not
belong in any layer and should be defined in your user-config. Six toggles are
now all that compose my
This goes for some toggles not explicitly owned by Spacemacs - trying to setup
fringe-mode failed for me even in a
is-linuxp and a few other OS utilities that conditionally setup
dotspacemacs/init variables like font size. Layers load after these variables
are set, so the utilities cannot be moved to a layer. Set them at the top of
Spacemacs layers load ordering causes issues for extra themes. Theme packages cannot be put in a layer. As a result, to use solarized I set:
;; ~/.spacemacs.d/init.el (defun dotspacemacs/layers () (setq-default dotspacemacs-additional-packages '(solarized-theme) ...)) (defun dotspacemacs/init () (setq-default dotspacemacs-themes '(solarized-dark solarized-light) ...))
Spacemacs Core Layers
Without doing a deep dive into Spacemacs core, you can expect the following
layers to always be loaded before all personal layers. This is how
dash is always available and
evil-define-key can be used in keybindings
g d or
(spacemacs/jump-to-definition) in emacs lisp mode to jump to
that layer's packages.el to check out its packages and configuration.
(configuration-layer/declare-layers '(spacemacs-base spacemacs-completion spacemacs-layouts spacemacs-editing spacemacs-editing-visual spacemacs-evil spacemacs-language spacemacs-misc spacemacs-modeline spacemacs-navigation spacemacs-org spacemacs-purpose spacemacs-visual))
These layers follow the same rules and principles as every other layer. If you have the curiosity, these layers make Spacemacs what it is.
Functionality provided here can be made use of by any layer, assuming those packages and layers are not explicitly excluded.
Those that value organization and robustness will find Spacemacs layers to improve on other configuration management methods.
Following Spacemacs conventions leads to predictable, friendly configurations.
Once you've become familiar with its conventions, there is no overhead.