Bowmansarrow

It's been a while since I posted a blog. After reviewing a couple of the more recent SystemCrafters live streams1 it seemed like a good time to add some thoughts on how Crafted Emacs might be used to solve similar problems. I wasn't able to participate live, I still have a day job and have meetings and stuff, so I had to watch them after-the-fact. Something I usually try to do anyway, but I prefer to participate in the streams as they happen.

Crafted Emacs for minimal configuration

In the live stream on 16 November 2024, David talks about his approach to rewriting his configuration. After not using a literate approach for a while, he has returned to using a literate approach to his config. Not my cup of tea, but I totally understand why he would go that route, and he gives reasons why he likes that approach during the stream. He also mentions only using GNU and Non-GNU ELPAs to help minimize his configuration. Crafted Emacs assumes you want every ELPA, but it does prioritize the GNU and Non-GNU ELPAs above MELPA-stable and MELPA. With Emacs 29, you get both GNU and Non-GNU ELPAs by default, so if you choose to limit yourself to just those, you don't need to use the crafted-early-config.el in your config, but you probably still need to add (require 'package) to your config if you intend to continue to use any of the crafted-*-packages.el modules as they need the package-selected-packages variable to be defined. For the completions David talked about, if you use the crafted-defaults-config.el module, those are setup by default for you. This includes the following snippet to control the size of the *Completions* buffer:

(add-to-list 'display-buffer-alist
             '("\\*Completions\\*"
               (display-buffer-reuse-window display-buffer-pop-up-window)
               (inhibit-same-window . t)
               (window-height . 10)))

If you are not using that module, but prefer to use the built-in completions (or something like icomplete, ido, or fido) the above snippet will help keep *Completions* window from taking over the screen. David discusses the completion styles and gives examples, so watch the live stream2 for a good overview of how that variable works.

With all that said, a minimal Crafted Emacs configuration might be something like this:

(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (and custom-file
           (file-exists-p custom-file))
  (load custom-file nil :nomessage))

(load (expand-file-name "~/crafted-emacs/modules/crafted-init-config"))
;; Adjust the path (e.g. to an absolute one)
;; depending where you cloned Crafted Emacs.
;; (load "/path/to/crafted-emacs/modules/crafted-init-config")

