guixconfig/home/emacs/init.el
2024-03-27 17:07:30 +01:00

862 lines
26 KiB
EmacsLisp
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; 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://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)
;;;; Elpaca
;;;;; Installation
(defvar elpaca-installer-version 0.7)
(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 :depth 1
: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 (apply #'call-process `("git" nil ,buffer t "clone"
,@(when-let ((depth (plist-get order :depth)))
(list (format "--depth=%d" depth) "--no-single-branch"))
,(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 nil))
(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
:after org
: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)
(global-prettify-symbols-mode t)
(indent-tabs-mode nil)
(menu-bar-mode nil)
(minibuffer-prompt-properties (read-only t cursor-intangible t face minibuffer-prompt))
(native-comp-async-report-warnings-errors nil)
(read-extended-command-predicate #'command-completion-default-include-p)
(recentf-mode t)
(pixel-scroll-precision-large-scroll-height 30)
(scroll-bar-mode nil)
(tab-always-indent 'complete)
(tool-bar-mode nil)
(newsticker-url-list-defaults nil)
(newsticker-url-list
'(("Tagesschau" "https://www.tagesschau.de/index~atom.xml" nil nil nil)
("NZZ Neuste" "https://www.nzz.ch/recent.rss" nil nil nil)
("SRF News" "https://www.srf.ch/news/bnf/rss/1646" nil nil nil)
("SRF Wissen" "https://www.srf.ch/bnf/rss/630" nil nil nil)
("Deutschlandfunk Nachrichten" "https://www.deutschlandfunk.de/nachrichten-100.rss" nil nil nil)
("Deutschlandfunk Wissen" "https://www.deutschlandfunk.de/wissen-106.rss" nil nil nil)
("RBB" "https://www.rbb24.de/aktuell/index.xml/feed=rss.xml" nil nil nil)
("Guix" "https://guix.gnu.org/feeds/blog.atom" nil nil nil)
("Mastering Emacs" "https://www.masteringemacs.org/feed" nil nil nil)
("Schiene.de" "https://www.schiene.de/feed/" nil nil nil)
("Anil Dash Blog" "https://www.anildash.com/feed.xml" nil nil nil)))
:custom-face
(default ((t (:weight normal :height 110 :family "LibertinusMono Nerd Font Mono"))))
(fixed-pitch ((t (:weight normal :height 110 :family "LibertinusMono Nerd Font Mono"))))
(variable-pitch ((t (:weight normal :height 135 :family "LibertinusSerif Nerd Font Propo"))))
:hook
(minibuffer-setup . cursor-intangible-mode)
:config
(setq xref-backend-functions (list))
(advice-add 'risky-local-variable-p :override #'ignore)
(global-display-fill-column-indicator-mode t)
(pixel-scroll-precision-mode 1))
(use-package gnus
:custom
(message-send-mail-function 'message-send-mail-with-sendmail)
(sendmail-program "msmtp")
(message-sendmail-f-is-evil t)
(message-sendmail-extra-arguments '("--read-envelope-from")))
(defun set-buffer-variable-pitch ()
(interactive)
(variable-pitch-mode t)
(setq line-spacing 3)
(set-face-attribute 'org-table nil :inherit 'fixed-pitch)
(set-face-attribute 'org-code nil :inherit 'fixed-pitch)
(set-face-attribute 'org-block nil :inherit 'fixed-pitch)
;; investigate: this face does not exist
;;(set-face-attribute 'org-block-background nil :inherit 'fixed-pitch)
)
(use-package outline-minor
:bind
(:map evil-normal-state-map
("zoc" . #'outline-cycle-buffer))
:hook
clojure-mode
scheme-mode
emacs-lisp-mode)
;;;; Org Mode
(use-package org
:preface
(defun cc/org-local-stuff ()
(setq-local visual-fill-column-center-text t))
;; TODO: WTF was that for?
;;:elpaca (:repo "https://git.savannah.gnu.org/git/emacs/org-mode.git" :branch "emacs-sync")
:after visual-fill-column
:custom
(org-babel-load-languages '((emacs-lisp . t)
(scheme . t)
(shell . t)))
:hook
(org-mode . org-indent-mode)
(org-src-mode . hack-local-variables)
(org-mode . visual-line-mode)
(org-mode . set-buffer-variable-pitch)
:config
(setq org-directory "~/org")
;;(add-to-list 'org-modules 'collector)
)
(use-package org-roam
: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
:after org-roam)
(use-package org-roam-ui
: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
: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
:config
(unicode-fonts-setup))
(set-frame-parameter nil 'alpha-background 90)
(add-to-list 'default-frame-alist '(alpha-background . 90))
(use-package lambda-line
:ensure (: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
:ensure (: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))
;;;;; Long line handling
(use-package visual-fill-column
:custom
(visual-fill-column-enable-sensible-window-split t)
:hook
(prog-mode . visual-line-mode)
visual-line-mode
;; :config
;; (add-hook 'prog-mode-hook #'visual-line-mode)
;; (add-hook 'visual-line-mode-hook #'visual-fill-column-mode)
)
(use-package adaptive-wrap
:config
(setq-default adaptive-wrap-extra-indent 4)
;;(add-hook 'visual-line-mode-hook #'adaptive-wrap-prefix-mode)
:hook
(visual-line-mode . adaptive-wrap-prefix-mode))
;;;; Security
(use-package keychain-environment
:init
(keychain-refresh-environment))
(use-package pass)
;;;; Evil Mode
(use-package evil
: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 "<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
: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
: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)
:custom
(xref-show-xrefs-function #'consult-xref)
: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))
("C-<SPC>" . 'embark-act)
("C-M-<return>" . '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)
:config
(which-key-mode t))
;;;;; Code Completion
(use-package cape
:config
(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))))
(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))))
(defun my/geiser-capf ()
(setq completion-at-point-functions
(list (apply #'cape-capf-super
(append geiser-capf--capfs
(list
#'tempel-complete
#'cape-dabbrev
#'cape-file
#'cape-dict
#'cape-line
#'cape-emoji
#'cape-keyword))))))
(advice-add 'eglot-completion-at-point :around #'cape-wrap-buster)
:hook
(org-mode . my/capf)
(prog-mode . my/capf)
(eglot-managed-mode . my/eglot-capf)
(geiser-mode . my/geiser-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
:custom
(xref-union-excluded-backends (lambda (b) (eq b #'etags--xref-backend)))
:hook
cider-mode)
;;;; 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
:after evil-easymotion
:custom
(evil-snipe-scope 'whole-visible)
(evil-snipe-repeat-scope 'whole-buffer)
(evil-snipe-spillover-scope 'whole-buffer)
(evil-snipe-tab-increment t)
:commands
evil-snipe-override-mode
:init
(evil-snipe-override-mode 1)
:hook
(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
:after evil
:config
(evilem-default-keybindings "<leader>"))
;;;; 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 cc/slurp-forward ()
"Slurps forward when the key is after the closing paren."
(interactive)
(call-interactively #'backward-char)
(call-interactively #'paredit-forward-slurp-sexp))
(defun cc/barf-forward ()
"Barfs forward even when the key is after the closing paren."
(interactive)
(call-interactively #'backward-char)
(call-interactively #'paredit-forward-barf-sexp))
(defun looking-at-opening-paren ()
(looking-at (rx (or "(" "{" "["))))
(defun being-past-closing-paren ()
(looking-back (rx (or ")" "}" "]"))))
;;;;; Basic
(use-package paredit
:config
;; (add-hook 'clojure-ts-mode-hook #'paredit-mode)
;; (add-hook 'emacs-lisp-mode-hook #'paredit-mode)
;; (add-hook 'scheme-mode-hook #'paredit-mode)
(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)
(kbd ">") (conditional-keybind #'being-past-closing-paren
#'cc/slurp-forward)
(kbd "<") (conditional-keybind #'being-past-closing-paren
#'cc/barf-forward))
:hook
clojure-ts-mode
clojure-mode
emacs-lisp-mode
scheme-mode)
;;;;; 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
:custom
(eglot-connect-timeout 90)
(eglot-autoshutdown t)
(eglot-report-progress t)
:config
(setq-default eglot-workspace-configuration
'((clojure-lsp (maxCompletions . 300))))
: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)
(clojure-mode . eglot-ensure))
(use-package consult-eglot
:after (consult eglot))
;;;;; Clojure
(use-package clojure-mode
:preface
(defun embark-eglot-rename (from to)
"Renames the symbol at point."
(interactive "sRename: \nsRename %s to: ")
(funcall-interactively #'eglot-rename to))
:delight ""
:after (embark cider)
:config
(defvar-keymap embark-clj-identifier-map
:parent embark-identifier-map
"c" #'embark-eglot-rename)
(add-to-list 'embark-keymap-alist '(identifier . embark-clj-identifier-map))
:hook
(clojure-mode . (lambda ()
(setq xref-backend-functions (list))
(setq-local prettify-symbols-alist
'(("fn" . "λ")
("comp" . "")
("and" . "")
("or" . "")
("not" . "¬"))))))
(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 'normal 'cider-mode-map
(kbd "<localleader>ce") #'cider-eval-sexp-at-point))
;;;;; Scheme
(use-package geiser
:custom
(geiser-chicken-match-limit 200)
:config
(defalias 'run-geiser 'geiser))
(use-package paren-face
:hook
scheme-mode
emacs-lisp-mode
clojure-ts-mode
;; :config
;; (add-hook 'scheme-mode-hook #'paren-face-mode)
;; (add-hook 'emacs-lisp-mode-hook #'paren-face-mode)
;; (add-hook 'clojure-ts-mode-hook #'paren-face-mode)
)
(use-package highlight-parentheses
:hook
prog-mode
;; :config
;; (add-hook 'prog-mode-hook #'highlight-parentheses-mode)
)
;;;;;; Chicken Scheme
(use-package scheme
:hook
(scheme-mode . (lambda ()
(setq-local prettify-symbols-alist
'(("lambda" . "λ")
("compose" . "")
("and" . "")
("or" . "")
("not" . "¬"))))))
(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
;; Magit requires 'transient' >= 0.5.0, but due to bad defaults, Emacs' package manager refuses to
;; upgrade this and other built-in packages to higher releases from GNU Elpa.
;; (use-package transient
;; :init
;; (progn (unload-feature 'transient t)
;; (require 'transient)))
;; To fix this, you have to add this to your init file:
;; (setq package-install-upgrade-built-in t)
;; You must also make sure the updated version is loaded, by evaluating the `progn` form below.
(use-package magit
:after transient
: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
;; :config
;; (add-hook 'prog-mode-hook #'git-gutter-mode)
)
;;;; File Formats
;;;;; Asciidoc
(use-package adoc-mode
:hook
(adoc-mode . visual-line-mode)
(adoc-mode . (lambda () (setq-local visual-fill-column-center-text t))))
;;;; 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
: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