dotfiles/org/config/spacemacs.org

104 KiB
Raw Blame History

Phundraks Spacemacs Configuration

Introduction

This file is the main source file for my Emacs configuration which contains most of the user code. It is exported thanks to Emacs code tangling from the original Org file which you can find on my dotfiles repository1 if you are reading the web version of it. You can also find there my .spacemacs2 and its code which isnt part of the present file. As you can see in my .spacemacs, at init-time, if Emacs detects the tangled configuration files are older than the Org file, then Emacs tangles them again, and then loads them.

Spacemacs layers and packages

Here will be our layer configuration set. Everything here is set with a setq-default in the dotspacemacs/layers function like so:

  (defun dotspacemacs/layers ()
    (setq-default
     ;; configuration goes here
     ))

General configuration

First, we need to tell Spacemacs which base distribution we are using. This is a layer contained in the directory +distribution. For now, available distributions are spacemacs-base and spacemacs (the default one).

  (setq-default dotspacemacs-distribution 'spacemacs)

We can seet a lazy installation of layers —i.e. layers are installed only when a file with a supported type is opened. Possible values are:

all
will lazy install any layer that support lazy installation even the layers listed in dotspacemacs-configuration-layers
unused
will lazy install only unused layers (i.e. layers not listed in the variable dotspacemacs-configuration-layers)
nil
disables the lazy installation feature and you have to explicitly list a layer in the variable dotspacemacs-configuration-layers to install it.

The default value is unused.

  (setq-default dotspacemacs-enable-lazy-installation 'unused)

If the following variable is non-nil, Spacemacs will ask for confirmation before installing a layer lazily. The default value is t.

  (setq-default dotspacemacs-ask-for-lazy-installation t)

Package management

It is possible to indicate to Spacemacs a list of additional paths where to look for configuration layers. Paths must have a trailing slash, i.e. ~/.mycontribs/. As you can see, I added none:

(setq-default dotspacemacs-configuration-layer-path '())

However, I do have additional packages I installed either from the Elpa or the Melpa. These are set in dotspacemacs-additional-packages, a 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 puth the configuration in dotspacemacs/user-config. To use a local version of a package, use the :location property, for instance:

  '(your-package :location "~/path/to/your-package/")

With the variable dotspacemacs-additional-packages, it is possible to install extra packages which are not already included in any layers. Dependencies should be explicitly included as they wont be resolved automatically. Here is a table of all the extra packages I use:

name of the package why is it installed
dired-du alternative to ncdu with Dired
doom-themes some cool themes
edit-indirect edit region in separate buffer
elcord rich integration of Emacs in Discord
eshell-git-prompt pimp my Eshell
kaolin-themes some cool themes
magit-gitflow integrate gitflow in Magit
meson-mode major mode for Meson build files
multiple-cursors I dont like the layer, I prefer this package alone
org-sidebar display on the side the outline of an Org buffer
outorg edit comments as Org-mode buffers
pinentry enter a GPG password from Emacs
visual-fill-column allow the use of fill-column in visual-line-mode
wttrin weather in Emacs
yasnippet-snippets snippets for YaSnippet

It is possible to also list packages that cannot be updated:

  (setq-default dotspacemacs-frozen-packages '())

And to list packages which wont be installed nor loaded:

(setq-default dotspacemacs-excluded-packages '())

Finally, it is possible to define the behaviour of Spacemacs when installing packages. Possible values are:

used-only
installs only explicitly used packages and deletes any unused packages as well as their unused dependencies
used-but-keep-unused
installs only the used packages but wont delete unused ones
all
installs all packages supported by Spacemacs and never uninstalls them.

The default value is used-only.

(setq-default dotspacemacs-install-packages 'used-only)

Layers

All layers are set one variable: dotspacemacs-configuration-layers. This variable is a list of layers, some of them will have some custom variables. Typically, the variable will be set like so:

  (setq-default dotspacemacs-configuration-layers
                '(emacs-lisp
                  helm
                  multiple-cursors
                  org
                  (shell :variables shell-default-height
                         30 shell-default-position 'bottom)
                  treemacs))

Checkers

The two first checkers I use are for spell and syntax checking. spell-checking is disabled by default, however it should auto-detect the dictionary to use.

  (spell-checking :variables
                  spell-checking-enable-by-default nil
                  spell-checking-enable-auto-dictionary t)
  syntax-checking

Completion

auto-completion is a layer enabled in order to provide auto-completion to all supported language layers. It is set so that the RET key has no behavior with this layer, however the TAB key cycles between candidates displayed by the auto-completion toolbox. I also want the autocompletion to include snippets in the popup, and the content of the popup is sorted by usage. It is also disabled for two modes: magit and Org.

  (auto-completion :variables
                auto-completion-complete-with-key-sequence-delay 0.2
                auto-completion-enable-help-tooltip 'manual
                auto-completion-enable-snippets-in-popup t
                auto-completion-enable-sort-by-usage t
                :disabled-for
                org
                git)

helm is also enabled, with its header disabled.

  (helm :variables helm-no-header t)

Email

As described below, I use Gnus as my main email client. Therefore, I have the gnus layer enabled:

gnus

Emacs

The first layer enabled in this category is better-defaults. I also made it so that when a command equivalent to C-a or C-e is pressed, the cursor will respectively first move to the beginning of code first before going past the indentation and to the end of the code before going to the end of the line before going over the end of the comments on the same line.

  (better-defaults :variables
                   better-defaults-move-to-beginning-of-code-first t
                   better-defaults-move-to-end-of-code-first t)

I also enabled ibuffer and made it so that buffers are sorted by projects.

  (ibuffer :variables
           ibuffer-group-buffers-by 'projects)

Most important of all, the org layer is also enabled. I enabled support for Epub exports, Github, Reveal.JS exports, and sticky headers. Project support is also enabled through files named TODOs.org. I also set the org-download folder for images in ~/Pictures/org/, and I set the RET key to follow org links if the cursor is on one.

  (org :variables
       org-enable-epub-support t
       org-enable-github-support t
       org-enable-reveal-js-support t
       org-enable-sticky-header t
       org-enable-org-journal-support t
       spaceline-org-clock-p t
       org-projectile-file "TODOs.org"
       org-download-image-dir "~/Pictures/org/"
       org-return-follows-link t)

The semantic layer is also enabled.

  semantic

File trees

In this category, I only enabled one layer: treemacs. In this layer, I set is so that treemacs syncs with my current buffer, and it automatically refreshes its buffer when there is a change in the part of the file system shown by treemacs.

  (treemacs :variables
            treemacs-use-follow-mode t
            treemacs-use-filewatch-mode t)

Fonts

In this category, again, one layer is enabled: unicode-fonts. This layer addssupport for the unicode-fonts package.

unicode-fonts

Fun

In this category, I only enabled two layers: selectric and xkcd.

selectric xkcd

Internationalization

In this category, I enabled the keyboard-layout layer to enable compatibility with the bépo layout. This layer, however, is disabled for magit, Dired and eww.

  (keyboard-layout :variables
                   kl-layout 'bepo
                   kl-disabled-configurations '(magit dired eww))

Programming languages

Domain-specific (DSLs)

In this category, I enabled support for the R programming language (the ess layer), the major-modes layer for the Arch Linux PKGBUILDs support, the prolog, emacs-lisp and scheme layers, support for the CSV format with the csv layer, the yaml language, shell scripting languages and support for the dot tool with the graphviz layer.

  ess major-modes prolog emacs-lisp scheme graphviz yaml shell-scripts

I also added support for HTML and CSS with the html layer, with the web formatting tool set to web-beautify, and the LSP layer compatibility enabled for CSS, less, SCSS and HTML.

 (html :variables
       web-fmt-tool 'web-beautify
       css-enable-lsp t
       less-enable-lsp t
       scss-enable-lsp t
       html-enable-lsp t)

The json layer is also enabled, with the format tool set to web-beautify.

 (json :variables
       json-fmt-tool 'web-beautify)

The LaTeX layer has also been enabled, with its default compiler set to XeLaTeX. I also enabled the auto-fill feature, the folding capacity and the “magic” symbols.

 (latex :variables
        latex-build-command "xelatex"
        latex-enable-auto-fill t
        latex-enable-folding t
        latex-enable-magic t)

The Markdown layer has been enabled, with support for live preview with vmd, and and automatic MMM-mode generation for C, C++, Python, Rust and Emacs Lisp.

 (markdown :variables
           markdown-live-preview-engine 'vmd
           markdown-mmm-auto-modes '("c"
                                     "c++"
                                     "python"
                                     "rust"
                                     ("elisp" "emacs-lisp")))
Frameworks

Only one framework support has been enabled so far, and is is for the Django framework.

  django
General-purpose

Among the layers I activated, the only one without any specific configuration is the asm layer for the Assembly language.

  asm

Next, you can find the C/C++ layer for which I set the default language for .h files to be C. I also enabled support for the C++11 standard, the Google coding style for C++, support for subprojects and organization of the include directives on a file save. I also set a couple of LSP-related variables, such as the LSP executable for C/C++ for its CCLS backend and some highlight variables.

  (c-c++ :variables
         c-c++-default-mode-for-headers 'c-mode
         c-c++-adopt-subprojects t
         c-c++-enable-google-style t
         c-c++-enable-c++11 t
         c-c++-backend 'lsp-ccls
         c-c++-lsp-executable "/usr/bin/ccls"
         c-c++-lsp-sem-highlight-method 'overlay
         c-c++-lsp-sem-highlight-rainbow t
         c++-enable-organize-includes-on-save t)

Dart has also been enabled, with a custom path to the SDK of the Dart server, and to the LSP server of Dart.

  (dart :variables
        dart-server-sdk-path "/opt/flutter/bin/cache/dart-sdk/"
        lsp-dart-sdk-dir "/opt/flutter/bin/cache/dart-sdk/")

When it comes to the Python layer, I set its backend and formatter to be bound to the LSP layer. Its fill columnn was also set to 80 characters, imports are sorted on save, and the tests can be run using either nose.el or pytest.

  (python :variables
          python-backend 'lsp
          python-sort-imports-on-save t
          python-fill-column 80
          python-test-runner '(pytest nose)
          python-formatter 'lsp)

With the Rust layer, the only custom configuration set is the backend being bound to the LSP layer.

  (rust :variables rust-backend 'lsp)

As regards the JavaScript layer, I set its backend to the LSP layer, and bound its format tool to web-beautify and its REPL is browser-based. I also want to include node_modules/.bin to be automatically added to the buffer local exec_path.

  (javascript :variables
              javascript-backend 'lsp
              javascript-fmt-tool 'web-beautify
              javascript-repl 'skewer
              node-add-modules-path t)

Readers

In this category, only the epub and pdf layers are enabled so I can read these files from Emacs directly.

epub pdf

Version control

Only the git layer is enabled in this category.

git

Themes

Here, the colors layer is the only one enabled. It activates support for identifiers colorization, and strings representing colors.

colors

Tools

In this category, the first layer to be enabled is the CMake layer for which I enabled support for the cmake-ide package.

  (cmake :variables
         cmake-enable-cmake-ide-support t)

Next, we have the Docker, Nginx, Pass (the standard Unix password manager), Prettier, Systemd, Imenu-list, Web-beautify, Dap, Helpful, and LSP layers enabled.

  docker imenu-list nginx pass prettier systemd web-beautify helpful dap lsp

We also have the RestClient layer enabled for which I enabled the Org compatibility support.

  (restclient :variables
              restclient-use-org t)

And finally, we also have the Shell layer for which I specified its default height when spawning at the bottom of the screen should be 40 lines high, and the default shell to invoke is Eshell.

  (shell :variables
         shell-default-height 40
         shell-default-position 'right
         shell-default-shell 'eshell)

Web Services

In this category, I have only enabled a layer for Twitter support.

twitter

Custom layers

Lastly, three custom layers have been enabled: a w3m layer, and two of my custom layers for Dired and for conlanging tools.

conlanging dired-phundrak w3m

Init

The dotspacemacs/init function is the one called at the very begining of the Spacemacs startup, before any kind of configuration, including the layer configuration. Only the values of the Spacemacs settings should be modified here. By default, every values are set in a setq-default sexp, and they represent all the supported Spacemacs settings. Hence, the function looks like this:

  (defun dotspacemacs/init ()
    (setq-default
     ;; default Spacemacs configuration here
     ))

Emacs with pdumper

It is possible to compile Emacs 27 from source with support for the portable dumper, as shown in Spacemacs EXPERIMENTAL.org file. I do not use this feature yet, as I am still on Emacs 26 provided from Arch Linuxs repositories, so Ill disable the Spacemacs support for this feature. The default value of this variable is nil.

  (setq-default dotspacemacs-enable-emacs-pdumper nil)

In case the support for pdumper was enabled, Spacemacs needs to know the name of the Emacs executable which supports such a feature. The executable must be in the users PATH. By default, the value of the variable is "emacs".

  (setq-default dotspacemacs-emacs-pdumper-executable-file "emacs")

And finally, we can name the Spacemacs dump file. This is the file that will be created by the portable dumper in the cache directory under the dumps sub-directory. To load it when starting Emacs, the parameter --dump-file should be added when invoking Emacs 27.1 executable from the command line, for instance:

  ./emacs --dump-file=~/.emacs.d/.cache/dumps/spacemacs.pdmp

The default value of this variable is "spacemacs.pdmp".

  (setq-default dotspacemacs-emacs-dumper-dump-file "spacemacs.pdmp")

Package managment and updates

Spacemacs core configuration can be updated via git commands using Github services. If Spacemacs is not set to the develop branch, it can check by itself if any update is available. However, I am using said branch, therefore I should set this variable to nil. The default value is nil.

  (setq-default dotspacemacs-check-for-update nil)

When it comes to package management, Spacemacs is able to store them in different directories depending on the version of Emacs used or based on other variables. I personally prefer to use the value emacs-version since it makes it easier to upgrade or downgrade Emacs without any conflict with the already installed packages. The default value is emacs-version.

  (setq-default dotspacemacs-elpa-subdirectory 'emacs-version)

Spacemacs has a capacity of performing rollbacks after updates. We can set the maximum number of rollback slots to keep in the cache. The default value is 5.

  (setq-default dotspacemacs-max-rollback-slots 5)

Elpa repository

It is possible to ask Emacs to use an HTTPS connection when contacting the Elpa whenever possible. This value should be set to nil when the user has no way to contact the Elpa though HTTPS, otherwise it is strongly recommended to let it set to t. This variable however has no effect if Emacs is launched with the parameter --insecure which forces the value of this variable to nil. The default value is t.

(setq-default dotspacemacs-elpa-https t)

We can set a maximum amount of seconds which will represent the maximum allowed time to contact the Elpa repository. By default, this setting is set on 5.

  (setq-default dotspacemacs-elpa-timeout 5)

Spacelpa repository

The Spacelpa repository is a Spacemacs-specific package repository. It is possible to use it as the primary source to install a locked version of a package. If the below value is set to nil, then Spacemacs will install the latest version of packages from MELPA. I personally dont use it, so I let it set to nil. The default value is nil.

(setq-default dotspacemacs-use-spacelpa nil)

If the below value is not nil, then the signature for the downloaded Spacelpa packages must be verified.

  (setq-default dotspacemacs-verify-spacelpa-archives t)

Editing style

By default, Spacemacs encourages the use of evil-mode, which brings vim keybinding in Emacs. Still, it has three different styles available:

  • vim, which goes full evil-mode usage and most adapted to Emacs newcomers, especially if they were used to vim before, with the use of a normal mode and an insert mode.
  • emacs which keeps an Emacs-like feel to the keybindings, without any difference between an insert or normal mode.
  • hybrid is a modification of the vim mode which brings the emacs style in insert mode, but otherwise behaves like the vim style in normal mode. This is the style I personally use.

The value can also be a list with the :variables keyword (similar to layers). Check the editing styles section of the documentation for details on available variables. The default value is vim.

  (setq-default dotspacemacs-editing-style '(hybrid :variables
                                                    hybrid-mode-enable-evilified-state t
                                                    hybrid-mode-default-state 'normal))

Spacemacs home configuration

The value below specifies the startup banner of Spacemacs. The 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 the 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. The default value is official.

(setq-default dotspacemacs-startup-banner 'official)

On the Spacemacs homepage, a list of elements can also be shown, be it recent files, projects, agenda items,… Each of the elements making up the list value of the below variable are pairs in the form (list-type . list-size). If the value is nil, then it is disabled. The possible values for list-type are:

recents
displays recently opened files
bookmarks
displays saved bookmarks
projects
displays projectile projects recently opened
agenda
displays upcoming events from Org-mode agendas
todos
displays recent TODOs detected in projectile projects

The order in which they are set in the below list affects their order on the Spacemacs startup page. List sikes may be nil, in which case spacemacs-buffer-startup-lists-length takes effect.

  (setq-default dotspacemacs-startup-lists '((recents . 15)
                                             (projects . 15)
                                             (agenda . 10)))

The below variable allows the startup page to respond to resize events. Its default value is t.

  (setq-default dotspacemacs-startup-buffer-responsive t)

Default major modes

The below variable sets a default major mode for a new empty buffer. Possible values are mode names such as text-mode, or nil to use Fundamental mode. The default value is text-mode, but I prefer to use org-mode by default.

(setq-default dotspacemacs-new-empty-buffer-major-mode 'org-mode)

Similarly, the below variable sets the default mode for the scratch buffer. Its default value is text-mode, but I also set it to use org-mode by default.

(setq-default dotspacemacs-scratch-mode 'org-mode)

By the way, it is possible to set a default message for the scratch buffer, such as “Welcome to Spacemacs!”. I prefer to keep it clean. The default value is nil.

(setq-default dotspacemacs-initial-scratch-message nil)

Visual configuration

Themes

Spacemacs makes it quite easy to use themes and organize them. The below value is a list of themes, the first of the list is loaded when Spacemacs starts. The user can press SPC T n to cycle to the next theme in the list.

  (setq-default dotspacemacs-themes '(doom-vibrant doom-nord spacemacs-dark doom-one
                                                   doom-opera doom-dracula doom-molokai doom-peacock
                                                   doom-sourcerer doom-spacegrey kaolin-dark
                                                   kaolin-aurora kaolin-bubblegum kaolin-galaxy
                                                   kaolin-mono-dark kaolin-temple kaolin-valley-dark))

Emacs also makes use of themes for the Spaceline at the bottom of buffers. Supported themes are:

  • spacemacs
  • all-the-icons
  • custom
  • doom (the one I use)
  • vim-powerline
  • vanilla

The first three are Spaceline themes. doom is the Doom-Emacs mode-line, and vanilla is the default Emacs mode-line. custom is a user defined theme, refer to Spacemacs DOCUMENTATION.org file for more info on how to create your own Spaceline theme. Value can be a symbol or list with additional properties. The default value is '(spacemacs :separator wave :separator-scale 1.5)).

  (setq-default dotspacemacs-mode-line-theme '(doom
                                               :separator wave
                                               :separator-scale 1.0))

It is also possible to color the cursor depending on which mode Spacemacs is in, in order to mach the state color in GUI Emacs. The default value is t.

  (setq-default dotspacemacs-colorize-cursor-according-to-state t)

The below variable sets either the default font or a prioritized list of fonts to be used by Emacs.

  (setq-default dotspacemacs-default-font '("FiraCode Nerd Font Mono" :size 8.0
                                            :weight normal
                                            :width normal))

Other on-screen elements

which-key is a helper which displays available keyboard shortcuts. This variable sets in seconds the time Spacemacs should wait between a key press and the moment which-key should be shown.

  (setq-default dotspacemacs-which-key-delay 0.4)

This variable sets which-key's frame position. Possible values are:

  • right
  • bottom
  • right-then-bottom

right-then-bottom tries to display the frame to the right, but if there is insufficient space it displays it at the bottom. The default value is bottom.

  (setq-default dotspacemacs-which-key-position 'bottom)

This controls where switch-to-buffer displays the buffer. If the value is 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. The default value is nil.

  (setq-default dotspacemacs-switch-to-buffer-prefers-purpose nil)

If this variable is 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. The default value is t.

  (setq-default dotspacemacs-loading-progress-bar t)

If the value is non-nil, Emacs will show the title of the transient states. The default value is t.

  (setq-default dotspacemacs-show-transient-state-title t)

If non-nil, this will show the color guide hint for transient state keys. The default value is t.

  (setq-default dotspacemacs-show-transient-state-color-guide t)

If non-nil, unicode symbols are displayed in the mode line. If you use Emacs as a daemon and want unicode characters only in GUI set the value to quoted display-graphic-p. The default value is t.

  (setq-default 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. The default value is t.

  (setq-default dotspacemacs-smooth-scrolling t)

The following value controls the line number activation. If set to t, relative or visual then line numbers are enabled in all prog-mode and text-mode derivatives. If set to relative, line numbers are relative. If set to visual, line numbers are also relative, but only visual lines are counted. For example, folded lines will not be counted and wrapped lines are counted as multiple lines. This variable can also be set to a property list for finer control:

  '(:relative nil
    :visual nil
    :disabled-for-modes dired-mode
                        doc-view-mode
                        markdown-mode
                        org-mode
                        pdf-view-mode
                        text-mode
    :size-limit-kb 1000)

When used in a plist, visual takes precendence over relative.

  (setq-default dotspacemacs-line-numbers '(:relative nil
                                            :enabled-for-modes prog-mode))

Select a scope to highlight delimiter. Possible values are:

  • any
  • current
  • all
  • nil

The default value is all (highlights any scope and emphasis the current one).

  (setq-default dotspacemacs-highlight-delimiters 'all)

After a certain amount of time in seconds, Spacemacs can zone-out. The default value is nil. I set it so Spacemacs zones out after 15 minutes.

  (setq-default dotspacemacs-zone-out-when-idle 900)

Run spacemacs/prettify-org-buffer when visiting the README.org files of Spacemacs. The default value is nil.

  (setq-default dotspacemacs-pretty-docs nil)

Appearance of Emacs frames

Starting from Emacs 24.4, it is possible to make the Emacs frame fullscreen when Emacs starts up if the variable is set to a non-nil value. The default value is nil.

  (setq-default dotspacemacs-fullscreen-at-startup nil)

This variable is to be used if the user does not want to use native fullscreen with spacemacs/toggle-fullscreen. This disables for instance the fullscreen animation under OSX. The default value is nil.

  (setq-default dotspacemacs-fullscreen-use-non-native nil)

If you do not start Emacs in fullscreen at startup, you might want it to be maximized by default. If the value for the variable below is set to be non-nil, the frame will be maximized. This can only work if dotspacemacs-fullscreen-at-startup is set to nil, and it is only available from Emacs 24.4 onwards. The default value is nil.

(setq-default dotspacemacs-maximized-at-startup nil)

If non-nil, the frame is undecorated when Emacs starts up. Combine this with the variable dotspacemacs-maximized-at-startup in OSX to obtain borderless fullscreen. The default value is nil.

  (setq-default dotspacemacs-undecorated-at-startup nil)

You can also set a transparency level for Emacs when you toggle the transparency of the frame with toggle-transparency. The value of the transparency, going from 0 to 100 in increasing opacity, describes the transparency level of a frame when its active or selected. The default value is 90.

  (setq-default dotspacemacs-active-transparency 95)

Similarly, you can set a value from 0 to 100 in increasing opacity which describes the transparency level of a frame when its inactive or deselected. The default value is 90.

  (setq-default dotspacemacs-inactive-transparency 80)

The variable below sets the format of frame title. You can use:

%a
the abbreviated-file-name or buffer-name
%t
projectile-project-name
%I
invocation-name
%S
system-name
%U
contents of $USER
%b
buffer name
%f
visited file name
%F
frame name
%s
process status
%p
percent of buffer above top of window, or Top, Bot, or All
%P
percent of buffer above bottom of window, perhaps plus Top, or Bot, or All
%m
mode name
%n
Narrow if appropriate
%z
mnemonics of buffer, terminal, and keyboard coding systems
%Z
like %z, but including the end-of-line format

The default value is "%I@%S".

  (setq-default dotspacemacs-frame-title-format "%b (%m)")

Format specification for setting the icon title format. The default value is nil, same as frame-title-format.

  (setq-default dotspacemacs-icon-title-format nil)

Spacemacs leader keys and shortcuts

The below setting sets the Spacemacs leader key. By default, this is the SPC key.

  (setq-default dotspacemacs-leader-key "SPC")

Once the leader key has been pressed, it is possible to set another key in order to call Emacs command M-x. By default, it is again the SPC key.

  (setq-default dotspacemacs-emacs-command-key "SPC")

It is also possible to invoke Vim Ex commands with the press of a key, and by default it is the : key.

  (setq-default dotspacemacs-ex-command-key ":")

The below variable sets the leader key accessible in emacs-state and insert-state:

  (setq-default dotspacemacs-emacs-leader-key "M-m")

The major mode leader key is a shortcut key which is the equivalent of pressing <leader> m. Set it to nil to disable it. Its default value is ,.

  (setq-default dotspacemacs-major-mode-leader-key ",")

In emacs-state and insert-state, the same major mode leader key can be accessible from another shortcut, which by default is C-M-m.

  (setq-default 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 and TAB, and C-m and RET. Setting it to a non-nil value allows for separate commands under C-i and TAB, and C-m and RET. In the terminal, these pairs are generally indistinguishable, so this only works in the GUI. The default value is nil.

  (setq-default dotspacemacs-distinguish-gui-tab nil)

Layouts

The variable belows sets the name of the default layout. Its default value is "Default".

  (setq-default dotspacemacs-default-layout-name "Default")

If non-nil, the default layout name is displayed in the mode-line. The default value is nil.

  (setq-default dotspacemacs-display-default-layout nil)

If non-nil, then the last auto saved layouts are resumed automatically upon start. The default value is nil.

  (setq-default dotspacemacs-auto-resume-layouts nil)

If non-nil, the layout name will be auto-generated when creating new layouts. It only has an effect when using the “jump to layout by number” command. The default value is nil.

  (setq-default dotspacemacs-auto-generate-layout-names nil)

Files-related settings

The below value sets the size in MB above which Spacemacs will prompt to open the file literally in order to avoid preformance issues. Opening a file literally means that no major or minor mode is active. The default value is 1.

(setq-default dotspacemacs-large-file-size 5)

This variable sets the location where to auto-save files. Possible values are:

original
auto-saves files in-place
cache
auto-saves files in another file stored in the cache directory
nil
disables auto-saving.

The default value is cache.

(setq-default dotspacemacs-auto-save-file-location 'original)

Emacs server

Emacs can be launched as a server if the following value is set to non-nil and if one isnt already running. The default value is nil.

  (setq-default dotspacemacs-enable-server nil)

You can also set a custom emacs server socket location. If the value is nil, Emacs will use whatever the Emacs default is, otherwise a directory path like "~/.emacs.d/server". It has no effect if dotspacemacs-enable-server is nil.

  (setq-default dotspacemacs-server-socket-dir nil)

It is also possible to tell Emacs that the quit function should keep the server open when quitting. The default value is nil.

  (setq-default dotspacemacs-persistent-server t)

Miscellaneous

This value changes the folding method of code blocks. The possible values are either evil, the default value, or origami.

  (setq-default dotspacemacs-folding-method 'evil)

If non-nil, smartparens-strict-mode will be enabled in programming modes. The default value is nil.

  (setq-default 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 temporarily disabled by pressing C-q before ). The default value is nil.

  (setq-default dotspacemacs-smart-closing-parenthesis nil)

List of search tool executable names. Spacemacs uses the first installed tool of the list. Supported tools are:

  • rg
  • ag
  • pt
  • ack
  • grep

The default value is '("rg" "ag" "pt" "ack" "grep").

  (setq-default dotspacemacs-search-tools '("rg" "ag" "pt" "ack" "grep"))

Delete whitespace while saving buffer. Possible values are:

all
aggresively delete empty lines and long sequences of whitespace
trailing
only detele the whitespace at end of lines
changed
to delete only whitespace for changed lines
nil
disable cleanup

The default value is nil.

  (setq-default dotspacemacs-whitespace-cleanup nil)

User Initialization

While Emacs and especially Spacemacs loads, I want it to initialize some elements and load some packages. First of all, I want it to load my private Emacs config file:

(load "~/.emacs.d/private/private_emacs.el")

Then, I want a couple of requires:

  (require 'org-id)
  (require 'package)
  (require 'ox-latex)
  (require 'ox-publish)

I also want to load whats in icons-in-terminal so I can use them in various packages in Emacs:

  (add-to-list 'load-path "~/.local/share/icons-in-terminal/")

I would also like to enable the setup of flycheck for Rust when Flycheck is loaded:

  (add-hook 'flycheck-mode-hook #'flycheck-rust-setup)

By default, Flyspell should be disabled and only enabled manually.

  (flyspell-mode 0)

Finally, here is a quick workaround for Tramp, sometimes it cannot connect to my hosts if I dont have this code snippet.

  (setq tramp-ssh-controlmaster-options
        "-o ControlMaster=auto -o ControlPath='tramp.%%C' -o ControlPersist=no")

User Configuration

ASM configuration

The first thing I will set with my ASM configuration is where the reference PDF is located.

  (setq x86-lookup-pdf "~/Documents/code/asm/Intelx86/325383-sdm-vol-2abcd.pdf")

I will also modify what the comment character is, from a ; to a #:

  (setq asm-comment-char ?\#)

C/C++

As the C/C++ syntax is checked by flycheck, lets make sure we are using the latest standard available, that is C++17 and C17, from Clang.

  (add-hook 'c-mode-hook
            (lambda ()
              (setq flycheck-clang-language-standard "c17")))
  (add-hook 'c++-mode-hook
            (lambda ()
              (setq flycheck-clang-language-standard "c++17")))

Custom functions

In this section, I will put my various custom functions that do not fit in other sections and which are more oriented towards general usage throughout Emacs and in Elisp code.

Almost all of my code snippets will be prefixed by either my name or the name of the package or layer they are part of, unless they are an explicit overwrite of a function that already exists.

phundrak/fill-paragraph

This function was created in order to bind to another keyboard shortcut the already existing C-u M-q which I cannot type with evil-mode unless Im in insert mode.

(defun phundrak/fill-paragraph ()
  (interactive)
  (let* ((current-prefix-arg 4))
    (call-interactively 'fill-paragraph)))

terminal-here-default-terminal-command

This function is actually an overwrite of the default one which apparently does not work on my machine. This function is called by terminal-here-launch and spawns an external terminal emulator in the directory emacs was in when the terminal was invoked. I simply point out to this function the name of my terminal emulator. Here is the code:

  (defun terminal-here-default-terminal-command (_dir)
    '("st"))

Dart configuration

For Dart, I mainly declared some custom shortcuts bound to dart-mode related to flutter, so nothing too exciting here. Some prefix are declared in order to avoid the shortcuts in helm to show up as just custom.

  (spacemacs/declare-prefix-for-mode 'dart-mode "o" "user-defined")
  (spacemacs/declare-prefix-for-mode 'dart-mode "of" "flutter")
  (spacemacs/declare-prefix-for-mode 'dart-mode "ofr" "flutter-run")

Now, for the shortcuts themselves:

  (spacemacs/set-leader-keys-for-major-mode 'dart-mode
    "ofH" 'flutter-hot-restart
    "ofh" 'flutter-hot-reload
    "ofq" 'flutter-quit
    "ofr" (lambda () (interactive) (flutter-run "-v"))
    "ofs" 'flutter-screenshot)

Dired

When it comes to dired, I chose do modify some elements on how things are sorted and shown, but there isnt much configuration. First, I want to always copy folders in a recursive way, no questions asked.

  (setq dired-recursive-copies 'always)

Also, when I have two Dired buffers opened side by side, I generally want them to interact, for example if I want to move something around. So, lets tell Emacs that:

  (setq dired-dwim-target t)

Finally, lets tell Dired how to sort the elements to be displayed: directories first, non-hidden first.

  (setq dired-listing-switches "-ahl --group-directories-first")

By the way, lets enable org-download when we are in a Dired buffer:

  (add-hook 'dired-mode-hook 'org-download-enable)

Emacs Lisp

Here will be stored my configuration directly related to Emacs Lisp, including some functions or default modes.

Enable eldoc-mode by default

By default, if some Elisp code is opened, I want to enable eldoc-mode so I can easily get some documentation on the symbols in the source code. This is done via the use of hooks.

  (add-hook 'prog-mode-hook 'eldoc-mode)

phundrak/write-to-buffer

I was very surprised when I discovered no such function exists in Elisp. This function basically writes a string into a buffer, and optionally switches the user to the buffer. Here is the code for that function:

  (defun write-to-buffer (input-string outputbuf &optional switchbuf)
    "Writes `input-string' to the specified `output-buffer'. If
  `switch-buffer' is non-nil, the active buffer will switch to the
  output buffer; otherwise, it will take the user back to their
  initial buffer. Works with `input-string' as a string or a list
  of strings."
    (let ((oldbuf (current-buffer)))
      (switch-to-buffer outputbuf)
      (cond ((char-or-string-p input-string) (insert input-string))
            ((listp input-string) (dolist (elem input-string)
                                    (insert (format "%s\n" elem)))))
      (if switchbuf
          (switch-to-buffer oldbuf))))

Eshell

Eshell is a built-in shell available from Emacs which I use almost as often as Fish. Some adjustments are necessary for making this shell usable for me.

Environment variables

Some environment variables need to be correctly set so Eshell can correctly work. The first environment variable to be set is the PATH, as I have a couple of directories where executables are located. Lets add them to our path.

  (setenv "PATH"
          (concat
           (getenv "HOME") "/.pub-cache/bin"
           ":" (getenv "HOME") "/.local/bin"
           ":" (getenv "HOME") "/go/bin"
           ":" (getenv "HOME") "/.cargo/bin"
           ":" (getenv "HOME") "/.gem/ruby/2.6.0/bin"
           ":" (getenv "PATH")))

I would also like to set two environment variables related to Dart development: the DART_SDK and ANDROID_HOME variables.

  (setenv "DART_SDK" "/opt/dart-sdk/bin")
  (setenv "ANDROID_HOME" (concat (getenv "HOME") "/Android/Sdk/"))

Finally, Id like to add a custom directory to the PKG_CONFIG_PATH:

  (setenv "PKG_CONFIG_PATH" (concat
                             "/usr/local/lib/pkgconfig/" ":"
                             (getenv "PKG_CONFIG_PATH")))

Custom functions

When Im in Eshell, sometimes I wish to open multiple files at once in Emacs. For this, when I have several arguments for find-file, I want to be able to open them all at once. Lets modify find-file like so:

  (defadvice find-file (around find-files activate)
    "Also find all files within a list of files. This even works recursively."
    (if (listp filename)
        (loop for f in filename do (find-file f wildcards))
      ad-do-it))

I also want to be able to have multiple instances of Eshell opened at once. For that, I declared the function eshell-new that does exactly that.

  (defun eshell-new()
    "Open a new instance of eshell."
    (interactive)
    (eshell 'N))

Aliases

Just like most shells, it is possible to declare in Eshell aliases. First, I would like to be able to use open to open files in Emacs:

  (defalias 'open 'find-file)

I also have openo which allows me to perform the same action, but in another window:

  (defalias 'openo 'find-file-other-window)

The function yes-or-no-p is also aliased to y-or-n-p so I only have to answer by y or n instead of typing yes or no.

  (defalias 'yes-or-no-p 'y-or-n-p)

For some ease of use, Ill also declare list-buffers as an alias of ibuffer.

  (defalias 'list-buffers 'ibuffer)

Visual commands

With Eshell, some commands dont work very well, especially commands that create a TUI. So, lets declare them as visual commands or subcommands:

  (setq eshell-visual-commands
        '("fish" "zsh" "bash" "tmux" "htop" "top" "vim" "bat" "nano")
        eshell-visual-subcommands
        '("git" "log" "l" "diff" "show"))

Eshell theme

As with most shells, again, it is possible to customize the appearance of the Eshell prompt. First, we need to declare a macro so we can set a face with properties:

  (defmacro with-face (str &rest properties)
    `(propertize ,str 'face (list ,@properties)))

Now, lets declare a function that will abbreviate the current pwd fish-shell style.

  (defun eshell/abbr-pwd ()
    (let ((home (getenv "HOME"))
          (path (eshell/pwd)))
      (cond
       ((string-equal home path) "~")
       ((f-ancestor-of? home path) (concat "~/" (f-relative path home)))
       (path))))

Now, lets declare our prompt:

  (defun eshell/my-prompt ()
    (let ((header-bg "#161616"))
      (concat
       (with-face (eshell/abbr-pwd) :foreground "#008700")
       "\n"
       (if (= (user-uid) 0)
           (with-face "➜" :foreground "red")
         (with-face "➜" :foreground "#2345ba"))
       " ")))

Now, lets declare our prompt regexp and our prompt functions:

  (setq eshell-prompt-regexp "^[^#$\n]*[#$] "
        eshell-prompt-function 'eshell/my-prompt)

Finally, lets declare the theme of our shell:

  (eshell-git-prompt-use-theme 'powerline)

File extensions

Sometimes, Emacs doesnt recognize or misrecognizes some extensions, resulting in a wrong mode set for said file. Lets fix that by associating the extension with the desired mode:

  (dolist (e '(("xml" . web-mode)
               ("xinp" . web-mode)
               ("aiml" . web-mode)
               ("C" . c++-mode)
               ("dconf" . conf-mode)
               ("yy" . bison-mode)
               ("ll" . flex-mode)
               ("s" . asm-mode)
               ("pl" . prolog-mode)
               ("l" . scheme-mode)
               ("vs" . glsl-mode)
               ("fs" . glsl-mode)))
    (push (cons (concat "\\."
                        (car e)
                        "\\'") (cdr e))
          auto-mode-alist))

We also have a couple of extensions which should all be in conf-unix-mode, lets indicate that to Emacs:

  (dolist (e '("service" "timer" "target" "mount" "automount"
               "slice" "socket" "path" "netdev" "network"
               "link"))
    (push (cons (concat "\\." e "\\'") 'conf-unix-mode)
          auto-mode-alist))

Gnus

Here comes my Gnus configuration. Gnus is an email client I use daily to read, manage, answer to and forward messages I receive by email.

Shortcuts

Some shortcuts needed to be redefined in order for Evil to work well with Gnus. Here is first the declaration of a prefix:

  (spacemacs/declare-prefix "og" "gnus")

And here are said shortcuts. As described above in the shortcuts chapter, these Spacemacs shortcuts are invoked with the SPC leader key.

  (spacemacs/set-leader-keys
    "ogD" 'turn-on-gnus-dired-mode
    "ogd" 'gnus-summary-delete-article
    "ogf" 'gnus-summary-mail-forward
    "ogo" 'my-gnus-group-list-subscribed-groups
    "ogr" 'gnus-summary-insert-new-articles
    "ogs" 'message-send-and-exit)

Hooks

To sort by topics my different mailboxes and folders, I use the gnus-topic-mode minor mode. To get it active by default, I use the following hook to activate it:

  (add-hook 'gnus-group-mode-hook 'gnus-topic-mode)

Mail account configuration

This section will be tangled in ~/.gnus.el.

I only use one email account with Gnus: lucien@phundrak.com. Here is how I configured it:

  (setq gnus-secondary-select-methods '((nnimap "lucien@phundrak.com"
                                                (nnimap-address "mail.phundrak.com")
                                                (nnimap-server-port 143)
                                                (nnimap-stream starttls)))
        message-send-mail-function 'smtpmail-send-it
        smtpmail-smtp-server "mail.phundrak.com"
        smtpmail-stream-type 'starttls
        smtpmail-smtp-service 587
        gnus-message-archive-method '(nnimap "mail.phundrak.com")
        gnus-message-archive-group "Sent"
        nnml-directory "~/Mails"
        message-directory "~/Mails"
        gnus-fetch-old-headers 'some
        mm-discouraged-alternatives '("text/html" "text/richtext"))

General options

This section will be tangled in ~/.gnus.el.

I want to use at one point the Emacs Application Framework which is set to be able one day to render Gnus emails, but for now I am using w3m to render HTML emails I receive.

  (setq mm-text-html-renderer 'w3m)

I also want Gnus to use the cache in case I need to navigate my emails offline:

  (setq gnus-use-cache t)

Lets set a quick organization of the Gnus folders, the format in which sent messages should be saved, and the typology of Gnus topics:

  (eval-after-load 'gnus-topic
    '(progn
       (setq gnus-message-archive-group '((format-time-string "sent.%Y")))
       (setq gnus-topic-topology '(("Gnus" visible)
                                   (("lucien@phundrak.com" visible nil nil))))
       (setq gnus-topic-alist '(("lucien@phundrak.com" ; the key of the topic
                                 "nnimap+lucien@phundrak.com:INBOX"
                                 "nnimap+lucien@phundrak.com:Sent"
                                 "nnimap+lucien@phundrak.com:Drafts")
                                ("Gnus")))))

Visual configuration

This section will be tangled in ~/.gnus.el.

I get it that it used to be a good option with 4/3 screens, but frankly opening an email at the bottom of the frame instead of the side of the frame does not look good anymore. So, lets fix that:

  (gnus-add-configuration
   '(article (horizontal 1.0 (summary .4 point) (article 1.0))))

LSP

When it comes to the LSP layer, there are some options which are not enabled by default that I want to use, especially some modes I want to take advantage of. This is why I enable first the lsp-treemacs-sync-mode so treemacs is LSP aware:

  (lsp-treemacs-sync-mode 1)

I also enable some layers related to dap, the Debug Adapter Protocol, which works really nicely with LSP. Lets enable Daps modes:

  (dap-mode 1)
  (dap-ui-mode 1)
  (dap-tooltip-mode 1)

Finally, I also want the documentation tooltip to show up when the cursor is above a documented piece of code or symbol. Lets enable that too:

  (tooltip-mode 1)

Miscellaneous

I have a lot of variables that need to be set but dont fall in any other category, so Ill collect them here.

I have this regexp for detecting paragraphs.

(setq paragraph-start "\f\\|[ \t]*$\\|[ \t]*[-+*] ")

Evil

As a user of Evil, Im sometimes pissed when I accidentally press C-u and it gets me to the top of the document. So, lets disable it:

  (setq evil-want-C-u-scroll nil)

Default modes

Some buffers sometimes wont have a default mode at all, such as the *scratch* buffer. In any vanilla configuration, they will then default to text-mode. I personally prefer org-mode to be my default mode, so lets set it so!

  (setq edit-server-default-major-mode 'org-mode)

I also want to have by default some aggressive indentation in my source files. Lets enable that:

  (global-aggressive-indent-mode 1)

However, I do not wish to see it activated for Dart mode, so lets exclude it:

  (add-to-list 'aggressive-indent-excluded-modes 'dart-mode)

Hooks

I also have some hooks I use for enabling some major and minor modes. The first one here allows the execution of the deletion of trailing space each time I save a file.

  (add-hook 'before-save-hook 'delete-trailing-whitespace)

I also want to always be in visual-line-mode so Emacs soft-wraps lines that are too long for the buffer they are displayed in.

  (add-hook 'prog-mode-hook 'visual-line-mode)

I also want for some non-programming modes to enable a hard-limit in terms of how many characters can fit on one line. The modes that benefit from that are message-mode, org-mode, text-mode and markdown-mode.

  (mapc (lambda (x)
       (add-hook x 'auto-fill-mode)
       (add-hook x 'visual-line-mode))
     '(message-mode-hook
       org-mode-hook
       text-mode-hook
       markdown-mode-hook))

Pinentry

Pinentry should use the loopback mode when communicating with GnuPG. Lets set it so:

(setq epa-pinentry-mode 'loopback)

Prettified symbols

Just because it is pleasing to the eye, some symbols in source code get prettified into simpler symbols. Here is the list of symbols that are to be prettified. You can see in the corresponding comment what symbol will be displayed.

  (setq prettify-symbols-alist '(("lambda" . 955) ; λ
                                 ("->" . 8594)    ; →
                                 ("<->" . 8596)   ; ↔
                                 ("<-" . 8592)    ; ←
                                 ("=>" . 8658)    ; ⇒
                                 ("<=>" . 8860)   ; ⇔
                                 ("<=" . 8656)    ; ⇐
                                 ("mapc" . 8614)  ; ↦
                                 ("map" . 8614)   ; ↦
                                 (">>" . 187)     ; »
                                 ("<<" . 171)     ; «
                                 ))

Twittering mode

For twittering-mode, a Twitter major mode for Emacs, I want to encrypt my data using a master password, which I do thanks to this option:

  (setq twittering-use-master-password t)

Wttr.in cities

Thanks to the wttrin package, I can get the weather forecast in Emacs for a couple of cities. I just need to specify them to Emacs like so:

  (setq wttrin-default-cities '("Aubervilliers" "Paris" "Lyon" "Nonières"
                                "Saint Agrève"))

Nov-mode

nov-mode is the mode used in the Epub reader. Here I will write a little function that I will call through a hook each time Im opening a new EPUB file.

  (defun my-nov-font-setup ()
    (face-remap-add-relative 'variable-pitch :family "Charis SIL"
                             :size 16
                             :height 1.0))

Lets bind this function to the nov-mode hook. By the way, well also enable the visual-line-mode here, just in case.

  (mapc (lambda (mode)
          (add-hook 'nov-mode-hook mode))
        '('my-nov-font-setup 'visual-line-mode))

Lets also set the maximum length of the lines in nov-mode:

  (setq nov-text-width 80)

Python

Emacs throws me an error about the python interpreter, lets silence it:

  (setq python-shell-completion-native-disabled-interpreters '("python"))

Org-mode

Org-mode is probably one of the best if not the best Emacs feature I have ever discovered. It is awesome for writing documents, regardless of the format you need it to be exported to, for agenda management, and for literary programming, such as with this document.

  (with-eval-after-load 'org
    ;; configuration goes here
    )

Custom org-mode functions

We begin with a couple of custom functions that I use in my org-mode files.

Custom and unique headings ID

The first ones are dedicated to provide org-mode headings a fixed and unique ID that wont change over time. This code was taken from https://writequit.org/articles/emacs-org-mode-generate-ids.html. The first functions job is to create these unique IDs

  (defun eos/org-id-new (&optional prefix)
    "Create a new globally unique ID.

  An ID consists of two parts separated by a colon:
  - a prefix
  - a   unique   part   that   will   be   created   according   to
    `org-id-method'.

  PREFIX  can specify  the  prefix,  the default  is  given by  the
  variable  `org-id-prefix'.  However,  if  PREFIX  is  the  symbol
  `none', don't  use any  prefix even if  `org-id-prefix' specifies
  one.

  So a typical ID could look like \"Org-4nd91V40HI\"."
    (let* ((prefix (if (eq prefix 'none)
                       ""
                     (concat (or prefix org-id-prefix)
                             "-"))) unique)
      (if (equal prefix "-")
          (setq prefix ""))
      (cond
       ((memq org-id-method
              '(uuidgen uuid))
        (setq unique (org-trim (shell-command-to-string org-id-uuid-program)))
        (unless (org-uuidgen-p unique)
          (setq unique (org-id-uuid))))
       ((eq org-id-method 'org)
        (let* ((etime (org-reverse-string (org-id-time-to-b36)))
               (postfix (if org-id-include-domain
                            (progn
                              (require 'message)
                              (concat "@"
                                      (message-make-fqdn))))))
          (setq unique (concat etime postfix))))
       (t (error "Invalid `org-id-method'")))
      (concat prefix unique)))

Now, lets see the function that will be used to get the custom id of a heading at point. If the function does not detect any custom ID, then one should be created and inserted.

  (defun eos/org-custom-id-get (&optional pom create prefix)
    "Get the CUSTOM_ID property of the entry at point-or-marker POM.
     If POM is nil, refer to the  entry at point. If the entry does
     not have an CUSTOM_ID, the function returns nil. However, when
     CREATE  is non  nil, create  a  CUSTOM_ID if  none is  present
     already. PREFIX will be passed through to `eos/org-id-new'. In
     any case, the CUSTOM_ID of the entry is returned."
    (interactive)
    (org-with-point-at pom
      (let ((id (org-entry-get nil "CUSTOM_ID")))
        (cond
         ((and id
               (stringp id)
               (string-match "\\S-" id)) id)
         (create (setq id (eos/org-id-new (concat prefix "h")))
                 (org-entry-put pom "CUSTOM_ID" id)
                 (org-id-add-location id
                                      (buffer-file-name (buffer-base-buffer)))
                 id)))))

Finally, this is the function that gets called on file saves. If the function detects auto-id:t among the org options in the #+OPTIONS: header, then the above function is called.

  (defun eos/org-add-ids-to-headlines-in-file ()
    "Add CUSTOM_ID properties to all headlines in the current
     file which do not already have one. Only adds ids if the
     `auto-id' option is set to `t' in the file somewhere. ie,
     ,#+OPTIONS: auto-id:t"
    (interactive)
    (save-excursion
      (widen)
      (goto-char (point-min))
      (when (re-search-forward "^#\\+OPTIONS:.*auto-id:t"
                               (point-max)
                               t)
        (org-map-entries (lambda ()
                           (eos/org-custom-id-get (point)
                                                  'create))))))

Lets add a hook to the above function so it is called automatically on save, and only in read-write functions.

  (add-hook 'org-mode-hook
            (lambda ()
              (add-hook 'before-save-hook
                        (lambda ()
                          (when (and (eq major-mode 'org-mode)
                                     (eq buffer-read-only nil))
                            (eos/org-add-ids-to-headlines-in-file))))))

Org babel languages

One of the amazing features of org-mode is its literary programming capacities by running code blocks from within Org-mode itself. But for that, only a couple of languages are supported directly by Org-mode itself, and they need to be activated. Here are the languages I activated in my Org-mode configuration:

  (org-babel-do-load-languages
   'org-babel-load-languages
   '((C          . t)
     (dot        . t)
     (emacs-lisp . t)
     (gnuplot    . t)
     (latex      . t)
     (makefile   . t)
     (python     . t)
     (R          . t)
     (sass       . t)
     (scheme     . t)
     (shell      . t)))

Scheme requires a default implementation for geiser:

  (setq geiser-default-implementation 'racket)

By the way, I wish to see source code behave the same way in the source blocks as in their own major mode. Lets tell Emacs so:

  (setq org-src-tab-acts-natively t)

Org variables

User information

Some variables about myself need to be set so Org-mode knows what information to include in exported files.

  (setq user-full-name "Lucien Cartier-Tilet"
        user-real-login-name "Lucien Cartier-Tilet"
        user-login-name "phundrak"
        user-mail-address "lucien@phundrak.com")
Visual settings

Visually, I prefer to hide the markers of macros, so lets do that:

  (setq org-hide-macro-markers t)
Org behavior

Here is one behavior that I really want to see modified: the ability to use M-RET without slicing the text the marker is on.

  (setq org-M-RET-may-split-line nil)

I also have added a couple of custom structure templates for Org mode (>= 9.3), mainly for source code blocks.

  (add-to-list 'org-structure-template-alist '("L" . "src emacs-lisp"))

Since Org 9.3, Org no longer attempts to restore the window configuration in the frame to which the user returns after editing a source block with org-edit-src-code. This means with the original value of org-src-window-setup (reorganize-frame), the current frame will be split in two between the original org window and the source window, and then only the org window will remain once we quit the source window. This is not a desired behavior for me, so I chose to set this variable to other-window in order to keep my windows organization.

  (setq org-src-window-setup 'other-window)
Miscellaneous

When creating a link to an Org flie, I want to create an ID only if the link is created interactively, and only if there is no custom ID already created.

  (setq org-id-link-to-org-use-id 'create-if-interactive-and-no-custom-id)

Org files exports

When it comes to exports, I want the LaTeX and PDF exports to be done with XeLaTeX only. This implies the modification of the following variable:

  (setq org-latex-compiler "xelatex")

I also want to get by default minted for LaTeX listings so I can have syntax highlights:

  (setq org-latex-listings 'minted)

The default packages break my LaTeX exports: for some reasons, images are not loaded and exported in PDFs, so I needed to redifine the default packages excluding the one that broke my exports. I also added two default packages, minted and xeCJK for syntax highlighting and Japanese (and additionally Chinese and Korean) support.

  (setq org-latex-default-packages-alist '((""         "graphicx"  t)
                                           ("T1"       "fontspec"  t ("pdflatex"))
                                           (""         "longtable" nil)
                                           (""         "wrapfig"   nil)
                                           (""         "rotating"  nil)
                                           ("normalem" "ulem"      t)
                                           (""         "amsmath"   t)
                                           (""         "textcomp"  t)
                                           (""         "amssymb"   t)
                                           (""         "capt-of"   nil)
                                           (""         "minted"    nil)
                                           (""         "xeCJK"     nil)
                                           (""         "hyperref"  nil)))

By the way, reference links in LaTeX should be written in this format:

  (setq org-export-latex-hyperref-format "\\ref{%s}")

When it comes to the export itself, the latex file needs to be processed several times through XeLaTeX.

  (setq org-latex-pdf-process
        '("xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
          "xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
          "xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"))

For Reveal.JS exports, I need to set where to find the framework by default:

  (setq org-reveal-root "file:///home/phundrak/fromGIT/reveal.js")

I also want to disable by default behavior of ^ and _ for only one character, making it compulsory to use instead ^{} and _{} respectively. This is due to my frequent usage of the underscore in my org files as a regular character and not a markup one. So, lets disable it:

  (setq org-use-sub-superscripts (quote {}))

On HTML exports, Org-mode tries to include a validation link for the exported HTML. Lets disable that since I never use it.

  (setq org-html-validation-link nil)

Custom LaTeX formats

I currently have two custom formats for my Org-mode exports: one for general use (initialy for my conlanging files, hence its conlang name), and one for beamer exports.

Below is the declaration of the conlang LaTeX class:

  '("conlang"
    "\\documentclass{book}"
    ("\\chapter{%s}" . "\\chapter*{%s}")
    ("\\section{%s}" . "\\section*{%s}")
    ("\\subsection{%s}" . "\\subsection*{%s}")
    ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))

And here is the declaration of the beamer class:

  `("beamer"
    ,(concat "\\documentclass[presentation]{beamer}\n"
             "[DEFAULT-PACKAGES]"
             "[PACKAGES]"
             "[EXTRA]\n")
    ("\\section{%s}" . "\\section*{%s}")
    ("\\subsection{%s}" . "\\subsection*{%s}")
    ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))

Both these classes have to be added to org-latex-classes like so:

  (eval-after-load "ox-latex"
    ;; update the list of LaTeX classes and associated header (encoding, etc.)
    ;; and structure
    '(add-to-list 'org-latex-classes
                  <<org-latex-class-conlang>>
                  <<org-latex-class-beamer>>
                  ))

Org agenda

One awesome feature of Org mode is the agenda. By default, my agendas are stored in ~/org/agenda.

  (setq org-agenda-files (list "~/org/agenda"))

I also have a custom command in Org agenda to mark some tasks as daily tasks, with the :DAILY: tag:

  (setq org-agenda-custom-commands '(("h" "Daily habits"
                                      ((agenda ""))
                                      ((org-agenda-show-log t)
                                       (org-agenda-ndays 7)
                                       (org-agenda-log-mode-items '(state))
                                       (org-agenda-skip-function
                                        '(org-agenda-skip-entry-if 'notregexp
                                                                   ":DAILY:"))))))

By the way, lets also add all TODO.org files in Org-agenda with Org-projectile:

  (with-eval-after-load 'org-agenda
    (require 'org-projectile)
    (mapcar #'(lambda (file)
                (when (file-exists-p file)
                  (push file org-agenda-files)))
            (org-projectile-todo-files)))

Org journal

I also occasionally use Org journal. All my files are stored in ~/org/journal, as set below:

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

The default prefix for org journals is the following:

  (setq org-journal-date-prefix "#+TITLE: ")

The timestamp will be set following the ISO 8601 format:

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

Org projects

Another great features of Org-mode is the Org projects that allow the user to easily publish a bunch of org files to a remote location. Here is the current declaration of my projects, which will be detailed later:

  (setq org-publish-project-alist
        '(
          <<org-proj-config-html>>
          <<org-proj-config-static>>
          <<org-proj-config>>
          <<org-proj-lang-html>>
          <<org-proj-lang-pdf>>
          <<org-proj-lang-static>>
          <<org-proj-lang>>))
Configuration website
  ("config-website-org"
   :base-directory "~/org/config/"
   :base-extension "org"
   :exclude "\\./\\(CONTRIB\\|head\\|temp\\|svg-ink\\).*"
   :publishing-directory "/ssh:Naro:~/www/phundrak.com/www/config"
   :recursive t
   :language "fr"
   :publishing-function org-html-publish-to-html
   :headline-levels 5
   :auto-preamble t)

And lastly, we have the component for all the static files needed to run the website:

  ("config-website-static"
   :base-directory "~/org/config/"
   :base-extension "css\\|scss\\|dart\\|js\\|png\\|jpg\\|gif\\|svg\\|jpeg\\|ttf\\|woff\\|txt\\|epub\\|md"
   :publishing-directory "/ssh:Naro:~/www/phundrak.com/www/config"
   :recursive t
   :language "fr"
   :publishing-function org-publish-attachment)

The project is then defined like so:

  ("config-website"
   :components ("config-website-org"
                "config-website-static"))
Linguistics website

In my case, I only have my linguistics website, made out of three projects. The first component is the one generating the HTML files from the org files.

  ("langue-phundrak-com-org"
   :base-directory "~/Documents/conlanging/web/"
   :base-extension "org"
   :exclude "\\./\\(CONTRIB\\|README\\|head\\|temp\\|svg-ink\\).*"
   :publishing-directory "/ssh:Naro:~/www/phundrak.com/langue-phundrak-com/web"
   :recursive t
   :language "fr"
   :publishing-function org-html-publish-to-html
   :headline-levels 5
   :auto-sitemap t
   :auto-preamble t)

We also have the component for the LaTeX and PDF part of the website:

  ("langue-phundrak-com-pdf"
   :base-directory "~/Documents/conlanging/web/"
   :base-extension "org"
   :exclude "\\./\\(CONTRIB\\|README\\|index\\|head\\|temp\\|svg-ink\\).*"
   :publishing-directory "/ssh:Naro:~/www/phundrak.com/langue-phundrak-com/web"
   :recursive t
   :language "fr"
   :publishing-function org-latex-publish-to-pdf
   :headline-levels 5
   :auto-preamble t)

And lastly, we have the component for all the static files needed to run the website:

  ("langue-phundrak-com-static"
   :base-directory "~/Documents/conlanging/web/"
   :base-extension "css\\|scss\\|dart\\|js\\|png\\|jpg\\|gif\\|svg\\|jpeg\\|ttf\\|woff\\|txt\\|epub"
   :publishing-directory "/ssh:Naro:~/www/phundrak.com/langue-phundrak-com/web"
   :recursive t
   :language "fr"
   :publishing-function org-publish-attachment)

The project is then defined like so:

  ("langue-phundrak-com"
   :components ("langue-phundrak-com-org"
                "langue-phundrak-com-static"
                "langue-phundrak-com-pdf"))

Rust

The first thing I need to set for my Rust setup is the path to racer.

  (setq racer-cmd "~/.cargo/bin/racer")

Now, I also need to point to racer where the source code of Rust is located so I can get some documentation.

  (setq racer-rust-src-path "~/.rustup/toolchains/nightly-x86_64-unknown-linux-gnu/lib/rustlib/src/rust/src")

Finally, I wish to enable electric-pair-mode and indent-guide-mode for Rust files, so lets enable that through the use of a hook:

  (add-hook 'rust-mode-hook
            '(lambda ()
               (local-set-key (kbd "TAB") #'company-indent-or-complete-common)
               (electric-pair-mode 1)
               (indent-guide-mode 1)))

Scheme

The Scheme configuration will be very short, I just need to tell Emacs the name of the interpreter since it is not the default one:

(setq geiser-chicken-binary "chicken-csi")

Shortcuts

As you will see, I defined A LOT of custom shortcuts. First, I have some shortcuts defined the vanilla Emacs way:

  (global-set-key (kbd "C-x C-b") 'ibuffer)
  (global-set-key (kbd "S-C-<left>") 'shrink-window-horizontally)
  (global-set-key (kbd "S-C-<right>") 'enlarge-window-horizontally)
  (global-set-key (kbd "S-C-<down>") 'shrink-window)
  (global-set-key (kbd "S-C-<up>") 'enlarge-window)
  (global-set-key (kbd "C-x <up>") 'windmove-up)
  (global-set-key (kbd "C-x <down>") 'windmove-down)
  (global-set-key (kbd "C-x <right>") 'windmove-right)
  (global-set-key (kbd "C-x <left>") 'windmove-left)
  (global-set-key (kbd "C-<prior>") 'previous-buffer)
  (global-set-key (kbd "C-<next>") 'next-buffer)
  (global-set-key (kbd "M-»") 'end-of-buffer)
  (global-set-key (kbd "M-«") 'beginning-of-buffer)
  (global-set-key (kbd "<XF86HomePage>") 'spacemacs/home)
  (global-set-key (kbd "<XF86Open>") 'helm-find-files)
  (global-set-key (kbd "<XF86Close>") 'kill-this-buffer)
  (global-set-key (kbd "<XF86Save>") 'save-buffer)
  (global-set-key (kbd "<C-tab>") 'evil-close-fold)
  (global-set-key (kbd "<S-C-tab>") 'evil-close-folds)
  (global-set-key (kbd "<C-iso-lefttab>") 'evil-open-fold)

These shortcuts can be called as-is, that is, typing C-x C-b will call ibuffer.

Now, I also have some Spacemacs shortcuts, defined in a way they can be used seamlessly with Evil. First, lets declare some prefixes in order to avoid seeing lots of custom in helm:

  (spacemacs/declare-prefix "o" "custom")
  (spacemacs/declare-prefix "oa" "applications")
  (spacemacs/declare-prefix "oB" "byte-compile .emacs.d")
  (spacemacs/declare-prefix "oc" "comments")
  (spacemacs/declare-prefix "of" "files")
  (spacemacs/declare-prefix "ofb" "bin.org")
  (spacemacs/declare-prefix "ofe" "spacemacs.org")
  (spacemacs/declare-prefix "off" "fish.org")
  (spacemacs/declare-prefix "ofi" "i3.org")
  (spacemacs/declare-prefix "ofI" "index.org")
  (spacemacs/declare-prefix "ofp" "polybar.org")
  (spacemacs/declare-prefix "ofr" "yadm README")
  (spacemacs/declare-prefix "oi" "insert")
  (spacemacs/declare-prefix "oii" "invisible space")
  (spacemacs/declare-prefix "om" "multiple-cursors")
  (spacemacs/declare-prefix "oo" "org-mode")
  (spacemacs/declare-prefix "ooi" "custom IDs")
  (spacemacs/declare-prefix "oos" "structure")
  (spacemacs/declare-prefix "oot" "tables")
  (spacemacs/declare-prefix "oott" "toggle width")
  (spacemacs/declare-prefix "oote" "expand")
  (spacemacs/declare-prefix "oots" "shrink")
  (spacemacs/declare-prefix "or" "external command")
  (spacemacs/declare-prefix "ot" "toggle")
  (spacemacs/declare-prefix "ow" "writeroom")
  (spacemacs/declare-prefix "ox" "text")

Now, onto the shortcuts:

  (spacemacs/set-leader-keys
    "oac"  'calc
    "oaC"  'calendar
    "oae"  'eww
    "oaw"  'wttrin
    "oB"   (lambda () (byte-recompile-directory (expand-file-name "~/.emacs.d") 0))
    "ob"   'fancy-battery-mode
    "occ"  'outorg-copy-edits-and-exit
    "oce"  'outorg-edit-as-org
    "oco"  'outline-minor-mode
    "od"   'elcord-mode
    "oF"   'flycheck-mode
    "ofb"  (lambda () (interactive) (find-file "~/org/config/bin.org"))
    "ofe"  (lambda () (interactive) (find-file "~/org/config/spacemacs.org"))
    "off"  (lambda () (interactive) (find-file "~/org/config/fish.org"))
    "ofi"  (lambda () (interactive) (find-file "~/org/config/i3.org"))
    "ofI"  (lambda () (interactive) (find-file "~/org/config/index.org"))
    "ofp"  (lambda () (interactive) (find-file "~/org/config/polybar.org"))
    "ofr"  (lambda () (interactive) (find-file "~/README.org"))
    "ofo"  'find-file-at-point
    "oii"  (lambda () (interactive) (insert ""))
    "ome"  'mc/edit-lines
    "omn"  'mc/mark-next-like-this
    "omp"  'mc/mark-previous-like-this
    "oma"  'mc/mark-all-like-this
    "ooi"  'eos/org-add-ids-to-headlines-in-file
    "oos"  'org-insert-structure-template
    "ooT"  'org-sidebar-tree
    "oott" 'org-table-toggle-column-width
    "oote" 'org-table-expand
    "oots" 'org-table-shrink
    "oow"  'org-pomodoro
    "owi"  'writeroom-increase-width
    "or"   'helm-run-external-command
    "os"   'prettify-symbols-mode
    "oti"  'toggle-input-method
    "otI"  'set-input-method
    "owd"  'writeroom-decrease-width
    "oxf"  'phundrak/fill-paragraph)

You can notice they all begin with o. This is actually a userspace, and I know these shortcuts wont conflict with any other packages. These shortcuts, like a lot of Spacemacs shortcuts, can be called with the use of the leader key, in my case SPC. So, if I want to call the calculator, I will type SPC o a c.

Footnotes