;; needed if you want to use any of the crafted-*-packages modules
(require 'package)

(require 'crafted-defaults-config)

(add-to-list 'display-buffer-alist
             '("\\*Completions\\*"
               (display-buffer-reuse-window display-buffer-pop-up-window)
               (inhibit-same-window . t)
               (window-height . 10)))

;; Set default coding system (especially for Windows)
(set-default-coding-systems 'utf-8)

(provide 'init)
;;; init.el ends here

You can also take a look at my post where I develop a minimal configuration.

Final thoughts…

Developing a minimal configuration is an interesting challenge. My configuration is not quite as minimal as it used to be, I have added packages over time as needed to be productive with tasks at work. I also have a “default” set of “can't live without” packages I choose to install. David chose to implement the portions of some packages he actually uses rather than install the full package. The pros of just installing the package is reduced cognitive load (someone else does the work of writing and updating features you need) and an ostensibly shorter base configuration. The pros of writing the packages by pulling just the functionality you use and molding it to your configuration as David does is less reliance on external packages. This is quicker to get up and running with just your configuration, which can be handy when on a remote host, or a system with corporate controls that prevent downloading code not vetted by the corporate IT infrastructure.

Regardless of your approach, Crafted Emacs can help you get started with the building blocks you need to be productive quickly. After that, it's up to you to whittle things down or write custom code or whatever to fit your own personal needs.

Happy Crafting!

Tags: #emacs #systemcrafters

Footnotes

1 See this one and this one for context.

2 Start here for completion styles

Easy Customization interface?

There is the impression, at least to me, the built-in Emacs configuration utility known as the Easy Customization gets a bit overlooked by a lot of users. I see posts in different places about people just coming to Emacs and wanting to get started. What they tend to find is random snippets of Emacs Lisp to paste into a file. Rarely does anyone actually mention you can configure Emacs without writing any lisp code and get quite a well configured Emacs as a result.

The problem.

I have been nagged by a behavior in Emacs, one I'm guilty of authoring in which the *Completions* window unhelpfully pops up when I'm trying to complete something in the minibuffer with fido-vertical-mode. This seems like a duplication of effort and is largely due to the way Crafted Emacs sets up completion in the crafted-defaults-config module. As I was considering how I might resolve this I started Emacs in a blank directory (ala the --init-directory command line parameter), and then I opened the Emacs manual (C-h i) and started reading chapter 9 on completions.

Researching.

As I was reading, I thought to set some customizations for completions, so I ran M-x customize-option RET <option> RET and then applied the settings. This generated a bunch of variable settings in a block of lisp. But I didn't write any of it. I just set values for my preferences and Emacs saved those decisions in a way it would be able to consume later – in the custom-set-variables form.

Going bigger.

After tinkering with completions for a bit, this thing grew another head and I thought about trying to see how close I could get to my current configuration without installing any packages and not writing any elisp, or at least as little as possible. The result can be found here. I think I was a bit surprised at how close I got to my normal configuration. Really, its about 80%-90% of the way there. I need a few extra packages to really flush things out, but in general, I have most of everything I need on a day-to-day basis. Full disclosure, I did write some lisp, I didn't find a way to change key bindings through the Easy Customization interface, and I modified the display-buffer-alist by copying code from Crafted Emacs, but I could have used the Easy Customization interface instead.

And bigger still.

Inspired by how easy that was, I rewrote my entire configuration. Starting with the base from above, I just added more customization through the Easy Customization interface, wrote some elisp where it seemed to make sense and restarted Emacs. I goofed in a couple of places, but those were easy to fix. I looked through all the packages I was installing decided I didn't really need some of them, and left them out of this configuration. I listed all the packages directly in the custom-set-variables form as values for the package-selected-packages variable. Crafted Emacs does this by calling add-to-list in the *-package modules. So, by putting them directly there I didn't need any of the *-package modules, and since the custom.el file gets loaded early, I could still call package-install-selected-packages per the Crafted Emacs manual. I do have some elisp to conditionally add some packages to the list based on which system-type or emacs-version or if certain executables are on the system. I still use the *-config modules from Crafted Emacs and some of my own personal modules get loaded as well. The rest of the configuration is largely keybindings and lazily applied settings when certain packages are loaded.

The result.

Overall, I'm happy with the result. The “minimal” version of my init.el file is about 66% of the size of the “craftedv2” version, which is a bit arbitrary as I have my configuration spread out over numerous other files (custom.el, custom modules, Crafted Emacs modules). Startup time is less than a second, not that it matters since I run Emacs as a server and then use emacsclient to start editing sessions as needed.

Conclusion

What started out as just tinkering with completions and the Easy Customization interface turned into a rewrite of my configuration. I do like to recommend the usage of the Easy Customization interface, especially for those coming to Emacs for the first time.

Tags: emacs

Literate Emacs Configurations

I'd like to present some thoughts on literate configurations. This is one of those interesting bits in the Emacs configuration space that shows up from time to time. I'm in the “I don't do it this way” camp and I'll present some thoughts on why that is. For those of you who choose to be in the “I do it!” camp, well, that's fantastic! The great thing about Emacs is doing it “your” way, whatever “way” that is.

What is it anyway?

Donald Knuth wrote, “Literate programming” is a methodology that combines a programming language with a documentation language, thereby making programs more robust, more portable, more easily maintained, and arguably more fun to write than programs that are written only in a high-level language. The main idea is to treat a program as a piece of literature, addressed to human beings rather than to a computer. The program is also viewed as a hypertext document, rather like the World Wide Web.”1

In the sense of your Emacs configuration, it is basically writing everything in some markup language with executable code snippets woven through the prose documenting your decisions. The most common markup language in this context is the venerable Org mode. It is well supported, has a huge list of language integrations, including Emacs Lisp (of course), and is arguably one of the “killer features” available to Emacs users. It's also a very simple markup language with very little in the way of actual syntax and it exports to many different presentation formats. Forges like GitHub and GitLab will render Org files natively in the same way they render Markdown files. This make it very useful for influencers like Protesilaos Stavrou2 (also known as “Prot”) among others to host their Emacs configuration where people can read them, get some context on why or how the configuration works, and still see the code. David Wilson in a recent livestream3 converted his configuration back to a literate style and mentioned some of the advantages being:

  • Having things nicely organized in a single large Org file.
  • Easy to generate a website from the configuration.
  • Easy to describe why you do certain things in your configuration.

Why its a challenge

In the same video, David goes on to talk about why he stopped using it for a while:

  • He got tired of having to re-tangle his configuration files every time he synced his dot files between machines.
  • If you tangle (ie. generate) all the code files in your “dot files” folder and then symlink those to your home folder, you either have to ignore all the generated files or check them in with your Org file, which means lots of diffs when you re-tangle your Org file after each change.
  • There is the possibility you might change one of the generated files and forget to update the Org file, which would then overwrite your changes when you re-tangle your configuration.

Another challenge, it does take time to tangle your configuration, especially if yours is on the longish side. Do that every time you save your configuration and Emacs will seem to lag a few seconds as it tangles things.

Why I'm a “don't” person

Keeping in mind, these are my opinions, here are some reasons why I prefer not to use a literate configuration:

  • It's a hassle. Keeping things synced, both on the filesystem as well as in version control is just more than I prefer to manage.
  • It's easier to not use a literate configuration. No extra configuration, no slow down tangling things, no extra files to either ignore or version frequently, etc.
  • Documenting things can be done just as easily with code comments.
  • Organizing your configuration is a matter of discipline not markup. Using Org mode does not improve how well organized your code is if you don't discipline yourself to keep things organized. It's just extra syntax. The same is true of keeping your configuration in “module” files. Its only more organized if you maintain the discipline of keeping it organized.
  • I don't need to generate a website from my configuration. Anyone who wants to read it can do so on GitLab, which will render the Emacs Lisp code and comments just fine.

Outline modes – outline-minor-mode and allout-mode

There was a suggestion on David's stream regarding using allout-mode, one of the outline modes built-in to Emacs. I've used this mode in the past, but I usually end up back in Org mode because of all the features that project brings to the table.

allout-mode is a fairly simple outliner though and pretty easy to get into if you need a nice outlining tool. And by simple I mean, really simple. No frills. It outlines and that's about it. The default keyboard prefix is C-c SPACE which can be a bit to type, but once you get used to it, its not bad. That said, changing it to something like s-SPACE might make it more approachable.

Using the built-in outline modes (outline-minor-mode or allout-mode) seem to be a nice alternative. In fact, reading through the documentation on Comment Tips4, using three ;;; should start on the left column and are already considered headers in Outline mode, thus using them and turning on outline-minor-mode and you instantly get navigation keyboarding, the ability to collapse sections, etc. and you can document your code in the same way you would with Org mode using only the Emacs Lisp syntax, and no tangling required.

allout-mode adds additional flavor to those ;;; comments, so you only write ;;; plus the header level needed and you also get code navigation keyboarding, the ability to collapse sections, etc and you still only document your code with Emacs Lisp syntax and no tangling required. allout-mode also should allow generating your configuration as LaTeX, but there is a bug in my case which I'll try tracking down at some point. I don't need it as I don't need to generate my configuration in any other language than the default Emacs Lisp.

Getting started with allout-mode

I'll show an example here of how to get started using allout-mode. Using outline-minor-mode doesn't require anything, per se, but you might like to use something like this to turn it on in your configuration:

M-x add-file-local-variable-prop-line RET eval RET (outline-minor-mode 1) RET

This would assume you are just using multiple semi-colon's as described in the Emacs Lisp Comment Tips4. To use allout-mode requires just a little more setup and then some updates to those lines beginning with ;;;.

So, lets start with your init.el file.

  • M-x add-file-local-variable-prop-line RET mode RET emacs-lisp RET
  • M-x add-file-local-variable-prop-line RET eval RET (allout-mode 1) RET
  • M-x add-file-local-variable RET eval RET (allout-expose-topic '(0 :)) RET
  • M-x revert-buffer RET

The list item in that list sets the variables and executes the code, you'll get the standard Emacs warning about this, so you can choose to say 'y' to run it once. Other options exist to persist that decision as well. That's all you need to get things started. You should also customize the allout-auto-activation variable and set it to t, at least you should according to the various docstrings in allout.el.

To proceed from there, you add ;;;_* to major headings. A sub-heading can be added with ;;;_ * (Note the extra space). See the allout.el source to see a more detailed example. In my case, I generally use just these, with a couple of exceptions.

allout-mode allows you to set your bullets to something that means something semantically. For example ;;;_ ? might indicate a question (like, “do I need this section?”), ;;;_ ^ might indicate this section refers to the section above, for example if you are setting up IDE rules, you might have generic IDE configuration first, then sub-topics for each programming language:

;;;_* IDE
;;; This section configures eglot as my language server
(require 'crafted-ide-config)           ; Crafted Emacs module
(with-eval-after-load 'crafted-ide-config
  (crafted-ide-configure-tree-sitter '(latex python)))

;;;_ ^ Prog mode hooks
(with-eval-after-load "prog-mode"
  (keymap-set prog-mode-map "C-c e n" #'flymake-goto-next-error)
  (keymap-set prog-mode-map "C-c e p" #'flymake-goto-prev-error))

;;;_ ^ Python
(require 'my-ide-python)                ; My custom Python module

Example init.el file

To complete this blog post, here is the Crafted Emacs example init.el5 using allout-mode. To complete the requirement as mentioned by Mr. Knuth1, you should be able to export this to LaTeX, although, for me there seems to be a bug.

;;; init.el --- Crafted Emacs Base Example -*- mode: emacs-lisp; lexical-binding: t; eval: (allout-mode 1); -*-

;; Copyright (C) 2023
;; SPDX-License-Identifier: MIT

;; Author: System Crafters Community

;;; Commentary:

;; Base example init.el (extended from the info file).
;; Basic example of loading a module.

;;; Code:

;;;_* Initial phase

;;;_ ^ Custom File
;;; Load the custom file if it exists.  Among other settings, this will
;;; have the list `package-selected-packages', so we need to load that
;;; before adding more packages.  The value of the `custom-file'
;;; variable must be set appropriately, by default the value is nil.
;;; This can be done here, or in the early-init.el file.
(setq custom-file (expand-file-name "custom.el" user-emacs-directory))
(when (and custom-file
           (file-exists-p custom-file))
  (load custom-file nil :nomessage))

;;;_ ^ Bootstrap crafted-emacs
;;; Bootstrap crafted-emacs in init.el
;;; Adds crafted-emacs modules to the `load-path', sets up a module
;;; writing template, sets the `crafted-emacs-home' variable.
(load (expand-file-name "../../modules/crafted-init-config"
                        user-emacs-directory))
;;; Adjust the path (e.g. to an absolute one)
;;; depending where you cloned Crafted Emacs.
;;; (load "/path/to/crafted-emacs/modules/crafted-init-config")

;;;_* Packages phase
;;; Collect list of packages to install. Do not just blindly copy this
;;; list, instead think about what you need and see if there is a
;;; module which provides the list of packages needed. This phase is
;;; not needed if manage the installed packages with Guix or Nix. It
;;; is also not needed if you do not need Crafted Emacs to install
;;; packages for a module, for example,
;;; `crafted-speedbar-config' does not require any packages to
;;; be installed.

;;; Add package definitions for completion packages
;;; to `package-selected-packages'.
(require 'crafted-completion-packages)

;;;_ ^ Manually select "ef-themes" package
(add-to-list 'package-selected-packages 'ef-themes)

;;;_ ^ Install the packages listed in the `package-selected-packages' list.
(package-install-selected-packages :noconfirm)

;;;_* Configuration phase
;;; Some example modules to configure Emacs. Don't blindly copy these,
;;; they are here for example purposes. Find the modules which work
;;; for you.

;;;_ ^ Completions
;;; Load configuration for the completion module
(require 'crafted-completion-config)

;;;_ ^ Crafted Emacs configuration
;;; Some more configurations that don't require packages to be installed
(require 'crafted-defaults-config)
(require 'crafted-startup-config)

;;;_* Optional configuration

;;;_ ^ Profile emacs startup
(defun ce-base-example/display-startup-time ()
  "Display the startup time after Emacs is fully initialized."
  (message "Crafted Emacs loaded in %s."
           (emacs-init-time)))
(add-hook 'emacs-startup-hook #'ce-base-example/display-startup-time)

;;;_ ^ Set default coding system (especially for Windows)
(set-default-coding-systems 'utf-8)


(provide 'init)

;;;_* Local emacs vars.
;;Local variables:
;;allout-layout: (0 :)
;;eval: (allout-expose-topic allout-layout)
;;End:

;;; init.el ends here

Final thoughts

I'm generally not a fan of literate configuration. The idea isn't a bad one, it's just not for me. I don't see the point in writing in two different languages for this particular use-case, and there are simpler ways to get the same effect. I do think literate programming has it's place, for example, see this video from a recent meetup on the subject. I encourage you to try it both ways though, and to find the one which makes sense to you in your configuration.

Happy Crafting!

Footnotes

1 https://www-cs-faculty.stanford.edu/~knuth/lp.html

2 https://protesilaos.com

3 https://www.youtube.com/live/Ex9zI4Fcirs?si=Izqdqu88BSmsI-c6

4 https://www.gnu.org/software/emacs/manual/html_node/elisp/Comment-Tips.html

5 Yep, shameless plug. https://github.com/SystemCrafters/crafted-emacs/blob/master/examples/base/init.el

Happy New Year

Hello Crafters, welcome to 2024! Hope everyone had a wonderful and safe holiday season, and now that is behind us time to get back to work, right!?!!

Crafted Emacs Update

Since the release of Crafted Emacs v2 last year, things have been a bit quite on the development front. Since the last time I gave an update there have been a few improvements:

  • Usage of eglot-ensure was changed to an “opt-in” configuration. This change included checking to see if the mode was actually available on the system before adding eglot-ensure to a hook. This makes a lot more sense now, not everyone will have all the programming modes installed, much less have the desire to turn on eglot for all of them.
  • There was a bug in the docs after the release, I missed removing a reference to the development branch. Thanks to @bird-dancer for noticing and providing the PR for the fix!
  • Another bug related to loading the custom-file was found by @jvalleroy, also thanks for the PR to fix it!
  • @mgmarlow has been fairly active, providing discussion, the patch for eglot-ensure mentioned above, and an example configuration for the rust programming language. Thank you!!
  • I changed our tree-sitter configuration, originally we tried to install every ts grammar by default, but a change to the tree-sit-auto broke it. Reviewing how we were using that package, it seemed we had been approaching the problem backwards all along, so it is also an “opt-in” rather than an “opt-out” configuration.

Example: Adding the Go language

There have been frequent questions around providing one language mode or another, or all of them, over the course of the project. With Crafted Emacs v2, we moved to more general modules, which a user could use as building blocks for extending Crafted Emacs as they see fit. You can read more of the language module discussion here if you wish.

Currently, we have the example of adding rust as a language module, I'll walk through the code I used recently to extend my own configuration for the Go language.

The initial process

I took a little time to search the internet for others who had configured Emacs for Go development. I also took some time to review the existing go-mode.el, which originally shipped with Go, but later was rewritten by Dominik Honnef, see the GitHub page for more information.

Updating my init.el configuration

I need to make several changes in my base configuration file:

  • I add to the list of packages which need to be installed
  • Turn on the tree-sitter mode for Go

Adding the needed packages

I need a couple of packages installed as Emacs doesn't know about Go out of the box. I add these lines early in my init.el file:

(add-to-list 'package-selected-packages 'go-eldoc)
(add-to-list 'package-selected-packages 'go-mode)

I evaluate these lines, then evaluate this (package-install-selected-packages :noconfirm) to get the packages installed.

Update treesit-auto to install go-ts-mode

I like to use tree-sitter modes, so I add go to the list I already have. Mine now looks like this (yours may be different):

(with-eval-after-load 'crafted-ide-config (crafted-ide-configure-tree-sitter '(go java javascript latex markdown python typescript)))

Putting together a custom module

I start by building on the work in crafted-ide-config:

(require 'crafted-ide-config nil :noerror)

This way, I get to take advantage of the work already done to setup eglot, tree-sitter modes, editorconfig, etc.

Setup project.el

We need to tell project.el about Go projects. project.el does not know about GOPATH or go modules, so we need to tell it how to find the go.mod file. This also enables eglot to work as it uses project.el to find project assets.

(require 'project)

(defun project-find-go-module (dir)
  (when-let ((root (locate-dominating-file dir "go.mod")))
    (cons 'go-module root)))

(cl-defmethod project-root ((project (head go-module)))
  (cdr project))

(add-hook 'project-find-functions #'project-find-go-module)

Setup hooks

Now, we need to setup some hooks to turn things on. I setup both go-mode and go-ts-mode here, but you may choose whichever. That said, go-mode and go-ts-mode are not equal. There are features provided in go-mode that are not available in the ts version. This lack of parity is a bit unfortunate, and exists for other language modes as well. Usually, the ts modes is much less fully featured.

You can reasonably pick one of the modes in the example below and leave the other one out, or just include both if you aren't sure, no harm done.

On the hooks, you'll see I order them using numbers. This is because I want to make sure flymake is loaded before the call to flymake-show-buffer-diagnostics.

For the before-save-hook I make sure it is first in the list (a negative number makes it earlier in the list), but I also make it buffer local, rather than a global setting. So the call to eglot-format-buffer only gets called on go buffers.

(require 'go-mode)
(require 'eglot)


;; these lines are only needed if you choose to use go-mode
(add-hook 'go-mode-hook 'flymake-mode 8)
(add-hook 'go-mode-hook 'flymake-show-buffer-diagnostics 9)
(add-hook 'go-mode-hook 'eglot-ensure 10)

;; these lines are only needed if you choose to use go-ts-mode.
(add-hook 'go-ts-mode-hook 'flymake-mode 8)
(add-hook 'go-ts-mode-hook 'flymake-show-buffer-diagnostics 9)
(add-hook 'go-ts-mode-hook 'eglot-ensure 10)

;; Optional: install eglot-format-buffer as a save hook.
;; The depth of -10 places this before eglot's willSave notification,
;; so that that notification reports the actual contents that will be saved.
(defun eglot-format-buffer-on-save ()
  (add-hook 'before-save-hook #'eglot-format-buffer -10 t))
(add-hook 'go-mode-hook #'eglot-format-buffer-on-save)
(add-hook 'go-ts-mode-hook #'eglot-format-buffer-on-save)

Setup gopls

Configuring gopls when using eglot happens on the eglot-workspace-configuration which can be set globally in your Emacs configuration or in a .dir-locals.el file in your project. I choose to set it in my Emacs configuration. For more configuration options for gopls see here

(setq-default eglot-workspace-configuration
              '((:gopls .
                        ((staticcheck . t)
                         (matcher . "CaseSensitive")))))

Setup flymake window height

And, finally, as I want the diagnostics window to popup when I open a Go file, I configure the window height to my preference. This sets the window height to 10 lines at the bottom of the frame so I can read the diagnostics as they popup. Recall, I add the function to open the flymake diagnostics window to the hook go-mode and go-ts-mode hooks.

(add-to-list 'display-buffer-alist
             '("^\\*Flymake diagnostics"
               (display-buffer-reuse-window display-buffer-pop-up-window)
               (window-height . 10)))

Updating my configuration

I put all that code in a file located in the custom-modules folder in my user-emacs-directory, which in my case is: $HOME/.emacs.d/custom-modules/my-ide-go.el. Crafted Emacs automatically puts the $HOME/.emacs.d/custom-modules onto the Emacs load-path list, so all that remains is to add the appropriate require in my init.el file:

(require 'my-ide-go)

Now, I can restart Emacs or just evaluate that one line and my Go configuration is installed!

Tags: #emacs

It's been slow… which is a good thing… I think

It's been a surprisingly slow month in Crafted Emacs land. After the release of V2, I sorta expected a flurry of messages or issues related to transitioning to the new release. None of that happened. Naturally, I'm surprised. I'm hoping it means we did a good job with Crafted Emacs on this release.

An interesting discussion…

There was a discussion started on creating per-language modules. The summary is basically we had tried something like that in Crafted Emacs V1, but there are issues trying to do that going forward. We opted to not try to provide per-language modules deliberately while providing a (hopefully) richer crafted-ide module to provide some baseline starting point for most languages. There are gotchas here as noted in the discussion, one of which happens to be the discrepancy between features provided by language mode and the corresponding tree sitter enabled module (ala python-mode vs python-ts-mode). There was a good suggestion of providing example configurations for language modules which could reside in the examples folder. This would be a welcome addition, so if you have one, perhaps consider submitting a PR. Common requests are for Python, Javascript, Rust, Go, and C/C++.

Odd behavior when loading a theme…

There is an odd message that might show up for you from time to time, it looks something like invalid function '(("gnu" . 99) ...). It might say something slightly different after the “invalid function” bit, but looking closely, it appears to be a value set in the custom-set-variables call usually held in the custom.el file. There is a related discussion on the Emacs mailing list here with a very detailed description of what's going on. In Crafted Emacs, we load the custom.el (assuming it exists) very early in the initialization process. There are several reasons for this, we want to load any customizations the user saved through the “Easy Customization” facilities provided out of the box in Emacs; having the values pre-loaded causes no harm when using customize-set-variable; the user could use the custom.el file as their base configuration on a different machine if they needed to spin things up quickly, but didn't have access to their entire Emacs configuration – for example on remote hosts. However, the side-effect is the values get marked as “CHANGED outside Customize”. Which is a surprise since we deliberately use the forms from the built-in customization system. We also save those values at the end of the initialization process to enable the behaviors above. What doesn't happen automatically though, when we use customize-set-variable and later customize-save-customized, neither form causes the values to be loaded again. Even when the values haven't changed from what was saved the last time Emacs was started and this time, the values get marked as “CHANGED”. I thought about calling customize-save-variable which sets the value and writes it to the custom.el file, but that would affect startup time. Not everyone cares about that – those of us who start Emacs once and then run it basically indefinitely don't care so much about startup time. Some people do, and I like for things to start snappily as well. The end result is we load the custom.el file a second time at the end of the initialization process so the values are marked as “SET and SAVED”. Doing so, I haven't been able to get the “invalid function …” error when I decide to change my theme in the middle of a running session.

Yep, that's me optimizing for a corner case. The only time a user would run into that error was when they tried to load a theme after Emacs had already started and after setting some variables with customize-set-variable, but not loading the changes from the custom-set-variables form. Even then, it wasn't a guarantee you'd hit it. Sometimes I had to call load-theme or M-x load-theme several times before I'd hit the error. It's pretty elusive.

And that is the only change to Crafted Emacs since the release.

A non-sequitur topic change…

December is nearly here, and this time of the year in most parts of the world begins celebrations of different holidays. I may (or maybe I won't) get another post out later in December, but in case I don't, on behalf of the Crafted Emacs team we wish you a happy and safe holiday season.

Happy Crafting!

Tags: #emacs

Crafted Emacs V2 Announcement

Crafted Emacs V2 is released! The current master branch is now updated to reflect the new approach to assisting getting your configuration up to speed. Info files exist, so feel free to C-h i m Crafted Emacs RET to read the manual from the comfort of Emacs!

There is a transition guide:

See the v1 to v2 transition guide

This is a breaking change for anyone using Crafted Emacs V1. For those wishing to track the former version of Crafted Emacs, that can be done by following the craftedv1 branch, which was the former master branch. This version will likely not see much in the way of maintenance, and is provided for legacy purposes and to assist those who may need to take some time to transition to v2.

The branches used during development of v2 have been deleted. The new master branch is the currently supported and official release of Crafted Emacs. Additionally, many issues have been closed. The ones remaining exist because they were topics we either planned for future release or document some decision.

If you have questions, feel free to create issues (best approach) or see if one of the maintainers is in the Emacs – System Crafters channel.

Happy Crafting!

Tags: #emacs

Crafted Emacs V2 Pre-release Announcement

After the RC1 announcement last month, we have had a flurry of small tasks and things to fix. Those are now done and we are ready to release Crafted Emacs V2.

We will be releasing Crafted Emacs V2 on Friday, 20 October 2023.

This will be a breaking change for anyone using Crafted Emacs V1 (the current version from the master branch). We will be moving branches around in git, which will likely add to the confusion, but after Friday this week, there will be a craftedv1 branch for those who wish to stay with the starter kit version of Crafted Emacs. This version will likely not see much in the way of maintenance, and is provided for legacy purposes and to assist those who may need to take some time to transition to v2.

After Friday, the branches used during development of v2 will cease to exist. Thus if you are tracking the alpha, beta, or RC1 branches, those will disappear. The new master branch will be the currently supported and official release of Crafted Emacs. Additionally, many (most) of the issues still outstanding will be closed as no-longer applicable since most were opened against v1 and are really old with no further discussion occurring on them.

Make sure to take a look at the v1 to v2 transition guide. N.B. This link work for the rest of this week, but not after the release. I'll post another blog entry with an updated link on Friday. If you have questions, feel free to create issues (best approach) or see if one of the maintainers is in the Emacs – System Crafters channel.

Happy Crafting!

Tags: #emacs

RC1 is available

Short note: Crafted Emacs RC1 is out. For those (and hopefully there are many) who wish to try it, you need to checkout the craftedv2RC1 branch.

Moving forward, there are a few things we are working on. We have some progress on a template to use when submitting issues, that should be available “soon”. We will be working on some guidance when transitioning to Crafted Emacs V2 from Crafted Emacs V1. We will also look to beefing up the documentation on contributing modules for Crafted Emacs. We have one for contributing documentation, but only a brief mention in the README.

None of those items are blockers for releasing Crafted Emacs V2. We'll leave RC1 in place for a couple of weeks, depending on community involvement and any issues encountered which need to be fixed. We may have a RC2 if there are enough issues to fix.

Finally huge thanks to my fellow contributors, Judy and Stefan, for putting in so much time and helping getting to this point so quickly!! You guys are awesome!

Happy Crafting!

Tags: #emacs

RC1 Progress

It's almost here. A ton of work has been done on the documentation front led largely by Stefan. I think I'm the actual blocker at the moment, as I need to document the Crafted OSX module. I'll get to that in the next few days. Once I complete that, we should be ready for a final internal review before cutting to a RC1 branch.

TODOs once RC1 is released

  • We need to develop a transition guide to address the differences between Crafted Emacs V1 and V2. We'd like for this to be a smooth transition, but V2 is completely different in mindset from V1, so there will be a lot of work to transition from one to the other.
  • I'll delete the deleted-modules directory
  • Double check comments in code to make sure they are still accurate.
  • Testing.

Crafted Emacs V2 release on the horizon

Once we get the RC1 branch put out the door, we'll be looking for as many as who are willing to put the screws to the configuration and file bug reports. Once those are resolved, we'll release V2. So the time between RC1 and a V2 release may be short or long depending on how many people are willing to test and file issues for us to look at and resolve. Once things are settled out for about a week or so, we'll do another internal review to make sure we have covered everything and then I'll push the next release and submit a blog post.

Updates

Fun fact (I'm sure you probably knew this), Emacs has a way to document changes in a ChangeLog file. So, I've given it a go for the past few weeks to keep track of changes since the my last post here. It's a bit of a duplication of work from one sense because the same information is in the *vc-change-log*, it just isn't formatted the same way. Not sure I'll keep up with it, but it has been an interesting exercise. So, here is what we have been up to recently:

  • Documentation for these modules:
    • Crafted Defaults
    • Crafted Evil
    • Crafted IDE
    • Crafted Init
    • Crafted Speedbar
    • Crafted Startup
    • Crafted Updates
    • Crafted Workspaces
    • The Getting Started Guide
  • Fixes for the Crafted Speedbar module
  • Fixes for the Crafted OSX module
  • Deleted the obsolete bootstrap directory.

In other news…

I've been using vc mode a lot more for my version control operations in Emacs. Magit provides quite the nice experience, but vc mode is also a lot nicer than what it seems a lot of people give it credit for. One of the nicest things about magit is the menu that pops up when need to do an operation. The status page is also well built and has some nice information on it. If I use vc-dir and then from there type L I get nearly the same information. At the top, I see my repository information, under that a list of things that changed or are unregistered, and in the bottom window, I see the *vc-change-log*. For me, there have been several cases where vc mode has been quicker to operate than magit. I haven't tried to track that down, but especially for local work, vc mode is extremely quick. Some operations take extra steps. For example in magit I can stage a new file and a changed file at the same time and commit that in one step. With vc, I have to register the new file, commit that, then possibly amend that commit to include the edited file because everything has to be in the same state and added is not the same as edited. In cases like that, I just use magit. Simpler to do. Otherwise, it's just as easy to use vc either directly from the buffer I'm editing or from vc-dir to mark multiple files and then commit them.

I've also tried working with forge in magit. For me, it's been a bit flaky. A couple of things to pay attention to: the repository name must match on both sides. So, for example, you must use git clone https://github.com/SystemCrafters/crafted-emacs and not git clone https://github.com/systemcrafters/crafted-emacs because the case doesn't match and forge won't find the repository. Once you get that all worked out, you can pull the issues and PRs, but you can't approve or request changes on a PR from the forge interface. You can post comments though. Still a good package though, and if you work with PRs but don't need those features, it might work out for you. There hasn't been a release in over a year, and the released version has a number of defects which show up with odd messages like “Switching to deleted buffer”. There are fixes available, so you may prefer to pull forge directly from source with package-vc (or something similar) or just use the version from MELPA. I'll probably contact the author and ask for an updated release and I'd rather have the released version than the development version.

Happy Crafting!!

Tags: #emacs

Documentation work has been ongoing this month, as well as a few fixes. I'll get to that in a moment though.

New Teammate!

I have expanded our team to include Stefan Thesing (@sthesing) who has been doing a ton of work on getting documentation in order. He has raised a few points for thoughtful discussion and has also worked on a few code PRs as well. I appreciate his efforts and he seemed to be a good fit for the team. Judy and I had a conversation about it and decided to see if he wanted in. We are happy to announce his agreement and look forward to working together even more in the future!

Updates

Now that I have that wonderful news out of the way, here are some of the updates to the Crafted Emacs V2 Beta branch:

  • The way we figure out if a package is available for configuration was updated across the board. This took some thought and research, but we found a pretty good way forward (at least I think so). Stefan was instrumental in getting most of that work done.
  • Documentation. Lots and lots of documentation. Stefan reproduces the crafted-completion-config documentation replete with screenshots along the same lines as he did for the prior release. Duchene Horst provided an update for using the straight package manager.
  • Judy provided updates for named functions in hooks, other broken feature guards, the path for when the auto-insert template for Crafted Emacs modules fires, and consolidating how aggressive-indent-mode is configured.

RC1 on the horizon

We have a plan for a RC1 type of release. That is coming, hopefully soon. Right now, our goal is to complete the documentation of the modules listed in Issue 128, so if anyone wants to submit a PR for one of the modules that doesn't have a check mark next to it, please do so! The more help we get, the faster we get there!

Happy Crafting!!

Tags: #emacs