dotfiles/guix/init.org

39 KiB

#+title Ian's Emacs Config

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)
    (unless package-archive-contents
  (package-refresh-contents))

    ;; 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)

    ;; Persist history over Emacs restarts. Vertico sorts by history position.
    (use-package savehist
  :init
  (savehist-mode))

Secrets

(use-package pinentry)
(use-package pass)
(use-package password-store)
(pinentry-start)
(setq gptel-api-key (password-store-get "openai-alt"))  ;; 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 deft-directory "~/notes/deft"
	org-roam-directory "~/notes/roam"
	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 custom/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 custom/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

  (use-package treemacs)

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"))

  (use-package org-make-toc
    :hook (org-mode . org-make-toc-mode))
  (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))

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 14")
  (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)

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

  (use-package perspective)
  (unless (equal persp-mode t)
    (persp-mode))
  (use-package ace-window)
  (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l))
  (defvar 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)
      ;;(?u aw-switch-buffer-other-window "Switch Buffer Other Window")
      (?u aw-switch-buffer-other-window 'winner-undo)
      (?U aw-switch-buffer-other-window 'winner-redo)
      (?c aw-split-window-fair "Split Fair Window")
      (?v aw-split-window-vert "Split Vert Window")
      (?b aw-split-window-horz "Split Horz Window")
      (?o delete-other-windows "Delete Other Windows")
      (?? aw-show-dispatch-help))
    "List of actions for `aw-dispatch-default'.")
  ;; TODO: maybe put workspace controls in aw-dispatch?

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>" '(treemacs-find-file  :which-key "Find current file in sidebar")
      "," '(+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" '(custom/conditional-imenu      :which-key "Imenu")  ;; consult-outline?
      "w" '(ace-window                    :which-key "Window")  

      ;; 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" '(counsel-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" '(custom/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" '(counsel-recentf                               :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"        '(counsel-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"        '(counsel-describe-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"        '(counsel-faces                    :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)
      "mrR"	'(empv-play-random-channel)
      "mrl"	'(empv-log-current-radio-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-graph                    :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-file                 :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" '(counsel-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" '(counsel-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

  :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)
  (use-package yasnippet-snippets)
  (yas-global-mode)

<el

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
    :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

  (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)

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+)
  (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
    :config
    (evil-collection-init))

  (setq evil-want-C-u-scroll t)
  (setq evil-want-C-i-jump nil)
  (setq evil-respect-visual-line-mode t)

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

Clean up Org Roam

  • Major mode notes master node

Create yasnippets repo as per The docs