Skip to content

rynffoll/emacs

Repository files navigation

Emacs config

Table of Contents

Early Initialization

;;; early-init.el --- Early Initialization -*- lexical-binding: t; no-byte-compile: t -*-

Defaults

(setq default-directory "~/")

(setq load-prefer-newer t)
(setq create-lockfiles nil)
(setq ring-bell-function 'ignore)
(setq delete-by-moving-to-trash t)
(setq read-process-output-max (* 1024 1024))
(setq native-comp-async-report-warnings-errors nil)
(setq use-short-answers t) ;; yes-or-no -> y-or-n

UTF-8

(prefer-coding-system 'utf-8)

Disable early package initialization

(setq package-enable-at-startup nil)

GC tweaks

(setq gc-cons-threshold most-positive-fixnum)

(add-hook 'emacs-startup-hook
          #'(lambda ()
              (let ((init-time (float-time (time-subtract after-init-time before-init-time)))
                    (packages  (length package-activated-list))
                    (gc-time   (float-time gc-elapsed))
                    (gc-count  gcs-done))
                (message "Emacs ready (init time = %.2fs, packages = %d, gc time = %.2fs, gc count = %d)."
                         init-time packages gc-time gc-count))))

File handler tweaks

(defvar +file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)

(add-hook 'emacs-startup-hook
          #'(lambda ()
              (setq file-name-handler-alist +file-name-handler-alist)))

UI

common

(setq inhibit-startup-screen t)
(setq inhibit-startup-message t)

(setq initial-scratch-message nil)

(setq frame-inhibit-implied-resize t)
(setq frame-resize-pixelwise t)
(setq window-resize-pixelwise t)

(setq use-dialog-box nil)

(setq-default fringes-outside-margins t)

(tooltip-mode -1)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(tool-bar-mode -1)

(add-to-list 'default-frame-alist '(left . 0.5))
(add-to-list 'default-frame-alist '(top  . 0.5))
(add-to-list 'default-frame-alist '(width  . 0.75))
(add-to-list 'default-frame-alist '(height . 0.9))

(add-to-list 'default-frame-alist '(internal-border-width . 0))

font

(setq inhibit-compacting-font-caches t)
;; (defvar +font "JetBrains Mono:weight=medium:size=14")
;; (defvar +font "Iosevka Term:weight=medium:size=14")
;; (defvar +font "Iosevka Term:weight=medium:width=expanded:size=14") ;; Ioesevka Term Extended
;; (defvar +font "Martian Mono Condensed 14")
;; (defvar +font "Cascadia Code:size=16")
;; (defvar +font "Cascadia Code NF:size=16")
;; (defvar +font "Iosevka:size=16")
(defvar +font "Iosevka Term:size=16")

