;;; init.el --- Description -*- lexical-binding: t; -*- ;; ;; Copyright (C) 2023 Daniel Ziltener ;; ;; Author: Daniel Ziltener ;; Maintainer: Daniel Ziltener ;; 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: (require 'cl-macs) ;;;; 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 (cl-defun conditional-keybind (filter-fn target-fn &optional (fail-fn #'self-insert-command)) (lambda (_prefix) (interactive "P") (if (funcall filter-fn) (call-interactively target-fn) (call-interactively fail-fn)))) ;;;; 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 "")) (evil-set-leader 'normal (kbd "z") t) (evil-mode 1) :bind (:map evil-normal-state-map ("f" . 'find-file) ("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 ("" . 'consult-find) ("gs" . 'consult-eglot-symbols) ("b" . 'consult-buffer) ("gb" . 'consult-project-buffer) ("g/" . 'consult-git-grep) ("/" . 'consult-grep) ("/" . 'consult-line))) (use-package embark :bind ("C-" . 'embark-act) ("C-M-" . '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))) (use-package evil-snipe :custom (evil-snipe-scope 'whole-visible) (evil-snipe-repeat-scope 'whole-buffer) (evil-snipe-spillover-scope 'whole-buffer) :hook evil-mode (evil-mode . evil-snipe-override-mode) (magit-mode . turn-off-evil-snipe-override-mode) ;; See https://github.com/hlissner/evil-snipe/issues/95 ;; :config ;; (evilem-define "gs" 'evil-snipe-repeat ;; :bind ((evil-snipe-scope 'buffer) ;; (evil-snipe-enable-highlight) ;; (evil-snipe-enable-incremental-highlight))) ) (use-package evil-easymotion :config (evilem-default-keybindings "")) ;;;; Lisp Navigation and Editing ;;;;; Helper Functions (defun cc/move-sexp-backward () "Move balanced expression (sexp) to the right of point backward one sexp. Point must be at the beginning of balanced expression (sexp)." (interactive) (transpose-sexps 1) (forward-sexp -2)) (defun cc/move-sexp-forward () "Move balanced expression (sexp) to the right of point forward one sexp. Point must be at the beginning of balanced expression (sexp)." (interactive) (forward-sexp 1) (transpose-sexps 1) (forward-sexp -1)) (defun looking-at-opening-paren () (looking-at (rx (or "(" "{" "[")))) (defun being-past-closing-paren () (looking-back (rx (or ")" "}" "]")))) ;;;;; Basic (use-package smartparens :hook (smartparens-mode . show-smartparens-mode) (smartparens-mode . smartparens-strict-mode) clojure-ts-mode emacs-lisp-mode scheme-mode :config (add-to-list 'sp-clojure-modes 'clojure-ts-mode) (add-to-list 'sp-clojure-modes 'clojurec-ts-mode) (add-to-list 'sp-clojure-modes 'clojurescript-ts-mode) (add-to-list 'sp-lisp-modes 'clojure-ts-mode) (add-to-list 'sp-lisp-modes 'clojurec-ts-mode) (add-to-list 'sp-lisp-modes 'clojurescript-ts-mode) (evil-define-key 'insert smartparens-mode-map (kbd "r") (conditional-keybind #'looking-at-opening-paren #'sp-raise-sexp) (kbd "w") (conditional-keybind #'looking-at-opening-paren #'cc/move-sexp-backward) (kbd "s") (conditional-keybind #'looking-at-opening-paren #'cc/move-sexp-forward) (kbd "c") (conditional-keybind #'looking-at-opening-paren #'sp-clone-sexp) (kbd "DEL") (conditional-keybind #'being-past-closing-paren #'sp-backward-delete-sexp #'evil-delete-backward-char-and-join) (kbd ">") (conditional-keybind #'being-past-closing-paren (lambda (prefix) (interactive "P") (call-interactively #'backward-char) (call-interactively #'sp-forward-slurp-sexp) (call-interactively #'sp-forward-sexp) (call-interactively #'forward-char))) (kbd "<") (conditional-keybind #'being-past-closing-paren (lambda (prefix) (interactive "P") (call-interactively #'backward-char) (call-interactively #'sp-forward-barf-sexp) (call-interactively #'forward-char))))) (use-package evil-cleverparens :after smartparens :hook smartparens) ;;;;; 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 "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