Jump to content

Emacs: Difference between revisions

From NixOS Wiki
imported>Nodupe
mNo edit summary
Warn about double-listing emacs-pgtk.
 
(25 intermediate revisions by 10 users not shown)
Line 1: Line 1:
{{Expansion|This article is incomplete.}}
{{application infobox
== About ==  
  |name=GNU Emacs
Emacs is an interactive graphical emacs lisp interpreter that comes with many applications, but is primarily used as a text and code editor. It has one of the largest repositories of packages of any similar code editor such as [[vim]] or its fork [[neovim]].  
  |image=EmacsIcon.svg
  |type=Text Editor
  |firstRelease=1985; 40 years ago
  |license=[https://www.gnu.org/licenses/gpl.html GNU General Public License]
  |os=Cross-platform
  |website=[https://www.gnu.org/software/emacs gnu.org/emacs]
  |github=
}}
<strong>Emacs</strong> is a free and open-source text editor known for its exceptional extensibility and adaptability. It can be customized into anything from a simple editor to a full development environment or productivity tool. Emacs features built-in self-documentation, syntax-aware editing, and a vast ecosystem of community-developed packages.<ref>https://www.gnu.org/software/emacs/</ref>


=== Features ===
For an easier introduction, [https://doomemacs.org Doom Emacs] offers a pre-configured Emacs framework with modern defaults and features like IDE tools, note-taking, and task management.
Emacs is often valued as a general purpose programming environment. Its power comes from its
* Extensibility
* Automatic self-documenting behaviour
* Flexibility
* Syntax awareness
* language server protocol support
* potential for reproducible portable literate configurations


=== Doom Emacs ===
There is an official Matrix room for Nix/Emacs: [https://matrix.to/#/#emacs:nixos.org #emacs:nixos.org].
The [https://github.com/hlissner/doom-emacs Doom Emacs] project provides a framework with a more beginner-friendly default configuration, and pre-configured modules for popular features (e.g. IDE-like features, note-taking, and time management). Since it uses pinning in its configuration for dependencies, it is possible to package Doom Emacs with nix (see [https://github.com/nix-community/nix-doom-emacs nix-doom-emacs]).


== Installation ==
== Installation ==
Several stable versions of emacs are available by default in nixpkgs, and unstable branches are also available via the community overlay. Also, see the [https://nixos.org/manual/nixos/stable/index.html#module-services-emacs NixOS manual entry for Emacs] for additional details about installation and configuration.


=== With Home-Manager ===
==== Shell ====
{{file|home.nix|nix|<nowiki>
 
{
To temporarily use Emacs in a shell environment without modifying your system configuration, you can run:
  programs.emacs = {
{{Commands|
    enable = true;
<nowiki>
    package = pkgs.emacs; # replace with pkgs.emacs-gtk, or a version provided by the community overlay if desired.
$ nix-shell -p emacs
    extraConfig = ''
</nowiki>
      (setq standard-indent 2)
}}
    '';
This makes the Emacs editor available in your current shell. You can then launch Emacs by typing <code>emacs</code>.
  };
 
}
==== System setup ====
</nowiki>}}
 
See the [https://rycee.gitlab.io/home-manager/options.html#opt-programs.emacs.enable Home-Manager manual] for a full list of options.
To install Emacs system-wide, making it available to all users, add the following to your configuration:
<syntaxhighlight lang="nix">
# Example for /etc/nixos/configuration.nix
environment.systemPackages = [
  pkgs.emacs
];
 
# User-specific installation (in ~/.config/nixpkgs/home.nix)
home.packages = [
  pkgs.emacs
];
</syntaxhighlight>
After rebuilding your system with <code>nixos-rebuild switch</code> or <code>home-manager switch</code>, Emacs will be installed and accessible.
 
== Configuration ==
{{Note|Currently, configuring Emacs is possible by using Home Manager. A workaround for a global configuration is highlighted in the advanced section.}}
 
==== Basic ====
<syntaxhighlight lang="nix">
programs.emacs = {
  enable = true;
  defaultEditor = true;
};
</syntaxhighlight>
 
==== Advanced ====
<syntaxhighlight lang="nix">
# Global Configuration
# Emacs is running as a daemon here, accesible via the "emacsclient" command
services.emacs = {
  enable = true;
  package = pkgs.emacs;
};


=== Without Home-Manager ===
# Home Configuration
Emacs can be installed in the same way as other packages:
programs.emacs = {
{{file|configuration.nix|nix|<nowiki>
   enable = true;
{
  package = pkgs.emacs# replace with pkgs.emacs-gtk if desired
   environment.systemPackages = with pkgs; [
   defaultEditor = true;
    emacs # replace with emacs-gtk, or a version provided by the community overlay if desired.
  extraConfig = ''
   ];
    (setq standard-indent 2)
}
  '';
</nowiki>}}
};
</syntaxhighlight>


=== Enabling the Emacs daemon ===
== Tips and Tricks ==
Many Emacs users run [https://www.emacswiki.org/emacs/EmacsAsDaemon Emacs as a daemon] and access Emacs via the <code>emacsclient</code> command. NixOS provides a <code>systemd</code> service to facilitate this, which you can enable by adding the following to your <code>configuration.nix</code>:
{{file|configuration.nix|nix|<nowiki>
{
  services.emacs = {
    enable = true;
    package = pkgs.emacs; # replace with emacs-gtk, or a version provided by the community overlay if desired.
  };
}
</nowiki>}}


=== Available Emacs variants ===
==== Installing Packages ====
{{warning| Certain issues are possible, when mixing different versions of Emacs, in particular a configuration file tailored towards emacs with native compilation, may misbehave on non-native compiling versions, unless only the emacs lisp code is shared between them.}}
{{Note|Emacs, much like NixOS can rebuild and re-fetch all of its packages based on its initialization file alone, if one chooses to use an extension called "use-package". Such a configuration file can be version controlled and used in all compatible operating systems.}}
One can mix and match whether Emacs packages are installed by Nix or Emacs. This can be particularly useful for Emacs packages that need to be built, such as vterm. One way to install Emacs packages through Nix is by the following, replacing {{ic|emacs-pgtk}} with the variant in use:<syntaxhighlight lang="nix">
environment.systemPackages = with pkgs;
[ ...
  ((emacsPackagesFor emacs-pgtk).emacsWithPackages (
    epkgs: [ epkgs.vterm ]
  ))
  ...
];


==== Stable (nixpkgs) ====
# To make the packages available to emacsclient, one can do the following:
Emacs is available in nixpkgs under the names <code>emacs</code> and <code>emacs-gtk</code>.
services.emacs.package = with pkgs; (
[https://github.com/NixOS/nixpkgs/pull/189543 Since 2022-09], the package called <code>emacs</code> now installs the lucid toolkit instead of gtk. The reason is that emacs is less stable with gtk especially in daemon mode. However, the lucid flavor of emacs will not take into account the gtk theme (since it is not even gtk) and looks quite… ugly (see comparisons [https://emacs.stackexchange.com/questions/33065/on-linux-why-should-one-choose-lucid-over-gtk-gui-for-emacs here]). If you still prefer the gtk version of emacs, you can instead install <code>emacs-gtk</code> (before 2022-09 this package does not exist and emacs defaults to the gtk version).
  (emacsPackagesFor emacs-pgtk).emacsWithPackages (
    epkgs: [ epkgs.vterm ]
  )
);


==== Unstable (community overlay) ====
# Some packages have characters like + that Nix considers a syntax error.  
The [https://github.com/nix-community/emacs-overlay community overlay] provides nightly versions of the Emacs unstable branches, ELPA / MELPA packages, and [https://github.com/ch11ng/exwm EXWM] + its dependencies. '''To use these, first apply the overlay (instructions below), which will make the packages available in nixpkgs.''' Then you can follow the normal nixpkgs installation instructions (above), but use your package of choice from the overlay (e.g. <code>pkgs.emacsGit</code>) in place of <code>pkgs.emacs</code>. See the [https://github.com/nix-community/emacs-overlay#emacs-overlay README] for a complete list of packages provided, and their differences.
# To fix this, write the package name in quotes and specify the package set, even if using with epkgs;.  
# For example, use epkgs."ido-completing-read+".


===== With flakes =====
Using a system flake, one can specify the specific revision of the overlay as a flake input, for example:


inputs.emacs-overlay.url = "github:nix-community/emacs-overlay/da2f552d133497abd434006e0cae996c0a282394";


This can then be used in the system configuration by using the {{ic|self}} argument:
nixpkgs.overlays = [ (import self.inputs.emacs-overlay) ];


=====  Without flakes =====
For installing one of the unstable branches of emacs, add the following lines to {{ic|/etc/nixos/configuration.nix}}:
{{file|configuration.nix|nix|<nowiki>
{
  nixpkgs.overlays = [
    (import (builtins.fetchGit {
      url = "https://github.com/nix-community/emacs-overlay.git";
      ref = "master";
      rev = "bfc8f6edcb7bcf3cf24e4a7199b3f6fed96aaecf"; # change the revision
    }))
  ];
}
</nowiki>}}


=== Darwin (macOS) ===
Nixpkgs provides several of the "Mac Port" versions of Emacs, which have been patched to provide better integration with macOS (see the [https://nixos.org/manual/nixos/stable/index.html#module-services-emacs-releases NixOS manual entry for a full list of packages]). However, those packages typically track the stable releases of Emacs.


If you would like to use the latest version of Emacs on Darwin, one option is to use a package like <code>emacsPgkt</code> from the community overlay (see above), and apply patches yourself via an override. For example, here is a derivation that applies the patches from the [https://github.com/d12frosted/homebrew-emacs-plus <code>emacs-plus</code> homebrew formula]:
</syntaxhighlight>Note that if the expression <code>(emacsPackagesFor emacs-pgtk)</code> is present, <code>emacs-pgtk</code> need not be listed separately in the list <code>environment.systemPackages</code>. Indeed, if one does that, <code>nixos-rebuild</code> will warn about link collisions when the configuration is rebuilt.


<syntaxhighlight lang="nix">
==== Tree-sitter ====
pkgs.emacsPgtk.overrideAttrs (old: {
[[Emacs]] 29 [[emacswiki:Tree-sitter|supports Tree-sitter parsers]] when built with the <code>--with-tree-sitter</code> option. The <code>emacsPackages.treesit-grammars</code> fake package makes them accessible to Emacs when using <code>emacs29.pkgs.withPackages</code>:<ref>https://github.com/NixOS/nixpkgs/pull/230751</ref><syntaxhighlight lang="nix">
      patches =
{
        (old.patches or [])
  pkgs ? import <nixpkgs> { },
        ++ [
}:
          # Fix OS window role (needed for window managers like yabai)
pkgs.emacs29.pkgs.withPackages (epkgs: [
          (fetchpatch {
  (epkgs.treesit-grammars.with-grammars (grammars: [ grammars.tree-sitter-bash ]))
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/fix-window-role.patch";
])
            sha256 = "0c41rgpi19vr9ai740g09lka3nkjk48ppqyqdnncjrkfgvm2710z";
          })
          # Use poll instead of select to get file descriptors
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-29/poll.patch";
            sha256 = "0j26n6yma4n5wh4klikza6bjnzrmz6zihgcsdx36pn3vbfnaqbh5";
          })
          # Enable rounded window with no decoration
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-29/round-undecorated-frame.patch";
            sha256 = "111i0r3ahs0f52z15aaa3chlq7ardqnzpwp8r57kfsmnmg6c2nhf";
          })
          # Make Emacs aware of OS-level light/dark mode
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/system-appearance.patch";
            sha256 = "14ndp2fqqc95s70fwhpxq58y8qqj4gzvvffp77snm2xk76c1bvnn";
          })
        ];
    });
  };
}
</syntaxhighlight>
</syntaxhighlight>


==== Window manager integration ====
When using Emacs with tree-sitter support, it's recommended to install both <code>epkgs.tree-sitter-langs</code> and <code>epkgs.treesit-grammars</code>. While <code>treesit-grammars</code> handles the registration of grammars with Emacs's native tree-sitter interface, the actual grammar files will come from <code>tree-sitter-langs</code>. <code>tree-sitter-langs</code> being a MELPA package means it receives regular updates when new grammar versions are released, whereas the grammars in the tree-sitter-grammars package may lag behind in nixpkgs. The combination ensures you get both up-to-date grammars and proper integration with Emacs's built-in tree-sitter support.
Out of the box, non-"Mac Port" versions of Emacs will not be picked up properly by window managers like [https://github.com/koekeishiya/yabai Yabai] because [https://github.com/koekeishiya/yabai/issues/86#issuecomment-507537023 Emacs does not set the correct macOS window role]. This can be fixed with a patch (e.g. the first patch in the example above). However, even with the patch, Yabai may not correctly pick up Emacs if you invoke the <code>emacs</code> binary directly from a shell. For Emacs to work properly with window managers you must invoke it by running the macOS app that is generated when you install Emacs with nix. You can setup an alias to do this like so (replace <code>pkgs.emacs</code> with the package you are using):


{{file|home.nix|nix|<nowiki>
<b>Bonus Tip:</b>
programs.zsh = {
enable = true;
shellAliases = {
  emacs = "${pkgs.emacs}/Applications/Emacs.app/Contents/MacOS/Emacs";
};
};
</nowiki>}}


== Installing packages ==
<code>emacs.pkgs.pretty-sha-path</code> is quality of life improvement for Nix, Guix users.
{{tip|Emacs, much like NixOS can rebuild and re-fetch all of its packages based on its initialization file alone, if one chooses to use an extension called {{ic|(use-package)}}. Such a configuration file can be version controlled and used in all compatible operating systems.}}
One can mix and match whether Emacs packages are installed by Nix or Emacs. This can be particularly useful for Emacs packages that need to be built, such as vterm. One way to install Emacs packages through Nix is by the following, replacing {{ic|emacsPgtkNativeComp}} with the variant in use:


environment.systemPackages = with pkgs;
Allows toggling Guix/Nix store paths by replacing SHA-sequences with ellipsis, i.e.:
  [ ...
    ((emacsPackagesFor emacsPgtkNativeComp).emacsWithPackages (
      epkgs: [ epkgs.vterm ]
    ))
    ...
  ];


To make the packages available to {{ic|emacsclient}}, one can do the following:
<syntaxhighlight lang="bash">/gnu/store/72f54nfp6g1hz873w8z3gfcah0h4nl9p-foo-0.1  → /gnu/store/…-foo-0.1
  services.emacs.package = with pkgs; (
/nix/store/nh4n4yzb1bx7nss2rg342dz44g14m06x-bar-0.2  → /nix/store/…-bar-0.2</syntaxhighlight>
  (emacsPackagesFor emacsPgtkNativeComp).emacsWithPackages (
    epkgs: [ epkgs.vterm ]
  )
  );


Note that some packages may have strange characters like <code>+</code> that would be considered as a syntax error by nix. To avoid that, make sure to write it in quotes and to prepend it with the package set that you want l (even if you used <code>with epkgs; …</code>) like <code>epkgs."ido-completing-read+"</code>.
located at https://github.com/alezost/pretty-sha-path.el


=== Automatic package management ===
==== Automatic Package Management ====
If you use <code>use-package</code> or <code>leaf</code> in your configuration, the community overlay can manage your Emacs packages automatically by using <code>emacsWithPackagesFromUsePackage</code>. First, install the overlay (instructions above), then add the following to your <code>configuration.nix</code>:
If you use <code>use-package</code> or <code>leaf</code> in your configuration, the community overlay can manage your Emacs packages automatically by using <code>emacsWithPackagesFromUsePackage</code>. First, install the overlay (instructions above), then add the following to your <code>configuration.nix</code>:
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
Line 166: Line 140:
       # Optionally provide extra packages not in the configuration file.
       # Optionally provide extra packages not in the configuration file.
       extraEmacsPackages = epkgs: [
       extraEmacsPackages = epkgs: [
         epkgs.use-package;
         epkgs.use-package
       ];
       ];


Line 182: Line 156:
See the [https://github.com/nix-community/emacs-overlay#extra-library-functionality overlay README] for a full list of options.
See the [https://github.com/nix-community/emacs-overlay#extra-library-functionality overlay README] for a full list of options.


=== Adding packages from outside ELPA / MELPA ===
==== Adding packages from outside ELPA/MELPA ====
Some packages may require more sophisticated derivation, but the following is a good starting point for adding external packages:
Some packages may require more sophisticated derivation, but the following is a good starting point for adding external packages:


{{file|lambda-line.nix|nix|<nowiki>
{{file|lambda-line.nix|nix|<nowiki>
{
{
   trivialBuild,
   melpaBuild,
   fetchFromGitHub,
   fetchFromGitHub,
   all-the-icons,
   all-the-icons,
}:
}:
trivialBuild rec {
melpaBuild {
   pname = "lambda-line";
   pname = "lambda-line";
   version = "main-23-11-2022";
   version = "0-unstable-2022-11-23";
   src = fetchFromGitHub {
   src = fetchFromGitHub {
     owner = "Lambda-Emacs";
     owner = "Lambda-Emacs";
Line 201: Line 175:
   };
   };
   # elisp dependencies
   # elisp dependencies
   propagatedUserEnvPkgs = [
   packageRequires = [
     all-the-icons
     all-the-icons
   ];
   ];
  buildInputs = propagatedUserEnvPkgs;
}
}
</nowiki>}}
</nowiki>}}
Line 218: Line 191:
         lambda-line = callPackage ./lambda-line.nix {
         lambda-line = callPackage ./lambda-line.nix {
           inherit (pkgs) fetchFromGitHub;
           inherit (pkgs) fetchFromGitHub;
           inherit (epkgs) trivialBuild all-the-icons;
           inherit (epkgs) melpaBuild all-the-icons;
         };
         };
       };
       };
Line 232: Line 205:
   environment.systemPackages = with pkgs;
   environment.systemPackages = with pkgs;
     [ ...
     [ ...
       ((emacsPackagesFor emacsPgtkNativeComp).emacsWithPackages (epkgs: [  
       ((emacsPackagesFor emacs-pgtk).emacsWithPackages (epkgs: [  
           epkgs.vterm  
           epkgs.vterm  
           (callPackage ./lambda-line.nix {
           (callPackage ./lambda-line.nix {
             inherit (pkgs) fetchFromGitHub;
             inherit (pkgs) fetchFromGitHub;
             inherit (epkgs) trivialBuild all-the-icons;
             inherit (epkgs) melpaBuild all-the-icons;
           };)  
           };)  
       ]))
       ]))
Line 243: Line 216:
}</nowiki>}}
}</nowiki>}}


=== Packaging and testing emacs nixpkgs ===
==== Packaging and testing Emacs nixpkgs ====
Emacs packages can be defined and tested like other nixpkgs.
Emacs packages can be defined and tested like other nixpkgs.
They can be obtained from melpa, elpa or other sources such as github.
They can be obtained from melpa, elpa or other sources such as github.


{{file|default.nix|nix|<nowiki>
{{file|default.nix|nix|<nowiki>
{ trivialBuild
{ melpaBuild
, lib
, lib
, fetchFromGitHub
, fetchFromGitHub
Line 254: Line 227:
}:
}:


trivialBuild {
melpaBuild {
   pname = "...";
   pname = "...";
   version = "...";
   version = "...";
Line 262: Line 235:
     repo = "...";
     repo = "...";
     rev = "...";
     rev = "...";
     sha256 = "...";
     hash = "...";
   };
   };


Line 271: Line 244:
   meta = {
   meta = {
     description = "...";
     description = "...";
     license = lib.licenses.gpl3;
     license = lib.licenses.gpl3Plus;
    platforms = lib.platforms.all;
   };
   };
}
}
</nowiki>}}
</nowiki>}}


