[Misc] switching to new repo for org files

This commit is contained in:
2023-09-18 18:45:14 +02:00
parent 566861ee28
commit 4e7e98c28b
176 changed files with 15713 additions and 18925 deletions

377
docs/emacs/basic-config.org Normal file
View File

@@ -0,0 +1,377 @@
#+title: Emacs — Basic Configuration
#+setupfile: ../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/basic-config.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Basic Configuration
** Early Init
:PROPERTIES:
:header-args:emacs-lisp: :tangle ~/.config/emacs/early-init.el :mkdirp yes
:header-args:emacs-lisp+: :exports code :results silent :lexical t
:END:
The early init file is the file loaded before anything else in
Emacs. This is where I put some options in order to disable as quickly
as possible some built-in features of Emacs before they can be even
loaded, speeding Emacs up a bit.
#+begin_src emacs-lisp :mkdirp yes
(setq package-enable-at-startup nil
inhibit-startup-message t
frame-resize-pixelwise t ; fine resize
package-native-compile t) ; native compile packages
(scroll-bar-mode -1) ; disable scrollbar
(tool-bar-mode -1) ; disable toolbar
(tooltip-mode -1) ; disable tooltips
(set-fringe-mode 10) ; give some breathing room
(menu-bar-mode -1) ; disable menubar
(blink-cursor-mode 0) ; disable blinking cursor
(setq gc-cons-threshold (* 1024 1024 1024))
#+end_src
** Emacs Behavior
*** Editing Text in Emacs
I *never* want to keep trailing spaces in my files, which is why Im
doing this:
#+begin_src emacs-lisp
(add-hook 'before-save-hook #'whitespace-cleanup)
#+end_src
I dont understand why some people add two spaces behind a full stop,
I sure dont. Lets tell Emacs.
#+begin_src emacs-lisp
(setq-default sentence-end-double-space nil)
#+end_src
There is a minor mode in Emacs which allows to have a finer way of
jumping from word to word: ~global-subword-mode~. It detects if what
Emacs usually considers a word can be understood as several words, as
in camelCase words, and allows us to jump words on this finer level.
#+begin_src emacs-lisp
(global-subword-mode 1)
#+end_src
Changing half my screen each time my cursor goes too high or too low
is not exactly ideal. Fortunately, if we set ~scroll-conservatively~
high enough we can have the cursor stay on top or at the bottom of the
screen while the text scrolls progressively.
#+begin_src emacs-lisp
(setq scroll-conservatively 1000)
#+end_src
Lastly, I want the default mode for Emacs to be Emacs Lisp.
#+begin_src emacs-lisp
(setq-default initial-major-mode 'emacs-lisp-mode)
#+end_src
**** Indentation
I dont like tabs. They rarely look good, and if I need it I can
almost always tell Emacs to use them through a ~.dir-locals.el~ file or
through the config file of my code formatter. So by default, lets
disable them:
#+begin_src emacs-lisp
(setq-default indent-tabs-mode nil)
(add-hook 'prog-mode-hook (lambda () (setq indent-tabs-mode nil)))
#+end_src
Just to go on a little tangent here: I dont exactly /hate/ tabs, but I
find them really annoying when your text editor knows only them. Sure,
for indentation they work great, and they allow different people
getting different settings in their text editor depending on their
preferred tastes —some may prefer 2 spaces tabs, some may prefer 4
spaces tabs, some deranged people prefer 8 spaces tabs, and some
monsters prefer 3!
But the thing is, once you indented your code, and then you need
alignment, tabs dont work anymore! Or they may on *your* text editor
but not on your coworkers! (Hes the one using 3 spaces tabs by the
way).
So, is the answer to use spaces instead of tabs, and screw peoples
preferences in terms of tabs width? No, I say the answer is more
moderate than that, and it might frighten or anger some of you at
first: use both spaces and tabs. Now, before you lynch me on the main
avenue in front of everyone, let me tell you absolutely no one should
ever be mixing spaces and tabs for indentation, that would be
absolutely terrible and would bring the worst of both worlds. Whats
the best of both worlds then?
#+begin_center
/Tabs for indentation/
/Spaces for alignment/
#+end_center
I havent found a way to automate that in Emacs yet aside from
formatters config file, and tabs look bat in EmacsLisp anyway, so
Ill stick with spaces by default and change it where needed.
*** Programming Modes
First off, my definition of what makes a “programming mode” doesnt exactly
fit mine, so on top of ~prog-mode~, lets add a few other modes.
#+name: line-number-modes-table
| Modes |
|------------|
| prog-mode |
| latex-mode |
#+name: prog-modes-gen
#+header: :cache yes :exports none :tangle no
#+begin_src emacs-lisp :var modes=line-number-modes-table
(mapconcat (lambda (mode) (format "%s-hook" (car mode)))
modes
" ")
#+end_src
**** Line Number
Since version 26, Emacs has a built-in capacity of displaying line
numbers on the left-side of the buffer. This is a fantastic feature
that should actually be the default for all programming modes.
#+begin_src emacs-lisp
(dolist (mode '(<<prog-modes-gen()>>))
(add-hook mode #'display-line-numbers-mode))
#+end_src
**** Folding code
Most programming languages can usually have their code folded, be it
code between curly braces, chunks of comments or code on another level
of indentation (Python, why…?). The minor-mode that enables that is
~hs-minor-mode~, lets enable it for all of these programming modes:
#+begin_src emacs-lisp
(dolist (mode '(<<prog-modes-gen()>>))
(add-hook mode #'hs-minor-mode))
#+end_src
*** Stay Clean, Emacs!
As nice as Emacs is, it isnt very polite or clean by default: open a
file, and it will create backup files in the same directory. But then,
when you open your directory with your favorite file manager and see
almost all of your files duplicated with a =~= appended to the filename,
it looks really uncomfortable! This is why I prefer to tell Emacs to
keep its backup files to itself in a directory it only will access.
#+begin_src emacs-lisp
(setq backup-directory-alist `(("." . ,(expand-file-name ".tmp/backups/"
user-emacs-directory))))
#+end_src
It also loves to litter its ~init.el~ with custom variables here and
there, but the thing is: I regenerate my ~init.el~ each time I tangle
this file! How can I keep Emacs from adding stuff that will be almost
immediately lost? Did someone say /custom file/?
#+begin_src emacs-lisp
(setq-default custom-file (expand-file-name ".custom.el" user-emacs-directory))
(when (file-exists-p custom-file) ; Dont forget to load it, we still need it
(load custom-file))
#+end_src
If we delete a file, we want it moved to the trash, not simply deleted.
#+begin_src emacs-lisp
(setq delete-by-moving-to-trash t)
#+end_src
Finally, the scatch buffer always has some message at its beginning, I
dont want it!
#+begin_src emacs-lisp
(setq-default initial-scratch-message nil)
#+end_src
*** Stay Polite, Emacs!
When asking for our opinion on something, Emacs loves asking us to
answer by “yes” or “no”, but *in full*! Thats very rude! Fortunately,
we can fix this.
#+begin_src emacs-lisp
(defalias 'yes-or-no-p 'y-or-n-p)
#+end_src
This will make Emacs ask us for either hitting the ~y~ key for “yes”, or
the ~n~ key for “no”. Much more polite!
It is also very impolite to keep a certain version of a file in its
buffer when said file has changed on disk. Lets change this behavior:
#+begin_src emacs-lisp
(global-auto-revert-mode 1)
#+end_src
Much more polite! Note that if the buffer is modified and its changes
havent been saved, it will not automatically revert the buffer and
your unsaved changes wont be lost. Very polite!
*** Misc
Lets raise Emacs undo memory to 10 MB, and make Emacs auto-save our
files by default.
#+begin_src emacs-lisp
(setq undo-limit 100000000
auto-save-default t)
#+end_src
#+begin_src emacs-lisp
(setq window-combination-resize t) ; take new window space from all other windows
#+end_src
** Personal Information
Emacs needs to know its master! For various reasons by the way, some
packages rely on these variables to know who it is talking to or
dealing with, such as ~mu4e~ which will guess who you are if you havent
set it up correctly.
#+begin_src emacs-lisp
(setq user-full-name "Lucien Cartier-Tilet"
user-real-login-name "Lucien Cartier-Tilet"
user-login-name "phundrak"
user-mail-address "lucien@phundrak.com")
#+end_src
** Visual Configuration
The first visual setting in this section will activate the visible
bell. What it does is I get a visual feedback each time I do something
Emacs doesnt agree with, like tring to go up a line when Im already
at the top of the buffer.
#+begin_src emacs-lisp
(setq visible-bell t)
#+end_src
It is nicer to see a cursor cover the actual space of a character.
#+begin_src emacs-lisp
(setq x-stretch-cursor t)
#+end_src
When text is ellipsed, I want the ellipsis marker to be a single
character of three dots. Lets make it so:
#+begin_src emacs-lisp
(with-eval-after-load 'mule-util
(setq truncate-string-ellipsis ""))
#+end_src
With Emacs 29.0.50 onwards, a new frame parameter exists:
~alpha-background~. Unlike ~alpha~, this frame parameter only makes Emacs
background transparent, excluding images and text.
#+begin_src emacs-lisp
(add-to-list 'default-frame-alist '(alpha-background . 0.9))
#+end_src
*** Modeline Modules
I sometimes use Emacs in fullscreen, meaning my usual taskbar will be
hidden. This is why I want the current date and time to be displayed,
in an ISO-8601 style, although not exactly ISO-8601 (this is the best
time format, fight me).
#+begin_src emacs-lisp
(require 'time)
(setq display-time-format "%Y-%m-%d %H:%M")
(display-time-mode 1) ; display time in modeline
#+end_src
Something my taskbar doesnt have is a battery indicator. However, I
want it enabled only if I am on a laptop or if a battery is available.
#+begin_src emacs-lisp
(let ((battery-str (battery)))
(unless (or (equal "Battery status not available" battery-str)
(string-match-p (regexp-quote "N/A") battery-str))
(display-battery-mode 1)))
#+end_src
This isnt a modeline module per se, but we have an indicator of the
current line in Emacs. And although it is useful, I also often wish to
know which column Im on. This can be activated like so:
#+begin_src emacs-lisp
(column-number-mode)
#+end_src
The following code is, as will several chunks of code in this config,
borrowed from [[https://tecosaur.github.io/emacs-config/#theme-modeline][TECs configuration]]. It hides the encoding information
of the file if the file itself is a regular UTF-8 file with ~\n~ line
ending. Be aware the ~doom-modeline-buffer-encoding~ variable is usabel
here only because I use the Doom modeline as seen below.
#+begin_src emacs-lisp
(defun modeline-contitional-buffer-encoding ()
"Hide \"LF UTF-8\" in modeline.
It is expected of files to be encoded with LF UTF-8, so only show
the encoding in the modeline if the encoding is worth notifying
the user."
(setq-local doom-modeline-buffer-encoding
(unless (and (memq (plist-get (coding-system-plist buffer-file-coding-system) :category)
'(coding-category-undecided coding-category-utf-8))
(not (memq (coding-system-eol-type buffer-file-coding-system) '(1 2))))
t)))
#+end_src
Now, lets automate the call to this function in order to apply the
modifications to the modeline each time we open a new file.
#+begin_src emacs-lisp
(add-hook 'after-change-major-mode-hook #'modeline-contitional-buffer-encoding)
#+end_src
*** Fonts
I dont like the default font I usually have on my machines, I really
dont. I prefer [[https://github.com/microsoft/cascadia-code][Cascadia Code]], as it also somewhat supports the [[https://www.internationalphoneticassociation.org/][IPA]].
#+begin_src emacs-lisp
(defvar phundrak/default-font-size 90
"Default font size.")
(defvar phundrak/default-font-name "Cascadia Code"
"Default font.")
(defun my/set-font ()
(when (find-font (font-spec :name phundrak/default-font-name))
(set-face-attribute 'default nil
:font phundrak/default-font-name
:height phundrak/default-font-size)))
(my/set-font)
(add-hook 'server-after-make-frame-hook #'my/set-font)
#+end_src
*** Frame Title
This is straight-up copied from [[https://tecosaur.github.io/emacs-config/config.html#window-title][TEC]]s configuration. See their comment
on the matter.
#+begin_src emacs-lisp
(setq frame-title-format
'(""
"%b"
(:eval
(let ((project-name (projectile-project-name)))
(unless (string= "-" project-name)
(format (if (buffer-modified-p) " ◉ %s" "  ●  %s - Emacs") project-name))))))
#+end_src
** A better custom variable setter
Something people often forget about custom variables in Elisp is they
can have a custom setter that will run some code if we set the
variable properly with ~customize-set-variable~, so ~setq~ shouldnt be
the users choice by default. But repeatedly writing
~customize-set-variable~ can get tiring and boring. So why not take the
best of both world and create ~csetq~, a ~setq~ that uses
~customize-set-variable~ under the hood while it keeps a syntax similar
to the one ~setq~ uses?
#+begin_src emacs-lisp
(defmacro csetq (&rest forms)
"Bind each custom variable FORM to the value of its VAL.
FORMS is a list of pairs of values [FORM VAL].
`customize-set-variable' is called sequentially on each pairs
contained in FORMS. This means `csetq' has a similar behaviour as
`setq': each VAL expression are evaluated sequentially, i.e. the
first VAL is evaluated before the second, and so on. This means
the value of the first FORM can be used to set the second FORM.
The return value of `csetq' is the value of the last VAL.
\(fn [FORM VAL]...)"
(declare (debug (&rest sexp form))
(indent 1))
;; Check if we have an even number of arguments
(when (= (mod (length forms) 2) 1)
(signal 'wrong-number-of-arguments (list 'csetq (1+ (length forms)))))
;; Transform FORMS into a list of pairs (FORM . VALUE)
(let (sexps)
(while forms
(let ((form (pop forms))
(value (pop forms)))
(push `(customize-set-variable ',form ,value)
sexps)))
`(progn ,@(nreverse sexps))))
#+end_src
I first got inspired by [[https://oremacs.com/2015/01/17/setting-up-ediff/][this blog article]] (archived article, just in
case) but it seems the code snippet no longer works properly, so not
only did I have to modify it to make it work with an arbitrary amount
of arguments (as long as its pairs of variables and their value), but
I also had to make the code simply work.

121
docs/emacs/custom-elisp.org Normal file
View File

@@ -0,0 +1,121 @@
#+title: Emacs — Custom Elisp
#+setupfile: ../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/custom-elisp.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Custom Elisp
** Dired functions
*** ~phundrak/open-marked-files~
This function allows the user to open all marked files from a dired
buffer in new Emacs buffers.
#+begin_src emacs-lisp
(defun phundrak/open-marked-files (&optional files)
"Open all marked FILES in Dired buffer as new Emacs buffers."
(interactive)
(let* ((file-list (if files
(list files)
(if (equal major-mode "dired-mode")
(dired-get-marked-files)
(list (buffer-file-name))))))
(mapc (lambda (file-path)
(find-file file-path))
(file-list))))
#+end_src
** Switch between buffers
Two default shortcuts I really like from Spacemacs are ~SPC b m~ and ~SPC
b s~, which bring the user directly to the ~*Messages*~ buffer and the
~*scratch*~ buffer respectively. These functions do exactly this.
#+begin_src emacs-lisp
(defun switch-to-messages-buffer ()
"Switch to Messages buffer."
(interactive)
(switch-to-buffer (messages-buffer)))
(defun switch-to-scratch-buffer ()
"Switch to Messages buffer."
(interactive)
(switch-to-buffer "*scratch*"))
#+end_src
** Screenshots
Since Emacs27, it is possible for Emacs to take screenshots of itself
in various formats. Im mainly interested in the SVG and PNG format,
so Ill only write functions for these. It isnt really redundant with
the ~screenshot.el~ package used [[file:./packages/applications.md#screenshot][here]] since these functions take a
screenshot of Emacs as a whole rather than of a code snippet.
First, we have a general function which is a slight modification of
the function shared by Alphapapa in [[https://www.reddit.com/r/emacs/comments/idz35e/emacs_27_can_take_svg_screenshots_of_itself/g2c2c6y/][this Reddit comment]]. I modified it
to make it possible to pass as an argument the format the screenshot
will be taken as or ask the user which format they would like to save
it as.
#+begin_src emacs-lisp
(defun self-screenshot (&optional type)
"Save a screenshot of type TYPE of the current Emacs frame.
As shown by the function `', type can weild the value `svg',
`png', `pdf'.
This function will output in /tmp a file beginning with \"Emacs\"
and ending with the extension of the requested TYPE."
(interactive (list
(intern (completing-read "Screenshot type: "
'(png svg pdf postscript)))))
(let* ((extension (pcase type
('png ".png")
('svg ".svg")
('pdf ".pdf")
('postscript ".ps")
(otherwise (error "Cannot export screenshot of type %s" otherwise))))
(filename (make-temp-file "Emacs-" nil extension))
(data (x-export-frames nil type)))
(with-temp-file filename
(insert data))
(kill-new filename)
(message filename)))
#+end_src
I used this function to take the screenshots you can see in this
document.
** Handle new windows
The two functions below allow the user to not only create a new window
to the right or below the current window (respectively), but also to
focus the new window immediately.
#+begin_src emacs-lisp
(defun split-window-right-and-focus ()
"Spawn a new window right of the current one and focus it."
(interactive)
(split-window-right)
(windmove-right))
(defun split-window-below-and-focus ()
"Spawn a new window below the current one and focus it."
(interactive)
(split-window-below)
(windmove-down))
(defun kill-buffer-and-delete-window ()
"Kill the current buffer and delete its window."
(interactive)
(progn
(kill-this-buffer)
(delete-window)))
#+end_src
** Extend ~add-to-list~
One function I find missing regarding ~add-to-list~ is ~add-all-to-list~
which enables the user to add multiple elements to a list at once.
Instead, with vanilla Emacs, I have to repeatedly call ~add-to-list~.
Thats not very clean. Lets declare this missing function:
#+begin_src emacs-lisp
(defun add-all-to-list (list-var elements &optional append compare-fn)
"Add ELEMENTS to the value of LIST-VAR if it isnt there yet.
ELEMENTS is a list of values. For documentation on the variables
APPEND and COMPARE-FN, see `add-to-list'."
(let (return)
(dolist (elt elements return)
(setq return (add-to-list list-var elt append compare-fn)))))
#+end_src

1
docs/emacs/img Symbolic link
View File

@@ -0,0 +1 @@
../img/emacs

125
docs/emacs/index.org Normal file
View File

@@ -0,0 +1,125 @@
#+title: Emacs Configuration
#+setupfile: ../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/init.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Emacs Configuration
[[file:./img/emacs.svg]]
** Introduction
After a couple of years using Spacemacs and a failed attempt at
switching to DoomEmacs, Im finally switching back to a vanilla
configuration! Why? Because I got tired of the framework getting in my
way when I wanted to do stuff. Im sure this is more applicable to
Spacemacs than DoomEmacs since the latter has nice macros written to
easily add new packages and configure them, such as ~package!~, ~after!~,
and others. But ultimately, I wanted to have a system I designed
entirely, with the keybinds I want, the packages I want.
Aso, why Emacs? You know this famous quote:
#+begin_quote
Emacs is a great operating system, it just lacks a good text editor.
#+end_quote
Its actually pretty true in my opinion. Emacs is basically a Lisp
machine with a default text editor, programmed with EmacsLisp, a
general-purpose programming language. Therefore, if you want to do
something in Emacs, with enough Elisp you can do it --- if its not in
Emacs already, that is.
#+attr_html: :alt Dammit Emacs… :loading lazy
#+caption: [[https://xkcd.com/378/][XKCD n°378]]: Real Programmers
[[file:./img/real_programmers.png]]
** A Warning Before You Proceed
:PROPERTIES:
:header-args:emacs-lisp: :tangle no
:END:
This configuration makes heavy use of the [[https://orgmode.org/manual/Noweb-Reference-Syntax.html][noweb]] syntax. This means if
you encounter some code that looks ~<<like-this>>~, org-mode will
replace this snippet with another code snippet declared elsewhere in
my configuration. If you see some code that looks ~<<like-this()>>~,
some generating code will run and replace this piece of text with the
text generated. A quick example:
#+begin_src elisp
(defun hello ()
<<generate-docstring()>>
<<print-hello>>)
#+end_src
Will instead appear as
#+begin_src emacs-lisp :noweb yes
(defun hello ()
<<generate-docstring()>>
<<print-hello>>)
#+end_src
This is because I have the block of code below named
~generate-docstring~ which generates an output, which replaces its noweb
tag. You can recognize noweb snippets generating code with the
parenthesis. Often, such blocks arent visible in my HTML exports, but
you can still see them if you open the actual org source file.
#+name: generate-docstring
#+begin_src emacs-lisp
(concat "\""
"Print \\\"Hello World!\\\" in the minibuffer."
"\"")
#+end_src
On the other hand, noweb snippets without parenthesis simply replace
the snippet with the equivalent named code block. For instance the one
below is named ~print-hello~ and is placed as-is in the target source
block.
#+name: print-hello
#+begin_src emacs-lisp
(message "Hello World!")
#+end_src
** Loading All Configuration Modules
#+name: emacs-modules
| Module Name | Config Page |
|--------------------------+----------------------------------|
| =basic-config.el= | [[file:./basic-config.org][Basic Configuration]] |
| =custom-elisp.el= | [[file:./custom-elisp.org][Custom Elisp]] |
| =package-manager.el= | [[file:./package-manager.org][Package Manager]] |
| =keybinding-managemers.el= | [[file:./keybinding-managemers.org][Keybinding Managers]] |
| =applications.el= | [[file:./packages/applications.org][Packages — Applications]] |
| =autocompletion.el= | [[file:./packages/autocompletion.org][Packages — Autocompletion]] |
| =editing.el= | [[file:./packages/editing.org][Packages — Editing]] |
| =emacs-builtin.el= | [[file:./packages/emacs-builtin.org][Packages — Emacs Built-ins]] |
| =exwm.el= | [[file:./packages/exwm.org][Packages — EXWM]] |
| =helpful.el= | [[file:./packages/helpful.org][Packages — Making My Life Easier]] |
| =latex.el= | [[file:./packages/latex.org][Packages — LaTeX]] |
| =misc.el= | [[file:./packages/misc.org][Packages — Misc]] |
| =org.el= | [[file:./packages/org.org][Packages — Org Mode]] |
| =programming.el= | [[file:./packages/programming.org][Packages — Programming]] |
| =visual-config.el= | [[file:./packages/visual-config.org][Packages — Visual Configuration]] |
| =keybindings.el= | [[file:./keybindings.org][Keybindings]] |
#+name: generate-modules
#+begin_src emacs-lisp :tangle no :cache yes :var modules=emacs-modules :exports none
(mapconcat (lambda (line)
(concat "\"" (string-trim (car line) "=" "=") "\""))
modules
" ")
#+end_src
#+RESULTS[f76449860408293997e174ff94c743d46951835b]: generate-modules
: "basic-config.el" "custom-elisp.el" "package-manager.el" "keybinding-managemers.el" "applications.el" "autocompletion.el" "editing.el" "emacs-builtin.el" "exwm.el" "helpful.el" "latex.el" "misc.el" "org.el" "programming.el" "visual-config.el" "keybindings.el"
#+begin_src emacs-lisp :noweb yes
(dolist (module '(<<generate-modules()>>))
(load (expand-file-name module
(expand-file-name "lisp" user-emacs-directory))))
#+end_src
* TODOs :noexport:
** TODO advise ~evil-insert~ in eshell
Advise ~evil-insert~ to go to the end of the buffer while in
~eshell-mode~.
** DONE Get started with org-roam
CLOSED: [2023-06-17 Sat 13:38]

View File

@@ -0,0 +1,211 @@
#+title: Emacs — Keybinding Managers
#+setupfile: ../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/keybinding-managemers.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Keybinding Managers
** Which-key
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)
:defer t
:init (which-key-mode)
:diminish which-key-mode
:config
(setq which-key-idle-delay 1))
#+end_src
** General
General is an awesome package for managing keybindings. Not only is it
oriented towards keychords by default (which I love), but it also
provides some integration with evil so that we can declare keybindings
for certain states only! This is a perfect replacement for ~define-key~,
~evil-define-key~, and any other function for defining keychords. And it
is also possible to declare a prefix for my keybindings! By default,
all keybinds will be prefixed with ~SPC~ and keybinds related to a
specific mode (often major modes) will be prefixed by a comma ~,~ (and
by ~C-SPC~ and ~M-m~ respectively when in ~insert-mode~ or ~emacs-mode~). You
can still feel some influence from my Spacemacs years here.
#+begin_src emacs-lisp
(use-package general
:straight (:build t)
:init
(general-auto-unbind-keys)
:config
(general-create-definer phundrak/undefine
:keymaps 'override
:states '(normal emacs))
(general-create-definer phundrak/evil
:states '(normal))
(general-create-definer phundrak/leader-key
:states '(normal insert visual emacs)
:keymaps 'override
:prefix "SPC"
:global-prefix "C-SPC")
(general-create-definer phundrak/major-leader-key
:states '(normal insert visual emacs)
:keymaps 'override
:prefix ","
:global-prefix "M-m"))
#+end_src
** Evil
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
(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
<<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))
#+end_src
I want to undefine some 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-specific 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-visual-line
"T" 'evil-join
"s" 'evil-previous-visual-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
:straight (:build t)
:config
;; bépo conversion
(defun my/bépo-rotate-evil-collection (_mode mode-keymaps &rest _rest)
(evil-collection-translate-key 'normal mode-keymaps
;; bépo ctsr is qwerty hjkl
"c" "h"
"t" "j"
"s" "k"
"r" "l"
;; add back ctsr
"h" "c"
"j" "t"
"k" "s"
"l" "r"))
(add-hook 'evil-collection-setup-hook #'my/bépo-rotate-evil-collection)
(evil-collection-init))
#+end_src
~undo-tree~ is my preferred way of undoing and redoing stuff. The main
reason is it doesnt create a linear undo/redo history, but rather a
complete tree you can navigate to see your complete editing history.
One of the two obvious things to do are to tell Emacs to save all its
undo history fies in a dedicated directory, otherwise wed risk
littering all of our directories. The second thing is to simply
globally enable its mode.
#+begin_src emacs-lisp
(use-package undo-tree
:defer t
:straight (:build t)
:custom
(undo-tree-history-directory-alist
`(("." . ,(expand-file-name (file-name-as-directory "undo-tree-hist")
user-emacs-directory))))
:init
(global-undo-tree-mode)
:config
<<undo-tree-ignore-text-properties>>
<<undo-tree-compress-files>>
(setq undo-tree-visualizer-diff t
undo-tree-visualizer-timestamps t
undo-tree-auto-save-history t
undo-tree-enable-undo-in-region t
undo-limit (* 800 1024)
undo-strong-limit (* 12 1024 1024)
undo-outer-limit (* 128 1024 1024)))
#+end_src
An interesting behavior from DoomEmacs is to compress the history
files with ~zstd~ when it is present on the system. Not only do we enjoy
much smaller files (according to DoomEmacs, we get something like 80%
file savings), Emacs can load them much faster than the regular files.
Sure, it uses more CPU time uncompressing these files, but its
insignificant, and its still faster than loading a heavier file.
#+name: undo-tree-compress-files
#+begin_src emacs-lisp :tangle no
(when (executable-find "zstd")
(defun my/undo-tree-append-zst-to-filename (filename)
"Append .zst to the FILENAME in order to compress it."
(concat filename ".zst"))
(advice-add 'undo-tree-make-history-save-file-name
:filter-return
#'my/undo-tree-append-zst-to-filename))
#+end_src
** Hydra
[[https://github.com/abo-abo/hydra][Hydra]] is a simple menu creator for keybindings.
#+begin_src emacs-lisp
(use-package hydra
:straight (:build t)
:defer t)
#+end_src

391
docs/emacs/keybindings.org Normal file
View File

@@ -0,0 +1,391 @@
#+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=keybinds-windows prefix=""
(mapconcat (lambda (line)
(let* ((key (nth 0 line))
(function (nth 1 line))
(comment (or (nth 2 line) ""))
(package (or (nth 3 line) "")))
(format "\"%s%s\" %s"
prefix
key
(if (string= "" comment)
(if (member function '("" "nil")) "nil" (concat "#'" function))
(format "'(%s :wk %s%s)"
(if (member function '("" "nil")) ":ignore t" function)
(if (member function '("none" "nil")) "t" (concat "\"" comment "\""))
(if (string-blank-p package) "" (concat ":package " package)))))))
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
"C-a" #'beginning-of-line
"C-e" #'end-of-line
"C-y" #'yank
"M-y" #'counsel-yank-pop)
#+end_src
#+begin_src emacs-lisp
(general-define-key
"<f5>" #'compile
"<f6>" #'recompile)
(phundrak/leader-key
"SPC" '(counsel-M-x :wk "M-x")
"'" #'shell-pop
<<general-keybindings-gen(table=keybinds-tabs, prefix="TAB ")>>
<<general-keybindings-gen(table=keybinds-apps, prefix="a")>>
<<general-keybindings-gen(table=keybinds-apps-shell, prefix="as")>>
<<general-keybindings-gen(table=treemacs-keybinds, prefix="at")>>
<<general-keybindings-gen(table=keybinds-buffers, prefix="b")>>
"c" '(:ignore t :wk "code")
"cl" #'evilnc-comment-or-uncomment-lines
<<keybindings-flycheck>>
<<general-keybindings-gen(table=keybinds-files, prefix="f")>>
<<keybinds-specific-files>>
<<general-keybindings-gen(table=keybinds-help, prefix="h")>>
"i" '(:ignore t :wk "insert")
"iu" #'counsel-unicode-char
<<general-keybindings-gen(table=keybinds-jump, prefix="j")>>
<<general-keybindings-gen(table=keybinds-toggle, prefix="t ")>>
<<general-keybindings-gen(table=keybinds-text, prefix="T")>>
<<general-keybindings-gen(table=keybinds-windows, prefix="w")>>
<<general-keybindings-gen(table=keybinds-quit, prefix="q")>>
"u" #'universal-argument
"U" #'undo-tree-visualize)
#+end_src
** Apps
Here are my apps keybinds. Each one of them is prefixed by ~a~.
#+name: keybinds-apps
| Key | Function | Description | Package |
|-----+----------------------------+-------------+------------|
| | | apps | |
| c | calc | | |
| C | | calendar | |
| CC | calendar | | |
| Co | org-agenda | | org |
| Cs | org-caldav-sync | | org-caldav |
| d | docker | | |
| E | elfeed | | |
| e | | email | |
| ec | mu4e-compose-new | | |
| em | mu4e | | |
| k | keycast-mode | | |
| K | keycast-log-mode | | |
| m | | mastodon | |
| mm | mastodon | | mastodon |
| mn | mastodon-notifications-get | | mastodon |
| mt | mastodon-toot | | mastodon |
| T | tetris | | |
| w | wttrin | | wttrin |
I also have two main shell-related functions, prefixed with ~as~.
#+name: keybinds-apps-shell
| Key | Function | Description | Package |
|-----+-------------+-------------+-------------|
| | | shells | |
| e | eshell-new | | |
| v | vterm | | vterm |
| V | multi-vterm | | multi-vterm |
** Buffers
My buffer-related keybinds are all prefixed by ~b~.
#+name: keybinds-buffers
| Key | Function | Description |
|-----+------------------------------------+-------------|
| | | buffers |
| b | bufler-switch-buffer | |
| B | bury-buffer | |
| c | clone-indirect-buffer | |
| C | clone-indirect-buffer-other-window | |
| l | bufler | |
| d | kill-this-buffer | |
| D | kill-buffer | |
| h | dashboard-refresh-buffer | |
| m | switch-to-messages-buffer | |
| n | next-buffer | |
| p | previous-buffer | |
| r | counsel-buffer-or-recentf | |
| s | switch-to-scratch-buffer | |
** 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-flycheck
#+begin_src emacs-lisp :tangle no
"e" '(:ignore t :which-key "errors")
"e." '(hydra-flycheck/body :wk "hydra")
"el" #'counsel-flycheck
"ee" '(:keymap flycheck-command-map :package 'flycheck :wk "flycheck")
"ef" '(:keymap flyspell-mode-map :package 'flyspell :wk "flyspell")
"eF" #'flyspell-hydra/body
#+end_src
** Files
My keybinds for file manipulation are prefixed by ~f~.
#+name: keybinds-files
| Key | Function | Description |
|-----+----------------------+-------------|
| | | files |
| f | counsel-find-file | |
| F | ivy-quick-find-files | |
| h | hexl-find-file | |
| r | counsel-recentf | |
| s | save-buffer | |
I also have some keybinds dedicated to opening specific files.
#+name: keybinds-specific-files
#+begin_src emacs-lisp :tangle no
"fc" '((lambda ()
(interactive)
(find-file "~/org/config/emacs.org"))
:wk "emacs.org")
"fi" '((lambda ()
(interactive)
(find-file (concat user-emacs-directory "init.el")))
:which-key "init.el")
"fR" '((lambda ()
(interactive)
(counsel-find-file ""
(concat user-emacs-directory
(file-name-as-directory "straight")
(file-name-as-directory "repos"))))
:which-key "straight package")
"fS" '((lambda ()
(interactive)
(find-file "~/org/config/stumpwm.org"))
:which-key "stumpwm.org")
#+end_src
** Help
My keybinds for help are prefixed by ~h~.
#+name: keybinds-help
| Key | Function | Description |
|-----+--------------------------+-------------|
| | | help |
| k | which-key-show-top-level | |
| 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 | |
** Jump
My keybinds for jumping around are prefixed by ~j~.
#+name: keybinds-jump
| Key | Function | Description |
|-----+-------------------------+-------------|
| | | jump |
| f | counsel-file-jump | |
| d | dirvish-dwim | |
| D | dired-jump-other-window | |
** Project
My keybinds for my projects are prefixed by ~p~.
#+name: keybinds-project
| Key | Function | Description |
|-----+--------------------------------------------+-------------|
| | | project |
| ! | projectile-run-shell-command-in-root | |
| & | projectile-run-async-shell-command-in-root | |
| b | counsel-projectile-switch-to-buffer | |
| c | counsel-projectile | |
| d | counsel-projectile-find-dir | |
| e | projectile-edit-dir-locals | |
| f | counsel-projectile-find-file | |
| g | projectile-find-tag | |
| k | project-kill-buffers | |
| p | counsel-projectile-switch-project | |
| t | ivy-magit-todos | |
| v | projectile-vc | |
*** Treemacs
#+name: treemacs-keybinds
| Key | Function | Description |
|-----+----------------------------------------+-------------|
| | | treemacs |
| c | | create |
| cd | treemacs-create-dir | |
| cf | treemacs-create-file | |
| ci | treemacs-create-icon | |
| ct | treemacs-create-theme | |
| cw | treemacs-create-workspace | |
| d | treemacs-delete-file | |
| f | | files |
| ff | treemacs-find-file | |
| ft | treemacs-find-tag | |
| l | | lsp |
| ls | treemacs-expand-lsp-symbol | |
| ld | treemacs-expand-lsp-treemacs-deps | |
| lD | treemacs-collapse-lsp-treemacs-deps | |
| lS | treemacs-collapse-lsp-symbol | |
| p | | projects |
| pa | treemacs-add-project-to-workspace | |
| pf | treemacs-project-follow-mode | |
| pn | treemacs-project-of-node | |
| pp | treemacs-project-at-point | |
| pr | treemacs-remove-project-from-workspace | |
| pt | treemacs-move-project-down | |
| ps | treemacs-move-project-up | |
| r | | rename |
| rf | treemacs-rename-file | |
| rp | treemacs-rename-project | |
| rr | treemacs-rename | |
| rw | treemacs-rename-workspace | |
| t | treemacs | |
| T | | toggles |
| Td | treemacs-toggle-show-dotfiles | |
| Tn | treemacs-toggle-node | |
| v | | visit node |
| va | treemacs-visit-node-ace | |
| vc | treemacs-visit-node-close-treemacs | |
| vn | treemacs-visit-node-default | |
| y | | yank |
| ya | treemacs-copy-absolute-path-at-point | |
| yp | treemacs-copy-project-path-at-point | |
| yr | treemacs-copy-relative-path-at-point | |
| yf | treemacs-copy-file | |
** 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 keybinds are prefixed by ~SPC TAB~.
#+name: keybinds-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: keybinds-text
| Key | Function | Description |
|-----+----------------------+-------------|
| | | text |
| e | string-edit-at-point | |
| u | downcase-region | |
| U | upcase-region | |
| z | hydra-zoom/body | |
** Toggles
My toggle keybinds are prefixed by ~t~.
#+name: keybinds-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 | |
** Windows
A couple of keybinds are hidden from which-key, otherwise theres not
much to say. The prefix here is ~w~.
#+name: keybinds-windows
| Key | Function | Description |
|-----+-------------------------------+-------------|
| | | windows |
| c | evil-window-left | |
| t | evil-window-down | |
| s | evil-window-up | |
| r | evil-window-right | |
| . | windows-adjust-size/body | |
| - | split-window-below-and-focus | |
| / | split-window-right-and-focus | |
| $ | winum-select-window-by-number | |
| 0 | winum-select-window-0-or-10 | none |
| 1 | winum-select-window-1 | none |
| 2 | winum-select-window-2 | none |
| 3 | winum-select-window-3 | none |
| 4 | winum-select-window-4 | none |
| 5 | winum-select-window-5 | none |
| 6 | winum-select-window-6 | none |
| 7 | winum-select-window-7 | none |
| 8 | winum-select-window-8 | none |
| 9 | winum-select-window-9 | none |
| b | kill-buffer-and-delete-window | |
| d | delete-window | |
| o | other-window | |
| D | delete-other-windows | |
| w | | writeroom |
| w. | writeroom-buffer-width/body | |
| ww | writeroom-mode | |
** Quit
Why would I ever use any of these keybinds? They are prefixed with ~q~.
#+name: keybinds-quit
| Key | Function | Description |
|-----+----------------------------+-------------|
| | | quit |
| f | delete-frame | |
| q | save-buffers-kill-terminal | |
| Q | kill-emacs | |

View File

@@ -0,0 +1,85 @@
#+title: Emacs — Package Manager
#+setupfile: ../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/package-manager.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Package Manager
** Repositories
By default, only GNUs repositories are available to the package
managers of Emacs. I also want to use Melpa and org-modes repository,
so lets add them! Note that the stock /elpa/ repository is renamed to
/gnu/ due to the addition of another Elpa repository, /nongnu/, which will
hosts packages that do not conform to the FSFs copyright assignment.
Both the /gnu/ and the /nonfree/ repositories are Elpa repositories now,
and they are renamed here in order to avoid any confusion between the
two of them. Melpa is a community-maintained repository which contains
an absurd amount of Emacs packages.
#+begin_src emacs-lisp
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")
("nongnu" . "https://elpa.nongnu.org/nongnu/")))
#+end_src
** Straight
For my package management, I prefer to use ~straight~ ([[https://github.com/raxod502/straight.el][GitHub]]). This is
due to its capacity of integrating nicely with ~use-package~, which also
supports ~general~ which I use for my keybindings (see below), but also
because with it, I can specify where to retrieve packages that are not
on MELPA or ELPA but on GitHub and other online Git repositories too.
First, lets bootstrap straight.
#+begin_src emacs-lisp
(defvar bootstrap-version)
(defvar comp-deferred-compilation-deny-list ()) ; workaround, otherwise straight shits itself
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
(bootstrap-version 5))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
#+end_src
Now, we can refresh our package list in order to be able to install
stuff.
#+begin_src emacs-lisp
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
#+end_src
From time to time, I fork some packages either because Im trying to
implement something new in said package, or because the package is
unmaintained, and I want to continue developing it a bit more. Straight
provides a nice feature for using forks of a package with its ~:fork~
option. If set to ~t~, then straight will attempt to retrieve the
package with the same name but with a different username on the same
host. This username is retrieved through the following variable:
#+begin_src emacs-lisp
(setq straight-host-usernames
'((github . "Phundrak")
(gitlab . "Phundrak")))
#+end_src
The huge advantage of straight is it clones through git the packages
it installs. This means development can be done directly on the
downloaded package. However, Forge (a Magit extension for interacting
with websites such as GitHub, Gitlab, and such) interacts by default
with the forge described by the =origin= remote, which isnt necessarily
the one I want Forge to interact with by default. Therefore,
=straight.el= will name all default remotes =straight= to avoid any name
collision with my regular development flow.
#+begin_src emacs-lisp
(setq straight-vc-git-default-remote-name "straight")
#+end_src
We finally come to the ~use-package~ installation. This is done like so:
#+begin_src emacs-lisp
(straight-use-package '(use-package :build t))
(setq use-package-always-ensure t)
#+end_src

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,310 @@
#+title: Emacs — Packages — Autocompletion
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/autocompletion.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Autocompletion
** Code Autocompletion
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)
:defer t
:hook (company-mode . evil-normalize-keymaps)
:init (global-company-mode)
:config
(setq company-minimum-prefix-length 2
company-toolsip-limit 14
company-tooltip-align-annotations t
company-require-match 'never
company-global-modes '(not erc-mode message-mode help-mode gud-mode)
company-frontends
'(company-pseudo-tooltip-frontend ; always show candidates in overlay tooltip
company-echo-metadata-frontend) ; show selected candidate docs in echo area
company-backends '(company-capf)
company-auto-commit nil
company-auto-complete-chars nil
company-dabbrev-other-buffers nil
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
:straight (:build t)
:config
(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)
:after (company all-the-icons)
:config
(setq company-box-show-single-candidate t
company-box-backends-colors nil
company-box-max-candidates 50
company-box-icons-alist 'company-box-icons-all-the-icons
company-box-icons-all-the-icons
(let ((all-the-icons-scale-factor 0.8))
`(
<<gen-company-box-icons()>>))))
#+end_src
** Ivy
My main menu package is =ivy= which I use as much as possible Ive
noticed =helm= can be slow, very slow in comparison to =ivy=, so Ill use
the latter as much as possible. Actually, only =ivy= is installed for
now. I could have used =ido= too, but I find it to be a bit too
restricted in terms of features compared to =ivy=.
#+begin_src emacs-lisp
(use-package ivy
:straight t
:defer t
:diminish
:bind (("C-s" . swiper)
:map ivy-minibuffer-map
("TAB" . ivy-alt-done)
("C-l" . ivy-alt-done)
("C-t" . ivy-next-line)
("C-s" . ivy-previous-line)
("C-u" . ivy-scroll-up-command)
("C-d" . ivy-scroll-down-command)
:map ivy-switch-buffer-map
("C-t" . ivy-next-line)
("C-s" . ivy-previous-line)
("C-l" . ivy-done)
("C-d" . ivy-switch-buffer-kill)
:map ivy-reverse-i-search-map
("C-t" . ivy-next-line)
("C-s" . ivy-previous-line)
("C-d" . ivy-reverse-i-search-kill))
:config
(ivy-mode 1)
(setq ivy-wrap t
ivy-height 17
ivy-sort-max-size 50000
ivy-fixed-height-minibuffer t
ivy-read-action-functions #'ivy-hydra-read-action
ivy-read-action-format-function #'ivy-read-action-format-columns
projectile-completion-system 'ivy
ivy-on-del-error-function #'ignore
ivy-use-selectable-prompt t))
#+end_src
There is also [[https://github.com/raxod502/prescient.el][~prescient.el~]] that offers some nice features when
coupled with ~ivy~, guess what was born out of it? ~ivy-prescient~, of
course!
#+begin_src emacs-lisp
(use-package ivy-prescient
:after ivy
:straight (:build t))
#+end_src
I warned you Id use too much ~all-the-icons~, I did!
#+begin_src emacs-lisp
(use-package all-the-icons-ivy
:straight (:build t)
:after (ivy all-the-icons)
:init (all-the-icons-ivy-setup)
:hook (after-init . all-the-icons-ivy-setup))
(all-the-icons-ivy-setup)
#+end_src
A buffer popping at the bottom of the screen is nice and all, but have
you considered a floating buffer in the center of your frame?
#+begin_src emacs-lisp
(use-package ivy-posframe
:defer t
:after (:any ivy helpful)
:hook (ivy-mode . ivy-posframe-mode)
:straight (:build t)
:init
(ivy-posframe-mode 1)
:config
(setq ivy-fixed-height-minibuffer nil
ivy-posframe-border-width 10
ivy-posframe-parameters
`((min-width . 90)
(min-height . ,ivy-height))))
#+end_src
Something that can be missing sometimes in Ivy is the ability to
select multiple entries at once. For instance, when programming in
Java, LPS can offer you to automatically generate the methods ~equals~
and ~hashCode~ based on selected members, but with vanilla Ivy, you can
only select one. Not really useful. ~ivy-hydra~ is a package that offers
a Hydra interface when in Ivy which allows you to select multiple
choices among other things.
#+begin_src emacs-lisp
(use-package ivy-hydra
:requires (ivy hydra)
:after ivy
:straight (:build t))
#+end_src
Finally, lets make ~ivy~ richer:
#+begin_src emacs-lisp
(use-package ivy-rich
:straight (:build t)
:after ivy
:init
(ivy-rich-mode 1))
#+end_src
** Counsel
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 t
:after recentf
:after ivy
:bind (("M-x" . counsel-M-x)
("C-x b" . counsel-ibuffer)
("C-x C-f" . counsel-find-file)
:map minibuffer-local-map
("C-r" . 'counsel-minibuffer-history)))
#+end_src
** Yasnippet
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
:straight (:build t)
:init
(yas-global-mode)
:hook ((prog-mode . yas-minor-mode)
(text-mode . yas-minor-mode)))
#+end_src
Of course, yasnippet wouldnt be as awesome as it is without pre-made
snippets.
#+begin_src emacs-lisp
(use-package yasnippet-snippets
:defer t
:after yasnippet
:straight (:build t))
#+end_src
Similarly, yatemplate offers pre-made files rather than just strings.
Thats still yasnippet by the way.
#+begin_src emacs-lisp
(use-package yatemplate
:defer t
:after yasnippet
:straight (:build t))
#+end_src
And finally, with ivy you can choose 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)
:general
(phundrak/leader-key
:infix "i"
:packages 'ivy-yasnippet
"y" #'ivy-yasnippet))
#+end_src

View File

@@ -0,0 +1,174 @@
#+title: Emacs — Packages — Editing
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/editing.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Editing
First, Ill define some keybindings for easily inserting pairs when
editing text.
#+begin_src emacs-lisp
(general-define-key
:states 'visual
"M-[" #'insert-pair
"M-{" #'insert-pair
"M-<" #'insert-pair
"M-'" #'insert-pair
"M-`" #'insert-pair
"M-\"" #'insert-pair)
#+end_src
** Atomic Chrome
Why write in your browser when you could write with Emacs? Despite its
name, this package isnt only geared towards Chrome/Chromium-based
browsers but also towards Firefox since its 2.0 version. I find it a
bit unfortunate Chromes name stuck in the packages name though.
#+begin_src emacs-lisp
(use-package atomic-chrome
:straight (:build t)
:init
(atomic-chrome-start-server)
:config
(setq atomic-chrome-default-major-mode 'markdown-mode
atomic-chrome-url-major-mode-alist `(("github\\.com" . gfm-mode)
("gitlab\\.com" . gfm-mode)
("labs\\.phundrak\\.com" . markdown-mode)
("reddit\\.com" . markdown-mode))))
#+end_src
** Editorconfig
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
:straight (:build t)
:diminish editorconfig-mode
:init
(editorconfig-mode t))
#+end_src
** Evil Nerd Commenter
Emacs default commenting system is nice, but I dont find it smart
enough for me.
#+begin_src emacs-lisp
(use-package evil-nerd-commenter
:after evil
:straight (:build t))
#+end_src
** Iedit
Iedit is a powerful text editing tool that can be used to refactor
code through the edition of multiple regions at once, be it in a
region or in a whole buffer. Since Im using evil, Ill also use a
compatibility package that adds states for iedit.
#+begin_src emacs-lisp
(use-package evil-iedit-state
:defer t
:straight (:build t)
:commands (evil-iedit-state evil-iedit-state/iedit-mode)
:init
(setq iedit-curent-symbol-default t
iedit-only-at-symbol-boundaries t
iedit-toggle-key-default nil)
:general
(phundrak/leader-key
:infix "r"
:packages '(iedit evil-iedit-state)
"" '(:ignore t :which-key "refactor")
"i" #'evil-iedit-state/iedit-mode)
(general-define-key
:keymaps 'evil-iedit-state-map
"c" nil
"s" nil
"J" nil
"S" #'iedit-expand-down-a-line
"T" #'iedit-expand-up-a-line
"h" #'evil-iedit-state/evil-change
"k" #'evil-iedit-state/evil-substitute
"K" #'evil-iedit-state/substitute
"q" #'evil-iedit-state/quit-iedit-mode))
#+end_src
** Smartparens
#+begin_src emacs-lisp
(use-package smartparens
:straight (:build t)
:defer t)
#+end_src
** Parinfer
Dont let the name of the package fool you! ~parinfer-rust-mode~ is not
a ~parinfer~ mode for ~rust-mode~, but a mode for ~parinfer-rust~. ~parinfer~
was a project for handling parenthesis and other double markers in a
much more intuitive way when writing Lisp code. However, it is now out
of date (last commit was on January 2nd, 2019) and the repository has
since been archived. New implementations then appeared, one of them is
[[https://github.com/eraserhd/parinfer-rust][~parinfer-rust~]], obviously written in Rust, around which
~parinfer-rust-mode~ is built. Enabling ~parinfer-rust-mode~ should also
automatically disable ~smartparens-mode~ in order to avoid conflicting
behavior.
#+begin_src emacs-lisp
(use-package parinfer-rust-mode
:defer t
:straight (:build t)
:diminish parinfer-rust-mode
:hook emacs-lisp-mode common-lisp-mode scheme-mode
:init
(setq parinfer-rust-auto-download t
parinfer-rust-library-directory (concat user-emacs-directory
"parinfer-rust/"))
(add-hook 'parinfer-rust-mode-hook
(lambda () (smartparens-mode -1)))
:general
(phundrak/major-leader-key
:keymaps 'parinfer-rust-mode-map
"m" #'parinfer-rust-switch-mode
"M" #'parinfer-rust-toggle-disable))
#+end_src
** Smartparens
~smartparens~ is a package similar to ~parinfer~, but while the latter is
more specialized for Lisp dialects, ~smartparens~ works better with
other programming languages that still uses parenthesis, but not as
much as Lisp dialects; think for example C, C++, Rust, Javascript, and
so on.
#+begin_src emacs-lisp
(use-package smartparens
:defer t
:straight (smartparens :build t
:type git
:host github
:repo "Fuco1/smartparens")
:hook (prog-mode . smartparens-mode))
#+end_src
** ~string-edit~
~string-edit~ is a cool package that allows the user to write naturally
a string and get it automatically escaped for you. No more manually
escaping your strings!
#+begin_src emacs-lisp
(use-package string-edit-at-point
:defer t
:straight (:build t))
#+end_src
** Writeroom
On the other hand, ~writeroom~ allows the user to enter a
distraction-free mode of Emacs, and I like that! But the default width
is a bit too small for me, and I prefer not to go fullscren.
#+begin_src emacs-lisp
(use-package writeroom-mode
:defer t
:straight (:build t)
:init (global-writeroom-mode 1)
:config
(setq writeroom-width 100
writeroom-fullscreen-effect nil
writeroom-maximize-window nil
writeroom-mode-line t
writeroom-major-modes '(text-mode org-mode markdown-mode nov-mode Info-mode)))
#+end_src

View File

@@ -0,0 +1,496 @@
#+title: Emacs — Packages — Emacs Built-ins
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/emacs-builtin.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Emacs built-ins
** Dired
Dired is Emacs built-in file manager. Its really great, and replaces
any graphical file manager for me most of the time because:
- I am not limited to /x/ tabs or panes
- All actions can be done with keybindings
- I get a consistent behavior between Dired and Emacs, since its the
same thing.
I used to have an extensive configuration for Dired with a couple of
additional packages to make it more usable. Dirvish rendered that
obsolete!
#+begin_src emacs-lisp
(use-package dirvish
:straight (:build t)
:defer t
:init (dirvish-override-dired-mode)
:custom
(dirvish-quick-access-entries
'(("h" "~/" "Home")
("d" "~/Downloads/" "Downloads")
("c" "~/org/config" "Config")
("C" "~/Documents/conlanging/content" "Conlanging")))
(dirvish-mode-line-format
'(:left (sort file-time "" file-size symlink) :right (omit yank index)))
(dirvish-attributes '(all-the-icons file-size collapse subtree-state vc-state git-msg))
:config
(dirvish-peek-mode)
<<dired-drag-and-drop>>
<<dired-listing-flags>>
<<dired-files-and-dirs>>
<<dirvish-exa-offload>>
(setq dired-dwim-target t
dired-recursive-copies 'always
dired-recursive-deletes 'top
delete-by-moving-to-trash t
dirvish-preview-dispatchers (cl-substitute 'pdf-preface 'pdf dirvish-preview-dispatchers))
:general
(phundrak/evil
:keymaps 'dirvish-mode-map
:packages '(dired dirvish)
"q" #'dirvish-quit
"TAB" #'dirvish-subtree-toggle)
(phundrak/major-leader-key
:keymaps 'dirvish-mode-map
:packages '(dired dirvish)
"A" #'gnus-dired-attach
"a" #'dirvish-quick-access
"d" #'dirvish-dispatch
"e" #'dirvish-emerge-menu
"f" #'dirvish-fd-jump
"F" #'dirvish-file-info-menu
"h" '(:ignore t :which-key "history")
"hp" #'dirvish-history-go-backward
"hn" #'dirvish-history-go-forward
"hj" #'dirvish-history-jump
"hl" #'dirvish-history-last
"l" '(:ignore t :which-key "layout")
"ls" #'dirvish-layout-switch
"lt" #'dirvish-layout-toggle
"m" #'dirvish-mark-menu
"s" #'dirvish-quicksort
"S" #'dirvish-setup-menu
"y" #'dirvish-yank-menu
"n" #'dirvish-narrow))
#+end_src
It requires some programs which can be installed like so:
#+begin_src sh :dir /sudo::~/ :exports code :tangle no :results verbatim
pacman -S --needed --noprogressbar --noconfirm --color=never \
fd poppler ffmpegthumbnailer mediainfo imagemagick tar unzip
#+end_src
Since Emacs 29, it is possible to enable drag-and-drop between Emacs
and other applications.
#+name: dired-drag-and-drop
#+begin_src emacs-lisp :tangle no
(csetq dired-mouse-drag-files t
mouse-drag-and-drop-region-cross-program t)
#+end_src
In Dirvish, its best to use the long name of flags whenever possible,
otherwise some commands wont work.
#+name: dired-listing-flags
#+begin_src emacs-lisp :tangle no
(csetq dired-listing-switches (string-join '("--all"
"--human-readable"
"--time-style=long-iso"
"--group-directories-first"
"-lv1")
" "))
#+end_src
However, it is possible to instead use ~exa~ when it is available.
Instead of making Emacs main thread to the file listing in a
directory, we offload it to an external thread.
#+name: dirvish-exa-offload
#+begin_src emacs-lisp :tangle no
(dirvish-define-preview exa (file)
"Use `exa' to generate directory preview."
:require ("exa")
(when (file-directory-p file)
`(shell . ("exa" "--color=always" "-al" ,file))))
(add-to-list 'dirvish-preview-dispatchers 'exa)
#+end_src
Finally, some directories need to be set for Dired to store various
files and images.
#+name: dired-files-and-dirs
#+begin_src emacs-lisp :tangle no
(let ((my/file (lambda (path &optional dir)
(expand-file-name path (or dir user-emacs-directory))))
(my/dir (lambda (path &optional dir)
(expand-file-name (file-name-as-directory path)
(or dir user-emacs-directory)))))
(csetq image-dired-thumb-size 150
image-dired-dir (funcall my/dir "dired-img")
image-dired-db-file (funcall my/file "dired-db.el")
image-dired-gallery-dir (funcall my/dir "gallery")
image-dired-temp-image-file (funcall my/file "temp-image" image-dired-dir)
image-dired-temp-rotate-image-file (funcall my/file "temp-rotate-image" image-dired-dir)))
#+end_src
Copying files with Dired is a blocking process. Its usually fine when
theres not a lot to copy, but it becomes annoying when moving larger
files. The package ~dired-rsync~ allows copying files with ~rsync~ in the
background; we can then carry on with our tasks while the copy is
happening.
#+begin_src emacs-lisp
(use-package dired-rsync
:if (executable-find "rsync")
:defer t
:straight (:build t)
:general
(phundrak/evil
:keymaps 'dired-mode-map
:packages 'dired-rsync
"C-r" #'dired-rsync))
#+end_src
** Compilation mode
After reading about a blog article, I found out it is possible to run
quite a few things through ~compilation-mode~, so why not? First, lets
redefine some keybinds for this mode. Ill also define a general
keybind in order to re-run my programs from other buffers than the
~compilation-mode~ buffer. I also want to follow the output of the
compilation buffer, as well as enable some syntax highlighting.
#+begin_src emacs-lisp
(use-package compile
:defer t
:straight (compile :type built-in)
:hook (compilation-filter . colorize-compilation-buffer)
:init
(require 'ansi-color)
(defun colorize-compilation-buffer ()
(let ((inhibit-read-only t))
(ansi-color-apply-on-region (point-min) (point-max))))
:general
(phundrak/evil
:keymaps 'compilation-mode-map
"g" nil
"r" nil
"R" #'recompile
"h" nil)
(phundrak/leader-key
"R" #'recompile)
:config
(setq compilation-scroll-output t))
#+end_src
** Eshell
[[file:../img/emacs-eshell.svg]]
Eshell is a built-in shell available from Emacs which I use almost as
often as fish. Some adjustments are necessary to make it fit my taste
though.
#+begin_src emacs-lisp
(use-package eshell
:defer t
:straight (:type built-in :build t)
:config
(setq eshell-prompt-function
(lambda ()
(concat (abbreviate-file-name (eshell/pwd))
(if (= (user-uid) 0) " # " " λ ")))
eshell-prompt-regexp "^[^#λ\n]* [#λ] ")
<<eshell-alias-file>>
<<eshell-concat-shell-command>>
<<eshell-alias-open>>
<<eshell-alias-clear>>
<<eshell-alias-buffers>>
<<eshell-alias-emacs>>
<<eshell-alias-mkcd>>
:general
(phundrak/evil
:keymaps 'eshell-mode-map
[remap evil-collection-eshell-evil-change] #'evil-backward-char
"c" #'evil-backward-char
"t" #'evil-next-visual-line
"s" #'evil-previous-visual-line
"r" #'evil-forward-char
"h" #'evil-collection-eshell-evil-change)
(general-define-key
:keymaps 'eshell-mode-map
:states 'insert
"C-a" #'eshell-bol
"C-e" #'end-of-line))
#+end_src
*** Aliases
First, lets declare our list of “dumb” aliases well use in
Eshell. You can find them here.
#+name: eshell-alias-file
#+begin_src emacs-lisp :tangle no
(setq eshell-aliases-file (expand-file-name "eshell-alias" user-emacs-directory))
#+end_src
A couple of other aliases will be defined through custom Elisp
functions, but first Ill need a function for concatenating a shell
command into a single string:
#+name: eshell-concat-shell-command
#+begin_src emacs-lisp :tangle no
(defun phundrak/concatenate-shell-command (&rest command)
"Concatenate an eshell COMMAND into a single string.
All elements of COMMAND will be joined in a single
space-separated string."
(mapconcat #'identity command " "))
#+end_src
Ill also declare some aliases here, such as ~open~ and ~openo~ that
respectively allow me to open a file in Emacs, and same but in another
window.
#+name: eshell-alias-open
#+begin_src emacs-lisp :tangle no
(defalias 'open #'find-file)
(defalias 'openo #'find-file-other-window)
#+end_src
The default behavior of ~eshell/clear~ is not great at all, although it
clears the screen it also scrolls all the way down. Therefore, lets
alias it to ~eshell/clear-scrollback~ which has the correct behavior.
#+name: eshell-alias-clear
#+begin_src emacs-lisp :tangle no
(defalias 'eshell/clear #'eshell/clear-scrollback)
#+end_src
As you see, these were not declared in my dedicated aliases file but
rather were declared programmatically. This is because I like to keep
my aliases file for stuff that could work too with other shells were
the syntax a bit different, and aliases related to Elisp are kept
programmatically. Ill also declare ~list-buffers~ an alias of ~ibuffer~
because naming it that way kind of makes more sense to me.
#+name: eshell-alias-buffers
#+begin_src emacs-lisp :tangle no
(defalias 'list-buffers 'ibuffer)
#+end_src
I still have some stupid muscle memory telling me to open ~emacs~, ~vim~
or ~nano~ in Eshell, which is stupid: Im already inside Emacs and I
have all its power available instantly. So, lets open each file
passed to these commands.
#+name: eshell-alias-emacs
#+begin_src emacs-lisp :tangle no
(defun eshell/emacs (&rest file)
"Open each FILE and kill eshell.
Old habits die hard."
(when file
(dolist (f (reverse file))
(find-file f t))))
#+end_src
Finally, Ill declare ~mkcd~ which allows the simultaneous creation of a
directory and moving into this newly created directory. And of course,
it will also work if the directory also exists or if parent
directories dont, similarly to the ~-p~ option passed to ~mkdir~.
#+name: eshell-alias-mkcd
#+begin_src emacs-lisp :tangle no
(defun eshell/mkcd (dir)
"Create the directory DIR and move there.
If the directory DIR doesnt exist, create it and its parents
if needed, then move there."
(mkdir dir t)
(cd dir))
#+end_src
*** Commands
When Im in Eshell, sometimes I wish to open multiple files at once in
Emacs. For this, when I have several arguments for ~find-file~, I want
to be able to open them all at once. Lets modify ~find-file~ like so:
#+BEGIN_SRC emacs-lisp
(defadvice find-file (around find-files activate)
"Also find all files within a list of files. This even works recursively."
(if (listp filename)
(cl-loop for f in filename do (find-file f wildcards))
ad-do-it))
#+END_SRC
I also want to be able to have multiple instances of Eshell opened at
once. For that, I declared the function ~eshell-new~ that does exactly
that.
#+begin_src emacs-lisp
(defun eshell-new ()
"Open a new instance of eshell."
(interactive)
(eshell 'N))
#+end_src
A very useful command I often use in fish is ~z~, a port from bashs and
zshs command that allows to jump around directories based on how
often we go in various directories.
#+begin_src emacs-lisp
(use-package eshell-z
:defer t
:after eshell
:straight (:build t)
:hook (eshell-mode . (lambda () (require 'eshell-z))))
#+end_src
*** Environment Variables
Some environment variables need to be correctly set so Eshell can
correctly work. I would like to set two environment variables related
to Dart development: the ~DART_SDK~ and ~ANDROID_HOME~ variables.
#+BEGIN_SRC emacs-lisp
(setenv "DART_SDK" "/opt/dart-sdk/bin")
(setenv "ANDROID_HOME" (concat (getenv "HOME") "/Android/Sdk/"))
#+END_SRC
The ~EDITOR~ variable also needs to be set for git commands, especially the
~yadm~ commands.
#+BEGIN_SRC emacs-lisp
(setenv "EDITOR" "emacsclient -c -a emacs")
#+END_SRC
Finally, for some specific situations I need ~SHELL~ to be set to
something more standard than fish:
#+begin_src emacs-lisp
(setenv "SHELL" "/bin/sh")
#+end_src
*** Visual configuration
I like to have at quick glance some information about my machine when
I fire up a terminal. I havent found anything that does that the way
I like it, so [[https://github.com/Phundrak/eshell-info-banner.el][Ive written a package]]! Its actually available on
MELPA, but since Im the main dev of this package, Ill keep track of
the git repository.
#+begin_src emacs-lisp
(use-package eshell-info-banner
:after (eshell)
:defer t
:straight (eshell-info-banner :build t
:type git
:host github
:protocol ssh
:repo "phundrak/eshell-info-banner.el")
:hook (eshell-banner-load . eshell-info-banner-update-banner)
:custom-face
(eshell-info-banner-normal-face ((t :foreground "#A3BE8C")))
(eshell-info-banner-background-face ((t :foreground "#E5E9F0")))
(eshell-info-banner-warning-face ((t :foreround "#D08770")))
(eshell-info-banner-critical-face ((t :foreground "#BF616A")))
:custom
(eshell-info-banner-partition-prefixes (list "/dev" "zroot" "tank")))
#+end_src
Another feature I like is fish-like syntax highlight, which brings
some more colors to Eshell.
#+begin_src emacs-lisp
(use-package eshell-syntax-highlighting
:after (esh-mode eshell)
:defer t
:straight (:build t)
:config
(eshell-syntax-highlighting-global-mode +1))
#+end_src
Powerline prompts are nice, git-aware prompts are even better!
~eshell-git-prompt~ is nice, but I prefer to write my own package for
that.
#+begin_src emacs-lisp
(use-package powerline-eshell
:if (string= (string-trim (shell-command-to-string "uname -n")) "leon")
:load-path "~/fromGIT/emacs-packages/powerline-eshell.el/"
:after eshell)
#+end_src
** Eww
Since Emacs 29, it is possible to automatically rename ~eww~ buffers to
a more human-readable name, see [[https://protesilaos.com/codelog/2021-10-15-emacs-29-eww-rename-buffers/][Prots blog]] post on the matter.
#+begin_src emacs-lisp
(use-package eww
:defer t
:straight (:type built-in)
:config
(setq eww-auto-rename-buffer 'title))
#+end_src
** Image-mode
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
** Info
Lets define some more intuitive keybinds for ~info-mode~.
#+begin_src emacs-lisp
(use-package info
:defer t
:straight (info :type built-in :build t)
:general
(phundrak/evil
:keymaps 'Info-mode-map
"c" #'Info-prev
"t" #'evil-scroll-down
"s" #'evil-scroll-up
"r" #'Info-next)
(phundrak/major-leader-key
:keymaps 'Info-mode-map
"?" #'Info-toc
"b" #'Info-history-back
"f" #'Info-history-forward
"m" #'Info-menu
"t" #'Info-top-node
"u" #'Info-up))
#+end_src
** Tab Bar
#+begin_src emacs-lisp
(use-package tab-bar
:defer t
:straight (:type built-in)
:custom
(tab-bar-close-button-show nil)
(tab-bar-new-button-show nil)
(tab-bar-new-tab-choice "*dashboard*")
:custom-face
(tab-bar ((t (:background "#272C36"
:foreground "#272C36"
:box (:line-width (8 . 5) :style flat-button)))))
:init
(advice-add #'tab-new
:after
(lambda (&rest _) (when (y-or-n-p "Rename tab? ")
(call-interactively #'tab-rename)))))
#+end_src
** Tramp
Tramp is an Emacs built-in package that allows the user to connect to
various hosts using various protocols, such as ~ssh~ and
~rsync~. However, I have some use-case for Tramp which are not
supported natively. I will describe them here.
#+begin_src emacs-lisp
(use-package tramp
:straight (tramp :type built-in :build t)
:config
<<tramp-add-yadm>>
(csetq tramp-ssh-controlmaster-options nil
tramp-verbose 0
tramp-auto-save-directory (locate-user-emacs-file "tramp/")
tramp-chunksize 2000)
(add-to-list 'backup-directory-alist ; deactivate auto-save with TRAMP
(cons tramp-file-name-regexp nil)))
#+end_src
*** Yadm
[[https://yadm.io/][~yadm~]] is a git wrapper made to easily manage your dotfiles. It has
loads of features I dont use (the main one I like but dont use is
its [[https://yadm.io/docs/templates][Jinja-like host and OS-aware syntax]]), but unfortunately Magit
doesnt play nice with it. Tramp to the rescue, and this page explains
how! Lets just insert in my config this code snippet:
#+name: tramp-add-yadm
#+begin_src emacs-lisp :tangle no
(add-to-list 'tramp-methods
'("yadm"
(tramp-login-program "yadm")
(tramp-login-args (("enter")))
(tramp-login-env (("SHELL") ("/bin/sh")))
(tramp-remote-shell "/bin/sh")
(tramp-remote-shell-args ("-c"))))
#+end_src
Ill also create a fuction for connecting to this new Tramp protocol:
#+begin_src emacs-lisp
(defun my/yadm ()
"Manage my dotfiles through TRAMP."
(interactive)
(magit-status "/yadm::"))
#+end_src

View File

@@ -0,0 +1,401 @@
#+title: Emacs — Packages — EXWM
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/exwm.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* EXWM
So, Im finally slowly getting back to EXWM. I tried it a couple of
years ago, but that was with the SpacemacsOS layer on Spacemacs, on a
laptop which got accidentaly formatted before I could save my config
and all… So it got me some time to come back. Im still a bit worried
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.
#+begin_src emacs-lisp
(use-package xelb
:if (seq-contains-p command-line-args "--with-exwm")
:straight (xelb :build t
:type git
:host github
:repo "emacs-straight/xelb"
:fork "ch11ng/xelb"))
#+end_src
Next is a function Ive +stolen+ copied from Daviwils [[https://config.daviwil.com/desktop][desktop
configuration]]. This allows to launch software in the background
easily.
#+begin_src emacs-lisp
(defun exwm/run-in-background (command &optional once)
(let ((command-parts (split-string command " +")))
(apply #'call-process `(,(car command-parts) nil 0 nil ,@(cdr command-parts)))))
#+end_src
In order to launch Emacs with EXWM with ~startx~, I need a ~xinit~ file.
This one is exported to ~$HOME/.xinitrc.emacs~.
#+begin_src sh :tangle ~/.xinitrc.emacs :shebang "#!/bin/sh"
xhost +SI:localuser:$USER
# Set fallback cursor
xsetroot -cursor_name left_ptr
# If Emacs is started in server mode, `emacsclient` is a convenient
# way to edit files in place (used by e.g. `git commit`)
export VISUAL=emacsclient
export EDITOR="$VISUAL"
# in case Java applications display /nothing/
# wmname LG3D
# export _JAVA_AWT_WM_NONREPARENTING=1
autorandr -l home
exec emacs --with-exwm
#+end_src
** EXWM itself
Now we come to the plat de résistance. Like with ~xelb~, Im using its
Git source to install it to make sure I get the right version --- the
version available on the GNU ELPA is from the same source, true, but I
dont know at which rate it is updated. And more packages down the
line will depend on this Git repository, so I might as well just clone
it right now.
As you can see, I added in the ~:config~ secion to two hooks functions
that rename buffers accurately. While the average X window will simply
get the name of the current X window, I want Firefox and Qutebrowser
to be prefixed with the name of the browser. Actually, all these will
be renamed this way:
#+name: exwm-renamed-buffers-list
- Kitty
- Qutebrowser
#+name: exwm-gen-buffers-rename
#+header: :exports none :tangle no
#+begin_src emacs-lisp :var buffers=exwm-renamed-buffers-list :cache yes
(format "%s\n%S"
(mapconcat (lambda (buffer)
(let ((buffer-name (if (stringp buffer)
buffer
(car buffer))))
(format "(\"%s\" %S)"
(downcase buffer-name)
`(exwm-workspace-rename-buffer
(concat ,(concat "EXWM: " buffer-name " - ")
exwm-title)))))
buffers
"\n")
'(_otherwise (exwm-workspace-rename-buffer exwm-title)))
#+end_src
#+RESULTS[64fdbf1e8957b82aad801ec57f2155a0a8f5be54]: exwm-gen-buffers-rename
: ("kitty" (exwm-workspace-rename-buffer (concat "EXWM: Kitty - " exwm-title)))
: ("qutebrowser" (exwm-workspace-rename-buffer (concat "EXWM: Qutebrowser - " exwm-title)))
: (_otherwise (exwm-workspace-rename-buffer exwm-title))
#+name: exwm-buffers-name
#+begin_src emacs-lisp :tangle no
(add-hook 'exwm-update-class-hook
(lambda () (exwm-workspace-rename-buffer exwm-class-name)))
(add-hook 'exwm-update-title-hook
(lambda ()
(pcase exwm-class-name
<<exwm-gen-buffers-rename()>>)))
#+end_src
As you can see below, in the ~:config~ section I added two advices and
one hook in order to correctly integrate evil with EXWM. When Im in
an X window, I want to be in insert-mode in order to type however I
want. However, when I exit one, I want to default back to normal-mode.
#+name: exwm-advices-evil
#+begin_src emacs-lisp :tangle no
(add-hook 'exwm-manage-finish-hook (lambda () (call-interactively #'exwm-input-release-keyboard)))
(advice-add #'exwm-input-grab-keyboard :after (lambda (&optional id) (evil-normal-state)))
(advice-add #'exwm-input-release-keyboard :after (lambda (&optional id) (evil-insert-state)))
#+end_src
Secondly, I add ~i~, ~C-SPC~, and ~M-m~ as exwm prefix keys so they arent
sent directly to the X windows but caught by Emacs (and EXWM). Ill
use the ~i~ key in normal-mode to enter ~insert-mode~ and have Emacs
release the keyboard so the X window can grab it. Initially, I had
~s-<escape>~ as a keybind for grabbing back the keyboard from an X
window, as if I were in insert mode and wanted to go back to normal
mode, and I had ~s-I~ to toggle keyboard grabbing. But I found myself
more than once trying to use ~s-<escape>~ to toggle this state, ~s-I~
completely forgotten. So I removed ~s-I~ and made ~s-<escape>~ behave like
~s-I~ once did.
#+name: exwm-prefix-keys
#+begin_src emacs-lisp :tangle no
(general-define-key
:keymaps 'exwm-mode-map
:states 'normal
"i" #'exwm-input-release-keyboard)
(exwm-input-set-key (kbd "s-<escape>") #'exwm-input-toggle-keyboard)
(push ?\i exwm-input-prefix-keys)
(push (kbd "C-SPC") exwm-input-prefix-keys)
(push (kbd "M-m") exwm-input-prefix-keys)
#+end_src
As stated a couple of times in my different configuration files, Im
using the bépo layout, which means the default keys in the number row
are laid as follows:
#+name: exwm-bepo-number-row
#+begin_src emacs-lisp :tangle no
(defconst exwm-workspace-keys '("\"" "«" "»" "(" ")" "@" "+" "-" "/" "*"))
#+end_src
With this, we can create keybinds for going or sending X windows to
workspaces 0 to 9.
#+name: exwm-workspace-keybinds
#+begin_src emacs-lisp :tangle no
(setq exwm-input-global-keys
`(,@exwm-input-global-keys
,@(mapcar (lambda (i)
`(,(kbd (format "s-%s" (nth i exwm-workspace-keys))) .
(lambda ()
(interactive)
(exwm-workspace-switch-create ,i))))
(number-sequence 0 9))
,@(mapcar (lambda (i)
`(,(kbd (format "s-%d" i)) .
(lambda ()
(interactive)
(exwm-workspace-move-window ,(let ((index (1- i)))
(if (< index 0)
(- 10 index)
;; FIXME: does not work with s-0
index))))))
(number-sequence 0 9))))
#+end_src
You can then see the list of the keybinds I have set for EXWM, which
are all prefixed with ~SPC x~ in normal mode (and ~C-SPC x~ in insert
mode), except for ~s-RET~ which opens an eshell terminal.
#+name: exwm-keybinds
#+begin_src emacs-lisp :tangle no
(exwm-input-set-key (kbd "s-<return>") (lambda ()
(interactive)
(eshell)))
(phundrak/leader-key
:infix "x"
"" '(:ignore t :which-key "EXWM")
"d" #'exwm-debug
"k" #'exwm-input-send-next-key
"l" '((lambda ()
(interactive)
(start-process "" nil "plock"))
:which-key "lock")
"r" '(:ignore t :wk "rofi")
"rr" '((lambda () (interactive)
(shell-command "rofi -show drun" (current-buffer) (current-buffer)))
:wk "drun")
"rw" '((lambda () (interactive)
(shell-command "rofi -show window" (current-buffer) (current-buffer)))
:wk "windows")
"R" '(:ignore t :wk "restart")
"Rr" #'exwm-reset
"RR" #'exwm-restart
"t" '(:ignore t :which-key "toggle")
"tf" #'exwm-layout-toggle-fullscreen
"tF" #'exwm-floating-toggle-floating
"tm" #'exwm-layout-toggle-mode-line
"w" '(:ignore t :which-key "workspaces")
"wa" #'exwm-workspace-add
"wd" #'exwm-workspace-delete
"ws" #'exwm-workspace-switch
"x" '((lambda ()
(interactive)
(let ((command (string-trim (read-shell-command "RUN: "))))
(start-process command nil command)))
:which-key "run")
"RET" #'eshell-new)
#+end_src
A couple of commands are also automatically executed through my
~autostart~ script written [[file:bin.org::#Autostart-a99e99e7][here]].
#+name: exwm-autostart
#+begin_src emacs-lisp :tangle no
(exwm/run-in-background "autostart")
#+end_src
Finally, lets only initialize and start EXWM once functions from
exwm-randr ran, because otherwise having multiple monitors dont work.
#+name: exwm-init
#+begin_src emacs-lisp :tangle no
(with-eval-after-load 'exwm-randr
(exwm-init))
#+end_src
The complete configuration for the ~exwm~ package can be found below.
#+begin_src emacs-lisp :noweb yes
(use-package exwm
:if (seq-contains-p command-line-args "--with-exwm")
:straight (exwm :build t
:type git
:host github
:repo "ch11ng/exwm")
:custom
(use-dialog-box nil "Disable dialog boxes since they are unusable in EXWM")
(exwm-input-line-mode-passthrough t "Pass all keypresses to emacs in line mode.")
:init
(require 'exwm-config)
(setq exwm-workspace-number 6)
:config
(set-frame-parameter (selected-frame) 'alpha-background 0.7)
<<exwm-randr>>
<<exwm-buffers-name>>
<<exwm-advices-evil>>
<<exwm-prefix-keys>>
<<exwm-bepo-number-row>>
<<exwm-workspace-keybinds>>
<<exwm-keybinds>>
<<exwm-autostart>>
<<exwm-init>>)
#+end_src
** EXWM-Evil integration
#+begin_src emacs-lisp
(use-package evil-exwm-state
:if (seq-contains-p command-line-args "--with-exwm")
:defer t
:after exwm
:straight (evil-exwm-state :build t
:type git
:host github
:repo "domenzain/evil-exwm-state"))
#+end_src
** Multimonitor support
#+name: exwm-randr
#+begin_src emacs-lisp :tangle no
(require 'exwm-randr)
(exwm/run-in-background "xwallpaper --zoom \"${cat $HOME/.cache/wallpaper}\"")
(start-process-shell-command
"xrandr" nil "xrandr --output eDP1 --mode 1920x1080 --pos 2560x0 --rotate normal --output HDMI1 --primary --mode 2560x1080 --pos 0x0 --rotate normal --output VIRTUAL1 --off --output DP-1-0 --off --output DP-1-1 --off")
(exwm-randr-enable)
(setq exwm-randr-workspace-monitor-plist '(3 "eDP1"))
#+end_src
** Keybinds for a desktop environment
#+begin_src emacs-lisp
(use-package desktop-environment
:defer t
:straight (desktop-environment :build t
:type git
:host github
:repo "DamienCassou/desktop-environment")
:after exwm
:diminish t
:config
(add-hook 'exwm-init-hook #'desktop-environment-mode)
(setq desktop-environment-update-exwm-global-keys :prefix
exwm-layout-show-al-buffers t)
(setq desktop-environment-bluetooth-command "bluetoothctl"
desktop-environment-brightness-get-command "xbacklight -get"
desktop-environment-brightness-get-regexp (rx line-start (group (+ digit)))
desktop-environment-brightness-set-command "xbacklight %s"
desktop-environment-brightness-normal-increment "-inc 5"
desktop-environment-brightness-normal-decrement "-dec 5"
desktop-environment-brightness-small-increment "-inc 2"
desktop-environment-brightness-small-decrement "-dec 2"
desktop-environment-volume-normal-decrement "-d 5"
desktop-environment-volume-normal-increment "-i 5"
desktop-environment-volume-small-decrement "-d 2"
desktop-environment-volume-small-increment "-i 2"
desktop-environment-volume-set-command "pamixer -u %s"
desktop-environment-screenshot-directory "~/Pictures/Screenshots"
desktop-environment-screenlock-command "plock"
desktop-environment-music-toggle-command "mpc toggle"
desktop-environment-music-previous-command "mpc prev"
desktop-environment-music-next-command "mpc next"
desktop-environment-music-stop-command "mpc stop")
(general-define-key
"<XF86AudioPause>" (lambda () (interactive)
(with-temp-buffer
(shell-command "mpc pause" (current-buffer) (current-buffer)))))
(desktop-environment-mode))
#+end_src
** Bluetooth
#+begin_src emacs-lisp
(defvar bluetooth-command "bluetoothctl")
#+end_src
#+begin_src emacs-lisp
(defun bluetooth-turn-on ()
(interactive)
(let ((process-connection-type nil))
(start-process "" nil bluetooth-command "power" "on")))
#+end_src
#+begin_src emacs-lisp
(defun bluetooth-turn-off ()
(interactive)
(let ((process-connection-type nil))
(start-process "" nil bluetooth-command "power" "off")))
#+end_src
#+begin_src emacs-lisp
(defun create-bluetooth-device (raw-name)
"Create a bluetooth device cons from RAW NAME.
The cons will hold first the MAC address of the device, then its
human-friendly name."
(let ((split-name (split-string raw-name " " t)))
`(,(mapconcat #'identity (cddr split-name) " ") . ,(cadr split-name))))
#+end_src
#+begin_src emacs-lisp
(require 'dbus)
(defun bluetooth-get-devices ()
(let ((bus-list (dbus-introspect-get-node-names :system "org.bluez" "/org/bluez/hci0")))
(mapcar (lambda (device)
`(,(dbus-get-property :system
"org.bluez"
(concat "/org/bluez/hci0/" device)
"org.bluez.Device1"
"Alias")
. ,device))
bus-list)))
#+end_src
#+begin_src emacs-lisp
(defun bluetooth-connect-device ()
(interactive)
(progn
(bluetooth-turn-on)
(let* ((devices (bluetooth-get-devices))
(device (alist-get (completing-read "Device: " devices)
devices nil nil #'string=)))
(dbus-call-method-asynchronously
:system "org.bluez"
(concat "/org/bluez/hci0" device)
"org.bluez.Device1"
"Connect"
(lambda (&optional msg)
(when msg (message "%s" msg)))))))
#+end_src

View File

@@ -0,0 +1,59 @@
#+title: Emacs — Packages — Making My Life Easier
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/helpful.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Making my life easier
** Bufler
Bufler is a package that organises and lists buffers in a much better
way than how they are usually sorted. You can easily and quickly find
buffers by their group, not only by their name, and THIS is great
news! Also, no ~helm~ please! And for some reasons the keybindings are
borked by default, so lets redefine them, and lets also rebind ~SPC~
to ~p~ since it would conflict with my main ~general~ prefix.
#+begin_src emacs-lisp
(use-package bufler
:straight (bufler :build t
:files (:defaults (:exclude "helm-bufler.el")))
:defer t
:general
(phundrak/evil
:keymaps 'bufler-list-mode-map
:packages 'bufler
"?" #'hydra:bufler/body
"g" #'bufler
"f" #'bufler-list-group-frame
"F" #'bufler-list-group-make-frame
"N" #'bufler-list-buffer-name-workspace
"k" #'bufler-list-buffer-kill
"p" #'bufler-list-buffer-peek
"s" #'bufler-list-buffer-save
"RET" #'bufler-list-buffer-switch))
#+end_src
** Helpful
As the name tells, ~helpful~ is a really helpful package which greatly
enhances a couple of built-in functions from Emacs, namely:
| Vanilla Emacs Function | Helpful Function | Comment |
|------------------------+------------------+-----------------------------------------------|
| ~describe-function~ | ~helpful-callable~ | Only interactive functions |
| ~describe-function~ | ~helpful-function~ | Only actual functions (including interactive) |
| ~describe-function~ | ~helpful-macro~ | |
| ~describe-command~ | ~helpful-command~ | |
| ~describe-key~ | ~helpful-key~ | |
| ~describe-variable~ | ~helpful-variable~ | |
#+begin_src emacs-lisp
(use-package helpful
:straight (:build t)
:after (counsel ivy)
:custom
(counsel-describe-function-function #'helpful-callable)
(counsel-describe-variable-function #'helpful-variable)
:bind
([remap describe-function] . counsel-describe-function)
([remap describe-command] . helpful-command)
([remap describe-variable] . counsel-describe-variable)
([remap describe-key] . helpful-key))
#+end_src

View File

@@ -0,0 +1,207 @@
#+title: Emacs — Packages — LaTeX
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/latex.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* LaTeX
#+begin_src emacs-lisp :noweb yes
(use-package auctex
:defer t
:straight (:build t)
:hook (tex-mode . lsp-deferred)
:hook (latex-mode . lsp-deferred)
:init
(setq TeX-command-default (if (executable-find "latexmk") "LatexMk" "LaTeX")
TeX-engine (if (executable-find "xetex") 'xetex 'default)
TeX-auto-save t
TeX-parse-self t
TeX-syntactic-comment t
TeX-auto-local ".auctex-auto"
TeX-style-local ".auctex-style"
TeX-source-correlate-mode t
TeX-source-correlate-method 'synctex
TeX-source-correlate-start-server nil
TeX-electric-sub-and-superscript t
TeX-fill-break-at-separators nil
TeX-save-query t)
:config
<<latex-fontification>>
(setq TeX-master t)
(setcar (cdr (assoc "Check" TeX-command-list)) "chktex -v6 -H %s")
(add-hook 'TeX-mode-hook (lambda ()
(setq ispell-parser 'tex
fill-nobreak-predicate (cons #'texmathp fill-nobreak-predicate))))
(add-hook 'TeX-mode-hook #'visual-line-mode)
(add-hook 'TeX-update-style-hook #'rainbow-delimiters-mode)
:general
(phundrak/major-leader-key
:packages 'lsp-mode
:keymaps '(latex-mode-map LaTeX-mode-map)
"l" '(:keymap lsp-command-map :which-key "lsp"))
(phundrak/major-leader-key
:packages 'auctex
:keymaps '(latex-mode-map LaTeX-mode-map)
"v" '(TeX-view :which-key "View")
"c" '(TeX-command-run-all :which-key "Compile")
"m" '(TeX-command-master :which-key "Run a command")))
#+end_src
From Doom Emacs configuration:
#+name: latex-fontification
#+begin_src emacs-lisp :tangle no
(setq font-latex-match-reference-keywords
'(;; BibLaTeX.
("printbibliography" "[{") ("addbibresource" "[{")
;; Standard commands.
("cite" "[{") ("citep" "[{")
("citet" "[{") ("Cite" "[{")
("parencite" "[{") ("Parencite" "[{")
("footcite" "[{") ("footcitetext" "[{")
;; Style-specific commands.
("textcite" "[{") ("Textcite" "[{")
("smartcite" "[{") ("Smartcite" "[{")
("cite*" "[{") ("parencite*" "[{")
("supercite" "[{")
;; Qualified citation lists.
("cites" "[{") ("Cites" "[{")
("parencites" "[{") ("Parencites" "[{")
("footcites" "[{") ("footcitetexts" "[{")
("smartcites" "[{") ("Smartcites" "[{")
("textcites" "[{") ("Textcites" "[{")
("supercites" "[{")
;; Style-independent commands.
("autocite" "[{") ("Autocite" "[{")
("autocite*" "[{") ("Autocite*" "[{")
("autocites" "[{") ("Autocites" "[{")
;; Text commands.
("citeauthor" "[{") ("Citeauthor" "[{")
("citetitle" "[{") ("citetitle*" "[{")
("citeyear" "[{") ("citedate" "[{")
("citeurl" "[{")
;; Special commands.
("fullcite" "[{")
;; Cleveref.
("cref" "{") ("Cref" "{")
("cpageref" "{") ("Cpageref" "{")
("cpagerefrange" "{") ("Cpagerefrange" "{")
("crefrange" "{") ("Crefrange" "{")
("labelcref" "{")))
(setq font-latex-match-textual-keywords
'(;; BibLaTeX brackets.
("parentext" "{") ("brackettext" "{")
("hybridblockquote" "[{")
;; Auxiliary commands.
("textelp" "{") ("textelp*" "{")
("textins" "{") ("textins*" "{")
;; Subcaption.
("subcaption" "[{")))
(setq font-latex-match-variable-keywords
'(;; Amsmath.
("numberwithin" "{")
;; Enumitem.
("setlist" "[{") ("setlist*" "[{")
("newlist" "{") ("renewlist" "{")
("setlistdepth" "{") ("restartlist" "{")
("crefname" "{")))
#+end_src
#+begin_src emacs-lisp
(use-package tex-mode
:defer t
:straight (:type built-in)
:config
(setq LaTeX-section-hook '(LaTeX-section-heading
LaTeX-section-title
LaTeX-section-toc
LaTeX-section-section
LaTeX-section-label)
LaTeX-fill-break-at-separators nil
LaTeX-item-indent 0))
#+end_src
#+begin_src emacs-lisp
(use-package preview
:defer t
:straight (:type built-in)
:config
(add-hook 'LaTeX-mode-hook #'LaTeX-preview-setup)
(setq-default preview-scale 1.4
preview-scale-function
(lambda () (* (/ 10.0 (preview-document-pt)) preview-scale)))
(setq preview-auto-cache-preamble nil)
(phundrak/major-leader-key
:packages 'auctex
:keymaps '(latex-mode-map LaTeX-mode-map)
"p" #'preview-at-point
"P" #'preview-clearout-at-point))
#+end_src
#+begin_src emacs-lisp
(use-package cdlatex
:defer t
:after auctex
:straight (:build t)
:hook (LaTeX-mode . cdlatex-mode)
:hook (org-mode . org-cdlatex-mode)
:config
(setq cdlatex-use-dollar-to-ensure-math nil)
:general
(phundrak/major-leader-key
:packages 'cdlatex
:keymaps 'cdlatex-mode-map
"$" nil
"(" nil
"{" nil
"[" nil
"|" nil
"<" nil
"^" nil
"_" nil
[(control return)] nil))
#+end_src
#+begin_src emacs-lisp
(use-package adaptive-wrap
:defer t
:after auctex
:straight (:build t)
:hook (LaTeX-mode . adaptative-wrap-prefix-mode)
:init (setq-default adaptative-wrap-extra-indent 0))
#+end_src
#+begin_src emacs-lisp
(use-package auctex-latexmk
:after auctex
:defer t
:straight (:build t)
:init
(setq auctex-latexmk-inherit-TeX-PDF-mode t)
(add-hook 'LaTeX-mode (lambda () (setq TeX-command-default "LatexMk")))
:config
(auctex-latexmk-setup))
#+end_src
#+begin_src emacs-lisp
(use-package company-auctex
:defer t
:after (company auctex)
:straight (:build t)
:config
(company-auctex-init))
#+end_src
#+begin_src emacs-lisp
(use-package company-math
:defer t
:straight (:build t)
:after (company auctex)
:config
(defun my-latex-mode-setup ()
(setq-local company-backends
(append '((company-math-symbols-latex company-latex-commands))
company-backends)))
(add-hook 'TeX-mode-hook #'my-latex-mode-setup))
#+end_src

View File

@@ -0,0 +1,276 @@
#+title: Emacs — Packages — Misc
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/misc.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Misc
** ArchWiki pages
A small package Ive written allows the user to view ArchLinux pages
either in Emacs or in an external web browser. I prefer the defaults.
#+begin_src emacs-lisp
(use-package archwiki
:defer t
:straight (archwiki :build t
:type git
:repo "https://labs.phundrak.com/phundrak/archwiki.el"))
#+end_src
** ~avy~
~avy~ is a really convenient way of jumping around and performing
actions on these selections, but Ill need some configuration to make
it bépo-compatible.
#+begin_src emacs-lisp
(use-package avy
:defer t
:straight t
:config
(csetq avy-keys '(?a ?u ?i ?e ?c ?t ?s ?r ?n)
avy-dispatch-alist '((?x . avy-action-kill-move)
(?X . avy-action-kill-stay)
(?T . avy-action-teleport)
(?m . avy-action-mark)
(?C . avy-action-copy)
(?y . avy-action-yank)
(?Y . avy-action-yank-line)
(?I . avy-action-ispell)
(?z . avy-action-zap-to-char)))
(defun my/avy-goto-url ()
"Jump to url with avy."
(interactive)
(avy-jump "https?://"))
(defun my/avy-open-url ()
"Open url selected with avy."
(interactive)
(my/avy-goto-url)
(browse-url-at-point))
:general
(phundrak/evil
:pakages 'avy
"gc" #'evil-avy-goto-char-timer
"gl" #'evil-avy-goto-line)
(phundrak/leader-key
:packages 'avy
:infix "j"
"b" #'avy-pop-mark
"c" #'evil-avy-goto-char-timer
"l" #'avy-goto-line)
(phundrak/leader-key
:packages 'avy
:infix "A"
"c" '(:ignore t :which-key "copy")
"cl" #'avy-copy-line
"cr" #'avy-copy-region
"k" '(:ignore t :which-key "kill")
"kl" #'avy-kill-whole-line
"kL" #'avy-kill-ring-save-whole-line
"kr" #'avy-kill-region
"kR" #'avy-kill-ring-save-region
"m" '(:ignore t :which-key "move")
"ml" #'avy-move-line
"mr" #'avy-move-region
"mt" #'avy-transpose-lines-in-region
"n" #'avy-next
"p" #'avy-prev
"u" #'my/avy-goto-url
"U" #'my/avy-open-url)
(phundrak/major-leader-key
:packages '(avy org)
:keymaps 'org-mode-map
"A" '(:ignore t :which-key "avy")
"Ar" #'avy-org-refile-as-child
"Ah" #'avy-org-goto-heading-timer))
#+end_src
** Calc
Lets give ~calc-mode~ some better defaults.
#+begin_src emacs-lisp
(setq calc-angle-mode 'rad
calc-symbolic-mode t)
#+end_src
** Elcord
Whats the point of using Emacs if you cant tell everyone?
#+begin_src emacs-lisp
(use-package elcord
:straight (:built t)
:defer t
:config
(csetq elcord-use-major-mode-as-main-icon t
elcord-refresh-rate 5
elcord-boring-buffers-regexp-list `("^ "
,(rx "*" (+ any) "*")
,(rx bol (or "Re: "
"Fwd: ")))))
#+end_src
** ~ivy-quick-find-files.el~
This package is a small utility package Ive written in order to
quickly find files across my filesystem.
#+begin_src emacs-lisp
(use-package ivy-quick-find-files
:defer t
:straight (ivy-quick-find-files :type git
:host github
:repo "phundrak/ivy-quick-find-files.el"
:build t)
:config
(setq ivy-quick-find-files-program 'fd
ivy-quick-find-files-dirs-and-exts '(("~/org" . "org")
("~/Documents/university" . "org"))
ivy-quick-find-files-fd-additional-options "-L"))
#+end_src
** Keycast
In case I am sharing my screen with people and I want to show which
functions are called on my keystrokes since I dont exactly use
standard keybindings.
#+begin_src emacs-lisp
(use-package keycast
:defer t
:straight (:build t)
:config
(define-minor-mode keycast-mode
"Show current command and its key binding in the mode line."
:global t
(if keycast-mode
(add-hook 'pre-command-hook 'keycast--update t)
(remove-hook 'pre-command-hook 'keycast--update)))
(add-to-list 'global-mode-string '("" mode-line-keycast " ")))
#+end_src
** Keyfreq
Keyfreq is a package that records all the commands I call from Emacs
and builds a heatmap out of it.
#+begin_src emacs-lisp
(use-package keyfreq
:straight (:build t)
:init
(keyfreq-mode 1)
(keyfreq-autosave-mode 1)
:config
(setq keyfreq-excluded-commands '(self-insert-command org-self-insert-command
evil-previous-visual-line evil-next-visual-line
ivy-next-line evil-backward-char evil-forward-char
evil-next-line evil-previous-line evil-normal-state
text-scale-pinch)))
#+end_src
** Mastodon
#+begin_src emacs-lisp
(use-package mastodon
:defer t
:ensure t
:straight (mastodon :type git
:host codeberg
:repo "martianh/mastodon.el")
:config
(setq mastodon-instance-url "https://emacs.ch"
mastodon-active-user "phundrak")
(defun me/mastodon-toot--send-language-if-none ()
(unless mastodon-toot--language
(mastodon-toot--set-toot-language)))
(advice-add #'me/mastodon-toot--send-language-if-none :before #'mastodon-toot--send)
:general
(phundrak/evil
:packages '(mastodon)
:keymaps 'mastodon-mode-map
"]]" '(mastodon-tl--goto-next-toot :wk "Next status")
"[[" '(mastodon-tl--goto-prev-toot :wk "Previous status")
"gt" '(mastodon-tl--next-tab-item :wk "Next tab item")
"gs" '(mastodon-tl--previous-tab-item :wk "Previous tab item")
"»" '(mastodon-tl--goto-next-toot :wk "Next status")
"«" '(mastodon-tl--goto-prev-toot :wk "Previous status")
"q" #'kill-current-buffer)
(phundrak/major-leader-key
:package 'mastodon
:keymaps 'mastodon-mode-map
"#" '(mastodon-tl--get-tag-timeline :wk "Tag timeline")
"f" '(mastodon-tl--get-federated-timeline :wk "Federated timeline")
"F" '(mastoton-tl--view-filters :wk "Filters")
"H" '(mastodon-tl--get-local-timeline :wk "Home timeline")
"L" '(mastodon-tl--get-local-timeline :wk "Local timeline")
"N" '(mastodon-notifications-get :wk "Notifications")
"T" '(mastodon-tl--thread :wk "Thread")
"O" '(mastodon-profile--my-profile :wk "My profile")
"S" '(mastodon-tl--get-follow-suggestions :wk "Follow suggestions")
"a" '(mastodon-profile--get-toot-author :wk "Toot author")
"b" '(mastodon-profile--view-bookmarks :wk "Bookmarks")
"s" '(mastodon-search--search-query :wk "Search query")
"U" '(mastodon-tl--update :wk "Update")
"t" '(nil :wk "Toots")
"tt" '(mastodon-toot :wk "Toot")
"tb" '(mastodon-toot--toggle-boost :wk "Boost")
"tB" '(mastodon-toot--bookmark-toot-toggle :wk "Bookmark")
"td" '(mastodon-toot--delete-toot :wk "Delete")
"tD" '(mastodon-toot--delete-and-redraft-toot :wk "Redraft")
"tf" '(mastodon-toot--toggle-favourite :wk "Favourite")
"tF" '(mastodon-profile--view-favourites :wk "View favourites")
"tr" '(mastodon-toot--reply :wk "Reply")
"tp" '(mastodon-toot--pin-toot-toggle :wk "Pin")
"ts" '(mastodon-tl--toggle-spoiler-text-in-toot :wk "Spoiler")
"tu" '(mastodon-toot--copy-toot-url :wk "Copy url")
"tv" '(mastodon-tl--poll-vote :wk "Vote on poll")
"f" '(nil :wk "Follow requests")
"fa" '(mastodon-notifications--follow-request-accept :wk "Accept")
"fr" '(mastodon-notifications--follow-request-reject :wk "Reject")
"fv" '(mastodon-profile--view-follow-requests :wk "View follow requests")
"u" '(nil :wk "User")
"uf" '(mastodon-tl--follow-user :wk "Follow")
"uF" '(mastodon-tl--unfollow-user :wk "Unfollow")
"ub" '(mastodon-tl--block-user :wk "Block")
"uB" '(mastodon-tl--unblock-user :wk "Unblock")
"um" '(mastodon-tl--mute-user :wk "Mute")
"uM" '(mastodon-tl--unmute-user :wk "Unmute")
"un" '(mastodon-profile--update-user-profile-note :wk "Update user profile note")
"uu" '(mastodon-profile--show-user :wk "Show user")))
#+end_src
** Mediawiki
#+begin_src emacs-lisp
(use-package mediawiki
:defer t
:straight (:build t)
:custom
(mediawiki-site-alist '(("PhundrakWiki" ; Title
"https://wiki.phundrak.com/" ; URL
"phundrak" ; username
nil ; password
nil ; LDAP
"Main Page")))) ; Default page
#+end_src
** SICP
Who would get interested in Emacs and not want to read the SICP?
Moreover, inside Emacs?
#+begin_src emacs-lisp
(use-package sicp
:straight (:build t)
:defer t)
#+end_src
** Winum
Winum allows Emacs to associate windows with a specific number and
navigate through these windows by directly refering to their
associated number! This allows for faster window configuration than
just going to the frame above, then left, left, and up.
#+begin_src emacs-lisp
(use-package winum
:straight (:build t)
:init (winum-mode))
#+end_src
** Ytplay
~ytplay~ is a small package Ive written with which you can choose at
which resolution to play a YouTube video in an external video player.
#+begin_src emacs-lisp
(use-package ytplay
:defer t
:straight (ytplay :build t
:type git
:repo "https://labs.phundrak.com/phundrak/ytplay.el"))
#+end_src

1399
docs/emacs/packages/org.org Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,260 @@
#+title: Emacs — Packages — Visual Configuration
#+setupfile: ../../headers
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/visual-config.el
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
* Visual Configuration
** Dashboard
#+begin_src emacs-lisp
(use-package dashboard
:straight (:build t)
:ensure t
:after all-the-icons
:config
(setq dashboard-banner-logo-title "Phundraks Vanilla Emacs"
dashboard-startup-banner 'logo
dashboard-center-content t
dashboard-show-shortcuts t
dashboard-set-navigator t
dashboard-set-heading-icons t
dashboard-set-file-icons t
initial-buffer-choice (lambda () (get-buffer "*dashboard*"))
dashboard-projects-switch-function 'counsel-projectile-switch-project-by-name)
(setq dashboard-navigator-buttons
`(((,(all-the-icons-faicon "language" :height 1.1 :v-adjust 0.0)
"Linguistics Website"
""
(lambda (&rest _) (browse-url "https://langue.phundrak.com")))
(,(all-the-icons-faicon "firefox" :height 1.1 :v-adjust 0.0)
"Config Website"
""
(lambda (&rest _) (browse-url "https://config.phundrak.com"))))
((,(all-the-icons-octicon "git-branch" :height 1.1 :v-adjust 0.0)
"Dotfiles Sources"
""
(lambda (&rest _) (browse-url "https://labs.phundrak.com/phundrak/dotfiles")))
("!" "Issues" "Show issues" (lambda (&rest _)
(browse-url "https://labs.phundrak.com/phundrak/dotfiles/issues"))
warning))
((,(all-the-icons-faicon "level-up" :height 1.1 :v-adjust 0.0)
"Update Packages"
""
(lambda (&rest _) (progn
(require 'straight)
(straight-pull-all)
(straight-rebuild-all)))))))
(setq dashboard-items '((recents . 15)
(agenda . 10)
(projects . 10)))
(dashboard-setup-startup-hook)
:init
(add-hook 'after-init-hook 'dashboard-refresh-buffer))
#+end_src
** Fringe
Its nice to know which lines were modified since the last commit in a
file.
#+begin_src emacs-lisp
(use-package git-gutter-fringe
:straight (:build t)
:hook ((prog-mode . git-gutter-mode)
(org-mode . git-gutter-mode)
(markdown-mode . git-gutter-mode)
(latex-mode . git-gutter-mode)))
#+end_src
** Icons? Did someone say icons?
/*YES! ALL OF THEM!*/
Ahem…
The package ~all-the-icons~ allows us to use a wide variety of icons in
Emacs for various purposes, wherever we want, and /THAT/ is *GREAT*! Ill
(ab)use this feature in my config, be warned! *NOTE*: The first time a
configuration with ~all-the-icons~ loads on a machine, the needed fonts
might not be available, so youll need to install them with the
command ~M-x all-the-icons-install-fonts~.
#+begin_src emacs-lisp
(use-package all-the-icons
:defer t
:straight t)
#+end_src
~prettify-symbols-mode~ is also a nifty feature of Emacs, and it is
built-in! With that, I can replace strings of my choice by another
character of my choice! First, lets declare the general symbols that
will be used everywhere.
#+begin_src emacs-lisp
(defun prog-mode-set-symbols-alist ()
(setq prettify-symbols-alist '(("lambda" . )))
(prettify-symbols-mode 1))
(add-hook 'prog-mode-hook #'prog-mode-set-symbols-alist)
#+end_src
We can now take care of the language-specific symbols. First, lets
declare some symbols for the Lisp languages.
#+begin_src emacs-lisp
(setq-default lisp-prettify-symbols-alist '(("lambda" . )
("defun" . ?𝑓)
("defvar" . ?𝑣)
("defcustom" . ?𝑐)
("defconst" . ?𝐶)))
(defun lisp-mode-prettify ()
(setq prettify-symbols-alist lisp-prettify-symbols-alist)
(prettify-symbols-mode -1)
(prettify-symbols-mode 1))
(dolist (lang '(emacs-lisp lisp common-lisp scheme))
(add-hook (intern (format "%S-mode-hook" lang))
#'lisp-mode-prettify))
#+end_src
Finally, similar to how ~org-appear~ behaves, lets show the real string
of our symbols when the cursor is on it.
#+begin_src emacs-lisp
(setq prettify-symbols-unprettify-at-point t)
#+end_src
** Ligatures
The font Im using (see *here*) supports ligatures, but Emacs in GUI
mode does not. And of course, theres a package for that.
# Insert equivalent of #Basic-configuration-Visual-Configuration-Fontsxfkjel6184j0 in *here*
#+begin_src emacs-lisp
(use-package ligature
:straight (ligature :type git
:host github
:repo "mickeynp/ligature.el"
:build t)
:config
(ligature-set-ligatures 't
'("www"))
;; Enable traditional ligature support in eww-mode, if the
;; `variable-pitch' face supports it
(ligature-set-ligatures '(eww-mode org-mode elfeed-show-mode)
'("ff" "fi" "ffi"))
;; Enable all Cascadia Code ligatures in programming modes
(ligature-set-ligatures 'prog-mode
'("|||>" "<|||" "<==>" "<!--" "####" "~~>" "***" "||=" "||>"
":::" "::=" "=:=" "===" "==>" "=!=" "=>>" "=<<" "=/=" "!=="
"!!." ">=>" ">>=" ">>>" ">>-" ">->" "->>" "-->" "---" "-<<"
"<~~" "<~>" "<*>" "<||" "<|>" "<$>" "<==" "<=>" "<=<" "<->"
"<--" "<-<" "<<=" "<<-" "<<<" "<+>" "</>" "###" "#_(" "..<"
"..." "+++" "/==" "///" "_|_" "www" "&&" "^=" "~~" "~@" "~="
"~>" "~-" "**" "*>" "*/" "||" "|}" "|]" "|=" "|>" "|-" "{|"
"[|" "]#" "::" ":=" ":>" ":<" "$>" "==" "=>" "!=" "!!" ">:"
">=" ">>" ">-" "-~" "-|" "->" "--" "-<" "<~" "<*" "<|" "<:"
"<$" "<=" "<>" "<-" "<<" "<+" "</" "#{" "#[" "#:" "#=" "#!"
"##" "#(" "#?" "#_" "%%" ".=" ".-" ".." ".?" "+>" "++" "?:"
"?=" "?." "??" ";;" "/*" "/=" "/>" "//" "__" "~~" "(*" "*)"
"\\\\" "://"))
(global-ligature-mode t))
#+end_src
** Modeline
The DoomEmacs modeline looks nice in my opinion, lets use it.
#+begin_src emacs-lisp
(use-package doom-modeline
:straight (:build t)
:defer t
:init (doom-modeline-mode 1)
:config
(csetq doom-modeline-height 15
doom-modeline-enable-word-count t
doom-modeline-continuous-word-count-modes '(markdown-mode gfm-mode org-mode)
doom-modeline-mu4e t
doom-modeline-env-version t)
(mu4e-alert-enable-mode-line-display))
#+end_src
** Pixel-perfect alignment of Markdown and org-mode tables
:END:
Usually, I have no issue with the alignment of the tables I write in
org-mode and (more rarely) Markdown. However, there are occurences
where Ill use a character that does not exactly respect my monospace
font, which messes with the alignment of the table (often when I do
linguistics stuff). A solution to this is the package ~valign~. A little
caveat though, as its name implies ~valign~ helps with vertical
alignment. If some lines are too high, they wont exactly fit. Unless?
Unless ~valign-fancy-bar~ is set to ~t~.
For now, I disabled the hook with org-mode and markdown-mode because
it slows down opening these files quite a lot. Ill re-enable the hook
once it is fixed.
#+begin_src emacs-lisp
(use-package valign
:defer t
:straight (:build t)
:after (org markdown-mode)
;; :hook ((org-mode markdown-mode) . valign-mode)
:custom ((valign-fancy-bar t)))
#+end_src
** Secret mode
Sometimes, I want to hide the text displayed by Emacs but not lock
altogether my computer. In this case, ~secret-mode~ comes in handy.
#+begin_src emacs-lisp
(use-package secret-mode
:defer t
:straight (secret-mode :build t
:type git
:host github
:repo "bkaestner/secret-mode.el"))
#+end_src
** Solaire: Incandescent Emacs
A common issue when you have a lot of windows opened in Emacs is
sometimes theres just too much. Is the first window source code? Is
the other one just an open email? Oh, lets not forget the ~*Messages*~
buffer open next to another source buffer.
Solaire-mode applies a subtle but useful tweak to your current color
scheme: the background of programming buffers is slightly lighter than
the background of other buffers. (Or is it other buffers that have a
slightly darker background? Im not sure.)
#+begin_src emacs-lisp
(use-package solaire-mode
:defer t
:straight (:build t)
:init (solaire-global-mode +1))
#+end_src
** Theme
You may have noticed I use the Nord theme pretty much everywhere on my
computer, why not Emacs? In my opinion, its aurora variant is nicer
than the default Nord theme since it is richer in colors --- just a
personal preference.
#+begin_src emacs-lisp
(use-package doom-themes
:straight (:build t)
:defer t
:init (load-theme 'doom-nord-aurora t))
#+end_src
** Rainbow Delimiters
This makes Lisp especially more readable, but its also nice to have
for any language that has delimiters like brackets too.
#+begin_src emacs-lisp
(use-package rainbow-delimiters
:straight (:build t)
:defer t
:hook (prog-mode . rainbow-delimiters-mode))
#+end_src
** Yall want some more /COLORS/?
It is possible to make info buffers much more colorful (and imo easier
to read) with this simple package:
#+begin_src emacs-lisp
(use-package info-colors
:straight (:build t)
:commands info-colors-fnontify-node
:hook (Info-selection . info-colors-fontify-node)
:hook (Info-mode . mixed-pitch-mode))
#+end_src