From e6ed60548397627bf10f561f9438201dbba0a36e Mon Sep 17 00:00:00 2001 From: Azat Bahawi Date: Sun, 21 Apr 2024 02:15:42 +0300 Subject: 2024-04-21 --- modules/emacs/default.nix | 270 +++++++++++++++++++++++++++++++++++++++++ modules/emacs/doom/config.el | 248 +++++++++++++++++++++++++++++++++++++ modules/emacs/doom/init.el | 99 +++++++++++++++ modules/emacs/doom/packages.el | 12 ++ 4 files changed, 629 insertions(+) create mode 100644 modules/emacs/default.nix create mode 100644 modules/emacs/doom/config.el create mode 100644 modules/emacs/doom/init.el create mode 100644 modules/emacs/doom/packages.el (limited to 'modules/emacs') 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")) -- cgit 1.4.1