nixconfig/emacs/init.el
2023-11-17 12:20:24 +01:00

567 lines
15 KiB
EmacsLisp

;;; init.el --- Description -*- lexical-binding: t; -*-
;;
;; Copyright (C) 2023 Daniel Ziltener
;;
;; Author: Daniel Ziltener <dziltener@lyrion.ch>
;; Maintainer: Daniel Ziltener <dziltener@lyrion.ch>
;; Created: November 13, 2023
;; Modified: November 13, 2023
;; Version: 0.0.1
;; Keywords: abbrev bib c calendar comm convenience data docs
;; emulations extensions faces files frames games hardware help
;; hypermedia i18n internal languages lisp local maint mail matching
;; mouse multimedia news outlines processes terminals tex tools unix
;; vc wp
;; Homepage: https://github.com/dziltener@lyrion.ch/init
;; Package-Requires: ((emacs "24.3"))
;;
;; This file is not part of GNU Emacs.
;;
;;; Commentary:
;;
;; Description
;;
;;; Code:
;;;; Early Variables
(setq custom-file "~/.emacs.d/custom.el")
(when (file-exists-p custom-file)
(load custom-file))
;;;; Personal Information Setup
(setq user-full-name "Daniel Ziltener"
user-mail-address "dziltener@lyrion.ch")
(auth-source-pass-enable)
;;;; Straight.el
;; (defvar bootstrap-version)
;; (let ((bootstrap-file
;; (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
;; (bootstrap-version 6))
;; (unless (file-exists-p bootstrap-file)
;; (with-current-buffer
;; (url-retrieve-synchronously
;; "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
;; 'silent 'inhibit-cookies)
;; (goto-char (point-max))
;; (eval-print-last-sexp)))
;; (load bootstrap-file nil 'nomessage))
;; (setq straight-use-package-by-default t)
;;;; Package Management Configuration
;; See: https://github.com/radian-software/el-patch
(use-package el-patch)
;;;; Helper Functions
(defun conditional-keybind (filter-fn target-fn)
(lambda (_prefix)
(interactive "P")
(if (funcall filter-fn)
(call-interactively target-fn)
(call-interactively #'self-insert-command))))
;;;; Emacs
(use-package emacs
:custom
(completion-cycle-threshold 10)
(read-extended-command-predicate
#'command-completion-default-include-p)
(minibuffer-prompt-properties
(read-only t cursor-intangible t face minibuffer-prompt))
(tab-always-indent 'complete)
(indent-tabs-mode nil)
(enable-recursive-minibuffers t)
(enable-remote-dir-locals t)
(global-hl-line-mode t)
(menu-bar-mode nil)
(scroll-bar-mode nil)
(tool-bar-mode nil)
(recentf-mode t)
:hook
(minibuffer-setup . cursor-intangible-mode)
:config
(advice-add 'risky-local-variable-p :override #'ignore))
;;;; Org Mode
(use-package org
:ensure t
:hook
(org-src-mode . hack-local-variables)
:config
(setq org-directory "~/org")
(add-to-list 'org-modules 'collector))
(use-package org-roam
:ensure t
:custom
(org-roam-directory "~/org/roam")
:config
(progn (org-roam-db-autosync-mode)))
(use-package websocket
:ensure t
:after org-roam)
(use-package org-roam-ui
:ensure t
:after org-roam
:custom
(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))
(use-package org-modern
:ensure t
:hook
((org-mode . org-modern-mode)
(org-agenda-finalize . org-modern-agenda)))
(use-package org-rainbow-tags
:hook
(org-mode . org-rainbow-tags-mode))
;;;; Design
(use-package color-theme-modern)
(use-package moe-theme)
(use-package catppuccin-theme
:custom
(catppuccin-flavor 'mocha)
(catppuccin-highlight-matches t)
(catppuccin-italic-comments t)
:custom-face
(font-lock-doc-face ((t (:inherit font-lock-comment-face
:foreground "#fab387"))))
:config
(load-theme 'catppuccin))
(set-frame-parameter nil 'alpha-background 80)
(add-to-list 'default-frame-alist '(alpha-background . 80))
(set-frame-font "Victor Mono Nerd Font-10:bold" nil t)
;;;; Security
(use-package keychain-environment
:init
(keychain-refresh-environment))
(use-package pass)
(use-package password-store)
(use-package password-store-otp)
;;;; Evil Mode
(use-package evil
;; :after evil-leader
:ensure t
:init
(setq evil-want-keybinding nil)
:config
(evil-set-leader 'normal (kbd "<SPC>"))
(evil-set-leader 'normal (kbd "z") t)
(evil-mode 1)
:bind
(:map evil-normal-state-map
("<leader>f" . 'find-file)
("<leader>k" . 'kill-buffer)))
(use-package evil-collection
:after evil
:ensure t
:custom
(evil-collection-outline-bind-tab-p 1)
:commands evil-collection-init
:init
(evil-collection-init))
;;;; Search, Completion, Execution
;;;;; Preliminary Packages
(use-package savehist
:init
(savehist-mode))
(use-package orderless
:after consult
:config
(with-eval-after-load 'eglot
(setq completion-category-defaults nil))
(setq completion-styles
'(orderless basic)
completion-category-defaults nil
completion-category-overrides '((file (styles partial-completion)))))
(use-package consult
:bind
(:map evil-normal-state-map
("<leader><SPC>" . 'consult-find)
("<leader>gs" . 'consult-eglot-symbols)
("<leader>b" . 'consult-buffer)
("<leader>gb" . 'consult-project-buffer)
("<leader>g/" . 'consult-git-grep)
("<leader>/" . 'consult-grep)
("/" . 'consult-line)))
(use-package embark
:bind
("C-<SPC>" . 'embark-act)
("C-M-<return>" . 'embark-bindings))
(use-package embark-consult
:after (embark consult)
:hook
(embark-collect-mode . consult-preview-at-point-mode))
(use-package vertico
:commands
vertico-mode
:init
(vertico-mode))
(use-package marginalia
:commands
marginalia-mode
:init
(marginalia-mode))
(use-package nerd-icons-completion
:after marginalia
:commands
nerd-icons-completion-mode
:hook
(marginalia-mode-hook . nerd-icons-completion-marginalia-setup)
:init
(nerd-icons-completion-mode))
(use-package which-key
:commands
which-key-setup-minibuffer
:init
(which-key-setup-minibuffer))
;;;;; Code Completion
(use-package cape
:config
(advice-add 'eglot-completion-at-point :around #'cape-wrap-buster))
(defun my/corfu-combined-sort (candidates)
"Sort CANDIDATES using both display-sort-function and corfu-sort-function."
(let ((candidates
(let ((display-sort-func (corfu--metadata-get 'display-sort-function)))
(if display-sort-func
(funcall display-sort-func candidates)
candidates))))
(if corfu-sort-function
(funcall corfu-sort-function candidates)
candidates)))
(use-package corfu
:custom
(corfu-cycle t)
(corfu-preselect 'prompt)
(corfu-auto t)
(corfu-scroll-margin 5)
(corfu-quit-no-match 'separator)
(evil-collection-corfu-key-themes '(tab-n-go))
:config
(setq corfu-sort-override-function #'my/corfu-combined-sort)
:commands
global-corfu-mode
:init
(global-corfu-mode))
(use-package corfu-history
:config
(add-to-list 'savehist-additional-variables 'corfu-history)
:hook
(global-corfu-mode . corfu-history-mode))
(use-package corfu-popupinfo
:after (corfu corfu-terminal)
:custom
(corfu-popupinfo-delay '(0.1 . 0.5))
:commands
corfu-popupinfo-mode
:init
(corfu-popupinfo-mode))
(use-package nerd-icons-corfu
:after corfu
:init
(add-to-list 'corfu-margin-formatters 'nerd-icons-corfu-formatter))
(use-package corfu-terminal
:if (not (display-graphic-p))
:after corfu
:commands
corfu-terminal-mode
:init
(corfu-terminal-mode +1))
(use-package tempel)
;;;; Basic Navigation
(use-package goto-chg
:bind
(:map evil-normal-state-map
("g," . 'goto-last-change)
("g;" . 'goto-last-change-reverse)))
;;;; Lisp Navigation and Editing
;;;;; Basic
(use-package smartparens
:hook
(smartparens-mode . show-smartparens-mode)
(smartparens-mode . smartparens-strict-mode)
:config
(evil-define-key 'insert smartparens-mode-map
(kbd "r") (conditional-keybind (lambda () (looking-at "("))
#'sp-raise-sexp)
(kbd ">") (conditional-keybind (lambda () (thing-at-point-looking-at ")"))
#'sp-forward-slurp-sexp)))
(use-package evil-cleverparens
:after smartparens
:hook smartparens)
;; (use-package lispy
;; :custom
;; (lispy-close-quotes-at-end-p t)
;; (lispy-compat '("cider" "edebug" "magit-blame-mode"))
;; (lispy-visit-method #'consult-find)
;; (lispy-occur-backend #'consult-line)
;; :hook
;; emacs-lisp-mode
;; scheme-mode
;; :config
;; (evil-define-key 'insert 'clojure-ts-mode-map
;; "(" #'lispy-parens
;; "{" #'lispy-braces
;; "}" #'lispy-brackets
;; ")" #'lispy-right-nostring
;; "\"" #'lispy-quotes
;; (kbd "<DEL>") #'lispy-delete-backward
;; ">" #'special-lispy-slurp
;; "<" #'special-lispy-barf
;; "c" #'special-lispy-clone
;; "q" #'special-lispy-ace-paren
;; "w" #'special-lispy-move-up
;; "s" #'special-lispy-move-down
;; "r" #'special-lispy-raise
;; "e" #'special-lispy-eval))
;; (use-package lispyville
;; :bind
;; (:map evil-normal-state-map
;; ("<leader>," . 'lispyville-comment-or-uncomment)
;; ("<leader>." . 'lispyville-comment-and-clone-dwim)
;; ("<leader>ci" . 'lispyville-comment-or-uncomment-line))
;; :hook
;; (lispy-mode . lispyville-mode))
;;;;; Visual Aid
;; (use-package rainbow-delimiters
;; :hook
;; emacs-lisp-mode
;; scheme-mode)
;;;; Programming
(use-package editorconfig
:commands
editorconfig-mode
:init
(editorconfig-mode 1))
(use-package flymake)
(use-package consult-flymake
:after (consult flymake))
(defun my/eglot-capf ()
(setq-local completion-at-point-functions
(list (cape-super-capf
#'eglot-completion-at-point
#'tempel-complete
#'cape-dabbrev
#'cape-file
#'cape-dict))))
(use-package eglot
:custom
(eglot-connect-timeout 90)
(eglot-autoshutdown t)
(eglot-report-progress t)
:config
(defun eglot-mode ()
(eglot-inlay-hints-mode +1)
(my/eglot-capf))
(setq-default eglot-workspace-configuration
'((clojure-lsp (maxCompletions . 300))))
(add-to-list 'eglot-server-programs
'((clojure-ts-mode clojurec-ts-mode clojurescript-ts-mode)
"clojure-lsp"
:initializationOptions
(:preferences
(:includeInlayParameterNameHints
"all"
:includeInlayParameterNameHintsWhenArgumentMatchesName
t
:includeInlayFunctionParameterTypeHints
t
:includeInlayVariableTypeHints
t
:includeInlayVariableTypeHintsWhenTypeMatchesName
t
:includeInlayPRopertyDeclarationTypeHints
t
:includeInlayFunctionLikeReturnTypeHints
t
:includeInlayEnumMemberValueHints
t))))
:hook
(eglot-managed-mode . (lambda ()
(add-hook 'before-save-hook
(lambda ()
(call-interactively #'eglot-format-buffer))
nil 'local)))
(eglot-managed-mode . eglot-inlay-hints-mode)
(eglot-managed-mode . #'my/eglot-capf))
(use-package consult-eglot
:after (consult eglot))
(use-package tree-sitter
:ensure t)
;;;;; Clojure
(use-package clojure-ts-mode
:after tree-sitter
:config
(require 'sesman)
(sesman-install-menu clojure-mode-map)
:hook
((clojure-ts-mode . eglot-ensure)
(clojure-ts-mode . (lambda ()
(setq-local sesman-system 'CIDER)))
(clojure-ts-mode . (lambda ()
(sesman-install-menu clojure-mode-map)))
(clojurec-ts-mode . (lambda ()
(sesman-install-menu clojurec-mode-map)))
(clojurescript-ts-mode . (lambda ()
(sesman-install-menu clojurescript-mode-map))))
:mode
("\\.clj\\'" . #'clojure-ts-mode)
("\\.cljc\\'" . #'clojurec-ts-mode)
("\\.cljs\\'" . #'clojurescript-ts-mode)
:init
(add-to-list 'tree-sitter-major-mode-language-alist
'(clojure-ts-mode . clojure))
(add-to-list 'tree-sitter-major-mode-language-alist
'(clojurec-ts-mode . clojure))
(add-to-list 'tree-sitter-major-mode-language-alist
'(clojurescript-ts-mode . clojure)))
(use-package cider
:hook
(clojure-ts-mode . cider-mode)
:config
(evil-define-key 'insert 'cider-mode-map
"C-x C-e" #'cider-eval-last-sexp)
(evil-define-key 'normal 'cider-mode-map
(kbd "<localleader>ce") #'cider-eval-sexp-at-point))
;;;;; Chicken Scheme
(defun flymake-chicken-init ()
(add-hook 'flymake-diagnostic-functions
#'flymake-chicken-backend nil t)
(flymake-mode))
(use-package geiser
:config
(defalias 'run-geiser 'geiser))
(use-package lsp-scheme
:autoload lsp-scheme-chicken
:hook
(scheme-mode . lsp-scheme)
:custom
(lsp-scheme-implementation "chicken")
:config
(progn (add-to-list 'eglot-server-programs
'(scheme-mode . ("chicken-lsp-server"))))
(require 'lsp-scheme))
;; (use-package flymake-chicken
;; :hook
;; ((scheme-mode . flymake-chicken-init)
;; (scheme-mode . flymake-mode))
;; :custom
;; (flycheck-global-modes '(not scheme-mode))
;; :config
;; (add-hook 'flymake-diagnostic-functions #'flymake-chicken-backend nil t))
;;;; Other Languages
(use-package nix-mode
:hook
eglot-ensure
:mode ("\\.nix\\'" . nix-mode))
;; (use-package lsp-tailwindcss
;; :init
;; (setq lsp-tailwindcss-add-on-mode t
;; lsp-tailwindcss-experimental-class-regex ["\"([^\"]*)\""])
;; :config
;; (add-to-list 'lsp-tailwindcss-major-modes 'clojurescript-ts-mode)
;; (add-to-list 'lsp-tailwindcss-major-modes 'clojurec-ts-mode))
(use-package dhall-mode
:mode "\\.dhall\'"
:hook
((dhall-mode . lsp)))
;;;; Version Control
;;;;; Git
(use-package magit
:autoload
magit)
(use-package magit-todos
:after magit
:hook
(magit-mode . magit-todos-mode))
(use-package forge
:after magit
:config
(advice-add 'magit :after (lambda (&rest _args)
(call-interactively #'forge-pull))))
(use-package code-review
:after forge
:custom
(code-review-auth-login-marker 'forge))
(use-package git-gutter
:hook prog-mode)
;;;; LaTeX
;; https://github.com/politza/pdf-tools/#known-problems
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer)
;;;; Communication
;;;;; IRC
(use-package circe
:ensure t
:hook
(circe-chat-mode . enable-circe-color-nicks)
:custom
(circe-network-options
'(("Lyrion Libera Chat"
:host "lyrion.ch"
:port 6697
:tls t
:nick "zilti"
:sasl-username "zilti/irc.libera.chat"
:sasl-password (lambda (_)
(password-store-get "Privat/Soju"))))))
(provide 'init)
;;; init.el ends here