They are located at pkgs/applications/editors/emacs/elisp-packages/manual-packages/ and a new pkg must be added under pkgs/applications/editors/elisp-packages/manual-packages.nix.
They are located at <code>pkgs/applications/editors/emacs/elisp-packages/manual-packages/</code> [https://github.com/NixOS/nixpkgs/tree/master/pkgs/applications/editors/emacs/elisp-packages/manual-packages] and a new pkg must be added under <code>pkgs/applications/editors/elisp-packages/manual-packages.nix</code> [https://github.com/NixOS/nixpkgs/blob/master/pkgs/applications/editors/emacs/elisp-packages/manual-packages.nix]. Once the nixpkg is ready, it can be tested using the following command. This inserts the nixpkg into the load-path of Emacs.
Once the nixpkg is ready, it can be tested using the following command. This inserts the nixpkg into the load-path of emacs.
{{Commands|
<nowiki>
$ nix-shell -I nixpkgs=<path_to_nixpkgs_copy> -p "(emacsPackagesFor pkgs.emacs28).emacsWithPackages (epkgs: [ epkgs.<package> ])"
</nowiki>
}}
 
==== Window Manager Integration ====
Out of the box, non-"Mac Port" versions of Emacs will not be picked up properly by window managers like [https://github.com/koekeishiya/yabai Yabai] because [https://github.com/koekeishiya/yabai/issues/86#issuecomment-507537023 Emacs does not set the correct macOS window role]. This can be fixed with a patch (e.g. the first patch in the example above). However, even with the patch, Yabai may not correctly pick up Emacs if you invoke the <code>emacs</code> binary directly from a shell. For Emacs to work properly with window managers you must invoke it by running the macOS app that is generated when you install Emacs with nix. You can setup an alias to do this like so (replace <code>pkgs.emacs</code> with the package you are using):<syntaxhighlight lang="nix">
programs.zsh = {
  enable = true;
  shellAliases = {
    emacs = "${pkgs.emacs}/Applications/Emacs.app/Contents/MacOS/Emacs";
  };
};
</syntaxhighlight>


==== Available Emacs Variants ====
{{warning| Certain issues are possible, when mixing different versions of Emacs, in particular a configuration file tailored towards emacs with native compilation, may misbehave on non-native compiling versions, unless only the emacs lisp code is shared between them.}}
===== Stable (nixpkgs) =====
Emacs is available in nixpkgs under the names <code>emacs</code> and <code>emacs-gtk</code>.
[https://github.com/NixOS/nixpkgs/pull/189543 Since 2022-09], the package called <code>emacs</code> now installs the lucid toolkit instead of gtk. The reason is that Emacs is less stable with gtk especially in daemon mode. However, the lucid flavor of Emacs will not take into account the GTK theme (since it is not even GTK) and looks quite… ugly (see comparisons [https://emacs.stackexchange.com/questions/33065/on-linux-why-should-one-choose-lucid-over-gtk-gui-for-emacs here]). If you still prefer the GTK version of Emacs, you can instead install <code>emacs-gtk</code> (before 2022-09 this package does not exist and Emacs defaults to the gtk version).
===== Unstable (community overlay) =====
The [https://github.com/nix-community/emacs-overlay community overlay] provides nightly versions of the Emacs unstable branches, ELPA/MELPA packages, and [https://github.com/ch11ng/exwm EXWM] + its dependencies. '''To use these, first apply the overlay (instructions below), which will make the packages available in nixpkgs.''' Then you can follow the normal nixpkgs installation instructions (above), but use your package of choice from the overlay (e.g. <code>pkgs.emacsGit</code>) in place of <code>pkgs.emacs</code>. See the [https://github.com/nix-community/emacs-overlay#emacs-overlay README] for a complete list of packages provided, and their differences.
====== With flakes ======
Using a system flake, one can specify the specific revision of the overlay as a flake input, for example:<syntaxhighlight lang="nix">
inputs.emacs-overlay.url = "github:nix-community/emacs-overlay/da2f552d133497abd434006e0cae996c0a282394";
</syntaxhighlight>This can then be used in the system configuration by using the {{ic|self}} argument:<syntaxhighlight lang="nix">
nixpkgs.overlays = [ (import self.inputs.emacs-overlay) ];
</syntaxhighlight>
======  Without flakes ======
For installing one of the unstable branches of Emacs, add the following lines to your configuration file:
{{file|configuration.nix|nix|<nowiki>
{
  nixpkgs.overlays = [
    (import (builtins.fetchGit {
      url = "https://github.com/nix-community/emacs-overlay.git";
      ref = "master";
      rev = "bfc8f6edcb7bcf3cf24e4a7199b3f6fed96aaecf"; # change the revision
    }))
  ];
}
</nowiki>}}
===== Darwin (macOS) =====
Nixpkgs provides several of the "Mac Port" versions of Emacs, which have been patched to provide better integration with macOS (see the [https://nixos.org/manual/nixos/stable/index.html#module-services-emacs-releases NixOS manual entry for a full list of packages]). However, those packages typically track the stable releases of Emacs.
If you would like to use the latest version of Emacs on Darwin, one option is to use a package like <code>emacsPgkt</code> from the community overlay (see above), and apply patches yourself via an override. For example, here is a derivation that applies the patches from the [https://github.com/d12frosted/homebrew-emacs-plus <code>emacs-plus</code> homebrew formula]:
<syntaxhighlight lang="nix">
pkgs.emacsPgtk.overrideAttrs (old: {
      patches =
        (old.patches or [])
        ++ [
          # Fix OS window role (needed for window managers like yabai)
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/fix-window-role.patch";
            sha256 = "0c41rgpi19vr9ai740g09lka3nkjk48ppqyqdnncjrkfgvm2710z";
          })
          # Enable rounded window with no decoration
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-29/round-undecorated-frame.patch";
            sha256 = "111i0r3ahs0f52z15aaa3chlq7ardqnzpwp8r57kfsmnmg6c2nhf";
          })
          # Make Emacs aware of OS-level light/dark mode
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/system-appearance.patch";
            sha256 = "14ndp2fqqc95s70fwhpxq58y8qqj4gzvvffp77snm2xk76c1bvnn";
          })
        ];
    });
  };
}
</syntaxhighlight>


  nix-shell -I nixpkgs=<path_to_nixpkgs_copy> -p "(emacsPackagesFor pkgs.emacs28).emacsWithPackages (epkgs: [ epkgs.<package> ])"
