August Feng

Debugging Spacemacs packages

About

An on-going documentation where I save knowledge gained from debugging emacs related things.

spacemacs recipes

  (oref (configuration-layer/get-package 'lsp-mode) :location)

Referencing layer packages locally

using local

The Spacemacs' documentation includes an FAQ answer on How to override a layer package.

I have the emacs-lsp package cloned to /Users/august.feng/repositories/gh/emacs-lsp/lsp-mode, so I'll be creating a symbolic link to that, and respectively adding (lsp-mode :location local) to dotspacemacs-additional-packages.

  mkdir -p ~/.emacs.d/layers/+tools/lsp/local
  ln -s ${HOME}/repositories/gh/emacs-lsp/lsp-mode ~/.emacs.d/layers/+tools/lsp/local/lsp-mode
  (lsp-mode :location (recipe :fetcher local))

using location

This is not a well supported method for packages that reorganize lisp files for distribution, and is unreliable because it just simply inserts the :location path directly load-path.

  ;; examples
  (forge-core :location "~/repositories/gh/magit/forge/lisp")

  (lsp-mode :location "~/repositories/gh/emacs-lsp/lsp-mode") ;; lsp-mode clients are inside `clients` folder.
  (lsp-fsharp :location "~/repositories/gh/emacs-lsp/lsp-mode/clients") ;; lsp-mode clients are inside `clients` folder.

using quelpa recipes

packages using quelpa recipes are the most properly installed. spacemacs will use quelpa to thoroughly rebuild the package at "/.emacs.d/elpa/28.1/develop/lsp-mode-abc.edf/.

  (lsp-mode (recipe :fetcher file :files (:defaults "clients/*.el") :path "~/repositories/gh/emacs-lsp/lsp-mode")) ;; see melpa/melpa's recipes folder for ~:files~ values.

using not to exclude existing packages from layers

I wanted to iterate on the poetry package, which is bundled with the python layer.

I own it in my augustfengd layer and ignore it in the python layer via the :packages keyword. (ref)

  ;; dotspacemacs-configuration-layers
  '(augustfengd
    (python :packages (not poetry)))

Breakpoints

instrumenting functions

removing instrumentation

Rather than re-evaluating without instrumentation, we can use edebug-remove-instrumentation to prompt us for a list of functions to remove instrumentation from them.

  (call-interactively 'edebug-remove-instrumentation)

on events

debugging on entry

We can remove breakpoints caused by entry on functions.

  (call-interactively 'cancel-debug-on-entry)

debugging on variable changes

This breakpoint surfaced the call stack, and I was able to identify the code that inadvertently caused the loading of org-capture.

  (debug-on-variable-change 'org-capture-templates)

lsp-mode

session file

lsp-mode uses lsp-session-file to track known workspaces. Since the bug happens when we add a new workspace, we need to remove our workspace from that file:

  (require 'lsp-mode)
  (call-interactively 'lsp-workspace-folders-remove)

clients

The list of lsp clients are held in the lsp-clients hash table. We can effect the changes by removing and re-registering the client.

  (remhash 'fsac lsp-clients)

local lsp servers

init files

I've not had too much luck with the bug-hunter package while investigating an initialization issue, but I'd like to try again.

Creating environments

removing hooks

We can reduce the noise by removing hooks.

  (call-interactively 'remove-hook) ;; and search for fsharp-mode.

minimal emacs with cask

We can use cask to spin up a minimal emacs instance.

  ;; Cask
  (source gnu)
  (source melpa)

  (depends-on "lsp-mode")
  (depends-on "fsharp-mode")

  ;; init.el
  (require 'lsp-mode)
  (require 'fsharp-mode)
  (add-hook 'fsharp-mode-hook #'lsp-deferred)

  ;; cask emacs -l init.el

second emacs process

It's been a nice experience to keep one emacs instance to iterate on the lisp code, and start and restart new instances of emacs that will source the new code.

We can use a helm command (C-x c C-c C-x emacs) to run an new emacs instance with our changes while use the current emacs to iterate on a code.

parallel spacemacs installation

In certain cases where we want to hack away the Spacemacs code without mutating our working instance, just clone the repository elsewhere (e.g: /.emacs.d.hack) and s/".spacemacs"/".spacemacs.hack"/ in the directory so that new Spacemacs installation uses another configuration file instead.

Now it's just a matter of running Emacs with the argument --init-directory=~/.emacs.d.hack.