#+STARTUP: overview #+TITLE: My Emacs #+CREATOR: Laurens Miers #+LANGUAGE: en * Elpaca ** Core #+begin_src emacs-lisp (defvar elpaca-installer-version 0.7) (defvar elpaca-directory (expand-file-name "elpaca/" user-emacs-directory)) (defvar elpaca-builds-directory (expand-file-name "builds/" elpaca-directory)) (defvar elpaca-repos-directory (expand-file-name "repos/" elpaca-directory)) (defvar elpaca-order '(elpaca :repo "https://github.com/progfolio/elpaca.git" :ref nil :depth 1 :files (:defaults "elpaca-test.el" (:exclude "extensions")) :build (:not elpaca--activate-package))) (let* ((repo (expand-file-name "elpaca/" elpaca-repos-directory)) (build (expand-file-name "elpaca/" elpaca-builds-directory)) (order (cdr elpaca-order)) (default-directory repo)) (add-to-list 'load-path (if (file-exists-p build) build repo)) (unless (file-exists-p repo) (make-directory repo t) (when (< emacs-major-version 28) (require 'subr-x)) (condition-case-unless-debug err (if-let ((buffer (pop-to-buffer-same-window "*elpaca-bootstrap*")) ((zerop (apply #'call-process `("git" nil ,buffer t "clone" ,@(when-let ((depth (plist-get order :depth))) (list (format "--depth=%d" depth) "--no-single-branch")) ,(plist-get order :repo) ,repo)))) ((zerop (call-process "git" nil buffer t "checkout" (or (plist-get order :ref) "--")))) (emacs (concat invocation-directory invocation-name)) ((zerop (call-process emacs nil buffer nil "-Q" "-L" "." "--batch" "--eval" "(byte-recompile-directory \".\" 0 'force)"))) ((require 'elpaca)) ((elpaca-generate-autoloads "elpaca" repo))) (progn (message "%s" (buffer-string)) (kill-buffer buffer)) (error "%s" (with-current-buffer buffer (buffer-string)))) ((error) (warn "%s" err) (delete-directory repo 'recursive)))) (unless (require 'elpaca-autoloads nil t) (require 'elpaca) (elpaca-generate-autoloads "elpaca" repo) (load "./elpaca-autoloads"))) (add-hook 'after-init-hook #'elpaca-process-queues) (elpaca `(,@elpaca-order)) #+end_src ** Use-package integration #+begin_src emacs-lisp ;; Install use-package support (elpaca elpaca-use-package ;; Enable use-package :ensure support for Elpaca. (elpaca-use-package-mode) ) ;; wait to get elpaca use-package integration (elpaca-wait) #+end_src * Built-in packages ** Eldoc I got the following error message when loading eglot: #+BEGIN_SRC eglot failed eldoc installed version (1 13 0) lower than min required 1.14.0 00.239351 #+END_SRC So install the eldoc package to be sure we have the latest version. But after installing it, we get a new warning: #+BEGIN_SRC ⛔ Warning (emacs): eldoc loaded before Elpaca activation #+END_SRC This seemed tricker than expected, but found a solution in the github issues of elpaca: https://github.com/progfolio/elpaca/issues/236 #+BEGIN_SRC emacs-lisp (use-package eldoc :preface ;; avoid loading of built-in eldoc, see https://github.com/progfolio/elpaca/issues/236#issuecomment-1879838229 (unload-feature 'eldoc t) (setq custom-delayed-init-variables '()) (defvar global-eldoc-mode nil) :demand t :config (global-eldoc-mode)) #+END_SRC ** Jsonrpc After eldoc was taken care of, a new error was reported: #+BEGIN_SRC eglot failed jsonrpc installed version (1 0 16) lower than min required 1.0.24 00.280828 #+END_SRC So let's install the latest one: #+BEGIN_SRC emacs-lisp (use-package jsonrpc) #+END_SRC ** Wait for loading updated packages Wait until updated built-in packages are fully loaded: #+BEGIN_SRC emacs-lisp (elpaca-wait) #+END_SRC * General config ** Bell The audible bell is annoying AF. #+BEGIN_SRC emacs-lisp (setq visible-bell 1) #+END_SRC ** Enable column numbers #+BEGIN_SRC emacs-lisp (setq column-number-mode 1) #+END_SRC ** Delete trailing whitespaces #+BEGIN_SRC emacs-lisp (add-hook 'before-save-hook 'delete-trailing-whitespace) #+END_SRC ** Save history and recent files #+begin_src emacs-lisp ;; The built-in `savehist-mode' saves minibuffer histories. Vertico ;; can then use that information to put recently selected options at ;; the top. ;; ;; Further reading: https://protesilaos.com/emacs/dotemacs#h:25765797-27a5-431e-8aa4-cc890a6a913a (savehist-mode 1) ;; The built-in `recentf-mode' keeps track of recently visited files. ;; You can then access those through the `consult-buffer' interface or ;; with `recentf-open'/`recentf-open-files'. ;; ;; I do not use this facility, because the files I care about are ;; either in projects or are bookmarked. (recentf-mode 1) #+end_src ** Backups #+BEGIN_SRC emacs-lisp (defvar myrmi-backup-directory (concat user-emacs-directory "backups")) (if (not (file-exists-p myrmi-backup-directory)) (make-directory myrmi-backup-directory t) ) (setq backup-directory-alist `(("." . ,myrmi-backup-directory))) (setq make-backup-files t backup-by-copying t version-control t delete-old-versions t delete-by-moving-to-trash t kept-old-versions 6 kept-new-versions 9 auto-save-default t auto-save-timeout 20 auto-save-interval 200 ) #+END_SRC ** Yes-or-no Because I'm lazy, important yes-or-no questions can be answered with y-or-n: #+begin_src emacs-lisp (defalias 'yes-or-no-p 'y-or-n-p) #+end_src ** Switch windows #+begin_src emacs-lisp (global-set-key (kbd "M-o") 'other-window) #+end_src ** Maximize at startup More info : https://www.emacswiki.org/emacs/FullScreen #+begin_src emacs-lisp (push '(fullscreen . maximized) default-frame-alist) #+end_src ** ibuffer Use list-buffers bigger brother. #+begin_src emacs-lisp (global-set-key [remap list-buffers] 'ibuffer) #+end_src ** Mark #+begin_src emacs-lisp (global-set-key (kbd "M-SPC") 'mark-word) #+end_src ** Isearch Display number of matches: #+begin_src emacs-lisp (setq-default isearch-lazy-count t) #+end_src Reference that might be interesting for later: https://endlessparentheses.com/leave-the-cursor-at-start-of-match-after-isearch.html ** Abbrev #+begin_src emacs-lisp (global-set-key [remap dabbrev-expand] 'hippie-expand) #+end_src ** Zap #+begin_src emacs-lisp (global-set-key (kbd "M-S-z") 'zap-up-to-char) #+end_src ** Spell checking Look into customizing the 'ispell' group. #+begin_src emacs-lisp (add-hook 'prog-mode-hook 'flyspell-prog-mode) #+end_src ** Delete selection mode #+BEGIN_SRC emacs-lisp (delete-selection-mode t) #+END_SRC ** Enable disabled commands Some commands are disabled to protect the user. Narrow-region/page is a really handy feature, enable it: #+BEGIN_SRC emacs-lisp (put 'narrow-to-page 'disabled nil) (put 'narrow-to-region 'disabled nil) #+END_SRC ** Use-package *** Always ensure #+BEGIN_SRC emacs-lisp (require 'use-package-ensure) (setq use-package-always-ensure t) #+END_SRC ** Adaptive cursor width Make cursor the width of the character it is under f.e. full width of a tab. #+BEGIN_SRC emacs-lisp (setq x-stretch-cursor t) #+END_SRC ** Enable auto-revert #+BEGIN_SRC emacs-lisp (setq global-auto-revert-mode 1) #+END_SRC * Resize-mode Minor-mode to easily resize frames (works with EXWM (firefox, ...)). Courtesy goes to kuanyui (https://gist.github.com/kuanyui/65a408d393871048771c): #+BEGIN_SRC emacs-lisp ;;; resize-frame.el --- A minor mode to resize frames easily. -*- lexical-binding: t; -*- ;; Copyright (C) 2014 kuanyui ;; Author: kuanyui ;; Keywords: frames, tools, convenience ;; License: WTFPL 1.0 ;;; Commentary: ;; Press "ESC `" and use arrow-keys or i/j/k/l to adjust frames. press any key to done. ;;; Code: (defvar resize-frame-map (let ((map (make-keymap))) (define-key map (kbd "") 'enlarge-window) (define-key map (kbd "") 'shrink-window) (define-key map (kbd "") 'enlarge-window-horizontally) (define-key map (kbd "") 'shrink-window-horizontally) (set-char-table-range (nth 1 map) t 'resize-frame-done) (define-key map (kbd "C-p") 'enlarge-window) (define-key map (kbd "C-n") 'shrink-window) (define-key map (kbd "C-f") 'enlarge-window-horizontally) (define-key map (kbd "C-b") 'shrink-window-horizontally) map)) (define-minor-mode resize-frame "A simple minor mode to resize-frame. C-c C-c to apply." ;; The initial value. :init-value nil ;; The indicator for the mode line. :lighter " ResizeFrame" ;; The minor mode bindings. :keymap resize-frame-map :global t (if (<= (length (window-list)) 1) (progn (setq resize-frame nil) (message "Only root frame exists, abort.")) (message "Use arrow-keys or i/j/k/l to adjust frames."))) (defun resize-frame-done () (interactive) (setq resize-frame nil) (message "Done.")) (global-set-key (kbd "C-x C-r") 'resize-frame) #+END_SRC * Completion ** Minibuffer #+BEGIN_SRC emacs-lisp ;; Enable vertico (use-package vertico ;; :custom ;; (vertico-scroll-margin 0) ;; Different scroll margin ;; (vertico-count 20) ;; Show more candidates ;; (vertico-resize t) ;; Grow and shrink the Vertico minibuffer ;; (vertico-cycle t) ;; Enable cycling for `vertico-next/previous' :init (vertico-mode)) #+END_SRC ** Consult #+BEGIN_SRC emacs-lisp (use-package consult ;; Replace bindings. Lazily loaded by `use-package'. :bind (;; C-c bindings in `mode-specific-map' ;; ("C-c M-x" . consult-mode-command) ;; ("C-c h" . consult-history) ;; ("C-c k" . consult-kmacro) ;; ("C-c m" . consult-man) ;; ("C-c i" . consult-info) ([remap Info-search] . consult-info) ;; C-x bindings in `ctl-x-map' ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command ("C-x b" . consult-buffer) ;; orig. switch-to-buffer ("C-x 4 b" . consult-buffer-other-window) ;; orig. switch-to-buffer-other-window ("C-x 5 b" . consult-buffer-other-frame) ;; orig. switch-to-buffer-other-frame ("C-x t b" . consult-buffer-other-tab) ;; orig. switch-to-buffer-other-tab ("C-x r b" . consult-bookmark) ;; orig. bookmark-jump ("C-x p b" . consult-project-buffer) ;; orig. project-switch-to-buffer ;; Custom M-# bindings for fast register access ;; ("M-#" . consult-register-load) ("M-'" . consult-register-store) ;; orig. abbrev-prefix-mark (unrelated) ;; ("C-M-#" . consult-register) ;; Other custom bindings ("M-y" . consult-yank-pop) ;; orig. yank-pop ;; M-g bindings in `goto-map' ("M-g e" . consult-compile-error) ("M-g f" . consult-flymake) ;; Alternative: consult-flycheck ("M-g g" . consult-goto-line) ;; orig. goto-line ("M-g M-g" . consult-goto-line) ;; orig. goto-line ;; ("M-g o" . consult-outline) ;; Alternative: consult-org-heading ;; ("M-g m" . consult-mark) ;; ("M-g k" . consult-global-mark) ("M-i" . consult-imenu) ("M-I" . consult-imenu-multi) ;; M-s bindings in `search-map' ("M-s d" . consult-find) ;; Alternative: consult-fd ;; ("M-s c" . consult-locate) ("M-s g" . consult-grep) ;; ("M-s G" . consult-git-grep) ;; ("M-s r" . consult-ripgrep) ("M-s l" . consult-line) ;; ("M-s L" . consult-line-multi) ;; ("M-s k" . consult-keep-lines) ;; ("M-s u" . consult-focus-lines) ;; Isearch integration ("M-s e" . consult-isearch-history) :map isearch-mode-map ("M-e" . consult-isearch-history) ;; orig. isearch-edit-string ("M-s e" . consult-isearch-history) ;; orig. isearch-edit-string ("M-s l" . consult-line) ;; needed by consult-line to detect isearch ("M-s L" . consult-line-multi) ;; needed by consult-line to detect isearch ;; Minibuffer history :map minibuffer-local-map ("M-s" . consult-history) ;; orig. next-matching-history-element ("M-r" . consult-history) ;; orig. previous-matching-history-element ) ;; Enable automatic preview at point in the *Completions* buffer. This is ;; relevant when you use the default completion UI. :hook (completion-list-mode . consult-preview-at-point-mode) ;; The :init configuration is always executed (Not lazy) :init ;; Optionally configure the register formatting. This improves the register ;; preview for `consult-register', `consult-register-load', ;; `consult-register-store' and the Emacs built-ins. ;; (setq register-preview-delay 0.5 ;; register-preview-function #'consult-register-format) ;; Optionally tweak the register preview window. ;; This adds thin lines, sorting and hides the mode line of the window. ;; (advice-add #'register-preview :override #'consult-register-window) ;; Use Consult to select xref locations with preview (setq xref-show-xrefs-function #'consult-xref xref-show-definitions-function #'consult-xref) ;; Configure other variables and modes in the :config section, ;; after lazily loading the package. ;; :config ;; Optionally configure preview. The default value ;; is 'any, such that any key triggers the preview. ;; (setq consult-preview-key 'any) ;; (setq consult-preview-key "M-.") ;; (setq consult-preview-key '("S-" "S-")) ;; For some commands and buffer sources it is useful to configure the ;; :preview-key on a per-command basis using the `consult-customize' macro. ;; (consult-customize ;; consult-theme :preview-key '(:debounce 0.2 any) ;; consult-ripgrep consult-git-grep consult-grep ;; consult-bookmark consult-recent-file consult-xref ;; consult--source-bookmark consult--source-file-register ;; consult--source-recent-file consult--source-project-recent-file ;; :preview-key "M-." ;; :preview-key '(:debounce 0.4 any)) ;; Optionally configure the narrowing key. ;; Both < and C-+ work reasonably well. ;; (setq consult-narrow-key "<") ;; "C-+" ;; Optionally make narrowing help available in the minibuffer. ;; You may want to use `embark-prefix-help-command' or which-key instead. ;; (keymap-set consult-narrow-map (concat consult-narrow-key " ?") #'consult-narrow-help) ) #+END_SRC ** In-buffer completion *** Consult #+BEGIN_SRC emacs-lisp (setq completion-in-region-function (lambda (&rest args) (apply (if vertico-mode #'consult-completion-in-region #'completion--in-region) args))) #+END_SRC *** Corfu #+BEGIN_SRC emacs-lisp (use-package corfu ;; Optional customizations :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 ;; Enable Corfu only for certain modes. See also `global-corfu-modes'. ;; :hook ((prog-mode . corfu-mode) ;; (shell-mode . corfu-mode) ;; (eshell-mode . corfu-mode)) ;; Recommended: Enable Corfu globally. This is recommended since Dabbrev can ;; be used globally (M-/). See also the customization variable ;; `global-corfu-modes' to exclude certain modes. :init (global-corfu-mode)) #+end_src *** Company-mode #+BEGIN_SRC (use-package company :config (define-key prog-mode-map (kbd "TAB") #'company-indent-or-complete-common) :init (global-company-mode) ) #+END_SRC ** Orderless #+begin_src emacs-lisp (use-package orderless :demand t :custom (completion-styles '(orderless basic)) ;; (gnus-completion-styles '(orderless substring basic)) ;; (completion-category-overrides '((file (styles basic partial-completion)))) ;; Below not necessary if using vertico ;; (completion-category-overrides '( ;; (command (styles orderless basic partial-completion)) ;; (file (styles orderless basic partial-completion)) ;;;; (buffer (styles orderless basic)) ;; (variable (styles orderless basic)) ;; (symbol (styles orderless basic)) ;; (consult-location (styles orderless)) ;; (consult-multi (styles orderless)) ;; ) ;; ) ) #+end_src ** Marginalia #+begin_src emacs-lisp ;; Enable rich annotations using the Marginalia package (use-package marginalia ;; Bind `marginalia-cycle' locally in the minibuffer. To make the binding ;; available in the *Completions* buffer, add it to the ;; `completion-list-mode-map'. :bind (:map minibuffer-local-map ("M-A" . marginalia-cycle)) ;; The :init section is always executed. :init ;; Marginalia must be activated in the :init section of use-package such that ;; the mode gets enabled right away. Note that this forces loading the ;; package. (marginalia-mode)) #+end_src * Dired ** Dired-x #+begin_src emacs-lisp (with-eval-after-load 'dired (require 'dired-x) ;; Set dired-x global variables here. For example: ;; (setq dired-x-hands-off-my-keys nil) ) (add-hook 'dired-mode-hook (lambda () ;; Set dired-x buffer-local variables here. For example: ;; (dired-omit-mode 1) )) #+end_src ** Guess target directory I currently prefer to have two dired windows open in the same frame. Instruct dired to 'Prefer next windows on the same frame' when renaming/copying files. #+BEGIN_SRC emacs-lisp (setq dired-dwim-target 'dired-dwim-target-next) #+END_SRC * Whole-line-or-region Source: https://github.com/purcell/whole-line-or-region Operate on the current line if no region is active. #+begin_src emacs-lisp (use-package whole-line-or-region :config (whole-line-or-region-global-mode 1) ) #+end_src * Terminal ** Eshell *** Smart mode Plan 9 smart terminal features, for more info: https://www.masteringemacs.org/article/complete-guide-mastering-eshell #+BEGIN_SRC emacs-lisp (require 'eshell) (require 'em-smart) (setq eshell-where-to-jump 'begin) (setq eshell-review-quick-commands nil) (setq eshell-smart-space-goes-to-end t) (add-hook 'eshell-mode-hook 'eshell-smart-initialize) #+END_SRC ** Toggle between char- and line-mode Courtesy goes to https://joelmccracken.github.io/entries/switching-between-term-mode-and-line-mode-in-emacs-term/ #+BEGIN_SRC emacs-lisp (require 'term) (defun jnm/term-toggle-mode () "Toggles term between line mode and char mode" (interactive) (if (term-in-line-mode) (term-char-mode) (term-line-mode))) (define-key term-mode-map (kbd "C-c C-j") 'jnm/term-toggle-mode) (define-key term-mode-map (kbd "C-c C-k") 'jnm/term-toggle-mode) (define-key term-raw-map (kbd "C-c C-j") 'jnm/term-toggle-mode) (define-key term-raw-map (kbd "C-c C-k") 'jnm/term-toggle-mode) #+END_SRC For the keybindings, we have to defien them in both raw and line mode. From the help page of term mode: If you define custom keybindings, make sure to assign them to the correct keymap (or to both): use ‘term-raw-map’ in raw mode and ‘term-mode-map’ in line mode. * Theme #+BEGIN_SRC emacs-lisp (use-package monokai-theme :init (load-theme 'monokai t) ) #+END_SRC * Dashboard #+begin_src emacs-lisp (use-package dashboard :config (add-hook 'elpaca-after-init-hook #'dashboard-insert-startupify-lists) (add-hook 'elpaca-after-init-hook #'dashboard-initialize) (dashboard-setup-startup-hook)) #+end_src * Hydra Install and wait for hydra to be available since we are using it in this init.el : #+begin_src emacs-lisp (use-package hydra :ensure (:wait t) ) #+end_src ** Text zoom #+begin_src emacs-lisp (defhydra hydra-zoom (global-map "") "zoom" ("g" text-scale-increase "in") ("l" text-scale-decrease "out") ) #+end_src * Zygospore Revert =C-x 1= by pressing =C-x 1= again: [[https://github.com/louiskottmann/zygospore.el]] FYI: At one point, used this together with sr-speedbar. They did not play well together... #+BEGIN_SRC emacs-lisp (use-package zygospore :config (global-set-key (kbd "C-x 1") 'zygospore-toggle-delete-other-windows) ) #+END_SRC * Iedit Highlight occurences of symbol and replace them simultanously. Shortkey: =C-;= https://github.com/victorhge/iedit #+BEGIN_SRC emacs-lisp (use-package iedit) #+END_SRC * Programming ** Angry faces #+BEGIN_SRC emacs-lisp (defface highlight-angry-faces '( (default :background "Yellow" :foreground "Red") ) "Angry faces highlighting." :group 'basic-faces ) (mapc (lambda (mode) (font-lock-add-keywords mode '( ("\\<\\(FIXME\\)" 1 'highlight-angry-faces t) ("\\<\\(TODO\\)" 1 'highlight-angry-faces t) ))) '(text-mode emacs-lisp-mode rust-mode zig-mode c-ts-mode c-mode prog-mode) ) #+END_SRC ** Electric pair #+BEGIN_SRC emacs-lisp (add-hook 'prog-mode-hook 'electric-pair-mode) #+END_SRC ** Eglot #+BEGIN_SRC emacs-lisp (use-package eglot) (setq eglot-stay-out-of '(xref)) (add-hook 'prog-mode-hook 'eglot-ensure) (add-hook 'eglot-managed-mode-hook (lambda () (if (eglot-managed-p) (add-hook 'xref-backend-functions 'eglot-xref-backend) (remove-hook 'xref-backend-functions 'eglot-xref-backend) ))) #+END_SRC ** Markdown-mode #+BEGIN_SRC emacs-lisp (use-package markdown-mode) #+END_SRC ** Yasnippet #+BEGIN_SRC emacs-lisp (use-package yasnippet :hook (prog-mode . yas-minor-mode) (org-mode . yas-minor-mode) (text-mode . yas-minor-mode) :config (yas-reload-all) ) #+END_SRC ** Magit *** Transient Magit depends on this and it seems it's not installed as a dependency, so install it explicitly. #+BEGIN_SRC emacs-lisp (use-package transient :ensure (:wait t) ) #+END_SRC *** Core #+BEGIN_SRC emacs-lisp (use-package magit :ensure (:wait t) ) #+END_SRC **** Extra commands ***** Update all submodules #+BEGIN_SRC emacs-lisp (transient-define-suffix magit-submodule-update-all () "Update all submodules" :description "Update All git submodule update --init --recursive" (interactive) (magit-with-toplevel (magit-run-git-async "submodule" "update" "--force"))) (transient-append-suffix 'magit-submodule "f" '("U" magit-submodule-update-all)) #+END_SRC ** Dumb-jump #+BEGIN_SRC emacs-lisp (use-package dumb-jump :init (add-hook 'xref-backend-functions #'dumb-jump-xref-activate) ) #+END_SRC ** C-programming *** Tree-sitter #+BEGIN_SRC emacs-lisp (add-to-list 'major-mode-remap-alist '(c-mode . c-ts-mode)) #+END_SRC ** Compilation *** Goto end of buffer on completion Compilation output is almost always bigger than a normal buffer. Move to the end if the compilation finishes. #+BEGIN_SRC emacs-lisp (defun goto-end-compilation-buffer (comp-buffer msg) (goto-char (point-max)) ) (add-hook 'compilation-finish-functions #'goto-end-compilation-buffer) #+END_SRC ** Rust #+BEGIN_SRC emacs-lisp (use-package rust-mode :init (setq rust-mode-treesitter-derive t)) #+END_SRC ** Zig #+BEGIN_SRC emacs-lisp (use-package zig-mode) #+END_SRC ** Python #+BEGIN_SRC emacs-lisp (use-package python-mode) #+END_SRC * Multiple cursors #+BEGIN_SRC emacs-lisp (use-package multiple-cursors :bind ("C-x r a" . mc/edit-beginnings-of-lines) ("C-x r e" . mc/edit-ends-of-lines) ("C->" . mc/mark-next-like-this) ("C-<" . mc/mark-previous-like-this) ("C-c C->" . mc/mark-all-like-this) ) #+END_SRC * Volatile highlights Show/highlight changes when doing undo/yanks/kills/... https://github.com/k-talo/volatile-highlights.el #+BEGIN_SRC emacs-lisp (use-package volatile-highlights :config (volatile-highlights-mode t) ) #+END_SRC * Comment-dwim-2 Replacement for built-in =comment-dwim=, more comment features. https://github.com/remyferre/comment-dwim-2 #+BEGIN_SRC emacs-lisp (use-package comment-dwim-2 :config (global-set-key (kbd "M-;") 'comment-dwim-2) ) #+END_SRC * Projectile #+BEGIN_SRC emacs-lisp (use-package projectile :config (setq projectile-enable-caching t) (define-key projectile-mode-map (kbd "C-x p") 'projectile-command-map) (projectile-mode +1) (require 'project) (add-hook 'project-find-functions #'project-projectile) ) #+END_SRC * Org ** General config *** Super/Sub-scripts Use ={}= for subscripting: https://orgmode.org/manual/Subscripts-and-superscripts.html #+BEGIN_SRC emacs-lisp (setq org-use-sub-superscripts '{}) #+END_SRC *** Indentation Preserve indentation in SRC blocks #+BEGIN_SRC emacs-lisp (setq org-src-preserve-indentation t) #+END_SRC ** Org-todo *** Mark parent entry as DONE when children are DONE #+BEGIN_SRC emacs-lisp (defun org-summary-todo (n-done n-not-done) "Switch entry to DONE when all subentries are done, to TODO otherwise." (let (org-log-done org-todo-log-states) ; turn off logging (org-todo (if (= n-not-done 0) "DONE" "TODO")))) (add-hook 'org-after-todo-statistics-hook #'org-summary-todo) #+END_SRC ** Org bullets #+BEGIN_SRC emacs-lisp (use-package org-bullets :config (add-hook 'org-mode-hook (lambda () (org-bullets-mode)))) #+END_SRC ** Org Roam #+BEGIN_SRC emacs-lisp (use-package org-roam :custom (org-roam-directory "~/projects/notes") (org-roam-completion-everywhere t) :config (org-roam-setup) (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags}" 'face 'org-tag))) (org-roam-db-autosync-mode) ;; Add todo lists to org-agenda (custom-set-variables '(org-agenda-files (directory-files-recursively org-roam-directory "todo\\.org$"))) ) #+END_SRC *** UI #+BEGIN_SRC emacs-lisp (use-package org-roam-ui :ensure (:host github :repo "org-roam/org-roam-ui" :branch "main" :files ("*.el" "out")) :after org-roam ;; normally we'd recommend hooking orui after org-roam, but since org-roam does not have ;; a hookable mode anymore, you're advised to pick something yourself ;; if you don't care about startup time, use ;; :hook (after-init . org-roam-ui-mode) :config (setq org-roam-ui-sync-theme t org-roam-ui-follow t org-roam-ui-update-on-save t org-roam-ui-open-on-start t) ;; Start UI ;; (org-roam-ui-mode) ) #+END_SRC *** Consult #+BEGIN_SRC emacs-lisp (use-package consult-org-roam :ensure t :after org-roam :init (require 'consult-org-roam) ;; Activate the minor mode (consult-org-roam-mode 1) ;; :custom ;; Use `ripgrep' for searching with `consult-org-roam-search' ;; (consult-org-roam-grep-func #'consult-ripgrep) ;; Configure a custom narrow key for `consult-buffer', default is 'n', this sets it to 'r' ;; (consult-org-roam-buffer-narrow-key ?r) ;; Display org-roam buffers right after non-org-roam buffers ;; in consult-buffer (and not down at the bottom) ;; (consult-org-roam-buffer-after-buffers t) :config ;; Eventually suppress previewing for certain functions (consult-customize consult-org-roam-forward-links :preview-key "M-.") :bind ;; Define some convenient keybindings as an addition ("C-c n f" . consult-org-roam-file-find) ("C-c n b" . consult-org-roam-backlinks) ("C-c n B" . consult-org-roam-backlinks-recursive) ("C-c n l" . consult-org-roam-forward-links) ("C-c n s" . consult-org-roam-search) ("C-c n d" . org-roam-dailies-goto-today) ) #+END_SRC * Elisp ** Add demos to describe-function #+BEGIN_SRC emacs-lisp (use-package elisp-demos :config (advice-add 'describe-function-1 :after #'elisp-demos-advice-describe-function-1) ) #+END_SRC * Custom ** Org-roam Inspired by https://github.com/org-roam/org-roam/wiki/User-contributed-Tricks#filter-by-a-tag . #+BEGIN_SRC emacs-lisp (defun myrmi/org-roam-node-find-tag-filter () "Select a single tag from list and filter `org-roam-node' by it." (interactive) (let ((tag (car (completing-read-multiple "Tag: " (org-roam-tag-completions))))) (org-roam-node-find nil nil (lambda (node) (member tag (org-roam-node-tags node)))))) #+END_SRC ** Sudo current buffer #+BEGIN_SRC emacs-lisp (defun myrmi/sudo-current-buffer () "Use TRAMP to `sudo' the current buffer." (interactive) (when buffer-file-name (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name) ) ) ) #+END_SRC ** Save symbol at point #+BEGIN_SRC emacs-lisp (defun myrmi/save-symbol-at-point () "Make symbol at point the latest kill in the kill ring." (interactive) (let ((symbol (thing-at-point 'symbol))) (when symbol (kill-new symbol)))) (global-set-key (kbd "C-M-w") 'myrmi/save-symbol-at-point) #+END_SRC ** Ceedling #+BEGIN_SRC emacs-lisp (defvar ceedling-project-file-name "project.yml") (defvar ceedling-cmd "ceedling") (defvar ceedling-project-root ".") (defun myrmi/run-ceedling-tests (&optional file-name) (interactive) (let* ( (file-path (or file-name buffer-file-name)) (root-path (or (locate-dominating-file file-path ceedling-project-file-name) ceedling-project-root)) ) (compile (concat "cd " root-path " && " ceedling-cmd) ) ) ) #+END_SRC ** Set path to shell path #+BEGIN_SRC emacs-lisp (defun set-exec-path-from-shell-PATH () (let ((path-from-shell (replace-regexp-in-string "[[:space:]\n]*$" "" (shell-command-to-string "$SHELL -l -c 'echo $PATH'")))) (setenv "PATH" path-from-shell) (setq exec-path (split-string path-from-shell path-separator)))) (set-exec-path-from-shell-PATH) #+END_SRC ** Reload dir-locals.el #+BEGIN_SRC emacs-lisp (defun myrmi/reload-dir-locals-for-current-buffer () "Reload dir locals for the current buffer" (interactive) (let ((enable-local-variables :all)) (hack-dir-local-variables-non-file-buffer))) (defun myrmi/reload-dir-locals-for-all-buffers-in-this-directory () "For every buffer with the same `default-directory` as the current buffer, reload dir-locals." (interactive) (let ((dir default-directory)) (dolist (buffer (buffer-list)) (with-current-buffer buffer (when (equal default-directory dir) (myrmi/reload-dir-locals-for-current-buffer)))))) #+END_SRC ** Visit/reload config These snippets assume my-config-file variable is set outside this configuration. This should normally be done by the init.el to load this configuration. #+BEGIN_SRC emacs-lisp (defun myrmi/visit-config () "Reloads ~/.emacs.d/config.org at runtime" (interactive) (find-file my-config-file)) (defun myrmi/reload-config () "Reloads ~/.emacs.d/config.org at runtime" (interactive) (org-babel-load-file my-config-file)) #+END_SRC ** Tips and Tricks *** Cheat-sheet | Key | Explanation | |-----------------------+-----------------------------------------------------------| | C-h k | Lookup key sequencesmartparens wrapping | | C-q | Insert quoted/explicitly. F.e. to insert a tab, ... | | M-x untabify/tabify | Convert to spaces/tabs | | M-x describe-bindings | List all mapped keys/commands | | M-q | Fill paragraph |