== Troubleshooting ==


== Bugs ==
==== Plasma taskbar grouping ====
To fix/workaround [[KDE|Plasma]] grouping Emacs incorrectly (confusing emacs.desktop with emacsclient.desktop), perform the following:


=== Plasma taskbar grouping ===
* Open Emacs
To fix/workaround [[Plasma]] grouping emacs incorrectly (confusing emacs.desktop with emacsclient.desktop), perform the following:
* Right click title bar
1. open emacs
* More Actions > Configure Special Window Settings
2. right click title bar
* Add Property > Desktop File Name
3. More Actions > Configure Special Window Settings
* Set desktop file name to "/home/<USERNAME>/.nix-profile/share/applications/emacs.desktop"
4. click Add Property > Desktop File Name
* Apply the changes
5. set desktop file name to "/home/<USERNAME>/.nix-profile/share/applications/emacs.desktop"
* Restart Emacs if need
6. hit OK
7. restart emacs if need


all emacs instances should now be grouped together, allowing you to pin it and reliably switch to it with Super+<number>
All Emacs instances should now be grouped together, allowing you to pin it and reliably switch to it with Super+<number>


=== Spell checking ===
==== Spell checking ====
Because emacs expects the dictionaries to be on the same directory as aspell, they won't be picked up. To fix it install the <code>aspellWithDicts</code> package, specifying the dictionaries you want to use:  
Because Emacs expects the dictionaries to be on the same directory as aspell, they won't be picked up. To fix it install the <code>aspellWithDicts</code> package, specifying the dictionaries you want to use:  


