From f43cc131cac7400309abc640f13b102f85e77dff Mon Sep 17 00:00:00 2001 From: willemml Date: Thu, 6 Apr 2023 10:49:15 -0700 Subject: [PATCH] use emacs-overlay, move emacs config to .el files --- .gitignore | 1 + .../profiles/user/willem/darwin/launchd.nix | 2 +- .../profiles/user/willem/programs/emacs.nix | 903 ------------------ .../user/willem/programs/emacs/default.nix | 121 +++ .../user/willem/programs/emacs/early-init.el | 74 ++ .../user/willem/programs/emacs/init.el | 478 +++++++++ .../profiles/user/willem/programs/firefox.nix | 2 +- home-manager/modules/programs/emacs-init.nix | 584 ----------- 8 files changed, 676 insertions(+), 1489 deletions(-) delete mode 100644 home-manager/modules/profiles/user/willem/programs/emacs.nix create mode 100644 home-manager/modules/profiles/user/willem/programs/emacs/default.nix create mode 100644 home-manager/modules/profiles/user/willem/programs/emacs/early-init.el create mode 100644 home-manager/modules/profiles/user/willem/programs/emacs/init.el delete mode 100644 home-manager/modules/programs/emacs-init.nix diff --git a/.gitignore b/.gitignore index b4dba09..bf7b720 100644 --- a/.gitignore +++ b/.gitignore @@ -2,3 +2,4 @@ .\#* /.direnv /.pre-commit-config.yaml +result diff --git a/home-manager/modules/profiles/user/willem/darwin/launchd.nix b/home-manager/modules/profiles/user/willem/darwin/launchd.nix index f887163..c6a48de 100644 --- a/home-manager/modules/profiles/user/willem/darwin/launchd.nix +++ b/home-manager/modules/profiles/user/willem/darwin/launchd.nix @@ -11,7 +11,7 @@ enable = true; config = { ProgramArguments = [ - "${config.programs.emacs.finalPackage}/bin/emacs" + "${config.programs.emacs.package}/bin/emacs" "--fg-daemon" ]; KeepAlive = true; diff --git a/home-manager/modules/profiles/user/willem/programs/emacs.nix b/home-manager/modules/profiles/user/willem/programs/emacs.nix deleted file mode 100644 index 89456e4..0000000 --- a/home-manager/modules/profiles/user/willem/programs/emacs.nix +++ /dev/null @@ -1,903 +0,0 @@ -{ - config, - pkgs, - ... -}: let - pcfg = config.programs.emacs.init.usePackage; -in { - programs.emacs.enable = true; - - programs.emacs.package = pkgs.emacsGit; - - services.emacs = pkgs.lib.mkIf pkgs.stdenv.isLinux { - enable = true; - client.enable = true; - startWithUserSession = true; - }; - - programs.emacs.init = { - enable = true; - packageQuickstart = true; - recommendedGcSettings = true; - usePackageVerbose = false; - earlyInit = '' - ; -*-emacs-lisp-*- - ;; Disable Toolbar - (tool-bar-mode -1) - - ;; Disable scrollbar - (scroll-bar-mode -1) - - ;; Disable menubar - (menu-bar-mode -1) - - (setq debug-on-error t) - - ;; Use UTF-8 - (set-terminal-coding-system 'utf-8) - (set-keyboard-coding-system 'utf-8) - (prefer-coding-system 'utf-8) - - ;; Minimize native-comp warnings - (setq native-comp-async-report-warnings-errors nil) - (setq warning-minimum-level 'error) - - ;; Disable startup message. - (setq inhibit-startup-screen t - inhibit-startup-echo-area-message (user-login-name)) - - ;; Empty initial scratch buffer. - (setq initial-major-mode 'emacs-lisp-mode - initial-scratch-message nil) - ''; - - prelude = '' - ; -*-emacs-lisp-*- - (setq package-archives '(("melpa" . "https://melpa.org/packages/") - ("melpa-stable" . "https://stable.melpa.org/packages/") - ("gnu" . "https://elpa.gnu.org/packages/") - ("nongnu" . "https://elpa.nongnu.org/nongnu/"))) - - (setenv "PATH" (concat "${config.home.profileDirectory}/bin:" (getenv "PATH"))) - ''; - - postlude = '' - ;-*-emacs-lisp-*- - ;; Accept 'y' and 'n' rather than 'yes' and 'no'. - (defalias 'yes-or-no-p 'y-or-n-p) - - ;; Typically, I only want spaces when pressing the TAB key. I also - ;; want 4 of them. - (setq-default indent-tabs-mode nil - tab-width 4 - c-basic-offset 4) - - ;; Increase emacs data read limit (default too low for LSP) - (setq read-process-output-max (* 1024 1024)) - - ;; Stop creating backup and autosave files. - (setq make-backup-files nil - auto-save-default nil) - - ;; Always show line and column number in the mode line. - (line-number-mode) - (column-number-mode) - - ;; Soft wrap lines - (visual-line-mode) - - ;; Use one space to end sentences. - (setq sentence-end-double-space nil) - - ;; Enable highlighting of current line. - (global-hl-line-mode 1) - - (defun with-buffer-name-prompt-and-make-subdirs () - "Offer to create parent directory when finding file in a non-existent directory." - (let ((parent-directory (file-name-directory buffer-file-name))) - (when (and (not (file-exists-p parent-directory)) - (y-or-n-p (format "Directory `%s' does not exist! Create it? " parent-directory))) - (make-directory parent-directory t)))) - (add-to-list 'find-file-not-found-functions #'with-buffer-name-prompt-and-make-subdirs) - - (global-set-key (kbd "M-n") "~") - (global-set-key (kbd "M-N") "`") - - ;; Keybind to format/prettify document, uses either format-all or - ;; lsp-mode depending on availability - (global-set-key (kbd "C-c C-y") 'my/format-document) - - ;; Don't warn when cannot guess python indent level - (setq-default python-indent-guess-indent-offset-verbose nil) - - ;; Disable scroll + C to zoom - (global-unset-key (kbd "C-")) - (global-unset-key (kbd "C-")) - ''; - - usePackage = { - all-the-icons = { - enable = true; - extraConfig = ":if (display-graphic-p)"; - }; - - all-the-icons-dired = { - enable = true; - hook = ["(dired-mode . all-the-icons-dired-mode)"]; - }; - - calibredb = { - enable = true; - config = '' - ; -*-emacs-lisp-*- - (setq calibredb-root-dir "~/Documents/calibre-library") - (setq calibredb-db-dir (expand-file-name "metadata.db" calibredb-root-dir)) - (setq calibredb-library-alist '(("~/Documents/calibre-library"))) - (setq sql-sqlite-program "${pkgs.sqlite}/bin/sqlite3") - ''; - }; - - cdlatex = { - enable = true; - after = ["latex"]; - hook = ["(LaTeX-mode . turn-on-cdlatex)"]; - }; - - citeproc.enable = true; - - company = { - enable = true; - defines = ["comapny-text-icons-margin"]; - init = '' - ;; Align company-mode tooltips to the right hand side - (setq company-tooltip-align-annotations t) - ;; Display number of completions before and after current suggestions - ;; in company-mode - (setq company-tooltip-offset-display 'lines) - ;; Display text icon of type in company popup - (setq company-format-margin-function #'company-text-icons-margin) - ''; - hook = ["(sh-mode . company-mode)" "(emacs-lisp-mode . company-mode)"]; - }; - - company-math = { - enable = true; - after = ["company"]; - init = '' - ; -*-emacs-lisp-*- - (add-to-list 'company-backends 'company-math-symbols-unicode) - ''; - }; - - counsel = { - enable = true; - bind = { - "M-x" = "counsel-M-x"; - "C-x C-f" = "counsel-find-file"; - " f" = "counsel-describe-function"; - " v" = "counsel-describe-variable"; - " o" = "counsel-describe-symbol"; - " l" = "counsel-find-library"; - " i" = "counsel-info-lookup-symbol"; - " u" = "counsel-unicode-char"; - "C-c g" = "counsel-git"; - "C-c j" = "counsel-git-grep"; - "C-c k" = "counsel-ag"; - "C-x l" = "counsel-locate"; - "C-S-o" = "counsel-rhythmbox"; - }; - bindLocal = { - minibuffer-local-map = {"C-r" = "counsel-minibuffer-history";}; - }; - }; - - doom-modeline = { - enable = true; - hook = ["(after-init . doom-modeline-mode)"]; - config = '' - (setq doom-modeline-icon t) - ''; - }; - - edit-indirect.enable = true; - - edit-server = { - enable = true; - command = ["edit-server-start"]; - config = '' - (setq edit-server-new-frame nil) - ''; - hook = ["(after-init . edit-server-start)"]; - }; - - editorconfig = { - enable = true; - init = '' - (editorconfig-mode 1) - ''; - }; - - async = { - enable = true; - init = '' - (require 'smtpmail-async) - - (setq send-mail-function 'async-smtpmail-send-it - message-send-mail-function 'async-smtpmail-send-it) - ''; - }; - - flycheck = { - enable = true; - hook = ["(after-init . global-flycheck-mode)"]; - config = '' - (setq flycheck-disabled-checkers '(emacs-lisp-checkdoc)) - ''; - }; - - yafolding.enable = true; - - format-all = { - enable = true; - command = ["format-all-buffer"]; - config = '' - (setq-default format-all-formatters format-all-default-formatters) - ''; - }; - - gnuplot = { - enable = true; - init = '' - (require 'gnuplot) - (autoload 'gnuplot-mode "gnuplot" "Gnuplot major mode" t) - (autoload 'gnuplot-make-buffer "gnuplot" "open a buffer in gnuplot-mode" t) - (setq auto-mode-alist (append '(("\\.gp$" . gnuplot-mode)) auto-mode-alist)) - (require 'gnuplot-context) - ''; - }; - - graphviz-dot-mode = { - enable = true; - bindLocal.graphviz-dot-mode-map = { - "C-c C-y" = "graphviz-dot-indent-graph"; - }; - }; - - htmlize.enable = true; - - ivy = { - enable = true; - command = ["ivy-mode"]; - init = '' - (setq ivy-use-virtual-buffers t) - (setq ivy-use-selectable-prompt t) - (setq enable-recursive-minibuffers t) - ''; - bind = {"C-c C-r" = "ivy-resume";}; - hook = ["(after-init . ivy-mode)"]; - }; - - ivy-bibtex = { - enable = true; - after = ["ivy"]; - init = '' - ; -*-emacs-lisp-*- - ;; ivy-bibtex requires ivy's `ivy--regex-ignore-order` regex builder, which - ;; ignores the order of regexp tokens when searching for matching candidates. - (require 'ivy-bibtex) - (setq ivy-re-builders-alist - '((ivy-bibtex . ivy--regex-ignore-order) - (t . ivy--regex-plus))) - (setq ivy-bibtex-bibliography '("~/Documents/org/zotero.bib")) - (setq reftex-default-bibliography '("~/Documents/org/zotero.bib")) - (setq bibtex-completion-pdf-field "file") - ''; - }; - - latex = { - enable = true; - package = epkgs: epkgs.auctex; - hook = [ - '' - (LaTeX-mode - . (lambda () - (turn-on-reftex))) - '' - ]; - init = '' - (setq TeX-PDF-mode t - TeX-auto-save t - TeX-parse-self t) - ''; - }; - - # lsp-ivy = { - # enable = true; - # command = ["lsp-ivy-workspace-symbol"]; - # }; - - # lsp-java = { - # enable = true; - # init = '' - # ; -*-emacs-lisp-*- - # (setq lsp-java-format-settings-url - # "https://raw.githubusercontent.com/google/styleguide/gh-pages/eclipse-java-google-style.xml") - # (setq lsp-java-format-settings-profile - # "GoogleStyle") - # (setq lsp-java-jdt-download-url - # "https://download.eclipse.org/jdtls/milestones/1.16.0/jdt-language-server-1.16.0-202209291445.tar.gz") - # ''; - # hook = ["(java-mode . lsp)"]; - # }; - - # lsp-mode = { - # enable = true; - # after = ["format-all"]; - # command = ["lsp-format-buffer"]; - # extraConfig = '' - # :preface - # (defun my/format-document () - # "Formats the buffer using 'lsp-format-buffer'. - # Falls back to 'format-all-buffer' if LSP does not support formatting." - # (interactive) - # (cond ((fboundp 'lsp-feature?) - # (cond ((lsp-feature? "textDocument/formatting") - # (lsp-format-buffer)) - # ((lsp-feature? "textDocument/rangeFormatting") - # (lsp-format-buffer)) - # (t (format-all-buffer)))) - # (t - # (format-all-buffer)))) - # ''; - # functions = ["lsp-deferred" "lsp-feature" "lsp-register-client"]; - # init = '' - # (setq lsp-log-io nil) - # (setq lsp-keymap-prefix "C-c l") - # ''; - # config = '' - # (lsp-treemacs-sync-mode 1) - # (add-to-list 'lsp-language-id-configuration '(nix-mode . "nix")) - # (lsp-register-client - # (make-lsp-client :new-connection (lsp-stdio-connection '("rnix-lsp")) - # :major-modes '(nix-mode) - # :server-id 'nix)) - # ''; - # hook = [ - # "(lsp-mode . company-mode)" - # "(rust-mode . lsp)" - # "(c-mode . lsp)" - # "(javascript-mode . lsp)" - # "(nix-mode . lsp)" - # ]; - # bind = {"C-c C-y" = "my/format-document";}; - # }; - - # lsp-treemacs = { - # enable = true; - # command = ["lsp-treemacs-errors-lisp"]; - # }; - - # lsp-ui = { - # enable = true; - # command = ["lsp-ui-mode"]; - # }; - - magit = { - enable = true; - }; - - meow = { - enable = true; - init = '' - ; -*-emacs-lisp-*- - (defun meow-setup () - (setq meow-cheatsheet-layout meow-cheatsheet-layout-colemak) - (meow-motion-overwrite-define-key - ;; Use e to move up, n to move down. - ;; Since special modes usually use n to move down, we only overwrite e here. - '("e" . meow-prev) - '("" . ignore)) - (meow-leader-define-key - '("?" . meow-cheatsheet) - ;; To execute the originally e in MOTION state, use SPC e. - '("e" . "H-e") - '("1" . meow-digit-argument) - '("2" . meow-digit-argument) - '("3" . meow-digit-argument) - '("4" . meow-digit-argument) - '("5" . meow-digit-argument) - '("6" . meow-digit-argument) - '("7" . meow-digit-argument) - '("8" . meow-digit-argument) - '("9" . meow-digit-argument) - '("0" . meow-digit-argument)) - (meow-normal-define-key - '("0" . meow-expand-0) - '("1" . meow-expand-1) - '("2" . meow-expand-2) - '("3" . meow-expand-3) - '("4" . meow-expand-4) - '("5" . meow-expand-5) - '("6" . meow-expand-6) - '("7" . meow-expand-7) - '("8" . meow-expand-8) - '("9" . meow-expand-9) - '("-" . negative-argument) - '(";" . meow-reverse) - '("," . meow-inner-of-thing) - '("." . meow-bounds-of-thing) - '("[" . meow-beginning-of-thing) - '("]" . meow-end-of-thing) - '("/" . meow-visit) - '("a" . meow-append) - '("A" . meow-open-below) - '("b" . meow-back-word) - '("B" . meow-back-symbol) - '("c" . meow-change) - '("d" . meow-delete) - '("e" . meow-prev) - '("E" . meow-prev-expand) - '("f" . meow-find) - '("g" . meow-cancel-selection) - '("G" . meow-grab) - '("h" . meow-left) - '("H" . meow-left-expand) - '("i" . meow-right) - '("I" . meow-right-expand) - '("j" . meow-join) - '("k" . meow-kill) - '("l" . meow-line) - '("L" . meow-goto-line) - '("m" . meow-mark-word) - '("M" . meow-mark-symbol) - '("n" . meow-next) - '("N" . meow-next-expand) - '("o" . meow-block) - '("O" . meow-to-block) - '("p" . meow-yank) - '("q" . meow-quit) - '("r" . meow-replace) - '("s" . meow-insert) - '("S" . meow-open-above) - '("t" . meow-till) - '("u" . meow-undo) - '("U" . meow-undo-in-selection) - '("v" . meow-search) - '("w" . meow-next-word) - '("W" . meow-next-symbol) - '("x" . meow-delete) - '("X" . meow-backward-delete) - '("y" . meow-save) - '("z" . meow-pop-selection) - '("'" . repeat) - '("" . ignore))) - (require 'meow) - (meow-setup) - (meow-global-mode 1) - ''; - }; - - mu4e = let - smtpConfig = name: ( - let - account = config.accounts.email.accounts.${name}; - port = builtins.toString account.smtp.port; - host = account.smtp.host; - in '' - ("${name}" - (mu4e-drafts-folder "/${name}/${account.folders.drafts}") - (mu4e-sent-folder "/${name}/${account.folders.sent}") - (mu4e-trash-folder "/${name}/${account.folders.trash}") - ; (mu4e-maildir-shortcuts - ; '( (:maildir "/${name}/${account.folders.inbox}" :key ?i) - ; (:maildir "/${name}/${account.folders.sent}" :key ?s) - ; (:maildir "/${name}/${account.folders.drafts}" :key ?d) - ; (:maildir "/${name}/${account.folders.trash}" :key ?t))) - (smtpmail-default-smtp-server "${host}") - (smtpmail-smtp-server "${host}") - (smtpmail-smtp-service ${port} ) - (smtpmail-smtp-user "${account.userName}") - (user-mail-address "${account.address}")) - '' - ); - smtpAccountStrings = pkgs.lib.forEach (builtins.attrNames config.accounts.email.accounts) (account: " ${(smtpConfig account)} "); - smtpAccounts = "'( ${pkgs.lib.concatStrings smtpAccountStrings} )"; - in { - enable = true; - after = ["async"]; - package = epkgs: pkgs.mu; - demand = true; - extraPackages = [pkgs.gnutls pkgs.mu]; - init = '' - ;-*-emacs-lisp-*- - - (add-to-list 'load-path "${pkgs.mu}/share/emacs/site-lisp/mu4e") - - (require 'mu4e) - - (setq starttls-use-gnutls t - message-kill-buffer-on-exit t - mail-user-agent 'mu4e-user-agent) - - (set-variable 'read-mail-command 'mu4e) - - (defvar my-mu4e-account-alist ${smtpAccounts} ) - - (mapc #'(lambda (var) - (set (car var) (cadr var))) - (cdr (assoc "leitso" my-mu4e-account-alist))) - - (defun my-mu4e-set-account () - "Set the account for composing a message." - (let* ((account - (if mu4e-compose-parent-message - (let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir))) - (string-match "/\\(.*?\\)/" maildir) - (match-string 1 maildir)) - (completing-read (format "Compose with account: (%s) " - (mapconcat #'(lambda (var) (car var)) - my-mu4e-account-alist "/")) - (mapcar #'(lambda (var) (car var)) my-mu4e-account-alist) - nil t nil nil (caar my-mu4e-account-alist)))) - (account-vars (cdr (assoc account my-mu4e-account-alist)))) - (if account-vars - (mapc #'(lambda (var) - (set (car var) (cadr var))) - account-vars) - (error "No email account found")))) - - (setq mu4e-bookmarks - '((:name "Unread messages" :query "flag:unread AND NOT (flag:trashed OR maildir:/feeds)" :key ?u) - (:name "Today's messages" :query "date:today..now AND NOT maildir:/feeds" :key ?t) - (:name "Last 7 days" :query "date:7d..now AND NOT maildir:/feeds" :key ?w) - (:name "Feed" :query "maildir:/feeds" :key ?f) - (:name "XKCD" :query "list:xkcd.localhost" :key ?x))) - - (add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account) - - ''; - - bind = { - "C-c C-u" = "my-mu4e-set-account"; - }; - - hook = ["(mu4e-compose-pre-hook . my-mu4e-set-account)"]; - }; - - nix-mode = { - enable = true; - extraConfig = '' - :mode "\\.nix\\'" - ''; - config = '' - (setq nix-nixfmt-bin "${pkgs.nixfmt}/bin/nixfmt") - (setq nix-executable "/nix/var/nix/profiles/default/bin/nix") - ''; - }; - - nix-update = { - enable = true; - command = ["nix-update-fetch"]; - bindLocal.nix-mode-map."C-c C-u" = "nix-update-fetch"; - }; - - ob-calc = { - enable = true; - after = ["org"]; - }; - - ob-dot = { - enable = true; - after = ["org"]; - }; - - ob-emacs-lisp = { - enable = true; - after = ["org"]; - }; - - ob-gnuplot = { - enable = true; - after = ["org"]; - }; - - ob-matlab = { - enable = true; - after = ["org"]; - init = '' - (setq org-babel-octave-shell-command "${pkgs.octave}/bin/octave -q") - ''; - }; - - ob-python = { - enable = true; - after = ["org"]; - init = '' - ; -*-emacs-lisp-*- - (setq org-babel-python-command "${pkgs.python310}/bin/python3.10") - (setq-default python-indent-guess-indent-offset-verbose nil) - (defun my/org-babel-execute:python-session (body params) - (let ((session-name (cdr (assq :session params)))) - (when (not (eq session-name "none")) - (org-babel-python-initiate-session session-name)))) - (advice-add #'org-babel-execute:python :before #'my/org-babel-execute:python-session) - ''; - }; - - ob-shell = { - enable = true; - after = ["org"]; - }; - - org = { - enable = true; - extraConfig = '' - ; -*-emacs-lisp-*- - :preface - (defun my/indent-org-block-automatically () - "Indent the current org code block." - (interactive) - (when (org-in-src-block-p) - (org-edit-special) - (indent-region (point-min) (point-max)) - (org-edit-src-exit))) - (defun my/org-force-open-current-window () - "Open a link using 'org-open-at-point' in current window." - (interactive) - (let ((org-link-frame-setup - (quote - ((vm . vm-visit-folder) - (vm-imap . vm-visit-imap-folder) - (gnus . gnus) - (file . find-file) - (wl . wl))) - )) - (org-open-at-point))) - (defun my/follow-org-link (arg) - "Follow a link in orgmode If ARG is given. - Opens in new window otherwise opens in current window." - (interactive "P") - (if arg - (org-open-at-point) - (my/org-force-open-current-window))) - (defun krofna-hack () - (when (looking-back (rx "$ ")) - (save-excursion - (backward-char 1) - (org-toggle-latex-fragment)))) - ''; - - init = '' - ; -*-emacs-lisp-*- - (require 'oc) - (require 'oc-basic) - (require 'oc-csl) - (require 'oc-natbib) - (require 'ox-latex) - - (add-hook 'org-mode-hook - (lambda () - (add-hook 'post-self-insert-hook #'krofna-hack 'append 'local))) - - (add-to-list 'exec-path "${config.home.profileDirectory}/bin") - - (add-to-list 'org-latex-classes - '("mla" - "\\documentclass{mla}" - ("\\section{%s}" . "\\section*{%s}") - ("\\subsection{%s}" . "\\subsection*{%s}") - ("\\subsubsection{%s}" . "\\subsubsection*{%s}") - ("\\paragraph{%s}" . "\\paragraph*{%s}") - ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) - (add-to-list 'org-latex-classes - '("letter" - "\\documentclass{letter}" - ("\\section{%s}" . "\\section*{%s}") - ("\\subsection{%s}" . "\\subsection*{%s}") - ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))) - - (plist-put org-format-latex-options :scale 3) - - (setq org-agenda-block-separator ?─) - (setq org-agenda-current-time-string "⭠ now ─────────────────────────────────────────────────") - (setq org-agenda-files '("${config.home.sessionVariables.ORGDIR}" "${config.home.sessionVariables.UBCDIR}")) - (setq org-agenda-tags-column 0) - (setq org-auto-align-tags nil) - (setq org-catch-invisible-edits 'show-and-error) - (setq org-cite-csl-styles-dir "~/Zotero/styles") - (setq org-cite-export-processors '((t basic))) - (setq org-cite-global-bibliography '("${config.home.sessionVariables.ORGDIR}/zotero.bib")) - (setq org-confirm-babel-evaluate nil) - (setq org-ellipsis "…") - (setq org-export-with-tags nil) - (setq org-hide-emphasis-markers t) - (setq org-highlight-latex-and-related '(latex)) - (setq org-html-head "") - (setq org-html-head-include-default-style nil) - (setq org-html-head-include-scripts nil) - (setq org-html-validation-link nil) - (setq org-image-actual-width 300) - (setq org-insert-heading-respect-content t) - (setq org-latex-pdf-process '("latexmk -pdflatex='pdflatex -interaction nonstopmode' -pdf -bibtex -f %f")) - (setq org-pretty-entities t) - (setq org-preview-latex-default-process 'dvisvgm) - (setq org-special-ctrl-a/e t) - (setq org-src-fontify-natively t) - (setq org-src-preserve-indentation t) - (setq org-src-tab-acts-natively t) - (setq org-src-window-setup 'current-window) - (setq org-tags-column 0) - - (setq org-agenda-time-grid - '((daily today require-timed) - (800 1000 1200 1400 1600 1800 2000) - " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")) - - (setq org-publish-project-alist - '(("html" - :base-directory "${config.home.sessionVariables.ORGDIR}" - :base-extension "org" - :htmlized-source t - :recursive t - :publishing-directory "${config.home.sessionVariables.ORGDIR}/exports" - :publishing-function org-html-publish-to-html) - ("pdf" - :base-directory "${config.home.sessionVariables.ORGDIR}" - :base-extension "org" - :recursive t - :publishing-directory "${config.home.sessionVariables.ORGDIR}/exports" - :publishing-function org-latex-publish-to-pdf) - ("all" :components ("html" "pdf")) - )) - - ''; - hook = [ - "(org-babel-after-execute . org-redisplay-inline-images)" - "(org-mode . visual-line-mode)" - "(org-mode . org-cdlatex-mode)" - ]; - bind = { - "C-c n c" = "org-id-get-create"; - "C-c n a" = "org-agenda"; - }; - bindLocal.org-mode-map = { - "C-c C-o" = "my/follow-org-link"; - "C-c C-y" = "my/indent-org-block-automatically"; - - "C-c ]" = "org-cite-insert"; - }; - }; - - org-auctex = { - enable = true; - package = epkgs: - epkgs.trivialBuild { - pname = "org-auctex"; - version = "e1271557b9f36ca94cabcbac816748e7d0dc989c"; - - packageRequires = [epkgs.auctex]; - - src = pkgs.fetchFromGitHub { - owner = "karthink"; - repo = "org-auctex"; - rev = "e1271557b9f36ca94cabcbac816748e7d0dc989c"; - sha256 = "sha256-cMAhwybnq5HA1wOaUqDPML3nnh5m1iwEETTPWqPbAvw="; - }; - }; - hook = ["(org-mode . org-auctex-mode)"]; - }; - - org-contrib.enable = true; - - org-download = { - enable = true; - after = ["org"]; - init = '' - (require 'org-download) - (setq-default org-download-image-dir "${config.home.sessionVariables.ORGDIR}/images") - ''; - hook = ["(dired-mode . org-download-enable)"]; - }; - - org-modern = { - enable = true; - after = ["org"]; - hook = ["(org-mode . org-modern-mode)"]; - }; - - pdf-tools = { - enable = true; - init = '' - ; -*-emacs-lisp-*- - (setq-default pdf-view-display-size 'fit-width) - (setq pdf-annot-activate-created-annotations t) - ''; - }; - - # - plantuml-mode = { - enable = true; - init = '' - (setq plantuml-executable-path "${pkgs.plantuml}/bin/plantuml") - (setq plantuml-default-exec-mode 'executable) - ''; - }; - # - - rust-mode = { - enable = true; - bindLocal.rust-mode-map = { - "C-c C-y" = "lsp-format-buffer"; - "C-c C-c" = "rust-run-clippy"; - "C-c C-r" = "rust-run"; - "C-c C-t" = "rust-test"; - "C-c C-o" = "rust-compile"; - }; - }; - - separedit = { - enable = true; - bind = {"C-c '" = "separedit";}; - hook = ["(separedit-buffer-creation . normal-mode)"]; - init = '' - ; -*-emacs-lisp-*- - (setq separedit-preserve-string-indentation t) - ''; - }; - - solarized-theme = { - enable = true; - init = "(load-theme 'solarized-gruvbox-dark t)"; - }; - - swiper = { - enable = true; - bind = {"C-s" = "swiper";}; - }; - - # tree-sitter = { - # enable = true; - # package = epkgs: epkgs.tsc; - # init = '' - # (setq tree-sitter-major-mode-language-alist '((arduino-mode . c))) - # ''; - # hook = [ - # "(rust-mode . tree-sitter-hl-mode)" - # "(python-mode . tree-sitter-hl-mode)" - # "(c-mode . tree-sitter-hl-mode)" - # "(shell-mode . tree-sitter-hl-mode)" - # "(javascript-mode . tree-sitter-hl-mode)" - # ]; - # }; - - # tree-sitter-langs = { - # enable = true; - # package = epkgs: epkgs.tree-sitter-langs; - # }; - - # yasnippet = { - # enable = true; - # init = '' - # (setq yas-snippet-dirs '("${config.home.sessionVariables.ORGDIR}/snippets")) - # (yas-global-mode 1) - # ''; - # }; - - # yasnippet-snippets = { - # enable = true; - # init = '' - # (yas-reload-all) - # ''; - # }; - - arduino-mode = { - enable = true; - hook = ["(arduino-mode . flycheck-arduino-setup)"]; - init = '' - (require 'flycheck-arduino) - (setq arduino-executable "/Applications/Arduino.app/Contents/MacOS/Arduino") - ''; - }; - }; - }; -} diff --git a/home-manager/modules/profiles/user/willem/programs/emacs/default.nix b/home-manager/modules/profiles/user/willem/programs/emacs/default.nix new file mode 100644 index 0000000..821cf90 --- /dev/null +++ b/home-manager/modules/profiles/user/willem/programs/emacs/default.nix @@ -0,0 +1,121 @@ +{ + config, + pkgs, + ... +}: let + emacsConfig = pkgs.emacsWithPackagesFromUsePackage { + config = ./init.el; + + defaultInitFile = true; + + package = + (pkgs.emacsPackagesFor pkgs.emacsGit).emacsWithPackages + (epkgs: + (with epkgs; let + org-auctex = epkgs.trivialBuild { + pname = "org-auctex"; + version = "e1271557b9f36ca94cabcbac816748e7d0dc989c"; + + buildInputs = [epkgs.auctex]; + + src = pkgs.fetchFromGitHub { + owner = "karthink"; + repo = "org-auctex"; + rev = "e1271557b9f36ca94cabcbac816748e7d0dc989c"; + sha256 = "sha256-cMAhwybnq5HA1wOaUqDPML3nnh5m1iwEETTPWqPbAvw="; + }; + }; + mu4e-accounts = epkgs.trivialBuild { + pname = "mu4e-accounts"; + version = "0.1"; + buildInputs = [pkgs.mu]; + src = let + smtpConfig = name: ( + let + account = config.accounts.email.accounts.${name}; + port = builtins.toString account.smtp.port; + host = account.smtp.host; + in '' + ("${name}" + (mu4e-drafts-folder "/${name}/${account.folders.drafts}") + (mu4e-sent-folder "/${name}/${account.folders.sent}") + (mu4e-trash-folder "/${name}/${account.folders.trash}") + ; (mu4e-maildir-shortcuts + ; '( (:maildir "/${name}/${account.folders.inbox}" :key ?i) + ; (:maildir "/${name}/${account.folders.sent}" :key ?s) + ; (:maildir "/${name}/${account.folders.drafts}" :key ?d) + ; (:maildir "/${name}/${account.folders.trash}" :key ?t))) + (smtpmail-default-smtp-server "${host}") + (smtpmail-smtp-server "${host}") + (smtpmail-smtp-service ${port} ) + (smtpmail-smtp-user "${account.userName}") + (user-mail-address "${account.address}")) + '' + ); + smtpAccountStrings = pkgs.lib.forEach (builtins.attrNames config.accounts.email.accounts) (account: " ${(smtpConfig account)} "); + smtpAccounts = "'( ${pkgs.lib.concatStrings smtpAccountStrings} )"; + in + pkgs.writeText "mu4e-accounts.el" '' + (defvar my-mu4e-account-alist ${smtpAccounts} ) + (provide 'mu4e-accounts) + ''; + }; + in [ + all-the-icons + all-the-icons-dired + arduino-mode + async + auctex + calibredb + cdlatex + citeproc + company + company-quickhelp + counsel + editorconfig + edit-indirect + format-all + gnuplot + graphviz-dot-mode + htmlize + ivy + ivy-bibtex + magit + meow + mu4e-accounts + nix-mode + nix-update + org + org-auctex + org-contrib + org-download + org-modern + pdf-tools + plantuml-mode + rustic + separedit + solarized-theme + swiper + yasnippet + ]) + ++ (with pkgs; [ + gnuplot + mu + plantuml + sqlite + ])); + }; +in { + home.file.".emacs.d/early-init.el".source = ./early-init.el; + home.file.".emacs.d/init.el".source = ./init.el; + + programs.emacs.enable = true; + + programs.emacs.package = emacsConfig; + + services.emacs = pkgs.lib.mkIf pkgs.stdenv.isLinux { + enable = true; + client.enable = true; + startWithUserSession = true; + }; +} diff --git a/home-manager/modules/profiles/user/willem/programs/emacs/early-init.el b/home-manager/modules/profiles/user/willem/programs/emacs/early-init.el new file mode 100644 index 0000000..08e7c66 --- /dev/null +++ b/home-manager/modules/profiles/user/willem/programs/emacs/early-init.el @@ -0,0 +1,74 @@ +;;; early-init.el -- willemm's Emacs configuration (early-init). +;; +;;; Commentary: +;; +;; The early-init part of my Emacs configuration. +;; Originally generated by home-manager. +;; +;;; Code: + +(defun hm/reduce-gc () + "Reduce the frequency of garbage collection." + (setq gc-cons-threshold most-positive-fixnum + gc-cons-percentage 0.6)) + +(defun hm/restore-gc () + "Restore the frequency of garbage collection." + (setq gc-cons-threshold 16777216 + gc-cons-percentage 0.1)) + +;; Make GC more rare during init, while minibuffer is active, and +;; when shutting down. In the latter two cases we try doing the +;; reduction early in the hook. +(hm/reduce-gc) +(add-hook 'minibuffer-setup-hook #'hm/reduce-gc -50) +(add-hook 'kill-emacs-hook #'hm/reduce-gc -50) + +;; But make it more regular after startup and after closing minibuffer. +(add-hook 'emacs-startup-hook #'hm/restore-gc) +(add-hook 'minibuffer-exit-hook #'hm/restore-gc) + +;; Avoid unnecessary regexp matching while loading .el files. +(defvar hm/file-name-handler-alist file-name-handler-alist) +(setq file-name-handler-alist nil) + +(defun hm/restore-file-name-handler-alist () + "Restore the `file-name-handler-alist` variable." + (setq file-name-handler-alist hm/file-name-handler-alist) + (makunbound 'hm/file-name-handler-alist)) + +(add-hook 'emacs-startup-hook #'hm/restore-file-name-handler-alist) + +;; Avoid expensive frame resizing. Inspired by Doom Emacs. +(setq frame-inhibit-implied-resize t) + +;; Disable Toolbar +(tool-bar-mode -1) + +;; Disable scrollbar +(scroll-bar-mode -1) + +;; Disable menubar +(menu-bar-mode -1) + +(setq debug-on-error t) + +;; Use UTF-8 +(set-terminal-coding-system 'utf-8) +(set-keyboard-coding-system 'utf-8) +(prefer-coding-system 'utf-8) + +;; Minimize native-comp warnings +(defvar native-comp-async-report-warnings-errors nil) +(defvar warning-minimum-level 'error) + +;; Disable startup message. +(setq inhibit-startup-screen t + inhibit-startup-echo-area-message (user-login-name)) + +;; Empty initial scratch buffer. +(setq initial-major-mode 'emacs-lisp-mode + initial-scratch-message nil) + +(provide 'early-init) +;;; early-init.el ends here diff --git a/home-manager/modules/profiles/user/willem/programs/emacs/init.el b/home-manager/modules/profiles/user/willem/programs/emacs/init.el new file mode 100644 index 0000000..440678f --- /dev/null +++ b/home-manager/modules/profiles/user/willem/programs/emacs/init.el @@ -0,0 +1,478 @@ +;;; init.el -- willemm's Emacs configuration. +;; +;;; Commentary: +;; +;; My Emacs configuration, uses nix-community's emacs-overlay for package installation. +;; Originally generated by home-manager, taken apart and reassembled by me. +;; +;;; Code: + +(setenv "PATH" (concat "/Users/willem/.nix-profile/bin:" (getenv "PATH"))) +(add-to-list 'exec-path "/Users/willem/.nix-profile/bin") + +(setq inhibit-default-init t) + +;; Accept 'y' and 'n' rather than 'yes' and 'no'. +(defalias 'yes-or-no-p 'y-or-n-p) + +;; Typically, I only want spaces when pressing the TAB key. I also +;; want 4 of them. +(setq-default indent-tabs-mode nil + tab-width 4 + c-basic-offset 4) + +;; Increase emacs data read limit (default too low for LSP) +(setq read-process-output-max (* 1024 1024)) + +;; Stop creating backup and autosave files. +(setq make-backup-files nil + auto-save-default nil) + +;; Always show line and column number in the mode line. +(line-number-mode) +(column-number-mode) + +;; Soft wrap lines +(visual-line-mode) + +;; Use one space to end sentences. +(setq sentence-end-double-space nil) + +;; Enable highlighting of current line. +(global-hl-line-mode 1) + +(defun with-buffer-name-prompt-and-make-subdirs () + "Offer to create parent directory when finding file in a non-existent directory." + (let ((parent-directory (file-name-directory buffer-file-name))) + (when (and (not (file-exists-p parent-directory)) + (y-or-n-p (format "Directory `%s' does not exist! Create it? " parent-directory))) + (make-directory parent-directory t)))) +(add-to-list 'find-file-not-found-functions #'with-buffer-name-prompt-and-make-subdirs) + +(global-set-key (kbd "M-n") "~") +(global-set-key (kbd "M-N") "`") + +;; Don't warn when cannot guess python indent level +(setq-default python-indent-guess-indent-offset-verbose nil) + +;; Disable scroll + C to zoom +(global-unset-key (kbd "C-")) +(global-unset-key (kbd "C-")) + +(require 'arduino-mode) +(require 'async) +(require 'calibredb) +(require 'cdlatex) +(require 'citeproc) +(require 'company) +(require 'company-quickhelp) +(require 'counsel) +(require 'edit-indirect) +(require 'editorconfig) +(require 'eglot) +(require 'format-all) +(require 'gnuplot) +(require 'gnuplot-context) +(require 'graphviz-dot-mode) +(require 'htmlize) +(require 'ivy) +(require 'ivy-bibtex) +(require 'magit) +(require 'meow) +(require 'mu4e) +(require 'mu4e-accounts) +(require 'nix-mode) +(require 'nix-update) +(require 'ob-dot) +(require 'ob-emacs-lisp) +(require 'ob-gnuplot) +(require 'ob-matlab) +(require 'ob-python) +(require 'ob-shell) +(require 'oc) +(require 'oc-basic) +(require 'oc-csl) +(require 'oc-natbib) +(require 'org) +(require 'org-auctex) +(require 'org-contrib) +(require 'org-download) +(require 'org-modern) +(require 'ox-latex) +(require 'pdf-tools) +(require 'plantuml-mode) +(require 'rustic) +(require 'smtpmail-async) +(require 'swiper) +(require 'tex) +(require 'yasnippet) + +(setq org-directory (expand-file-name "~/Documents/org")) + +(when (display-graphic-p) + (require 'all-the-icons) + (require 'all-the-icons-dired) + (add-hook 'dired-mode-hook 'all-the-icons-dired-mode)) + +(setq arduino-executable "/Applications/Arduino.app/Contents/MacOS/Arduino") + +(setq send-mail-function 'async-smtpmail-send-it + message-send-mail-function 'async-smtpmail-send-it) + +(setq calibredb-root-dir "~/Documents/calibre-library") +(setq calibredb-db-dir (expand-file-name "metadata.db" calibredb-root-dir)) +(setq calibredb-library-alist '(("~/Documents/calibre-library"))) + +;; TODO: temporary fix for company-mode#1381 +(delete 'company-files company-backends) + +(add-hook 'after-init-hook 'global-company-mode) + +;; Align company-mode tooltips to the right hand side +(setq company-tooltip-align-annotations t) +;; Display number of completions before and after current suggestions +;; in company-mode +(setq company-tooltip-offset-display 'lines) +;; Display text icon of type in company popup + +(company-quickhelp-mode) + +(global-set-key "\C-s" 'swiper) +(global-set-key (kbd "C-c C-r") 'ivy-resume) +(global-set-key (kbd "") 'ivy-resume) +(global-set-key (kbd "M-x") 'counsel-M-x) +(global-set-key (kbd "C-x C-f") 'counsel-find-file) +(global-set-key (kbd " f") 'counsel-describe-function) +(global-set-key (kbd " v") 'counsel-describe-variable) +(global-set-key (kbd " o") 'counsel-describe-symbol) +(global-set-key (kbd " l") 'counsel-find-library) +(global-set-key (kbd " i") 'counsel-info-lookup-symbol) +(global-set-key (kbd " u") 'counsel-unicode-char) +(global-set-key (kbd "C-c g") 'counsel-git) +(global-set-key (kbd "C-c j") 'counsel-git-grep) +(global-set-key (kbd "C-c k") 'counsel-ag) +(global-set-key (kbd "C-x l") 'counsel-locate) +(global-set-key (kbd "C-S-o") 'counsel-rhythmbox) +(define-key minibuffer-local-map (kbd "C-r") 'counsel-minibuffer-history) + +(editorconfig-mode 1) + +(add-hook 'eglot-connect-hook 'company-mode) + +(global-set-key (kbd "C-c C-y") 'format-all-buffer) +(setq-default format-all-formatters format-all-default-formatters) + +(autoload 'gnuplot-mode "gnuplot" "Gnuplot major mode" t) +(autoload 'gnuplot-make-buffer "gnuplot" "open a buffer in gnuplot-mode" t) +(setq auto-mode-alist (append '(("\\.gp$" . gnuplot-mode)) auto-mode-alist)) + +(define-key graphviz-dot-mode-map (kbd "C-c C-y") 'graphviz-dot-indent-graph) + +(global-set-key (kbd "C-c C-r") 'ivy-resume) +(add-hook 'after-init-hook 'ivy-mode) + +(setq ivy-use-virtual-buffers t) +(setq ivy-use-selectable-prompt t) +(setq enable-recursive-minibuffers t) + +;; ivy-bibtex requires ivy's `ivy--regex-ignore-order` regex builder, which +;; ignores the order of regexp tokens when searching for matching candidates. +(setq ivy-re-builders-alist + '((ivy-bibtex . ivy--regex-ignore-order) + (t . ivy--regex-plus))) +(defvar ivy-bibtex-bibliography '((expand-file-name "zotero.bib" org-directory))) +(setq reftex-default-bibliography '((expand-file-name "zotero.bib" org-directory))) +(setq bibtex-completion-pdf-field "file") + +(add-hook 'LaTeX-mode-hook 'turn-on-cdlatex) +(add-hook 'LaTeX-mode (lambda () + (turn-on-reftex))) +(setq TeX-PDF-mode t + TeX-auto-save t + TeX-parse-self t) + + + +(defun meow-setup () + "Initialize meow-edit for colemak." + (setq meow-cheatsheet-layout meow-cheatsheet-layout-colemak) + (meow-motion-overwrite-define-key + ;; Use e to move up, n to move down. + ;; Since special modes usually use n to move down, we only overwrite e here. + '("e" . meow-prev) + '("" . ignore)) + (meow-leader-define-key + '("?" . meow-cheatsheet) + ;; To execute the originally e in MOTION state, use SPC e. + '("e" . "H-e") + '("1" . meow-digit-argument) + '("2" . meow-digit-argument) + '("3" . meow-digit-argument) + '("4" . meow-digit-argument) + '("5" . meow-digit-argument) + '("6" . meow-digit-argument) + '("7" . meow-digit-argument) + '("8" . meow-digit-argument) + '("9" . meow-digit-argument) + '("0" . meow-digit-argument)) + (meow-normal-define-key + '("0" . meow-expand-0) + '("1" . meow-expand-1) + '("2" . meow-expand-2) + '("3" . meow-expand-3) + '("4" . meow-expand-4) + '("5" . meow-expand-5) + '("6" . meow-expand-6) + '("7" . meow-expand-7) + '("8" . meow-expand-8) + '("9" . meow-expand-9) + '("-" . negative-argument) + '(";" . meow-reverse) + '("," . meow-inner-of-thing) + '("." . meow-bounds-of-thing) + '("[" . meow-beginning-of-thing) + '("]" . meow-end-of-thing) + '("/" . meow-visit) + '("a" . meow-append) + '("A" . meow-open-below) + '("b" . meow-back-word) + '("B" . meow-back-symbol) + '("c" . meow-change) + '("d" . meow-delete) + '("e" . meow-prev) + '("E" . meow-prev-expand) + '("f" . meow-find) + '("g" . meow-cancel-selection) + '("G" . meow-grab) + '("h" . meow-left) + '("H" . meow-left-expand) + '("i" . meow-right) + '("I" . meow-right-expand) + '("j" . meow-join) + '("k" . meow-kill) + '("l" . meow-line) + '("L" . meow-goto-line) + '("m" . meow-mark-word) + '("M" . meow-mark-symbol) + '("n" . meow-next) + '("N" . meow-next-expand) + '("o" . meow-block) + '("O" . meow-to-block) + '("p" . meow-yank) + '("q" . meow-quit) + '("r" . meow-replace) + '("s" . meow-insert) + '("S" . meow-open-above) + '("t" . meow-till) + '("u" . meow-undo) + '("U" . meow-undo-in-selection) + '("v" . meow-search) + '("w" . meow-next-word) + '("W" . meow-next-symbol) + '("x" . meow-delete) + '("X" . meow-backward-delete) + '("y" . meow-save) + '("z" . meow-pop-selection) + '("'" . repeat) + '("" . ignore))) + +(meow-setup) +(meow-global-mode 1) + +(define-key mu4e-main-mode-map (kbd "C-c C-u") 'my-mu4e-set-account) +(add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account) + +(defvar starttls-use-gnutls t) +(setq message-kill-buffer-on-exit t + mail-user-agent 'mu4e-user-agent) + +(set-variable 'read-mail-command 'mu4e) + +(mapc #'(lambda (var) + (set (car var) (cadr var))) + (cdr (assoc "leitso" my-mu4e-account-alist))) + +(defun my-mu4e-set-account () + "Set the account for composing a message." + (let* ((account + (if mu4e-compose-parent-message + (let ((maildir (mu4e-message-field mu4e-compose-parent-message :maildir))) + (string-match "/\\(.*?\\)/" maildir) + (match-string 1 maildir)) + (completing-read (format "Compose with account: (%s) " + (mapconcat #'(lambda (var) (car var)) + my-mu4e-account-alist "/")) + (mapcar #'(lambda (var) (car var)) my-mu4e-account-alist) + nil t nil nil (caar my-mu4e-account-alist)))) + (account-vars (cdr (assoc account my-mu4e-account-alist)))) + (if account-vars + (mapc #'(lambda (var) + (set (car var) (cadr var))) + account-vars) + (error "No email account found")))) + +(setq mu4e-bookmarks + '((:name "Unread messages" :query "flag:unread AND NOT (flag:trashed OR maildir:/feeds)" :key ?u) + (:name "Today's messages" :query "date:today..now AND NOT maildir:/feeds" :key ?t) + (:name "Last 7 days" :query "date:7d..now AND NOT maildir:/feeds" :key ?w) + (:name "Feed" :query "maildir:/feeds" :key ?f) + (:name "XKCD" :query "list:xkcd.localhost" :key ?x))) + +(add-hook 'mu4e-compose-pre-hook 'my-mu4e-set-account) + +(add-to-list 'auto-mode-alist '("\\.nix\\'" . nix-mode)) + +(define-key nix-mode-map (kbd "C-c C-u") 'nix-update-fetch) + +(setq org-babel-octave-shell-command "octave -q") + +(setq org-babel-python-command "python3.10") +(setq-default python-indent-guess-indent-offset-verbose nil) +(defun my/org-babel-execute:python-session (body params) + "Initiate a python session before executing org babel blocks that use sessions. +BODY is the content of the org-babel block and PARAMS are any parameters specified." + (let ((session-name (cdr (assq :session params)))) + (when (not (eq session-name "none")) + (org-babel-python-initiate-session session-name)))) +(advice-add #'org-babel-execute:python :before #'my/org-babel-execute:python-session) + +(defun my/indent-org-block-automatically () + "Indent the current org code block." + (interactive) + (when (org-in-src-block-p) + (org-edit-special) + (indent-region (point-min) (point-max)) + (org-edit-src-exit))) +(defun my/org-force-open-current-window () + "Open a link using 'org-open-at-point' in current window." + (interactive) + (let ((org-link-frame-setup + (quote + ((vm . vm-visit-folder) + (vm-imap . vm-visit-imap-folder) + (gnus . gnus) + (file . find-file) + (wl . wl))) + )) + (org-open-at-point))) +(defun my/follow-org-link (arg) + "Follow a link in orgmode If ARG is given. +Opens in new window otherwise opens in current window." + (interactive "P") + (if arg + (org-open-at-point) + (my/org-force-open-current-window))) +(defun krofna-hack () + "Toggle latex fragments after exiting closing them." + (when (looking-back (rx "$ ")) + (save-excursion + (backward-char 1) + (org-latex-preview)))) + + +(global-set-key (kbd "C-c n a") 'org-agenda) + +(define-key org-mode-map (kbd "C-c C-o") 'my/follow-org-link) +(define-key org-mode-map (kbd "C-c C-y") 'my/indent-org-block-automatically) +(define-key org-mode-map (kbd "C-c ]") 'org-cite-insert) + +(add-hook 'org-babel-after-execute-hook 'org-redisplay-inline-images) +(add-hook 'org-mode-hook 'visual-line-mode) +(add-hook 'org-mode-hook 'org-cdlatex-mode) +(add-hook 'org-mode-hook + (lambda () + (add-hook 'post-self-insert-hook #'krofna-hack 'append 'local))) + +(add-to-list 'org-latex-classes + '("mla" + "\\documentclass{mla}" + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}") + ("\\paragraph{%s}" . "\\paragraph*{%s}") + ("\\subparagraph{%s}" . "\\subparagraph*{%s}"))) +(add-to-list 'org-latex-classes + '("letter" + "\\documentclass{letter}" + ("\\section{%s}" . "\\section*{%s}") + ("\\subsection{%s}" . "\\subsection*{%s}") + ("\\subsubsection{%s}" . "\\subsubsection*{%s}"))) + +(plist-put org-format-latex-options :scale 3) + +(setq org-agenda-files '(org-directory (expand-file-name "ubc" org-directory))) +(setq org-agenda-tags-column 0) +(setq org-auto-align-tags nil) +(setq org-fold-catch-invisible-edits 'show-and-error) +(setq org-cite-csl-styles-dir "~/Zotero/styles") +(setq org-cite-export-processors '((t basic))) +(setq org-cite-global-bibliography '((expand-file-name "zotero.bib" org-directory))) +(setq org-confirm-babel-evaluate nil) +(setq org-ellipsis "…") +(setq org-export-with-tags nil) +(setq org-hide-emphasis-markers t) +(setq org-highlight-latex-and-related '(latex)) +(setq org-html-head "") +(setq org-html-head-include-default-style nil) +(setq org-html-head-include-scripts nil) +(setq org-html-validation-link nil) +(setq org-image-actual-width 300) +(setq org-insert-heading-respect-content t) +(setq org-latex-pdf-process '("latexmk -pdflatex='pdflatex -interaction nonstopmode' -pdf -bibtex -f %f")) +(setq org-pretty-entities t) +(setq org-preview-latex-default-process 'dvisvgm) +(setq org-special-ctrl-a/e t) +(setq org-src-fontify-natively t) +(setq org-src-preserve-indentation t) +(setq org-src-tab-acts-natively t) +(setq org-src-window-setup 'current-window) +(setq org-tags-column 0) + +(setq org-agenda-time-grid + '((daily today require-timed) + (800 1000 1200 1400 1600 1800 2000) + " ┄┄┄┄┄ " "┄┄┄┄┄┄┄┄┄┄┄┄┄┄┄")) + +(setq org-publish-project-alist + '(("html" + :base-directory org-directory + :base-extension "org" + :htmlized-source t + :recursive t + :publishing-directory (expand-file-name "exports" org-directory) + :publishing-function org-html-publish-to-html) + ("pdf" + :base-directory org-directory + :base-extension "org" + :recursive t + :publishing-directory (expand-file-name "exports" org-directory) + :publishing-function org-latex-publish-to-pdf) + ("all" :components ("html" "pdf")))) + +(add-hook 'org-mode-hook 'org-auctex-mode) + +(add-hook 'dired-mode-hook 'org-download-enable) +(setq-default org-download-image-dir (expand-file-name "images" org-directory)) + +(add-hook 'org-mode-hook 'org-modern-mode) + +(setq-default pdf-view-display-size 'fit-width) +(defvar pdf-annot-activate-created-annotations t) + +(setq plantuml-default-exec-mode 'executable) + +(define-key rustic-mode-map (kbd "C-c C-y") 'eglot-format-buffer) +(setq rustic-lsp-client 'eglot) + +(defvar separedit-preserve-string-indentation t) +(global-set-key (kbd "C-c '") 'separedit) +(add-hook 'separedit-buffer-creation-hook 'normal-mode) + +(load-theme 'solarized-gruvbox-dark t) + +(global-set-key (kbd "C-s") 'swiper) + +(setq yas-snippet-dirs '((expand-file-name "snippets" org-directory))) + +(provide 'init) +;;; init.el ends here diff --git a/home-manager/modules/profiles/user/willem/programs/firefox.nix b/home-manager/modules/profiles/user/willem/programs/firefox.nix index b1ea5b2..72954d7 100644 --- a/home-manager/modules/profiles/user/willem/programs/firefox.nix +++ b/home-manager/modules/profiles/user/willem/programs/firefox.nix @@ -86,7 +86,7 @@ clearurls don-t-fuck-with-paste #dracula-dark-colorscheme - edit-with-emacs + #edit-with-emacs #fastforward i-dont-care-about-cookies musescore-downloader diff --git a/home-manager/modules/programs/emacs-init.nix b/home-manager/modules/programs/emacs-init.nix deleted file mode 100644 index c0d4424..0000000 --- a/home-manager/modules/programs/emacs-init.nix +++ /dev/null @@ -1,584 +0,0 @@ -# MIT License -# Copyright (c) 2019 Robert Helgesson -# Permission is hereby granted, free of charge, to any person obtaining a copy -# of this software and associated documentation files (the "Software"), to deal -# in the Software without restriction, including without limitation the rights -# to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -# copies of the Software, and to permit persons to whom the Software is -# furnished to do so, subject to the following conditions: -# The above copyright notice and this permission notice shall be included in all -# copies or substantial portions of the Software. -# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -# SOFTWARE. -{ - config, - lib, - pkgs, - ... -}: -with lib; let - cfg = config.programs.emacs.init; - - packageFunctionType = mkOptionType { - name = "packageFunction"; - description = "function from epkgs to package"; - check = isFunction; - merge = mergeOneOption; - }; - - usePackageType = types.submodule ({ - name, - config, - ... - }: { - options = { - enable = mkEnableOption "Emacs package ${name}"; - - package = mkOption { - type = - types.either (types.str // {description = "name of package";}) - packageFunctionType; - default = name; - description = '' - The package to use for this module. Either the package name - within the Emacs package set or a function taking the Emacs - package set and returning a package. - ''; - }; - - defer = mkOption { - type = types.either types.bool types.ints.positive; - default = false; - description = '' - The setting. - ''; - }; - - defines = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The entries to use for . - ''; - }; - - demand = mkOption { - type = types.bool; - default = false; - description = '' - The setting. - ''; - }; - - diminish = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The entries to use for . - ''; - }; - - chords = mkOption { - type = types.attrsOf types.str; - default = {}; - example = { - "jj" = "ace-jump-char-mode"; - "jk" = "ace-jump-word-mode"; - }; - description = '' - The entries to use for . - ''; - }; - - functions = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The entries to use for . - ''; - }; - - mode = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The entries to use for . - ''; - }; - - after = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The entries to use for . - ''; - }; - - bind = mkOption { - type = types.attrsOf types.str; - default = {}; - example = { - "M-" = "drag-stuff-up"; - "M-" = "drag-stuff-down"; - }; - description = '' - The entries to use for . - ''; - }; - - bindLocal = mkOption { - type = types.attrsOf (types.attrsOf types.str); - default = {}; - example = { - helm-command-map = {"C-c h" = "helm-execute-persistent-action";}; - }; - description = '' - The entries to use for local keymaps in . - ''; - }; - - bindKeyMap = mkOption { - type = types.attrsOf types.str; - default = {}; - example = {"C-c p" = "projectile-command-map";}; - description = '' - The entries to use for . - ''; - }; - - command = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The entries to use for . - ''; - }; - - config = mkOption { - type = types.lines; - default = ""; - description = '' - Code to place in the section. - ''; - }; - - extraConfig = mkOption { - type = types.lines; - default = ""; - description = '' - Additional lines to place in the use-package configuration. - ''; - }; - - hook = mkOption { - type = types.listOf types.str; - default = []; - description = '' - The entries to use for . - ''; - }; - - earlyInit = mkOption { - type = types.lines; - default = ""; - description = '' - Lines to add to when - this package is enabled. - - Note, the package is not automatically loaded so you will have to - require the necessary features yourself. - ''; - }; - - init = mkOption { - type = types.lines; - default = ""; - description = '' - The entries to use for . - ''; - }; - - extraPackages = mkOption { - type = types.listOf types.package; - default = []; - description = '' - Extra packages to add to . - ''; - }; - - assembly = mkOption { - type = types.lines; - readOnly = true; - internal = true; - description = "The final use-package code."; - }; - }; - - config = mkIf config.enable { - assembly = let - quoted = v: ''"${escape [''"''] v}"''; - mkBindHelper = cmd: prefix: bs: - optionals (bs != {}) ([":${cmd} (${prefix}"] - ++ mapAttrsToList (n: v: " (${quoted n} . ${v})") bs - ++ [")"]); - - mkAfter = vs: optional (vs != []) ":after (${toString vs})"; - mkCommand = vs: optional (vs != []) ":commands (${toString vs})"; - mkDefines = vs: optional (vs != []) ":defines (${toString vs})"; - mkDiminish = vs: optional (vs != []) ":diminish (${toString vs})"; - mkMode = map (v: ":mode ${v}"); - mkFunctions = vs: optional (vs != []) ":functions (${toString vs})"; - mkBind = mkBindHelper "bind" ""; - mkBindLocal = bs: let - mkMap = n: v: mkBindHelper "bind" ":map ${n}" v; - in - flatten (mapAttrsToList mkMap bs); - mkBindKeyMap = mkBindHelper "bind-keymap" ""; - mkChords = mkBindHelper "chords" ""; - mkHook = map (v: ":hook ${v}"); - mkDefer = v: - if isBool v - then optional v ":defer t" - else [":defer ${toString v}"]; - mkDemand = v: optional v ":demand t"; - in - concatStringsSep "\n " - (["(use-package ${name}"] - ++ mkAfter config.after - ++ mkBind config.bind - ++ mkBindKeyMap config.bindKeyMap - ++ mkBindLocal config.bindLocal - ++ mkChords config.chords - ++ mkCommand config.command - ++ mkDefer config.defer - ++ mkDefines config.defines - ++ mkFunctions config.functions - ++ mkDemand config.demand - ++ mkDiminish config.diminish - ++ mkHook config.hook - ++ mkMode config.mode - ++ optionals (config.init != "") [":init" config.init] - ++ optionals (config.config != "") [":config" config.config] - ++ optional (config.extraConfig != "") config.extraConfig) - + ")"; - }; - }); - - usePackageStr = name: pkgConfStr: '' - (use-package ${name} - ${pkgConfStr}) - ''; - - mkRecommendedOption = type: extraDescription: - mkOption { - type = types.bool; - default = false; - example = true; - description = - '' - Whether to enable recommended ${type} settings. - '' - + optionalString (extraDescription != "") '' - - ${extraDescription} - ''; - }; - - # Recommended GC settings. - gcSettings = '' - (defun hm/reduce-gc () - "Reduce the frequency of garbage collection." - (setq gc-cons-threshold most-positive-fixnum - gc-cons-percentage 0.6)) - - (defun hm/restore-gc () - "Restore the frequency of garbage collection." - (setq gc-cons-threshold 16777216 - gc-cons-percentage 0.1)) - - ;; Make GC more rare during init, while minibuffer is active, and - ;; when shutting down. In the latter two cases we try doing the - ;; reduction early in the hook. - (hm/reduce-gc) - (add-hook 'minibuffer-setup-hook #'hm/reduce-gc -50) - (add-hook 'kill-emacs-hook #'hm/reduce-gc -50) - - ;; But make it more regular after startup and after closing minibuffer. - (add-hook 'emacs-startup-hook #'hm/restore-gc) - (add-hook 'minibuffer-exit-hook #'hm/restore-gc) - - ;; Avoid unnecessary regexp matching while loading .el files. - (defvar hm/file-name-handler-alist file-name-handler-alist) - (setq file-name-handler-alist nil) - - (defun hm/restore-file-name-handler-alist () - "Restores the file-name-handler-alist variable." - (setq file-name-handler-alist hm/file-name-handler-alist) - (makunbound 'hm/file-name-handler-alist)) - - (add-hook 'emacs-startup-hook #'hm/restore-file-name-handler-alist) - ''; - - # Whether the configuration makes use of `:diminish`. - hasDiminish = any (p: p.diminish != []) (attrValues cfg.usePackage); - - # Whether the configuration makes use of `:bind`. - hasBind = - any (p: p.bind != {} || p.bindLocal != {} || p.bindKeyMap != {}) - (attrValues cfg.usePackage); - - # Whether the configuration makes use of `:chords`. - hasChords = any (p: p.chords != {}) (attrValues cfg.usePackage); - - usePackageSetup = - '' - (eval-when-compile - (require 'use-package) - ;; To help fixing issues during startup. - (setq use-package-verbose ${ - if cfg.usePackageVerbose - then "t" - else "nil" - })) - - '' - + optionalString hasDiminish '' - ;; For :diminish in (use-package). - (require 'diminish) - '' - + optionalString hasBind '' - ;; For :bind in (use-package). - (require 'bind-key) - - ;; Fixes "Symbol’s function definition is void: use-package-autoload-keymap". - (autoload #'use-package-autoload-keymap "use-package-bind-key") - '' - + optionalString hasChords '' - ;; For :chords in (use-package). - (use-package use-package-chords - :config (key-chord-mode 1)) - ''; - - earlyInitFile = '' - ;;; hm-early-init.el --- Emacs configuration à la Home Manager -*- lexical-binding: t; -*- - ;; - ;;; Commentary: - ;; - ;; The early init component of the Home Manager Emacs configuration. - ;; - ;;; Code: - - ${cfg.earlyInit} - - (provide 'hm-early-init) - ;; hm-early-init.el ends here - ''; - - initFile = - '' - ;;; hm-init.el --- Emacs configuration à la Home Manager -*- lexical-binding: t; -*- - ;; - ;;; Commentary: - ;; - ;; A configuration generated from a Nix based configuration by - ;; Home Manager. - ;; - ;;; Code: - - ${optionalString cfg.startupTimer '' - (defun hm/print-startup-stats () - "Prints some basic startup statistics." - (let ((elapsed (float-time (time-subtract after-init-time - before-init-time)))) - (message "Startup took %.2fs with %d GCs" elapsed gcs-done))) - (add-hook 'emacs-startup-hook #'hm/print-startup-stats) - ''} - - ${cfg.prelude} - - ${usePackageSetup} - '' - + concatStringsSep "\n\n" (map (getAttr "assembly") - (filter (getAttr "enable") (attrValues cfg.usePackage))) - + '' - - ${cfg.postlude} - - (provide 'hm-init) - ;; hm-init.el ends here - ''; -in { - options.programs.emacs.init = { - enable = mkEnableOption "Emacs configuration"; - - recommendedGcSettings = mkRecommendedOption "garbage collection" '' - This will reduce garbage collection frequency during startup and - while the minibuffer is active. - ''; - - startupTimer = mkEnableOption "Emacs startup duration timer"; - - earlyInit = mkOption { - type = types.lines; - default = ""; - description = '' - Configuration lines to add in early-init.el. - ''; - }; - - prelude = mkOption { - type = types.lines; - default = ""; - description = '' - Configuration lines to add in the beginning of - init.el. - ''; - }; - - postlude = mkOption { - type = types.lines; - default = ""; - description = '' - Configuration lines to add in the end of - init.el. - ''; - }; - - packageQuickstart = mkOption { - type = types.bool; - default = true; - description = '' - Whether to enable package-quickstart. This will make sure that - package.el is activated and all autoloads are - available. - - If disabled you can save quite a few milliseconds on the startup time, - but you will most likely have to tweak the command - option of various packages. - - As an example, running (emacs-init-time) on an Emacs - configuration with this option enabled reported ~300ms. Disabling the - option dropped the init time to ~200ms. - ''; - }; - - usePackageVerbose = mkEnableOption "verbose use-package mode"; - - usePackage = mkOption { - type = types.attrsOf usePackageType; - default = {}; - example = literalExpression '' - { - dhall-mode = { - mode = [ '''"\\.dhall\\'"''' ]; - }; - } - ''; - description = '' - Attribute set of use-package configurations. - ''; - }; - }; - - config = mkIf (config.programs.emacs.enable && cfg.enable) { - # Collect the extra packages that should be included in the user profile. - # These are typically tools called by Emacs packages. - home.packages = - concatMap (v: v.extraPackages) - (filter (getAttr "enable") (builtins.attrValues cfg.usePackage)); - - programs.emacs.init.earlyInit = let - standardEarlyInit = mkBefore '' - ${optionalString cfg.recommendedGcSettings gcSettings} - - ${ - if cfg.packageQuickstart - then '' - (setq package-quickstart t - package-quickstart-file "hm-package-quickstart.el") - '' - else '' - (setq package-enable-at-startup nil) - '' - } - - ;; Avoid expensive frame resizing. Inspired by Doom Emacs. - (setq frame-inhibit-implied-resize t) - ''; - - # Collect the early initialization strings for each package. - packageEarlyInits = - map (p: p.earlyInit) - (filter (p: p.earlyInit != "") (builtins.attrValues cfg.usePackage)); - in - mkMerge ([standardEarlyInit] ++ packageEarlyInits); - - programs.emacs.extraPackages = epkgs: let - getPkg = v: - if isFunction v - then [(v epkgs)] - else optional (isString v && hasAttr v epkgs) epkgs.${v}; - - packages = - concatMap (v: getPkg (v.package)) - (filter (getAttr "enable") (builtins.attrValues cfg.usePackage)); - in [ - (epkgs.trivialBuild { - pname = "hm-early-init"; - src = pkgs.writeText "hm-early-init.el" earlyInitFile; - packageRequires = packages; - preferLocalBuild = true; - allowSubstitutes = false; - }) - - (epkgs.trivialBuild { - pname = "hm-init"; - src = pkgs.writeText "hm-init.el" initFile; - packageRequires = - [epkgs.use-package] - ++ packages - ++ optional hasBind epkgs.bind-key - ++ optional hasDiminish epkgs.diminish - ++ optional hasChords epkgs.use-package-chords; - preferLocalBuild = true; - allowSubstitutes = false; - preBuild = '' - # Do a bit of basic formatting of the generated init file. - emacs -Q --batch \ - --eval '(find-file "hm-init.el")' \ - --eval '(let ((indent-tabs-mode nil) (lisp-indent-offset 2)) (indent-region (point-min) (point-max)))' \ - --eval '(write-file "hm-init.el")' - - ${optionalString cfg.packageQuickstart '' - # Generate a package quickstart file to make autoloads and such - # available. - emacs -Q --batch \ - --eval "(require 'package)" \ - --eval "(setq package-quickstart-file \"hm-package-quickstart.el\")" \ - --eval "(package-quickstart-refresh)" - - # We know what we're doing? - sed -i '/no-byte-compile: t/d' hm-package-quickstart.el - ''} - ''; - }) - ]; - - home.file = { - ".emacs.d/early-init.el".text = '' - (require 'hm-early-init) - (provide 'early-init) - ''; - - ".emacs.d/init.el".text = '' - (require 'hm-init) - (provide 'init) - ''; - }; - }; -}