about summary refs log tree commit diff
path: root/modules/emacs
diff options
context:
space:
mode:
Diffstat (limited to 'modules/emacs')
-rw-r--r--modules/emacs/default.nix270
-rw-r--r--modules/emacs/doom/config.el248
-rw-r--r--modules/emacs/doom/init.el99
-rw-r--r--modules/emacs/doom/packages.el12
4 files changed, 629 insertions, 0 deletions
diff --git a/modules/emacs/default.nix b/modules/emacs/default.nix
new file mode 100644
index 0000000..2230ee0
--- /dev/null
+++ b/modules/emacs/default.nix
@@ -0,0 +1,270 @@
+{
+  config,
+  inputs,
+  lib,
+  pkgs,
+  ...
+}:
+with lib;
+let
+  cfg = config.nixfiles.modules.emacs;
+in
+{
+  options.nixfiles.modules.emacs.enable = mkEnableOption "GNU Emacs";
+
+  config = mkIf cfg.enable {
+    secrets.authinfo = {
+      file = "${inputs.self}/secrets/authinfo";
+      owner = my.username;
+    };
+
+    nixfiles.modules = {
+      common.xdg.defaultApplications.emacsclient = [
+        "application/atom+xml"
+        "application/json"
+        "application/rss+xml"
+        "application/schema+json"
+        "application/xhtml+xml"
+        "application/xml"
+        "text/csv"
+        "text/plain"
+      ];
+      git.client.enable = true;
+      gnupg.enable = true;
+      password-store.enable = true;
+      profiles.dev.enable = true;
+      profiles.email.enable = true;
+    };
+
+    hm = {
+      stylix.targets.emacs.enable = false;
+
+      xdg.configFile =
+        mapAttrs
+          (
+            _: value:
+            value
+            // {
+              onChange = with config.hm.programs; ''
+                export EMACSDIR="''${XDG_CONFIG_HOME:-$HOME/.config}/emacs"
+                export DOOMDIR="''${XDG_CONFIG_HOME:-$HOME/.config}/doom"
+
+                if [[ ! -d "$EMACSDIR/.git" ]]; then
+                  ${getExe git.package} clone --depth=1 --branch=master \
+                    "https://github.com/doomemacs/doomemacs" "$EMACSDIR"
+                fi
+
+                if [[ ! -d "$DOOMDIR/snippets" ]]; then
+                  mkdir -p "$DOOMDIR/snippets"
+                fi
+
+                if [[ -x "$EMACSDIR/bin/doom" ]]; then
+                  if [[ ! -d "$EMACSDIR/.local" ]]; then
+                    PATH="''${PATH:-/bin:/usr/bin:/usr/local/bin}:${emacs.package}/bin:${git.package}/bin" \
+                      "$EMACSDIR/bin/doom" install --force --verbose
+                  fi
+
+                  PATH="''${PATH:-/bin:/usr/bin:/usr/local/bin}:${emacs.package}/bin:${git.package}/bin" \
+                    "$EMACSDIR/bin/doom" sync -e --gc --force --verbose
+                fi
+              '';
+            }
+          )
+          {
+            "doom/init.el".source = ./doom/init.el;
+            "doom/packages.el".source = ./doom/packages.el;
+            "doom/config.el" = {
+              text = concatLines [
+                (
+                  let
+                    extraBins = with pkgs; [
+                      (aspellWithDicts (
+                        p: with p; [
+                          en
+                          ru
+                        ]
+                      )) # :checkers (spell +aspell)
+                      asmfmt # :editor format
+                      cargo # :lang rust
+                      clang-tools # :lang (cc +lsp) :editor format
+                      cmake-format # :lang cc :editor format
+                      cmigemo # :lang japanese
+                      config.hm.programs.emacs.package # !doom
+                      config.nix.package # !doom
+                      delve # :lang go :tools debugger
+                      dockerfile-language-server-nodejs # :tools (docker +lsp)
+                      dockfmt # :tools docker :editor format
+                      editorconfig-core-c # :tools editorconfig
+                      fd # doom!
+                      gcc # :lang cc
+                      ghc # :lang haskell
+                      gnuplot # :lang (org +gnuplot)
+                      gnutar # :tools tree-sitter
+                      gnutls # doom! :app irc
+                      go # :lang go
+                      godef # :lang go
+                      gomodifytags # :lang go
+                      gopls # :lang (go +lsp)
+                      gore # :lang go
+                      gotests # :lang go
+                      gotools # :lang go
+                      graphviz # :lang (org +roam2) :lang plantuml
+                      gzip # :tools tree-sitter
+                      haskellPackages.cabal-fmt # :lang haskell :editor format
+                      haskellPackages.cabal-install # :lang haskell
+                      haskellPackages.haskell-language-server # :lang (haskell +lsp)
+                      haskellPackages.hoogle # :lang haskell
+                      haskellPackages.ormolu # :lang haskell :editor format
+                      html-tidy # :lang web :editor format
+                      jdk # :lang java :lang plantuml :checkers grammar
+                      languagetool # :checkers grammar
+                      libxml2 # :lang data :editor format
+                      markdownlint-cli # :lang markdown
+                      nil # :lang (nix +lsp)
+                      nixfmt # :lang nix :editor format
+                      nls # :lang (nickel +lsp)
+                      nodePackages.bash-language-server # :lang (sh +lsp)
+                      nodePackages.eslint # :lang (json +lsp)
+                      nodePackages.js-beautify # :lang web
+                      nodePackages.prettier # :editor format
+                      nodePackages.stylelint # :lang web
+                      nodePackages.vscode-css-languageserver-bin # lang (web +lsp)
+                      nodePackages.vscode-html-languageserver-bin # lang (web +lsp)
+                      nodePackages.vscode-json-languageserver-bin # lang (json +lsp)
+                      nodejs # :tools debugger
+                      pandoc # :lang org markdown latex
+                      pinentry-emacs # doom!
+                      pipenv # :lang python
+                      poetry # :lang python
+                      pre-commit # :tools magit
+                      python3 # :lang python
+                      python3Packages.black # :lang python :editor format
+                      python3Packages.isort # :lang python :editor format
+                      python3Packages.nose # :lang python
+                      python3Packages.pyflakes # :lang python :editor format
+                      python3Packages.pytest # :lang python
+                      python3Packages.python-lsp-server # :lang python :editor format
+                      ripgrep # doom!
+                      rust-analyzer # :lang (rust +lsp)
+                      rustc # :lang rust
+                      rustfmt # :lang rust
+                      shellcheck # :lang sh
+                      shfmt # :lang sh :editor format
+                      sops
+                      sqlite # :lang (org +roam2) :tools lookup
+                      terraform-ls # :tools (terraform +lsp)
+                      texlab # lang (tex +lsp)
+                      texlive.combined.scheme-full # :lang org tex
+                      unzip # :tools debugger
+                      wordnet # :tools (lookup +dictionary +offline)
+                      yaml-language-server # :lang (yaml +lsp)
+                      zig # :lang zig :editor format
+                      zls # :lang (zig +lsp)
+                      zstd # :emacs undo
+                      gdb # :tools debugger
+                    ];
+                  in
+                  ''
+                    ;; Integrate packages which are required by various modules
+                    ;; without polluting the user's profile.
+                    (setq exec-path (append exec-path '(${concatMapStringsSep " " (x: ''"${x}/bin"'') extraBins})))
+                    (setenv "PATH" (concat (getenv "PATH") ":${concatMapStringsSep ":" (x: "${x}/bin") extraBins}"))
+
+                    ;; HACK Explicitly load specific Emacs packages from Nixpkgs.
+                    ;; For some reason providing them as "extraPackages" doesn't
+                    ;; work.
+                    (add-to-list 'load-path "${pkgs.mu.mu4e}/share/emacs/site-lisp/mu4e")
+                    (add-to-list 'load-path "${pkgs.emacsPackages.vterm}/share/emacs/site-lisp/elpa/vterm-${pkgs.emacsPackages.vterm.version}")
+
+                    (appendq! auth-sources '(("${config.secrets.authinfo.path}")))
+
+                    ;; :input japanese
+                    (setq migemo-dictionary "${pkgs.cmigemo}/share/migemo/utf-8/migemo-dict"
+                          migemo-options '("--quiet" "--emacs")
+                          skk-large-jisyo "${pkgs.skk-dicts}/share/SKK-JISYO.L"
+                          skk-show-inline t)
+
+                    ;; :editor parinfer
+                    (setq parinfer-rust-auto-download nil
+                          parinfer-rust-library "${pkgs.parinfer-rust}/lib/libparinfer_rust.so")
+
+                    ;; :lang (org +roam2) :email mu4e
+                    (setq emacsql-sqlite-executable "${getExe pkgs.emacsql-sqlite}")
+
+                    ;; :lang plantuml
+                    (setq plantuml-jar-path "${pkgs.plantuml}/lib/plantuml.jar"
+                          plantuml-executable-path "${getExe' pkgs.plantuml "plantuml"}"
+                          org-plantuml-jar-path plantuml-jar-path
+                          org-plantuml-executable-path plantuml-executable-path)
+
+                    ;; :app irc
+                    (setq circe-default-nick "${my.username}"
+                          circe-default-realname "${my.email}"
+                          circe-default-user circe-default-nick)
+                  ''
+                )
+                (with config.stylix.fonts; ''
+                  (setq doom-font "${monospace.name}-${toString sizes.terminal}"
+                        doom-serif-font "${serif.name}-${toString sizes.terminal}"
+                        doom-variable-pitch-font "${sansSerif.name}-${toString sizes.terminal}")
+                '')
+                (
+                  with config.hm.accounts.email;
+                  let
+                    mu4eAccounts =
+                      let
+                        muAccounts = filter (a: a.mu.enable) (attrValues accounts);
+                      in
+                      concatMapStringsSep "\n" (
+                        a:
+                        with a;
+                        let
+                          personalAddresses = concatMapStringsSep " " (v: ''"${v}"'') aliases;
+                        in
+                        ''
+                          (set-email-account! "${name}"
+                            '((user-full-name           . "${realName}")
+                              (user-mail-address        . "${address}")
+                              (mu4e-inbox-folder        . "/${name}/${folders.inbox}")
+                              (mu4e-sent-folder         . "/${name}/${folders.sent}")
+                              (mu4e-drafts-folder       . "/${name}/${folders.drafts}")
+                              (mu4e-trash-folder        . "/${name}/${folders.trash}")
+                              (mu4e-refile-folder       . "/${name}/Archive")
+                              (+mu4e-personal-addresses . (${personalAddresses})))
+                            t)
+                        ''
+                      ) muAccounts;
+                  in
+                  ''
+                    (setq mu4e-root-maildir "${maildirBasePath}")
+
+                    ${mu4eAccounts}
+                  ''
+                )
+                (builtins.readFile ./doom/config.el)
+              ];
+            };
+          };
+
+      programs = {
+        emacs = {
+          enable = true;
+          package = pkgs.emacs29;
+        };
+
+        bash.initExtra = mkAfter ''
+          export PATH="$PATH:$XDG_CONFIG_HOME/emacs/bin"
+
+          # https://github.com/akermu/emacs-libvterm
+          if [[ "$INSIDE_EMACS" = vterm ]] && [[ -n "$EMACS_VTERM_PATH" ]] && [[ -f "$EMACS_VTERM_PATH/etc/emacs-vterm-bash.sh" ]]; then
+              source "$EMACS_VTERM_PATH/etc/emacs-vterm-bash.sh"
+          fi
+
+          # Not sourced from inside Emacs for some reason. Maybe it's not
+          # considered an interactive shell?
+          [[ -f ~/.profile ]] && . ~/.profile
+        '';
+      };
+    };
+  };
+}
diff --git a/modules/emacs/doom/config.el b/modules/emacs/doom/config.el
new file mode 100644
index 0000000..79c0156
--- /dev/null
+++ b/modules/emacs/doom/config.el
@@ -0,0 +1,248 @@
+;;
+;;; Misc
+;;
+
+(setq frame-title-format '("GNU Emacs"))
+
+(setq-hook! '(prog-mode-hook yaml-mode-hook)
+  display-line-numbers-type 'relative
+  scroll-margin 10
+  hscroll-margin 10)
+
+(setq browse-url-generic-program (executable-find "firefox")
+      browse-url-browser-function 'browse-url-generic)
+
+;;
+;;; Doom-specific
+;;
+
+(setq doom-theme 'modus-operandi
+      doom-modeline-icon nil
+      doom-modeline-indent-info t
+      doom-modeline-total-line-number t
+      doom-modeline-height 30)
+
+;;
+;;; Editorconfig
+;;
+
+(setq +editorconfig-mode-alist '((sh-mode . "sh"))
+      editorconfig-exclude-modes '(lisp-mode
+                                   common-lisp-mode
+                                   emacs-lisp-mode))
+
+;;
+;;; LSP
+;;
+
+(setq lsp-enable-suggest-server-download nil
+      lsp-modeline-code-actions-enable nil)
+
+;;
+;;; Go
+;;
+
+(setq lsp-go-analyses
+  '((unsedvariable . t)
+    (unusedparams . t)
+    (unusedwrite . t)))
+
+;;
+;;; Org
+;;
+
+(setq org-directory "~/doc/org/")
+
+;; For some reason only using `after!' work here. `setq-hook!' and etc doesn't
+;; produce expected results.
+(after! org
+  (setq org-todo-keywords '((sequence
+                             "TODO(t)"
+                             "LOOP(r)"
+                             "STRT(s@)"
+                             "WAIT(w@/!)"
+                             "HOLD(h@/!)"
+                             "IDEA(i)"
+                             "PROJ(p)"
+                             "|"
+                             "DONE(d@/!)"
+                             "KILL(k@/!)"))
+        org-todo-keyword-faces '(("STRT" . +org-todo-active)
+                                 ("WAIT" . +org-todo-onhold)
+                                 ("HOLD" . +org-todo-onhold)
+                                 ("PROJ" . +org-todo-project)
+                                 ("KILL" . +org-todo-cancel))
+        org-capture-templates '(("t" "Todo" entry
+                                 (file+headline +org-capture-todo-file "Inbox")
+                                 "* TODO %?\n%i\n%a" :prepend t)
+                                ("n" "Note" entry
+                                 (file+headline +org-capture-notes-file "Inbox")
+                                 "* %u %?\n%i\n%a" :prepend t)
+                                ("j" "Journal" entry
+                                 (file+olp+datetree +org-capture-journal-file)
+                                 "* %U %?\n%i\n%a" :prepend t))))
+
+(add-hook! 'org-mode-hook 'auto-fill-mode)
+
+(setq-hook! 'org-mode-hook fill-column 80)
+
+(setq org-roam-directory "~/doc/roam/"
+      org-roam-db-location (concat org-roam-directory ".db"))
+
+(use-package! org-roam-ui
+  :requires websocket
+  :after org-roam
+  :config
+  (setq org-roam-ui-sync-theme t
+        org-roam-ui-follow t
+        org-roam-ui-update-on-save t
+        org-roam-ui-open-on-start t))
+
+;;
+;;; LaTeX
+;;
+
+(map! :map cdlatex-mode-map
+      :i "TAB" #'cdlatex-tab)
+
+;;
+;;; PlantUML
+;;
+
+(setq plantuml-default-exec-mode 'executable
+      org-plantuml-exec-mode 'plantuml)
+
+;;
+;;; Elisp
+;;
+
+(after! flycheck
+  (pushnew! flycheck-disabled-checkers 'emacs-lisp-checkdoc))
+
+;; Turn this off because it leaves face artifacts when changing indentation.
+(add-hook! 'emacs-lisp-mode-hook
+  (highlight-indent-guides-mode -1))
+
+;;
+;;; Haskell
+;;
+
+(setq lsp-haskell-formatting-provider "ormolu")
+
+;;
+;;; Nickel
+;;
+
+(use-package! nickel-mode
+  :config
+  (after! lsp-mode
+    (add-to-list 'lsp-language-id-configuration '(nickel-mode . "nickel")
+      (lsp-register-client (make-lsp-client
+                             :new-connection (lsp-stdio-connection "nls")
+                             :activation-fn (lsp-activate-on "nickel")
+                             :server-id 'nls
+                             :major-modes 'nickel-mode)))
+    (add-hook 'nickel-mode-hook 'lsp-deferred)))
+
+;;
+;;; YAML
+;;
+
+;; Turn off `flycheck-mode' and `lsp-mode' for Helm templates.
+(add-hook! 'yaml-mode-hook
+  (defun nixfiles/disable-flycheck-for-helm-templates-h ()
+    (when (and buffer-file-name
+               (string-match-p "/templates/" buffer-file-name)
+               (or (string-suffix-p ".yaml" buffer-file-name)
+                   (string-suffix-p ".yml" buffer-file-name)))
+      (remove-hook! 'yaml-mode-local-vars-hook #'lsp!))))
+
+(setq-hook! 'yaml-mode-hook +format-with-lsp nil)
+
+;;
+;;; Elfeed
+;;
+
+(setq elfeed-db-directory "~/.elfeed"
+      elfeed-enclosure-default-dir (concat elfeed-db-directory "/enclosures")
+      rmh-elfeed-org-files (list (concat elfeed-db-directory "/index.org"))
+      elfeed-goodies/powerline-default-separator nil
+      elfeed-goodies/entry-pane-size 0.75
+      elfeed-goodies/entry-pane-position 'bottom)
+
+(add-hook! 'elfeed-new-entry-hook
+           '((elfeed-make-tagger :before "2 weeks ago"
+                                 :remove 'unread)
+             (elfeed-make-tagger :feed-title "SberMarket Tech"
+                                 :entry-title (not ".*(DevOps|Golang).*")
+                                 :add 'junk
+                                 :remove 'unread)
+             (elfeed-make-tagger :feed-title "dotconferences"
+                                 :entry-title (not ".*dotGo.*")
+                                 :add 'junk
+                                 :remove 'unread)))
+
+;;
+;;; mu4e
+;;
+
+(setq-hook! 'mu4e-main-mode-hook
+  mu4e-update-interval 30
+  message-send-mail-function #'message-send-mail-with-sendmail
+  message-sendmail-extra-arguments '("--read-envelope-from")
+  message-sendmail-f-is-evil t
+  send-mail-function #'sendmail-send-it
+  sendmail-program (executable-find "msmtp"))
+
+;;
+;;; Circe
+;;
+
+(setq circe-network-options
+      (mapcar (lambda (server)
+                `(,server
+                  :server-buffer-name ,server
+                  :host "azahi.cc"
+                  :port 6697
+                  :tls t
+                  :logging nil
+                  :user ,(concat circe-default-user "/" server)
+                  :pass ,(lambda (&rest _)
+                           (+pass-get-secret "server/soju.shire.net/azahi"))))
+              '("libera" "oftc" "hackint" "rizon")))
+
+;;
+;;; Sops
+;;
+
+(use-package! sops
+  :config
+  (global-sops-mode 1))
+
+;;
+;;; Hledger
+;;
+
+(use-package! hledger-mode
+  :disabled
+  :mode ("\\.journal\\'")
+  :hook ((hledger-view-mode . hl-line-mode)
+         (hledger-view-mode . center-text-for-reading))
+  :init
+  (setq hledger-jfile "~/doc/accounting/current.journal")
+  :config
+  (set-company-backend! 'hledger-mode 'hledger-company)
+  (add-hook! 'hledger-mode-hook
+    (lambda (&rest _)
+      (make-local-variable 'company-backends)
+      (add-to-list 'company-backends 'hledger-company))))
+
+(use-package! hledger-input
+  :disabled
+  :hook ((hledger-input-post-commit . hledger-show-new-balances)
+         (hledger-input-mode . auto-fill-mode)
+         (hledger-input-mode . (lambda (&rest _)
+                                 (make-local-variable 'compay-idle-delay)
+                                 (setq-local company-idle-delay 0.1))))
+  :init
+  (setq hledger-input-buffer-height 20))
diff --git a/modules/emacs/doom/init.el b/modules/emacs/doom/init.el
new file mode 100644
index 0000000..571993b
--- /dev/null
+++ b/modules/emacs/doom/init.el
@@ -0,0 +1,99 @@
+(doom! :input
+       japanese
+
+       :completion
+       company
+       vertico
+
+       :ui
+       doom
+       (emoji +unicode)
+       hl-todo
+       indent-guides
+       ligatures
+       modeline
+       nav-flash
+       ophints
+       (popup +defaults)
+       (vc-gutter +diff-hl +pretty)
+       window-select
+       workspaces
+
+       :editor
+       (evil +everywhere)
+       file-templates
+       fold
+       format
+       parinfer
+       snippets
+       word-wrap
+
+       :emacs
+       dired
+       electric
+       ibuffer
+       undo
+       vc
+
+       :term
+       eshell
+       vterm
+
+       :checkers
+       syntax
+       (spell +aspell +everywhere)
+       grammar
+
+       :tools
+       ansible
+       (debugger +lsp)
+       direnv
+       (docker +lsp)
+       editorconfig
+       (eval +overlay)
+       (lookup +dictionary +offline)
+       (lsp +peek)
+       magit
+       make
+       (pass +auth)
+       pdf
+       (terraform +lsp)
+       tree-sitter
+       upload
+
+       :os
+       (:if (featurep :system 'macos) macos)
+
+       :lang
+       (cc +lsp +tree-sitter)
+       data
+       dhall
+       emacs-lisp
+       (go +lsp +tree-sitter)
+       (haskell +lsp +tree-sitter)
+       java
+       javascript
+       (json +lsp +tree-sitter)
+       kotlin
+       (latex +latexmk +cdlatex +lsp)
+       markdown
+       (nix +lsp +tree-sitter)
+       (org +pandoc +roam2)
+       plantuml
+       (python +poetry +lsp +tree-sitter)
+       (rust +lsp +tree-sitter)
+       (sh +lsp +tree-sitter)
+       web
+       (yaml +lsp +tree-sitter)
+       (zig +lsp +tree-sitter)
+
+       :email
+       mu4e
+
+       :app
+       calendar
+       irc
+       (rss +org)
+
+       :config
+       (default +bindings +smartparens))
diff --git a/modules/emacs/doom/packages.el b/modules/emacs/doom/packages.el
new file mode 100644
index 0000000..2ed0e4c
--- /dev/null
+++ b/modules/emacs/doom/packages.el
@@ -0,0 +1,12 @@
+(disable-packages! writegood-mode)
+
+(package! org-roam-ui)
+
+(package! nickel-mode)
+
+(package! hledger-mode)
+
+(package! sops
+  :recipe (:type git
+           :host github
+           :repo "djgoku/sops"))

Consider giving Nix/NixOS a try! <3