├── .gitignore ├── README.md ├── base.nix ├── default.nix ├── docs.nix ├── example.nix ├── modules ├── company │ └── default.nix ├── default.nix ├── evil │ ├── collection.nix │ └── default.nix ├── helm │ └── default.nix ├── language-support │ ├── default.nix │ ├── golang.nix │ ├── markdown.nix │ └── nix.nix ├── lsp │ ├── default.nix │ └── lsp-ui.nix ├── magit │ └── default.nix ├── nogui.nix ├── org │ ├── default.nix │ └── org-roam.nix ├── performance │ ├── default.nix │ └── startup-gc-threshold.nix ├── themes │ ├── base16.nix │ ├── default.nix │ ├── loader.nix │ └── themes.nix ├── traits │ ├── default.nix │ ├── evil-escesc.nix │ ├── evil-markdown.nix │ ├── evil-org-nogui.nix │ ├── evil-org.nix │ └── nogui-xclip.nix ├── warnings.nix ├── workarounds │ ├── default.nix │ └── evil-org-evil-redirect-digit-argument.nix └── yasnippet │ └── default.nix └── target.nix /.gitignore: -------------------------------------------------------------------------------- 1 | result 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # nix-emacs 2 | 3 | Use the same module system that leverages NixOS to configure your emacs customization 4 | -------------------------------------------------------------------------------- /base.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkOption types optional; 4 | in { 5 | options = { 6 | target = mkOption { 7 | type = types.attrsOf types.package; 8 | default = {}; 9 | visible = false; 10 | }; 11 | identifier = mkOption { 12 | type = types.str; 13 | description = "Unique identifier for the configuration"; 14 | default = "default"; 15 | }; 16 | package = mkOption { 17 | type = types.package; 18 | description = "Emacs package used"; 19 | default = pkgs.emacs; 20 | }; 21 | plugins = mkOption { 22 | type = types.listOf types.package; 23 | description = "Emacs plugins"; 24 | default = []; 25 | }; 26 | extraFlags = mkOption { 27 | type = types.listOf types.str; 28 | description = "Extra flags to launch the entrypoint"; 29 | default = []; 30 | }; 31 | initEl = { 32 | pre = mkOption { 33 | type = types.lines; 34 | description = "init.el pre part for ordering"; 35 | default = ""; 36 | }; 37 | main = mkOption { 38 | type = types.lines; 39 | description = "init.el pre part for ordering"; 40 | default = ""; 41 | }; 42 | pos = mkOption { 43 | type = types.lines; 44 | description = "init.el pre part for ordering"; 45 | default = ""; 46 | }; 47 | }; 48 | }; 49 | } 50 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? import {} 2 | , modules ? [] 3 | , specialArgs ? {} 4 | , ... 5 | }@args: 6 | let 7 | inherit (builtins) removeAttrs length trace head tail; 8 | inherit (pkgs) lib; 9 | inherit (lib) evalModules; 10 | in 11 | let 12 | traceWarnings = warnings: v: 13 | if length warnings == 0 14 | then v 15 | else 16 | trace (head warnings) (traceWarnings (tail warnings) v) 17 | ; 18 | 19 | mainModule = removeAttrs args ["pkgs" "specialArgs"]; 20 | input = evalModules { 21 | modules = [ 22 | (args: mainModule) 23 | ./base.nix 24 | ./modules 25 | ./target.nix 26 | ]; 27 | specialArgs = specialArgs // { 28 | inherit pkgs; 29 | }; 30 | }; 31 | in traceWarnings input.config.warnings input.config.target.entrypoint // { 32 | inherit (input) config options; 33 | inherit input; 34 | inherit (input.config.target) entrypoint; 35 | } 36 | -------------------------------------------------------------------------------- /docs.nix: -------------------------------------------------------------------------------- 1 | {pkgs ? import {}}: 2 | let 3 | example = pkgs.callPackage ./example.nix {}; 4 | optionsDoc = pkgs.nixosOptionsDoc { 5 | inherit (example) options; 6 | }; 7 | in pkgs.runCommandNoCC "doc.html" { 8 | buildInputs = with pkgs; [ pandoc ]; 9 | } '' 10 | pandoc ${optionsDoc.optionsDocBook} -o $out -f docbook -t html 11 | '' 12 | -------------------------------------------------------------------------------- /example.nix: -------------------------------------------------------------------------------- 1 | # Config example used to demo if it works and as a baseline for users to experiment 2 | # Use `nix-build example.nix` and open emacs via ./result/bin/emacs 3 | # This file returns a function that returns a derivation so import/callPackage and nix-env should work as well 4 | 5 | {pkgs ? import {}}: 6 | pkgs.callPackage ./default.nix { 7 | initEl = { 8 | pos = '' 9 | ;; Works 10 | (tool-bar-mode 0) 11 | ''; 12 | }; 13 | nogui = true; 14 | evil = { 15 | enable = true; 16 | escesc = true; 17 | collection = true; 18 | }; 19 | company.enable = true; 20 | magit.enable = true; 21 | language-support = { 22 | nix.enable = true; 23 | markdown.enable = true; 24 | golang.enable = true; 25 | }; 26 | performance.startup.increase-gc-threshold-on-init = true; 27 | # themes.selected = "manoj-dark"; 28 | themes.base16-pallete = { 29 | }; 30 | org = { 31 | enable = true; 32 | roam = { 33 | enable = true; 34 | # ack-v2 = true; 35 | }; 36 | }; 37 | helm.enable = true; 38 | yasnippet = { 39 | enable = true; 40 | global-mode.enable = true; 41 | official-snippets.enable = true; 42 | }; 43 | lsp = { 44 | enable = true; 45 | lsp-ui.enable = true; 46 | }; 47 | } 48 | -------------------------------------------------------------------------------- /modules/company/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkIf mkEnableOption; 4 | in { 5 | options = { 6 | company.enable = mkEnableOption "company"; 7 | }; 8 | config = mkIf config.company.enable { 9 | plugins = with pkgs.emacsPackages; [ 10 | company 11 | ]; 12 | initEl = { 13 | pos = '' 14 | (add-hook 'after-init-hook 'global-company-mode) 15 | ''; 16 | }; 17 | }; 18 | } 19 | -------------------------------------------------------------------------------- /modules/default.nix: -------------------------------------------------------------------------------- 1 | {...}: 2 | { 3 | imports = [ 4 | ./nogui.nix 5 | ./warnings.nix 6 | ./language-support 7 | ./themes 8 | 9 | ./org 10 | ./evil 11 | ./magit 12 | ./lsp 13 | ./helm 14 | ./company 15 | ./yasnippet 16 | 17 | ./workarounds 18 | ./performance 19 | ./traits 20 | ]; 21 | } 22 | -------------------------------------------------------------------------------- /modules/evil/collection.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkIf mkEnableOption; 4 | in { 5 | options = { 6 | evil.collection = mkEnableOption "evil-collection"; 7 | }; 8 | config = mkIf (config.evil.enable && config.evil.collection) { 9 | plugins = with pkgs.emacsPackages; [ evil-collection ]; 10 | initEl = { 11 | pre = '' 12 | (setq evil-want-integration t) 13 | (setq evil-want-keybinding nil) 14 | ''; 15 | main = '' 16 | (require 'evil-collection nil t) 17 | ''; 18 | pos = '' 19 | (evil-collection-init) 20 | ''; 21 | }; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /modules/evil/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkOption mkEnableOption mkIf types; 4 | cfg = config.evil; 5 | in { 6 | imports = [ 7 | ./collection.nix 8 | ]; 9 | options = { 10 | evil = { 11 | enable = mkEnableOption "evil-mode"; 12 | }; 13 | }; 14 | config = mkIf cfg.enable { 15 | initEl = { 16 | main = '' 17 | (require 'evil) 18 | ''; 19 | pos = '' 20 | (evil-mode 1) 21 | ''; 22 | }; 23 | plugins = with pkgs.emacsPackages; [ evil ]; 24 | }; 25 | } 26 | -------------------------------------------------------------------------------- /modules/helm/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkEnableOption; 4 | in 5 | { 6 | options.helm.enable = mkEnableOption "helm"; 7 | config = { 8 | plugins = with pkgs.emacsPackages; [ helm ]; 9 | initEl.pre = '' 10 | (setq helm-allow-mouse t) 11 | (global-set-key (kbd "M-x") #'helm-M-x) 12 | (global-set-key (kbd "C-x r b") #'helm-filtered-bookmarks) 13 | (global-set-key (kbd "C-x C-f") #'helm-find-files) 14 | 15 | ''; 16 | initEl.main = '' 17 | (require 'helm) 18 | ''; 19 | initEl.pos = '' 20 | (helm-mode 1) 21 | ''; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /modules/language-support/default.nix: -------------------------------------------------------------------------------- 1 | {...}: { 2 | imports = [ 3 | ./markdown.nix 4 | ./nix.nix 5 | ./golang.nix 6 | ]; 7 | } 8 | -------------------------------------------------------------------------------- /modules/language-support/golang.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkOption types mkEnableOption mkIf; 4 | cfg = config.language-support.golang; 5 | in { 6 | options = { 7 | language-support.golang = { 8 | enable = mkEnableOption "golang language support"; 9 | }; 10 | }; 11 | config = mkIf cfg.enable { 12 | plugins = with pkgs.emacsPackages; [ go-mode ]; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /modules/language-support/markdown.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkOption types mkEnableOption mkIf; 4 | cfg = config.language-support.markdown; 5 | in { 6 | options = { 7 | language-support.markdown = { 8 | enable = mkEnableOption "markdown language support"; 9 | }; 10 | }; 11 | config = mkIf cfg.enable { 12 | plugins = with pkgs.emacsPackages; [ markdown-mode ]; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /modules/language-support/nix.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkOption types mkEnableOption mkIf; 4 | cfg = config.language-support.nix; 5 | in { 6 | options = { 7 | language-support.nix = { 8 | enable = mkEnableOption "nix language-support"; 9 | }; 10 | }; 11 | config = mkIf cfg.enable { 12 | plugins = with pkgs.emacsPackages; [ nix-mode ]; 13 | initEl = { 14 | main = '' 15 | (require 'nix-mode) 16 | ''; 17 | pos = '' 18 | (add-to-list 'auto-mode-alist '("\\.nix\\'" . nix-mode)) 19 | ''; 20 | }; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /modules/lsp/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkIf mkEnableOption; 4 | in { 5 | imports = [ 6 | ./lsp-ui.nix 7 | ]; 8 | options.lsp.enable = mkEnableOption "lsp-mode"; 9 | config = mkIf config.lsp.enable { 10 | plugins = with pkgs.emacsPackages; [ 11 | lsp-mode 12 | ]; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /modules/lsp/lsp-ui.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkIf mkEnableOption; 4 | in { 5 | options.lsp.lsp-ui.enable = mkEnableOption "lsp-ui"; 6 | config = mkIf (config.lsp.enable && config.lsp.lsp-ui.enable) { 7 | plugins = with pkgs.emacsPackages; [ 8 | lsp-ui 9 | ]; 10 | }; 11 | } 12 | -------------------------------------------------------------------------------- /modules/magit/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkEnableOption mkIf; 4 | in 5 | { 6 | options.magit.enable = mkEnableOption "magit"; 7 | config = mkIf config.magit.enable { 8 | plugins = with pkgs.emacsPackages; [ magit ]; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /modules/nogui.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkOption types mkIf; 4 | in { 5 | options = { 6 | nogui = mkOption { 7 | type = types.bool; 8 | default = false; 9 | description = "Open Emacs in a terminal instead of in a GUI"; 10 | }; 11 | }; 12 | config = mkIf config.nogui { 13 | extraFlags = [ "-nw" ]; 14 | }; 15 | } 16 | -------------------------------------------------------------------------------- /modules/org/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkOption mkEnableOption; 4 | in { 5 | imports = [ 6 | ./org-roam.nix 7 | ]; 8 | options = { 9 | org = { 10 | enable = mkEnableOption "org-mode"; 11 | }; 12 | }; 13 | config = { 14 | plugins = with pkgs.emacsPackages; [ org ]; 15 | }; 16 | } 17 | -------------------------------------------------------------------------------- /modules/org/org-roam.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkEnableOption mkIf; 4 | in { 5 | options.org.roam = { 6 | enable = mkEnableOption "org-roam"; 7 | ack-v2 = mkEnableOption "disable the annoying reminder about note migration from v1"; 8 | }; 9 | config = mkIf (config.org.enable && config.org.roam.enable) { 10 | plugins = with pkgs.emacsPackages; [ 11 | org-roam 12 | ]; 13 | initEl.pre = mkIf config.org.roam.ack-v2 '' 14 | (setq org-roam-v2-ack t) 15 | ''; 16 | initEl.pos = '' 17 | (add-hook 'after-init-hook (lambda () 18 | (define-key (current-global-map) (kbd "C-c n f") 'org-roam-node-find) 19 | (define-key (current-global-map) (kbd "C-c n r") 'org-roam-node-random) 20 | (define-key (org-mode-map) (kbd "C-c n i") 'org-roam-node-insert) 21 | (define-key (org-mode-map) (kbd "C-c n o") 'org-id-get-create) 22 | (define-key (org-mode-map) (kbd "C-c n t") 'org-roam-tag-add) 23 | (define-key (org-mode-map) (kbd "C-c n a") 'org-roam-alias-add) 24 | (define-key (org-mode-map) (kbd "C-c n l") 'org-roam-buffer-toggle))) 25 | 26 | ''; 27 | }; 28 | } 29 | -------------------------------------------------------------------------------- /modules/performance/default.nix: -------------------------------------------------------------------------------- 1 | {...}: 2 | { 3 | imports = [ 4 | ./startup-gc-threshold.nix 5 | ]; 6 | } 7 | -------------------------------------------------------------------------------- /modules/performance/startup-gc-threshold.nix: -------------------------------------------------------------------------------- 1 | {config, lib, ...}: 2 | let 3 | inherit (lib) mkEnableOption mkIf; 4 | in 5 | { 6 | options = { 7 | performance.startup.increase-gc-threshold-on-init = mkEnableOption "increase GC threshold to avoid GCs on initialization"; 8 | }; 9 | config = mkIf config.performance.startup.increase-gc-threshold-on-init { 10 | initEl.pre = '' 11 | (let 12 | ( 13 | ;; Temporarily increase the GC threshold to avoid GCs on initialization 14 | (gc-cons-threshold most-positive-fixnum) 15 | ;; Avoid analyzing files when loading remote files 16 | (file-name-handler-alist nil)) 17 | ''; 18 | initEl.pos = '' 19 | ) 20 | ''; 21 | }; 22 | } 23 | -------------------------------------------------------------------------------- /modules/themes/base16.nix: -------------------------------------------------------------------------------- 1 | { lib, pkgs, config, ... }: 2 | let 3 | inherit (lib) mkIf mkOption mkDefault types concatStringsSep listToAttrs attrNames; 4 | inherit (cfg.base16-pallete) base00 base01 base02 base03 base04 base05 base06 base07 base08 base09 base0A base0B base0C base0D base0E base0F; 5 | inherit (pkgs) writeText; 6 | cfg = config.themes; 7 | color-keys = [ 8 | "base00" 9 | "base01" 10 | "base02" 11 | "base03" 12 | "base04" 13 | "base05" 14 | "base06" 15 | "base07" 16 | "base08" 17 | "base09" 18 | "base0A" 19 | "base0B" 20 | "base0C" 21 | "base0D" 22 | "base0E" 23 | "base0F" 24 | ]; 25 | in { 26 | options = { 27 | themes.base16-pallete = let # stolen from https://github.com/Misterio77/nix-colors/blob/main/module/colorscheme.nix 28 | mkColorOption = name: { 29 | inherit name; 30 | value = mkOption { 31 | type = types.strMatching "[a-fA-F0-9]{6}"; 32 | description = "${name} color."; 33 | }; 34 | }; 35 | in mkOption { 36 | description = "Base16 pallette to be applied instead of a theme"; 37 | default = null; 38 | type = types.nullOr (types.submodule { 39 | options = (listToAttrs (map mkColorOption color-keys)); 40 | }); 41 | }; 42 | }; 43 | config = mkIf (cfg.base16-pallete != null) (let 44 | elFile = writeText "base16-nix-theme.nix" '' 45 | ;; base16-nix-theme.el -- A base16 colorscheme 46 | 47 | ;;; Commentary: 48 | ;; Base16: (https://github.com/base16-project/base16) 49 | 50 | ;;; Authors: 51 | ;; Scheme: {{scheme-author}} 52 | ;; Template: Kaleb Elwert 53 | 54 | ;;; Code: 55 | (require 'base16-theme) 56 | 57 | (defvar base16-nix-theme-colors 58 | '(${concatStringsSep " " (map (name: '':${name} "#${cfg.base16-pallete.${name}}"'') color-keys)}) 59 | "All colors for the nix-emacs generated base16 theme are defined here.") 60 | 61 | ;; Define the theme 62 | (deftheme base16-nix) 63 | 64 | ;; Add all the faces to the theme 65 | (base16-theme-define 'base16-nix base16-nix-theme-colors) 66 | 67 | ;; Mark the theme as provided 68 | (provide-theme 'base16-nix) 69 | (provide 'base16-nix-theme) 70 | ;;; base16-nix-theme.el ends here 71 | ''; 72 | 73 | base16-plugin = pkgs.stdenv.mkDerivation { 74 | pname = "base16-nix"; 75 | version = "1"; 76 | src = elFile; 77 | dontUnpack = true; 78 | 79 | installPhase = '' 80 | install -d $out/share/emacs/site-lisp 81 | install $src $out/share/emacs/site-lisp/base16-nix-theme.el 82 | ''; 83 | }; 84 | in { 85 | themes.selected = mkDefault "base16-nix"; 86 | initEl.pre = '' 87 | (add-to-list 'custom-theme-load-path "${base16-plugin}/share/emacs/site-lisp") 88 | ''; 89 | themes.available.base16-nix.packages = with pkgs.emacsPackages; [ 90 | base16-theme 91 | base16-plugin 92 | ]; 93 | }); 94 | } 95 | -------------------------------------------------------------------------------- /modules/themes/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) optional mkOption types; 4 | cfg = config.themes; 5 | in { 6 | imports = [ 7 | ./themes.nix 8 | ./loader.nix 9 | ./base16.nix 10 | ]; 11 | options = { 12 | themes = { 13 | available = mkOption { 14 | description = "Themes available to just select"; 15 | default = {}; 16 | type = types.attrsOf (types.submodule ({...}: { 17 | options = { 18 | packages = mkOption { 19 | description = "Extra packages required for the theme"; 20 | default = []; 21 | type = types.listOf types.package; 22 | }; 23 | supportsNoGui = mkOption { 24 | description = "Do the theme works on the CLI mode?"; 25 | default = false; 26 | type = types.bool; 27 | }; 28 | }; 29 | })); 30 | }; 31 | selected = mkOption { 32 | description = "Selected theme"; 33 | default = null; 34 | type = types.nullOr types.str; 35 | }; 36 | }; 37 | }; 38 | } 39 | -------------------------------------------------------------------------------- /modules/themes/loader.nix: -------------------------------------------------------------------------------- 1 | {config, pkgs, lib, ...}: 2 | let 3 | inherit (lib) mkIf optional; 4 | cfg = config.themes; 5 | in mkIf (cfg.selected != null) ( 6 | let 7 | selected = cfg.available."${cfg.selected}"; 8 | in { 9 | warnings = optional (!selected.supportsNoGui && config.nogui) "the selected theme does not support GUIless mode"; 10 | plugins = selected.packages; 11 | initEl.pos = '' 12 | (load-theme '${cfg.selected}) 13 | ''; 14 | }) 15 | -------------------------------------------------------------------------------- /modules/themes/themes.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | # TODO: some of these themes actually works in CLI mode 3 | { 4 | config = { 5 | themes.available = { # define the default themes as no package required 6 | adwaita.packages = []; 7 | deeper-blue.packages = []; 8 | dichromacy.packages = []; 9 | leuven.packages = []; 10 | light-blue.packages = []; 11 | manoj-dark.packages = []; 12 | misterioso.packages = []; 13 | tango-dark.packages = []; 14 | tsdh-dark.packages = []; 15 | tsdh-light.packages = []; 16 | wheatgrass.packages = []; 17 | whiteboard.packages = []; 18 | wombat.packages = []; 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /modules/traits/default.nix: -------------------------------------------------------------------------------- 1 | {...}: 2 | { 3 | imports = [ 4 | ./evil-org.nix 5 | ./evil-org-nogui.nix 6 | ./evil-escesc.nix 7 | ./evil-markdown.nix 8 | ./nogui-xclip.nix 9 | ]; 10 | } 11 | -------------------------------------------------------------------------------- /modules/traits/evil-escesc.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkEnableOption mkIf; 4 | in { 5 | options = { 6 | evil.escesc = mkEnableOption "Accept esc esc to go to normal mode quickly"; 7 | }; 8 | config = { 9 | initEl.pos = mkIf (config.evil.escesc && config.evil.enable) '' 10 | (define-key evil-insert-state-map (kbd "ESC ") 'evil-normal-state) 11 | ''; 12 | }; 13 | } 14 | -------------------------------------------------------------------------------- /modules/traits/evil-markdown.nix: -------------------------------------------------------------------------------- 1 | {config, lib, pkgs, ...}: 2 | let 3 | inherit (lib) optional; 4 | in 5 | { 6 | config = { 7 | warnings = [] 8 | ++ optional (config.evil.enable && config.language-support.markdown.enable) "markdown language support is enabled and evil mode is enabled too but evil-markdown is not defined, the evil part of markdown-mode will be disabled"; 9 | }; 10 | } 11 | -------------------------------------------------------------------------------- /modules/traits/evil-org-nogui.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkIf; 4 | in 5 | { 6 | config = mkIf (config.org.enable && config.evil.enable && config.nogui) { 7 | initEl = { 8 | pre = '' 9 | ;; https://github.com/Somelauw/evil-org-mode#common-issues 10 | (setq evil-want-C-i-jump nil) 11 | ''; 12 | }; 13 | }; 14 | } 15 | -------------------------------------------------------------------------------- /modules/traits/evil-org.nix: -------------------------------------------------------------------------------- 1 | {pkgs, config, lib, ...}: 2 | let 3 | inherit (lib) mkIf; 4 | in 5 | { 6 | config = mkIf (config.org.enable && config.evil.enable) { 7 | plugins = with pkgs.emacsPackages; [ evil-org ]; 8 | initEl = { 9 | pre = '' 10 | (setq evil-org-key-theme '(textobjects navigation additional insert todo)) 11 | ''; 12 | main = '' 13 | (require 'evil-org) 14 | ''; 15 | pos = '' 16 | (evil-org-set-key-theme) 17 | (add-hook 'org-mode-hook 'evil-org-mode) 18 | ''; 19 | }; 20 | }; 21 | } 22 | -------------------------------------------------------------------------------- /modules/traits/nogui-xclip.nix: -------------------------------------------------------------------------------- 1 | {config, pkgs, lib, ...}: 2 | let 3 | inherit (lib) mkIf; 4 | in 5 | { 6 | config = mkIf config.nogui { 7 | plugins = with pkgs.emacsPackages; [ xclip ]; 8 | initEl = { 9 | main = '' 10 | (require 'xclip) 11 | ''; 12 | pos = '' 13 | (xclip-mode 1) 14 | ''; 15 | }; 16 | }; 17 | } 18 | -------------------------------------------------------------------------------- /modules/warnings.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkOption types; 4 | in { 5 | options = { 6 | warnings = mkOption { 7 | description = "Evaluation warnings"; 8 | default = []; 9 | type = types.listOf types.str; 10 | }; 11 | }; 12 | } 13 | -------------------------------------------------------------------------------- /modules/workarounds/default.nix: -------------------------------------------------------------------------------- 1 | {...}: 2 | { 3 | imports = [ 4 | ./evil-org-evil-redirect-digit-argument.nix 5 | ]; 6 | } 7 | -------------------------------------------------------------------------------- /modules/workarounds/evil-org-evil-redirect-digit-argument.nix: -------------------------------------------------------------------------------- 1 | {config, lib, ...}: 2 | let 3 | inherit (lib) mkOption types mkIf; 4 | in 5 | { 6 | options.workaround.evil-org-evil-redirect-digit-argument = mkOption { 7 | type = types.bool; 8 | description = "See https://github.com/Somelauw/evil-org-mode/issues/93#issuecomment-950306532"; 9 | default = true; 10 | }; 11 | config = mkIf (config.org.enable && config.evil.enable && config.workaround.evil-org-evil-redirect-digit-argument) { 12 | warnings = [ 13 | "there is a bug on https://github.com/Somelauw/evil-org-mode and the fix should be available soon. See https://github.com/Somelauw/evil-org-mode/issues/93#issuecomment-950306532" 14 | ]; 15 | initEl.pre = '' 16 | (fset 'evil-redirect-digit-argument 'ignore) ;; before evil-org loaded 17 | ''; 18 | }; 19 | } 20 | -------------------------------------------------------------------------------- /modules/yasnippet/default.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (lib) mkIf mkEnableOption optional; 4 | cfg = config.yasnippet; 5 | in { 6 | options.yasnippet = { 7 | enable = mkEnableOption "yasnippet"; 8 | global-mode.enable = mkEnableOption "yasnippet globally"; 9 | official-snippets.enable = mkEnableOption "official snippet collection"; 10 | }; 11 | config = mkIf config.yasnippet.enable { 12 | plugins = with pkgs.emacsPackages; 13 | optional cfg.enable yasnippet 14 | ++ optional cfg.official-snippets.enable yasnippet-snippets 15 | ; 16 | initEl.main = '' 17 | (require 'yasnippet) 18 | ''; 19 | initEl.pos = mkIf config.yasnippet.global-mode.enable '' 20 | (yas-global-mode 1) 21 | ''; 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /target.nix: -------------------------------------------------------------------------------- 1 | {pkgs, lib, config, ...}: 2 | let 3 | inherit (builtins) concatStringsSep attrValues; 4 | inherit (pkgs) writeText; 5 | in { 6 | config = let 7 | initEl = writeText "init-${config.identifier}.el" ( 8 | concatStringsSep "\n" (with config.initEl; [ pre main pos ]) 9 | ); 10 | overrided = config.package.pkgs.withPackages config.plugins; 11 | flags = config.extraFlags; 12 | in { 13 | target = { 14 | entrypoint = pkgs.stdenvNoCC.mkDerivation { 15 | inherit (overrided) meta; 16 | inherit (overrided.emacs) pname version; 17 | 18 | dontUnpack = true; 19 | 20 | nativeBuildInputs = with pkgs; [ makeWrapper ]; 21 | installPhase = '' 22 | cp -r ${overrided} $out 23 | chmod +w $out/bin/emacs 24 | ls $out 25 | makeWrapper ${overrided}/bin/emacs $out/bin/emacs ${concatStringsSep " " (map (v: ''--add-flags "${v}"'') (flags ++ ["-l" initEl]))} 26 | ''; 27 | }; 28 | nixlessBundleZipped = 29 | pkgs.runCommandNoCC "nixless-emacs.zip" {} "cd ${config.target.nixlessBundle}; ${pkgs.zip}/bin/zip -r $out ."; 30 | nixlessBundle = builtins.trace "DISCLAIMER: nixless emacs is a very experimental feature. Be careful!" 31 | pkgs.stdenvNoCC.mkDerivation { 32 | inherit (overrided.emacs) pname version; 33 | dontUnpack = true; 34 | dontFixup = true; 35 | nativeBuildInputs = with pkgs; [ makeWrapper ]; 36 | 37 | installPhase = '' 38 | mkdir $out/modules -p 39 | thePath=`cat ${overrided}/bin/emacs | grep deps | head -n 1 | sed 's;^.*(\(.*\)).*$;\\1;'` 40 | echo $thePath 41 | cp -rvL $thePath/elpa $out/modules/elpa 42 | # cat $thePath/subdirs.el | sed 's/ \r/g' 43 | # cp -L $thePath/subdirs.el $out/modules 44 | { 45 | echo "(setq load-path (let ((dir (file-name-as-directory (concat (file-name-as-directory (getenv \"CONFPATH\")) \"modules\")))) (delete-dups (append " 46 | cat $thePath/subdirs.el | sed 's/ /\n/g' | tr "\"'()" ' ' | grep site-lisp | sed 's/ //g' | sed "s;$thePath;;g" | sed 's;^/;;g' | while read -r line; do 47 | echo "(list (concat dir \"$line\"))" 48 | done 49 | echo "load-path))))" 50 | echo "(require 'json)" 51 | echo "(message (json-encode load-path))" 52 | echo 53 | echo 54 | cat ${initEl} 55 | } > $out/init.el 56 | 57 | { 58 | echo '#!/usr/bin/env bash' 59 | echo 'export CONFPATH=`dirname "$(realpath "$0")"`' 60 | echo 'echo "confpath: $CONFPATH"' 61 | echo 'export EMACSLOADPATH=$CONFPATH/modules:$EMACSLOADPATH' 62 | echo 'exec "emacs" -l "$CONFPATH/init.el" "$@"' 63 | } > $out/nemacs 64 | 65 | chmod +x $out/nemacs 66 | 67 | { 68 | echo 'set "PATH=%PATH;C:\Program Files\Emacs\x86_64\bin"' 69 | echo 'set CONFPATH=%~dp0' 70 | echo 'set "EMACSLOADPATH=%CONFPATH%modules;"' 71 | echo 'start runemacs -l "%CONFPATH%init.el" %*' 72 | } > $out/nemacs.bat 73 | ''; 74 | }; 75 | }; 76 | }; 77 | } 78 | --------------------------------------------------------------------------------