Emacs configurations

emacs

Table of Contents

  1. Full-all-in-Emacs-everywhere
    1. Highlights
      1. Different themes per buffer
      2. Spelling
      3. RSS with Elfeed
  2. Lazy loading manually
    1. Highlights
  3. The Profiler
    1. Highlights
  4. After thoughts

The most appealing feature of Emacs is to enable every single user to enjoy a very customized experience and this is possible through a very powerful infrastructure a.k.a Elisp Interpreter and by lots of community contribution around packages and code fragments to accomplish the most varied tasks.

All of it can be summarized by the relationship between an Emacs user and she’s configuration setup.

Over the years I wrote a lot of customized .emacs.d folders and even added to my 2021 resolutions to stick with my current one for a longer run. I tried to study the configs and explore possibilities, also I enjoy the feeling of “crafting my own tool” behind it.

Let’s talk about some of these experiments.

Full-all-in-Emacs-everywhere

I don’t even use this setup in my daily activities but I invested a lot of time in crafting this beauty. The setup uses EXWM as my Window Manager and lots of customization around desktop activities such as screenshots, multi-monitor support, audio, etc.

Highlights

I learned a lot about literate programming style and how awesome Org Mode can be to accomplish that, but there are a couple of interesting things in this config I want to call out.

Different themes per buffer

Add this code to your load-path and you can use the function load-theme-buffer-local to customize it such as this example:

    (load-theme-buffer-local 'deeper-blue (get-buffer "*wttr.in - São Paulo*"))

Spelling

English is not my first language, therefore I use a lot of resources to spell-check, find meanings, translation, synonyms for common words, etc. I use this same setup for ages.

RSS with Elfeed

Yeah, I enjoyed a lot to do all this customization with Elfeed. Specially the portion about scoring each RSS entry to match content I would be more interesting in reading first.

Also, you see the power of literate programming in Org-mode using this anchors.

    (require 'elfeed)
    (require 'cl-lib)
    (require 'elfeed-search)
    (require 'elfeed-db)

    <<elfeed-basic-config>>
    <<elfeed-mode-disabled>>
    <<elfeed-newsletters>>
    <<elfeed-scoring>>
    <<elfeed-filters>>
    <<elfeed-automatic-update>>
    <<elfeed-starred>>
    <<elfeed-youtube>>

Lazy loading manually

I always understood in theory how lazy loading works, but I never gave much attention to it. I tend to not close my Emacs session that often, therefore startup time was rarely an issue for me (which is usually the main motivation I see around for lazy loading)

However, as I stared digging deeper in Emacs and look at what packages were loaded at a time, I wondered “why does CIDER (clojure interactive development environment) is loaded when I only want to write some essays in Org-mode?” (I made up this example to illustrate the point, can’t remember which package was the trigger)

Then I started a new config to manage to understand this situation.

Highlights

I noticed that I had started my own “framework” and I even wrote some specialized functions to handle some activities such as load, update, list, and delete packages.

The bulk of the work is here:


    (defun bk/add-load-path (pkg subdir)
      "If PKG/SUBDIR exist add it to `load-path'.
    Return non-nil if successful."
      (let* ((path (concat (file-name-as-directory
                            (expand-file-name pkg user-emacs-directory))
                           (concat "pkgs/" subdir))))
        (when (file-readable-p path)
          (add-to-list 'load-path path))))

    (defun bk-auto-loads (file &rest func-or-ext-with-func)
      "`autoload' and `auto-mode-alist' for packages in the FILE.
    FUNC-OR-EXT-WITH-FUNC are the triggers of the package activation.
    After any of the functions is called, the whole package is loaded in memory."
      (dolist (x func-or-ext-with-func)
        (autoload
          (if (consp x) (cdr x) x)
          file
          "Undocumented `autoload'."
          t)
        (when (consp x) (add-to-list 'auto-mode-alist x))))

With this two functions you can “register” the entrypoint functions to your modules or functionalities that will be the triggers to load the full module afterwards.


    ;; * cider mode
    ;; - History
    ;;   -  2020-08-14 Created
    ;;   -  2020-08-18 Adding key binding to cider-jack-in
    (when (bk/add-load-path "langs/clojure" "cider")
      (bk-auto-loads "cider"
                     #'cider-jack-in
                     #'cider-connect
                     #'cider-jack-in-clj&cljs))

In the case above, if you open your Emacs and hit M-x cider- the only options you will see are those three functions registered as entrypoint. To contrast with my current setup (which I just found out and really don’t like that much), I haven’t used Clojure today at all and if I hit M-x cider- there are hundreds of functions available.

Current setup:


    (use-package cider
      :ensure t
      :commands (cider cider-connect cider-jack-in cider-jack-in-clj)
      :config
      (add-hook 'cider-mode-hook #'eldoc-mode)
      (add-hook 'cider-mode-hook #'whitespace-cleanup-mode)
      (add-hook 'cider-repl-mode-hook #'eldoc-mode)
      (add-hook 'cider-repl-mode-hook #'paredit-mode))

By reading use-package I expected that only the functions specified in the :commands key were available to me. (Another fight, for another day)

I thought about continuing evolving this configuration to improve the very bad aspect of “manual installation” of packages and its dependencies through git submodules. Who knows, I might come back to it some day.

The Profiler

My idea was to leverage chemacs to build very isolated configurations to specific tasks. For example, I might open my “clojure toolbox” that only is concerned with Clojure and nothing else.

Highlights

The idea was to provide a configuration file (the same from chemacs actually was pretty good) and be able to lunch your own instances as you need. The cost of startup time is decreased by loading all the instances as emacs servers when you log in.

    (("default" . ((user-emacs-directory . "~/emacs/profile/default")))
     ("clojure" . ((user-emacs-directory . "~/emacs/profile/clojure")))
     ("roam" . ((user-emacs-directory . "~/emacs/profile/roam")))
     ("ledger" . ((user-emacs-directory . "~/emacs/profile/ledger"))))

And a set of aliases to help you out.


    # GUI instances
    alias emacs="emacsclient -c -s default"
    alias emacs.default="emacsclient -c -s default"
    alias emacs.clojure="emacsclient -c -s clojure"
    alias emacs.roam="emacsclient -c -s roam"
    alias emacs.ledger="emacsclient -c -s ledger"

    # terminal instances
    alias et="emacsclient -t -s default"
    alias et.default="emacsclient -t -s default"
    alias et.clojure="emacsclient -t -s clojure"
    alias et.roam="emacsclient -t -s roam"
    alias et.ledger="emacsclient -t -s ledger"

I still like this idea.

After thoughts

I like how much I learned by writing each one of this configuration files and I am definitely proud to be able to go through my own ideas and explore Emacs landscape. But the underlying principle here is how flexible Emacs actually is.

My current configuration setup is this one which I am aiming to learn more about how to leverage use-package correctly.

The term Emacs Bankruptcy is very famous in the community, but I don’t believe this is the only reason you would be willing to “re-write” your configurations. I definitely encourage you to experiment.

You will notice that some pieces of code will follow you whatever you go :)

Happy Hacking.