[Emacs] More documentation

This commit is contained in:
Lucien Cartier-Tilet 2022-04-06 18:50:46 +02:00
parent 4d7f5fe947
commit 8ff0beec06
Signed by: phundrak
GPG Key ID: BD7789E705CB8DCA
1 changed files with 223 additions and 111 deletions

View File

@ -764,6 +764,11 @@ We finally come to the ~use-package~ installation. This is done like so:
:PROPERTIES:
:CUSTOM_ID: Keybinding-Management-Which-keymsblel6184j0
:END:
Which key is, I think, one of my favorite quality of life package.
When you begin a keybind, Emacs will show you all keybinds you can
follow the first one with in order to form a full keychord. Very
useful when you have a lot of keybinds and dont remember exactly what
is what.
#+begin_src emacs-lisp
(use-package which-key
:straight (:build t)
@ -844,64 +849,84 @@ can still feel some influence from my Spacemacs years here.
:PROPERTIES:
:CUSTOM_ID: Keybinding-Management-Eviljg30fl6184j0
:END:
Evil emulates most of vims keybinds, because lets be honest here,
they are much more comfortable than Emacs.
#+begin_src emacs-lisp
(use-package evil
:straight (:build t)
:after (general)
:init
(progn
(setq evil-want-integration t
evil-want-keybinding nil
evil-want-C-u-scroll t
evil-want-C-i-jump nil)
(require 'evil-vars)
(evil-set-undo-system 'undo-tree))
(setq evil-want-integration t
evil-want-keybinding nil
evil-want-C-u-scroll t
evil-want-C-i-jump nil)
(require 'evil-vars)
(evil-set-undo-system 'undo-tree)
:config
(general-define-key
:keymaps 'evil-motion-state-map
"SPC" nil
"," nil)
(general-define-key
:keymaps 'evil-insert-state-map
"C-t" nil)
(general-define-key
:keymaps 'evil-insert-state-map
"U" nil
"C-a" nil
"C-y" nil
"C-e" nil)
<<evil-undefine-keys>>
<<evil-bepo>>
(evil-mode 1)
(setq evil-want-fine-undo t) ; more granular undo with evil
(evil-set-initial-state 'messages-buffer-mode 'normal)
(evil-set-initial-state 'dashboard-mode 'normal)
;; Use visual line motions even outside of visual-line-mode buffers
(evil-global-set-key 'motion "t" 'evil-next-visual-line)
(evil-global-set-key 'motion "s" 'evil-previous-visual-line)
(dolist (key '("c" "C" "t" "T" "s" "S" "r" "R" "h" "H" "j" "J" "k" "K" "l" "L"))
(general-define-key :states 'normal key nil))
(general-define-key
:states 'motion
"h" 'evil-replace
"H" 'evil-replace-state
"j" 'evil-find-char-to
"J" 'evil-find-char-to-backward
"k" 'evil-substitute
"K" 'evil-smart-doc-lookup
"l" 'evil-change
"L" 'evil-change-line
"c" 'evil-backward-char
"C" 'evil-window-top
"t" 'evil-next-line
"T" 'evil-join
"s" 'evil-previous-line
"S" 'evil-lookup
"r" 'evil-forward-char
"R" 'evil-window-bottom))
(evil-set-initial-state 'dashboard-mode 'normal))
#+end_src
I want to undefine some of the default keybinds of Evil because it
does not match my workflow. Namely, I use the space key and the comma
as leaders for my keybinds, and Im way too used to Emacs ~C-t~, ~C-a~,
~C-e~, and ~C-y~.
#+name: evil-undefine-keys
#+begin_src emacs-lisp :tangle no
(evil-global-set-key 'motion "t" 'evil-next-visual-line)
(evil-global-set-key 'motion "s" 'evil-previous-visual-line)
(general-define-key
:keymaps 'evil-motion-state-map
"SPC" nil
"," nil)
(general-define-key
:keymaps 'evil-insert-state-map
"C-t" nil)
(general-define-key
:keymaps 'evil-insert-state-map
"U" nil
"C-a" nil
"C-y" nil
"C-e" nil)
#+end_src
Something else that really bugs me is I use the bépo layout, which is
not at all like the qwerty layout. For instance, <hjkl> becomes
<ctsr>. Thus, I need some bépo-spécific changes.
#+name: evil-bepo
#+begin_src emacs-lisp :tangle no
(dolist (key '("c" "C" "t" "T" "s" "S" "r" "R" "h" "H" "j" "J" "k" "K" "l" "L"))
(general-define-key :states 'normal key nil))
(general-define-key
:states 'motion
"h" 'evil-replace
"H" 'evil-replace-state
"j" 'evil-find-char-to
"J" 'evil-find-char-to-backward
"k" 'evil-substitute
"K" 'evil-smart-doc-lookup
"l" 'evil-change
"L" 'evil-change-line
"c" 'evil-backward-char
"C" 'evil-window-top
"t" 'evil-next-line
"T" 'evil-join
"s" 'evil-previous-line
"S" 'evil-lookup
"r" 'evil-forward-char
"R" 'evil-window-bottom)
#+end_src
This package enables and integrates Evil into a lot of different
modes, such as org-mode, dired, mu4e, etc. Again, I need some
additional code compared to most people due to the bépo layout.
#+begin_src emacs-lisp
(use-package evil-collection
:after evil
@ -1025,6 +1050,8 @@ windows.
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Autocompletion-Code-Autocompletion4no1fl6184j0
:END:
Company is, in my opinion, the best autocompleting engine for Emacs,
and it is one of the most popular if not /the/ most popular.
#+begin_src emacs-lisp
(use-package company
:straight (:build t)
@ -1040,30 +1067,17 @@ windows.
company-frontends
'(company-pseudo-tooltip-frontend ; always show candidates in overlay tooltip
company-echo-metadata-frontend) ; show selected candidate docs in echo area
;; Buffer-local backends will be computed when loading a major
;; mode, so only specify a global default here.
company-backends '(company-capf)
;; These auto-complete the current selection when
;; `company-auto-complete-chars' is typed. This is too
;; magical. We already have the much more explicit RET and
;; TAB.
company-auto-commit nil
company-auto-complete-chars nil
;; Only search the current buffer for `company-dabbrev' (a
;; backend that suggests text you open buffers). This prevents
;; Company from causing lag once you have a lot of buffers
;; open.
company-dabbrev-other-buffers nil
;; Make `company-dabbrev' fully case-sensitive, to improve UX
;; with domai-specific words with particular casing.
company-dabbrev-ignore-case nil
company-dabbrev-downcase nil))
#+end_src
This package is a backend for company. It emulates
~ac-source-dictionary~ by proposing text related to the current
major-mode.
#+begin_src emacs-lisp
(use-package company-dict
:after company
@ -1072,6 +1086,95 @@ windows.
(setq company-dict-dir (expand-file-name "dicts" user-emacs-directory)))
#+end_src
On the other hand, ~company-box~ is a Company front-end which offers
colors, icons, documentation and so on. Very nice.
Declaring all the icons for the variable
~company-box-icons-all-the-icons~ is quite verbose in Elisp, so I do it
with an org-table.
#+name: company-box-icons
| Type | Icon | Color |
|---------------+--------------------------+--------|
| Unknown | find_in_page | purple |
| Text | text_fields | green |
| Method | functions | red |
| Function | functions | red |
| Constructor | functions | red |
| Field | functions | red |
| Variable | adjust | blue |
| Class | class | red |
| Interface | settings_input_component | red |
| Module | view_module | red |
| Property | settings | red |
| Unit | straighten | red |
| Value | filter_1 | red |
| Enum | plus_one | red |
| Keyword | filter_center_focus | red |
| Snippet | short_text | red |
| Color | color_lens | red |
| File | insert_drive_file | red |
| Reference | collections_bookmark | red |
| Folder | folder | red |
| EnumMember | people | red |
| Constant | pause_circle_filled | red |
| Struct | streetview | red |
| Event | event | red |
| Operator | control_point | red |
| TypeParameter | class | red |
| Template | short_text | green |
| ElispFunction | functions | red |
| ElispVariable | check_circle | blue |
| ElispFeature | stars | orange |
| ElispFace | format_paint | pink |
#+name: gen-company-box-icons
#+headers: :tangle no :noweb yes :exports none :cache yes
#+header: :wrap "src emacs-lisp :exports none :tangle no"
#+begin_src emacs-lisp :var table=company-box-icons
(mapconcat (lambda (row)
(format "(%s . ,(all-the-icons-material \"%s\" :face 'all-the-icons-%s))"
(car row)
(cadr row)
(caddr row)))
table
"\n")
#+end_src
#+RESULTS[8ebf4bb3f7f354571a5d42cf58f8b9ba847ba028]: gen-company-box-icons
#+begin_src emacs-lisp :exports none :tangle no
(Unknown . ,(all-the-icons-material "find_in_page" :face 'all-the-icons-purple))
(Text . ,(all-the-icons-material "text_fields" :face 'all-the-icons-green))
(Method . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Function . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Constructor . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Field . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Variable . ,(all-the-icons-material "adjust" :face 'all-the-icons-blue))
(Class . ,(all-the-icons-material "class" :face 'all-the-icons-red))
(Interface . ,(all-the-icons-material "settings_input_component" :face 'all-the-icons-red))
(Module . ,(all-the-icons-material "view_module" :face 'all-the-icons-red))
(Property . ,(all-the-icons-material "settings" :face 'all-the-icons-red))
(Unit . ,(all-the-icons-material "straighten" :face 'all-the-icons-red))
(Value . ,(all-the-icons-material "filter_1" :face 'all-the-icons-red))
(Enum . ,(all-the-icons-material "plus_one" :face 'all-the-icons-red))
(Keyword . ,(all-the-icons-material "filter_center_focus" :face 'all-the-icons-red))
(Snippet . ,(all-the-icons-material "short_text" :face 'all-the-icons-red))
(Color . ,(all-the-icons-material "color_lens" :face 'all-the-icons-red))
(File . ,(all-the-icons-material "insert_drive_file" :face 'all-the-icons-red))
(Reference . ,(all-the-icons-material "collections_bookmark" :face 'all-the-icons-red))
(Folder . ,(all-the-icons-material "folder" :face 'all-the-icons-red))
(EnumMember . ,(all-the-icons-material "people" :face 'all-the-icons-red))
(Constant . ,(all-the-icons-material "pause_circle_filled" :face 'all-the-icons-red))
(Struct . ,(all-the-icons-material "streetview" :face 'all-the-icons-red))
(Event . ,(all-the-icons-material "event" :face 'all-the-icons-red))
(Operator . ,(all-the-icons-material "control_point" :face 'all-the-icons-red))
(TypeParameter . ,(all-the-icons-material "class" :face 'all-the-icons-red))
(Template . ,(all-the-icons-material "short_text" :face 'all-the-icons-green))
(ElispFunction . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(ElispVariable . ,(all-the-icons-material "check_circle" :face 'all-the-icons-blue))
(ElispFeature . ,(all-the-icons-material "stars" :face 'all-the-icons-orange))
(ElispFace . ,(all-the-icons-material "format_paint" :face 'all-the-icons-pink))
#+end_src
#+begin_src emacs-lisp
(use-package company-box
:straight (:build t)
@ -1083,37 +1186,8 @@ windows.
company-box-icons-alist 'company-box-icons-all-the-icons
company-box-icons-all-the-icons
(let ((all-the-icons-scale-factor 0.8))
`((Unknown . ,(all-the-icons-material "find_in_page" :face 'all-the-icons-purple))
(Text . ,(all-the-icons-material "text_fields" :face 'all-the-icons-green))
(Method . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Function . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Constructor . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Field . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(Variable . ,(all-the-icons-material "adjust" :face 'all-the-icons-blue))
(Class . ,(all-the-icons-material "class" :face 'all-the-icons-red))
(Interface . ,(all-the-icons-material "settings_input_component" :face 'all-the-icons-red))
(Module . ,(all-the-icons-material "view_module" :face 'all-the-icons-red))
(Property . ,(all-the-icons-material "settings" :face 'all-the-icons-red))
(Unit . ,(all-the-icons-material "straighten" :face 'all-the-icons-red))
(Value . ,(all-the-icons-material "filter_1" :face 'all-the-icons-red))
(Enum . ,(all-the-icons-material "plus_one" :face 'all-the-icons-red))
(Keyword . ,(all-the-icons-material "filter_center_focus" :face 'all-the-icons-red))
(Snippet . ,(all-the-icons-material "short_text" :face 'all-the-icons-red))
(Color . ,(all-the-icons-material "color_lens" :face 'all-the-icons-red))
(File . ,(all-the-icons-material "insert_drive_file" :face 'all-the-icons-red))
(Reference . ,(all-the-icons-material "collections_bookmark" :face 'all-the-icons-red))
(Folder . ,(all-the-icons-material "folder" :face 'all-the-icons-red))
(EnumMember . ,(all-the-icons-material "people" :face 'all-the-icons-red))
(Constant . ,(all-the-icons-material "pause_circle_filled" :face 'all-the-icons-red))
(Struct . ,(all-the-icons-material "streetview" :face 'all-the-icons-red))
(Event . ,(all-the-icons-material "event" :face 'all-the-icons-red))
(Operator . ,(all-the-icons-material "control_point" :face 'all-the-icons-red))
(TypeParameter . ,(all-the-icons-material "class" :face 'all-the-icons-red))
(Template . ,(all-the-icons-material "short_text" :face 'all-the-icons-green))
(ElispFunction . ,(all-the-icons-material "functions" :face 'all-the-icons-red))
(ElispVariable . ,(all-the-icons-material "check_circle" :face 'all-the-icons-blue))
(ElispFeature . ,(all-the-icons-material "stars" :face 'all-the-icons-orange))
(ElispFace . ,(all-the-icons-material "format_paint" :face 'all-the-icons-pink))))))
`(
<<gen-company-box-icons()>>))))
#+end_src
*** Ivy
@ -1208,6 +1282,9 @@ Finally, lets make ~ivy~ richer:
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Autocompletion-Counselorr1fl6184j0
:END:
I could almost merge this chapter with the previous one since counsel
is a package that provides loads of completion functions for ivy. The
ones I find most useful are ~counsel-M-x~ and ~counsel-find-file~.
#+begin_src emacs-lisp
(use-package counsel
:straight (:build t)
@ -1225,6 +1302,9 @@ Finally, lets make ~ivy~ richer:
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Autocompletion-Yasnippet68t1fl6184j0
:END:
Yasnippet allows you to insert some pre-made code by just typing a few
characters. It can even generate some string with Elisp expressions
and ask the user for some input in some precise places.
#+begin_src emacs-lisp
(use-package yasnippet
:defer t
@ -1235,6 +1315,8 @@ Finally, lets make ~ivy~ richer:
(text-mode . yas-minor-mode)))
#+end_src
Of course, yasnippet wouldnt be as awesome as it is without premade
snippets.
#+begin_src emacs-lisp
(use-package yasnippet-snippets
:defer t
@ -1242,6 +1324,8 @@ Finally, lets make ~ivy~ richer:
:straight (:build t))
#+end_src
Similarly, yatemplate offers premade files rather than just strings.
Thats still yasnippet by the way.
#+begin_src emacs-lisp
(use-package yatemplate
:defer t
@ -1249,15 +1333,18 @@ Finally, lets make ~ivy~ richer:
:straight (:build t))
#+end_src
And finally, with ivy you can chose your snippets from a menu if
youre not sure or if you dont remember what your snippet is.
#+begin_src emacs-lisp
(use-package ivy-yasnippet
:defer t
:after (ivy yasnippet)
:straight (:build t))
(phundrak/leader-key)
:infix "i"
:packages 'ivy-yasnippet
"y" #'ivy-yasnippet
:straight (:build t)
:general
(phundrak/leader-key
:infix "i"
:packages 'ivy-yasnippet
"y" #'ivy-yasnippet))
#+end_src
** Applications
@ -1296,7 +1383,7 @@ Due to this, I absolutely need a mode for editing Dockerfiles.
:mode "Dockerfile\\'")
#+end_src
The =docker= package also provides interactivity with Docker and
The ~docker~ package also provides interactivity with Docker and
docker-compose from Emacs.
#+begin_src emacs-lisp
(use-package docker
@ -2528,6 +2615,10 @@ with ~magit-gitflow~:
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Project-Management-Forgelcq5fl6184j0
:END:
Forge acts as an interface for Github, Gitlab, and Bitbucket inside
Magit. A lot of possibilities are present, you can read issues and
pull requests, create them, and fork projects among other things.
*NOTE*: Make sure to configure a GitHub token before using this
package!
- [[https://magit.vc/manual/forge/Token-Creation.html#Token-Creation][Token Creation]]
@ -2542,26 +2633,33 @@ with ~magit-gitflow~:
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Project-Management-Projectilesvr5fl6184j0
:END:
First, I need to install ~ripgrep~, a faster reimplementation of ~grep~,
which will be very useful when managing projects.
#+begin_src emacs-lisp
(use-package ripgrep
:if (executable-find "rg")
:straight (:build t)
:defer t)
#+end_src
Now, I can use projectile, which is sort of the /de facto/ standard
project manager in Emacs. I know theres ~project.el~, but,… Eh…
#+begin_src emacs-lisp
(use-package projectile
:straight (:build t)
:diminish projectile-mode
:config (projectile-mode)
:custom ((projectile-completion-system 'ivy))
:bind-keymap
("C-c p" . projectile-command-map)
:init
(setq projectile-switch-project-action #'projectile-dired)
:config
(add-to-list 'projectile-ignored-projects "~/"))
(projectile-mode)
(add-to-list 'projectile-ignored-projects "~/")
:general
(phundrak/leader-key
"p" '(:keymap projectile-command-map :which-key "projectile")))
#+end_src
And of course, there is a counsel package dedicated to projectile.
#+begin_src emacs-lisp
(use-package counsel-projectile
:straight (:build t)
@ -2602,6 +2700,9 @@ excluded files.
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Screenshot96d1fl6184j0
:END:
~screenshot.el~ is a nice utility package made by TEC. It allows the
user to take a screenshot of a specific area of a buffer and make it
look nice.
#+begin_src emacs-lisp
(use-package screenshot
:defer t
@ -2646,6 +2747,9 @@ buffer.
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Shells-VTermzfh1fl6184j0
:END:
VTerm gives Emacs access to regular shells with an almost regular
emulator. Be aware you will most likely need to hit ~C-c~ twice to send
an interrupt signal.
#+begin_src emacs-lisp
(use-package vterm
:defer t
@ -2744,6 +2848,10 @@ bit unfortunate Chromes name stuck in the packages name though.
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-Editorconfig-txn4dtx0rbj0
:END:
Editorconfig is a unified way of passing to your text editor settings
everyone working in a repo need to follow. ~.editorconfig~ files work
for VSCode users, vim users, Atom users, Sublime users, and of course
Emacs users.
#+begin_src emacs-lisp
(use-package editorconfig
:defer t
@ -2995,6 +3103,7 @@ And lets add some fancy icons in dired!
(advice-add #'all-the-icons-dired--refresh :around #'my/all-the-icons-dired--refresh))
#+end_src
Lastly, lets install some extensions to ~image-dired~.
#+begin_src emacs-lisp
(use-package image-dired+
:after (image-dired)
@ -3292,6 +3401,9 @@ a more human-readable name, see [[https://protesilaos.com/codelog/2021-10-15-ema
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Image-mode-dchdl251jdj0
:END:
I wont modify much for ~image-mode~ (the mode used to display images)
aside from Emacs ability to use external converters to display some
images it wouldnt be able to handle otherwise.
#+begin_src emacs-lisp
(setq image-use-external-converter t)
#+end_src
@ -3382,6 +3494,10 @@ about Emacs being single threaded, so if I get one blocking function
blocking Emacs, my whole desktop will hang, but for now I havent had
this issue.
All my EXWM config is enabled only if I launch Emacs with the argument
~--with-exwm~, otherwise none of the related packages get installed, let
alone activated and made available.
First, I need to install the /X protocol Emacs Lisp Bindings/. It
doesnt seem to be available in any repo, so Ill install it directly
from Git.
@ -4533,7 +4649,7 @@ selected text is quite easy.
| strike-through | ~+~ | 43 |
#+name: org-create-emphasis-functions
#+header: :tangle no :exports results
#+header: :tangle no :exports results :cache yes
#+header: :wrap "src emacs-lisp :tangle no :exports code"
#+begin_src emacs-lisp :var emphasis-list=org-emphasis-character
(mapconcat (lambda (emphasis)
@ -4550,7 +4666,7 @@ selected text is quite easy.
"\n")
#+end_src
#+RESULTS: org-create-emphasis-functions
#+RESULTS[dbd10cce4ae05a046838214784f0f4c16765e728]: org-create-emphasis-functions
#+begin_src emacs-lisp :tangle no :exports code
(defun org-emphasize-bold ()
"Emphasize as bold the current region."
@ -7745,14 +7861,10 @@ Undefining some stuff to make keybind prefixes work correctly.
<<general-keybindings-gen(table=keybinds-jump, prefix="j")>>
<<general-keybindings-gen(table=keybinds-project, prefix="p")>>
<<general-keybindings-gen(table=keybinds-toggle, prefix="t")>>
<<general-keybindings-gen(table=keybinds-text, prefix="T")>>
<<general-keybindings-gen(table=keybinds-project, prefix="p")>>
<<general-keybindings-gen(table=keybinds-windows, prefix="w")>>
<<general-keybindings-gen(table=keybinds-quit, prefix="q")>>