About Lectures Research Software Blog
Musical Site

Moods Blog

Dojo Shin Kaï

RSS Feed
Thank you!

XHTML 1.0 conformant
CSS 2.0 conformant
Didier Verna's scientific blog: Lisp, Emacs, LaTeX and random stuff.

Tag - Emacs

Entries feed - Comments feed

Tuesday, September 3 2013

Menu bar icons for Emacs

Note: the feature described below is now available in the cutebar branch of my Emacs fork on GitHub.

A huge peeve of mine on OS X is the mixture of the (application) menu bar, starting on the left, and the status bar, starting on the right: when you have a lot of status indicators like me, even a reasonably sized application menu bar will irreparably hide a lot of status, which is really annoying.

One day, I had this idea that application menu bar (wide) titles could be replaced with (narrow) icons, hence leaving more space to the status bar. Of course, it shouldn't be up to the menu, or even to the application itself to choose which icon to use. It should be up to the user. A user will want a single icon set to work with all applications (e.g. you choose a nice File icon, and you want all applications to use it instead of the word "File").

So one day, I implemented a SIMBL plugin and preference pane for doing exactly that. Don't look for it, it's never been released. It lets the user create associations between menu titles and icons and hijacks OS X applications to modify the appearance of their menu bar. Alas, it doesn't work very well. Native Cocoa applications not doing anything fancy with their menus are ok, but most other applications are not.

Emacs menu bar icons Today, let me introduce some support for this feature in Emacs. Attached to this article is a patch against the current trunk plus a small image file. For this to work, you will need to put the image file (barsplit.png) in the etc/images/ directory of Emacs'source tree, apply the patch and recompile (--with-ns of course). Then, find yourself a nice set of icons and go customize the options menu-bar-use-icons, menu-bar-icons-directory and menu-bar-icons in the "menu" custom group. The docstrings should be self-explanatory. As you can see on the screenshot, what you get is a much narrower, visual menu bar. The first menu (the so-called "application menu") always uses the official application's icon. The other ones are your choice. Finally, the menu bar ends with a visual separator allowing to better distinguish its end from the start of the status bar.

The current implementation is very naive (sorry, I meant highly dynamic): titles / icons associations are recomputed every time the menu bar is redrawn. But this has in fact some advantages:

  1. the code is quite simple,
  2. customizations made by the user are visible immediately, without the need for a complex event listener / notification / whatever machinery (this machinery may already exist in the Emacs codebase though).

In fact, I've been using this patch for quite a while now and I didn't notice any performance impact on my 3 years-old Mac Book Pro. One last thing you need to know: the behavior of this feature may be unreliable (even if implemented correctly, which I think I did) because messing with the menu bar like this is uncharted territory, totally unsupported by Apple. Enjoy anyway :-)

Now, if somebody comes up with a nice and comprehensive set of menu bar icons for Emacs (and other OS X apps), I'd be delighted...

Tuesday, May 28 2013

el-rcfiles is released (first public version)

I've been using this for years, but never bothered to make it public until now.

el-rcfiles is a very small and simple library which provides Unix-like RC files for Emacs Lisp libraries. It's compatible with GNU Emacs and XEmacs, available in ELPA form, as a tarball and from GitHub. More details (including download) available here, but here is also the library's commentary section, for quick reference.

;;; Commentary:

;; The purpose of el-rcfiles is to provide the equivalent of traditional
;; Unix rc files (i.e. configuration files) for Emacs Lisp
;; libraries. The advantages of using configuration files are the
;; following:
;;   - your initialization file is less bloated,
;;   - since configuration files are lazily loaded, your Emacs session
;;     is (or begins) lighter. That is unless you already use lots of
;;     EVAL-AFTER-LOAD forms...

;; Usage:

;; 1. Load the library, go to the rcfiles Custom group and tweak (or not).
;; 2. Put a call to (rcfiles-register-rc-files) in your initialization
;;    file. This function can also be called interactively anytime you
;;    add, remove or modify a configuration file.
;; 3. Put your configuration code for a library `foo' in a file called
;;    `<rcfiles-directory>/foo<rcfiles-pseudo-extension>.el'.

Tuesday, May 14 2013

Emacs session bootstrap tweaks

This article essentially describes the top of my Emacs init file. That part of the code is devoted to modify the session bootstrap process, that is, some things that are normally done very early. It mostly deals with the package infrastructure but also contains a couple of other tricks that some people may consider useful. It goes like this…

