diff --git a/nixos/modules/module-list.nix b/nixos/modules/module-list.nix
index be72c0ef29c0..49e3e2d4a948 100644
--- a/nixos/modules/module-list.nix
+++ b/nixos/modules/module-list.nix
@@ -164,6 +164,7 @@
./services/desktops/profile-sync-daemon.nix
./services/desktops/telepathy.nix
./services/development/hoogle.nix
+ ./services/editors/emacs.nix
./services/games/factorio.nix
./services/games/ghost-one.nix
./services/games/minecraft-server.nix
diff --git a/nixos/modules/services/editors/emacs.nix b/nixos/modules/services/editors/emacs.nix
new file mode 100644
index 000000000000..43b4219c51dd
--- /dev/null
+++ b/nixos/modules/services/editors/emacs.nix
@@ -0,0 +1,86 @@
+{ config, lib, pkgs, ... }:
+
+with lib;
+
+let
+
+ cfg = config.services.emacs;
+
+ editorScript = pkgs.writeScriptBin "emacseditor" ''
+ #!${pkgs.stdenv.shell}
+ if [ -z "$1" ]; then
+ exec ${cfg.package}/bin/emacsclient --create-frame --alternate-editor ${cfg.package}/bin/emacs
+ else
+ exec ${cfg.package}/bin/emacsclient --alternate-editor ${cfg.package}/bin/emacs "$@"
+ fi
+ '';
+
+in {
+
+ options.services.emacs = {
+ enable = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Whether to enable a user service for the Emacs daemon. Use emacsclient to connect to the
+ daemon. If true, services.emacs.install is
+ considered true, whatever its value.
+ '';
+ };
+
+ install = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ Whether to install a user service for the Emacs daemon. Once
+ the service is started, use emacsclient to connect to the
+ daemon.
+
+ The service must be manually started for each user with
+ "systemctl --user start emacs" or globally through
+ services.emacs.enable.
+ '';
+ };
+
+
+ package = mkOption {
+ type = types.package;
+ default = pkgs.emacs;
+ defaultText = "pkgs.emacs";
+ description = ''
+ emacs derivation to use.
+ '';
+ };
+
+ defaultEditor = mkOption {
+ type = types.bool;
+ default = false;
+ example = true;
+ description = ''
+ When enabled, configures emacsclient to be the default editor
+ using the EDITOR environment variable.
+ '';
+ };
+ };
+
+ config = mkIf (cfg.enable || cfg.install) {
+ systemd.user.services.emacs = {
+ description = "Emacs: the extensible, self-documenting text editor";
+
+ serviceConfig = {
+ Type = "forking";
+ ExecStart = "${pkgs.bash}/bin/bash -c 'source ${config.system.build.setEnvironment}; exec ${cfg.package}/bin/emacs --daemon'";
+ ExecStop = "${cfg.package}/bin/emacsclient --eval (kill-emacs)";
+ Restart = "always";
+ };
+ } // optionalAttrs cfg.enable { wantedBy = [ "default.target" ]; };
+
+ environment.systemPackages = [ cfg.package editorScript ];
+
+ environment.variables = if cfg.defaultEditor then {
+ EDITOR = mkOverride 900 "${editorScript}/bin/emacseditor";
+ } else {};
+ };
+}
diff --git a/nixos/tests/emacs-daemon.nix b/nixos/tests/emacs-daemon.nix
new file mode 100644
index 000000000000..a4d63bdb7e41
--- /dev/null
+++ b/nixos/tests/emacs-daemon.nix
@@ -0,0 +1,45 @@
+import ./make-test.nix ({ pkgs, ...} : {
+ name = "emacs-daemon";
+ meta = with pkgs.stdenv.lib.maintainers; {
+ maintainers = [ DamienCassou ];
+ };
+
+ enableOCR = true;
+
+ machine =
+ { config, pkgs, ... }:
+
+ { imports = [ ./common/x11.nix ];
+ services.emacs = {
+ enable = true;
+ defaultEditor = true;
+ };
+
+ # Important to get the systemd service running for root
+ environment.variables.XDG_RUNTIME_DIR = "/run/user/0";
+
+ environment.variables.TEST_SYSTEM_VARIABLE = "system variable";
+ };
+
+ testScript =
+ ''
+ $machine->waitForUnit("multi-user.target");
+
+ # checks that the EDITOR environment variable is set
+ $machine->succeed("test \$(basename \"\$EDITOR\") = emacseditor");
+
+ # waits for the emacs service to be ready
+ $machine->waitUntilSucceeds("systemctl --user status emacs.service | grep 'Active: active'");
+
+ # connects to the daemon
+ $machine->succeed("emacsclient --create-frame \$EDITOR &");
+
+ # checks that Emacs shows the edited filename
+ $machine->waitForText("emacseditor");
+
+ # makes sure environment variables are accessible from Emacs
+ $machine->succeed("emacsclient --eval '(getenv \"TEST_SYSTEM_VARIABLE\")'") =~ /system variable/ or die;
+
+ $machine->screenshot("emacsclient");
+ '';
+})