Emacs minimalistic config

This commit is contained in:
Alexey Norets 2025-09-21 13:55:18 +03:00
commit fcd18f085a
3 changed files with 608 additions and 0 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
/*
!/*.el
!/*.org
!/.gitignore

42
early-init.el Normal file
View File

@ -0,0 +1,42 @@
;; -*- lexical-binding: t; -*-
;; Temporarily increase the garbage collection threshold. These
;; changes help shave off about half a second of startup time. The
;; `most-positive-fixnum' is DANGEROUS AS A PERMANENT VALUE. See the
;; `emacs-startup-hook' a few lines below for what I actually use.
(setq gc-cons-threshold most-positive-fixnum
gc-cons-percentage 0.5)
;; Same idea as above for the `file-name-handler-alist' and the
;; `vc-handled-backends' with regard to startup speed optimisation.
;; Here I am storing the default value with the intent of restoring it
;; via the `emacs-startup-hook'.
(defvar prot-emacs--file-name-handler-alist file-name-handler-alist)
(defvar prot-emacs--vc-handled-backends vc-handled-backends)
(setq file-name-handler-alist nil
vc-handled-backends nil)
(add-hook 'emacs-startup-hook
(lambda ()
(setq gc-cons-threshold (* 1024 1024 20)
gc-cons-percentage 0.2
file-name-handler-alist prot-emacs--file-name-handler-alist
vc-handled-backends prot-emacs--vc-handled-backends)))
;;
(setq load-prefer-newer t)
(setq byte-compile-warnings '(not obsolete))
(setq warning-suppress-log-types '((comp) (bytecomp)))
;; Initialise installed packages at this early stage, by using the
;; available cache. I had tried a setup with this set to nil in the
;; early-init.el, but (i) it ended up being slower and (ii) various
;; package commands, like `describe-package', did not have an index of
;; packages to work with, requiring a `package-refresh-contents'.
(setq package-enable-at-startup t)
(menu-bar-mode -1)
(scroll-bar-mode -1)
(tool-bar-mode -1)

562
init.el Normal file
View File

@ -0,0 +1,562 @@
;; -*- lexical-binding: t; -*-
(require 'package)
(setq package-vc-register-as-project nil) ; Emacs 30
(add-hook 'package-menu-mode-hook #'hl-line-mode)
;; List of packages for auto install scratch
(setq package-list '(use-package))
;; Also read: <https://protesilaos.com/codelog/2022-05-13-emacs-elpa-devel/>
(setq package-archives
'(("gnu-elpa" . "https://elpa.gnu.org/packages/")
("gnu-elpa-devel" . "https://elpa.gnu.org/devel/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")
("melpa" . "https://melpa.org/packages/")))
;; Highest number gets priority (what is not mentioned has priority 0)
(setq package-archive-priorities
'(("gnu-elpa" . 3)
("melpa" . 2)
("nongnu" . 1)))
;; NOTE 2023-08-21: I build Emacs from source, so I always get the
;; latest version of built-in packages. However, this is a good
;; solution to set to non-nil if I ever switch to a stable release.
(setq package-install-upgrade-built-in nil)
; activate all the packages (in particular autoloads)
(package-initialize)
; fetch the list of packages available
(unless package-archive-contents
(package-refresh-contents))
;; Whitespace-mode settings.
(use-package emacs
:init
(custom-set-variables '(whitespace-display-mappings '((space-mark 32 [183] [46])
(space-mark 160 [164] [95])
(newline-mark 10 [172 10])
(tab-mark 9 [187 9] [92 9]))))
(custom-set-faces
'(whitespace-space ((t (:bold t :foreground "#282828"))))
'(whitespace-newline ((t (:bold t :foreground "#282828"))))
)
(add-hook 'prog-mode-hook (lambda () (setq display-line-numbers 'relative)))
(add-hook 'prog-mode-hook 'whitespace-mode)
)
;; Frame settings.
(use-package emacs
:init
(setq initial-frame-alist '(
(fullscreen . maximized)
(font . "JetBrains Mono 22")
;; (font . "Iosevka Fixed 24")
(undecorated . t)
(vertical-scroll-bars . nil)
(inhibit-double-buffering . t)
;; (ns-transparent-titlebar . nil)
(background-color . "#181818") ;;"black")
))
)
;; Basic settings.
(use-package emacs
:init
(delete-selection-mode 1)
(blink-cursor-mode 0)
(save-place-mode t)
(savehist-mode t)
(setq use-short-answers t
ring-bell-function 'ignore
scroll-conservatively 101
help-window-select t
create-lockfiles nil
auto-save-default nil
make-backup-files nil
custom-safe-themes t
initial-buffer-choice nil ;; If not nil always show scratch buffer, even open other file.
backup-directory-alist '((".*" . "/tmp"))
custom-file (make-temp-file "emacs-custom-")
whitespace-style (quote (face spaces tabs space-mark tab-mark newline newline-mark))
Man-sed-command "gsed")
:config
(setq-default truncate-lines nil
display-line-numbers-width 3
indent-tabs-mode nil
tab-width 4
c-basic-offset 4
c-basic-indent 4)
(xterm-mouse-mode t)
(show-paren-mode t))
;; Mode line format. -----
(defun my-evil-mode-indicator ()
(interactive)
(cond ((eq evil-state 'visual) "<V>")
((eq evil-state 'insert) "<I>")
((eq evil-state 'normal) "<N>")
((eq evil-state 'emacs) "<E>")
(t " * ")))
(setq-default mode-line-format '("%e " mode-line-modified " "
(:eval (propertize (buffer-name)) 'face 'font-lock-constant-face)
"%6l:%c (%o) "
(:eval
(if (and (mode-line-window-selected-p) (bound-and-true-p evil-mode))
(my-evil-mode-indicator))
" ")
(:eval (unless (not vc-mode) (concat " | git:" (substring-no-properties vc-mode 5))))
mode-line-format-right-align
(:eval (concat " " (symbol-name major-mode)))
" " mode-line-misc-info))
(use-package emacs
:init
;; Add prompt indicator to `completing-read-multiple'.
;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
(defun crm-indicator (args)
(cons (format "[CRM%s] %s"
(replace-regexp-in-string
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
crm-separator)
(car args))
(cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; (add hook 'rfn-eshadow-update-overlay-hook #'vertico-directory-tidy)
;; Enable recursive minibuffers
(setq enable-recursive-minibuffers t))
(use-package modus-themes
:ensure t
:defer t
:config
(custom-set-faces
'(dired-header ((t (:foreground "#95a99f" :slant italic)))))
(custom-set-faces
'(dired-directory ((t (:foreground "#96a6c8" :slant italic)))))
(setq modus-themes-italic-constructs nil
modus-themes-bold-constructs nil
modus-themes-mixed-fonts nil
modus-themes-variable-pitch-ui nil
modus-themes-custom-auto-reload t
modus-themes-disable-other-themes t
modus-themes-prompts '(italic bold)
modus-themes-completions
'((matches . (extrabold))
(selection . (semibold italic text-also)))
modus-themes-org-blocks 'tined-background
)
(setq modus-vivendi-palette-overrides
;; Setting for theme like gruber-darker
`(
(fg-main "#e4e4ef")
;; Background
(bg-main "#181818")
;; Comment and string
(comment "#cc8c3c") ;; yellow-faint)
(string "#73c936")
;; Code colors
(builtin "#95a99f")
(constant "#95a99f")
(fnname "#96a6c8")
(keyword "#ffdd33")
(preprocessor "#95a99f")
(type "#95a99f")
(cursor "#ffdd33")
(variable "#f4f4ff")
(bg-region "#484848")
(fg-region unspecified)
(fg-completion-match-0 "#ffdd33")
(fg-prompt "#96a6c8")
(bg-mode-line-active "#282828")
(fg-mode-line-active "#ffffff")
(fg-line-number-active "#ffdd33")
(bg-line-number-active "#181818")
(bg-line-number-inactive "#181818")
;; SRC-block
(bg-prose-block-delimiter bg-cyan-nuanced)
;; Region bg and fg
(bg-region bg-hover) ; try to replace `bg-ochre' with `bg-lavender', `bg-sage'
(fg-region unspecified)
)))
(load-theme 'modus-vivendi t)
;; Denote package. ----
(use-package denote
:ensure t
:init
:custom
(denote-directory "~/Nextcloud/DenoteNotes/")
:hook
(dired-mode . denote-dired-mode)
:custom-face
(denote-faces-link ((t (:slant italic)))))
(global-set-key (kbd "C-c n n") 'denote-open-or-create)
(use-package consult-denote
:ensure t
:config
(define-key global-map (kbd "C-c n f") #'consult-denote-find)
(define-key global-map (kbd "C-c n g") #'consult-denote-grep))
(use-package vertico
:ensure t
:init
(setq vertico-scroll-margin 0)
(setq vertico-count 5)
(setq vertico-resize nil)
(setq vertico-cycle t)
(vertico-mode))
(use-package emacs
:custom
;; Support opening new minibuffers from inside existing minibuffers.
(enable-recursive-minibuffers t)
;; Hide commands in M-x which do not work in the current mode. Vertico
;; commands are hidden in normal buffers. This setting is useful beyond
;; Vertico.
(read-extended-command-predicate #'command-completion-default-include-p)
;; Do not allow the cursor in the minibuffer prompt
(minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt)))
;; Dired module. -----
(when (string= system-type "darwin")
(setq dired-use-ls-dired nil))
(use-package dired
:init
(setq delete-by-moving-to-trash t)
(setq dired-listing-switches "-lah")
(setq dired-dwim-target t)
(setq dired-auto-revert-buffer #'dired-directory-changed-p)
)
;; ISearch module. -----
(use-package isearch
:ensure nil
:demand t
:config
(setq search-whitespace-regexp ".*?" ; one `setq' here to make it obvious they are a bundle
isearch-lax-whitespace t
isearch-regexp-lax-whitespace nil))
(use-package isearch
:ensure nil
:demand t
:config
(setq search-highlight t)
(setq isearch-lazy-highlight t)
(setq lazy-highlight-initial-delay 0.5)
(setq lazy-highlight-no-delay-length 4))
(use-package isearch
:ensure nil
:demand t
:config
(setq isearch-lazy-count t)
(setq lazy-count-prefix-format "(%s/%s) ")
(setq lazy-count-suffix-format nil))
(use-package isearch
:ensure nil
:demand t
:config
(setq isearch-wrap-pause t) ; `no-ding' makes keyboard macros never quit
(setq isearch-repeat-on-direction-change t))
(use-package isearch
:ensure nil
:demand t
:config
(setq list-matching-lines-jump-to-current-line nil) ; do not jump to current line in `*occur*' buffers
;; (add-hook 'occur-mode-hook #'prot-common-truncate-lines-silently) ; from `prot-common.el'
(add-hook 'occur-mode-hook #'hl-line-mode))
(use-package isearch
:ensure nil
:defer t
:config
(defun my-occur-from-isearch ()
(interactive)
(let ((query (if isearch-regexp
isearch-string
(regexp-quote isearch-string))))
(isearch-update-ring isearch-string isearch-regexp)
(let (search-nonincremental-instead)
(ignore-errors (isearch-done t t)))
(occur query)))
:bind
(:map isearch-mode-map
("C-o" . my-occur-from-isearch)))
(use-package isearch
:ensure nil
:defer t
:config
(defun my-project-search-from-isearch ()
(interactive)
(let ((query (if isearch-regexp
isearch-string
(regexp-quote isearch-string))))
(isearch-update-ring isearch-string isearch-regexp)
(let (search-nonincremental-instead)
(ignore-errors (isearch-done t t)))
(project-find-regexp query)))
:bind
(:map isearch-mode-map
("C-f" . my-project-search-from-isearch)))
;; Selection window (rg, grep, help etc). -----
(defun my-select-window (window &rest _)
"Select WINDOW for display-buffer-alist"
(select-window window))
(setq display-buffer-alist
'(((or . ((derived-mode . occur-mode)
(derived-mode . rg-mode)
(derived-mode . grep-mode)
(derived-mode . Buffer-menu-mode)
(derived-mode . log-view-mode)
(derived-mode . help-mode) ; See the hooks for `visual-line-mode'
(derived-mode . flymake-diagnostics-buffer-mode)
"\\*\\(|Buffer List\\|Occur\\|vc-change-log\\|compilation\\|eldoc.*\\).*"
))
(display-buffer-reuse-mode-window display-buffer-pop-up-window)
(body-function . my-select-window)
(dedicated . t)
(preserve-size . (t . t)))))
;; Marginalia. -----
(use-package marginalia
:ensure t
;; Either bind `marginalia-cycle' globally or only in the minibuffer
:bind (("M-A" . marginalia-cycle)
:map minibuffer-local-map
("M-A" . marginalia-cycle))
;; The :init configuration is always executed (Not lazy!)
:init
;; Must be in the :init section of use-package such that the mode gets
;; enabled right away. Note that this forces loading the package.
(marginalia-mode))
;; Orderless. -----
(use-package orderless
:ensure t
:demand t
:after minibuffer
:config
(setq completion-styles '(orderless basic)
completion-category-defaults nil
;; orderless-matching-styles '(orderless-prefixes orderless-regexp)
completion-category-overrides '((file (styles . (partial-completion))))
))
;; Corfu
(use-package corfu
:ensure t
:defer 3
:custom
(corfu-cycle t) ;; Enable cycling for `corfu-next/previous'
(corfu-auto t) ;; Enable auto completion
;; (corfu-separator ?\s) ;; Orderless field separator
;; (corfu-quit-at-boundary nil) ;; Never quit at completion boundary
;; (corfu-quit-no-match nil) ;; Never quit, even if there is no match
;; (corfu-preview-current nil) ;; Disable current candidate preview
;; (corfu-preselect 'prompt) ;; Preselect the prompt
;; (corfu-on-exact-match nil) ;; Configure handling of exact matches
;; (corfu-scroll-margin 5) ;; Use scroll margin
(corfu-popupinfo-mode t)
:bind (:map corfu-map
("C-y" . corfu-complete)
("C-e" . corfu-reset)
("<TAB>" . nil)
)
:init
(global-corfu-mode))
(use-package corfu-terminal
:ensure t
:defer 3
:init
(unless (display-graphic-p)
(corfu-terminal-mode +1)))
;; Add extensions
(use-package cape
:ensure t
:defer 3
;; Bind prefix keymap providing all Cape commands under a mnemonic key.
;; Press C-c p ? to for help.
:bind ("C-c p" . cape-prefix-map) ;; Alternative keys: M-p, M-+, ...
;; Alternatively bind Cape commands individually.
;; :bind (("C-c p d" . cape-dabbrev)
;; ("C-c p h" . cape-history)
;; ("C-c p f" . cape-file)
;; ...)
:init
;; 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.
(add-hook 'completion-at-point-functions #'cape-dabbrev)
(add-hook 'completion-at-point-functions #'cape-file)
(add-hook 'completion-at-point-functions #'cape-elisp-block)
;; (add-hook 'completion-at-point-functions #'cape-history)
;; ...
)
;; Org-mode. ------
(use-package org
:ensure t
:hook (org-mode . visual-line-mode)
:custom
(org-ellipsis "...")
(org-sturtup-indent t)
(org-hide-emphasis-markers t))
;; (use-package mini-modeline
;; :ensure t
;; ;; :quelpa (mini-modeline :repo "kiennq/emacs-mini-modeline" :fetcher github)
;; ;; :after smart-mode-line
;; :config
;; (setq mini-modeline-display-gui-line t)
;; (setq mini-modeline-enhance-visual t)
;; (setq mini-modeline-l-format '("%e " mode-line-modified " "
;; (:eval (propertize (buffer-name)) 'face 'font-lock-constant-face)
;; "%6l:%c (%o) "
;; (:eval (unless (not vc-mode) (concat " | git:" (substring-no-properties vc-mode 5))))))
;; (setq mini-modeline-r-format '(""
;; (:eval (concat " " (symbol-name major-mode)))
;; " " mode-line-misc-info))
;; (mini-modeline-mode t))
;; Avy -----
(use-package avy
:ensure t)
;; Move Lines/Text -----
(use-package move-text
:ensure t)
(defun indent-region-advice (&rest ignored)
(let ((deactivate deactivate-mark))
(if (region-active-p)
(indent-region (region-beginning) (region-end))
(indent-region (line-beginning-position) (line-end-position)))
(setq deactivate-mark deactivate)))
(advice-add 'move-text-up :after 'indent-region-advice)
(advice-add 'move-text-down :after 'indent-region-advice)
;;; Magig ------
(use-package magit
:ensure t
:defer 0
:init
(setq magit-auto-revert-mode nil))
;; Keybindings ------
(define-key (current-global-map) [remap dired] 'dired-jump)
(define-key (current-global-map) [remap list-buffers] 'ibuffer)
(define-key (current-global-map) [remap kill-buffer] 'kill-current-buffer)
(global-set-key (kbd "C-c d d") 'kill-whole-line)
(global-set-key (kbd "C-c w s") 'visual-line-mode)
(global-set-key (kbd "S-C-<left>") 'shrink-window-horizontally)
(global-set-key (kbd "S-C-<right>") 'enlarge-window-horizontally)
(global-set-key (kbd "S-C-<down>") 'shrink-window)
(global-set-key (kbd "S-C-<up>") 'enlarge-window)
(global-set-key (kbd "C-z") 'move-text-down)
(global-set-key (kbd "C-q") 'move-text-up)
(global-set-key (kbd "C-c t c") 'avy-goto-char)
(global-set-key (kbd "C-c t w") 'avy-goto-word-0)
;;; Functions. -----
;;RecentFiles
(defun my/recentf-open-files-compl ()
(interactive)
(recentf-mode 1)
(let* ((tocpl (mapcar (lambda (x) (cons (file-name-nondirectory x) x))
recentf-list))
(fname (completing-read "Recent-file name: " tocpl nil nil)))
(when fname
(find-file (cdr (assoc-string fname tocpl))))))
(global-set-key "\C-x\C-r" 'my/recentf-open-files-compl)
;; Half page up/down
(defun my/half-page-up ()
(interactive)
;; (scroll-down-command )
(move-to-window-line-top-bottom 0)
(recenter))
(global-set-key (kbd "M-p") 'my/half-page-up)
(defun my/half-page-down ()
(interactive)
(if (eq (line-number-at-pos) (line-number-at-pos (window-start)))
;; If the cursor is at the top of the page, move it to the center
(progn
(let ((middle-line (1+ (/ (window-height) 2))))
(move-to-window-line middle-line)))
;; (scroll-up scroll-amount)
(move-to-window-line -1 )
(recenter)))
(global-set-key (kbd "M-n") 'my/half-page-down)
;; Split window and follow cursor. -----
(defun my/split-and-follow-horizontaly ()
(interactive)
(split-window-below)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 2") 'my/split-and-follow-horizontaly)
(defun my/split-and-follow-verticaly ()
(interactive)
(split-window-right)
(balance-windows)
(other-window 1))
(global-set-key (kbd "C-x 3") 'my/split-and-follow-verticaly)
;; Kill whole word/line
(defun my/kill-whole-word ()
(interactive)
(forward-char 1)
(backward-word)
(kill-word 1))
(global-set-key (kbd "C-c w w") 'my/kill-whole-word)
(defun my/copy-whole-line ()
(interactive)
(save-excursion
(kill-new
(buffer-substring
(point-at-bol)
(point-at-eol)))))
(global-set-key (kbd "C-c w l") 'my/copy-whole-line)
;; Duplicate Line.
(defun my/duplicate-line ()
"Duplicate current line"
(interactive)
(let ((column (- (point) (point-at-bol)))
(line (let ((s (thing-at-point 'line t)))
(if s (string-remove-suffix "\n" s) ""))))
(move-end-of-line 1)
(newline)
(insert line)
(move-beginning-of-line 1)
(forward-char column)))
(global-set-key (kbd "C-,") 'my/duplicate-line)