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’ repository[fn:1] if you are reading the web version of it. You can also find there my ~.spacemacs~[fn:2] and its code which isn’t 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.
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).
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.
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 only one:
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 I need some configuration for these packages, then I should consider creating a layer. I can also puth the configuration in ~dotspacemacs/user-config~. To use a local version of a package, use the ~:location~ property, for instance:
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 won’t be resolved automatically. Here is a table of all the extra packages I use:
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:
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.
~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.
I use as my daily Email client ~mu4e~, so let’s enable it and tell Emacs where mu4e is installed. I also tell mu4e to use maildirs extensions, use async operations, where to keep attachments, and enable the mu4e modeline.
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.
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.
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.
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.
In this category, I enabled support for the ~major-modes~ layer for the Arch Linux PKGBUILDs support, ~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.
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.
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.
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.
PlantUML is a very useful DSL for creating UML diagrams from some text description. As you can see below, this layer will be enabled, both as a standalone mode for opening ~.pum~ files, but also for org-mode code blocks.
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 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.
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.
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~.
Elfeed is an Emacs feeed and RSS reader which can be managed through org files. Actually, through only one file in my case, located in my =~/org= directory.
Next, we have the Docker, Nginx, Pass (the standard Unix password manager), Prettier, Systemd, Meson, Imenu-list, Web-beautify, Dap, Helpful, and LSP layers enabled.
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.
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:
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 Linux’s repositories, so I’ll disable the Spacemacs support for this feature. The default value of this variable is ~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 user’s ~PATH~. By default, the value of the variable is ~"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:
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~.
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~.
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~.
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~.
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~.
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 don’t use it, so I let it set to ~nil~. The default value is ~nil~.
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~.
If non-nil, the paste transient-state is enabled. While enabled, after you paste something, pressing ~C-j~ and ~C-k~ several times cycles through the elements in the ~kill-ring~. Default ~nil~.
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~.
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.
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.
Similarly, the below variable sets the default mode for the scratch buffer. Its default value is ~text-mode~, but I set it to use ~emacs-lisp-mode~ by default.
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~.
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.
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))~.
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~.
~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.
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~.
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~.
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~.
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~.
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~.
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:
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~.
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~.
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~.
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~.
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 it’s active or selected. The default value is ~90~.
Similarly, you can set a value from 0 to 100 in increasing opacity which describes the transparency level of a frame when it’s inactive or deselected. The default value is ~90~.
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~ in terminal mode, or ~M-return~ in GUI mode.
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~.
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~.
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~.
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 ="$HOME/.config/emacs/server"=. It has no effect if ~dotspacemacs-enable-server~ is ~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~.
et ~gc-cons-threshold~ and ~gc-cons-percentage~ when startup finishes. This is an advanced option and should not be changed unless you suspect performance issues due to garbage collection operations. The default is ~'(100000000 0.1)~
f non nil activate ~clean-aindent-mode~ which tries to correct virtual indentation of simple modes. This can interfer with mode specific indent handling like has been reported for ~go-mode~. If it does deactivate it here. Default ~t~.
f non ~nil~, shift your number row to match the entered keyboard layout (only in insert state). Currently supported keyboard layouts are ~querty-us~, ~quertz-de~ and ~querty-ca-fr~. New layouts can be added in ~spacemacs-editing~ layer. Default ~nil~.
et ~read-process-output-max~ when startup finishes. This defines how much data is read from a foreign process. Setting this >= 1 MB should increase performance for lsp servers in emacs 27.
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:
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.
Yes, I do use a preconfigured theme, as mentioned above, but for some elements such as Eshell, I need to define some variables for color, and I’ll do it here.
~with-face~ is a simple yet very useful macro that allows me to easily create strings with faces defined as properties to the string passed as the first argument. Here is how it is implemented:
The following is a nice little function I use in my Eshell prompt. It shortens the name of all the parent directories of the current one in its path, but leaves the current one written in full. It also abbreviates the equivalent of the ~$HOME~ (~/home/<username>/~) directory to a simple =~=.
This function is quite a simple function made to automatically publish [[https://blog.phundrak.com][my blog]] based on Hugo. After exporting my blog using ~ox-hugo~, I simply have to call this function which will look for all files located in =~/org/blog/public= and copy them to my remote server once ~hugo~ has been executed in =~/org/blog=.
This function is used in my Eshell prompt which you can consult [[#User_Configuration-Eshell-Eshell_theme-a06715a9][here]]. This function basically executes two git calls to get some information about a git repo, which path we provide as an argument. Based on the result of these git calls, the function will know what it needs to know about the repo to build a git prompt that will be inserted in my Eshell prompt. And just for shit and giggles, I’ve made it so it is a powerline prompt.
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 I’m in insert mode.
There are lots of files which I want to be able to quickly open. I used to have one shortcut for each one of these files, but as their number grew, I decided to switch to helm for my file selector which will be called by only one common shortcut. Most of my files will be located in =~/org=, but I have some conlanging files which are located in =~/Documents/conlanging=, and all my university notes are in =~/Documents/university=. Let’s declare these directories in a variable:
With this established, let’s write some emacs-lisp that will allow me to get a list of all these files and select them through helm. Be aware that I will be using some functions from third party packages, such as [[https://github.com/rejeep/f.el][f.el]] and [[https://github.com/magnars/dash.el][dash]].
This function detects if the path passed as an argument points to a git directory or to one of its subdirectories. If it is, it will return the path to the root of the git repository, else it will return ~nil~.
This function is particularly useful in Dired buffers when someone wants to open multiple files. This function will basically look for all marked files in the current dired buffer and open each one of them in their individual buffer.
The following function is a function that will allow me to easily create ~new~ functions for Rust structs. Inspired from [[https://github.com/jorgenschaefer/elpy][elpy]]’s ~elpy-snippet-init-assignments~ function, it will automatically write assignments to my new struct as I write new parameters in the ~new~ function. It also comes with a helper function that parses the arguments given to the ~new~ function.
This function allows for taking SVG screenshots of Emacs from itself using Cairo. The function definition was taken [[https://github.com/caiohcs/my-emacs#screenshots][from here]].
#+BEGIN_SRC emacs-lisp
(defun screenshot-svg ()
"Save a screenshot of the current frame as an SVG image.
Saves to a temp file and puts the filename in the kill ring."
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:
Here is another of Xah’s functions, this time to open a file externally to Emacs. For instance, I sometimes want to open a PDF in Zathura rather than in Emacs, or an HTML file in Firefox. With this function, it is now possible!
#+BEGIN_SRC emacs-lisp
(defun xah/open-in-external-app (&optional files)
"Open the current file or dired marked file in external app.
The app is chosen from your OS’ preference.
When called in emacs lisp, if files is given, open that.
When it comes to dired, I chose do modify some elements on how things are sorted and shown, but there isn’t much configuration. First, I want to always copy folders in a recursive way, no questions asked.
Also, when I have two Dired buffers opened side by side, I generally want them to interact with each other, for example if I want to move around or copy stuff. So, let’s tell Emacs that:
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.
This function is a function that will come in very handy for Eshell functions that call shell processes. It concatenates the initial string ~command~ with all the arguments ~args~, each separated with a space.
When I’m 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. Let’s modify ~find-file~ like so:
I still have some stupid muscle memory telling me to open ~emacs~ in the terminal, which is stupid with Eshell since I’m already inside Emacs. So, let’s open each file passed to the ~emacs~ command and bury the eshell buffer (we’ll get back to it later).
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. Let’s add them to our path.
#+BEGIN_SRC emacs-lisp
(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")))
#+END_SRC
I would also like to set two environment variables related to Dart development: the ~DART_SDK~ and ~ANDROID_HOME~ variables.
The code creating the Eshell banner is a bit lengthy and requires some additional explanations that would make the following chapter [[#User_Configuration-Eshell-Eshell_theme-a06715a9][Eshell theme]] too long. So, here it is!
The banner for Eshell will collect some system information and display them gracefully. These pieces of information are:
- The GNU/Linux distribution running (I do not use any other OS on my computer)
- The kernel name and its version
- The machine’s hostname
- Its uptime
- Its RAM and Swap usage
- How full are its mountpoints
Some of these information can be grabbed directly from Emacs built-in functions, but some others need to be retrieved manually. Let’s first get into it with the mounted partitions for which we’ll define a structure:
#+BEGIN_SRC emacs-lisp
(defstruct phundrak/mounted-partitions
"Object representing a mounted partition found in the system"
path size used percent)
#+END_SRC
We’ll also define a variable setting the maximum length of a partition path before it gets abbreviated:
#+BEGIN_SRC emacs-lisp
(defvar phundrak//eshell-banner--max-length 13)
#+END_SRC
Now, we can get our partitions. For this, we’ll make a call to the shell command ~df -lH~ and we’ll keep only the partitions mounted on a device stored in ~/dev~, for instance on ~/dev/sda~. And as mentioned above, if the mount path of the partition exceeds the length specified by ~phundrak//eshell-banner--max-length~, it will get abbreviated by [[#User-Configuration-Custom-functions-macros-and-variables-phundrak-abbr-path-559b46e3][~phundrak/abbr-path~]].
We’ll need some padding for the name of the information displayed on the left hand side of the banner. The maximum length without any partitions is eight characters due to the text ~Hostname~, so if any partition path is longer than this, the left padding will increase.
Now, Let’s set three variables that will be used in the function following this declaration. They will be used to determine in which color a percentage should be displayed. I’ll consider any percentage below 60% to be acceptable and therefore displayed in green. However, starting from this threshold, I want the user to be noticed of the usage of whatever percentage shown that it has gone up and it should be watched and displayed in yellow. Above 75%, the user should consider this a warning, and the percentage will be displayed in orange. Above 90%, it is considered critical and the percentage will be displayed in red.
This function will be used when displaying progress bars. These will be used for displaying the Ram, Swap and partitions usage of the system, displaying the used part in red and the free part in green. For this, we just need to know the size of the progress bar we wish to use as well as how full it should be. Note that the percentage should be between 0 and 100.
This function will be used in two distinct functions: ~phundrak/eshell-banner~ which we will see later, and ~phundrak//eshell-banner--display-memory~ which we will see now. This function displays information for the two types of memory we have, RAM and Swap memory. Here is the definition of this function:
#+BEGIN_SRC emacs-lisp
(defun phundrak//eshell-banner--display-memory (type used total text-padding ramp-length)
(phundrak//eshell-banner--display-partition part left-pad ramp-length))
partitions
"\n")
(format "\n%s\n" (s-repeat 79 "=")))))
#+END_SRC
We now only have to set the result of this function as our Eshell banner. Since a simple ~setq~ would only run ~phundrak/eshell-banner~ once when Emacs starts, we’ll actually make Emacs set the value of ~eshell-banner-message~ each time it is required by Eshell with a hook:
As with most shells, again, it is possible to customize the appearance of the Eshell prompt. As you can see, my prompt has some Nord colors, a shortened path, a git prompt, and an indicator of whether the previous command succeeded or failed. Note however that the abbreviation of the current path depends on the value of ~phundrak/prompt--abbreviate~, if it is ~t~ it is abbreviated; otherwise, it is kept in full. It can be toggled with a keyboard shortcut, see [[#User_Configuration-Shortcuts-Toggle-d53c27ef][Keybindings: Toggle]].
#+BEGIN_SRC emacs-lisp
(defun phundrak/eshell-prompt ()
"Definition of my prompt for Eshell
It displays a powerline prompt, with first an abbreviated path to
the current directory. If `phundrak/prompt--abbreviate' is `t',
then all preceding directories will be abbreviated to one
character, except hidden directory which first character will be
preceded by a dot. Otherwise, the full name of the directories is
displayed.
Then, if the current directory is a git repository or one of its
subdirectories, it will display the current state of the
repository. See `phundrak/eshell-git-status'
Finally, a lambda character is displayed, either in blue or in
red depending on if the last eshell command was a success or a
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.
The first ones are dedicated to provide org-mode headings a fixed and unique ID that won’t change over time. This code was taken from [[https://writequit.org/articles/emacs-org-mode-generate-ids.html][https://writequit.org/articles/emacs-org-mode-generate-ids.html]]. The first function’s job is to create these unique IDs
#+BEGIN_SRC emacs-lisp
(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\"."
Now, let’s 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.
(concat orgpath "_" (org-get-heading t t t t)))))))
(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 heading)))
(org-entry-put pom "CUSTOM_ID" id)
(org-id-add-location id
(buffer-file-name (buffer-base-buffer)))
id)))))
#+END_SRC
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.
#+BEGIN_SRC emacs-lisp
(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
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:
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 once we quit the source window only the org window will remain. This is not a desired behavior for me, so I chose to set this variable to ~split-window-right~ in order to keep my windows organization and have a similar behavior to the old one.
However, it is not rare that I want to change that for an horizontal split, which can be achieved with the value ~split-window-below~. Thus, I have made this function that allows me to switch between the (default) vertical split and the horizontal split.
#+BEGIN_SRC emacs-lisp
(defun phundrak/toggle-org-src-window-split ()
"This function allows the user to toggle the behavior of
`org-edit-src-code'. If the variable `org-src-window-setup' has
the value `split-window-right', then it will be changed to
`split-window-below'. Otherwise, it will be set back to
Lastly, I know this can be a terrible idea, but I want Emacs to just evaluate Org code blocks without asking me. Of course, this could represent some big security issue if not careful enough, but I generaly just open my own org files.
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.
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.
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, let’s disable it:
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:
Org-capture is an amazing feature of Org-mode which allows me to quickly save links, resources, reminders, and notes in neatly organized org files. Here they are described:
With Spacemacs, an Org capture can be invoked with the shortcut ~SPC a o c~. It will then ask which template I wish to use. In the table below are described the shortcuts that are available after ~SPC a o c~ is invoked. The /name/ will be the one displayed in Org capture’s interface, the /title/ is the headline where to save the capture (if it does not differ from the capture’s name, the cell will be blank). The /insertion mode/ tells Emacs how to add the capture to the /file/, using which /template/. A line with no insertion mode, file, or template is just a category. All of the following insert entries to their org files, that is a new org node with a headline and some content.
#+NAME: org-capture-shortcuts-table
| Shortcut | Name | Title | Insertion mode | file | template |
The following code snipped is not tangled into my configuration file, but instead creates the equivalent to the table above into EmacsLisp code found in the next code snippet.
You may notice a capture entry for my journal, and this is due to the fact I do not use ~org-journal~ anymore: it was too overpowered for me, and I prefer to keep it simple with a single file. And as you can see, and unlike a lot of other Emacs configurations, the content of the template is not set in the variable, but in external files which can be modified freely as actual Org buffers instead of trying to get a proper one with loads of ~\n~ characters and such. All these templates are declared below.
In the next sub-sections will be described my org capture templates. These are not tangled into my Emacs configuration files, but into separate ~.orgcaptmpl~ files stored into =~/org/capture/=.
Sent from a Free and Open-Source Linux operating system with GNU/Emacs
#+END_SRC
I use it in case my computer is not yet connected to the internet and I need to already write the email so I can send it later. All I will need to to afterwards will be to copy and paste my capture in a new message buffer and send it once I am back online. This is exported to =~/org/capture/email.orgcaptmpl=.
This template is quite simple: it creates a new entry with the current timestamp as its title, a brief title of my choosing, and then I can write whatever I wish to write. This is exported to =~/org/capture/journal.orgcaptmpl=.
This template is used for taking note about various subjects that can go from conlanging to development. I wrote it so I can know from where this capture was made and when, and it even supports text that was highlighted in Emacs that will be inserted in a quote block. This is exported to =~/org/capture/notes.orgcaptmpl=.
This capture is used when received through org-protocol, with the Org-protocol Extension for Firefox. It allows me to save in a quote block what I’ve highlighted, as well as the link of the webpage on which my saved content was highlighted. This file is exported to =~/org/capture/protocol.orgcaptmpl=.
This is the default template for resources, which generally are located on the Internet. By default, I give them the lowest priority, because although this is something for me to remember later, it is not by default important. You can see in the properties I record when the capture happened, and what the link is. The title of the capture is a summary of what this is, while the body of the capture is a more detailed explanation of what I capture, why, and how it could be useful to me.
One type of task I often capture is related to my servers or thing about computers in general. With this, I can capture a task for which I will either set a schedule or a deadline.
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:
This is my configuration for exporting my dotfiles to my website in a web format only. No PDFs or anything, just HTML. Please note that I do not use that often anymore, I much prefer the automatic script that I have which deploys through my Drone instance my website on git pushes.
And before we get into the actual configuration, I would like to introduce a couple of variables. This is a bit more verbose than if I declared everything manually, but now I can change all three values at the same time without a hasle.
Now, here is my configuration. In this snippet, my org files located in my source directory get exported in the HTML format and published to my target directory on my remote server through SSH via TRAMP. A sitemap is automatically generated, which comes in handy with the online sitemap that is available through the navigation bar.
Some buffers sometimes won’t 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 let’s set it so!
Sometimes, Emacs doesn’t recognize or misrecognizes some extensions, resulting in a wrong mode set for said file. Let’s fix that by associating the extension with the desired mode:
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.
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. This will also be enabled for Elfeed.
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 are ~message-mode~, ~org-mode~, ~text-mode~ and ~markdown-mode~.
I really like the ~M-(~ keybinding for wrapping a selected region between parenthesis. However, parenthesis are not everything (even in Lisp dialects), and other wrappers could be nice. And they are! Here is how they are declared:
As you will see, I defined a LOT of custom keybindings. All of them are Spacemacs keybindings, defined in a way they can be used seamlessly with Evil. They almost all begin with ~o~, which is a prefix reserved for user-defined keybindings so they won’t conflict with any package. Let’s declare it like so.
Before some more specialized categories, I have two commands which don’t fit into any other category that I sometime use. The first one is a fix for the Bépo keybindings which left out a keybind: ~winum-select-window-by-number~ is still bound to ~SPC ²~, which is not a key that is available on the bépo layout (instead, we use the dead key ~^~ followed by ~2~, or any digits). So instead, let’s use the key that is physically in the same place: ~$~.
#+BEGIN_SRC emacs-lisp
(spacemacs/declare-prefix "$" "select window by number")
The following, I use it rarely, it can launch an external command from Emacs to launch, for instance, my web browser or any other software not related to Emacs. It offers a similar interface to [[https://wiki.archlinux.org/index.php/Dmenu][dmenu]] through helm.
Now, let’s also declare the keybindings in this category. ~oac~ will invoke Emacs’ calculator, while ~oac~ invokes the calendar, ~oae~ invokes the Eww web browser, ~oaw~ invokes ~woman~ (actually ~helm-man-woman~), and ~oaW~ invokes the weather forecast. Lastly, the apostrophe in ~oa'~ will invoke Eshell directly, without any popup window as with ~,'~.
Finally, here we have the keybindings for ~org-tree-slide~, a presentation mode with orgmode. Since I want the keys to be directly accessible without any prefix from Spacemacs, I’ll have to declare them the vanilla way. First we have keybindings that will launch the presentation:
Next, we have some additional keybindings that will only be active when in ~org-tree-slide-mode~. The first one will allow us to exit this mode, while the second one will toggle the display of headers marked as ~DONE~. Next, we have ~F9~ and ~F10~ which are bound to movement in the slide, while ~F11~ changes the way the content is displayed. We also set ~org-tree-slide-skip-outline-level~ to set the maximum depth we will display as an individual heading during the presentation.
~oco~ enables the outline minor mode, which then allows for the edition of comments in org buffers with ~oce~ and saving them to the original source file with ~occ~.
A couple of keybindings will be added to Dired. The first one is the opening parenthesis which will enable or disable ~dired-hide-details-mode~. On the other hand, a closing parenthesis will show git information in the current Dired buffer.
A couple of other useful utilities, sach as opening all marked files, sorting files, opening them externally and renaming them, are also bound to a simple key press:
I also have a shortcut for ~helm-locate~ in case I need to find a file that is not in these directories. One advantage of this over ~helm-find~ is that it doesn’t matter from where I call it, it will find any file on my system that matches the query, whereas ~helm-find~ will only search in the current directory and its subdirectories. This time, the declaration is much simpler:
And that’s it! This should list all my org files under these directories and give me fuzzy finding for these files. I just need to partially type the name of the file I want to open and it should open without any issue.
I don’t really like Spacemacs’ layer for MultipleCursors, so I prefer to simply install the package and create shortcuts for it myself. Let’s first declare category:
~os~ allows me to insert an org structure template defined in ~org-structure-template-alist~ (see [[#User_Configuration-Org-mode-Org_variables-Org_behavior-0319db38][Org behavior]]), while ~ott~ displays the outline of the current org file.
These shortcuts allow to manipulate the width of the column the cursor is currently in, by either shrinking it, expanding it, or toggling its state between shrunk or expanded. A prefix for all of these commands has been also added in order to make the purpose of the shortcuts clearer.
As you can see, I have here four shortcuts for toggling various elements in Emacs:
- ~otb~ :: toggles ~fancy-battery-mode~. This comes in very handy when I am on a laptop that is not pluged in or which is charging.
- ~otd~ :: toggles ~elcord-mode~. This mode is used to create an Emacs rich integration in Discord.
- ~otf~ :: toggles the activation of FlyCheck, Emacs’ spell checker. It is by default disabled, and I can turn it on with this shortcut only when needed.
- ~ots~ :: toggles ~prettify-symbols-mode~. This allows Emacs to replace some symbols by some others, like for example by replacing ~lambda~ in Emacs Lisp buffers with an actual λ.
- ~otS~ :: toggles whether or not Eshell should shorten the current path in its prompt
We also have some input methods-related shortcuts in a sub-category: ~oti~. The first shortcuts below are used to either toggle between no input method or the last one used (~otit~), or choose an input method among the various available ones from Emacs (~otis~).
The shortcuts below though allow me to directly switch to one of these three known input methods I sometimes or often use, namely Japanese, Tibetan and IPA (by typing in X-SAMPA).
Mu4e is a frontend for mu, an email analyzer which sits on top of a Maildir which gets updated with the ~mbsync~ command from ~isync~. It has a lot of neat features, but I guess my favorite ones are:
Due to mu sitting on top of a maildir, I need to tell mu4e where said maildir is, and point it the trash, archive, and sent folders as well as the refresh command and how frequently I want my emails to be refreshed.
This source block is an example of the search queries in mu4e, and part of the reason why I very much like mu4e: these bookmarks are actually defined by search queries, but act as if they were just yet another type of custom inbox you get with modern Email client (and often you don’t even get them). All these bookmarks can be accessed through a shortcut on the main mu4e buffer, prefixed by ~b~. So, for instance, my unread messages are accessed through ~bU~.
On new email arrival, Emacs can send the system a notification which will be handled as any other notification received by the system and will display the number of unread emails to the user; in my case, notifications are handled by AwesomeWM.
This is the setup I have for my SMTP mail server: I point Emacs’ SMTP services to my private mail server on its SMTP port, which should be used with a STARTTLS stream. And I tell Emacs this is the default way to send an email.
The following also allows me to automatically include my signature in my Emails, to view images in my Emacs buffers and to show me the address of my contacts and not just their names.
Now this hook is added so I can get a maximal width for the text of my emails, I really don’t like it when lines are kilometers long. I would like instead to hook ~visual-line-mode~ and ~auto-fill-mode~, but for some reasons Emacs throws an error when I add them, So I go with ~visual-fill-column-mode~ instead.
On modern-day computers, with wide screens almost everywhere, there is no reason for the email buffer to open below the email directory and not on its right, which is why I set the split view to be vertical instead of horizontal. And to make it more readable, the header window will only occupy 40% of Emacs’ frame, the rest will be given to emails. As you can see, the width of the mu4e headers is evaluated each time we enter it, so it can react to the frame being potentially not the same width than earlier or the window not taking the entire frame. It has to have a minimal size though, I’d say 80 characters is enough for that.
Icons are nice and all, but my current font does not display some of the default icons set by mu4e. Due to this, I will define back these icons to the original characters defined by mu4e:
Something that irks me with the ~doom-nord~ theme is that emails I replied to are the same color as unread emails, and I wish to change this color. Luckily, I can change that! The foreground color of emails I replied to will now be [[#User_Configuration-Custom_functions_and_variables-Some_theming_variables-9b853a99][Nord15]]. The same goes for forwarded emails that will get the Nord14 foreground text color. And please, no underligning.
I am unsure yet if this has any effect on mu4e, but this variable should discourage mu4e from reading rich text emails and instead open them as plain text. However, I do not wish to discourage opening HTML emails since I can open them in the browser.
I am still unsure about this variable and if it has an effect on mu4e, but I wish to set a default web viewer for my HTML emails: w3m. This is not as effective as sending the email in the browser or rendering it as a PDF file, but it can be effective enough for some emails.
As I will always say, orgmode is an amazing piece of software that deserves particular care and love. That is why I want to give it a unique look and feel compared to the rest of my Emacs configuration, in order to make it feel much more comfortable.
In order to make org-mode even sexier, let’s enable ~variable-pitch-mode~ for org-mode so we can get some proportional font. I’ll also remove ~auto-fill-mode~ which seems to stick to Orgmode like hell and I don’t know why.
Fonts will play an important part in this, but so will colors and font size. The following code is largely based on the one found [[https://zzamboni.org/post/beautifying-org-mode-in-emacs/][on this blog post]] and [[https://lepisma.xyz/2017/10/28/ricing-org-mode/][this one]].
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.
~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 I’m opening a new EPUB file.
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:
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~.
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.
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:
I need to point to racer where the source code of Rust is located so I can get some documentation. This is installed with the ~rust-src~ component you can get through ~rustup~. To install it, simply run
Now, the source code for Rust should be included in your installation. I personally prefer to develop with Rust stable, so let’s indicate to Emacs to search for documentation in the stable sources:
Rust’s default ~cargo check~ command is already very good, however I also enjoy getting some more hints while developping, and ~clippy~ does a very good job at it. To get clippy, I need to run the following to install it:
And this will get it installed with all of my Rust toolchain, and it will be updated with it. Now, let’s indicate LSP that I want to use that instead of ~check~:
Projectile is an awesome utility which helps managing projects within Emacs. It will automatically detect version controlled directories, and will by default assume this is a project I can be working on. However, there are some directories that are version controlled that I do not want to see in my list of projects, namely all the cached AUR packages from my AUR helper, ~yay~. They are all stored in the same parent directory, so let’s ignore that. I will also make Emacs ignore all ~node_modules~ directories it could encounter. And for some reason, =~/.config/emacs= is always in my projects list (I now use XDG-compliant directories), so let’s also ignore that.
This paragraph is about making Emacs and GPG as a whole (since Emacs is /always/ open on my computer) more secure. The first thing I want to make is a function that will close any buffer that contains an open ~.gpg~ file –I certainly do not want anyone to be able to read such files on my computer if I leave it even for a couple of minutes.
Notice the ~(shell-command "gpgconf --kill gpg-agent")~ command there: it kills ~gpg-agent~ which will always respawn each time GPG2 is invoked. That way, I know anyone trying to open a GPG file will have to insert my password when trying to do so instead of just hoping I entered it not long ago and they won’t have to.
But surely, if I only define this function and hope to call it each time I leav my computer, surely at one point I will forget to execute it before leaving. I can’t trust myself to always call it manually. Which is why I’ll ask Emacs itself to call it after it detects a minute of idling. It may become from times to times a bit of a pain, but at least I’m now sure I won’t ever have to worry about someone reading my GPG files open in Emacs while I’m out for a quick break.
#+BEGIN_SRC emacs-lisp
(run-with-idle-timer 60 t 'phundrak/kill-gpg-buffers)
Yasnippet’s snippets tool is extremely powerful and allows me to write very quickly code. For now, we have snippets for two modes. The files you’ll see below are exported to ~$HOME/.config/emacs/private/snippets/~ and to their respective mode directory. For instance, my ~caption~ snippet for org-mode will be exported to ~$HOME/.config/emacs/private/snippets/org-mode/caption~.
Be aware that on top of these custom snippets, I also use the package [[file:awesome.org::#Autostart-f2cf42fe][yasnippet-snippets]] which provide plenty of already made snippets.
The second one is more interesting: it is used to create a ~new~ method for a struct, and it will try to create a function that will assign each argument passed to the method to members of the struct. It relies on the custom function [[#Custom-functions-yas-rust-new-assignments-4ad16bde][I wrote here]].
The first two snippets are used to add HTML or LaTeX attributes to elements in org-mode. The third also has a similar usage, inserting a ~#+CAPTION~ header before an element, as well as the fourth which inserts a ~#+NAME~ header.
Now, the following is a bit more complex: it is meant to be used as a new org buffer is created. It will insert an org header for the title, which will default to the buffer’s name capitalized minus the dashes or underscores replaced with spaces, it will insert a default author and email based on the user’s parameters, and the date at the moment of the creation of these headers. The user can also add some tags if they wish to.
Now, Let’s write some snippets for org blocks. The first one is for a comment block, then two snippets for an unnamed and a named Elisp source block, and two others for an unnamed and a named Python source block. There are also two block for generic unnamed source blocks and generic named source blocks.
Finally, there are a couple of miscellaneous org snippets that insert macros I often use in my conlanging documents. The first one inserts a phonetics macro, while the second one inserts a macro used for my Proto-Ñyqy language.
It is completely possible with Tramp to connect ot a docker container and modify files inside of it. It is not supported natively, but we can add it quite easily. Be aware, I am not the author of this code, you can find its original source [[https://www.emacswiki.org/emacs/TrampAndDocker][here]]. First, let’s add the Docker protocol to Tramp:
~yadm~ is the utility I use for managing my dotfiles, and it is a wrapper In order to manage my dotfiles, I use the following shortcut to launch Magit Status for ~yadm~:
around ~git~. Logically, it means Magit could theoretically manage my yadm repo. And it is indeed possible, according to [[https://github.com/TheLocehiliosan/yadm/blob/master/yadm.md][this page]] using TRAMP. I just need to add the following code snippet: