#+title: Emacs — Keybindings
#+setupfile: ../headers
#+property: header-args:emacs-lisp  :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/keybindings.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export

* Keybindings
Undefining some stuff to make keybind prefixes work correctly.

#+name: general-keybindings-gen
#+header: :tangle no :exports none :results value :cache yes
#+begin_src emacs-lisp :var table=keybindings-apps prefix="a"
(mapconcat
 (lambda (line)
   (let* ((key       (format "%s" (nth 0 line)))
          (function  (nth 1 line))
          (fn-nil-p  (member function '("" "nil")))
          (comment   (or (nth 2 line) ""))
          (comment-p (not (string= "" comment)))
          (comment   (cond ((nth 2 line) (concat " :wk \"" (nth 2 line) "\""))
                           (fn-nil-p     " :wk t")
                           (t            "")))
          (package   (or (nth 3 line) ""))
          (package-p (not (string= "" (nth 3 line))))
          (package   (if package-p (concat " :package " (nth 3 line)) "")))
     (format "\"%s\" %s"
             (concat prefix key)
             (if (or comment-p package-p)
                 (format "'(%s%s%s)"
                         (if (member function '("" "nil"))
                             ":ignore t"
                           function)
                         (if comment-p comment "")
                         (if package-p package ""))
               (concat "#'" function)))))
 table
 "\n")
#+end_src

#+begin_src emacs-lisp
(general-define-key
 :keymaps 'global-map
 "<mouse-2>" nil
 "<mouse-3>" nil)

(phundrak/evil
  :packages '(counsel)
  "U"   '(evil-redo :package evil)
  "C-a" #'beginning-of-line
  "C-e" #'end-of-line
  "C-y" #'yank
  "M-y" '(counsel-yank-pop :package counsel))
#+end_src

#+begin_src emacs-lisp :results none
(general-define-key
 "<f5>" #'compile
 "<f6>" #'recompile)

(phundrak/leader-key
  "SPC" '(counsel-M-x :wk "M-x")
  "'"   '(shell-pop :package shell-pop)
  "R"   #'recompile
  "u"   #'universal-argument

  <<general-keybindings-gen(table=keybindings-tabs, prefix="TAB ")>>
  <<general-keybindings-gen(table=keybindings-apps, prefix="a")>>
  <<general-keybindings-gen(table=keybindings-apps-shell, prefix="as")>>
  <<general-keybindings-gen(table=keybindings-treemacs, prefix="at")>>
  <<general-keybindings-gen(table=keybindings-buffers, prefix="b")>>
  <<general-keybindings-gen(table=keybindings-code, prefix="c")>>
  <<general-keybindings-gen(table=keybindings-errors, prefix="e")>>
  <<keybindings-errors-extra>>
  <<general-keybindings-gen(table=keybindings-files, prefix="f")>>
  <<keybindings-files-extras>>
  <<general-keybindings-gen(table=keybindings-git, prefix="g")>>
  <<general-keybindings-gen(table=keybindings-help, prefix="h")>>
  <<general-keybindings-gen(table=keybindings-insert, prefix="i")>>
  <<general-keybindings-gen(table=keybindings-jump, prefix="j")>>
  <<general-keybindings-gen(table=keybindings-language, prefix="l")>>
  <<general-keybindings-gen(table=keybindings-media, prefix="m")>>
  <<general-keybindings-gen(table=keybindings-org, prefix="o")>>
  <<general-keybindings-gen(table=keybindings-refactor, prefix="r")>>
  <<general-keybindings-gen(table=keybindings-toggle, prefix="t ")>>
  <<general-keybindings-gen(table=keybindings-text, prefix="T")>>
  <<general-keybindings-gen(table=keybindings-vc, prefix="v")>>
  <<general-keybindings-gen(table=keybindings-windows, prefix="w")>>
  <<general-keybindings-gen(table=keybindings-quit, prefix="q")>>)
#+end_src

** Apps
Here are my apps keybindings. Each one of them is prefixed by ~a~.
#+name: keybindings-apps
| Key | Function                   | Description | Package         |
|-----+----------------------------+-------------+-----------------|
|     |                            | apps        |                 |
| a   |                            | AI          |                 |
| ae  | eca                        |             | eca             |
| aC  | claude-code-ide            |             | claude-code-ide |
| ac  | claude-code-ide-menu       |             | claude-code-ide |
| c   | calc                       |             |                 |
| C   |                            | calendar    |                 |
| CC  | calendar                   |             |                 |
| Co  | org-agenda                 |             | org             |
| Cs  | org-caldav-sync            |             | org-caldav      |
| d   | docker                     |             | docker          |
| E   | elfeed                     |             | elfeed          |
| e   |                            | email       |                 |
| ec  | mu4e-compose-new           |             | mu4e            |
| em  | mu4e                       |             | mu4e            |
| k   | keycast-mode               |             | keycast         |
| K   | keycast-log-mode           |             | keycast         |
| m   |                            | mastodon    |                 |
| mm  | mastodon                   |             | mastodon        |
| mn  | mastodon-notifications-get |             | mastodon        |
| mt  | mastodon-toot              |             | mastodon        |
| T   | tetris                     |             |                 |
| S   | screenshot                 |             | screenshot      |
| w   | wttrin                     |             | wttrin          |

*** Shell apps
I also have two main shell-related functions, prefixed with ~as~.
#+name: keybindings-apps-shell
| Key | Function   | Description | Package |
|-----+------------+-------------+---------|
|     |            | shells      |         |
| e   | eshell-new |             |         |
| t   | eat        |             | eat     |

*** Treemacs
#+name: keybindings-treemacs
| Key | Function                               | Description | Package  |
|-----+----------------------------------------+-------------+----------|
|     |                                        | treemacs    |          |
| c   |                                        | create      |          |
| cd  | treemacs-create-dir                    |             | treemacs |
| cf  | treemacs-create-file                   |             | treemacs |
| ci  | treemacs-create-icon                   |             | treemacs |
| ct  | treemacs-create-theme                  |             | treemacs |
| cw  | treemacs-create-workspace              |             | treemacs |
| d   | treemacs-delete-file                   |             | treemacs |
| f   |                                        | files       |          |
| ff  | treemacs-find-file                     |             | treemacs |
| ft  | treemacs-find-tag                      |             | treemacs |
| l   |                                        | lsp         |          |
| ls  | treemacs-expand-lsp-symbol             |             | treemacs |
| ld  | treemacs-expand-lsp-treemacs-deps      |             | treemacs |
| lD  | treemacs-collapse-lsp-treemacs-deps    |             | treemacs |
| lS  | treemacs-collapse-lsp-symbol           |             | treemacs |
| p   |                                        | projects    |          |
| pa  | treemacs-add-project-to-workspace      |             | treemacs |
| pf  | treemacs-project-follow-mode           |             | treemacs |
| pn  | treemacs-project-of-node               |             | treemacs |
| pp  | treemacs-project-at-point              |             | treemacs |
| pr  | treemacs-remove-project-from-workspace |             | treemacs |
| pt  | treemacs-move-project-down             |             | treemacs |
| ps  | treemacs-move-project-up               |             | treemacs |
| r   |                                        | rename      |          |
| rf  | treemacs-rename-file                   |             | treemacs |
| rp  | treemacs-rename-project                |             | treemacs |
| rr  | treemacs-rename                        |             | treemacs |
| rw  | treemacs-rename-workspace              |             | treemacs |
| t   | treemacs                               |             | treemacs |
| T   |                                        | toggles     |          |
| Td  | treemacs-toggle-show-dotfiles          |             | treemacs |
| Tn  | treemacs-toggle-node                   |             | treemacs |
| v   |                                        | visit node  |          |
| va  | treemacs-visit-node-ace                |             | treemacs |
| vc  | treemacs-visit-node-close-treemacs     |             | treemacs |
| vn  | treemacs-visit-node-default            |             | treemacs |
| y   |                                        | yank        |          |
| ya  | treemacs-copy-absolute-path-at-point   |             | treemacs |
| yp  | treemacs-copy-project-path-at-point    |             | treemacs |
| yr  | treemacs-copy-relative-path-at-point   |             | treemacs |
| yf  | treemacs-copy-file                     |             | treemacs |

** Buffers
My buffer-related keybindings are all prefixed by ~b~.
#+name: keybindings-buffers
| Key | Function                           | Description | Package   |
|-----+------------------------------------+-------------+-----------|
|     |                                    | buffers     |           |
| b   | bufler-switch-buffer               |             | bufler    |
| B   | bury-buffer                        |             |           |
| c   | clone-indirect-buffer              |             |           |
| C   | clone-indirect-buffer-other-window |             |           |
| l   | bufler                             |             | bufler    |
| d   | kill-current-buffer                |             |           |
| D   | kill-buffer                        |             |           |
| h   | dashboard-refresh-buffer           |             | dashboard |
| m   | switch-to-messages-buffer          |             |           |
| n   | next-buffer                        |             |           |
| p   | previous-buffer                    |             |           |
| r   | counsel-buffer-or-recentf          |             | counsel   |
| R   | rename-uniquely                    |             |           |
| s   | switch-to-scratch-buffer           |             |           |

** Code
#+name: keybindings-code
| Key | Function                          | Description | Package             |
|-----+-----------------------------------+-------------+---------------------|
|     |                                   | code        |                     |
| l   | evilnc-comment-or-uncomment-lines |             | evil-nerd-commenter |
| n   | hl-todo-next                      |             | hl-todo             |
| p   | hl-todo-previous                  |             | hl-todo             |

** Errors
#+begin_src emacs-lisp
(defhydra hydra-flycheck
  (:pre (flycheck-list-errors)
   :post (quit-windows-on "*Flycheck errors*")
   :hint nil)
  ("f" flycheck-error-list-set-filter "Filter")
  ("t" flycheck-next-error "Next")
  ("s" flycheck-previous-error "Previous")
  ("gg" flycheck-first-error "First")
  ("G" (progn (goto-char (point-max)) (flycheck-previous-error)) "Last")
  ("q" nil))
#+end_src

#+name: keybindings-errors
| Key | Function            | Description    | Package |
|-----+---------------------+----------------+---------|
|     |                     | errors         |         |
| .   | hydra-flycheck/body | hydra-flycheck |         |
| l   | counsel-flycheck    |                | counsel |
| F   | flyspell-hydra/body | flyspell-hydra |         |

#+name: keybindings-errors-extra
#+begin_src emacs-lisp :tangle no
"ee" '(:keymap flycheck-command-map :package 'flycheck :wk "flycheck")
"ef" '(:keymap flyspell-mode-map :package 'flyspell :wk "flyspell")
#+end_src

** Files
My keybindings for file manipulation are prefixed by ~f~.
#+name: keybindings-files
| Key | Function          | Description | Package          |
|-----+-------------------+-------------+------------------|
|     |                   | files       |                  |
| f   | counsel-find-file |             | counsel          |
| F   | quick-find-files  |             | quick-find-files |
| h   | hexl-find-file    |             |                  |
| r   | counsel-recentf   |             | counsel          |
| s   | save-buffer       |             |                  |

I also have some keybindings dedicated to opening specific files.
#+name: keybindings-files-extras
#+begin_src emacs-lisp :tangle no
"fc"  '((lambda ()
          (interactive)
          (quick-find-files nil "~/org/config/docs/emacs" "org"))
        :wk "emacs config"
        :package quick-find-files)
"fC"  '((lambda ()
          (interactive)
          (quick-find-files nil "~/org/config/docs" "org"))
        :wk "general config"
        :package quick-find-files)
"fi"  '((lambda ()
          (interactive)
          (find-file (concat user-emacs-directory "init.el")))
        :which-key "init.el")
"fI"  '((lambda ()
          (interactive)
          (quick-find-files nil
                            (expand-file-name "lisp" user-emacs-directory)
                            "el"))
        :which-key "elisp config"
        :package quick-find-files)
"fR"  '((lambda ()
          (interactive)
          (counsel-find-file ""
                             (concat user-emacs-directory
                                    (file-name-as-directory "straight")
                                    (file-name-as-directory "repos"))))
        :which-key "straight package"
        :package counsel)
"fS"  '((lambda ()
          (interactive)
          (find-file "~/org/config/stumpwm.org"))
        :which-key "stumpwm.org")
#+end_src

** Git
#+name: keybindings-git
| Key | Function            | Description | Package |
|-----+---------------------+-------------+---------|
|     |                     | git         |         |
| b   | magit-blame         |             | magit   |
| c   | magit-clone         |             | magit   |
| d   | magit-dispatch      |             | magit   |
| i   | magit-init          |             | magit   |
| s   | magit-status        |             | magit   |
| l   | magit-log           |             | magit   |
| y   | my/yadm             |             | magit   |
| S   | magit-stage-file    |             | magit   |
| U   | magit-unstage-file  |             | magit   |
| f   |                     | file        |         |
| fd  | magit-diff          |             | magit   |
| fc  | magit-file-checkout |             | magit   |
| fl  | magit-file-dispatch |             | magit   |
| fF  | magit-find-file     |             | magit   |

** Help
My keybindings for help are prefixed by ~h~.
#+name: keybindings-help
| Key | Function                 | Description |
|-----+--------------------------+-------------|
|     |                          | help        |
| k   | which-key-show-top-level | which-key   |
| i   | info                     |             |
| I   | info-display-manual      |             |
| d   |                          | describe    |
| dc  | describe-char            |             |
| dC  | helpful-command          |             |
| df  | helpful-callable         |             |
| di  | describe-input-method    |             |
| dk  | helpful-key              |             |
| dm  | helpful-macro            |             |
| dM  | helpful-mode             |             |
| dp  | describe-package         |             |
| ds  | helpful-symbol           |             |
| dv  | helpful-variable         |             |

** Insert
#+name: keybindings-insert
| Key | Function             | Description | Package   |
|-----+----------------------+-------------+-----------|
|     |                      | insert      |           |
| u   | counsel-unicode-char |             | counsel   |
| y   | ivy-yasnippet        |             | yasnippet |

** Jump
My keybindings for jumping around are prefixed by ~j~.
#+name: keybindings-jump
| Key | Function                      | Description | Package |
|-----+-------------------------------+-------------+---------|
|     |                               | jump        |         |
| C   |                               | avy copy    |         |
| Cl  | avy-copy-line                 |             | avy     |
| Cr  | avy-copy-region               |             | avy     |
| D   | dired-jump-other-window       |             |         |
| U   | my/avy-open-url               | open-url    | avy     |
| b   | avy-pop-mark                  |             | avy     |
| c   | evil-avy-goto-char-timer      |             | avy     |
| d   | dirvish-dwim                  |             | dirvish |
| f   | counsel-file-jump             |             | counsel |
| k   |                               | avy kill    |         |
| kL  | avy-kill-ring-save-whole-line |             | avy     |
| kR  | avy-kill-ring-save-region     |             | avy     |
| kl  | avy-kill-whole-line           |             | avy     |
| kr  | avy-kill-region               |             | avy     |
| l   | avy-goto-line                 |             | avy     |
| m   |                               | move        |         |
| ml  | avy-move-line                 |             | avy     |
| mr  | avy-move-region               |             | avy     |
| mt  | avy-transpose-lines-in-region |             | avy     |
| n   | avy-next                      |             | avy     |
| p   | avy-prev                      |             | avy     |
| u   | my/avy-goto-url               | goto-url    | avy     |

