Files
nixos-configs/hosts/pinwheel/modules/emacs/config.org
2023-09-23 18:13:44 +02:00

13 KiB

Initialization

Package handling (by Nix)

   (when (featurep 'nativecomp)
     (setq comp-deferred-compilation nil))

Use package autoloads provided by Nix

  (defvar package-quickstart t)

Disable impure packages (as in not already fetched by Nix)

  (setq package-archives nil)

Initialize `use-package`

`bind-key` is required by `use-package`

   (use-package bind-key
     :config
     (add-to-list 'same-window-buffer-names "*Personal Keybindings*"))

  ;; (eval-when-compile
  ;;   (require 'use-package))
  ;; (use-package quelpa-use-package)

Optimization

Time startup

  (add-hook 'emacs-startup-hook
     (lambda ()
       (message "Started emacs in %.03fs"
           (float-time (time-subtract after-init-time before-init-time)))))

Keep a reference to the actual file-name-handler.

  (defvar file-name-handler-alist-actual file-name-handler-alist)

Set the file-name-handler to nil (because regexing is cpu intensive)

  (setq file-name-handler-alist nil)

Increase the gc threshold significantly for faster startup

  (setq gc-cons-threshold most-positive-fixnum)
  (add-hook 'emacs-startup-hook
    (lambda ()
      (setq gc-cons-threshold 16777216 ; 16mb
            gc-cons-percentage 0.1)))

The default is very low - 4k, lsp server responses are easily much larger

  (setq read-process-output-max (* 1024 1024)) ;; 1mb

Reset file-name-handler-alist after initialization

  (add-hook 'after-init-hook
    (lambda ()
      (garbage-collect)
      (setq file-name-handler-alist file-name-handler-alist-actual)) t)

This makes emacsclient startup faster in TUI-mode

(setq-default xterm-query-timeout nil)

Disable startup messages

  (setq inhibit-startup-message t)
  (setq initial-buffer-choice t)
  (setq initial-scratch-message nil)

Don't resize gui when setting new font

… it affecs startup time

  (setq frame-inhibit-implied-resize t)

Skip loading default lib, use fundamental-mode

  (setq inhibit-default-init t
        initial-major-mode 'fundamental-mode)

Setup

(setq confirm-kill-processes nil)

Use wl-clipboard for interprocess copy/paste

  (setq wl-copy-process nil)

  (defun wl-copy (text)
    (setq wl-copy-process (make-process :name "wl-copy"
                                        :buffer nil
                                        :command '("wl-copy" "-f" "-n")
                                        :connection-type 'pipe))
    (process-send-string wl-copy-process text)
    (process-send-eof wl-copy-process))

  (defun wl-paste ()
    (if (and wl-copy-process (process-live-p wl-copy-process))
        nil ; should return nil if we're the current paste owner
        (shell-command-to-string "wl-paste -n | tr -d \r")))

  (when (display-graphic-p)
    (setq interprogram-cut-function 'wl-copy)
    (setq interprogram-paste-function 'wl-paste)
  )

Don't create backup files, don't create #autosave# files

(setq temporary-file-directory "~/.emacs.d/tmp/")
(unless (file-exists-p "~/.emacs.d/tmp")
  (make-directory "~/.emacs.d/tmp"))

(setq backup-inhibited t
         make-backup-files nil ; don't create backup~ files
         create-lockfiles nil
         auto-save-default nil) ; don't create #autosave# files

Don't store custom settings

  (setq custom-file null-device)

Look and feel

Disable bell

  (setq ring-bell-function 'ignore)

Font

  (add-to-list 'default-frame-alist '(font . "DejaVuSansM Nerd Font Mono 16"))

Icons

  (use-package all-the-icons)

Modeline

  (use-package doom-modeline
    :init (doom-modeline-mode 1)
    :custom ((doom-modeline-height 15)))

Theme

  (use-package doom-themes
    :init (load-theme 'doom-dracula t))

Disable the menu bar

  (menu-bar-mode -1)

Disable the tool bar

  (tool-bar-mode -1)

Disable the scroll bar

  (scroll-bar-mode -1)

Disable tool tips

  (tooltip-mode -1)

Add margin left of buffers

  (set-fringe-mode 10)

Faster "confirm kill"

  (setq confirm-kill-emacs 'y-or-n-p)

Use ESC to quit prompts

  (global-set-key (kbd "<escape>") 'keyboard-escape-quit)

Enable column numbers

  (column-number-mode)

Enable line numbers

  (global-display-line-numbers-mode t)
  (setq display-line-numbers-width-start t)

Show trailing whitespace (when programming and in org-mode)

  (add-hook 'prog-mode-hook
  (lambda ()
    (setq show-trailing-whitespace t)))

  (add-hook 'org-mode-hook
  (lambda ()
    (setq show-trailing-whitespace t)))

Auto-insert matching parenthesis (when programming)

  (add-hook 'prog-mode-hook 'electric-pair-mode)

Hilight parethesis (when programming)

  (defun my-show-paren-mode ()
    "Enables show-paren-mode."
    (setq show-paren-delay 0)
    (set-face-background 'show-paren-match (face-background 'default))
    (set-face-foreground 'show-paren-match "#def")
    (set-face-attribute 'show-paren-match nil :weight 'extra-bold)
    (show-paren-mode 1))

  (add-hook 'prog-mode-hook 'my-show-paren-mode)

Calendar

Show week numbers

  (setq calendar-intermonth-text
        '(propertize
          (format "%2d"
                  (car
                   (calendar-iso-from-absolute
                    (calendar-absolute-from-gregorian (list month day year)))))
          'font-lock-face 'calendar-iso-week-face))

    (setq calendar-intermonth-header
          (propertize "Wk" 'font-lock-face 'font-lock-keyword-face))

Begin week with monday

  (setq calendar-week-start-day 1)

Tabs

Enable tabs

  (tab-bar-mode 1)

Remove tab buttons

  (setq tab-bar-close-button-show nil)
  (setq tab-bar-new-button-show nil)

Close tabs with :q

  (defun alex/close-tab (orig-fun &rest args)
    "Close tab instead of calling ORIG-FUN if there is more than a single tab."
    (if (cdr (tab-bar-tabs))
        (tab-bar-close-tab)
        (apply orig-fun args)))

  (advice-add #'evil-quit :around #'alex/close-tab)

Completion

Consult

Consult provides search and navigation commands based on the Emacs completion function completing-read. https://github.com/minad/consult

(use-package consult
  :bind
  ("C-x b" . 'consult-buffer))

Orderless completion

Allow orderless completion, e.g. `org mode` and `mode org` return same result https://github.com/oantolin/orderless

  (use-package orderless
    :custom (completion-styles '(orderless)))

Helpful

https://github.com/Wilfred/helpful

  (use-package helpful
    :bind
    ([remap describe-function] . helpful-callable)
    ([remap describe-command] . helpful-command)
    ([remap describe-variable] . helpful-variable)
    ([remap describe-key] . helpful-key)
    ([remap describe-symbol] . helpful-symbol))

Company

https://company-mode.github.io/

(use-package company
  :init
  (setq company-idle-delay 0
        company-echo-delay 0
        company-minimum-prefix-length 1)
  :config
  (global-company-mode))

Which key

`which-key` is a minor mode for Emacs that displays the key bindings following your currently entered incomplete command (a prefix) in a popup. https://github.com/justbur/emacs-which-key

(use-package which-key
  :config
  (which-key-mode)
  (which-key-setup-side-window-bottom)
  (setq which-key-sort-order 'which-key-key-order-alpha
        which-key-side-window-max-width 0.33
        which-key-idle-delay 0.05)
  )

Buffer history

`savehist` saves buffer history

  (use-package savehist
    :init
    (savehist-mode))

Vertico

(use-package vertico
  :init
  (vertico-mode))

Marginalia

(use-package marginalia
  :after vertico
  :init
  (marginalia-mode))

Keybindings

Setup prefix for keybindings.

  (use-package general)

  (general-create-definer alex/keybindings
    :keymaps '(normal insert visual emacs)
    :prefix ",")

Quick buffer save

  (alex/keybindings
    "," '(save-buffer :save-buffer "save"))

Cleanup whitespace

  (alex/keybindings
    "w" '(whitespace-cleanup :which-key "whitespace cleanup"))

Scale text

  (use-package hydra)

  (defhydra hydra-text-scale (:timeout 4)
    "scale text"
    ("k" text-scale-increase "in")
    ("j" text-scale-decrease "out")
    ("r" (text-scale-adjust 0) "reset")
    ("esc" nil "finished" :exit t))

  (alex/keybindings
    "t" '(:ignore t :which-key "text")
    "ts" '(hydra-text-scale/body :which-key "scale text"))

Evil

  (use-package evil
    :init
    (setq evil-undo-system 'undo-tree)
    (setq evil-want-integration t)
    (setq evil-want-keybinding nil)
    (setq evil-want-C-u-scroll t)
    (setq evil-want-C-i-jump nil)
    :config
    (evil-mode 1)

    ;; Use visual line motions even outside of visual-line-mode buffers
    (evil-global-set-key 'motion "j" 'evil-next-visual-line)
    (evil-global-set-key 'motion "k" 'evil-previous-visual-line)

    (evil-set-initial-state 'messages-buffer-mode 'normal)
    (evil-set-initial-state 'dashboard-mode 'normal))

  (use-package evil-surround
    :config (global-evil-surround-mode))

  (use-package evil-collection
    :after evil
    :config
    (evil-collection-init))

Undo tree

  (use-package undo-tree
    :init
    (setq undo-tree-auto-save-history nil)
    (global-undo-tree-mode 1))

Org-mode

  (use-package org
  :hook (org-mode . visual-line-mode) ;; wrap lines
  :config
  (setq org-ellipsis " ▾")
  (setq org-agenda-start-with-log-mode t)
  (setq org-log-done 'time)
  (setq org-cycle-separator-lines 1)
  (setq org-startup-folded 'content)
  (setq org-startup-indented t)
  (setq org-agenda-files '("~/sync/org"))

Org-habit

  (require 'org-habit)
  (add-to-list 'org-modules 'org-habit)
  (setq org-habit-graph-column 60))

Magit

  (use-package magit
    :custom
    (magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1))

Diff-hl (git diff in margin)

  (use-package diff-hl
    :config
    (setq diff-hl-side 'right)
    (global-diff-hl-mode t))

LSP

Eglot

   (defun alex/eglot-organize-imports () (interactive)
     (call-interactively 'eglot-code-action-organize-imports))

   (defun alex/eglot-on-save ()
     (add-hook 'before-save-hook #'eglot-format-buffer -10 t)
     (add-hook 'before-save-hook #'alex/eglot-organize-imports nil t)
   )

  (use-package eglot
    :config
    ;; Ensure `nil` is in your PATH.
    (add-to-list 'eglot-server-programs '(nix-mode . ("nil")))
    :hook (
           (eglot-managed-mode . alex/eglot-on-save)
           (go-mode . eglot-ensure)
           (nix-mode . eglot-ensure)
    )
  )

Eldoc-box

  (use-package eldoc-box
    :after eglot
    :bind (:map eglot-mode-map
              ("M-h" . eldoc-box-help-at-point)))

Go

  (use-package go-mode
    :hook (
           (go-mode . eglot-ensure)
    )
  )

Nix

  (use-package nix-mode
    :mode "\\.nix$"
    :hook (
          (nix-mode . eglot-ensure)
    )
  )

YAML

  (use-package yaml-mode
    :mode (
           ("\\.yml$" . yaml-mode)
           ("\\.yaml$" . yaml-mode)
    )
  )