The first line is self-explanatory (and please, be warned that I will discard any comment about it. You know why).

(require 'cl)

Platform-specific tweaks

A self-contained Emacs.app on MacOS X has its own site-lisp directory, but I want to make sure that the standard Unix one is here as well, and takes precedence.

(when (featurep 'ns)
  (add-to-list 'load-path "/usr/local/share/emacs/site-lisp"))

Updated When /not/ starting Emacs from the command-line (e.g. MacOS X app clicks or Quicksilver/Alfred, Unitiy launcher on Ubuntu etc.), I don't necessarily get my environment-based exec-path which can be problematic (e.g. for finding auxiliary programs such as movemail, gpg etc.). Emacs used to store the build-time value of exec-path in the custom's standard-value property, which was convenient for me because since I compile it myself, I could reuse that. This has changed however since this commit:

commit 2fc11b3fa3418e0e8a624376ea8bf4cbc70c2657
Author: Ludovic Courtès <ludo@gnu.org>
Date:   Mon Apr 20 17:44:23 2015 -0400

So now instead, I have patched it to save the build-time value in a new variable called BUILD-TIME-EXEC-PATH.

(when (boundp 'build-time-exec-path)
  (mapc (lambda (path) (setq exec-path (remove path exec-path)))
  (setq exec-path (append build-time-exec-path exec-path)))

ELPA infrastructure

Initialize ELPA now so that the rest of the initialization process may rely on packages without having to go through after-init-hook.

(require 'package)

I want system-wide directories to be named emacs-packages instead of site-lisp/elpa.

(setq package-directory-list
      (let (result)
        (dolist (path load-path)
          (and (stringp path)
                 (equal (file-name-nondirectory path) "site-lisp")
                 (push (expand-file-name "emacs-packages"
                                                       (directory-file-name path)))
	(nreverse result)))

I want my local directory to follow the same convention.

(setq package-user-dir "~/.emacs.d/emacs-packages")

Now, it's okay to initialize ELPA.


Now that the packages have been initialized, I actually want ELPA to install in /usr/local/share/emacs/emacs-packages by default, and keep my local directory for manual installations. One simple way to achieve that is to set my local directory to /usr/local/share/emacs/emacs-packages and to remove that from the system-wide directory list. One small drawback of this is that my local path is gone, so any new package installed there won't be seen until the next restart. This is not much of a problem though.

(setq package-user-dir "/usr/local/share/emacs/emacs-packages"
        package-directory-list (remove "/usr/local/share/emacs/emacs-packages"

Site and local (non ELPA) packages infrastructure

The purpose of this other infrastructure is to support packages that would be installed manually, outside ELPA, and in a way similar to XEmacs packages. A packages directory has lisp/, etc/ and info/ subdirectories. Every package installs its stuff directly in etc/ and info/, but adds its own subdirectory to lisp/ and puts its code (including a potential autoloads file) in there.

This additional infrastructure comes in handy in several situations. For instance, having Slime (auto)loaded in your session now becomes as simple as this:

ln -s /path/to/slime /usr/local/share/emacs/local-packages/lisp/

(defun dvl-initialize-packages (directory)
  "Initialize non-ELPA packages DIRECTORY.
This means:
  - adding the whole lisp/ subtree to LOAD-PATH,
  - loading the autoload files found there.
  (let ((default-directory (expand-file-name "lisp" directory)))
    ;; 1. Update LOAD-PATH
    (setq load-path
	   (let ((load-path (copy-sequence load-path)))
	     (append (copy-sequence (normal-top-level-add-to-load-path '(".")))
    ;; 2. Load autoload files
    (loop for directory in load-path
	    while (string-prefix-p default-directory directory)
	    do (mapc #'load (directory-files directory t "-autoloads\\.el$"))))
  ;; 3. Update the default Info directory list
  (add-to-list 'Info-default-directory-list
   (expand-file-name "info" directory)))

(require 'info)

Be sure to do this by increasing priority order.

(mapc #'dvl-initialize-packages

And now we can re-initialize Info with the proper defaults.

(setq Info-directory-list nil)

Custom settings

Now that we have bootstrapped the complete packages infrastructure, we can set the Custom file to something that makes sense and load it now.

(setq custom-file "~/.emacs.d/custom.el")
(load custom-file)

RC Files

Finally, install the rc files loader and we're done bootstrapping.


That completes my session bootstrap process.

French Flag English Flag
Copyright (C) 2008 -- 2018 Didier Verna didier@lrde.epita.fr