diff --git a/thoom-emacs/.gitignore b/thoom-emacs/.gitignore index 2141eca..5091463 100644 --- a/thoom-emacs/.gitignore +++ b/thoom-emacs/.gitignore @@ -3,4 +3,9 @@ recentf eln-cache straight history +\#*\# *~ +eshell +games +tramp +bookmarks diff --git a/thoom-emacs/TODO.org b/thoom-emacs/TODO.org new file mode 100644 index 0000000..9e8bc44 --- /dev/null +++ b/thoom-emacs/TODO.org @@ -0,0 +1,80 @@ +#+title: Emacs TODOs +#+STARTUP: content +* mine for ideas +https://github.com/daviwil/emacs-from-scratch/blob/9388cf6ecd9b44c430867a5c3dad5f050fdc0ee1/Emacs.org + +* keybindings +** emacs +better bindings for page up / page down / home / end +center cursor after page up / page down +** org-evil bindings +M-hjlk for moving headings +** vertico +C-hjkl for navigating files +** meow +*** equivalents of evil <, > for indentation +*** equivalent of gd/gu (use embark?) + gd = (+lookup/definition) + gu = (+lookup/references) +*** equivalent of r (replace character under point, don't enter insert mode) +*** equivalent of . for repeating edits +learn kmacros +* magit +* undo-tree +* parinfer +* line wrapping +https://elpa.gnu.org/packages/adaptive-wrap.html +* if nix in path, prefer nix versions of emacs packages +don't use :straight t in use-package declarations +instead, have section that conditionally runs straight-use-package directives if necessary +** Emacs packages installed via Nix don't work in Mac app + +* Load terminfo on MacOS from nix profile +source nix env vars from somewhere? +* direnv +* eglot / lsp-mode +* corfu +https://takeonrules.com/2022/01/17/switching-from-company-to-corfu-for-emacs-completion/ +* embark +** function for org tagging +* org +** C-RET should enter meow insert state +** better embark bindings for moving subtrees +** embark binding for tagging header +** keybind for narrow +** beautify +https://mstempl.netlify.app/post/beautify-org-mode/ +* languages +** python +** nix +** typescript +** web-mode +* meow +** questions +*** Why does xy copy the newline but x;y doesn't? +*** Beacon mode +How does beacon mode decide whether a movement creates all possible cursors or just one? +How to express "insert before the second word of the line"? +Why doesn't visit work consistently in beacon mode? +*** defining C- keys in normal mode seems to fuck everything up for some reason +** notes +*** r replaces selection with yank buffer +* Notes from Mastering Emacs +** C-x # in emacsclient says "done with current buffer" +** C-x 8 RET (insert-char) for to insert weird characters +** C-h m (describe-mode) +** I in embark goes to manual +** (global-set-key [remap ] ') +remaps all keybindings that refer to to +** repeat-mode +describe-repeat-maps to see which keys repeat +** tab-bar-mode +replacement for perspective.el +offers window configurations as tabs, similar to iTerm/Kitty +also look into tab history mode +** bookmarks +C-x r (m)ark, (l)ist, jump to (b)ookmark +** registers +C-x r (s)tore region, (i)nsert contents +C-x r (SPC) store point, (j)ump to register + diff --git a/thoom-emacs/ThoomEmacs.org b/thoom-emacs/ThoomEmacs.org new file mode 100644 index 0000000..f53e080 --- /dev/null +++ b/thoom-emacs/ThoomEmacs.org @@ -0,0 +1,550 @@ +#+title: Thoom Emacs +#+PROPERTY: header-args:emacs-lisp :tangle ./init.el :mkdirp yes +#+STARTUP: content +* Prelude +** Utility constants for checking operating system +#+begin_src emacs-lisp + ;; Check the system used + (defconst ON-LINUX (eq system-type 'gnu/linux)) + (defconst ON-MAC (eq system-type 'darwin)) + (defconst ON-BSD (or ON-MAC (eq system-type 'berkeley-unix))) + (defconst ON-WINDOWS (memq system-type '(cygwin windows-nt ms-dos))) + #+end_src +** Auto-tangle this file +#+begin_src emacs-lisp + (defun thoom/org-babel-tangle-config () + (when (string-equal (file-truename (buffer-file-name)) + (expand-file-name "~/.dotfiles/thoom-emacs/ThoomEmacs.org")) + ;; Dynamic scoping to the rescue + (let ((org-confirm-babel-evaluate nil)) + (org-babel-tangle)))) + + (add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'thoom/org-babel-tangle-config))) +#+end_src +* Package Management + +** straight.el + +#+BEGIN_SRC emacs-lisp + (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)) +#+END_SRC + +** use-package + +#+BEGIN_SRC emacs-lisp + (straight-use-package 'use-package) +#+END_SRC + +* Basic UI Tweaks +** Theme +#+begin_src emacs-lisp + (use-package doom-themes + :straight t + :config + ;; Global settings (defaults) + (setq doom-themes-enable-bold t ; if nil, bold is universally disabled + doom-themes-enable-italic t) ; if nil, italics is universally disabled + (load-theme 'doom-one t) + + ;; Enable flashing mode-line on errors + (doom-themes-visual-bell-config) + ;; Corrects (and improves) org-mode's native fontification. + (doom-themes-org-config)) +#+end_src + +** Hiding Stuff +Disable a bunch of stuff we don't want to see. + +#+BEGIN_SRC emacs-lisp + (setq inhibit-startup-message t + use-dialog-box nil) + + (tool-bar-mode -1) + (scroll-bar-mode -1) + + ;; On a Mac, the menu bar doesn't take up screen real-estate, so leave it on + (if (not ON-MAC) + (menu-bar-mode -1)) +#+END_SRC + +** General Settings +Set some common settings, like global-auto-revert-mode. + +#+BEGIN_SRC emacs-lisp + (setq-default scroll-error-top-bottom t) + + ;; Revert buffers when the underlying file has changed + (global-auto-revert-mode 1) + + ;; Remember recent files + (recentf-mode 1) + + ;; Save what you enter into minibuffer prompts + (setq history-length 25) + (savehist-mode 1) + + ;; Visually mark the line the cursor is on + (global-hl-line-mode 1) + + ;; TODO - Decide whether to enable this + ;; (defalias 'yes-or-no-p 'y-or-n-p) +#+END_SRC + +** hl-todo + +#+begin_src emacs-lisp + (use-package hl-todo + :straight t + :init + (global-hl-todo-mode)) +#+end_src + +** Repeat Mode + +#+begin_src emacs-lisp + (repeat-mode 1) + + (defmacro thoom/repeat-map (keymap-sym &rest bindings) + "A helper macro for defining repeat maps. keymap-sym is a symbol to name the keymap with. + bindings are a sequence of cons cells containing a string to be passed to kbd and a function + for that key to be mapped to." + (declare (indent 1)) + `(progn + (defvar ,keymap-sym + (let ((map (make-sparse-keymap))) + ,@(mapcar (lambda (binding) `(define-key map (kbd ,(car binding)) ',(cdr binding))) bindings) + map)) + (map-keymap + (lambda (_key cmd) + (when (symbolp cmd) + (put cmd 'repeat-map ',keymap-sym))) + ,keymap-sym))) +#+end_src + +** Tab Bar + +#+begin_src emacs-lisp + (tab-bar-mode) + + ;; TODO - keybindings +#+end_src + +** Custom File + +Set a location for the custom file so it doesn't pollute this file. + +#+BEGIN_SRC emacs-lisp + (setq custom-file (locate-user-emacs-file "custom-vars.el")) +#+END_SRC + +* Keybindings +** Which-key +#+begin_src emacs-lisp + (use-package which-key + :straight t + :init + (which-key-mode) + (which-key-setup-side-window-bottom)) +#+end_src +** Keybindings +#+BEGIN_SRC emacs-lisp + (use-package emacs + :bind + ;; Window management + (("C-c w v" . split-window-right) + ("C-c w s" . split-window-below) + ("C-S-h" . windmove-left) + ("C-S-j" . windmove-down) + ("C-S-k" . windmove-up) + ("C-S-l" . windmove-right) + + ;; Tab management + ("C-c w t c" . tab-bar-new-tab) + ("C-c w t d" . tab-bar-close-tab) + ("C-c w t n" . tab-bar-switch-to-next-tab) + ("C-c w t p" . tab-bar-switch-to-prev-tab) + ;; Common keybindings with tab switching in browsers, for use with my mouse bindings + ("C-" . tab-bar-switch-to-next-tab) + ("C-" . tab-bar-switch-to-prev-tab) + + ;; Buffer management + ("C-c b d" . kill-this-buffer) + ("C-c b b" . consult-buffer) + ("C-c b p" . previous-buffer) + ("C-c b n" . next-buffer) + + ("C-o" . pop-global-mark) + ("M-DEL" . backward-kill-word) + ("C-:" . execute-extended-command-for-buffer))) +#+END_SRC + +* Editing +** Fancy Indenting +When in indent-rigidly mode (=+= in normal state), use =H/L= to adjust indent by single character increments and =h/l= to adjust by tab stops. + +#+begin_src emacs-lisp + ;; TODO - define keys to move region up and down by lines + (define-key indent-rigidly-map (kbd "H") 'indent-rigidly-left) + (define-key indent-rigidly-map (kbd "L") 'indent-rigidly-right) + (define-key indent-rigidly-map (kbd "h") 'indent-rigidly-left-to-tab-stop) + (define-key indent-rigidly-map (kbd "l") 'indent-rigidly-right-to-tab-stop) +#+end_src +** Meow +#+begin_src emacs-lisp + (use-package meow + :straight t + :init + ;; TODO - make this unnecessary + (require 'meow) + (defun meow-wrap-negative (command) + (lambda () + (interactive) + (let ((current-prefix-arg -1)) + (call-interactively command)))) + + ;; TODO - debug this. should make org headings into meow things + (meow-thing-register 'heading 'heading 'heading) + (setq meow-use-clipboard t + meow-char-thing-table '((?\( . round) + (?\) . round) + (?\[ . square) + (?\] . square) + (?\{ . curly) + (?\} . curly) + (?\" . string) + (?\' . string) + (?h . heading) + (?e . symbol) + (?w . window) + (?b . buffer) + (?p . paragraph) + (?l . line) + (?d . defun) + (?. . sentence)) + meow-cheatsheet-layout meow-cheatsheet-layout-qwerty + meow-keypad-self-insert-undefined nil) + + (add-to-list 'meow-mode-state-list + '(eshell-mode . insert) t) + + (meow-motion-overwrite-define-key + '("j" . meow-next) + '("k" . meow-prev) + '("" . ignore)) + + (meow-leader-define-key + ;; SPC j/k will run the original command in MOTION state. + '("j" . "H-j") + '("k" . "H-k") + + ;; Use SPC (0-9) for digit arguments. + '("1" . meow-digit-argument) + '("2" . meow-digit-argument) + '("3" . meow-digit-argument) + '("4" . meow-digit-argument) + '("5" . meow-digit-argument) + '("6" . meow-digit-argument) + '("7" . meow-digit-argument) + '("8" . meow-digit-argument) + '("9" . meow-digit-argument) + '("0" . meow-digit-argument) + '("/" . meow-keypad-describe-key) + '("?" . meow-cheatsheet)) + + (meow-define-keys 'insert + '("C-g" . meow-insert-exit) + '("C-M-g" . meow-insert-exit)) + + (meow-normal-define-key + '("0" . meow-expand-0) + '("9" . meow-expand-9) + '("8" . meow-expand-8) + '("7" . meow-expand-7) + '("6" . meow-expand-6) + '("5" . meow-expand-5) + '("4" . meow-expand-4) + '("3" . meow-expand-3) + '("2" . meow-expand-2) + '("1" . meow-expand-1) + '("-" . negative-argument) + + '(";" . meow-reverse) + '("," . meow-inner-of-thing) + '("." . meow-bounds-of-thing) + '("[" . meow-beginning-of-thing) + '("]" . meow-end-of-thing) + + '("a" . meow-append) + '("A" . meow-open-below) + '("b" . meow-back-word) + '("B" . meow-back-symbol) + '("c" . meow-change) + ;; Potential addition + '("d" . meow-delete) + '("D" . meow-backward-delete) + '("e" . meow-next-word) + '("E" . meow-next-symbol) + '("f" . meow-find) + `("F" . ,(meow-wrap-negative 'meow-find)) + '("g" . meow-cancel-selection) + '("G" . meow-grab) + '("h" . meow-left) + '("H" . meow-left-expand) + '("i" . meow-insert) + '("I" . meow-open-above) + '("j" . meow-next) + '("J" . meow-next-expand) + '("k" . meow-prev) + '("K" . meow-prev-expand) + '("l" . meow-right) + '("L" . meow-right-expand) + '("m" . meow-join) + ;; Potential addition - M + '("n" . meow-search) + ;; Potential addition - N + '("o" . meow-block) + '("O" . meow-to-block) + '("p" . meow-yank) + '("P" . consult-yank-pop) + ;; Potential addition - q + ;; Potential addition - Q + '("r" . meow-replace) + '("R" . meow-swap-grab) + '("s" . meow-kill) + ;; Potential addition - S + '("t" . meow-till) + `("T" . ,(meow-wrap-negative 'meow-till)) + '("u" . meow-undo) + '("U" . meow-undo-in-selection) + '("v" . meow-visit) + `("V" . ,(meow-wrap-negative 'meow-visit)) + '("w" . meow-mark-word) + '("W" . meow-mark-symbol) + '("x" . meow-line) + `("X" . ,(meow-wrap-negative 'meow-line)) + '("y" . meow-save) + '("Y" . meow-sync-grab) + '("z" . meow-pop-selection) + ;; Potential addition - Z + '("'" . repeat) + '("/" . meow-comment) + '(":" . execute-extended-command) + '("=" . indent-region) + '("+" . indent-rigidly)) + + (meow-global-mode 1)) +#+end_src +* Org +#+begin_src emacs-lisp + (use-package org + :config + ;; Add structure templates + (add-to-list 'org-modules 'org-tempo t) + (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) + + ;; Repeat map for previous/next heading + (thoom/repeat-map thoom/org-previous-next-visible-heading-repeat-map + ("n" . org-next-visible-heading) + ("C-n" . org-next-visible-heading) + ("p" . org-previous-visible-heading) + ("C-p" . org-previous-visible-heading))) + + (use-package org-bullets + :straight t + :hook org-mode) +#+end_src + +* VMOCE + +** Vertico +#+begin_src emacs-lisp + (use-package vertico + :straight t + :init + (vertico-mode)) +#+end_src +** Marginalia +#+begin_src emacs-lisp + (use-package marginalia + :straight t + ;; Either bind `marginalia-cycle' globally or only in the minibuffer + :bind (:map minibuffer-local-map + ("M-A" . marginalia-cycle)) + + :init + (marginalia-mode)) +#+end_src +** Orderless +#+begin_src emacs-lisp + (use-package orderless + :straight t + :init + ;; Configure a custom style dispatcher (see the Consult wiki) + ;; (setq orderless-style-dispatchers '(+orderless-dispatch) + ;; orderless-component-separator #'orderless-escapable-split-on-space) + (setq completion-styles '(orderless basic) + completion-category-defaults nil + completion-category-overrides '((file (styles partial-completion))))) +#+end_src +** Consult +#+begin_src emacs-lisp + (use-package consult + :straight t + ;; Replace bindings. Lazily loaded due by `use-package'. + :bind (;; C-c bindings (mode-specific-map) + ("C-c h" . consult-history) + ("C-c m" . consult-mode-command) + ("C-c k" . consult-kmacro) + ;; C-x bindings (ctl-x-map) + ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command + ("C-x C-b" . consult-buffer) + ("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 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 + (" a" . consult-apropos) ;; orig. apropos-command + ;; M-g bindings (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-g i" . consult-imenu) + ("M-g I" . consult-imenu-multi) + ;; M-s bindings (search-map) + ("M-s d" . consult-find) + ("M-s D" . 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 m" . consult-multi-occur) + ("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 (kbd "M-.")) + ;; (setq consult-preview-key (list (kbd "") (kbd ""))) + ;; 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-recent-file + consult--source-project-recent-file + :preview-key (kbd "M-.")) + + ;; Optionally configure the narrowing key. + ;; Both < and C-+ work reasonably well. + (setq consult-narrow-key "<") ;; (kbd "C-+") + + ;; Optionally make narrowing help available in the minibuffer. + ;; You may want to use `embark-prefix-help-command' or which-key instead. + ;; (define-key consult-narrow-map (vconcat consult-narrow-key "?") #'consult-narrow-help) + + ;; By default `consult-project-function' uses `project-root' from project.el. + ;; Optionally configure a different project root function. + ;; There are multiple reasonable alternatives to chose from. + ;;;; 1. project.el (the default) + ;; (setq consult-project-function #'consult--default-project--function) + ;;;; 2. projectile.el (projectile-project-root) + ;; (autoload 'projectile-project-root "projectile") + ;; (setq consult-project-function (lambda (_) (projectile-project-root))) + ;;;; 3. vc.el (vc-root-dir) + ;; (setq consult-project-function (lambda (_) (vc-root-dir))) + ;;;; 4. locate-dominating-file + ;; (setq consult-project-function (lambda (_) (locate-dominating-file "." ".git"))) + ) +#+end_src +** Embark +#+begin_src emacs-lisp + (use-package embark + :straight t + + :bind + (("C-." . embark-act) ;; pick some comfortable binding + ("C-;" . embark-dwim) ;; good alternative: M-. + ("C-h B" . embark-bindings)) ;; alternative for `describe-bindings' + + :init + ;; Optionally replace the key help with a completing-read interface + (setq prefix-help-command #'embark-prefix-help-command) + + :config + ;; Hide the mode line of the Embark live/completions buffers + (add-to-list 'display-buffer-alist + '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" + nil + (window-parameters (mode-line-format . none))))) + + ;; Consult users will also want the embark-consult package. + (use-package embark-consult + :straight t + :after (embark consult) + :demand t ; only necessary if you have the hook below + ;; if you want to have consult previews as you move around an + ;; auto-updating embark collect buffer + :hook + (embark-collect-mode . consult-preview-at-point-mode)) +#+end_src diff --git a/thoom-emacs/init.el b/thoom-emacs/init.el index 2d4102e..54d9adb 100644 --- a/thoom-emacs/init.el +++ b/thoom-emacs/init.el @@ -1,34 +1,57 @@ -;;; init.el --- Support for the Foo programming language -*- lexical-binding: t; -*- +;; Check the system used +(defconst ON-LINUX (eq system-type 'gnu/linux)) +(defconst ON-MAC (eq system-type 'darwin)) +(defconst ON-BSD (or ON-MAC (eq system-type 'berkeley-unix))) +(defconst ON-WINDOWS (memq system-type '(cygwin windows-nt ms-dos))) -;;; Commentary: -;;; This is here to shut up the elisp linter. +(defun thoom/org-babel-tangle-config () + (when (string-equal (file-truename (buffer-file-name)) + (expand-file-name "~/.dotfiles/thoom-emacs/ThoomEmacs.org")) + ;; Dynamic scoping to the rescue + (let ((org-confirm-babel-evaluate nil)) + (org-babel-tangle)))) + +(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'thoom/org-babel-tangle-config))) -;;; Code: -;; Install 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) + (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)) (straight-use-package 'use-package) +(use-package doom-themes + :straight t + :config + ;; Global settings (defaults) + (setq doom-themes-enable-bold t ; if nil, bold is universally disabled + doom-themes-enable-italic t) ; if nil, italics is universally disabled + (load-theme 'doom-one t) + + ;; Enable flashing mode-line on errors + (doom-themes-visual-bell-config) + ;; Corrects (and improves) org-mode's native fontification. + (doom-themes-org-config)) + (setq inhibit-startup-message t use-dialog-box nil) (tool-bar-mode -1) (scroll-bar-mode -1) -;; TODO - only on non-Darwin -(menu-bar-mode -1) -(setq custom-file (locate-user-emacs-file "custom-vars.el")) +;; On a Mac, the menu bar doesn't take up screen real-estate, so leave it on +(if (not ON-MAC) + (menu-bar-mode -1)) + +(setq-default scroll-error-top-bottom t) ;; Revert buffers when the underlying file has changed (global-auto-revert-mode 1) @@ -40,20 +63,241 @@ (setq history-length 25) (savehist-mode 1) -(hl-line-mode 1) +;; Visually mark the line the cursor is on +(global-hl-line-mode 1) -(use-package doom-themes +;; TODO - Decide whether to enable this +;; (defalias 'yes-or-no-p 'y-or-n-p) + +(use-package hl-todo :straight t - :config - ;; Global settings (defaults) - (setq doom-themes-enable-bold t ; if nil, bold is universally disabled - doom-themes-enable-italic t) ; if nil, italics is universally disabled - (load-theme 'doom-one t) + :init + (global-hl-todo-mode)) - ;; Enable flashing mode-line on errors - (doom-themes-visual-bell-config) - ;; Corrects (and improves) org-mode's native fontification. - (doom-themes-org-config)) +(repeat-mode 1) + +(defmacro thoom/repeat-map (keymap-sym &rest bindings) + "A helper macro for defining repeat maps. keymap-sym is a symbol to name the keymap with. + bindings are a sequence of cons cells containing a string to be passed to kbd and a function + for that key to be mapped to." + (declare (indent 1)) + `(progn + (defvar ,keymap-sym + (let ((map (make-sparse-keymap))) + ,@(mapcar (lambda (binding) `(define-key map (kbd ,(car binding)) ',(cdr binding))) bindings) + map)) + (map-keymap + (lambda (_key cmd) + (when (symbolp cmd) + (put cmd 'repeat-map ',keymap-sym))) + ,keymap-sym))) + +(tab-bar-mode) + +;; TODO - keybindings + +(setq custom-file (locate-user-emacs-file "custom-vars.el")) + +(use-package which-key + :straight t + :init + (which-key-mode) + (which-key-setup-side-window-bottom)) + +(use-package emacs + :bind + ;; Window management + (("C-c w v" . split-window-right) + ("C-c w s" . split-window-below) + ("C-S-h" . windmove-left) + ("C-S-j" . windmove-down) + ("C-S-k" . windmove-up) + ("C-S-l" . windmove-right) + + ;; Tab management + ("C-c w t c" . tab-bar-new-tab) + ("C-c w t d" . tab-bar-close-tab) + ("C-c w t n" . tab-bar-switch-to-next-tab) + ("C-c w t p" . tab-bar-switch-to-prev-tab) + ;; Common keybindings with tab switching in browsers, for use with my mouse bindings + ("C-" . tab-bar-switch-to-next-tab) + ("C-" . tab-bar-switch-to-prev-tab) + + ;; Buffer management + ("C-c b d" . kill-this-buffer) + ("C-c b b" . consult-buffer) + ("C-c b p" . previous-buffer) + ("C-c b n" . next-buffer) + + ("C-o" . pop-global-mark) + ("M-DEL" . backward-kill-word) + ("C-:" . execute-extended-command-for-buffer))) + +;; TODO - define keys to move region up and down by lines +(define-key indent-rigidly-map (kbd "H") 'indent-rigidly-left) +(define-key indent-rigidly-map (kbd "L") 'indent-rigidly-right) +(define-key indent-rigidly-map (kbd "h") 'indent-rigidly-left-to-tab-stop) +(define-key indent-rigidly-map (kbd "l") 'indent-rigidly-right-to-tab-stop) + +(use-package meow + :straight t + :init + ;; TODO - make this unnecessary + (require 'meow) + (defun meow-wrap-negative (command) + (lambda () + (interactive) + (let ((current-prefix-arg -1)) + (call-interactively command)))) + + ;; TODO - debug this. should make org headings into meow things + (meow-thing-register 'heading 'heading 'heading) + (setq meow-use-clipboard t + meow-char-thing-table '((?\( . round) + (?\) . round) + (?\[ . square) + (?\] . square) + (?\{ . curly) + (?\} . curly) + (?\" . string) + (?\' . string) + (?h . heading) + (?e . symbol) + (?w . window) + (?b . buffer) + (?p . paragraph) + (?l . line) + (?d . defun) + (?. . sentence)) + meow-cheatsheet-layout meow-cheatsheet-layout-qwerty + meow-keypad-self-insert-undefined nil) + + (add-to-list 'meow-mode-state-list + '(eshell-mode . insert) t) + + (meow-motion-overwrite-define-key + '("j" . meow-next) + '("k" . meow-prev) + '("" . ignore)) + + (meow-leader-define-key + ;; SPC j/k will run the original command in MOTION state. + '("j" . "H-j") + '("k" . "H-k") + + ;; Use SPC (0-9) for digit arguments. + '("1" . meow-digit-argument) + '("2" . meow-digit-argument) + '("3" . meow-digit-argument) + '("4" . meow-digit-argument) + '("5" . meow-digit-argument) + '("6" . meow-digit-argument) + '("7" . meow-digit-argument) + '("8" . meow-digit-argument) + '("9" . meow-digit-argument) + '("0" . meow-digit-argument) + '("/" . meow-keypad-describe-key) + '("?" . meow-cheatsheet)) + + (meow-define-keys 'insert + '("C-g" . meow-insert-exit) + '("C-M-g" . meow-insert-exit)) + + (meow-normal-define-key + '("0" . meow-expand-0) + '("9" . meow-expand-9) + '("8" . meow-expand-8) + '("7" . meow-expand-7) + '("6" . meow-expand-6) + '("5" . meow-expand-5) + '("4" . meow-expand-4) + '("3" . meow-expand-3) + '("2" . meow-expand-2) + '("1" . meow-expand-1) + '("-" . negative-argument) + + '(";" . meow-reverse) + '("," . meow-inner-of-thing) + '("." . meow-bounds-of-thing) + '("[" . meow-beginning-of-thing) + '("]" . meow-end-of-thing) + + '("a" . meow-append) + '("A" . meow-open-below) + '("b" . meow-back-word) + '("B" . meow-back-symbol) + '("c" . meow-change) + ;; Potential addition + '("d" . meow-delete) + '("D" . meow-backward-delete) + '("e" . meow-next-word) + '("E" . meow-next-symbol) + '("f" . meow-find) + `("F" . ,(meow-wrap-negative 'meow-find)) + '("g" . meow-cancel-selection) + '("G" . meow-grab) + '("h" . meow-left) + '("H" . meow-left-expand) + '("i" . meow-insert) + '("I" . meow-open-above) + '("j" . meow-next) + '("J" . meow-next-expand) + '("k" . meow-prev) + '("K" . meow-prev-expand) + '("l" . meow-right) + '("L" . meow-right-expand) + '("m" . meow-join) + ;; Potential addition - M + '("n" . meow-search) + ;; Potential addition - N + '("o" . meow-block) + '("O" . meow-to-block) + '("p" . meow-yank) + '("P" . consult-yank-pop) + ;; Potential addition - q + ;; Potential addition - Q + '("r" . meow-replace) + '("R" . meow-swap-grab) + '("s" . meow-kill) + ;; Potential addition - S + '("t" . meow-till) + `("T" . ,(meow-wrap-negative 'meow-till)) + '("u" . meow-undo) + '("U" . meow-undo-in-selection) + '("v" . meow-visit) + `("V" . ,(meow-wrap-negative 'meow-visit)) + '("w" . meow-mark-word) + '("W" . meow-mark-symbol) + '("x" . meow-line) + `("X" . ,(meow-wrap-negative 'meow-line)) + '("y" . meow-save) + '("Y" . meow-sync-grab) + '("z" . meow-pop-selection) + ;; Potential addition - Z + '("'" . repeat) + '("/" . meow-comment) + '(":" . execute-extended-command) + '("=" . indent-region) + '("+" . indent-rigidly)) + + (meow-global-mode 1)) + +(use-package org + :config + ;; Add structure templates + (add-to-list 'org-modules 'org-tempo t) + (add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp")) + + ;; Repeat map for previous/next heading + (thoom/repeat-map thoom/org-previous-next-visible-heading-repeat-map + ("n" . org-next-visible-heading) + ("C-n" . org-next-visible-heading) + ("p" . org-previous-visible-heading) + ("C-p" . org-previous-visible-heading))) + +(use-package org-bullets + :straight t + :hook org-mode) (use-package vertico :straight t @@ -64,7 +308,7 @@ :straight t ;; Either bind `marginalia-cycle' globally or only in the minibuffer :bind (:map minibuffer-local-map - ("M-A" . marginalia-cycle)) + ("M-A" . marginalia-cycle)) :init (marginalia-mode)) @@ -76,62 +320,63 @@ ;; (setq orderless-style-dispatchers '(+orderless-dispatch) ;; orderless-component-separator #'orderless-escapable-split-on-space) (setq completion-styles '(orderless basic) - completion-category-defaults nil - completion-category-overrides '((file (styles partial-completion))))) + completion-category-defaults nil + completion-category-overrides '((file (styles partial-completion))))) (use-package consult :straight t ;; Replace bindings. Lazily loaded due by `use-package'. :bind (;; C-c bindings (mode-specific-map) - ("C-c h" . consult-history) - ("C-c m" . consult-mode-command) - ("C-c k" . consult-kmacro) - ;; C-x bindings (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 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 - (" a" . consult-apropos) ;; orig. apropos-command - ;; M-g bindings (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-g i" . consult-imenu) - ("M-g I" . consult-imenu-multi) - ;; M-s bindings (search-map) - ("M-s d" . consult-find) - ("M-s D" . 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 m" . consult-multi-occur) - ("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 + ("C-c h" . consult-history) + ("C-c m" . consult-mode-command) + ("C-c k" . consult-kmacro) + ;; C-x bindings (ctl-x-map) + ("C-x M-:" . consult-complex-command) ;; orig. repeat-complex-command + ("C-x C-b" . consult-buffer) + ("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 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 + (" a" . consult-apropos) ;; orig. apropos-command + ;; M-g bindings (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-g i" . consult-imenu) + ("M-g I" . consult-imenu-multi) + ;; M-s bindings (search-map) + ("M-s d" . consult-find) + ("M-s D" . 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 m" . consult-multi-occur) + ("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. @@ -144,7 +389,7 @@ ;; 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) + 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. @@ -152,7 +397,7 @@ ;; Use Consult to select xref locations with preview (setq xref-show-xrefs-function #'consult-xref - xref-show-definitions-function #'consult-xref) + xref-show-definitions-function #'consult-xref) ;; Configure other variables and modes in the :config section, ;; after lazily loading the package. @@ -211,9 +456,9 @@ :config ;; Hide the mode line of the Embark live/completions buffers (add-to-list 'display-buffer-alist - '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" - nil - (window-parameters (mode-line-format . none))))) + '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*" + nil + (window-parameters (mode-line-format . none))))) ;; Consult users will also want the embark-consult package. (use-package embark-consult @@ -224,170 +469,3 @@ ;; auto-updating embark collect buffer :hook (embark-collect-mode . consult-preview-at-point-mode)) - -(use-package which-key - :straight t - :init - (which-key-mode) - (which-key-setup-side-window-bottom)) - -(use-package meow - :straight t - :init - (defun meow-setup () - "Wow, the elisp linter is pedantic." - (setq meow-use-clipboard t - meow-char-thing-table '((?\( . round) - (?\) . round) - (?\[ . square) - (?\] . square) - (?\{ . curly) - (?\} . curly) - (?\" . string) - (?\' . string) - (?e . symbol) - (?w . window) - (?b . buffer) - (?p . paragraph) - (?l . line) - (?d . defun) - (?. . sentence)) - meow-cheatsheet-layout meow-cheatsheet-layout-qwerty - meow-keypad-self-insert-undefined nil) - - (add-to-list 'meow-mode-state-list - '(eshell-mode . insert) t) - - (meow-motion-overwrite-define-key - '("j" . meow-next) - '("k" . meow-prev) - '("" . ignore)) - - (meow-leader-define-key - ;; SPC j/k will run the original command in MOTION state. - '("j" . "H-j") - '("k" . "H-k") - - ;; Use SPC (0-9) for digit arguments. - '("1" . meow-digit-argument) - '("2" . meow-digit-argument) - '("3" . meow-digit-argument) - '("4" . meow-digit-argument) - '("5" . meow-digit-argument) - '("6" . meow-digit-argument) - '("7" . meow-digit-argument) - '("8" . meow-digit-argument) - '("9" . meow-digit-argument) - '("0" . meow-digit-argument) - '("/" . meow-keypad-describe-key) - '("?" . meow-cheatsheet)) - - (meow-define-keys 'insert - '("ESC" . meow-insert-exit)) - - (meow-normal-define-key - '("0" . meow-expand-0) - '("9" . meow-expand-9) - '("8" . meow-expand-8) - '("7" . meow-expand-7) - '("6" . meow-expand-6) - '("5" . meow-expand-5) - '("4" . meow-expand-4) - '("3" . meow-expand-3) - '("2" . meow-expand-2) - '("1" . meow-expand-1) - '("-" . negative-argument) - '(";" . meow-reverse) - '("," . meow-inner-of-thing) - '("." . meow-bounds-of-thing) - '("[" . meow-beginning-of-thing) - '("]" . meow-end-of-thing) - '("a" . meow-append) - '("A" . meow-open-below) - '("b" . meow-back-word) - '("B" . meow-back-symbol) - '("c" . meow-change) - '("d" . meow-delete) - '("D" . meow-backward-delete) - '("e" . meow-next-word) - '("E" . meow-next-symbol) - '("f" . meow-find) - '("g" . meow-cancel-selection) - '("G" . meow-grab) - '("h" . meow-left) - '("H" . meow-left-expand) - '("i" . meow-insert) - '("I" . meow-open-above) - '("j" . meow-next) - '("J" . meow-next-expand) - '("k" . meow-prev) - '("K" . meow-prev-expand) - '("l" . meow-right) - '("L" . meow-right-expand) - '("m" . meow-join) - '("n" . meow-search) - '("o" . meow-block) - '("O" . meow-to-block) - '("p" . meow-yank) - '("q" . meow-quit) - '("r" . meow-replace) - '("R" . meow-swap-grab) - '("s" . meow-kill) - '("t" . meow-till) - '("u" . meow-undo) - '("U" . meow-undo-in-selection) - '("v" . meow-visit) - '("w" . meow-mark-word) - '("W" . meow-mark-symbol) - '("x" . meow-line) - '("X" . meow-goto-line) - '("y" . meow-save) - '("Y" . meow-sync-grab) - '("z" . meow-pop-selection) - '("'" . repeat) - '("/" . meow-comment) - '("=" . indent-region))) - - (require 'meow) - (meow-setup) - (meow-global-mode 1)) - -;; Meow-tutor notes: -;; r replaces selection with yank buffer - -;; When extending a selection by word with e/b, for the purpose of deleting some words, -;; it would normally be convenient to delete the trailing space as well. What is the meow way to do that? we{#}Ls? - -;; Why does xy copy the newline but x;y doesn't? - -;; Beacon mode -;; How does beacon mode decide whether a movement creates all possible cursors or just one? -;; How to express "insert before the second word of the line"? -;; Why doesn't visit work consistently in beacon mode? - -;; TODO -;; equivalents of evil <, > for indentation -;; interactive/case insensitive visit? -;; equivalents of evil C-o, C-i -;; equivalent of gd/gu (use embark?) -;; gd = (+lookup/definition) -;; gu = (+lookup/references) -;; -;; equivalent of r -;; equivalent of . for repeating edits -;; -;; learn kmacros -;; learn emacs undo / undo tree -;; bind page up/down, make them act more like vim: center new cursor position, go all the way to the end of file if possible -;; vim surround -;; system clipboard integration -;; cmd-z undo on mac - -(use-package hl-todo - :straight t - :init - (global-hl-todo-mode)) - - -(provide 'init) -;;; init.el ends here