Emacs: Difference between revisions

Layer-09 (talk | contribs)
mNo edit summary
DHCP (talk | contribs)
fix formatting and consistency
 
(11 intermediate revisions by 7 users not shown)
Line 1: Line 1:
{{Infobox
{{application infobox
   |title=GNU Emacs
   |name=GNU Emacs
  |subtitle=Text Editor Application
   |image=EmacsIcon.svg
   |image=EmacsIcon.svg
   |content={{application infobox/content
   |type=Text Editor
    |firstRelease=1985; 40 years ago
  |firstRelease=1985; 40 years ago
    |license=[https://www.gnu.org/licenses/gpl.html GNU General Public License]
  |license=[https://www.gnu.org/licenses/gpl.html GNU General Public License]
    |os=Cross-platform
  |os=Cross-platform
    |github=
  |website=[https://www.gnu.org/software/emacs gnu.org/emacs]
    |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>
<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>


Line 23: Line 20:


To temporarily use Emacs in a shell environment without modifying your system configuration, you can run:
To temporarily use Emacs in a shell environment without modifying your system configuration, you can run:
{{Commands|
<syntaxhighlight lang=console>
<nowiki>
$ nix-shell -p emacs
$ nix-shell -p emacs
</nowiki>
</syntaxhighlight>
}}
 
This makes the Emacs editor available in your current shell. You can then launch Emacs by typing <code>emacs</code>.
This makes the Emacs editor available in your current shell. You can then launch Emacs by typing <code>emacs</code>.


Line 33: Line 29:


To install Emacs system-wide, making it available to all users, add the following to your configuration:
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
{{file|/etc/nixos/configuration.nix|nix|3=
environment.systemPackages = [
environment.systemPackages = [
   pkgs.emacs
   pkgs.emacs
];
];
}}


# User-specific installation (in ~/.config/nixpkgs/home.nix)
Alternatively, Emacs can be installed specific to a user via [[Home Manager]]:
 
{{file|home.nix|nix|3=
home.packages = [
home.packages = [
   pkgs.emacs
   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.
After rebuilding your system with <code>nixos-rebuild switch</code> or <code>home-manager switch</code>, Emacs will be installed and accessible.


== Configuration ==
== Configuration ==
{{Note|Currently, configuring Emacs is possible by using Home Manager. A workaround for a global configuration is highlighted in the advanced section.}}


==== Basic ====
==== NixOS System Configuration ====
<syntaxhighlight lang="nix">
 
programs.emacs = {
System wide configuration of Emacs is limited to only the [https://www.gnu.org/software/emacs/manual/html_node/emacs/Emacs-Server.html Emacs daemon]. To enable Emacs daemon user services system-wide and set as default editor:
  enable = true;
  defaultEditor = true;
};
</syntaxhighlight>


==== Advanced ====
{{file|/etc/nixos/configuration.nix|nix|3=
<syntaxhighlight lang="nix">
# Global Configuration
# Emacs is running as a daemon here, accesible via the "emacsclient" command
services.emacs = {
services.emacs = {
   enable = true;
   enable = true;
   package = pkgs.emacs;  
   defaultEditor = true;
};
};
}}
Use <code>emacsclient</code> to connect to the daemon. For a full list of module configuration options, see {{nixos:option|services.emacs}}.
==== Home Manager ====
[[Home Manager]] provides a larger set of user-specific configuration options for Emacs.


# Home Configuration
A minimal configuration that installs Emacs alongside <code>nix-mode</code> and <code>nixfmt</code> packages:
 
{{file|home.nix|nix|3=
programs.emacs = {
programs.emacs = {
   enable = true;
   enable = true;
   package = pkgs.emacs; # replace with pkgs.emacs-gtk if desired
   package = pkgs.emacs; # replace with pkgs.emacs-gtk if desired
   defaultEditor = true;
   extraPackages = epkgs: [
    epkgs.nix-mode
    epkgs.nixfmt
  ];
   extraConfig = ''
   extraConfig = ''
     (setq standard-indent 2)
     (setq standard-indent 2)
   '';
   '';
};
};
</syntaxhighlight>
}}
 
{{note| An alternative option to setting the config inside a Nix string, you can load the config file by <code>extraConfig <nowiki>=</nowiki> builtins.readFile ./emacs_config.el</code>.}}
 
To search for Emacs plugins within the package set, see {{nixos:package|emacsPackages.*}}. A full list of Home Manager configuration module options can be found [https://home-manager-options.extranix.com/?query=programs.emacs here].
 
Home Manager also provides a configuration module for enabling the Emacs daemon:
 
{{file|home.nix|nix|3=
# Emacs is running as a daemon here, accesible via the "emacsclient" command
services.emacs = {
  enable = true;
  defaultEditor = true;
};
}}
 
See [https://home-manager-options.extranix.com/?query=services.emacs the module options] for <code>services.emacs</code> configurations options.


== Tips and Tricks ==
== Tips and Tricks ==
Line 81: Line 101:
==== Installing Packages ====
==== 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.}}
{{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|emacsPgtkNativeComp}} with the variant in use:<syntaxhighlight lang="nix">
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:
environment.systemPackages = with pkgs;
{{file|/etc/nixos/configuration.nix|nix|3=
[ ...
environment.systemPackages = with pkgs; [
   ((emacsPackagesFor emacsPgtkNativeComp).emacsWithPackages (
  ...
   ((emacsPackagesFor emacs-pgtk).emacsWithPackages (
     epkgs: [ epkgs.vterm ]
     epkgs: [ epkgs.vterm ]
   ))
   ))
Line 92: Line 113:
# To make the packages available to emacsclient, one can do the following:
# To make the packages available to emacsclient, one can do the following:
services.emacs.package = with pkgs; (
services.emacs.package = with pkgs; (
   (emacsPackagesFor emacsPgtkNativeComp).emacsWithPackages (
   (emacsPackagesFor emacs-pgtk).emacsWithPackages (
     epkgs: [ epkgs.vterm ]
     epkgs: [ epkgs.vterm ]
   )
   )
Line 100: Line 121:
# To fix this, write the package name in quotes and specify the package set, even if using with epkgs;.  
# 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+".
# For example, use epkgs."ido-completing-read+".
}}


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.


====== Alternative way of installation to ensuring consistent package management for emacs and emacsclient ======
If you plan to use the same packages for both emacs and emacsclient, you can define a custom emacs like this:
{{file|/etc/nixos/configuration.nix|nix|3=
nixpkgs.config.packageOverrides = pkgs: rec {
  myEmacs = pkgs.emacs.pkgs.withPackages (epkgs: with epkgs; [
    org
    nixmode
    ... # list all your desired emacsPackages here
  ]);
};
}}


You may then reference it twice:


{{file|/etc/nixos/configuration.nix|nix|3=
# if you want it per-user instead of system-wide use 'users.users.<name>.packages = with pkgs; [' instead
environment.systemPackages = with pkgs; [
  myEmacs
];


# enabling emacsclient and making all the packages available
services.emacs = {
  enable = true;
  package = pkgs.myEmacs;
};
}}


</syntaxhighlight>
Using this approach, there is no need to keep two lists of emacsPackages in sync.


==== Tree-sitter ====
==== Tree-sitter ====
Line 133: Line 179:
==== 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">
{{file|/etc/nixos/configuration.nix|nix|3=
{
environment.systemPackages = [
  environment.systemPackages = [
  (pkgs.emacsWithPackagesFromUsePackage {
    (pkgs.emacsWithPackagesFromUsePackage {
    package = pkgs.emacsGit;  # replace with pkgs.emacsPgtk, or another version if desired.
      package = pkgs.emacsGit;  # replace with pkgs.emacsPgtk, or another version if desired.
    config = path/to/your/config.el;
      config = path/to/your/config.el;
    # config = path/to/your/config.org; # Org-Babel configs also supported
      # config = path/to/your/config.org; # Org-Babel configs also supported


      # 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
      ];
    ];


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


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.
Line 162: Line 206:
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|3=
{
{
   melpaBuild,
   melpaBuild,
Line 182: Line 226:
   ];
   ];
}
}
</nowiki>}}
}}


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


{{file|configuration.nix|nix|<nowiki>
{{file|configuration.nix|nix|3=
{
environment.systemPackages = [
  environment.systemPackages = [
  (pkgs.emacsWithPackagesFromUsePackage {
    (pkgs.emacsWithPackagesFromUsePackage {
    ...
      ...
    override = epkgs: epkgs // {
      override = epkgs: epkgs // {
      lambda-line = callPackage ./lambda-line.nix {
        lambda-line = callPackage ./lambda-line.nix {
        inherit (pkgs) fetchFromGitHub;
          inherit (pkgs) fetchFromGitHub;
        inherit (epkgs) melpaBuild all-the-icons;
          inherit (epkgs) melpaBuild all-the-icons;
        };
       };
       };
     })
     };
  ];
  })
}
];
</nowiki>}}
}}


or manual package management like so:
or manual package management like so:


{{file|configuration.nix|nix|<nowiki>
{{file|configuration.nix|nix|3=
{
environment.systemPackages = with pkgs; [
  environment.systemPackages = with pkgs;
  ...
    [ ...
  ((emacsPackagesFor emacs-pgtk).emacsWithPackages (epkgs: [
      ((emacsPackagesFor emacsPgtkNativeComp).emacsWithPackages (epkgs: [  
    epkgs.vterm
          epkgs.vterm  
    (callPackage ./lambda-line.nix {
          (callPackage ./lambda-line.nix {
      inherit (pkgs) fetchFromGitHub;
            inherit (pkgs) fetchFromGitHub;
      inherit (epkgs) melpaBuild all-the-icons;
            inherit (epkgs) melpaBuild all-the-icons;
    })
          };)  
  ]))
      ]))
  ...
      ...
];
    ];
}}
}</nowiki>}}


==== Packaging and testing Emacs nixpkgs ====
==== Packaging and testing Emacs nixpkgs ====
Line 223: Line 264:
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|3=
{ melpaBuild
{
, lib
  melpaBuild,
, fetchFromGitHub
  lib,
...
  fetchFromGitHub
  ...
}:
}:


Line 250: Line 292:
   };
   };
}
}
</nowiki>}}
}}


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.
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.
{{Commands|
<syntaxhighlight lang=console>
<nowiki>
$ nix-shell -I nixpkgs=<path_to_nixpkgs_copy> -p \
$ nix-shell -I nixpkgs=<path_to_nixpkgs_copy> -p "(emacsPackagesFor pkgs.emacs28).emacsWithPackages (epkgs: [ epkgs.<package> ])"
    "(emacsPackagesFor pkgs.emacs28).emacsWithPackages (epkgs: [ epkgs.<package> ])"
</nowiki>
</syntaxhighlight>
}}
}}


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


===== Darwin (macOS) =====
===== Darwin (macOS) =====
Line 308: Line 348:
<syntaxhighlight lang="nix">
<syntaxhighlight lang="nix">
pkgs.emacsPgtk.overrideAttrs (old: {
pkgs.emacsPgtk.overrideAttrs (old: {
      patches =
  patches = (old.patches or [ ]) ++ [
        (old.patches or [])
    # Fix OS window role (needed for window managers like yabai)
        ++ [
    (fetchpatch {
          # Fix OS window role (needed for window managers like yabai)
      url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/fix-window-role.patch";
          (fetchpatch {
      sha256 = "0c41rgpi19vr9ai740g09lka3nkjk48ppqyqdnncjrkfgvm2710z";
            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 {
          # Enable rounded window with no decoration
      url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-29/round-undecorated-frame.patch";
          (fetchpatch {
      sha256 = "111i0r3ahs0f52z15aaa3chlq7ardqnzpwp8r57kfsmnmg6c2nhf";
            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 {
          # Make Emacs aware of OS-level light/dark mode
      url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/system-appearance.patch";
          (fetchpatch {
      sha256 = "14ndp2fqqc95s70fwhpxq58y8qqj4gzvvffp77snm2xk76c1bvnn";
            url = "https://raw.githubusercontent.com/d12frosted/homebrew-emacs-plus/master/patches/emacs-28/system-appearance.patch";
    })
            sha256 = "14ndp2fqqc95s70fwhpxq58y8qqj4gzvvffp77snm2xk76c1bvnn";
  ];
          })
})
        ];
    });
  };
}
</syntaxhighlight>
</syntaxhighlight>
==== Running xwidgets ====
Currently, the xwidgets feature is available for Emacs, but will have some issues with the PGTK build.  Indeed, when create a webkit xwidget, the widget will initially show a blank page, for some seconds (usually 4/5 seconds), no matter whether you actually try to load a web page.
A workaround to this is to way that delay, and then try to load the page.  You can do so programmatically by waiting 5 seconds, or from within a webkit widget by waiting for 5 seconds, then pressing <code>g</code>, then <code>RET</code>.
Otherwise, you can fix the issue by building Emacs with the following patch<syntaxhighlight lang="diff">--- a/src/xwidget.c
+++ b/src/xwidget.c
@@ -362,8 +362,12 @@
"download-started",
G_CALLBACK (webkit_download_cb), xw);
+#if !defined HAVE_PGTK
+              /* when using pgtk, the about:blank workaround is not needed
+                would in fact make the initial load fail.  */
      webkit_web_view_load_uri (WEBKIT_WEB_VIEW (xw->widget_osr),
"about:blank");
+#endif
      /* webkitgtk uses GSubprocess which sets sigaction causing
Emacs to not catch SIGCHLD with its usual handle setup in
'catch_child_signal'.  This resets the SIGCHLD sigaction.  */</syntaxhighlight>Say you saved this file in <code>xwidget.patch</code>, then you can override emacs with<syntaxhighlight lang="nix">pkgs.emacs-pgtk.overrideAttrs (old: {
  patches = (old.patches or []) ++ [ ./xwidget.patch ];
}</syntaxhighlight>Beware, this will trigger a full Emacs compilation whenever you update it, because it will not match any cached binary.


== Troubleshooting ==
== Troubleshooting ==
Line 350: Line 409:
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|3=
{
environment.systemPackages = with pkgs; [
  environment.systemPackages = with pkgs; [
  (aspellWithDicts (dicts: with dicts; [ en en-computers en-science es ]))
    (aspellWithDicts (dicts: with dicts; [ en en-computers en-science es]))
];
  ];
}}
}
</nowiki>}}


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]