{{file|configuration.nix|nix|<nowiki>
{{file|configuration.nix|nix|<nowiki>
Line 310: Line 357:
A list of official dictionaries for aspell can be found on [https://ftp.gnu.org/gnu/aspell/dict/0index.html  Aspell Website]
A list of official dictionaries for aspell can be found on [https://ftp.gnu.org/gnu/aspell/dict/0index.html  Aspell Website]


== See also ==


* [[Home Manager]] – For declarative Emacs configuration at the user level: [https://nix-community.github.io/home-manager/options.html#opt-programs.emacs.enable Emacs module in Home Manager]
* [https://www.gnu.org/software/emacs/manual/ Emacs Manuals] – Official Emacs documentation.
* [https://search.nixos.org/options?channel=unstable&query=services.emacs NixOS options for Emacs services] – System-level Emacs configuration.
* [https://discourse.nixos.org/search?q=emacs Emacs discussions on NixOS Discourse] – Community tips, troubleshooting, and use cases.
* [https://doomemacs.org Doom Emacs] – A popular Emacs configuration framework.
* [https://github.com/nix-community/emacs-overlay Emacs Overlay on Nixpkgs] – For nightly builds and additional Emacs packages.


[[Category:NixOS]]
== References ==
[[Category:Incomplete]]
[[Category:Applications]]
[[Category:Applications]]
[[Category:CLI Applications]]
[[Category:NixOS Manual]]
[[Category:Text Editor]]

Latest revision as of 23:54, 10 July 2025

GNU Emacs

Text Editor Application

100%
Operating SystemCross-platform
LicenseGNU General Public License
External links
Websitegnu.org/emacs
GitHub[1]

Emacs is a free and open-source text editor known for its exceptional extensibility and adaptability. It can be customized into anything from a simple editor to a full development environment or productivity tool. Emacs features built-in self-documentation, syntax-aware editing, and a vast ecosystem of community-developed packages.[1]

For an easier introduction, Doom Emacs offers a pre-configured Emacs framework with modern defaults and features like IDE tools, note-taking, and task management.

There is an official Matrix room for Nix/Emacs: #emacs:nixos.org.

Installation

Shell

To temporarily use Emacs in a shell environment without modifying your system configuration, you can run:

$ nix-shell -p emacs

This makes the Emacs editor available in your current shell. You can then launch Emacs by typing emacs.

System setup

To install Emacs system-wide, making it available to all users, add the following to your configuration:

# Example for /etc/nixos/configuration.nix
environment.systemPackages = [
  pkgs.emacs
];

# User-specific installation (in ~/.config/nixpkgs/home.nix)
home.packages = [
  pkgs.emacs
];

After rebuilding your system with nixos-rebuild switch or home-manager switch, Emacs will be installed and accessible.

Configuration

Note: Currently, configuring Emacs is possible by using Home Manager. A workaround for a global configuration is highlighted in the advanced section.

Basic

programs.emacs = {
   enable = true;
   defaultEditor = true;
};

Advanced

# Global Configuration
# Emacs is running as a daemon here, accesible via the "emacsclient" command
services.emacs = {
  enable = true;
  package = pkgs.emacs; 
};

# Home Configuration
programs.emacs = {
  enable = true;
  package = pkgs.emacs;  # replace with pkgs.emacs-gtk if desired
  defaultEditor = true;
  extraConfig = ''
    (setq standard-indent 2)
  '';
};

Tips and Tricks

Installing Packages

Note: Emacs, much like NixOS can rebuild and re-fetch all of its packages based on its initialization file alone, if one chooses to use an extension called "use-package". Such a configuration file can be version controlled and used in all compatible operating systems.

One can mix and match whether Emacs packages are installed by Nix or Emacs. This can be particularly useful for Emacs packages that need to be built, such as vterm. One way to install Emacs packages through Nix is by the following, replacing emacs-pgtk with the variant in use:

environment.systemPackages = with pkgs;
[ ...
  ((emacsPackagesFor emacs-pgtk).emacsWithPackages (
    epkgs: [ epkgs.vterm ]
  ))
  ...
];

# To make the packages available to emacsclient, one can do the following:
services.emacs.package = with pkgs; (
  (emacsPackagesFor emacs-pgtk).emacsWithPackages (
    epkgs: [ epkgs.vterm ]
  )
);

# Some packages have characters like + that Nix considers a syntax error. 
# To fix this, write the package name in quotes and specify the package set, even if using with epkgs;. 
# For example, use epkgs."ido-completing-read+".

Note that if the expression (emacsPackagesFor emacs-pgtk) is present, emacs-pgtk need not be listed separately in the list environment.systemPackages. Indeed, if one does that, nixos-rebuild will warn about link collisions when the configuration is rebuilt.

Tree-sitter

Emacs 29 supports Tree-sitter parsers when built with the --with-tree-sitter option. The emacsPackages.treesit-grammars fake package makes them accessible to Emacs when using emacs29.pkgs.withPackages:[2]

{
  pkgs ? import <nixpkgs> { },
}:
pkgs.emacs29.pkgs.withPackages (epkgs: [
  (epkgs.treesit-grammars.with-grammars (grammars: [ grammars.tree-sitter-bash ]))
])

When using Emacs with tree-sitter support, it's recommended to install both epkgs.tree-sitter-langs and epkgs.treesit-grammars. While treesit-grammars handles the registration of grammars with Emacs's native tree-sitter interface, the actual grammar files will come from tree-sitter-langs. tree-sitter-langs being a MELPA package means it receives regular updates when new grammar versions are released, whereas the grammars in the tree-sitter-grammars package may lag behind in nixpkgs. The combination ensures you get both up-to-date grammars and proper integration with Emacs's built-in tree-sitter support.

Bonus Tip:

emacs.pkgs.pretty-sha-path is quality of life improvement for Nix, Guix users.

Allows toggling Guix/Nix store paths by replacing SHA-sequences with ellipsis, i.e.:

/gnu/store/72f54nfp6g1hz873w8z3gfcah0h4nl9p-foo-0.1    /gnu/store/…-foo-0.1
/nix/store/nh4n4yzb1bx7nss2rg342dz44g14m06x-bar-0.2    /nix/store/…-bar-0.2

located at https://github.com/alezost/pretty-sha-path.el

Automatic Package Management

If you use use-package or leaf in your configuration, the community overlay can manage your Emacs packages automatically by using emacsWithPackagesFromUsePackage. First, install the overlay (instructions above), then add the following to your configuration.nix:

{
  environment.systemPackages = [
    (pkgs.emacsWithPackagesFromUsePackage {
      package = pkgs.emacsGit;  # replace with pkgs.emacsPgtk, or another version if desired.
      config = path/to/your/config.el;
      # config = path/to/your/config.org; # Org-Babel configs also supported

      # Optionally provide extra packages not in the configuration file.
      extraEmacsPackages = epkgs: [
        epkgs.use-package
      ];

      # Optionally override derivations.
      override = epkgs: epkgs // {
        somePackage = epkgs.melpaPackages.somePackage.overrideAttrs(old: {
           # Apply fixes here
        });
      };
    })
  ];
}

See the overlay README for a full list of options.

Adding packages from outside ELPA/MELPA

Some packages may require more sophisticated derivation, but the following is a good starting point for adding external packages:

❄︎ lambda-line.nix
{
  melpaBuild,
  fetchFromGitHub,
  all-the-icons,
}:
melpaBuild {
  pname = "lambda-line";
  version = "0-unstable-2022-11-23";
  src = fetchFromGitHub {
    owner = "Lambda-Emacs";
    repo = "lambda-line";
    rev = "22186321a7442f1bd3b121f739007bd809cb38f8";
    hash = "sha256-2tOXMqpmd14ohzmrRoV5Urf0HlnRPV1EVHm/d8OBSGE=";
  };
  # elisp dependencies
  packageRequires = [
    all-the-icons
  ];
}

You can then use the new package with automatic package management like so:

❄︎ configuration.nix
{
  environment.systemPackages = [
    (pkgs.emacsWithPackagesFromUsePackage {
      ...
      override = epkgs: epkgs // {
        lambda-line = callPackage ./lambda-line.nix {
          inherit (pkgs) fetchFromGitHub;
          inherit (epkgs) melpaBuild all-the-icons;
        };
      };
    })
  ];
}

or manual package management like so:

❄︎ configuration.nix
{
  environment.systemPackages = with pkgs;
    [ ...
      ((emacsPackagesFor emacs-pgtk).emacsWithPackages (epkgs: [ 
          epkgs.vterm 
          (callPackage ./lambda-line.nix {
            inherit (pkgs) fetchFromGitHub;
            inherit (epkgs) melpaBuild all-the-icons;
          };) 
       ]))
      ...
    ];
}

Packaging and testing Emacs nixpkgs

Emacs packages can be defined and tested like other nixpkgs. They can be obtained from melpa, elpa or other sources such as github.

❄︎ default.nix
{ melpaBuild
, lib
, fetchFromGitHub
...
}:

melpaBuild {
  pname = "...";
  version = "...";

  src = fetchFromGitHub {
    owner = "...";
    repo = "...";
    rev = "...";
    hash = "...";
  };

  packageRequires = [ ... ];

  patches = [ ... ];

  meta = {
    description = "...";
    license = lib.licenses.gpl3Plus;
  };
}

They are located at pkgs/applications/editors/emacs/elisp-packages/manual-packages/ [2] and a new pkg must be added under pkgs/applications/editors/elisp-packages/manual-packages.nix [3]. Once the nixpkg is ready, it can be tested using the following command. This inserts the nixpkg into the load-path of Emacs.

$ nix-shell -I nixpkgs=&lt;path_to_nixpkgs_copy&gt; -p "(emacsPackagesFor pkgs.emacs28).emacsWithPackages (epkgs: [ epkgs.&lt;package&gt; ])"

Window Manager Integration

Out of the box, non-"Mac Port" versions of Emacs will not be picked up properly by window managers like Yabai because Emacs does not set the correct macOS window role. This can be fixed with a patch (e.g. the first patch in the example above). However, even with the patch, Yabai may not correctly pick up Emacs if you invoke the emacs binary directly from a shell. For Emacs to work properly with window managers you must invoke it by running the macOS app that is generated when you install Emacs with nix. You can setup an alias to do this like so (replace pkgs.emacs with the package you are using):

programs.zsh = {
  enable = true;
  shellAliases = {
    emacs = "${pkgs.emacs}/Applications/Emacs.app/Contents/MacOS/Emacs";
  };
};

Available Emacs Variants

⚠︎
Warning: Certain issues are possible, when mixing different versions of Emacs, in particular a configuration file tailored towards emacs with native compilation, may misbehave on non-native compiling versions, unless only the emacs lisp code is shared between them.
Stable (nixpkgs)

Emacs is available in nixpkgs under the names emacs and emacs-gtk.

Since 2022-09, the package called emacs now installs the lucid toolkit instead of gtk. The reason is that Emacs is less stable with gtk especially in daemon mode. However, the lucid flavor of Emacs will not take into account the GTK theme (since it is not even GTK) and looks quite… ugly (see comparisons here). If you still prefer the GTK version of Emacs, you can instead install emacs-gtk (before 2022-09 this package does not exist and Emacs defaults to the gtk version).

Unstable (community overlay)

The community overlay provides nightly versions of the Emacs unstable branches, ELPA/MELPA packages, and EXWM + its dependencies. To use these, first apply the overlay (instructions below), which will make the packages available in nixpkgs. Then you can follow the normal nixpkgs installation instructions (above), but use your package of choice from the overlay (e.g. pkgs.emacsGit) in place of pkgs.emacs. See the README for a complete list of packages provided, and their differences.

With flakes

Using a system flake, one can specify the specific revision of the overlay as a flake input, for example:

inputs.emacs-overlay.url = "github:nix-community/emacs-overlay/da2f552d133497abd434006e0cae996c0a282394";

This can then be used in the system configuration by using the self argument:

nixpkgs.overlays = [ (import self.inputs.emacs-overlay) ];
Without flakes

For installing one of the unstable branches of Emacs, add the following lines to your configuration file:

❄︎ configuration.nix
{
  nixpkgs.overlays = [
    (import (builtins.fetchGit {
      url = "https://github.com/nix-community/emacs-overlay.git";
      ref = "master";
      rev = "bfc8f6edcb7bcf3cf24e4a7199b3f6fed96aaecf"; # change the revision
    }))
  ];
}
Darwin (macOS)

Nixpkgs provides several of the "Mac Port" versions of Emacs, which have been patched to provide better integration with macOS (see the NixOS manual entry for a full list of packages). However, those packages typically track the stable releases of Emacs.

If you would like to use the latest version of Emacs on Darwin, one option is to use a package like emacsPgkt from the community overlay (see above), and apply patches yourself via an override. For example, here is a derivation that applies the patches from the emacs-plus homebrew formula:

pkgs.emacsPgtk.overrideAttrs (old: {
      patches =
        (old.patches or [])
        ++ [
          # Fix OS window role (needed for window managers like yabai)
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/fix-window-role.patch";
            sha256 = "0c41rgpi19vr9ai740g09lka3nkjk48ppqyqdnncjrkfgvm2710z";
          })
          # Enable rounded window with no decoration
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-29/round-undecorated-frame.patch";
            sha256 = "111i0r3ahs0f52z15aaa3chlq7ardqnzpwp8r57kfsmnmg6c2nhf";
          })
          # Make Emacs aware of OS-level light/dark mode
          (fetchpatch {
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/system-appearance.patch";
            sha256 = "14ndp2fqqc95s70fwhpxq58y8qqj4gzvvffp77snm2xk76c1bvnn";
          })
        ];
    });
  };
}

Troubleshooting

Plasma taskbar grouping

To fix/workaround Plasma grouping Emacs incorrectly (confusing emacs.desktop with emacsclient.desktop), perform the following:

  • Open Emacs
  • Right click title bar
  • More Actions > Configure Special Window Settings
  • Add Property > Desktop File Name
  • Set desktop file name to "/home/<USERNAME>/.nix-profile/share/applications/emacs.desktop"
  • Apply the changes
  • Restart Emacs if need

All Emacs instances should now be grouped together, allowing you to pin it and reliably switch to it with Super+<number>

Spell checking

Because Emacs expects the dictionaries to be on the same directory as aspell, they won't be picked up. To fix it install the aspellWithDicts package, specifying the dictionaries you want to use:

❄︎ configuration.nix
{
  environment.systemPackages = with pkgs; [
    (aspellWithDicts (dicts: with dicts; [ en en-computers en-science es]))
  ];
}

A list of official dictionaries for aspell can be found on Aspell Website

See also

References