44 KiB
- Preamble
- First things first
- One-Line Includes
- Notes
- AI
- Org Mode
- Basic Appearance and Behaviors
- Navigation
- Project management
- Autocomplete
- Languages
- Markups
- Shells
- Git
- Meow
- Evil
- Web browsing and youtube
- Todo
#+title Ian's Emacs Config
+++
title = "Emacs Configuration"
author = ["Ian Keane"]
date = 2023-02-09
tags = ["Config", "Text editing"]
description = 'My emacs configuration.'
+++
Preamble
My emacs configuration. It tangles to .emacs.d/init.el and exports to this markdown file on save. If you're viewing this in a repo, it's better to visit the website at <https://iankeane.srht.site/dotfiles>. If you are viewing this on the website and want the repo, you can find it at <https://sr.ht/~iankeane/dotfiles>. To see the hugo front-matter configuration, you'll have to view the raw code.
First things first
Literate Config Setup
To get started, run C-c C-v t
(defun dotfiles/org-babel-tangle-config ()
(when (string-equal (buffer-file-name)
(expand-file-name "~/dotfiles/guix/init.org"))
(let ((org-confirm-babel-evaluate nil))
(org-babel-tangle))))
(add-hook 'org-mode-hook (lambda () (add-hook 'after-save-hook #'dotfiles/org-babel-tangle-config)))
Package initialization
;; Initialize Package Sources
(require 'package)
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("org" . "https://orgmode.org/elpa/")
("elpa" . "https://elpa.gnu.org/packages/")))
(package-initialize)
;; Initialize use-package on non-linux platforms
(unless (package-installed-p 'use-package)
(package-install 'use-package))
(require 'use-package)
(setq use-package-always-ensure t)
(package-refresh-contents)
;; Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist
:init
(savehist-mode))
Straight
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name
"straight/repos/straight.el/bootstrap.el"
(or (bound-and-true-p straight-base-dir)
user-emacs-directory)))
(bootstrap-version 7))
(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)
Environment-specific setup
(setq IS-MACOS (eq system-type 'darwin))
(setq openai-key-string
(if IS-MACOS "self/openai-alt" "openai-alt"))
Secrets
(use-package pinentry
:ensure t)
(use-package pass
:ensure t)
(use-package password-store)
(pinentry-start)
(setq gptel-api-key (password-store-get openai-key-string)) ;; TODO if-macos
Global variables
Handle config file
(setq user-init-file (expand-file-name "~/.config/emacs/init.el"))
(defun reload-config ()
"Reload the Emacs configuration."
(interactive)
(load-file user-init-file))
Required directories for emacs setup
(defun ensure-directory (dir)
"Ceate a dir if it doesn't exist."
(unless (file-directory-p dir)
(make-directory dir t)))
(ensure-directory "~/.config/emacs/backups/")
(ensure-directory "~/.config/emacs/autosaves")
(ensure-directory "~/notes/roam")
(ensure-directory "~/notes/deft")
(ensure-directory "~/notes/code")
(ensure-directory "~/.config/emacs/video")
(ensure-directory "~/.config/emacs/audio")
(setq projectile-project-search-path '("~/code/")
empv-video-dir "~/.config/emacs/video"
empv-audio-dir "~/.config/emacs/audio"
backup-directory-alist `(("." . "~/.config/emacs/backups/"))
auto-save-file-name-transforms `((".*" "~/.config/emacs/autosaves/" t)))
Helper Functions
(defun ian/eval-region-or-buffer ()
"Eval the region if anything is selected, otherwise eval the whole buffer."
(interactive)
(if mark-active
(eval-region (region-beginning) (region-end))
(eval-buffer)))
(defun ian/conditional-imenu ()
"Call `consult-org-heading` in Org mode, otherwise `consult-imenu`."
(interactive)
(if (eq major-mode 'org-mode)
(consult-org-heading)
(consult-imenu)))
One-Line Includes
TODO: rename this section
(use-package treemacs)
;; Enable follow mode
;; Use treemacs-current-visibility function to expand backspace functionality
(setq treemacs--project-follow-delay 0)
(defun ian/treemacs-open-current-or-jump ()
"Find the current file and open treemacs if it's not open, otherwise jump
to the treemacs window"
(interactive)
(if
(not(eq (treemacs-current-visibility) 'visible))
(treemacs-find-file))
(treemacs-select-window))
Notes
(use-package deft)
(setq deft-recursive t
deft-extensions '("org" "txt"))
AI
(use-package gptel)
(setq gptl-default-mode 'org-mode)
Org Mode
(use-package org)
;; (add-hook 'org-mode-hook 'yas-minor-mode)
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(python . t)))
(setq org-confirm-babel-evaluate nil)
(require 'org-tempo)
(add-to-list 'org-structure-template-alist '("sh" . "src shell"))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(setq org-hide-emphasis-markers t)
(use-package org-appear
:hook (org-mode . org-appear-mode))
(use-package org-roam
:ensure t
:custom
(org-roam-directory "~/notes/roam")
:config
;; If you're using a vertical completion framework, you might want a more informative completion interface
;; (setq org-roam-node-display-template (concat "${title:*} " (propertize "${tags:10}" 'face 'org-tag)))
(org-roam-db-autosync-mode))
(use-package deft
:commands (deft)
:config
(setq deft-directory "~/notes/deft"
deft-extensions '("org" "txt")
deft-recursive t))
(use-package ox-hugo
:after ox)
(use-package org-roam-ui
:after org-roam
: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))
(use-package ox-gfm)
Basic Appearance and Behaviors
(setq inhibit-startup-message t)
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
(recentf-mode 1)
(savehist-mode 1) ; remember previous commands in minibuffer
(save-place-mode 1) ; put cursor in last place when opening a file
;; Avoid customization UI auto-variables in init.el
(setq custom-file (locate-user-emacs-file "custom-vars.el"))
(load custom-file 'noerror 'nomessage)
;; Don't show popup UI when prompting
(setq use-dialog-box nil)
;; Update files when changed on disk
(global-auto-revert-mode 1)
(use-package solaire-mode
:config (solaire-global-mode +1))
(use-package doom-themes
:ensure 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
(setq doom-themes-treemacs-theme "doom-atom") ; use "doom-colors" for less minimal icon theme
(doom-themes-treemacs-config)
;; Corrects (and improves) org-mode's native fontification.
(doom-themes-org-config))
(set-frame-font "DejaVu Sans Mono 17")
(use-package simple-modeline
:hook (after-init . simple-modeline-mode))
(use-package base16-theme)
(load-theme 'base16-oceanicnext t)
(global-display-line-numbers-mode t)
(dolist (mode
'(org-mode-hook
term-mode-hook
eshell-mode-hook))
(add-hook mode (lambda () (display-line-numbers-mode 0))))
(column-number-mode)
(use-package default-text-scale
:defer 1
:config
(default-text-scale-mode))
(use-package rainbow-delimiters
:hook (prog-mode . rainbow-delimiters-mode))
(use-package helpful) ; Slightly more helpful help
(setq tab-always-indent 'complete)
(setq tab-first-completion 'word)
;; Generate buffers in last window
(setq display-buffer-base-action
'(display-buffer-reuse-mode-window
display-buffer-reuse-window
display-buffer-same-window))
;; If a popup does happen, don't resize windows to be equal-sized
(setq even-window-sizes nil)
(setq whitespace-style '(trailing tabs newline tab-mark )) ; show tab characters
(setq indent-tabs-mode nil) ; tabs not spaces
(visual-line-mode)
Tab bar
(use-package tab-bar-echo-area
:ensure
:config
(tab-bar-echo-area-mode 1)
(setq tab-bar-show nil))
Navigation
Helper Functions
(defun split-and-follow-horizontally ()
(interactive)
(split-window-below)
(balance-windows)
(other-window 1))
(defun split-and-follow-vertically ()
(interactive)
(split-window-right)
(balance-windows)
(other-window 1))
Direct keymaps
;; (global-set-key (kbd "s-c") 'delete-window)
;; (global-set-key (kbd "s-h") 'windmove-left)
;; (global-set-key (kbd "s-j") 'windmove-down)
;; (global-set-key (kbd "s-k") 'windmove-up)
;; (global-set-key (kbd "s-l") 'windmove-right)
;; (define-key evil-normal-state-map (kbd "s-d") 'kill-this-buffer)
;; (define-key evil-normal-state-map (kbd "s-n") 'projectile-next-project-buffer)
;; (define-key evil-normal-state-map (kbd "s-p") 'projectile-previous-project-buffer)
;; (define-key evil-normal-state-map (kbd "s-J") 'split-and-follow-horizontally)
;; (define-key evil-normal-state-map (kbd "s-L") 'split-and-follow-vertically)
;; (define-key evil-normal-state-map (kbd "s-b") 'buffer-menu)
;; (define-key evil-normal-state-map (kbd "s-x") 'execute-extended-command)
;; (global-set-key (kbd "s-SPC") 'tab-next)
(global-set-key (kbd "<escape>") 'keyboard-escape-quit)
(use-package winner
:after evil
:config
(winner-mode))
Windows and Workspaces
Credit for manual dispatch function
(defun ace-window-manual-dispatch (arg)
"Calls `ace-window' with ARG asking for the dispatch, even if `aw-dispatch-always' is nil.
This could be useful to use the advanced commands"
(interactive "p")
(let ((aw-dispatch-always t))
(ace-window arg)
))
(use-package ace-window)
(setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
(setq aw-dispatch-alist
'(
(?x aw-delete-window "Delete Window")
(?m aw-swap-window "Swap Windows")
(?M aw-move-window "Move Window")
;; (?c aw-copy-window "Copy Window")
;; (?j aw-switch-buffer-in-window "Select Buffer")
;; (?n aw-flip-window)
;; ;;
(?b aw-switch-buffer-other-window "Switch Buffer Other Window")
(?u winner-undo)
(?U winner-redo)
(?c aw-split-window-fair "Split Fair Window")
(?v aw-split-window-vert "Split Vert Window")
(?H aw-split-window-horz "Split Horz Window")
(?o delete-other-windows "Delete Other Windows")
(?? aw-show-dispatch-help)))
(setq aw-scope 'frame)
;; TODO: Window width controls
Dired
(setq ring-bell-function 'ignore)
(setq dired-listing-switches "-al")
(setq dired-dwim-target t) ; opening 'other window' on a subdir enters 2 window dired mode for copy/paste
(use-package dired-single)
(defun my-dired-init ()
"Bunch of stuff to run for dired, either immediately or when it's
loaded."
;; <add other stuff here>
(define-key dired-mode-map [remap dired-find-file]
'dired-single-buffer)
(define-key dired-mode-map [remap dired-mouse-find-file-other-window]
'dired-single-buffer-mouse)
(define-key dired-mode-map [remap dired-up-directory]
'dired-single-up-directory))
;; if dired's already loaded, then the keymap will be bound
(if (boundp 'dired-mode-map)
;; we're good to go; just add our bindings
(my-dired-init)
;; it's not loaded yet, so add our bindings to the load-hook
(add-hook 'dired-load-hook 'my-dired-init))
(use-package dired-open
:config
(setq dired-open-extensions '(("png" . "sxiv")
("mkv" . "mpv")
("avi" . "mpv"))))
(use-package all-the-icons-dired
:hook (dired-mode . all-the-icons-dired-mode))
Treemacs
(use-package all-the-icons)
(use-package treemacs-all-the-icons)
Which-key
(use-package which-key
:init (which-key-mode)
:diminish which-key-mode
:config
(setq which-key-idle-delay 0.3))
General
- map spc W for split and winner-undo / redo operations on 2 windows
- bind persp-mode
- bind lispy for colemak-dh
- bind lispy doc features and ide-like features
- bind embark
- bind commentary
(use-package general
:ensure t
:config
(general-create-definer general-definition
:keymaps '(normal insert visual emacs)
:prefix "SPC"
:global-prefix "C-SPC")
(general-definition
;; Top level bindings
"SPC" '(projectile-find-file :which-key "Find project file")
"<backspace>" '(ian/treemacs-open-current-or-jump :which-key "Find current file in sidebar") ; TODO or treemacs-select-window
"," '(+ivy/switch-workspace-buffer :which-key "Buffers (workspace)")
"/" '(consult-ripgrep :which-key "Search project")
":" '(execute-extended-command :which-key "M-x")
";" '(eval-expression :which-key "Eval")
"<" '(consult-buffer :which-key "Buffers (all)")
"x" '(scratch-buffer :which-key "Scratch popup")
"-" '(dired :which-key "Find Directory")
;; "*" '(counsel-locate :which-key "Fuzzy find file") ;; find-file? consult-locate?
"d" '(docker :which-key "Docker")
"i" '(ian/conditional-imenu :which-key "Imenu") ;; consult-outline?
"w" '(ace-window :which-key "Window")
"W" '(ace-window-manual-dispatch :which-key "Window (dispatch)")
;; Agenda
"a" '(:ignore t :which-key "Agenda")
"aa" '(org-agenda :which-key "Open Agenda")
"a/" '(consult-org-agenda :which-key "Search agenda headlines")
"ac" '(:ignore t :which-key "Clock")
"acc" '(org-clock-goto :which-key "Active clock")
"ack" '(org-clock-cancel :which-key "Cancel current clock")
"act" '(+org/toggle-last-clock :which-key "Toggle last clock")
;; Buffers / bookmarks
"b" '(:ignore t :which-key "Buffers")
"bb" '(consult-bookmark :which-key "Goto Bookmark") ;; consult-bookmark
"bk" '(kill-current-buffer :which-key "Kill buffer")
"bm" '(bookmark-set :which-key "Set bookmark")
"bM" '(bookmark-delete :which-key "Delete bookmark")
;; "bo" '(NEEDS CUSTOM FUNCTION :which-key "Kill other buffers")
"br" '(revert-buffer :which-key "Revert buffer")
"bR" '(rename-buffer :which-key "Rename buffer")
"bz" '(bury-buffer :which-key "Bury buffer")
;; "bZ" '(NEEDS CUSTOM FUNCTION :which-key "Kill buried buffers")
"bj" '(+ivy/jump-list :which-key "Jump list")
"bu" '(vundo :which-key "Undo history")
;; Code
"c" '(:ignore t :which-key "Code")
"cc" '(compile :which-key "Compile")
"cC" '(recompile :which-key "Recompile")
"cd" '(+lookup/definition :which-key "Goto definition")
"cr" '(+lookup/references :which-key "Goto references")
"ce" '(ian/eval-region-or-buffer :which-key "Eval buffer/region")
;; "cf" '(NOT A COMMAND (re-do) :which-key "Format buffer/region")
"ci" '(+lookup/implementations :which-key "Find implementations")
"cj" '(lsp-ivy-workspace-symbol :which-key "Goto symbol (curr. workspace)")
"cJ" '(lsp-ivy-global-workspace-symbol :which-key "Goto symbol (any workspace)")
"ck" '(+lookup/documentation :which-key "Jump to documentation")
"cl" '(+default/lsp-command-map :which-key "LSP")
"co" '(lsp-organize-imports :which-key "LSP organize imports")
"cR" '(lsp-rename :which-key "LSP rename")
"cs" '(+eval/send-region-to-repl :which-key "Send to repl")
"ct" '(+lookup/type-definition :which-key "Find type definition")
"cw" '(delete-trailing-whitespace :which-key "Delete trailing whitespace")
;; "cn" '(doom/delete-trailing-newlines :which-key "Delete trailing newlines")
"cx" '(+default/diagnostics :which-key "List errors")
;; File
"f" '(:ignore t :which-key "File")
;; "fp" '(doom/open-private-config :which-key "Browse private config")
"fr" '(consult-recent-file :which-key "Recent files")
"fR" '(reload-config :which-key "Reload config")
;; "fm" '(doom/move-this-file :which-key "Move/rename file")
;; "fS" '(doom/sudo-find-file :which-key "Sudo find file")
;; "fs" '(doom/sudo-this-file :which-key "Sudo this file")
"fy" '(+default/yank-buffer-path :which-key "yank file path")
"fY" '(+default/yank-buffer-path-relative-to-project :which-key "Yank file path from project")
;; Git
"g" '(:ignore t :which-key "git")
"gb" '(magit-branch-checkout :which-key "magit switch branch")
"gB" '(magit-blame-addition :which-key "magit blame")
"gF" '(magit-fetch :which-key "magit fetch")
"gg" '(magit-status :which-key "magit status")
"gG" '(magit-status-here :which-key "magit status here")
"gL" '(magit-log-buffer-file :which-key "magit buffer log")
"gt" '(git-timemachine-toggle :which-key "git time machine")
"gd" '(:ignore t :which-key "dispatch")
"gdF" '(forge-dispatch :which-key "Forge dispatch")
"gdd" '(magit-dispatch :which-key "Magit dispatch")
"gdf" '(magit-file-dispatch :which-key "Magit file dispatch")
"gf" '(:ignore t :which-key "find")
"gfc" '(magit-show-commit :which-key "find commit")
"gff" '(magit-find-file :which-key "find file")
"gfg" '(magit-find-git-config-file :which-key "find gitconfig file")
"gfi" '(forge-visit-issue :which-key "find issue")
"gfp" '(forge-visit-pullreq :which-key "find pull request")
"gh" '(:ignore t :which-key "hunk")
"ghn" '(+vc-gutter/previous-hunk :which-key "jump to previous hunk")
"ghp" '(+vc-gutter/next-hunk :which-key "jump to next hunk")
"ghr" '(+vc-gutter/revert-hunk :which-key "revert hunk at point")
"ghs" '(+vc-gutter/stage-hunk :which-key "stage hunk at point")
"gl" '(:ignore t :which-key "list")
"gli" '(forge-list-issues :which-key "list issues")
"gln" '(forge-list-notifications :which-key "list notifications")
"glp" '(forge-list-pullreqs :which-key "list pull requests")
"glr" '(forge-list-issues :which-key "list repositories")
"gls" '(magit-list-submodules :which-key "list submodules")
"go" '(:ignore t :which-key "open")
"goI" '(forge-browse-issues :which-key "Browse issues")
"goP" '(forge-browse-pullreqs :which-key "Browse pull requests")
"goc" '(forge-browse-commit :which-key "Browse commit")
"goh" '(+vc/browse-at-remote-homepage :which-key "Browse homepage")
"goi" '(forge-browse-issue :which-key "Browse an issue")
"goo" '(+vc/browse-at-remote :which-key "Browse file or region")
"gop" '(forge-browse-pullreq :which-key "Browse a pull request")
"gor" '(forge-browse-remote :which-key "Browse remote")
;; Help
"h" '(:ignore t :which-key "help")
"h<return>" '(info-emacs-manual :which-key "Emacs manual")
"h'" '(describe-char :which-key "Describe character")
"ha" '(apropos :which-key "Apropos")
"hb" '(embark-bindings :which-key "Describe bindings")
"he" '(view-echo-area-messages :which-key "View echo area messages")
"hf" '(helpful-function :which-key "Describe function")
"hi" '(info :which-key "Info")
"hk" '(helpful-key :which-key "Describe key")
"hl" '(view-lossage :which-key "View actions log")
"hm" '(describe-mode :which-key "Describe mode")
"ho" '(helpful-symbol :which-key "Describe symbol")
"hv" '(helpful-variable :which-key "Describe variable")
"hx" '(helpful-command :which-key "Describe command")
"hA" '(apropos-documentation :which-key "Apropos(documentation)")
"hF" '(describe-face :which-key "Describe Face")
"hM" '(popwin:messages :which-key "View system messages")
"hw" '(:ignore t :which-key "which-key")
"hwf" '(which-key-show-full-keymap :which-key "Full keymap")
"hwi" '(which-key-show-minor-mode-keymap :which-key "Minor mode keymap")
"hwk" '(which-key-show-keymap :which-key "Show keymap")
"hwm" '(which-key-show-major-mode :which-key "Show major mode")
"hwt" '(which-key-show-top-level :which-key "Show top-level")
"m" '(:ignore t :which-key "media")
"my" '(empv-youtube :which-key "youtube")
"mt" '(empv-toggle :which-key "toggle")
"mT" '(empv-toggle-video :which-key "toggle-video")
"mq" '(empv-exit :which-key "quit")
"ms" '(empv-display-current :which-key "show currently playing")
"mr" '(:ignore t :which-key "radio")
"mrr" '(empv-play-radio :which-key "play")
"mrR" '(empv-play-random-channel :which-key "play random")
"mrl" '(empv-log-current-radio-song-name :which-key "log song name")
"mp" '(:ignore t :which-key "playlist")
"mpP" '(empv-playlist :which-key "playlist")
"mps" '(empv-playlist-select :which-key "select")
"mpn" '(empv-playlist-next :which-key "next")
"mpp" '(empv-playlist-prev :which-key "prev")
"mpc" '(empv-playlist-clear :which-key "clear")
"mpS" '(empv-playlist-shuffle :which-key "shuffle")
"mf" '(:ignore t :which-key "file")
"mff" '(empv-play-file :which-key "play file")
"mfd" '(empv-play-directory :which-key "play directory")
"mv" '(:ignore t :which-key "volume")
"mvd" '(empv-volume-down :which-key "down")
"mvu" '(empv-volume-up :which-key "up")
"mc" '(:ignore t :which-key "chapter")
"mcp" '(empv-chapter-prev :which-key "prev")
"mcn" '(empv-chapter-next :which-key "next")
"mcs" '(empv-chapter-select :which-key "select")
;; Notes
"nd" '(deft :which-key "Deft")
"nt" '(org-todo-list :which-key "Todo list")
"nf" '(org-roam-node-find :which-key "Find node")
"ng" '(org-roam-ui-open :which-key "Show graph")
"nr" '(org-roam-buffer-toggle :which-key "Toggle roam buffer")
"nb" '(org-roam-buffer-display-dedicated :which-key "Launch roam buffer")
"ns" '(org-roam-db-sync :which-key "Sync database")
"nc" '(org-roam-capture :which-key "Capture to node")
;; Org mode
"o" '(:ignore t :which-key "org")
"ol" '(org-store-link :which-key "Org store link")
"oc" '(org-capture :which-key "Org Capture")
"oC" '(org-capture-goto-target :which-key "Goto Capture")
"ot" '(org-babel-tangle :which-key "Org Tangle")
"oy" '(+org/export-to-clipboard :which-key "Org export to clipboard")
"oY" '(+org/export-to-clipboard-as-rich-text :which-key "Org export to clipboard (rich)")
"oe" '(:ignore t :which-key "export")
"oeh" '(org-html-export-to-html :which-key "Export Org to HTML")
"oa" '(:ignore t :which-key "attach")
"oaa" '(org-attach :which-key "Attach")
"oac" '(org-download-clipboard :which-key "Org download clipboard")
"oad" '(org-attach-delete-one :which-key "Delete one attachment")
"oaD" '(org-attach-delete-all :which-key "Delete all attachments")
"oas" '(org-attach-sync :which-key "Sync attachments")
"oay" '(org-download-yank :which-key "Org download yank")
;; Project
"p" '(:ignore t :which-key "project")
"ps" '(+neotree/open :which-key "Open project sidebar")
"pa" '(projectile-add-known-project :which-key "Add new project")
"pc" '(+ivy/project-compile :which-key "Compile in project")
"pd" '(projectile-remove-known-project :which-key "Remove known project")
"ps" '(projectile-switch-project :which-key "Switch projects")
"pC" '(projectile-configure-project :which-key "Configure project")
"pr" '(projectile-run-project :which-key "Run project")
"pt" '(magit-todos-list :which-key "List project todos")
"pT" '(projectile-test-project :which-key "Test project")
"pz" '(+taskrunner/project-tasks :which-key "List project tasks")
;; Shell
"s" '(:ignore t :which-key "shell")
"se" '(+eshell/toggle :which-key "Toggle eshell popup")
"sE" '(+eshell/here :which-key "Open eshell here")
"sr" '(+eval/open-repl-other-window :which-key "Repl")
"st" '(+vterm/toggle :which-key "Toggle vterm popup")
"sT" '(+vterm/here :which-key "Open vterm here")
;; Toggle
"t" '(:ignore t :which-key "toggle")
"tc" '(global-display-fill-column-indicator-mode :which-key "Fill Column Indicator")
"tf" '(flycheck-mode :which-key "Flycheck")
"tm" '(consult-minor-mode-menu :which-key "Minor modes")
"tp" '(org-tree-slide-mode :which-key "Org-tree-slide-mode")
"tw" '(+word-wrap-mode :which-key "Soft line wrapping")
"tz" '(+zen/toggle :which-key "Zen mode")
;; "tl" '(doom/toggle-line-numbers :which-key "Line numbers")
;; Visual / appearance
"v" '(:ignore t :which-key "visual/appearance")
"vt" '(load-theme :which-key "load theme")
;; Workspaces
"TAB TAB" '(+workspace/display :which-key "Display tab bar")
"TAB d" '(+workspace/delete :which-key "Delete this workspace")
"TAB l" '(+workspace/load :which-key "Load workspace from file")
"TAB n" '(+workspace/new :which-key "New workspace")
"TAB N" '(+workspace/new-named :which-key "New named workspace")
"TAB r" '(+workspace/rename :which-key "Rename workspace")
"TAB R" '(+workspace/restore-last-session :which-key "Restore last session")
"TAB s" '(+workspace/save :which-key "Save workspace")
"TAB x" '(+workspace/kill-session :which-key "Delete session")
))
Project management
(use-package projectile) ; todo config inside use-package
(use-package treemacs-projectile)
Autocomplete
Vertico
(use-package vertico
:init
(vertico-mode)
;; Different scroll margin
;; (setq vertico-scroll-margin 0)
;; Show more candidates
;; (setq vertico-count 20)
;; Grow and shrink the Vertico minibuffer
;; (setq vertico-resize t)
;; Optionally enable cycling for `vertico-next' and `vertico-previous'.
;; (setq vertico-cycle t)
)
Consult
(use-package consult
:bind (:map minibuffer-local-map ("C-r" . consult-history)))
Generic completion
Idk I think this came from the vertico readme
(use-package emacs
:init
;; Add prompt indicator to `completing-read-multiple'.
;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
(defun crm-indicator (args)
(cons (format "[CRM%s] %s"
(replace-regexp-in-string
"\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
crm-separator)
(car args))
(cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
;; Vertico commands are hidden in normal buffers.
;; (setq read-extended-command-predicate
;; #'command-completion-default-include-p)
;; Enable recursive minibuffers
(setq enable-recursive-minibuffers t))
(setq completion-styles '(basic substring partial-completion flex))
Orderless
(use-package orderless
:init
;; Configure a custom style dispatcher (see the Consult wiki)
;; (setq orderless-style-dispatchers '(+orderless-consult-dispatch orderless-affix-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)))))
Marginalia
(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))
Company-mode
(use-package company
:ensure t
:hook (prog-mode . company-mode)
:diminish
:bind (:map company-active-map
("<tab>" . company-select-next)
("TAB" . company-select-next)
("<backtab>" . company-select-previous)
("<S-tab>" . company-select-previous))
(:map lsp-mode-map ; more general mode than this?
("<tab>" . company-indent-or-complete-common))
:config
(global-company-mode 1)
:init
(setq company-idle-delay nil))
Embark
(use-package embark
:ensure t
:diminish eldoc-mode
:bind
(("C-." . embark-act) ;; pick some comfortable binding
("C-;" . embark-dwim) ;; good alternative: M-.
("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
:init
;; Show the Embark target at point via Eldoc. You may adjust the Eldoc
;; strategy, if you want to see the documentation from multiple providers.
(add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
: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
:ensure t ; only need to install it, embark loads it after consult if found
:hook
(embark-collect-mode . consult-preview-at-point-mode))
Snippets
(use-package yasnippet
:diminish yas-minor-mode)
(use-package yasnippet-snippets
:after lsp-mode)
(yas-global-mode)
Languages
LSP
(use-package lsp-mode
:commands (lsp lsp-deferred)
:init
(setq lsp-keymap-prefix "C-c l")
:config
(lsp-enable-which-key-integration t)
:hook (terraform-mode . lsp-deferred)
:hook (rust-mode . lsp-deferred))
(use-package lsp-ui)
(use-package lsp-treemacs)
(use-package flycheck
:ensure t
:diminish
:init (global-flycheck-mode))
Rust
(use-package rust-mode
:ensure t
:mode "\\.rs\\'"
:config
(setq rust-format-on-save t)) ; Automatically format rust files on save
(use-package cargo
:ensure t
:hook (rust-mode . cargo-minor-mode))
Terraform
(use-package terraform-mode
:ensure t)
Lisp
All lisp-family languages
(use-package lispy)
(use-package lispyville
:init
(general-add-hook '(emacs-lisp-mode-hook lisp-mode-hook) #'lispyville-mode)
:config
(lispyville-set-key-theme '(operators c-w additional)))
Markups
Markdown
(use-package markdown-mode
:mode ("\\.md\\'" . markdown-mode))
;;(use-package evil-markdown
;; :mode ("\\.md\\'" . evil-markdown-mode))
(use-package json-mode)
(use-package yaml-mode)
Beancount
(defun beancount-tab-function ()
"Improved beancount tab ripped off from doom emacs"
(interactive)
(if (and outline-minor-mode (outline-on-heading-p))
(beancount-outline-cycle)
(indent-according-to-mode)))
(use-package beancount
:straight (beancount :type git :host github :repo "beancount/beancount-mode")
:mode ("\\.beancount\\'" . beancount-mode)
:hook (beancount-mode . outline-minor-mode)
:config
(evil-define-key 'normal 'beancount-mode-map (kbd "TAB") 'beancount-tab-function)
) ;; Bind the TAB key
(add-hook 'beancount-mode-hook #'flymake-bean-check-enable)
Shells
Enable fish completions
Uses the external fish program to provide fish-style completions to eshell etc
(use-package fish-completion)
(when (and (executable-find "fish")
(require 'fish-completion nil t))
(global-fish-completion-mode))
Git
(use-package git-gutter+
:diminish)
(global-git-gutter+-mode t)
(use-package magit)
(use-package magit-todos)
(setq magit-display-buffer-function 'magit-display-buffer-same-window-except-diff-v1)
Meow
; (use-package 'meow)
; (defun meow-setup ()
; (setq meow-cheatsheet-layout meow-cheatsheet-layout-colemak)
; (meow-motion-overwrite-define-key
; ;; Use e to move up, n to move down.
; ;; Since special modes usually use n to move down, we only overwrite e here.
; '("e" . meow-prev)
; '("<escape>" . ignore))
; (meow-leader-define-key
; '("?" . meow-cheatsheet)
; ;; To execute the originally e in MOTION state, use SPC e.
; '("e" . "H-e")
; '("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-normal-define-key
; '("0" . meow-expand-0)
; '("1" . meow-expand-1)
; '("2" . meow-expand-2)
; '("3" . meow-expand-3)
; '("4" . meow-expand-4)
; '("5" . meow-expand-5)
; '("6" . meow-expand-6)
; '("7" . meow-expand-7)
; '("8" . meow-expand-8)
; '("9" . meow-expand-9)
; '("-" . negative-argument)
; '(";" . meow-reverse)
; '("," . meow-inner-of-thing)
; '("." . meow-bounds-of-thing)
; '("[" . meow-beginning-of-thing)
; '("]" . meow-end-of-thing)
; '("/" . meow-visit)
; '("a" . meow-append)
; '("A" . meow-open-below)
; '("b" . meow-back-word)
; '("B" . meow-back-symbol)
; '("c" . meow-change)
; '("d" . meow-delete)
; '("e" . meow-prev)
; '("E" . meow-prev-expand)
; '("f" . meow-find)
; '("g" . meow-cancel-selection)
; '("G" . meow-grab)
; '("m" . meow-left)
; '("M" . meow-left-expand)
; '("i" . meow-right)
; '("I" . meow-right-expand)
; '("j" . meow-join)
; '("k" . meow-kill)
; '("l" . meow-line)
; '("L" . meow-goto-line)
; '("h" . meow-mark-word)
; '("H" . meow-mark-symbol)
; '("n" . meow-next)
; '("N" . meow-next-expand)
; '("o" . meow-block)
; '("O" . meow-to-block)
; '("p" . meow-yank)
; '("q" . meow-quit)
; '("r" . meow-replace)
; '("s" . meow-insert)
; '("S" . meow-open-above)
; '("t" . meow-till)
; '("u" . meow-undo)
; '("U" . meow-undo-in-selection)
; '("v" . meow-search)
; '("w" . meow-next-word)
; '("W" . meow-next-symbol)
; '("x" . meow-delete)
; '("X" . meow-backward-delete)
; '("y" . meow-save)
; '("z" . meow-pop-selection)
; '("'" . repeat)
; '("<escape>" . ignore)))
;
; (require 'meow)
; (meow-setup)
; (meow-global-mode 1)
Evil
(use-package evil
:ensure t
:config
(evil-mode 1))
(use-package undo-tree
:ensure t
:after evil
:diminish
:config
(evil-set-undo-system 'undo-tree)
(global-undo-tree-mode 1))
(use-package evil-org
:ensure t
:after org
:hook (org-mode . (lambda () evil-org-mode))
;; :config
;; (require 'evil-org-agenda)
;; (evil-org-agenda-set-keys)
)
(use-package evil-collection
:after evil
:ensure t
:diminish evil-collection-unimpaired-mode
:init
(setq evil-want-C-u-scroll t)
:config
(evil-collection-init)
(setq evil-want-C-i-jump t
evil-respect-visual-line-mode t))
(use-package evil-commentary
:config
(evil-commentary-mode))
Web browsing and youtube
;; Using straight:
;;(use-package empv
;; :straight (:host github :repo "isamert/empv.el"))
(use-package empv)
(setq empv-radio-channels
'(("SomaFM - Groove Salad" . "http://www.somafm.com/groovesalad.pls")
("SomaFM - Drone Zone" . "http://www.somafm.com/dronezone.pls")
("SomaFM - Sonic Universe" . "https://somafm.com/sonicuniverse.pls")
("SomaFM - Metal" . "https://somafm.com/metal.pls")
("SomaFM - Vaporwaves" . "https://somafm.com/vaporwaves.pls")
("ADHD 1" . "https://www.youtube.com/watch?v=CmMrm4BpQHU")
("WREK FM" . "http://streaming.wrek.org:8000/wrek_live-128kb.m3u")
))
;; Todo: lainchan? adhd music stream from youtube? wuog? wrekFM? does freeside have streaming radio?
(with-eval-after-load 'embark (empv-embark-initialize-extra-actions))
(add-to-list 'empv-mpv-args "--ytdl-format=best")
(add-to-list 'empv-mpv-args "--save-position-on-quit")
(add-hook 'empv-init-hook #'empv-override-quit-key)
(setq empv-invidious-instance "https://invidious.projectsegfau.lt/api/v1")
Todo
General
-
Refactor to use use-package more effectively
- Use :mode and :config like here
- Set things which should be set before package install in :init
Terminals
- More terminals
- emacs-fish-completions
- setup terminals to complete to vertico
- starship prompts
New functions
- Git-time-machine-or-vc-region-history
Note taking
- deft
- org : roam2, hugo, pretty, dragndrop, bullet
Lisp stuff
- paredit
- lispy
One-offs
- hl-todo
- persistent undo
- commentary
- highlight tabs and newlines
- Vertico backwards delete
- alphabetical keybindings
- brighter modeline
-
surpress global minor modes
- Undo-Tree, company, flycheck, which-key
- ignore case in imenu
- improve which-key visibility
LSP stuff
- look into treemacs integrations
- consider eglot
- dap-mode
Completion
- dabbrev-expand or company on c-n c-p
- c-N c-P for expand full line
- yasnippet
- company-mode to corfu (or vertico completions? or cofu-in-vertico?)
- get vertico as completion box
Keybindings
- put general bindings in separate keymaps in separate sections
- map hyper bindings for buffer nav and jumping
- evil-org
- map alignment functions in 'code'section
- define global meow-left and vim-left, swich contextually
- fix c-u in evil mode
- fix tab key
- window size functions, winner undo/redo
- map default-text-scale operations
-
empv
- map
-
configure
- empv-radio-log-file
- empv-radio-log-format
- spc m y(outube)
- spc m l(ocal)
- spc m r(adio)
- empv-video-dir empv-audio-dir?
- empv-play-file
selected radio (See empv-radio-log-file and empv-radio-log-format variables and their documentations).
New plugins
- tramp
- k8s
- docker
- terraform
- straight?
- embark?
- emms, emms-play-url binding (youtube view)
- consult-lsp (better for errors than treemacs integrations probably)
- srht.el
- affe
- gnus
Appearance switches
- fonts
- random theme
- org mode bullets / pretty / etc
Research
- What does C-d do when in a minibuffer for vertico?
- embark
- ace-window / embark integration
System crafters videos
- 5 Hacks to improve org roam
- Improving the IRC experience
- Streamlined completions with vertico
- Keeping your folders clean while using emacs
- Static site generator from org mode
- Automated website publishing w/ org and sourcehut
- Emacs presentations
- Converting a literate config to guix home
- Emacs mail playlist
- Embark
Clean up Org Roam
- Major mode notes master node