;;; 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://gitea.lyrion.ch/zilti/guixconfig ;; Package-Requires: ((emacs "29.1")) ;; ;; This file is not part of GNU Emacs. ;; ;;; Commentary: ;; ;; Description ;; ;;; Code: ;;;; Requirements ;; Since I am using `cl-defun` in this init file, I need to require ;; `cl-macs`. (require 'cl-macs) ;;;; Early Variables (setq custom-file "~/.config/emacs/custom.el") (when (file-exists-p custom-file) (load custom-file)) (defvar init-dir (file-name-directory (or load-file-name (buffer-file-name)))) ;;;; Personal Information Setup (setq user-full-name "Daniel Ziltener" user-mail-address "dziltener@lyrion.ch") ;; I use `pass` as password storage. (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) ;;;; Elpaca ;;;;; Installation (defvar elpaca-installer-version 0.6) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (< emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) ((zerop (call-process "git" nil buffer t "clone" (plist-get order :repo) repo))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory \".\" 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (load "./elpaca-autoloads"))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca `(,@elpaca-order)) ;;;;; use-package integration (elpaca elpaca-use-package (elpaca-use-package-mode) (setq elpaca-use-package-by-default t)) (elpaca-wait) ;;;; Package Management Configuration ;; See: https://github.com/radian-software/el-patch (use-package el-patch) ;;;;; Guix Management (use-package guix) ;;;; Helper Functions (cl-defun conditional-keybind (filter-fn target-fn &optional (fail-fn #'self-insert-command)) "Creates a keybinding that checks `filter-fn`. If it succeeds, `target-fn` is run, otherwise `fail-fn`. If no fail-fn is given, `self-insert-command` is run instead. `target-fn` and `fail-fn` must both be interactive." (lambda (_prefix) (interactive "P") (if (funcall filter-fn) (call-interactively target-fn) (call-interactively fail-fn)))) ;;;; Emacs (use-package emacs :elpaca nil :delight (eldoc-mode " 󰙎") :custom (completion-cycle-threshold 10) (display-time-mode t) (enable-recursive-minibuffers t) (enable-remote-dir-locals t) (fill-column 100) (global-hl-line-mode t) (indent-tabs-mode nil) (menu-bar-mode nil) (minibuffer-prompt-properties (read-only t cursor-intangible t face minibuffer-prompt)) (read-extended-command-predicate #'command-completion-default-include-p) (recentf-mode t) (scroll-bar-mode nil) (tab-always-indent 'complete) (tool-bar-mode nil) :custom-face ;;(default ((t (:weight bold :height 113 :width normal :family "VictorMono Nerd Font")))) (default ((t (:weight regular :height 105 :width normal :family "MonaspiceXe Nerd Font Mono")))) :hook (minibuffer-setup . cursor-intangible-mode) :config (advice-add 'risky-local-variable-p :override #'ignore) (global-display-fill-column-indicator-mode t) (pixel-scroll-precision-mode 1)) ;;;; Org Mode (use-package org :elpaca (:repo "https://git.savannah.gnu.org/git/emacs/org-mode.git" :branch "emacs-sync") :ensure t :custom (org-babel-load-languages '((emacs-lisp . t) (scheme . t))) :hook (org-mode . org-indent-mode) (org-src-mode . hack-local-variables) (org-mode . visual-line-mode) :config (setq org-directory "~/org") (add-to-list 'org-modules 'collector)) (use-package org-roam :ensure t :custom (org-roam-directory "~/org/roam") :config (org-roam-db-autosync-mode)) (use-package consult-notes :config (consult-notes-org-roam-mode t)) (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) ) (use-package unicode-fonts :ensure t :config (unicode-fonts-setup)) (use-package ligature :config (ligature-set-ligatures 't '( ;; SS01 "==" "===" "=/=" "!=" "!==" "/=" "/==" "~~" "=~" "!~" ;; SS02 ">=" "<=" ;; SS03 "->" "<-" "=>" "" "<~" "<~~" "~>" "~~>" "<~>" ;; SS04 "" "" "/\\" "\\/" ;; SS05 "|>" "<|" ;; SS06 "##" "###" ;; SS07 "***" "/*" "*/" "/*/" "(*" "*)" "(*)" ;; SS08 ".=" ".-" "..<" ;; CALT "//" "///" "&&" "!!" "??" "?." "?:" "||" "::" ":::" ";;" ".." "..." "=!=" "#=" ":=" "=:" "=:=" ":>" ">:" "<:" ":<" "..=" "..-" )) (global-ligature-mode t)) (set-frame-parameter nil 'alpha-background 80) (add-to-list 'default-frame-alist '(alpha-background . 80)) (use-package lambda-line ;;:straight (:type git :host github :repo "lambda-emacs/lambda-line") :elpaca (:host github :repo "lambda-emacs/lambda-line") :custom (lambda-line-icon-time t) ;; requires ClockFace font (see below) (lambda-line-clockface-update-fontset "ClockFaceRect") ;; set clock icon (lambda-line-position 'bottom) ;; Set position of status-line (lambda-line-abbrev t) ;; abbreviate major modes (lambda-line-hspace " ") ;; add some cushion (lambda-line-prefix t) ;; use a prefix symbol (lambda-line-prefix-padding nil) ;; no extra space for prefix (lambda-line-status-invert nil) ;; no invert colors (lambda-line-gui-ro-symbol " ⨂") ;; symbols (lambda-line-gui-mod-symbol " ⬤") (lambda-line-gui-rw-symbol "  ") (lambda-line-vc-symbol "  ") (lambda-line-space-top +.50) ;; padding on top and bottom of line (lambda-line-space-bottom -.50) (lambda-line-symbol-position 0.1) ;; adjust the vertical placement of symbol :config ;; add evil indicator (advice-add 'lambda-line-compose :around (lambda (orig-fun status name primary tertiary secondary) (funcall orig-fun status (concat name evil-mode-line-tag) primary tertiary secondary))) ;; activate lambda-line (lambda-line-mode) (lambda-line-clockface-update-fontset "ClockFaceRect") (customize-set-variable 'flymake-mode-line-counter-format '("" flymake-mode-line-error-counter flymake-mode-line-warning-counter flymake-mode-line-note-counter "")) (customize-set-variable 'flymake-mode-line-format '(" " flymake-mode-line-exception flymake-mode-line-counters)) ;; set divider line in footer (when (eq lambda-line-position 'top) (setq-default mode-line-format (list "%_")) (setq mode-line-format (list "%_")))) (use-package lambda-themes ;;:straight (:type git :host github :repo "lambda-emacs/lambda-themes") :elpaca (:host github :repo "lambda-emacs/lambda-themes") :custom (lambda-themes-set-italic-comments t) (lambda-themes-set-italic-keywords t) (lambda-themes-set-variable-pitch t) :config ;; load preferred theme (load-theme 'lambda-dark)) (use-package visual-fill-column :custom (visual-fill-column-center-text t) (visual-fill-column-enable-sensible-window-split t) :hook visual-line-mode) (use-package adaptive-wrap :hook visual-fill-column) ;;;; 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 evil-emacs-state-tag " 󰯸 " evil-normal-state-tag " 󰰓 " evil-visual-state-tag " 󰰬 " evil-insert-state-tag " 󰰅 " evil-motion-state-tag " 󰬔 " evil-operator-state-tag " 󰰕 ") :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 :delight evil-collection-unimpaired-mode :custom (evil-collection-outline-bind-tab-p 1) :commands evil-collection-init :init (evil-collection-init)) ;;;; Search, Completion, Execution ;;;;; Preliminary Packages (use-package savehist :elpaca nil :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 basic partial-completion))))) (use-package embark-consult :hook (embark-collect-mode . consult-preview-at-point-mode) :config (require 'consult-flymake) (require 'consult-xref) :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)) ("C-" . 'embark-act) ("C-M-" . 'embark-bindings)) (use-package wgrep :config (setq wgrep-auto-save-buffer t)) (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 :preface (defun my/capf () (setq completion-at-point-functions (list (cape-capf-super #'tempel-complete #'cape-dabbrev #'cape-file #'cape-dict #'cape-line #'cape-emoji #'cape-keyword)))) :config (advice-add 'eglot-completion-at-point :around #'cape-wrap-buster) :hook (org-mode . my/capf) (prog-mode . my/capf)) (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)) (corfu-popupinfo-delay '(0.1 . 0.5)) :config (setq corfu-sort-override-function #'my/corfu-combined-sort) (add-to-list 'savehist-additional-variables 'corfu-history) :commands global-corfu-mode :init (global-corfu-mode) (corfu-popupinfo-mode 1) (corfu-history-mode 1)) (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 :hook global-corfu-mode) (use-package tempel) (use-package xref-union :hook cider-connected) ;;;; 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 :delight (evil-snipe-local-mode " 󰓾 ") :custom (evil-snipe-scope 'whole-visible) (evil-snipe-repeat-scope 'whole-buffer) (evil-snipe-spillover-scope 'whole-buffer) (evil-snipe-tab-increment t) :hook evil-mode (evil-mode . evil-snipe-override-mode) (evil-mode . evil-snipe-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)) (defvar last-sexp nil) (defun cc/clone-sexp () "Clone the sexp right after the cursor." (interactive) (call-interactively #'mark-sexp) (call-interactively #'kill-ring-save) (call-interactively #'evil-paste-before) (call-interactively #'forward-char) (call-interactively #'paredit-newline)) (defun looking-at-opening-paren () (looking-at (rx (or "(" "{" "[")))) (defun being-past-closing-paren () (looking-back (rx (or ")" "}" "]")))) ;;;;; Basic (use-package symex :custom (symex-modal-backend 'evil) :config (symex-initialize) :bind (:map evil-insert-state-map ("C-s" . #'symex-mode-interface))) (use-package paredit :hook clojure-mode emacs-lisp-mode scheme-mode :config (evil-define-key 'insert paredit-mode-map (kbd "r") (conditional-keybind #'looking-at-opening-paren #'paredit-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 #'cc/clone-sexp))) ;; (use-package smartparens ;; :delight (smartparens-mode " 󰅲 ") ;; :hook ;; (smartparens-mode . show-smartparens-mode) ;; (smartparens-mode . smartparens-strict-mode) ;; clojure-ts-mode ;; emacs-lisp-mode ;; scheme-mode ;; :custom ;; (sp-undo-pairs-separately t) ;; :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) ;; ;; TODO: Remove the following three lines once merge request got accepted ;; (load-file (concat init-dir "lib/smartparens-clojure.el")) ;; (load-file (concat init-dir "lib/smartparens-emacs-lisp.el")) ;; (load-file (concat init-dir "lib/smartparens-scheme.el")) ;; (require 'smartparens-clojure) ;; (require 'smartparens-emacs-lisp) ;; (require 'smartparens-scheme) ;; (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 "m") (conditional-keybind #'looking-at-opening-paren ;; #'sp-mark-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 :delight editorconfig-mode :commands editorconfig-mode :init (editorconfig-mode 1)) (use-package flymake :delight '(:eval (cons "  " (flymake--mode-line-counters)))) (use-package eglot :preface (defun my/eglot-capf () (setq completion-at-point-functions (list (cape-capf-super #'eglot-completion-at-point #'tempel-complete #'cape-dabbrev #'cape-file #'cape-dict #'cape-line #'cape-emoji #'cape-keyword)))) :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-mode clojurec-mode clojurescript-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 :delight "" :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 :elpaca (:host github :repo "clojure-emacs/cider" :tag "v1.12.0") :delight (cider-mode '(:eval (concat "  [" (cider--modeline-info) "]"))) :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)) ;;;;; Scheme (use-package geiser :preface (defun my/geiser-capf () (setq completion-at-point-functions (append geiser-capf--capfs (list (cape-capf-super #'tempel-complete #'cape-dabbrev #'cape-file #'cape-dict #'cape-line #'cape-emoji #'cape-keyword))))) :custom (geiser-chicken-match-limit 200) :config (defalias 'run-geiser 'geiser) :hook (geiser-mode . my/geiser-capf)) (use-package paren-face :hook scheme-mode emacs-lisp-mode clojure-ts-mode) (use-package highlight-parentheses :hook prog-mode) ;;;;;; Chicken Scheme (use-package scheme :elpaca nil :config (setq prettify-symbols-alist '(("lambda" . "λ"))) :hook (scheme-mode . eglot-ensure)) (defun flymake-chicken-init () (add-hook 'flymake-diagnostic-functions #'flymake-chicken-backend nil t) (flymake-mode)) (use-package geiser-chicken) ;;;;;; Guile (use-package geiser-guile :config (when (executable-find "guix") (add-to-list 'geiser-guile-load-path (expand-file-name "~/.config/guix/current/share/guile/site/3.0")))) ;; (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 zig-mode :hook (zig-mode . eglot-ensure) :mode ("\\.zig\\'" . zig-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 :delight git-gutter-mode :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 rcirc :elpaca nil :ensure t :after password-store :custom (rcirc-server-alist `(("liberachat.irc.lyrion.ch" :server-alias "irc.libera.chat" :port 6697 :nick "zilti" :full-name "Daniel Ziltener" :user-name "zilti/irc.libera.chat" :password ,(password-store-get "Privat/Soju") :encryption tls :channels ("#chicken"))) `(("oftc.irc.lyrion.ch" :server-alias "irc.oftc.net" :port 6697 :nick "zilti" :full-name "Daniel Ziltener" :user-name "zilti/irc.oftc.net" :password ,(password-store-get "Privat/Soju") :encryption tls :channels ())))) ;;;; Wrapping Up (use-package envrc :config (envrc-global-mode)) (provide 'init) ;;; init.el ends here