** Language
#+name: keybindings-language
| Key | Function                         | Description | Package  |
|-----+----------------------------------+-------------+----------|
|     |                                  | language    |          |
| .   | langtool-correct-at-point        |             | langtool |
| B   | langtool-correct-buffer          |             | langtool |
| b   | langtool-check-buffer            |             | langtool |
| c   | langtool-check                   |             | langtool |
| d   | langtool-check-done              |             | langtool |
| l   | langtool-switch-default-language |             | langtool |
| p   | langtool-show-message-at-point   |             | langtool |
| r   | langtool-correct-region          |             | langtool |

** Media
#+name: keybindings-media
| Key | Function                    | Description    | Package |
|-----+-----------------------------+----------------+---------|
|     |                             | media          |         |
| .   | hydra-media/body            | hydra-media    | emms    |
| «   | emms-player-mpd-previous    |                | emms    |
| »   | emms-player-mpd-next        |                | emms    |
| c   | emms-player-mpd-clear       |                | emms    |
| e   |                             | emms           |         |
| eb  | emms-browser                |                | emms    |
| ep  | emms-playlist-mode-go       |                | emms    |
| es  | emms-player-mpd-show        |                | emms    |
| p   | my/mpc-toggle               | mpd-play-pause |         |
| s   | emms-stop                   |                | emms    |
| u   |                             | update         |         |
| um  | emms-player-mpd-update-all  |                | emms    |
| uc  | emms-cache-set-from-mpd-all |                | emm s   |

** Project
My keybindings for my projects are prefixed by ~p~.
#+name: keybindings-project
| Key | Function                                   | Description | Package    |
|-----+--------------------------------------------+-------------+------------|
|     |                                            | project     |            |
| !   | projectile-run-shell-command-in-root       |             | projectile |
| &   | projectile-run-async-shell-command-in-root |             | projectile |
| b   | counsel-projectile-switch-to-buffer        |             | counsel    |
| c   | counsel-projectile                         |             | counsel    |
| d   | counsel-projectile-find-dir                |             | counsel    |
| e   | projectile-edit-dir-locals                 |             | projectile |
| f   | counsel-projectile-find-file               |             | counsel    |
| g   | projectile-find-tag                        |             | projectile |
| k   | project-kill-buffers                       |             |            |
| p   | counsel-projectile-switch-project          |             | cousel     |
| v   | projectile-vc                              |             | projectile |

** Refactor
#+name: keybindings-refactor
| Key | Function                         | Description     | Package          |
|-----+----------------------------------+-----------------+------------------|
|     |                                  | refactor        |                  |
| i   | evil-iedit-state/iedit-mode      | iedit-mode      | evil-iedit-state |
| q   | evil-iedit-state/quit-iedit-mode | quit-iedit-mode | evil-iedit-state |

** Org
#+name: keybindings-org
| Key | Function                       | Description | Package  |
|-----+--------------------------------+-------------+----------|
|     |                                | org         |          |
| c   |                                | clock       |          |
| cc  | org-clock-cancel               |             | org      |
| cd  | org-clock-display              |             | org      |
| cg  | org-clock-goto                 |             | org      |
| ci  | org-clock-in                   |             | org      |
| co  | org-clock-out                  |             | org      |
| C   | org-capture                    |             | org      |
| r   |                                | roam        |          |
| rb  | org-mark-ring-goto             | back        | org-roam |
| rB  | org-roam-buffer-toggle         |             | org-roam |
| rn  |                                | nodes       |          |
| rnf | org-roam-node-find             |             | org-roam |
| rni | org-roam-node-insert           |             | org-roam |
| rno | org-roam-node-open             |             | org-roam |
| rnr | org-roam-node-random           |             | org-roam |
| rnv | org-roam-node-visit            |             | org-roam |
| rs  |                                | sync        |          |
| rsa | org-roam-db-autosync-mode      |             | org-roam |
| rsc | org-roam-db-clear-all          |             | org-roam |
| rsd | org-roam-db-diagnose-node      |             | org-roam |
| rss | org-roam-db-sync               |             | org-roam |
| ru  |                                | ui          |          |
| rua | org-roam-ui-add-to-local-graph |             | org-roam |
| ruo | org-roam-ui-open               |             | org-roam |

** Tabs
Emacs has native tabs available, which can be interesting when working
on multiple projects at once between which we may want to switch. Tabs
allow the user not to have multiple frames while keeping the
advantages of having multiple frames.

My keybindings are prefixed by ~SPC TAB~.
#+name: keybindings-tabs
| Key | Function     | Description |
|-----+--------------+-------------|
|     |              | tabs        |
| TAB | tab-switch   |             |
| »   | tab-next     |             |
| «   | tab-previous |             |
| c   | tab-new      |             |
| C   | tab-new-to   |             |
| d   | tab-close    |             |
| n   | tab-next     |             |
| p   | tab-previous |             |
| r   | tab-rename   |             |

** Text
The prefix here is ~T~.
#+name: keybindings-text
| Key | Function             | Description | Package              |
|-----+----------------------+-------------+----------------------|
|     |                      | text        |                      |
| e   | string-edit-at-point |             | string-edit-at-point |
| u   | downcase-region      |             |                      |
| U   | upcase-region        |             |                      |
| z   | hydra-zoom/body      |             |                      |

*** TODO Rewrite hydra-zoom                                      :noexport:

** Toggles
My toggle keybindings are prefixed by ~t~.
#+name: keybindings-toggle
| Key | Function                              | Description  |
|-----+---------------------------------------+--------------|
|     |                                       | toggles      |
| TAB | tab-bar-mode                          |              |
| t   | my/modify-frame-alpha-background/body |              |
| T   | counsel-load-theme                    |              |
| d   |                                       | debug        |
| de  | toggle-debug-on-error                 |              |
| dq  | toggle-debug-on-quit                  |              |
| i   |                                       | input method |
| it  | toggle-input-method                   |              |
| is  | set-input-method                      |              |

*** TODO Rewrite =my/modify-frame-alpha-background/body=           :noexport:
** VCS
Magit is awesome, but I rarely use it nowadays in favour of [[https://jj-vcs.github.io/][Jujutsu]].
And for that, I use =vc.el= in Emacs thanks to =vc-jj= (see [[file:./packages/applications.md#Jujutsu][my Jujutsu
config for Emacs]]). But this is only half the story, let me now set my
keybinds for =vc.el=. ethey are all prefixed by =v=.

#+name: keybindings-vc
| Key | Function              | Description | Package |
|-----+-----------------------+-------------+---------|
| a   | vc-annotate           |             | vc      |
| r   | vc-revset             |             | vc      |
|     |                       | VCS         |         |
| j   |                       | jujutsu     |         |
| ja  | vc-jj-abandon-change  | abandon     | vc-jj   |
| jb  |                       | bookmarks   |         |
| jbd | vc-jj-bookmark-delete | delete      | vc-jj   |
| jbr | vc-jj-bookmark-rename | rename      | vc-jj   |
| jbs | vc-jj-bookmark-set    | set         | vc-jj   |
| je  | vc-jj-edit-change     | edit        | vc-jj   |
| jn  | vc-jj-new-change      | new         | vc-jj   |

** Windows
A couple of keybindings are hidden from which-key, otherwise there’s not
much to say. The prefix here is ~w~.
#+name: keybindings-windows
| Key | Function                      | Description    | Package        |
|-----+-------------------------------+----------------+----------------|
|     |                               | windows        |                |
| c   | evil-window-left              |                | evil           |
| t   | evil-window-down              |                | evil           |
| s   | evil-window-up                |                | evil           |
| r   | evil-window-right             |                | evil           |
| .   | windows-adjust-size/body      |                |                |
| -   | split-window-below-and-focus  |                |                |
| /   | split-window-right-and-focus  |                |                |
| $   | winum-select-window-by-number |                | winum          |
| 0   | winum-select-window-0-or-10   | none           | winum          |
| 1   | winum-select-window-1         | none           | winum          |
| 2   | winum-select-window-2         | none           | winum          |
| 3   | winum-select-window-3         | none           | winum          |
| 4   | winum-select-window-4         | none           | winum          |
| 5   | winum-select-window-5         | none           | winum          |
| 6   | winum-select-window-6         | none           | winum          |
| 7   | winum-select-window-7         | none           | winum          |
| 8   | winum-select-window-8         | none           | winum          |
| 9   | winum-select-window-9         | none           | winum          |
| b   | kill-buffer-and-window        |                |                |
| d   | delete-window                 |                |                |
| o   | other-window                  |                |                |
| D   | delete-other-windows          |                |                |
| w   |                               | writeroom      |                |
| w.  | my/writeroom-transient        | adapt width    |                |
| w=  | my/writeroom-reset            | reset width    |                |
| wf  | my/writeroom-fit-buffer       | fit to content |                |
| ww  | writeroom-mode                |                | writeroom-mode |

** Quit
Why would I ever use any of these keybindings? They are prefixed with ~q~.
#+name: keybindings-quit
| Key | Function                   | Description |
|-----+----------------------------+-------------|
|     |                            | quit        |
| f   | delete-frame               |             |
| q   | save-buffers-kill-terminal |             |
| Q   | kill-emacs                 |             |
