568 lines
12 KiB
EmacsLisp
568 lines
12 KiB
EmacsLisp
;;; Below are fragments from my Emacs configuration file
|
|
;;; (`~/.emacs.d/init.el`) using
|
|
;;; [straight.el](https://github.com/radian-software/straight.el) instead of
|
|
;;; Emacs builtin `package.el`. (For old `package.el` based version
|
|
;;; see [here](/dotemacs/2022-02-15/)).
|
|
|
|
;;; The newest version of this config is available from a [github
|
|
;;; repo](https://github.com/lukpank/.emacs.d).
|
|
|
|
|
|
;;; Bootstrap straight.el
|
|
;;; ---------------------
|
|
|
|
(defvar bootstrap-version)
|
|
(let ((bootstrap-file
|
|
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
|
|
(bootstrap-version 6))
|
|
(unless (file-exists-p bootstrap-file)
|
|
(with-current-buffer
|
|
(url-retrieve-synchronously
|
|
"https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
|
|
'silent 'inhibit-cookies)
|
|
(goto-char (point-max))
|
|
(eval-print-last-sexp)))
|
|
(load bootstrap-file nil 'nomessage))
|
|
|
|
(setq package-enable-at-startup nil
|
|
straight-use-package-by-default t)
|
|
(straight-use-package 'use-package)
|
|
|
|
|
|
;;; Productivity
|
|
;;; ------------
|
|
|
|
;;; ### Key discoverability ###
|
|
|
|
(use-package which-key
|
|
:init
|
|
(setq which-key-idle-delay 2.0
|
|
which-key-idle-secondary-delay 1.0)
|
|
:config
|
|
(which-key-mode))
|
|
|
|
;;; ### More efficient buffer/file selection ###
|
|
|
|
;;; Requires: [fzf](https://github.com/junegunn/fzf) and
|
|
;;; [ripgrep](https://github.com/BurntSushi/ripgrep) (rg), and git.
|
|
|
|
(setq recentf-max-saved-items 100)
|
|
|
|
(global-set-key "\C-cq" #'bury-buffer)
|
|
|
|
(use-package prescient
|
|
:config
|
|
(prescient-persist-mode))
|
|
|
|
(use-package ivy-prescient
|
|
:after counsel
|
|
:config
|
|
(ivy-prescient-mode))
|
|
|
|
(use-package counsel
|
|
:demand
|
|
:bind (("C-c a" . swiper-all)
|
|
("C-c e" . counsel-flycheck)
|
|
("C-c f" . counsel-fzf)
|
|
("C-c g" . counsel-git)
|
|
("C-c i" . counsel-imenu)
|
|
("C-c j" . counsel-git-grep)
|
|
("C-c L" . counsel-locate)
|
|
("C-c o" . counsel-outline)
|
|
("C-c r" . counsel-rg)
|
|
("C-c R" . counsel-register)
|
|
("C-c T" . counsel-load-theme)
|
|
("C-S-s" . swiper)
|
|
([remap dired] . counsel-dired))
|
|
:init
|
|
(setq ivy-use-virtual-buffers t)
|
|
:config
|
|
(ivy-mode 1)
|
|
(counsel-mode 1))
|
|
|
|
(use-package ivy-rich
|
|
:after ivy
|
|
:config
|
|
(ivy-rich-mode 1))
|
|
|
|
(use-package helpful
|
|
:init
|
|
(setq counsel-describe-function-function #'helpful-callable)
|
|
(setq counsel-describe-variable-function #'helpful-variable))
|
|
|
|
|
|
;;; ### File explorer sidebar ###
|
|
|
|
;;; Install fonts with `M-x all-the-icons-install-fonts`.
|
|
|
|
(use-package dired-sidebar
|
|
:bind ("C-c s" . dired-sidebar-toggle-sidebar))
|
|
|
|
(use-package all-the-icons
|
|
:defer)
|
|
|
|
(use-package all-the-icons-dired
|
|
:hook (dired-mode . all-the-icons-dired-mode))
|
|
|
|
(use-package all-the-icons-ivy-rich
|
|
:after ivy-rich
|
|
:config (all-the-icons-ivy-rich-mode 1))
|
|
|
|
(use-package treemacs
|
|
:bind ("C-c S" . treemacs))
|
|
|
|
|
|
;;; ### Window selection enhancements ###
|
|
|
|
(use-package windmove
|
|
:bind (("H-w j" . windmove-down)
|
|
("H-w k" . windmove-up)
|
|
("H-w h" . windmove-left)
|
|
("H-w l" . windmove-right)))
|
|
|
|
(use-package windswap
|
|
:bind (("H-w J" . windswap-down)
|
|
("H-w K" . windswap-up)
|
|
("H-w H" . windswap-left)
|
|
("H-w L" . windswap-right)))
|
|
|
|
|
|
;;; ### In buffer movement enhancements ###
|
|
|
|
;;; Search
|
|
|
|
(use-package ctrlf
|
|
:config
|
|
(ctrlf-mode))
|
|
|
|
;;; Improved in buffer search
|
|
|
|
(use-package ace-jump-mode
|
|
:bind ("C-." . ace-jump-mode))
|
|
|
|
;;; Go to last change in the current buffer
|
|
|
|
(use-package goto-chg
|
|
:bind ("C-c G" . goto-last-change))
|
|
|
|
|
|
;;; ### Editing enhancements ###
|
|
|
|
;;; Context aware insertion of pairs of parenthesis
|
|
|
|
(use-package smartparens
|
|
:hook ((prog-mode . smartparens-mode)
|
|
(emacs-lisp-mode . smartparens-strict-mode))
|
|
:init
|
|
(setq sp-base-key-bindings 'sp)
|
|
:config
|
|
(define-key smartparens-mode-map [M-backspace] #'backward-kill-word)
|
|
(define-key smartparens-mode-map [M-S-backspace] #'sp-backward-unwrap-sexp)
|
|
(require 'smartparens-config))
|
|
|
|
;;; Edit with multiple cursors
|
|
|
|
(use-package multiple-cursors
|
|
:bind (("C-c n" . mc/mark-next-like-this)
|
|
("C-c p" . mc/mark-previous-like-this)))
|
|
|
|
;;; Fix trailing spaces but only in modified lines
|
|
|
|
(use-package ws-butler
|
|
:hook (prog-mode . ws-butler-mode))
|
|
|
|
|
|
;;; ### Switching buffers ###
|
|
|
|
;;; Bind keys from `H-r a` to `H-r z` to switch to buffers from a
|
|
;;; register from `a` to `z`.
|
|
|
|
(defalias 'pr #'point-to-register)
|
|
|
|
(defun my-switch-to-register ()
|
|
"Switch to buffer given by key binding last character."
|
|
(interactive)
|
|
(let* ((v (this-command-keys-vector))
|
|
(c (aref v (1- (length v))))
|
|
(r (get-register c)))
|
|
(if (and (markerp r) (marker-buffer r))
|
|
(switch-to-buffer (marker-buffer r))
|
|
(jump-to-register c))))
|
|
|
|
(setq my-switch-to-register-map (make-sparse-keymap))
|
|
|
|
(dolist (character (number-sequence ?a ?z))
|
|
(define-key my-switch-to-register-map
|
|
(char-to-string character) #'my-switch-to-register))
|
|
|
|
(global-set-key (kbd "H-r") my-switch-to-register-map)
|
|
|
|
|
|
;;; ### Switching tabs ###
|
|
|
|
(dolist (i (number-sequence 1 9))
|
|
(global-set-key (format "\C-c%d" i) `(lambda () (interactive) (tab-select ,i))))
|
|
|
|
(tab-bar-mode 1)
|
|
|
|
|
|
;;; ### Yasnippet and abbrev mode ###
|
|
|
|
(setq-default abbrev-mode 1)
|
|
|
|
(use-package yasnippet
|
|
:defer 2
|
|
:config
|
|
(yas-global-mode 1))
|
|
|
|
(use-package yasnippet-snippets
|
|
:defer)
|
|
|
|
(use-package ivy-yasnippet
|
|
:bind ("C-c y" . ivy-yasnippet))
|
|
|
|
|
|
;;; Programming modes
|
|
;;; -----------------
|
|
|
|
;;; ### company and lsp-mode ###
|
|
|
|
;;; For modes using [company](https://company-mode.github.io/) for tab
|
|
;;; completion add
|
|
|
|
(use-package company
|
|
:bind (:map prog-mode-map
|
|
("C-i" . company-indent-or-complete-common)
|
|
("C-M-i" . counsel-company))
|
|
:hook (emacs-lisp-mode . company-mode))
|
|
|
|
(use-package company-prescient
|
|
:after company
|
|
:config
|
|
(company-prescient-mode))
|
|
|
|
;;; For modes that also use Language Server Protocol from [lsp-mode]
|
|
;;; add
|
|
|
|
(use-package lsp-mode
|
|
:hook ((c-mode c++-mode d-mode elm-mode go-mode js-mode kotlin-mode python-mode
|
|
typescript-mode vala-mode web-mode)
|
|
. lsp)
|
|
:init
|
|
(setq lsp-keymap-prefix "H-l"
|
|
lsp-rust-analyzer-proc-macro-enable t)
|
|
:config
|
|
(lsp-enable-which-key-integration t))
|
|
|
|
(use-package lsp-ui
|
|
:init
|
|
(setq lsp-ui-doc-position 'at-point
|
|
lsp-ui-doc-show-with-mouse nil
|
|
lsp-ui-sideline-show-code-actions t)
|
|
:bind (("C-c A" . lsp-execute-code-action)
|
|
("C-c d" . lsp-ui-doc-show)
|
|
("C-c I" . lsp-ui-imenu)))
|
|
|
|
(use-package flycheck
|
|
:defer)
|
|
|
|
;;; [lsp-mode]: https://emacs-lsp.github.io/lsp-mode/
|
|
|
|
;;; Compilation
|
|
|
|
(global-set-key "\C-ck" #'compile)
|
|
|
|
;;; [company and lsp-mode]: #company-and-lsp-mode
|
|
|
|
|
|
;;; ### C and C++ ###
|
|
|
|
;;; Requires: [company and lsp-mode],
|
|
;;; [clangd](https://clangd.llvm.org/).
|
|
|
|
(use-package cc-mode
|
|
:straight nil
|
|
:bind (:map c-mode-map
|
|
("C-i" . company-indent-or-complete-common)
|
|
:map c++-mode-map
|
|
("C-i" . company-indent-or-complete-common))
|
|
:init
|
|
(setq-default c-basic-offset 8))
|
|
|
|
|
|
;;; ### D ###
|
|
|
|
;;; Requires: [company and lsp-mode], `dmd`, `dub`,
|
|
;;; [dcd](https://code.dlang.org/packages/dcd), and
|
|
;;; [dtools](https://code.dlang.org/packages/dtools) (for `rdmd`) to
|
|
;;; build [serve-d](https://code.dlang.org/packages/serve-d) (but
|
|
;;; first check for newer version) with
|
|
|
|
;;; $ dub fetch serve-d@0.7.4
|
|
;;; $ dub run serve-d --build=release
|
|
;;; $ ln -s ~/.dub/packages/serve-d-0.7.4/serve-d/serve-d ~/.local/bin/
|
|
|
|
(use-package d-mode
|
|
:bind (:map d-mode-map
|
|
("C-i" . company-indent-or-complete-common)))
|
|
|
|
|
|
;;; ### Dart ###
|
|
|
|
;;; Requires: [company and lsp-mode], `flutter` in `PATH`,
|
|
;;; `flutter doctor` should be OK, and `M-x lsp-dart-dap-setup`.
|
|
|
|
(use-package dart-mode)
|
|
|
|
(use-package lsp-dart
|
|
:hook (dart-mode . lsp)
|
|
:bind (:map lsp-mode
|
|
("C-M-x" . lsp-dart-dap-flutter-hot-reload)))
|
|
|
|
|
|
;;; ### Elm ###
|
|
|
|
;;; Requires: [company and lsp-mode].
|
|
(use-package elm-mode
|
|
:hook (elm-mode . elm-indent-mode))
|
|
|
|
|
|
;;; ### Emacs lisp ###
|
|
|
|
;;; Requires: [company and lsp-mode] (actually just `company`) and
|
|
;;; [smartparens](#editing-enhancements).
|
|
|
|
|
|
;;; ### Go ###
|
|
|
|
;;; Requires: [company and lsp-mode],
|
|
;;; [gopls](https://github.com/golang/tools/blob/master/gopls/README.md#installation).
|
|
|
|
(defun my-go-before-save ()
|
|
"Format buffer and organize imports in Go mode."
|
|
(when (eq major-mode 'go-mode)
|
|
(lsp-organize-imports)
|
|
(lsp-format-buffer)))
|
|
|
|
(use-package go-mode
|
|
:hook (before-save . my-go-before-save))
|
|
|
|
|
|
;;; ### JavaScript ###
|
|
|
|
;;; Requires: [company and lsp-mode] `ts-ls` (proposed by [lsp-mode]
|
|
;;; when missing).
|
|
|
|
(use-package js
|
|
:straight nil
|
|
:bind (:map js-mode-map
|
|
([remap js-find-symbol] . xref-find-definitions))
|
|
:init
|
|
(setq js-indent-level 4))
|
|
|
|
|
|
;;; ### Kotlin ###
|
|
|
|
;;; Requires:
|
|
;;; [kotlin-language-server](https://github.com/fwcd/kotlin-language-server).
|
|
|
|
(use-package kotlin-mode)
|
|
|
|
;;; ### Lisp ###
|
|
|
|
(use-package sly
|
|
:defer
|
|
:config
|
|
(setq inferior-lisp-program "sbcl"
|
|
sly-mrepl-pop-sylvester nil)
|
|
:custom-face
|
|
(sly-mrepl-output-face ((t (:foreground "sienna")))))
|
|
|
|
(use-package paren-face
|
|
:defer)
|
|
|
|
(use-package paredit
|
|
:defer)
|
|
|
|
(use-package highlight-parentheses
|
|
:defer)
|
|
|
|
(defun my-lisp-mode-hook-fn ()
|
|
(smartparens-mode 0)
|
|
(paredit-mode 1)
|
|
(paren-face-mode 1)
|
|
(highlight-parentheses-mode 1)
|
|
(company-mode 1))
|
|
|
|
(add-hook 'lisp-mode-hook 'my-lisp-mode-hook-fn)
|
|
(add-hook 'emacs-lisp-mode-hook 'my-lisp-mode-hook-fn)
|
|
|
|
;;; ### Meson build system ###
|
|
|
|
(use-package meson-mode
|
|
:defer
|
|
:init
|
|
(setq meson-indent-basic 4))
|
|
|
|
|
|
;;; ### Python ###
|
|
|
|
;;; Requires: [company and lsp-mode],
|
|
;;; [pylsp](https://pypi.org/project/python-lsp-server/).
|
|
|
|
|
|
;;; ### Rust ###
|
|
|
|
;;; Requires: [company and lsp-mode], `rust-src` from [Rustup]
|
|
;;; and [rust-analyzer].
|
|
|
|
;;; [Rustup]: https://www.rust-lang.org/learn/get-started
|
|
;;; [rust-analyzer]: https://rust-analyzer.github.io/manual.html#installation
|
|
|
|
(use-package rustic
|
|
:defer)
|
|
|
|
|
|
;;; ### TypeScript ###
|
|
|
|
;;; Requires: [company and lsp-mode], [web-mode settings] (for tsx),
|
|
;;; `ts-ls` (proposed by [lsp-mode] when missing),
|
|
;;; [tsconfig.json](https://www.typescriptlang.org/docs/handbook/tsconfig-json.html).
|
|
|
|
(use-package typescript-mode
|
|
:defer)
|
|
|
|
|
|
;;; ### Vala ###
|
|
|
|
;;; Requires: [company and lsp-mode],
|
|
;;; [vala-language-server](https://github.com/Prince781/vala-language-server#installation).
|
|
|
|
(use-package vala-mode
|
|
:defer)
|
|
|
|
|
|
;;; ### Web mode ###
|
|
|
|
;;; Requires: [company and lsp-mode].
|
|
|
|
(use-package web-mode
|
|
:mode "\\.\\([jt]sx\\)\\'")
|
|
|
|
;;; [web-mode settings]: #web-mode
|
|
|
|
|
|
;;; Other modes
|
|
;;; -----------
|
|
|
|
(use-package ansible
|
|
:straight (:nonrecursive t))
|
|
|
|
(use-package devdocs
|
|
:bind ("C-c D" . devdocs-lookup))
|
|
|
|
(use-package diff-hl
|
|
:defer)
|
|
|
|
(use-package htmlize
|
|
:defer)
|
|
|
|
(use-package rainbow-mode
|
|
:hook css-mode)
|
|
|
|
(use-package restclient
|
|
:defer)
|
|
|
|
(use-package vterm
|
|
:defer
|
|
:init
|
|
(dolist (i (number-sequence 0 9))
|
|
(global-set-key (kbd (format "H-%d" i)) `(lambda () (interactive) (vterm ,i)))))
|
|
|
|
(use-package yaml-mode
|
|
:defer)
|
|
|
|
|
|
;;; ### Git ###
|
|
|
|
(use-package magit
|
|
:bind (("C-x g" . magit-status)
|
|
("C-x M-g" . magit-dispatch))
|
|
:init
|
|
(setq project-switch-commands nil)) ; avoid magit error on C-n/C-p
|
|
|
|
(use-package git-messenger
|
|
:bind ("C-x G" . git-messenger:popup-message)
|
|
:config
|
|
(setq git-messenger:show-detail t
|
|
git-messenger:use-magit-popup t))
|
|
|
|
(use-package git-timemachine
|
|
:bind ("C-c t" . git-timemachine))
|
|
|
|
|
|
;;; Appearance
|
|
;;; ----------
|
|
|
|
;;; ### Minimalistic look ###
|
|
|
|
(setq inhibit-startup-screen t)
|
|
(set-scroll-bar-mode 'right)
|
|
(menu-bar-mode 0)
|
|
(tool-bar-mode 0)
|
|
(scroll-bar-mode 0)
|
|
|
|
|
|
;;; ### Mode line ###
|
|
|
|
(use-package smart-mode-line
|
|
:config
|
|
(setq sml/no-confirm-load-theme t
|
|
sml/shorten-directory t
|
|
sml/shorten-modes t
|
|
sml/name-width 50
|
|
sml/mode-width 'full
|
|
sml/theme 'respectful)
|
|
(sml/setup))
|
|
|
|
|
|
;;; ### Switching themes ###
|
|
|
|
(use-package base16-theme
|
|
:defer)
|
|
|
|
(use-package faff-theme
|
|
:defer)
|
|
|
|
(setq my-dark-theme 'base16-espresso
|
|
my-light-theme 'base16-mexico-light)
|
|
|
|
(defun my-select-theme (theme)
|
|
(mapc #'disable-theme custom-enabled-themes)
|
|
(load-theme (cond
|
|
((eq theme 'dark) my-dark-theme)
|
|
((eq theme 'light) my-light-theme)
|
|
(t theme))
|
|
t)
|
|
(sml/setup))
|
|
|
|
(defun my-select-theme-if-none-selected (frame)
|
|
(if (and (eq 'x (window-system frame))
|
|
(null (seq-filter (lambda (theme)
|
|
(not (string-prefix-p "smart-mode-line-"
|
|
(symbol-name theme))))
|
|
custom-enabled-themes)))
|
|
(my-select-theme 'dark)))
|
|
|
|
(my-select-theme-if-none-selected nil)
|
|
(add-to-list 'after-make-frame-functions #'my-select-theme-if-none-selected)
|
|
|
|
(defun my-toggle-theme ()
|
|
"Toggle between dark and light themes."
|
|
(interactive)
|
|
(my-select-theme (if (custom-theme-enabled-p my-dark-theme)
|
|
my-light-theme
|
|
my-dark-theme)))
|
|
|
|
(global-set-key (kbd "C-S-<f6>") #'my-toggle-theme)
|