(add-to-list 'default-frame-alist `(font . ,+font))

If you’d like to test a different font, evaluate the following block:

(set-frame-font +font)

macos

(when (featurep 'ns)
  (setq ns-use-proxy-icon nil)
  (setq frame-title-format nil)
  (add-to-list 'default-frame-alist '(undecorated-round . t))
  (add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
  (add-to-list 'default-frame-alist '(ns-appearance . dark)))

Disable writing customization to init.el

;; (setq custom-file null-device)
;; Fix: Error in post-command-hook (vertico--exhibit): (error "Maximum buffer size exceeded")
(setq custom-file (locate-user-emacs-file "custom.el"))

Initialization

;;; init.el --- Initialization -*- lexical-binding: t; no-byte-compile: t -*-

Personal Info

(setq user-full-name "Ruslan Kamashev"
      user-login-name "rynffoll"
      user-mail-address "rynffoll@gmail.com")

Package Manager

use-package

(setq use-package-always-defer t)
(setq use-package-always-ensure t)
(setq use-package-hook-name-suffix nil)
(setq use-package-enable-imenu-support t)
(setq use-package-compute-statistics t)
(setq use-package-expand-minimally t)

package

(use-package package
  :ensure nil
  ;; :init
  ;; https://www.reddit.com/r/emacs/comments/1f8ok7c/comment/llhcdgy/
  ;; (setq package-install-upgrade-built-in t)
  ;; TODO: Emacs 31:
  ;; package-review-policy
  ;; package-autosuggest-mode
  ;; package-retention-policy
  ;; package-upgrade-keep-previous
  :config
  ;; https://elpa.gnu.org/devel/
  (add-to-list 'package-archives '("elpa-devel" . "https://elpa.gnu.org/devel/"))
  ;; https://github.com/melpa/melpa
  (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t)
  (add-to-list 'package-archives '("melpa-stable" . "https://stable.melpa.org/packages/") t)
  (package-initialize))

gnu-elpa-keyring-update

(use-package gnu-elpa-keyring-update)

Feature Flags

(defgroup +feature-flags nil
  "Feature flags for this configuration."
  :group 'convenience)

+with-evil

(defcustom +with-evil t
  "Enable Evil integration."
  :type 'boolean
  :group '+feature-flags)

+with-icons

(defcustom +with-icons t
  "Enable icon integrations."
  :type 'boolean
  :group '+feature-flags)

+with-dirvish

(defcustom +with-dirvish nil
  "Enable Dirvish integrations."
  :type 'boolean
  :group '+feature-flags)

Defaults

emacs

(use-package emacs
  :ensure nil
  :init
  (setq confirm-kill-emacs 'y-or-n-p))

compile

(use-package compile
  :ensure nil
  :init
  (setq compilation-scroll-output 'first-error))
(use-package ansi-color
  :ensure nil
  :hook
  (compilation-filter-hook . ansi-color-compilation-filter))

time

Tracking World Time with Emacs

(use-package time
  :ensure nil
  :init
  (setq world-clock-time-format "%a %d %b %R %z")
  (setq world-clock-list
        '(("America/Mexico_City" "Mexico/Mexico City")
          ("UTC" "UTC")
          ("Europe/Madrid" "Spain/Madrid")
          ("Europe/Moscow" "Russia/Moscow")
          ("Asia/Nicosia" "Cyprus/Nicosia")
          ("Asia/Tbilisi" "Georgia/Tbilisi")
          ("Asia/Yerevan" "Armenia/Yerevan")
          ("Asia/Almaty" "Kazakhstan/Almaty"))))

calendar

(use-package calendar
  :ensure nil
  :init
  (setq calendar-date-style 'iso)
  (setq calendar-week-start-day 1))

GC

(use-package gcmh
  :hook
  (emacs-startup-hook . gcmh-mode))

Async

(use-package async
  :hook
  (after-init-hook . async-bytecomp-package-mode)
  (dired-mode-hook . dired-async-mode))

Evil

(use-package evil
  :if +with-evil
  :demand
  :preface
  (defun +save-and-kill-buffer ()
    (interactive)
    (save-buffer)
    (kill-buffer))
  (defun +disable-evil-cursor ()
    (setq-local evil-default-cursor    '(nil))
    (setq-local evil-motion-state-cursor nil)
    (setq-local evil-visual-state-cursor nil)
    (setq-local evil-normal-state-cursor nil)
    (setq-local evil-insert-state-cursor nil)
    (setq-local evil-emacs-state-cursor  nil))
  :custom-face
  (evil-ex-substitute-matches
   ((t (:inherit diff-removed :foreground unspecified :background unspecified :strike-through t))))
  (evil-ex-substitute-replacement
   ((t (:inherit diff-added :foreground unspecified :background unspecified :underline nil))))
  :init
  (setq evil-want-keybinding nil)
  (setq evil-motion-state-cursor 'box)  ;; █
  (setq evil-visual-state-cursor 'box)  ;; █
  (setq evil-normal-state-cursor 'box)  ;; █
  (setq evil-insert-state-cursor 'bar)  ;; ⎸
  (setq evil-emacs-state-cursor  'hbar) ;; _
  (setq evil-symbol-word-search t)
  ;; (setq evil-move-beyond-eol nil)
  ;; (setq evil-move-cursor-back t)
  (setq evil-undo-system 'undo-redo)
  :config
  (evil-ex-define-cmd "q"  'kill-current-buffer)
  (evil-ex-define-cmd "wq" '+save-and-kill-buffer)
  (evil-mode t))
(use-package evil-collection
  :if +with-evil
  :demand
  :after evil
  :init
  (setq evil-collection-magit-want-horizontal-movement t)
  :config
  (evil-collection-init))
(use-package evil-commentary
  :if +with-evil
  :hook
  (after-init-hook . evil-commentary-mode))
(use-package evil-surround
  :if +with-evil
  :hook
  (after-init-hook . global-evil-surround-mode))
(use-package evil-org
  :if +with-evil
  :init
  (setq evil-org-key-theme '(todo textobjects insert navigation heading))
  :hook
  (org-mode-hook . evil-org-mode))

(use-package evil-org-agenda
  :if +with-evil
  :demand
  :ensure evil-org
  :after org-agenda
  :config
  (evil-org-agenda-set-keys))
(use-package evil-mc
  :if +with-evil
  :hook
  (after-init-hook . global-evil-mc-mode))

evil-terminal-cursor-changer

(use-package evil-terminal-cursor-changer
  :if +with-evil
  :unless (display-graphic-p)
  :init
  (setq etcc-use-color t)
  (setq etcc-use-blink nil)
  :hook
  (after-init-hook . evil-terminal-cursor-changer-activate))

General

(use-package general
  :config
  (general-create-definer +leader-def
    :states '(normal visual insert emacs motion)
    :keymaps 'override
    :prefix "SPC"
    :global-prefix "M-SPC")
  (general-create-definer +local-leader-def
    :states '(normal visual insert emacs motion)
    :keymaps 'override
    :prefix "SPC m"
    :global-prefix "M-SPC m")
  (+leader-def
    ""    '(nil :wk "leader")

    ":"   'execute-extended-command
    "."   'find-file
    ","   'switch-to-buffer

    "0"   'dired-sidebar-jump-to-sidebar
    "1"   'winum-select-window-1
    "2"   'winum-select-window-2
    "3"   'winum-select-window-3
    "4"   'winum-select-window-4
    "5"   'winum-select-window-5
    "6"   'winum-select-window-6
    "7"   'winum-select-window-7
    "8"   'winum-select-window-8
    "9"   'winum-select-window-9

    "b"   '(:ignore t :wk "buffer")
    "bb"  'switch-to-buffer
    "bk"  'kill-current-buffer
    "bK"  'kill-buffer-and-window
    "bn"  'evil-buffer-new
    "br"  'revert-buffer
    "bR"  'rename-buffer
    "bs"  'scratch-buffer
    "bl"  'list-buffers
    "bi"  'ibuffer

    "c"   '(:ignore t :wk "code")
    "cr"  'quickrun
    "cf"  'apheleia-format-buffer

    "e"   '(:ignore t :wk "emacs")
    "ed"  'iqa-find-user-init-directory
    "ee"  'iqa-find-user-init-file
    "ec"  'iqa-find-user-custom-file
    "er"  'iqa-reload-user-init-file
    "eR"  'restart-emacs

    "f"   '(:ignore t :wk "file")
    "fl"  'find-library
    "fr"  'recentf-open-files
    "ft"  'dired-sidebar-toggle-sidebar
    "ff"  '+dired-sidebar-follow-file
    "fR"  'crux-rename-file-and-buffer
    "fD"  'crux-delete-file-and-buffer
    "fg"  'magit-file-dispatch

    "F"   '(:ignore t :wk "frame")
    "Ff"  'select-frame-by-name
    "Fn"  'make-frame-command
    "Fc"  'delete-frame
    "FC"  'delete-other-frames
    "Fo"  'other-frame
    "Fb"  'switch-to-buffer-other-frame
    "FM"  'toggle-frame-maximized
    "FF"  'toggle-frame-fullscreen
    "F["  'ns-prev-frame
    "F]"  'ns-next-frame

    "g"   '(:ignore t :wk "git")
    "g."  'magit-dispatch
    "gf"  'magit-file-dispatch
    "gg"  'magit-status
    "gL"  'git-link-dispatch
    "gj"  'consult-git-log-grep
    "gt"  'git-timemachine

    "h"   '(:keymap help-map :package help :wk "help")

    "i"   '(:ignore t :wk "insert")
    "it"  'tempel-insert

    "j"   '(:ignore t :wk "jump") ;; TODO: goto-map (M-g)
    "ji"  'imenu
    "jc"  'avy-goto-char
    "jw"  'avy-goto-word-0
    "jW"  'avy-goto-word-1
    "jl"  'avy-goto-line
    "jL"  'avy-goto-end-of-line

    "l"   '(:ignore t :wk "llm")
    "lg"  'gptel
    "lc"  'claude-code-ide-menu
    "la"  'agent-shell

    "o"   '(:ignore t :wk "open")
    "oc"  'customize-group
    "ol"  'link-hint-open-link
    "ot"  'vterm
    "oe"  'eat
    "oa"  'org-agenda
    "ox"  'org-capture

    "p"   '(:keymap project-prefix-map :package project :wk "project")

    "s"   '(:ignore t :wk "search") ;; TODO: search-map (M-s)
    "sb"  'consult-line
    "sg"  'consult-ripgrep
    "st"  'consult-todo

    "S"   '(:ignore t :wk "session")
    "Ss"  'desktop-save-in-desktop-dir
    "Sr"  'desktop-read

    "TAB" '(:keymap tab-prefix-map :wk "tab-bar")

    "t"   '(:ignore t :wk "toggle")
    "tc"  'colorful-mode
    "tf"  'focus-mode
    "ti"  'highlight-indent-guides-mode
    "tl"  'global-hl-line-mode
    "tn"  'display-line-numbers-mode
    "ts"  'jinx-mode
    "tt"  'load-theme
    "tT"  'toggle-truncate-lines
    "tw"  'whitespace-mode
    "tz"  'olivetti-mode
    "tb"  'breadcrumb-mode
    )
  (+local-leader-def
    ""    '(nil :wk "local leader")))

Which-key

(use-package which-key
  :ensure nil
  :init
  (setq which-key-popup-type 'minibuffer)
  (setq which-key-dont-use-unicode nil)
  :hook
  (after-init-hook . which-key-mode))

Repeat

(use-package repeat
  :ensure nil
  :hook
  (after-init-hook . repeat-mode))

Keyboard Layout

(use-package mule
  :ensure nil
  :init
  (setq default-input-method 'russian-computer))
(use-package char-fold
  :ensure nil
  :init
  (setq char-fold-symmetric t)
  (setq search-default-mode #'char-fold-to-regexp))
(use-package reverse-im
  :general
  (evil-normal-state-map "C-х" 'evil-force-normal-state)
  (evil-insert-state-map "C-х" 'evil-normal-state)
  (evil-visual-state-map "C-х" 'evil-exit-visual-state)
  :init
  (setq reverse-im-cache-file (locate-user-emacs-file "reverse-im-cache.el"))
  (setq reverse-im-char-fold t)
  (setq reverse-im-read-char-advice-function #'reverse-im-read-char-exclude)
  (setq reverse-im-input-methods '("russian-computer"))
  :hook
  (after-init-hook . reverse-im-mode))

TTY

;; TODO: Emacs 31 (turned on by default)
(use-package xt-mouse
  :unless (display-graphic-p)
  :if (< emacs-major-version 31)
  :ensure nil
  :hook
  (after-init-hook . xterm-mouse-mode))
;; Better window divider in terminal: | -> │
;; https://www.reddit.com/r/emacs/comments/3u0d0u/how_do_i_make_the_vertical_window_divider_more/
(unless (display-graphic-p)
  (with-eval-after-load 'disp-table
    (defun +update-window-divider ()
      (let ((display-table (or buffer-display-table
                               standard-display-table))
            (divider (make-glyph-code ?│)))
        (set-display-table-slot display-table 'vertical-border divider)))
    (add-hook 'window-configuration-change-hook #'+update-window-divider)))

UI

scroll

(use-package emacs
  :ensure nil
  :init
  (setq scroll-preserve-screen-position t)
  (setq scroll-conservatively 101) ;; scroll one line at a time, no recenter
  (setq scroll-margin 4) ;; lines of context
  (setq fast-but-imprecise-scrolling t)
  (setq redisplay-skip-fontification-on-input t))
(use-package pixel-scroll
  :ensure nil
  :hook
  (after-init-hook . pixel-scroll-precision-mode))

ligatures

(use-package ligature
  :if (display-graphic-p)
  :config
  (ligature-set-ligatures
   'prog-mode
   '("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
     ":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
     "!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
     "<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
     "<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
     "..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
     "~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
     "[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
     ">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
     "<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
     "##" "#(" "#?" "#_" "%%" ".=" ".-" ".." ".?" "+>" "++" "?:"
     "?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)"
     "\\\\" "://"))
  :hook
  (after-init-hook . global-ligature-mode))

icons

nerd-icons

(use-package nerd-icons
  :if +with-icons
  :init
  (setq nerd-icons-color-icons t)
  :config
  (when (and (display-graphic-p)
             (not (member "Symbols Nerd Font Mono" (font-family-list))))
    (nerd-icons-install-fonts)))

Install fonts

(nerd-icons-install-fonts)

mode-line

(use-package bindings
  :ensure nil
  :init
  (setq mode-line-right-align-edge 'right-fringe))
(use-package hide-mode-line)
(use-package minions
  :hook
  (after-init-hook . minions-mode))

doom-modeline

(use-package doom-modeline
  :custom-face
  (mode-line ((t (:height 0.9))))
  (mode-line-active ((t (:height 0.9))))
  (mode-line-inactive ((t (:height 0.9))))
  :init
  (setq doom-modeline-icon +with-icons)
  (setq doom-modeline-modal-icon +with-icons)
  (setq doom-modeline-buffer-encoding 'nondefault)
  (setq doom-modeline-buffer-file-name-style 'buffer-name)
  (setq doom-modeline-check 'simple)
  (setq doom-modeline-unicode-number nil)
  (setq doom-modeline-workspace-name nil)
  :hook
  (after-init-hook . doom-modeline-mode))

header-line

(use-package faces
  :ensure nil
  :custom-face
  (header-line ((t (:height 0.9)))))

breadcrumb

(use-package breadcrumb
  :hook
  (after-init-hook . breadcrumb-mode))

themes

modus-themes

(use-package modus-themes
  ;; :ensure nil
  :pin melpa-stable
  :init
  (setq modus-themes-bold-constructs t)
  (setq modus-themes-italic-constructs t)
  (setq modus-themes-common-palette-overrides
        '(;; (bg-region bg-cyan-intense)
          (fg-region unspecified)
          (bg-prose-block-delimiter bg-inactive)
          (fg-prose-block-delimiter fg-dim)
          (bg-prose-block-contents bg-dim)
          (fringe unspecified)
          (border-mode-line-active unspecified)
          (border-mode-line-inactive unspecified)
          )))

ef-themes

(use-package ef-themes)

doric-themes

(use-package doric-themes)

doom-themes

(use-package doom-themes
  :init
  (setq doom-themes-enable-italic t)
  :config
  (doom-themes-org-config))
(setq +theme-alist '((default . modus-operandi)
                     (light   . modus-operandi)
                     (dark    . ef-dream)))

(defun +theme-change (appearance)
  "Load theme, taking current system APPEARANCE into consideration."
  (when-let ((theme (alist-get appearance +theme-alist)))
    (mapc #'disable-theme custom-enabled-themes)
    (load-theme theme :no-confirm)))

(defun +theme-toggle ()
  "Toggle between light and dark themes."
  (interactive)
  (if (memq (alist-get 'dark +theme-alist) custom-enabled-themes)
      (+theme-change 'light)
    (+theme-change 'dark)))

(if (and (display-graphic-p)
         (eq window-system 'ns)
         (boundp 'ns-system-appearance-change-functions))
    (add-hook 'ns-system-appearance-change-functions #'+theme-change)
  (load-theme (alist-get 'default +theme-alist) :no-confirm))

Frames

(use-package frame
  :ensure nil
  :preface
  (defun +reset-frame-parameters ()
    "Reset frame parameters to default values."
    (interactive)
    (modify-frame-parameters
     nil
     (seq-filter (lambda (param)
                   (memq (car param) '(left top width height)))
                 default-frame-alist)))
  :config
  (blink-cursor-mode -1))
(use-package fringe
  :if (display-graphic-p)
  :ensure nil
  :init
  (setf (cdr (assq 'continuation fringe-indicator-alist))
        '(nil nil) ;; no continuation indicators
        ;; '(nil right-curly-arrow) ;; right indicator only
        ;; '(left-curly-arrow nil) ;; left indicator only
        ;; '(left-curly-arrow right-curly-arrow) ;; default
        ))
(use-package default-text-scale
  :hook
  (after-init-hook . default-text-scale-mode))

Tabs

tab-bar

(use-package tab-bar
  :ensure nil
  :custom-face
  (tab-bar ((t (:height 0.9))))
  :general
  (tab-prefix-map
   "TAB" 'tab-recent
   "0" 'tab-recent
   "1" 'tab-bar-select-tab
   "2" 'tab-bar-select-tab
   "3" 'tab-bar-select-tab
   "4" 'tab-bar-select-tab
   "5" 'tab-bar-select-tab
   "6" 'tab-bar-select-tab
   "7" 'tab-bar-select-tab
   "8" 'tab-bar-select-tab
   "9" 'tab-last
   "." 'tab-switch
   "n" 'tab-new
   "[" 'tab-previous
   "]" 'tab-next
   ">" 'tab-move
   "<" 'tab-bar-move-tab-backward
   "c" 'tab-close
   "C" 'tab-close-other)
  (evil-window-map
   "u" 'tab-bar-history-back
   "U" 'tab-bar-history-forward)
  :init
  (setq tab-bar-format '(tab-bar-format-tabs-groups
                         tab-bar-separator
                         tab-bar-format-align-right
                         tab-bar-format-global))
  (setq tab-bar-close-button-show nil)
  (setq tab-bar-new-tab-choice "*scratch*")
  (setq tab-bar-tab-hints t)
  ;; (setq tab-bar-separator " ") ;; the same behavior in GUI and TUI
  (setq tab-bar-separator "")
  (setq tab-bar-auto-width nil)
  :config
  (add-to-list 'tab-bar-tab-name-format-functions
               #'tab-bar-tab-name-format-truncated)
  :hook
  (after-init-hook . tab-bar-mode)
  (after-init-hook . tab-bar-history-mode))
(use-package tab-bar-theme
  :ensure nil
  :load-path "site-lisp/tab-bar-theme"
  :hook
  (after-init-hook . tab-bar-theme-mode))
(use-package project-tab-groups
  :hook
  (after-init-hook . project-tab-groups-mode))
(use-package per-tab-group-theme
  :disabled
  :ensure nil
  :load-path "site-lisp/per-tab-group-theme"
  :hook
  (after-init-hook . per-tab-group-theme-mode))

tab-line

(use-package tab-line
  :ensure nil
  :init
  (setq tab-line-close-button-show nil)
  (setq tab-line-new-button-show nil))

Windows

window

(use-package window
  :ensure nil
  :general
  (evil-window-map
   "m" 'maximize-window
   "M" 'minimize-window))

winum

(use-package winum
  :init
  (setq winum-auto-setup-mode-line nil)
  (setq winum-scope 'frame-local)
  :hook
  (after-init-hook . winum-mode))

zoom

(use-package zoom
  :general
  (evil-window-map
   "z" 'zoom-mode)
  :init
  (setq zoom-size '(0.618 . 0.618)) ;; golden ratio
  (setq zoom-ignored-major-modes '(vundo-mode vundo-diff-mode))
  (setq zoom-ignored-buffer-names '("COMMIT_EDITMSG" " *vundo tree*"))
  (setq zoom-ignored-buffer-name-regexps '("^magit.*" "^\\*dape.*")))

shackle

shackle

(use-package shackle
  :init
  (setq shackle-default-size 0.4)
  (setq shackle-rules
        '((help-mode :align below :select t)
          (helpful-mode :align below)
          (cider-repl-mode :align below)
          (ansible-doc-module-mode :align below)
          ("\\*Async Shell Command\\*.*" :regexp t :ignore t)
          (Man-mode :align below :select t)
          ("\\*Man.*\\*" :regexp t :align below :select t)
          ;; ("*Warnings*" :align below)
          ("*Compile-Log*" :align below)
          (compilation-mode :align below)
          ("\\*vc-git :.*" :regexp t :align below :ignore t :select t)
          ("\\*docker-compose .*\\*" :regexp t :align below)
          (comint-mode :align below)
          (go-test-mode :align below)))
  :hook
  (after-init-hook . shackle-mode))

popper

popper

(use-package popper
  :disabled
  :general
  ("C-`"   'popper-toggle-latest)
  ("C-§"   'popper-toggle-latest)
  ;; ("M-`"   'popper-cycle)
  ;; ("M-~"   'popper-cycle-backwards)
  ("C-M-`" 'popper-toggle-type)
  ("C-M-§" 'popper-toggle-type)
  :init
  (setq popper-mode-line '(:eval (propertize " POP " 'face '(region bold))))
  (setq popper-display-control nil) ;; for shackle
  (setq popper-window-height 0.3)
  (setq popper-reference-buffers
        '("\\*Messages\\*"
          "Output\\*$"
          "\\*Async Shell Command\\*"
          "\\*[Wo]Man.*\\*$"
          ;; "\\*Warnings\\*"
          "\\*Compile-Log\\*"
          "\\*vc-git : .*"

          help-mode
          helpful-mode

          compilation-mode
          comint-mode

          flymake-diagnostics-buffer-mode

          cider-repl-mode
          ansible-doc-module-mode))
  :hook
  (after-init-hook . popper-mode))

(use-package popper-echo
  :disabled
  :ensure popper
  :init
  (setq popper-echo-dispatch-actions t)
  (setq popper-echo-lines 3)
  :hook
  (after-init-hook . popper-echo-mode)
  ;; (after-init-hook . popper-tab-line-mode)
  )

Buffers

common

(use-package uniquify
  :ensure nil
  :init
  (setq uniquify-buffer-name-style 'forward))

ibuffer

(use-package ibuffer
  :ensure nil
  :general
  ([remap list-buffers] 'ibuffer)
  :init
  (setq ibuffer-human-readable-size t) ;; emacs 31
  )
(use-package ibuffer-vc
  :disabled ;; replaced by projection-ibuffer
  :preface
  (defun +setup-ibuffer-vc ()
    (ibuffer-vc-set-filter-groups-by-vc-root)
    (unless (eq ibuffer-sorting-mode 'alphabetic)
      (ibuffer-do-sort-by-alphabetic)))
  :hook
  (ibuffer-hook . +setup-ibuffer-vc))
;; not only icons, but also other customizations (e.g. human-readable size, colors, etc.)
(use-package nerd-icons-ibuffer
  ;; :if +with-icons
  :init
  (setq nerd-icons-ibuffer-icon +with-icons)
  :hook
  (ibuffer-mode-hook . nerd-icons-ibuffer-mode))

persistent-scratch

(use-package persistent-scratch
  :init
  (setq persistent-scratch-backup-file-name-format "%Y-%m-%d")
  (setq persistent-scratch-backup-directory
        (expand-file-name "persistent-scratch" user-emacs-directory))
  :hook
  (after-init-hook . persistent-scratch-setup-default))

History

(use-package savehist
  :ensure nil
  :hook
  (after-init-hook . savehist-mode))
(use-package saveplace
  :ensure nil
  :hook
  (after-init-hook . save-place-mode))
(use-package recentf
  :ensure nil
  :init
  (setq recentf-max-saved-items 300)
  :hook
  (after-init-hook . recentf-mode))

Session Manager

desktop

(use-package desktop
  :ensure nil
  :init
  (setq desktop-path `(,user-emacs-directory))
  :config
  (dolist (mode '(git-commit-mode))
    (add-to-list 'desktop-modes-not-to-save mode)))

Completion

emacs

(use-package emacs
  :ensure nil
  :init
  (setq completion-ignore-case t)
  (setq read-buffer-completion-ignore-case t)
  (setq enable-recursive-minibuffers t)

  ;; Emacs 30 and newer: Disable Ispell completion function.
  ;; Try `cape-dict' as an alternative.
  (setq text-mode-ispell-word-completion nil)

  ;; Hide commands in M-x which do not apply to the current mode.  Corfu
  ;; commands are hidden, since they are not used via M-x. This setting is
  ;; useful beyond Corfu.
  (setq read-extended-command-predicate #'command-completion-default-include-p)

  ;; Do not allow the cursor in the minibuffer prompt
  (setq minibuffer-prompt-properties
        '(read-only t cursor-intangible t face minibuffer-prompt))
  :hook
  (minibuffer-setup-hook . cursor-intangible-mode))
(use-package mouse
  :ensure nil
  :if (display-graphic-p)
  :hook
  (after-init-hook . context-menu-mode))
(use-package nerd-icons-completion
  :if +with-icons
  :hook
  (vertico-mode-hook    . nerd-icons-completion-mode)
  (marginalia-mode-hook . nerd-icons-completion-marginalia-setup))

consult

(use-package consult
  :general
  ([remap apropos]                       'consult-apropos)
  ([remap bookmark-jump]                 'consult-bookmark)
  ([remap goto-line]                     'consult-goto-line)
  ([remap imenu]                         'consult-imenu)
  ([remap locate]                        'consult-locate)
  ([remap load-theme]                    'consult-theme)
  ([remap man]                           'consult-man)
  ([remap recentf-open-files]            'consult-recent-file)
  ([remap switch-to-buffer]              'consult-buffer)
  ([remap switch-to-buffer-other-window] 'consult-buffer-other-window)
  ([remap switch-to-buffer-other-frame]  'consult-buffer-other-frame)
  ([remap yank-pop]                      'consult-yank-pop)
  ([remap project-find-regexp]           'consult-ripgrep)
  :init
  (setq register-preview-delay 0)
  (setq register-preview-function #'consult-register-format)
  (advice-add #'register-preview :override #'consult-register-window)
  :hook
  (completion-list-mode-hook . consult-preview-at-point-mode))
(use-package consult-xref
  :ensure consult
  :init
  (setq xref-show-xrefs-function #'consult-xref)
  (setq xref-show-definitions-function #'consult-xref))
(use-package nerd-icons-xref
  :if +with-icons
  :hook
  (after-init-hook . nerd-icons-xref-mode))
(use-package consult-dir
  :general
  ([remap list-directory] 'consult-dir))
(use-package consult-todo
  :general
  (project-prefix-map
   "T" 'consult-todo-project))

marginalia

(use-package marginalia
  :general
  (minibuffer-local-map
    "M-A" 'marginalia-cycle)
  :hook
  (after-init-hook . marginalia-mode))

vertico

(use-package vertico
  :general
  (vertico-map
   "C-j" 'vertico-next
   "C-k" 'vertico-previous)
  :init
  (setq vertico-cycle t)
  :hook
  (after-init-hook . vertico-mode))
(use-package vertico-directory
  :ensure vertico
  :general
  (vertico-map
   "DEL" 'vertico-directory-delete-char)
  :hook
  (rfn-eshadow-update-overlay-hook . vertico-directory-tidy))

vertico-posframe

(use-package vertico-posframe
  :disabled ;; by performance reasons (try again in emacs 31 with feature `tty-child-frames')
  :init
  (setq vertico-posframe-poshandler #'posframe-poshandler-frame-center)
  (setq vertico-posframe-parameters
        '((left-fringe . 8)
          (right-fringe . 8)))
  :hook
  (vertico-mode-hook . vertico-posframe-mode))

orderless

(use-package orderless
  :init
  (setq completion-styles '(orderless))
  (setq orderless-matching-styles '(orderless-literal
                                    ;; orderless-flex
                                    orderless-prefixes
                                    orderless-regexp))
  (setq completion-category-overrides '((file (styles . (partial-completion))))))

corfu

(use-package corfu
  :general
  ("M-S-SPC" 'completion-at-point)
  :init
  (setq corfu-auto t)
  (setq corfu-cycle t)
  (setq corfu-min-width 40)
  :hook
  (after-init-hook . global-corfu-mode))
(use-package corfu-echo
  :ensure corfu
  :hook
  (corfu-mode-hook . corfu-echo-mode))
(use-package corfu-info
  :ensure corfu
  :unless (display-graphic-p)
  :after corfu
  :general
  (corfu-map
   "C-h" 'corfu-info-documentation))
(use-package corfu-popupinfo
  :ensure corfu
  :if (display-graphic-p)
  :general
  (corfu-map
   "C-h" 'corfu-popupinfo-documentation)
  :init
  (setq corfu-popupinfo-delay nil)
  :hook
  (corfu-mode-hook . corfu-popupinfo-mode))
(use-package corfu-history
  :ensure corfu
  :hook
  (corfu-mode-hook . corfu-history-mode))
(use-package corfu-terminal
  :if (< emacs-major-version 31)
  :unless (featurep 'tty-child-frames)
  :unless (display-graphic-p)
  :hook
  (corfu-mode-hook . corfu-terminal-mode))
(use-package kind-icon
  :unless +with-icons
  :after corfu
  :demand
  :preface
  (defun +kind-icon-reset-cache (theme)
    (call-interactively 'kind-icon-reset-cache))
  :init
  (setq kind-icon-default-face 'corfu-default)
  (setq kind-icon-blend-background t)
  (setq kind-icon-use-icons nil)
  (setq kind-icon-extra-space nil)
  :config
  (add-to-list 'corfu-margin-formatters #'kind-icon-margin-formatter)
  (advice-add #'disable-theme :before #'+kind-icon-reset-cache))
(use-package nerd-icons-corfu
  :if +with-icons
  :after corfu
  :init
  (add-to-list 'corfu-margin-formatters #'nerd-icons-corfu-formatter))

cape

(use-package cape
  :general
  ("C-c p" 'cape-prefix-map)
  :hook
  ;; Add to the global default value of `completion-at-point-functions' which is
  ;; used by `completion-at-point'.  The order of the functions matters, the
  ;; first function returning a result wins.  Note that the list of buffer-local
  ;; completion functions takes precedence over the global list.
  (completion-at-point-functions . cape-dabbrev)
  (completion-at-point-functions . cape-file)
  (completion-at-point-functions . cape-elisp-block))

embark

(use-package embark
  :general
  ("C-;" #'embark-act)
  (help-map
   "B" #'embark-bindings)
  :init
  (setq prefix-help-command #'embark-prefix-help-command)
  :config
  (add-to-list 'display-buffer-alist
               '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
                 nil
                 (window-parameters (mode-line-format . none)))))
(use-package embark-consult
  :hook
  (embark-collect-mode-hook . consult-preview-at-point-mode))

templ

(use-package tempel
  :preface
  (defun tempel-setup-capf ()
    ;; Add the Tempel Capf to `completion-at-point-functions'.  `tempel-expand'
    ;; only triggers on exact matches. We add `tempel-expand' *before* the main
    ;; programming mode Capf, such that it will be tried first.
    (setq-local completion-at-point-functions
                (cons #'tempel-expand completion-at-point-functions)))
  :general
  (tempel-map
    "TAB" 'tempel-next)
  :hook
  (conf-mode-hook . tempel-setup-capf)
  (prog-mode-hook . tempel-setup-capf)
  (text-mode-hook . tempel-setup-capf)
  ;; Optionally make the Tempel templates available to Abbrev,
  ;; either locally or globally. `expand-abbrev' is bound to C-x '.
  (after-init-hook . global-tempel-abbrev-mode))
(use-package tempel-collection)

Files

(use-package files
  :ensure nil
  :preface
  (defun +find-file-in-dir (dir)
    "Open a file starting in DIR."
    (interactive "DDirectory: ")
    (let ((default-directory (file-name-as-directory dir)))
      (call-interactively #'find-file)))
  :init
  (setq require-final-newline t)
  (setq make-backup-files nil)
  (setq auto-save-default nil))
(use-package autorevert
  :ensure nil
  :init
  (setq global-auto-revert-non-file-buffers t)
  :hook
  (after-init-hook . global-auto-revert-mode))
(use-package iqa
  :preface
  ;; for integration with project-tab-groups
  (defun +iqa-find-file-project (file)
    (let* ((dir (file-name-directory file))
           (default-directory dir))
      (project-current t)
      (find-file file)))
  :init
  (setq iqa-find-file-function #'+iqa-find-file-project)
  (setq iqa-user-init-file (locate-user-emacs-file "config.org")))
(use-package epg-config
  :ensure nil
  :init
  (setq epg-pinentry-mode 'loopback))

Projects

(use-package project
  :ensure nil
  :general
  (project-prefix-map
    "m" 'magit-project-status
    "b" 'consult-project-buffer)
  :init
  (setq project-buffers-viewer 'project-list-buffers-ibuffer)
  (setq project-kill-buffers-display-buffer-list t)
  (setq project-switch-commands
        '((project-find-file "Find file")
          (project-find-regexp "Find regexp")
          (project-find-dir "Find directory")
          (magit-project-status "Magit")))
  (setq project-vc-extra-root-markers '(".project")))

disproject

(use-package disproject
  :general
  (project-prefix-map
    "." 'disproject-dispatch))

projection

(use-package projection
  :general
  (project-prefix-map
    "P" '(:keymap projection-map :package projection-map :wk "projection"))
  :config
  (put 'projection-commands-configure-project 'safe-local-variable #'stringp)
  (put 'projection-commands-build-project     'safe-local-variable #'stringp)
  (put 'projection-commands-test-project      'safe-local-variable #'stringp)
  (put 'projection-commands-run-project       'safe-local-variable #'stringp)
  (put 'projection-commands-package-project   'safe-local-variable #'stringp)
  (put 'projection-commands-install-project   'safe-local-variable #'stringp)
  :hook
  (after-init-hook . global-projection-hook-mode))
(use-package projection-ibuffer
  :ensure projection
  :after ibuffer
  :demand t
  :preface
  (defun +projection-ibuffer-setup ()
    (setq ibuffer-filter-groups (projection-ibuffer--filter-groups))
    (unless (eq ibuffer-sorting-mode 'alphabetic)
      (ibuffer-do-sort-by-alphabetic)))
  :hook
  (ibuffer-hook . +projection-ibuffer-setup))
(use-package projection-multi
  :general
  (project-prefix-map
    "RET" 'projection-multi-compile))

(use-package projection-multi-embark
  :after embark
  :after projection-multi
  :demand t
  :config
  (projection-multi-embark-setup-command-map))

project-butler

(use-package project-butler
  :disabled
  :after project
  :demand
  :general
  (project-prefix-map
    "K" 'project-butler-cleanup)
  :config
  (add-to-list
   'project-butler-projects-list
   `(,user-emacs-directory . ("" ("config.org"))))
  (add-to-list
   'project-butler-projects-list
   `(,(file-name-as-directory org-directory)
     . ("1|2" (,+org-notes-file ,+org-todo-file)))))

Dired

(use-package dired
  :ensure nil
  :init
  (setq dired-listing-switches
        (concat
         "-l "                        ;; long listing (dired requires this)
         "--almost-all "              ;; show hidden files, but not . or ..
         "--no-group "                ;; do not show group, only owner
         ;; conflict w/ `dired-sidebar-follow-file'
         ;; "--classify "                ;; append indicator (one of */=>@|) to entries
         "--human-readable "          ;; print sizes in human readable format
         "--sort=version "            ;; sort by version number (netural order)
         "--group-directories-first " ;; group directories first
         "--time-style=long-iso"      ;; use ISO 8601 date format (YYYY-MM-DD HH:MM)
         ))
  (setq dired-auto-revert-buffer t)
  (setq dired-dwim-target t)
  (setq dired-recursive-copies 'always)
  (setq dired-recursive-deletes 'always)
  (setq dired-hide-details-hide-symlink-targets nil)
  (setq dired-mouse-drag-files t)
  (setq mouse-drag-and-drop-region-cross-program t)
  (setq dired-free-space nil)
  (setq dired-hide-details-hide-absolute-location t) ;; emacs 31
  :config
  (when (eq system-type 'darwin)
    (setq insert-directory-program "gls"))
  :hook
  (dired-mode-hook . dired-hide-details-mode))
(use-package dired-aux
  :ensure nil
  :init
  (setq dired-vc-rename-file t)
  (setq dired-create-destination-dirs 'ask))
(use-package dired-x
  :ensure nil
  :after dired
  :defer nil
  :general
  ( :keymaps 'dired-mode-map :states 'normal
    "M-." 'dired-omit-mode)
  :init
  (setq dired-omit-extensions nil)
  :config
  ;; Make dired-omit-mode hide all "dotfiles"
  (setq dired-omit-files
        (concat dired-omit-files "\\|^\\..*$")))

dired-hacks

(use-package dired-subtree
  :unless +with-dirvish
  :demand t
  :after dired
  :general
  (dired-mode-map
   "<backtab>" 'dired-subtree-cycle)
  :init
  (setq dired-subtree-use-backgrounds nil)
  ;; Tabs scale with `text-scale-adjust', plain spaces don't.
  ;; Avoid artifacts when `dired-subtree' is used together with `nerd-icons-dired' and scaled fonts.
  (when +with-icons
    (setq dired-subtree-line-prefix "\t\t")))

diredfl

(use-package diredfl
  :custom-face
  (diredfl-dir-name ((t (:bold t))))
  :hook
  (dired-mode-hook . diredfl-mode))
(use-package nerd-icons-dired
  :if +with-icons
  :unless +with-dirvish
  :preface
  (defvar-local +nerd-icons-dired--refresh-timer nil)
  (defun +nerd-icons-dired--refresh (orig-fn &rest _)
    "Debounced advice for `nerd-icons-dired--refresh'."
    (when (derived-mode-p 'dired-mode)
      (when (timerp +nerd-icons-dired--refresh-timer)
        (cancel-timer +nerd-icons-dired--refresh-timer))
      (setq +nerd-icons-dired--refresh-timer
            (run-with-timer
             0.01 nil
             (lambda (buf f)
               (when (buffer-live-p buf)
                 (with-current-buffer buf
                   (when (bound-and-true-p nerd-icons-dired-mode)
                     (funcall f)))))
             (current-buffer) orig-fn))))
  :config
  (advice-add 'nerd-icons-dired--refresh :around #'+nerd-icons-dired--refresh)
  :hook
  (dired-mode-hook . nerd-icons-dired-mode)
  (dired-subtree-after-insert-hook . nerd-icons-dired--refresh))
(use-package nerd-icons-multimodal
  :disabled ;; conflicts with dired-sidebar
  :if +with-icons
  :vc (:url "https://github.com/abougouffa/nerd-icons-multimodal" :rev :newest)
  :hook
  (dired-mode-hook   . nerd-icons-multimodal-mode)
  (archive-mode-hook . nerd-icons-multimodal-mode)
  (tar-mode-hook     . nerd-icons-multimodal-mode))
(use-package dired-git-info
  :general
  ( :keymaps 'dired-mode-map :states 'normal
    ")" 'dired-git-info-mode)
  :init
  (setq dgi-auto-hide-details-p nil))

dired-sidebar

(use-package dired-sidebar
  :unless +with-dirvish
  :autoload dired-sidebar-showing-sidebar-p
  :preface
  (defun +dired-sidebar-follow-file ()
    (interactive)
    (if (dired-sidebar-showing-sidebar-p)
        (dired-sidebar-follow-file)
      (dired-sidebar-jump-to-sidebar)))
  :init
  ;; (setq dired-sidebar-theme (if +with-icons 'nerd-icons 'none))
  (setq dired-sidebar-theme 'none) ;; don't need dired-sidebar's customizations for nerd-icons, it's flickery and buggy, just use nerd-icons-dired
  ;; (setq dired-sidebar-use-custom-modeline nil)
  (setq dired-sidebar-use-custom-modeline t)
  (setq dired-sidebar-mode-line-format nil) ;; hide mode-line
  (setq dired-sidebar-no-delete-other-windows t)
  (setq dired-sidebar-toggle-hidden-commands nil) ;; don't hide on `balance-windows'
  ;; (setq dired-sidebar-window-fixed nil)
  (setq dired-sidebar-use-custom-font t) ;; to custom `dired-sidebar-face'
  (setq dired-sidebar-face '(:height 0.9))
  (setq dired-sidebar-refresh-on-project-switch nil)
  :config
  (with-eval-after-load 'winum
    (defun winum-assign-0-to-dired-sidebar ()
      (when (and (eq major-mode 'dired-sidebar-mode)
                 (eq (selected-window) (frame-first-window)))
        0))
    (add-to-list 'winum-assign-functions #'winum-assign-0-to-dired-sidebar)))

Dirvish

(use-package dirvish
  :if +with-dirvish
  :custom-face
  (dirvish-hl-line ((t (:inherit hl-line))))
  :general
  ( :keymaps 'dirvish-mode-map :states 'normal
    "q" 'dirvish-quit)
  :init
  (when +with-icons
    (setq dirvish-attributes '(nerd-icons)))
  (setq dirvish-path-separators '("  ~" "" "/"))
  :config
  (with-eval-after-load 'doom-modeline
    (setq dirvish-mode-line-bar-image-width doom-modeline-bar-width)
    (setq dirvish-mode-line-height doom-modeline-height)
    (setq dirvish-header-line-height doom-modeline-height))
  (with-eval-after-load 'winum
    (dirvish-define-mode-line winum
      "A `winum-mode' indicator."
      (and (bound-and-true-p winum-mode)
           (let ((num (winum-get-number-string)))
             (propertize (format " %s " num)
                         'face 'winum-face))))
    (setq dirvish-mode-line-format
          '( :left  (winum sort)
             :right (omit yank))))
  :hook
  (after-init-hook . dirvish-override-dired-mode))
(use-package dirvish-subtree
  :if +with-dirvish
  :ensure dirvish
  :general
  ( :keymaps 'dirvish-mode-map :states 'normal
    "TAB" 'dirvish-subtree-toggle)
  :init
  (setq dirvish-subtree-prefix "  "))
(use-package dirvish-side
  :if +with-dirvish
  :ensure dirvish
  :autoload
  dirvish-side--session-visible-p
  dirvish-side--auto-jump
  :preface
  (defun +dirvish-side-follow-file ()
    (interactive)
    (if (dirvish-side--session-visible-p)
        (dirvish-side--auto-jump)
      (dirvish-side)))
  (defvar-local +dirvish-side-font-applied nil)
  (defun +dirvish-side-set-font (&rest _)
    (when-let* ((side-window (dirvish-side--session-visible-p))
                (side-buffer (window-buffer side-window)))
      (with-current-buffer side-buffer
        (unless +dirvish-side-font-applied
          (setq-local +dirvish-side-font-applied t)
          (buffer-face-set '(:height 0.9))))))
  :init
  (setq dirvish-side-window-parameters '((no-delete-other-windows . t)))
  :config
  (with-eval-after-load 'winum
    (defun winum-assign-0-to-dirvish-side ()
      (when (and (functionp 'dirvish-side--session-visible-p)
                 (eq (selected-window) (dirvish-side--session-visible-p))
                 (eq (selected-window) (frame-first-window)))
        0))
    (add-to-list 'winum-assign-functions #'winum-assign-0-to-dirvish-side))
  ;; update buffer face
  (advice-add 'dirvish-side :after #'+dirvish-side-set-font))

Environment Variables

$PATH from user’s shell

(use-package exec-path-from-shell
  :if (or (memq window-system '(mac ns x)) (daemonp))
  :demand
  :init
  (setq exec-path-from-shell-arguments '("-l"))
  :config
  (exec-path-from-shell-initialize))

Use the emacsclient as the $EDITOR of child processes

(use-package with-editor
  :general
  ([remap shell-command]       'with-editor-shell-command)
  ([remap async-shell-command] 'with-editor-async-shell-command)
  :hook
  (shell-mode-hook   . with-editor-export-editor)
  (term-exec-hook    . with-editor-export-editor)
  (eshell-mode-hook  . with-editor-export-editor))

Help

(use-package help
  :ensure nil
  :general
  (help-map
   "F" 'describe-face))
(use-package helpful
  :general
  ([remap describe-command]             'helpful-command)
  ([remap describe-key]                 'helpful-key)
  ([remap describe-variable]            'helpful-variable)
  ([remap describe-function]            'helpful-callable)
  ([remap Info-goto-emacs-command-node] 'helpful-function)
  (help-map
   "." 'helpful-at-point))

Editor

(use-package emacs
  :ensure nil
  :init
  (setq-default tab-width 4)
  (setq-default indent-tabs-mode nil))
(use-package delsel
  :ensure nil
  :general
  ("C-c C-g" 'minibuffer-keyboard-quit)
  :hook
  (after-init-hook . delete-selection-mode))
(use-package simple
  :ensure nil
  :hook
  (after-init-hook . column-number-mode))
(use-package prog-mode
  :ensure nil
  :hook
  (after-init-hook . global-prettify-symbols-mode))
(use-package so-long
  :ensure nil
  :hook
  (after-init-hook . global-so-long-mode))
(use-package hungry-delete
  :hook
  (after-init-hook . global-hungry-delete-mode))
(use-package elec-pair
  :ensure nil
  :hook
  (after-init-hook . electric-pair-mode))

Ediff

(use-package ediff
  :ensure nil
  :init
  (setq ediff-window-setup-function 'ediff-setup-windows-plain)
  (setq ediff-split-window-function 'split-window-horizontally)
  (setq ediff-merge-split-window-function 'split-window-horizontally)
  :hook
  (ediff-prepare-buffer-hook . show-all)
  (ediff-quit-hook . winner-undo))

Undo/Redo

undo-fu-session

(use-package undo-fu-session
  :init
  (setq undo-fu-session-incompatible-files '("/COMMIT_EDITMSG\\'" "/git-rebase-todo\\'"))
  :hook
  (after-init-hook . undo-fu-session-global-mode))

vundo

(use-package vundo
  :general
  ("C-x u" 'vundo)
  :custom-face
  (vundo-highlight  ((t (:inherit success :foreground unspecified))))
  (vundo-last-saved ((t (:inherit error   :foreground unspecified))))
  (vundo-saved      ((t (:inherit warning :foreground unspecified))))
  :config
  (setq vundo-compact-display t)
  (setq vundo-glyph-alist vundo-unicode-symbols))

Highlighting

hl-line

(use-package hl-line
  :ensure nil
  :preface
  (defun +disable-global-hl-line-mode ()
    (setq-local global-hl-line-mode nil))
  :hook
  (after-init-hook . global-hl-line-mode))

paren

(use-package paren
  :ensure nil
  :init
  (setq show-paren-when-point-inside-paren t)
  (setq show-paren-when-point-in-periphery t)
  :hook
  (after-init-hook . show-paren-mode))

paren-face

(use-package paren-face
  :hook
  (after-init-hook . global-paren-face-mode))

colorful-mode

(use-package colorful-mode)

page-break-lines

(use-package page-break-lines
  :hook
  (after-init-hook . global-page-break-lines-mode))

highlight-indent-guides

(use-package highlight-indent-guides
  :init
  (setq highlight-indent-guides-method 'character)
  (setq highlight-indent-guides-responsive 'top))

hl-todo

(use-package hl-todo
  :init
  (setq hl-todo-highlight-punctuation ":")
  ;; stolen from doom-emacs
  (setq hl-todo-keyword-faces
        '(;; For reminders to change or add something at a later date.
          ("TODO" warning bold)
          ;; For code (or code paths) that are broken, unimplemented, or slow,
          ;; and may become bigger problems later.
          ("FIXME" error bold)
          ;; For code that needs to be revisited later, either to upstream it,
          ;; improve it, or address non-critical issues.
          ("REVIEW" font-lock-keyword-face bold)
          ;; For code smells where questionable practices are used
          ;; intentionally, and/or is likely to break in a future update.
          ("HACK" font-lock-constant-face bold)
          ;; For sections of code that just gotta go, and will be gone soon.
          ;; Specifically, this means the code is deprecated, not necessarily
          ;; the feature it enables.
          ("DEPRECATED" font-lock-doc-face bold)
          ;; Extra keywords commonly found in the wild, whose meaning may vary
          ;; from project to project.
          ("NOTE" success bold)
          ("BUG" error bold)
          ("XXX" font-lock-constant-face bold)))
  :hook
  (after-init-hook . global-hl-todo-mode))

Line Numbers

(use-package display-line-numbers
  :ensure nil
  :init
  (setq display-line-numbers-width-start t))

Search

(use-package anzu
  :init
  (setq anzu-cons-mode-line-p nil)
  :hook
  (after-init-hook . global-anzu-mode))
(use-package evil-anzu
  :if +with-evil
  :demand
  :after evil anzu)

Folding

(use-package hideshow
  :ensure nil
  :hook
  (prog-mode-hook . hs-minor-mode))
(use-package outline-indent
  :hook
  (yaml-ts-mode-hook . outline-indent-minor-mode))

Spell Checking

jinx

(use-package jinx
  :general
  ([remap ispell-word] 'jinx-correct)
  :init
  (setq jinx-languages "ru en es")
  :hook
  (text-mode-hook       . jinx-mode)
  (org-mode-hook        . jinx-mode)
  ;; (prog-mode-hook       . jinx-mode)
  (git-commit-mode-hook . jinx-mode))

Syntax Checking

flymake

(use-package flymake
  :ensure nil
  :general
  (project-prefix-map
    "D" 'flymake-show-project-diagnostics)
  :init
  (setq flymake-fringe-indicator-position 'right-fringe)
  (setq flymake-margin-indicator-position 'right-margin)
  :hook
  (prog-mode-hook . flymake-mode))
(use-package sideline
  :init
  (setq sideline-backends-right '(sideline-flymake))
  (setq sideline-display-backend-name t))
(use-package sideline-flymake
  :init
  (setq sideline-flymake-display-mode 'point)
  :hook
  (flymake-mode-hook . sideline-mode))

Eval

eros

(use-package eros
  :custom-face
  (eros-result-overlay-face ((t (:inherit shadow :box t))))
  :hook
  (emacs-lisp-mode-hook . eros-mode))

quickrun

(use-package quickrun)

Format

apheleia

(use-package apheleia
  :hook
  (after-init-hook . apheleia-global-mode))

Goto

xref

(use-package xref
  :ensure nil
  :init
  (setq xref-search-program 'ripgrep))

avy

(use-package avy
  :init
  (setq avy-background t))
(use-package link-hint)

Terminal

vterm

(use-package vterm
  :init
  (setq vterm-shell "/opt/homebrew/bin/fish")
  (setq vterm-max-scrollback 10000)
  :config
  ;; https://github.com/akermu/emacs-libvterm/issues/313#issuecomment-1183650463
  (advice-add #'vterm--redraw :around (lambda (fun &rest args) (let ((cursor-type cursor-type)) (apply fun args))))
  :hook
  (vterm-mode-hook . +disable-global-hl-line-mode))
(use-package project-vterm
  :ensure nil
  :load-path "site-lisp/project-vterm"
  :general
  (project-prefix-map
    "t" 'project-vterm)
  :config
  (add-to-list 'project-switch-commands '(project-vterm "Vterm") t)
  (add-to-list 'project-kill-buffer-conditions '(major-mode . vterm-mode)))

eat

(use-package eat
  :hook
  (eat-mode-hook . +disable-global-hl-line-mode))
(use-package project-eat
  :ensure nil
  :load-path "site-lisp/project-eat"
  :general
  (project-prefix-map
    "E" 'project-eat)
  :config
  (add-to-list 'project-switch-commands '(project-eat "Eat") t)
  (add-to-list 'project-kill-buffer-conditions '(major-mode . eat-mode)))

Git

magit

(use-package magit
  :init
  (setq magit-define-global-key-bindings 'recommended)
  (setq magit-display-buffer-function 'magit-display-buffer-same-window-except-diff-v1)
  (setq magit-repository-directories `((,user-emacs-directory . 0)
                                       ("~/Projects/"         . 2)
                                       ("~/Developer/"        . 2)))
  (setq magit-diff-refine-hunk t)
  (setq magit-process-apply-ansi-colors t)
  (when +with-icons
    (setq magit-format-file-function #'magit-format-file-nerd-icons)))

magit-prime

(use-package magit-prime
  :hook
  (after-init-hook . magit-prime-mode))

magit-todos

(use-package magit-todos
  :init
  (setq magit-todos-keyword-suffix (rx (optional "(" (1+ (not (any ")"))) ")" ":")))
  (put 'magit-todos-exclude-globs 'safe-local-variable #'listp)
  :hook
  (magit-mode-hook . magit-todos-mode))

git-modes

Major modes for .gitignore, .gitconfig, .gitattributes, .gitmodules files.

(use-package git-modes
  :mode ("/.dockerignore\\'" . gitignore-mode))

diff-hl

(use-package diff-hl
  :vc (:url "https://github.com/rynffoll/diff-hl" :branch "dired-nested-paths" :rev :newest)
  :preface
  (defun +diff-hl-fringe-bmp-empty (_type _pos) 'diff-hl-bmp-empty)
  ;; https://github.com/dgutov/diff-hl/issues/116#issuecomment-1573253134
  (let* ((width 4)
         (bitmap (vector (1- (expt 2 width)))))
    (define-fringe-bitmap '+diff-hl-bmp-thin bitmap 1 width '(top t)))
  (defun +diff-hl-fringe-bmp-thin (_type _pos) '+diff-hl-bmp-thin)
  (defun +diff-hl-update-faces (&optional _theme)
    "Adapt diff-hl faces for fringe bitmap rendering.
Fringe bitmaps use the face foreground color, not background.
Move each face's background color to foreground and clear the
background so our thin bitmap displays the indicator color correctly.
Covers both working-tree faces and reference-revision faces."
    (when (display-graphic-p)
      (dolist (face '(diff-hl-insert
                      diff-hl-delete
                      diff-hl-change
                      diff-hl-reference-insert
                      diff-hl-reference-delete
                      diff-hl-reference-change))
        (when-let ((bg (face-background face nil t)))
          (set-face-foreground face bg) ;; fg -> bg
          (set-face-background face nil) ;; bg -> nil (transparent)
          ))))
  :init
  (setq diff-hl-disable-on-remote t)
  (setq diff-hl-update-async 'thread)
  (setq diff-hl-draw-borders nil)
  (setq diff-hl-margin-symbols-alist
        '((insert . " ") (delete . " ") (change . " ")
          (unknown . " ") (ignored . " ") (reference . " ")))
  ;; (setq diff-hl-fringe-bmp-function #'+diff-hl-fringe-bmp-empty)
  (setq diff-hl-fringe-bmp-function #'+diff-hl-fringe-bmp-thin)
  (setq diff-hl-fringe-flat-bmp '+diff-hl-bmp-thin)
  :hook
  (after-init-hook . global-diff-hl-mode)
  (after-init-hook . global-diff-hl-show-hunk-mouse-mode)
  (magit-post-refresh-hook . diff-hl-magit-post-refresh)
  (diff-hl-mode-hook . +diff-hl-update-faces)
  (enable-theme-functions . +diff-hl-update-faces))
(use-package diff-hl-flydiff
  :ensure diff-hl
  :init
  (setq diff-hl-flydiff-delay 0.5)
  :hook
  (diff-hl-mode-hook . diff-hl-flydiff-mode))
(use-package diff-hl-dired
  :ensure diff-hl
  :preface
  (defun +diff-hl-dired-update ()
    (when (bound-and-true-p diff-hl-dired-mode)
      (diff-hl-dired-update)))
  :init
  (setq diff-hl-dired-extra-indicators nil)
  ;; (setq diff-hl-dired-fringe-bmp-function #'+diff-hl-fringe-bmp-empty)
  (setq diff-hl-dired-fringe-bmp-function #'+diff-hl-fringe-bmp-thin)
  :config
  ;; diff-hl overlays are zero-width (point, point) and survive `delete-region'
  ;; — they leak onto the next visible line. Remove them before subtree deletion.
  (define-advice dired-subtree-remove (:before () clean-diff-hl-overlays)
    "Remove diff-hl overlays in subtree region before deletion."
    (when (bound-and-true-p diff-hl-dired-mode)
      (-when-let (ov (dired-subtree--get-ov))
        (diff-hl-remove-overlays (overlay-start ov) (overlay-end ov)))))
  :hook
  (dired-mode-hook . diff-hl-dired-mode-unless-remote)
  (dired-subtree-after-insert-hook . +diff-hl-dired-update)
  (diff-hl-dired-mode-hook . +diff-hl-update-faces))

git-link

(use-package git-link)

consult-git-log-grep

(use-package consult-git-log-grep
  :init
  (setq consult-git-log-grep-open-function #'magit-show-commit))

difftastic

(use-package difftastic
  :hook
  (after-init-hook . difftastic-bindings-mode))

git-timemachine

(use-package git-timemachine)

Org

common

(use-package org
  :ensure nil
  :init
  (setq org-modules nil)

  (setq org-directory "~/Org")

  ;; (setq org-startup-folded 'overview)
  (setq org-startup-indented t)
  (setq org-insert-heading-respect-content t)
  (setq org-hide-leading-stars t)

  (setq org-agenda-files '("todo.org"))
  (setq org-agenda-inhibit-startup t)
  (setq org-agenda-skip-unavailable-files t)

  (setq org-auto-align-tags nil)
  (setq org-tags-column 0)

  (setq org-ellipsis "")
  ;; (setq org-ellipsis " ⌄ ")
  (setq org-pretty-entities t)
  ;; (setq org-hide-emphasis-markers t)
  (setq org-use-sub-superscripts '{}) ;; allow _ and ^ characters to sub/super-script strings but only when string is wrapped in braces

  (setq org-use-fast-todo-selection 'expert)
  (setq org-todo-keywords '((sequence
                             "TODO(t)"
                             "STARTED(s)"
                             "NEXT(n)"
                             "WAITING(w)"
                             "HOLD(h)"
                             "|"
                             "DONE(d)"
                             "OBSOLETE(o)"
                             "CANCELLED(c)")))

  (setq org-log-done 'time)

  (setq org-startup-with-inline-images t) ;; TODO: emacs 31 (org 9.8): renamed to `org-startup-with-link-previews'
  (setq org-startup-with-link-previews t) ;; TODO: emacs 31 (org 9.8)

  (setq org-fontify-whole-heading-line t)
  (setq org-fontify-done-headline nil)

  (setq org-imenu-depth 6))

org-archive

(use-package org-archive
  :ensure org
  :init
  (setq org-archive-location (concat org-directory "/archive.org::datetree/"))
  (setq org-archive-file-header-format nil))

org-refile

(use-package org-refile
  :ensure org
  :preface
  ;; https://github.com/progfolio/.emacs.d#refile
  (defun +org-files-list ()
    "Returns a list of the file names for currently open Org files"
    (delq nil
          (mapcar (lambda (buffer)
                    (when-let* ((file-name (buffer-file-name buffer))
                                (directory (file-name-directory file-name)))
                      (unless (string-suffix-p "archives/" directory)
                        file-name)))
                  (org-buffer-list 'files t))))
  :init
  (setq org-refile-targets `((org-agenda-files :maxlevel . 3)
                             (+org-files-list  :maxlevel . 3)))
  (setq org-refile-use-outline-path 'file)
  (setq org-outline-path-complete-in-steps nil)
  (setq org-refile-allow-creating-parent-nodes 'confirm)
  (setq org-refile-use-cache t))

org-link

(use-package ol
  :ensure org
  :preface
  ;; source: https://gist.github.com/kim366/8abe978cc295b027df636b218862758e
  (defun +org-link-get-title (link &optional description)
    (cond
     ((string-match-p "^http" link)
      (with-temp-buffer
        (url-insert-file-contents link)
        (goto-char (point-min))
        (search-forward-regexp (rx "<title" (* (not (any ">"))) ">" (group (*? anything)) "</title>"))
        (match-string 1)))))
  :init
  (setq org-link-make-description-function #'+org-link-get-title))

org-src

(use-package org-src
  :ensure org
  :init
  (setq org-src-window-setup 'current-window)
  (setq org-edit-src-content-indentation 0) ;; TODO: emacs 31 (org 9.8): renamed to `org-src-content-indentation'
  (setq org-src-content-indentation 0) ;; TODO: emacs 31 (org 9.8)
  )

org-agenda

(use-package org-agenda
  :ensure org
  :init
  (setq org-agenda-window-setup 'current-window)
  (setq org-agenda-tags-column 0))

org-capture

(use-package org-capture
  :ensure org
  :init
  (setq org-capture-templates
        `(("j" "Journal")
          ("jj" "Journal note" entry
           (file+olp+datetree ,(expand-file-name "journal.org" org-directory))
           "* %<%H:%M> - %^{Title|untitled} :journal:\n\n%?\n\n"
           :empty-lines 1)
          ("jm" "Meeting note" entry
           (file+olp+datetree ,(expand-file-name "journal.org" org-directory))
           "* %<%H:%M> - %^{Title|untitled} :meeting:\n\n%?\n\n"
           :empty-lines 1 :clock-in t :clock-resume t)
          )))

org-faces

(use-package org-faces
  :ensure org
  :custom-face
  (org-tag              ((t (:inherit shadow :foreground unspecified :background unspecified :bold nil))))
  (org-ellipsis         ((t (:underline nil))))
  (org-block-begin-line ((t (:underline nil))))
  (org-block-end-line   ((t (:overline nil))))
  :init
  (setq org-fontify-quote-and-verse-blocks t)
  (setq org-priority-faces
        '((?A . (:inherit (bold error)))
          (?B . (:inherit (bold warning)))
          (?C . (:inherit (bold success)))))
  ;; TODO: simplify
  (setq org-todo-keyword-faces
        '(("STARTED"   . (:inherit (bold font-lock-constant-face org-todo)))
          ("NEXT"      . (:inherit (bold font-lock-constant-face org-todo)))
          ("WAITING"   . (:inherit (bold warning org-todo)))
          ("HOLD"      . (:inherit (bold warning org-todo)))
          ("OBSOLETE"  . (:inherit (bold shadow org-todo)))
          ("CANCELLED" . (:inherit (bold shadow org-todo))))))

toc-org

(use-package toc-org
  :init
  (setq toc-org-max-depth 6)
  :hook
  (org-mode-hook . toc-org-enable))

org-babel

ob-core

(use-package ob-core
  :ensure org
  :preface
  (defun +org-babel-add-lang (lang)
    "Enable LANG in `org-babel-load-languages'.
  Use instead of `org-babel-do-load-languages' to avoid
  overwriting `org-babel-load-languages'."
    (add-to-list 'org-babel-load-languages (cons lang t))
    (org-babel-do-load-languages 'org-babel-load-languages org-babel-load-languages))
  :init
  ;; built-in languages, for external use `+org-babel-add-lang'
  (setq org-babel-load-languages
        '((emacs-lisp . t)
          (shell      . t)
          (plantuml   . t)))
  (setq org-babel-results-keyword "results")
  :hook
  (org-babel-after-execute-hook . org-redisplay-inline-images))

ob-tangle

(use-package ob-tangle
  :ensure org
  :init
  (add-to-list 'safe-local-variable-values '(after-save-hook . org-babel-tangle)))

ob-plantuml

(use-package ob-plantuml
  :ensure nil
  :init
  (setq org-plantuml-exec-mode 'plantuml))

verb

(use-package verb
  :general
  (org-mode-map
   "C-c C-r" '(:keymap verb-command-map :package verb :wk "verb"))
  :init
  (setq verb-auto-kill-response-buffers t)
  (setq verb-json-use-mode 'json-ts-mode)
  :config
  (+org-babel-add-lang 'verb))

org-crypt

Encrypting org Files.

(use-package org-crypt
  :ensure org
  :init
  (setq org-tags-exclude-from-inheritance '("crypt"))
  ;; GPG key to use for encryption
  ;; Either the Key ID or set to nil to use symmetric encryption.
  (setq org-crypt-key nil)
  :config
  (org-crypt-use-before-save-magic))

Notes

deft

(use-package deft
  :general
  ( :keymaps 'deft-mode-map :states 'normal
    "gr" 'deft-refresh)
  :init
  (setq deft-directory (concat org-directory "/deft/"))
  (setq deft-extensions '("org"))
  (setq deft-use-filter-string-for-filename t)
  (setq deft-auto-save-interval 0) ;; disable
  (setq deft-file-naming-rules ;; kebab-case
        '((noslash . "-")
          (nospace . "-")
          (case-fn . downcase))))

LSP

eglot

(use-package eglot
  :ensure nil
  :general
  (+local-leader-def :keymaps 'eglot-mode-map
    "=" 'eglot-format
    "a" 'eglot-code-actions
    "R" 'eglot-rename
    "f" '(:ignore t :wk "find")
    "fd" 'eglot-find-declaration
    "ft" 'eglot-find-typeDefinition
    "fr" 'eglot-find-references
    "fi" 'eglot-find-implementation
    "h" '(:ignore t :wk "hierarchy")
    "hc" 'eglot-show-call-hierarchy
    "ht" 'eglot-show-type-hierarchy)
  :init
  (setq eglot-autoshutdown t))

Upgrade eglot to the latest version

(eglot-upgrade-eglot)
(use-package consult-eglot
  :general
  (+local-leader-def :keymaps 'eglot-mode-map
    "Fs" 'consult-eglot-symbols))

(use-package consult-eglot-embark
  :config
  (consult-eglot-embark-mode))

dape

(use-package dape
  :custom-face
  (dape-breakpoint-face ((t (:inherit error))))
  :init
  (setq dape-key-prefix (kbd "C-x C-a"))
  (setq dape-inlay-hints t)
  (setq dape-buffer-window-arrangement 'gud)
  (setq dape-breakpoint-margin-string "")
  :config
  (dape-breakpoint-global-mode)
  :hook
  (kill-emacs-hook . dape-breakpoint-save)
  (after-init-hook . dape-breakpoint-load))

mason

(use-package mason
  :hook
  (after-init-hook . mason-ensure))

Languages

treesit

(use-package treesit
  :ensure nil
  :init
  (setq treesit-font-lock-level 4)
  (setq treesit-language-source-alist
        '((go . ("https://github.com/tree-sitter/tree-sitter-go"))
          (gomod . ("https://github.com/camdencheek/tree-sitter-go-mod"))
          (gosum . ("https://github.com/tree-sitter-grammars/tree-sitter-go-sum"))
          (clojure . ("https://github.com/sogaiu/tree-sitter-clojure"))
          (lua . ("https://github.com/tree-sitter-grammars/tree-sitter-lua"))
          (bash . ("https://github.com/tree-sitter/tree-sitter-bash"))
          (json . ("https://github.com/tree-sitter/tree-sitter-json"))
          (yaml . ("https://github.com/tree-sitter-grammars/tree-sitter-yaml"))
          (dockerfile . ("https://github.com/camdencheek/tree-sitter-dockerfile"))))
  ;; TODO: emacs 31: treesit-enabled-modes
  (setq major-mode-remap-alist
        '((go-mode . go-ts-mode)
          (go-mod-mode . go-mod-ts-mode)
          (clojure-mode . clojure-ts-mode)
          (lua-mode . lua-ts-mode)
          (json-mode . json-ts-mode)
          (yaml-mode . yaml-ts-mode)
          (dockerfile-mode . dockerfile-ts-mode)))
  :config
  ;; TODO: emacs 31: treesit-auto-install-grammar
  (dolist (source treesit-language-source-alist)
    (unless (treesit-ready-p (car source) t) ;; `t' to quietly check
      (treesit-install-language-grammar (car source)))))

elisp

(use-package highlight-defined
  :init
  (setq highlight-defined-face-use-itself t)
  :hook
  (emacs-lisp-mode-hook . highlight-defined-mode))
(use-package highlight-quoted
  :hook
  (emacs-lisp-mode-hook . highlight-quoted-mode))
(use-package package-lint)
(use-package package-lint-flymake
  :hook
  (emacs-lisp-mode-hook . package-lint-flymake-setup))

clojure

(use-package clojure-ts-mode)
(use-package cider
  :custom-face
  (cider-result-overlay-face ((t (:inherit shadow :box t))))
  :general
  (+local-leader-def :keymaps 'clojure-ts-mode-map
    "c" '(:ignore t           :wk "connect")
    "cc" '(cider-jack-in      :wk "jack-in")
    "cj" '(cider-jack-in-clj  :wk "jack-in-clj")
    "cs" '(cider-jack-in-cljs :wk "jack-in-cljs")
    "cC" '(cider-connect      :wk "connect")
    "cR" '(cider-restart      :wk "restart")
    "cQ" '(cider-quit         :wk "quit")

    "b" '(:ignore t           :wk "buffer")
    "bs" 'cider-scratch

    "=" '(cider-format-buffer :wk "format"))
  :init
  (setq cider-eldoc-display-context-dependent-info t)
  :hook
  (clojure-ts-mode-hook . cider-mode))
(use-package clj-refactor
  :general
  (+local-leader-def :keymaps 'clojure-ts-mode-map
    "R" '(hydra-cljr-help-menu/body :wk "refactor"))
  :hook
  (clojure-ts-mode-hook . clj-refactor-mode))

golang

Install gopls

go install golang.org/x/tools/gopls@latest

Install dlv

go install github.com/go-delve/delve/cmd/dlv@latest
(use-package go-ts-mode
  :ensure nil
  :mode
  ("\\.go\\'" . go-ts-mode)
  ("go\\.mod\\'" . go-mod-ts-mode)
  :general
  (+local-leader-def :keymaps 'go-ts-mode-map
    "t"  '(:ignore t :wk "test"))
  :init
  (setq go-ts-mode-indent-offset 4)
  :hook
  (go-ts-mode-hook . eglot-ensure))
;; TODO: Emacs 31: gotest-ts is obsoleted by go-ts-mode's built-in test commands
(use-package gotest-ts
  :general
  (+local-leader-def :keymaps 'go-ts-mode-map
    "tt" 'gotest-ts-run-dwim))

makefile

(use-package makefile-executor
  :general
  (+local-leader-def :keymaps 'makefile-mode-map
    "e" 'makefile-executor-execute-target)
  :hook
  (makefile-mode-hook . makefile-executor-mode))

plantuml

(use-package plantuml-mode
  :general
  (+local-leader-def :keymaps 'plantuml-mode-map
    "p" '(plantuml-preview :wk "preview"))
  :init
  (setq plantuml-output-type (if (display-images-p) "png" "txt"))
  (setq plantuml-default-exec-mode 'executable))

sql

(use-package sql
  :ensure nil
  :general
  (+local-leader-def :keymaps 'sql-mode-map
    "c" '(:ignore t :wk "connect")
    "cc" '(sql-connect :wk "connect")

    "e" '(:ignore t :wk "eval")
    "ee" '(sql-send-paragraph :wk "paragraph")
    "el" '(sql-send-line-and-next :wk "line and next")
    "eb" '(sql-send-buffer :wk "buffer")
    "er" '(sql-send-region :wk "region")
    "es" '(sql-send-string :wk "string")

    "l" '(:ignore t :wk "list")
    "la" '(sql-list-all :wk "all")
    "lt" '(sql-list-table :wk "table"))
  :init
  (setq sql-connection-alist '((pg-local
                                (sql-product 'postgres)
                                (sql-port 5432)
                                (sql-server "localhost")
                                (sql-user "postgres")
                                (sql-password "postgres")
                                (sql-database "postgres")))))

markdown

(use-package markdown-mode
  :custom-face
  (markdown-code-face ((t (:inherit default))))
  :general
  (+local-leader-def :keymaps 'markdown-mode-map
    "." '(:keymap markdown-mode-command-map))
  :init
  (setq markdown-command "pandoc")
  ;; (setq markdown-hide-markup t)
  (setq markdown-fontify-whole-heading-line t)
  (setq markdown-fontify-code-blocks-natively t)
  :config
  (add-to-list 'markdown-code-lang-modes '("clj" . clojure-ts-mode)))
(use-package grip-mode
  :general
  (+local-leader-def :keymaps 'markdown-mode-map
    "g" 'grip-mode)
  :init
  (setq grip-update-after-change nil)
  (setq grip-preview-use-webkit t))
(use-package markdown-toc)
(use-package edit-indirect)

json

(use-package json-ts-mode
  :ensure nil
  :mode ("\\.json\\'" . json-ts-mode)
  :general
  (+local-leader-def :keymaps 'json-ts-mode-map
    "=" '(json-pretty-print-buffer :wk "format")))

yaml

(use-package yaml-ts-mode
  :ensure nil
  :mode ("\\.ya?ml\\'" . yaml-ts-mode)
  :preface
  (defun +yaml-ts-mode-set-evil-shift-width ()
    (setq-local evil-shift-width 2))
  :hook
  (yaml-ts-mode-hook . flymake-mode)
  (yaml-ts-mode-hook . +yaml-ts-mode-set-evil-shift-width))
(use-package yaml-pro
  :hook
  (yaml-ts-mode-hook . yaml-pro-ts-mode))

lua

(use-package lua-ts-mode
  :ensure nil
  :mode ("\\.lua\\'" . lua-ts-mode)
  :interpreter ("\\<lua\\(?:jit\\)?" . lua-ts-mode)
  :hook
  (lua-ts-mode-hook . eglot-ensure))

shell

(use-package executable
  :ensure nil
  :hook
  (after-save-hook . executable-make-buffer-file-executable-if-script-p))
(use-package flymake-shellcheck
  :hook
  (sh-mode-hook . flymake-shellcheck-load))
(use-package fish-mode)

vimrc

(use-package vimrc-mode)

ssh

(use-package ssh-config-mode)

protobuf

(use-package protobuf-ts-mode
  :mode "\\.proto\\'")

dockerfile

(use-package dockerfile-ts-mode
  :ensure nil
  :mode ("\\(?:Dockerfile\\(?:\\..*\\)?\\|\\.[Dd]ockerfile\\)\\'" . dockerfile-ts-mode))

Tools

editorconfig

(use-package editorconfig
  :ensure nil
  :hook
  (after-init-hook . editorconfig-mode))

docker

(use-package docker)
(use-package docker-compose-mode
  :general
  (+local-leader-def :keymaps 'docker-compose-mode-map
    "." 'docker-compose))

ansible

(use-package jinja2-mode
  :mode "\\.j2\\'")
(use-package ansible-vault-with-editor
  :vc (:url "https://github.com/rynffoll/ansible-vault-with-editor" :rev :newest)
  :general
  (+local-leader-def :keymaps 'yaml-ts-mode-map
    "e" '(ansible-vault-with-editor-edit :wk "edit")
    "E" '(ansible-vault-with-editor-encrypt :wk "encrypt")
    "D" '(ansible-vault-with-editor-decrypt :wk "decrypt")))

mise

(use-package mise
  :hook
  (after-init-hook . global-mise-mode))

proced

(use-package proced
  :ensure nil
  :init
  (setq proced-enable-color-flag t)
  ;; (setq proced-auto-update-flag t)
  (setq proced-format 'medium))
(use-package proced-narrow
  :general
  (proced-mode-map
   "M-n" 'proced-narrow))

keycast

(use-package keycast
  :init
  (setq keycast-tab-bar-location 'tab-bar-format-global)
  (setq keycast-tab-bar-format "%K")
  (setq keycast-tab-bar-minimal-width 2))

dothttp

(use-package dothttp
  :ensure nil
  :load-path "site-lisp/dothttp"
  :mode ("\\.http\\'" . dothttp-mode))
(use-package dothttp-grpc
  :ensure nil
  :demand t
  :after dothttp)

LLM

gptel

(use-package gptel
  :general
  (+local-leader-def :keymaps 'gptel-mode-map
    "." 'gptel-menu)
  (embark-general-map
   "." #'gptel-menu)
  :init
  (setq gptel-default-mode 'org-mode)
  (setq gptel-model 'gpt-5-mini)
  (setq gptel-backend (gptel-make-gh-copilot "Copilot"))
  :hook
  (gptel-post-stream-hook . gptel-auto-scroll)
  (gptel-post-response-functions . gptel-end-of-response))

gptel-quick

(use-package gptel-quick
  :vc (:url "https://github.com/karthink/gptel-quick" :rev :newest)
  :general
  (embark-general-map
   "?" #'gptel-quick))

gptel-magit

(use-package gptel-magit
  :hook
  (magit-mode-hook . gptel-magit-install))

claude-code-ide

(use-package claude-code-ide
  :vc (:url "https://github.com/manzaltu/claude-code-ide.el" :rev :newest)
  :general
  (project-prefix-map
   "C" 'claude-code-ide-menu)
  :init
  (setq claude-code-ide-use-side-window nil)
  (setq claude-code-ide-show-claude-window-in-ediff nil)
  ;; (setq claude-code-ide-switch-tab-on-ediff nil) ;; it doesn't work (the same tab names)
  :config
  (claude-code-ide-emacs-tools-setup))

agent-shell

(use-package agent-shell
  :general
  (+local-leader-def :keymaps 'agent-shell-mode-map
    "." 'agent-shell-help-menu)
  (project-prefix-map
   "a" 'agent-shell)
  ( :keymaps 'agent-shell-mode-map :states 'insert
    "RET" 'newline)
  ( :keymaps 'agent-shell-mode-map :states 'normal
    "RET" 'comint-send-input)
  :config
  (add-to-list 'evil-buffer-regexps '("\\*agent-shell-diff\\*" . emacs)))

copilot

(use-package copilot
  :general
  (copilot-completion-map
   "<tab>"   'copilot-accept-completion
   "TAB"     'copilot-accept-completion
   "C-<tab>" 'copilot-accept-completion-by-word
   "C-TAB"   'copilot-accept-completion-by-word
   "C-j"     'copilot-next-completion
   "C-k"     'copilot-previous-completion
   "C-n"     'copilot-next-completion
   "C-p"     'copilot-previous-completion)
  :init
  (setq copilot-indent-offset-warning-disable t)
  (setq copilot-max-char 1000000)
  (setq copilot-max-char-warning-disable t)
  :hook
  ;; (after-init-hook . global-copilot-mode)
  (prog-mode-hook . copilot-mode)
  (conf-mode-hook . copilot-mode)
  (git-commit-mode-hook . copilot-mode))

Install server

(copilot-install-server)

Utils

(use-package focus)
(use-package olivetti
  :init
  (setq olivetti-body-width 0.6))
(use-package crux)
(use-package try)
(use-package string-inflection)
(use-package show-font)
(use-package disk-usage)
(use-package list-environment)
(use-package daemons)
(use-package free-keys)

Private

Loading private configuration from ~~/.emacs.d/site-lisp/default.el~ 50.4 The Emacs Initialization File

;; TODO: emacs 31: use `user-lisp'
(add-to-list 'load-path (concat user-emacs-directory "site-lisp"))

About

Emacs config

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages