From 8ff0beec06662102ad48924b80027233dfd3b605 Mon Sep 17 00:00:00 2001 From: Lucien Cartier-Tilet Date: Wed, 6 Apr 2022 18:50:46 +0200 Subject: [PATCH] [Emacs] More documentation --- org/config/emacs.org | 334 +++++++++++++++++++++++++++++-------------- 1 file changed, 223 insertions(+), 111 deletions(-) diff --git a/org/config/emacs.org b/org/config/emacs.org index e9278b8..0e714ba 100644 --- a/org/config/emacs.org +++ b/org/config/emacs.org @@ -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 don’t 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 vim’s keybinds, because let’s 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-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 I’m 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, becomes +. 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)))))) + `( + <>)))) #+end_src *** Ivy @@ -1208,6 +1282,9 @@ Finally, let’s 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, let’s 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, let’s make ~ivy~ richer: (text-mode . yas-minor-mode))) #+end_src +Of course, yasnippet wouldn’t be as awesome as it is without premade +snippets. #+begin_src emacs-lisp (use-package yasnippet-snippets :defer t @@ -1242,6 +1324,8 @@ Finally, let’s make ~ivy~ richer: :straight (:build t)) #+end_src +Similarly, yatemplate offers premade files rather than just strings. +That’s still yasnippet by the way. #+begin_src emacs-lisp (use-package yatemplate :defer t @@ -1249,15 +1333,18 @@ Finally, let’s make ~ivy~ richer: :straight (:build t)) #+end_src +And finally, with ivy you can chose your snippets from a menu if +you’re not sure or if you don’t 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 there’s ~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 Chrome’s name stuck in the package’s 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 let’s add some fancy icons in dired! (advice-add #'all-the-icons-dired--refresh :around #'my/all-the-icons-dired--refresh)) #+end_src +Lastly, let’s 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 won’t modify much for ~image-mode~ (the mode used to display images) +aside from Emacs’ ability to use external converters to display some +images it wouldn’t 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 haven’t 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 doesn’t seem to be available in any repo, so I’ll 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. <> - <> - <> <> - <> - <> <>