2021-10-20 11:58:20 +00:00
#+title : Emacs Configuration
2021-11-08 14:02:25 +00:00
#+setupfile : headers
2022-10-17 13:59:54 +00:00
#+options : unique-id:t
2021-05-21 11:59:48 +00:00
#+html_head : <meta name="description" content="Phundrak’ s Emacs Configuration" />
#+html_head : <meta property="og:title" content="Phundrak’ s Emacs Configuration" />
#+html_head : <meta property="og:description" content="Phundrak’ s Emacs Configuration Detailed" />
#+property : header-args:emacs-lisp :mkdirp yes :lexical t :exports code
2022-02-04 15:59:53 +00:00
#+property : header-args:emacs-lisp+ :tangle ~/.config/emacs/init.el
2021-06-14 12:39:20 +00:00
#+property : header-args:emacs-lisp+ :mkdirp yes :noweb no-export
2021-05-21 11:59:48 +00:00
2021-11-22 13:32:43 +00:00
#+include : img/emacs.svg export html
2021-05-21 11:59:48 +00:00
* Introduction
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Introduction7gzhel6184j0
:END:
2021-05-21 11:59:48 +00:00
After a couple of years using Spacemacs and a failed attempt at
switching to DoomEmacs, I’ m finally switching back to a vanilla
2022-01-04 17:16:15 +00:00
configuration! Why? Because I got tired of the framework getting in my
way when I wanted to do stuff. I’ m 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
It’ s 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 it’ s not in
Emacs already, that is.
2021-05-21 11:59:48 +00:00
2021-11-23 14:01:23 +00:00
#+attr_html : :alt Dammit Emacs… :loading lazy
2022-01-04 17:16:15 +00:00
#+caption : [[https://xkcd.com/378/][XKCD n°378]]: Real Programmers
2021-11-22 13:32:43 +00:00
[[file:./img/real_programmers.png ]]
2022-02-05 11:25:35 +00:00
* A Warning Before You Proceed
:PROPERTIES:
:CUSTOM_ID: A-Warning-Before-You-Proceed-mgyar9i0ucj0
: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 aren’ t 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
* Basic Configuration
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configurationzt3iel6184j0
:END:
2021-06-09 15:22:47 +00:00
** Early Init
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Early-Inityj7iel6184j0
2022-02-04 15:59:53 +00:00
:header-args:emacs-lisp: :tangle ~/.config/emacs/early-init.el :mkdirp yes
2021-11-28 21:58:52 +00:00
:header-args:emacs-lisp+: :exports code :results silent :lexical t
2021-06-16 12:30:03 +00:00
:END:
2021-05-21 11:59:48 +00:00
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.
2021-11-28 21:58:52 +00:00
#+begin_src emacs-lisp :mkdirp yes
2021-10-12 09:31:20 +00:00
(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
2022-03-27 20:17:55 +00:00
(setq gc-cons-threshold (* 1024 1024 1024))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
** Emacs Behavior
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior6gbiel6184j0
:END:
2021-06-09 15:22:47 +00:00
*** Editing Text in Emacs
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Editing-Text-in-Emacsy2fiel6184j0
:END:
2021-06-09 15:22:47 +00:00
I *never* want to keep trailing spaces in my files, which is why I’ m
doing this:
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(add-hook 'before-save-hook #'whitespace-cleanup)
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
I don’ t understand why some people add two spaces behind a full stop,
I sure don’ t. Let’ s tell Emacs.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq-default sentence-end-double-space nil)
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
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
2021-11-20 22:08:38 +00:00
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.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(global-subword-mode 1)
2021-05-21 11:59:48 +00:00
#+end_src
2022-04-11 12:50:29 +00:00
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
2021-06-09 15:22:47 +00:00
Lastly, I want the default mode for Emacs to be Emacs Lisp.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq-default initial-major-mode 'emacs-lisp-mode)
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
**** Indentation
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Editing-Text-in-Emacs-Indentationauiiel6184j0
:END:
2021-05-21 11:59:48 +00:00
I don’ t 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, let’ s
disable them:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq-default indent-tabs-mode nil)
(add-hook 'prog-mode-hook (lambda () (setq indent-tabs-mode nil)))
2021-05-21 11:59:48 +00:00
#+end_src
2021-11-20 22:08:38 +00:00
Just to go on a little tangent here: I don’ t exactly /hate/ tabs, but I
2021-05-21 11:59:48 +00:00
find them really annoying when your text editor knows only them. Sure,
2021-11-20 22:08:38 +00:00
for indentation they work great, and they allow different people
2021-05-21 11:59:48 +00:00
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!
2023-03-20 16:17:57 +00:00
But the thing is, once you indented your code, and then you need
2021-05-21 11:59:48 +00:00
alignment, tabs don’ t work anymore! Or they may on *your* text editor
but not on your coworker’ s! (He’ s 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. What’ s
the best of both worlds then?
#+begin_center
/Tabs for indentation/
/Spaces for alignment/
#+end_center
I haven’ t found a way to automate that in Emacs yet aside from
2021-11-20 22:08:38 +00:00
formatters’ config file, and tabs look bat in EmacsLisp anyway, so
2021-05-21 11:59:48 +00:00
I’ ll stick with spaces by default and change it where needed.
2021-06-09 15:22:47 +00:00
*** Programming Modes
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Programming-Modesfnmiel6184j0
:END:
2021-11-20 22:08:38 +00:00
First off, my definition of what makes a “programming mode” doesn’ t exactly
2021-06-09 15:22:47 +00:00
fit mine, so on top of ~prog-mode~ , let’ s add a few other modes.
#+name : line-number-modes-table
| Modes |
|------------|
| prog-mode |
| latex-mode |
#+name : prog-modes-gen
2022-02-12 11:50:07 +00:00
#+header : :cache yes :exports none :tangle no
2021-06-14 12:39:20 +00:00
#+begin_src emacs-lisp :var modes=line-number-modes-table
2021-10-12 09:31:20 +00:00
(mapconcat (lambda (mode) (format "%s-hook" (car mode)))
modes
" ")
2021-06-09 15:22:47 +00:00
#+end_src
**** Line Number
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Programming-Modes-Line-Numbermcqiel6184j0
:END:
2021-06-09 15:22:47 +00:00
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.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(dolist (mode '(<<prog-modes-gen() >>))
(add-hook mode #'display-line-numbers-mode))
2021-06-09 15:22:47 +00:00
#+end_src
**** Folding code
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Programming-Modes-Folding-code16uiel6184j0
:END:
2021-06-09 15:22:47 +00:00
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~ , let’ s enable it for all of these programming modes:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(dolist (mode '(<<prog-modes-gen() >>))
(add-hook mode #'hs-minor-mode))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
*** Stay Clean, Emacs!
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Stay-Clean-Emacs7wxiel6184j0
:END:
2021-06-09 15:22:47 +00:00
As nice as Emacs is, it isn’ t 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
2021-11-20 22:08:38 +00:00
keep its backup files to itself in a directory it only will access.
2021-06-09 15:22:47 +00:00
#+begin_src emacs-lisp
2021-10-12 09:25:39 +00:00
(setq backup-directory-alist `(("." . ,(expand-file-name ".tmp/backups/ "
user-emacs-directory))))
2021-06-09 15:22:47 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-06-09 15:22:47 +00:00
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/ ?
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq-default custom-file (expand-file-name ".custom.el" user-emacs-directory))
(when (file-exists-p custom-file) ; Don’ t forget to load it, we still need it
(load custom-file))
2021-06-09 15:22:47 +00:00
#+end_src
If we delete a file, we want it moved to the trash, not simply deleted.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq delete-by-moving-to-trash t)
2021-06-09 15:22:47 +00:00
#+end_src
Finally, the scatch buffer always has some message at its beginning, I
don’ t want it!
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq-default initial-scratch-message nil)
2021-06-09 15:22:47 +00:00
#+end_src
*** Stay Polite, Emacs!
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Stay-Polite-Emacszp1jel6184j0
:END:
2021-06-09 15:22:47 +00:00
When asking for our opinion on something, Emacs loves asking us to
answer by “yes” or “no”, but *in full* ! That’ s very rude! Fortunately,
we can fix this.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defalias 'yes-or-no-p 'y-or-n-p)
2021-06-09 15:22:47 +00:00
#+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!
2021-06-14 12:37:30 +00:00
It is also very impolite to keep a certain version of a file in its
buffer when said file has changed on disk. Let’ s change this behavior:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(global-auto-revert-mode 1)
2021-06-14 12:37:30 +00:00
#+end_src
Much more polite! Note that if the buffer is modified and its changes
haven’ t been saved, it will not automatically revert the buffer and
your unsaved changes won’ t be lost. Very polite!
2021-06-09 15:22:47 +00:00
*** Misc
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Misc9j5jel6184j0
:END:
2023-03-20 16:17:57 +00:00
Let’ s raise Emacs undo memory to 10 MB, and make Emacs auto-save our
2021-06-09 15:22:47 +00:00
files by default.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq undo-limit 100000000
auto-save-default t)
2021-06-09 15:22:47 +00:00
#+end_src
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq window-combination-resize t) ; take new window space from all other windows
2021-06-09 15:22:47 +00:00
#+end_src
** Personal Information
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Personal-Informationi59jel6184j0
:END:
2021-06-09 15:22:47 +00:00
Emacs needs to know its master! For various reasons by the way, some
2023-03-20 16:17:57 +00:00
packages rely on these variables to know who it is talking to or
2021-06-09 15:22:47 +00:00
dealing with, such as ~mu4e~ which will guess who you are if you haven’ t
set it up correctly.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq user-full-name "Lucien Cartier-Tilet"
user-real-login-name "Lucien Cartier-Tilet"
user-login-name "phundrak"
user-mail-address "lucien@phundrak.com")
2021-06-09 15:22:47 +00:00
#+end_src
** Visual Configuration
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Visual-Configurationzvcjel6184j0
:END:
2021-06-09 15:22:47 +00:00
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 doesn’ t agree with, like tring to go up a line when I’ m already
at the top of the buffer.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq visible-bell t)
2021-06-09 15:22:47 +00:00
#+end_src
It is nicer to see a cursor cover the actual space of a character.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq x-stretch-cursor t)
2021-06-09 15:22:47 +00:00
#+end_src
When text is ellipsed, I want the ellipsis marker to be a single
character of three dots. Let’ s make it so:
#+begin_src emacs-lisp
2022-09-19 10:37:34 +00:00
(with-eval-after-load 'mule-util
(setq truncate-string-ellipsis "…"))
2021-06-09 15:22:47 +00:00
#+end_src
2022-05-17 15:24:54 +00:00
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.
2021-11-08 13:29:04 +00:00
#+begin_src emacs-lisp
2022-08-07 10:55:00 +00:00
(add-to-list 'default-frame-alist '(alpha-background . 0.9))
2021-11-08 13:29:04 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
*** Modeline Modules
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Visual-Configuration-Modeline-Modules9kgjel6184j0
:END:
2021-06-09 15:22:47 +00:00
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
2022-09-19 10:37:34 +00:00
(require 'time)
2021-10-12 09:31:20 +00:00
(setq display-time-format "%Y-%m-%d %H:%M")
(display-time-mode 1) ; display time in modeline
2021-06-09 15:22:47 +00:00
#+end_src
Something my taskbar doesn’ t 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
2021-10-12 09:31:20 +00:00
(let ((battery-str (battery)))
2021-10-19 17:17:10 +00:00
(unless (or (equal "Battery status not available" battery-str)
(string-match-p (regexp-quote "N/A") battery-str))
(display-battery-mode 1)))
2021-06-09 15:22:47 +00:00
#+end_src
This isn’ t 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 I’ m on. This can be activated like so:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(column-number-mode)
2021-06-09 15:22:47 +00:00
#+end_src
The following code is, as will several chunks of code in this config,
2021-06-14 12:37:30 +00:00
borrowed from [[https://tecosaur.github.io/emacs-config/#theme-modeline ][TEC’ s configuration ]]. It hides the encoding information
2021-06-09 15:22:47 +00:00
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
2021-10-12 09:31:20 +00:00
(defun modeline-contitional-buffer-encoding ()
"Hide \"LF UTF-8\" in modeline.
2021-06-09 15:22:47 +00:00
2021-10-12 09:31:20 +00:00
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)))
2021-06-09 15:22:47 +00:00
#+end_src
Now, let’ s 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
2021-10-12 09:31:20 +00:00
(add-hook 'after-change-major-mode-hook #'modeline-contitional-buffer-encoding)
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
*** Fonts
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Visual-Configuration-Fontsxfkjel6184j0
:END:
2021-06-09 15:22:47 +00:00
I don’ t like the default font I usually have on my machines, I really
don’ t. I prefer [[https://github.com/microsoft/cascadia-code ][Cascadia Code ]], as it also somewhat supports the [[https://www.internationalphoneticassociation.org/ ][IPA ]].
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defvar phundrak/default-font-size 90
"Default font size.")
2021-06-09 15:22:47 +00:00
2021-12-26 13:51:20 +00:00
(defvar phundrak/default-font-name "Cascadia Code"
"Default font.")
2022-02-11 10:12:23 +00:00
(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)
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
*** Frame Title
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Visual-Configuration-Frame-Titlej7ojel6184j0
:END:
2021-06-09 15:22:47 +00:00
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
2021-10-12 09:31:20 +00:00
(setq frame-title-format
'(""
"%b"
(:eval
(let ((project-name (projectile-project-name)))
(unless (string= "-" project-name)
2021-11-22 15:53:04 +00:00
(format (if (buffer-modified-p) " ◉ %s" " ● %s - Emacs") project-name))))))
2021-06-09 15:22:47 +00:00
#+end_src
2022-06-15 19:38:51 +00:00
** A better custom variable setter
:PROPERTIES:
:CUSTOM_ID: Basic-Configuration-A-better-custom-variable-setter-56z4ni61lhj0
:END:
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~ shouldn’ t be
the user’ s 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].
2022-06-15 20:25:09 +00:00
`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.
2022-06-15 19:38:51 +00:00
2022-06-15 20:25:09 +00:00
The return value of `csetq' is the value of the last VAL.
2022-06-15 19:38:51 +00:00
\(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)))))
2022-08-14 11:13:17 +00:00
;; 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))))
2022-06-15 19:38:51 +00:00
#+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 it’ s pairs of variables and their value), but
I also had to make the code simply work.
2021-05-21 11:59:48 +00:00
* Custom Elisp
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Custom-Elispksvjel6184j0
:END:
2021-06-09 15:22:47 +00:00
** Dired functions
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Custom-Elisp-Dired-functionsm8zjel6184j0
:END:
2021-06-09 15:22:47 +00:00
*** ~phundrak/open-marked-files~
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Custom-Elisp-Dired-functions-phundrak-open-marked-filesdw2kel6184j0
:END:
2021-06-09 15:22:47 +00:00
This function allows the user to open all marked files from a dired
2023-03-20 16:17:57 +00:00
buffer in new Emacs buffers.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defun phundrak/open-marked-files (&optional files)
2022-09-19 10:37:34 +00:00
"Open all marked FILES in Dired buffer as new Emacs buffers."
2021-10-12 09:31:20 +00:00
(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))))
2021-06-09 15:22:47 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-06-09 15:22:47 +00:00
** Switch between buffers
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Custom-Elisp-Switch-between-buffersp4ekel6184j0
:END:
2021-06-09 15:22:47 +00:00
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.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defun switch-to-messages-buffer ()
"Switch to Messages buffer."
(interactive)
2021-10-22 10:09:47 +00:00
(switch-to-buffer (messages-buffer)))
2021-05-21 11:59:48 +00:00
2021-10-12 09:31:20 +00:00
(defun switch-to-scratch-buffer ()
"Switch to Messages buffer."
(interactive)
(switch-to-buffer "*scratch* "))
2021-05-21 11:59:48 +00:00
#+end_src
2021-11-22 15:52:15 +00:00
** Screenshots
:PROPERTIES:
:CUSTOM_ID: Custom-Elisp-Screenshots-l9bkib013aj0
:END:
Since Emacs27, it is possible for Emacs to take screenshots of itself
2023-03-20 16:17:57 +00:00
in various formats. I’ m mainly interested in the SVG and PNG format,
2021-11-22 15:52:15 +00:00
so I’ ll only write functions for these. It isn’ t really redundant with
the ~screenshot.el~ package used [[#Packages-Configuration-Applications-Screenshot96d1fl6184j0 ][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
2023-03-20 16:17:57 +00:00
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.
2021-11-22 15:52:15 +00:00
#+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."
2023-03-20 16:19:15 +00:00
(interactive (list
(intern (completing-read "Screenshot type: "
'(png svg pdf postscript)))))
(let* ((extension (pcase type
2021-11-22 15:52:15 +00:00
('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
2022-03-10 21:26:31 +00:00
I used this function to take the screenshots you can see in this
2021-11-22 15:55:30 +00:00
document.
2022-03-10 21:53:38 +00:00
** Handle new windows
2021-06-16 12:30:03 +00:00
:PROPERTIES:
2022-03-10 21:53:38 +00:00
:CUSTOM_ID: Custom-Elisp-Handle-new-windows-f1za1rl02ej0
2021-06-16 12:30:03 +00:00
:END:
2021-06-09 15:22:47 +00:00
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
2021-10-12 09:31:20 +00:00
(defun split-window-right-and-focus ()
2021-11-09 12:39:34 +00:00
"Spawn a new window right of the current one and focus it."
2021-10-12 09:31:20 +00:00
(interactive)
(split-window-right)
2021-11-08 13:25:17 +00:00
(windmove-right))
2021-06-09 15:22:47 +00:00
2021-10-12 09:31:20 +00:00
(defun split-window-below-and-focus ()
2021-11-09 12:39:34 +00:00
"Spawn a new window below the current one and focus it."
2021-10-12 09:31:20 +00:00
(interactive)
(split-window-below)
2021-11-08 13:25:17 +00:00
(windmove-down))
2021-11-09 12:39:34 +00:00
(defun kill-buffer-and-delete-window ()
"Kill the current buffer and delete its window."
(interactive)
(progn
(kill-this-buffer)
(delete-window)))
2021-06-09 15:22:47 +00:00
#+end_src
2022-05-06 17:48:12 +00:00
** Extend ~add-to-list~
:PROPERTIES:
:CUSTOM_ID: Custom-Elisp-Extend-add-to-list-eh2325605gj0
:END:
One function I find missing regarding ~add-to-list~ is ~add-all-to-list~
2023-03-20 16:17:57 +00:00
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~ .
That’ s not very clean. Let’ s declare this missing function:
2022-05-06 17:48:12 +00:00
#+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 isn’ t 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
2021-05-21 11:59:48 +00:00
* Package Management
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Package-Managementqpwkel6184j0
:END:
2021-05-21 11:59:48 +00:00
** Repositories
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Package-Management-Repositoriesab0lel6184j0
:END:
2021-05-21 11:59:48 +00:00
By default, only GNU’ s repositories are available to the package
managers of Emacs. I also want to use Melpa and org-mode’ s repository,
2022-03-10 21:26:52 +00:00
so let’ s 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 FSF’ s 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.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq package-archives '(("melpa" . "https://melpa.org/packages/ ")
("gnu" . "https://elpa.gnu.org/packages/ ")
("nongnu" . "https://elpa.nongnu.org/nongnu/ ")))
2021-05-21 11:59:48 +00:00
#+end_src
** Straight
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Package-Management-Straightry3lel6184j0
:END:
2023-03-20 16:17:57 +00:00
For my package management, I prefer to use ~straight~ ([[https://github.com/raxod502/straight.el ][GitHub ]]). This is
2022-01-05 13:10:40 +00:00
due to its capacity of integrating nicely with ~use-package~ , which also
supports ~general~ which I use for my keybindings (see below), but also
2023-03-20 16:17:57 +00:00
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.
2022-01-05 13:10:40 +00:00
First, let’ s bootstrap straight.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(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))
2022-01-05 13:10:40 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2022-01-05 13:10:40 +00:00
Now, we can refresh our package list in order to be able to install
stuff.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(package-initialize)
(unless package-archive-contents
(package-refresh-contents))
2021-05-21 11:59:48 +00:00
2022-01-05 13:10:40 +00:00
#+end_src
From time to time, I fork some packages either because I’ m trying to
implement something new in said package, or because the package is
2023-03-20 16:17:57 +00:00
unmaintained, and I want to continue developing it a bit more. Straight
2022-01-05 13:10:40 +00:00
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
2023-03-20 16:17:57 +00:00
with websites such as GitHub, Gitlab, and such) interacts by default
with the forge described by the =origin= remote, which isn’ t 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.
2022-01-05 13:10:40 +00:00
#+begin_src emacs-lisp
(setq straight-vc-git-default-remote-name "straight")
#+end_src
2021-05-21 11:59:48 +00:00
2022-01-05 13:10:40 +00:00
We finally come to the ~use-package~ installation. This is done like so:
#+begin_src emacs-lisp
(straight-use-package '(use-package :build t))
2021-10-12 09:31:20 +00:00
(setq use-package-always-ensure t)
2021-05-21 11:59:48 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
* Keybinding Management
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Keybinding-Management728lel6184j0
:END:
2021-05-23 23:18:51 +00:00
** Which-key
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Keybinding-Management-Which-keymsblel6184j0
:END:
2022-04-06 16:50:46 +00:00
Which key is, I think, one of my favorite quality of life package.
When you begin a keybind, Emacs will show you all keybinds you can
follow the first one with in order to form a full keychord. Very
useful when you have a lot of keybinds and don’ t remember exactly what
is what.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package which-key
:straight (:build t)
:defer t
:init (which-key-mode)
:diminish which-key-mode
:config
(setq which-key-idle-delay 1))
2021-05-21 11:59:48 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
** General
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Keybinding-Management-Generalycflel6184j0
:END:
2021-06-09 15:22:47 +00:00
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,
2021-11-07 01:27:04 +00:00
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.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package general
:straight (:build t)
:init
2021-11-07 01:27:04 +00:00
(general-auto-unbind-keys)
:config
(general-create-definer phundrak/undefine
2021-11-07 14:54:20 +00:00
:keymaps 'override
2021-11-07 01:27:04 +00:00
:states '(normal emacs))
(general-create-definer phundrak/evil
:states '(normal))
(general-create-definer phundrak/leader-key
:states '(normal insert visual emacs)
2021-11-07 14:54:20 +00:00
:keymaps 'override
2021-11-07 01:27:04 +00:00
:prefix "SPC"
:global-prefix "C-SPC")
(general-create-definer phundrak/major-leader-key
:states '(normal insert visual emacs)
2021-11-07 14:54:20 +00:00
:keymaps 'override
2021-11-07 01:27:04 +00:00
:prefix ","
:global-prefix "M-m"))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-11 14:28:25 +00:00
#+name : general-keybindings-gen
2022-02-12 11:50:07 +00:00
#+header : :tangle no :exports none :results value :cache yes
2021-11-28 21:51:48 +00:00
#+begin_src emacs-lisp :var table=keybinds-windows prefix= ""
2021-10-12 09:31:20 +00:00
(mapconcat (lambda (line)
(let* ((key (car line))
(function (cadr line))
(comment (caddr line)))
2021-11-28 21:51:48 +00:00
(format "\"%s%s\" %s"
prefix
key
2021-10-12 09:31:20 +00:00
(if (string= "" comment)
2021-11-28 21:51:48 +00:00
(if (or (string= "" function)
(string= "nil" function))
2021-10-12 09:31:20 +00:00
"nil"
2021-11-28 21:51:48 +00:00
(concat "#'" function))
(format "'(%s :wk %s)"
(if (or (string= "" function)
(string= "nil" function))
":ignore t"
function)
(if (or (string= "none" comment)
(string= "nil" comment))
"t"
(concat "\"" comment "\"")))))))
2021-10-12 09:31:20 +00:00
table
"\n")
2021-06-11 14:28:25 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
** Evil
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Keybinding-Management-Eviljg30fl6184j0
:END:
2022-04-06 16:50:46 +00:00
Evil emulates most of vim’ s keybinds, because let’ s be honest here,
they are much more comfortable than Emacs’ .
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package evil
:straight (:build t)
2022-04-06 16:50:46 +00:00
:after (general)
2021-10-12 09:31:20 +00:00
:init
2022-04-06 16:50:46 +00:00
(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)
2021-11-07 01:27:04 +00:00
:config
2022-04-06 16:50:46 +00:00
<<evil-undefine-keys >>
<<evil-bepo >>
2021-10-12 09:31:20 +00:00
(evil-mode 1)
(setq evil-want-fine-undo t) ; more granular undo with evil
(evil-set-initial-state 'messages-buffer-mode 'normal)
2022-04-06 16:50:46 +00:00
(evil-set-initial-state 'dashboard-mode 'normal))
#+end_src
2021-05-21 11:59:48 +00:00
2023-03-20 16:17:57 +00:00
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 I’ m way too used to Emacs’ ~C-t~ , ~C-a~ , ~C-e~ ,
and ~C-y~ .
2022-04-06 16:50:46 +00:00
#+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)
2021-06-09 15:22:47 +00:00
2022-04-06 16:50:46 +00:00
(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)
2021-10-12 09:31:20 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2022-04-06 16:50:46 +00:00
Something else that really bugs me is I use the bépo layout, which is
2022-05-14 22:32:51 +00:00
not at all like the qwerty layout. For instance, ~hjkl~ becomes ~ctsr~ .
Thus, I need some bépo-specific changes.
2022-04-06 16:50:46 +00:00
#+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
2022-10-19 13:04:55 +00:00
"t" 'evil-next-visual-line
2022-04-06 16:50:46 +00:00
"T" 'evil-join
2022-10-19 13:04:55 +00:00
"s" 'evil-previous-visual-line
2022-04-06 16:50:46 +00:00
"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.
2021-10-12 09:31:20 +00:00
#+begin_src emacs-lisp
(use-package evil-collection
:after evil
:straight (:build t)
:config
2021-12-17 15:42:14 +00:00
;; 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)
2021-10-12 09:31:20 +00:00
(evil-collection-init))
2021-05-21 11:59:48 +00:00
#+end_src
2022-04-06 16:51:01 +00:00
~undo-tree~ is my preferred way of undoing and redoing stuff. The main
reason is it doesn’ t 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 we’ d risk
littering all of our directories. The second thing is to simply
globally enable its mode.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package undo-tree
:defer t
:straight (:build t)
2022-04-06 16:51:01 +00:00
:custom
(undo-tree-history-directory-alist
`(("." . ,(expand-file-name (file-name-as-directory "undo-tree-hist")
user-emacs-directory))))
2021-10-12 09:31:20 +00:00
:init
2022-04-06 16:51:01 +00:00
(global-undo-tree-mode)
:config
<<undo-tree-ignore-text-properties >>
<<undo-tree-compress-files >>
(setq undo-tree-visualizer-diff t
2022-11-23 16:59:21 +00:00
undo-tree-visualizer-timestamps t
2022-04-06 16:51:01 +00:00
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
2022-04-19 12:34:50 +00:00
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 it’ s
2023-03-20 16:17:57 +00:00
insignificant, and it’ s still faster than loading a heavier file.
2022-04-06 16:51:01 +00:00
#+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))
2021-05-21 11:59:48 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
** Hydra
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Keybinding-Management-Hydra0970fl6184j0
:END:
2021-06-18 16:01:41 +00:00
[[https://github.com/abo-abo/hydra ][Hydra ]] is a simple menu creator for keybindings.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package hydra
:straight (:build t)
:defer t)
2021-05-21 11:59:48 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** Hydras
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Keybinding-Management-Hydra-Hydrasvya0fl6184j0
:END:
2021-05-21 11:59:48 +00:00
The following hydra allows me to quickly zoom in and out in the
current buffer.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defhydra hydra-zoom ()
2021-06-18 16:01:41 +00:00
"
2021-10-12 09:31:20 +00:00
^Zoom^ ^Other
^^^^^^^--------------------------
[_t_ /_s_ ] zoom in/out [_q_ ] quit
[_0_ ]^^ reset zoom
"
("t" text-scale-increase "zoom in")
("s" text-scale-decrease "zoom out")
("0" text-scale-adjust "reset")
("q" nil "finished" :exit t))
2021-05-21 11:59:48 +00:00
#+end_src
Similarly, this one is also inspired from Spacemacs and allows the
user to interact with the width of the buffer in ~writeroom~ .
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defhydra writeroom-buffer-width ()
2021-06-18 16:01:41 +00:00
"
2021-10-12 09:31:20 +00:00
^Width^ ^Other
^^^^^^^^-----------------------
[_t_ ] enlarge [_r_ /_0_ ] adjust
[_s_ ] shrink [_q_ ]^^ quit
"
("q" nil :exit t)
("t" writeroom-increase-width "enlarge")
("s" writeroom-decrease-width "shrink")
("r" writeroom-adjust-width "adjust")
("0" writeroom-adjust-width "adjust"))
2021-05-21 11:59:48 +00:00
#+end_src
Another similar one is for ~mu4e-view-mode~ that allows me to shrink or
grow the ~mu4e-headers~ buffer when viewing an email.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defhydra mu4e-headers-split-adjust-width ()
2021-06-18 16:01:41 +00:00
"
2021-10-12 09:31:20 +00:00
^Zoom^ ^Other
^^^^^^^---------------------------------
[_t_ /_s_ ] shrink/enlarge view [_q_ ] quit
"
("q" nil :exit t)
("t" mu4e-headers-split-view-shrink "shrink")
("s" mu4e-headers-split-view-grow "enlarge"))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-18 16:01:41 +00:00
Similarly still, this one allows me to manage the size my Emacs
windows.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defhydra windows-adjust-size ()
2021-06-18 16:01:41 +00:00
"
2021-10-12 09:31:20 +00:00
^Zoom^ ^Other
^^^^^^^-----------------------------------------
[_t_ /_s_ ] shrink/enlarge vertically [_q_ ] quit
[_c_ /_r_ ] shrink/enlarge horizontally
"
("q" nil :exit t)
("c" shrink-window-horizontally)
("t" enlarge-window)
("s" shrink-window)
("r" enlarge-window-horizontally))
2021-06-18 16:01:41 +00:00
#+end_src
2022-06-21 14:36:31 +00:00
This one allows me to manipulate my Emacs frames’ background
transparency.
#+begin_src emacs-lisp
2022-07-05 13:29:45 +00:00
(defun my/transparency-round (val)
"Round VAL to the nearest tenth of an integer."
(/ (round (* 10 val)) 10.0))
2022-06-21 14:36:31 +00:00
(defun my/increase-frame-alpha-background ()
"Increase current frame’ s alpha background."
(interactive)
(set-frame-parameter nil
'alpha-background
2022-07-05 13:29:45 +00:00
(my/transparency-round
(min 1.0
(+ (frame-parameter nil 'alpha-background) 0.1))))
2022-06-21 14:36:31 +00:00
(message "%s" (frame-parameter nil 'alpha-background)))
(defun my/decrease-frame-alpha-background ()
"Decrease current frame’ s alpha background."
(interactive)
(set-frame-parameter nil
'alpha-background
2022-07-05 13:29:45 +00:00
(my/transparency-round
(max 0.0
(- (frame-parameter nil 'alpha-background) 0.1))))
2022-06-21 14:36:31 +00:00
(message "%s" (frame-parameter nil 'alpha-background)))
(defhydra my/modify-frame-alpha-background ()
"
^Transparency^ ^Other^
^^^^^^^^^^^^^^------------------------
2022-06-26 20:24:14 +00:00
[_t_ ] decrease transparency [_q_ ] quit
[_s_ ] increase transparency
2022-06-21 14:36:31 +00:00
"
("q" nil :exit t)
("s" my/decrease-frame-alpha-background)
("t" my/increase-frame-alpha-background))
#+end_src
2021-05-23 23:18:51 +00:00
* Packages Configuration
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configurationije0fl6184j0
:END:
2021-07-30 16:44:15 +00:00
** Autocompletion
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Autocompletionr8n1fl6184j0
:END:
*** Code Autocompletion
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Autocompletion-Code-Autocompletion4no1fl6184j0
:END:
2022-04-06 16:50:46 +00:00
Company is, in my opinion, the best autocompleting engine for Emacs,
and it is one of the most popular if not /the/ most popular.
2021-07-30 16:44:15 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(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)
2021-11-08 13:25:17 +00:00
company-auto-commit nil
2021-10-12 09:31:20 +00:00
company-auto-complete-chars nil
company-dabbrev-other-buffers nil
company-dabbrev-ignore-case nil
company-dabbrev-downcase nil))
#+end_src
2022-04-06 16:50:46 +00:00
This package is a backend for company. It emulates
~ac-source-dictionary~ by proposing text related to the current
major-mode.
2021-10-12 09:31:20 +00:00
#+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
2022-04-06 16:50:46 +00:00
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
2021-10-12 09:31:20 +00:00
#+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))
2022-04-06 16:50:46 +00:00
`(
<<gen-company-box-icons() >>))))
2021-07-30 16:44:15 +00:00
#+end_src
*** Ivy
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Autocompletion-Ivy84q1fl6184j0
:END:
2023-03-20 16:17:57 +00:00
My main menu package is =ivy= which I use as much as possible – I’ ve
noticed =helm= can be slow, very slow in comparison to =ivy= , so I’ ll 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= .
2021-07-30 16:44:15 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package ivy
:straight (:build 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)
2021-11-07 01:28:29 +00:00
("C-u" . ivy-scroll-up-command)
("C-d" . ivy-scroll-down-command)
2021-10-12 09:31:20 +00:00
: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))
2021-07-30 16:44:15 +00:00
#+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
2021-10-12 09:31:20 +00:00
(use-package ivy-prescient
:after ivy
:straight (:build t))
2021-07-30 16:44:15 +00:00
#+end_src
I warned you I’ d use too much ~all-the-icons~ , I did!
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package all-the-icons-ivy
:straight (:build t)
:after (ivy all-the-icons)
:hook (after-init . all-the-icons-ivy-setup))
2021-07-30 16:44:15 +00:00
#+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
2021-10-12 09:31:20 +00:00
(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))))
2021-07-30 16:44:15 +00:00
#+end_src
2023-03-10 14:27:50 +00:00
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
2021-07-30 16:44:15 +00:00
Finally, let’ s make ~ivy~ richer:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package ivy-rich
:straight (:build t)
:after ivy
:init
(ivy-rich-mode 1))
2021-07-30 16:44:15 +00:00
#+end_src
*** Counsel
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Autocompletion-Counselorr1fl6184j0
:END:
2022-04-06 16:50:46 +00:00
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~ .
2021-07-30 16:44:15 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package counsel
:straight (:build t)
2021-12-20 11:03:35 +00:00
:after recentf
2021-10-12 09:31:20 +00:00
: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)))
2021-07-30 16:44:15 +00:00
#+end_src
*** Yasnippet
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Autocompletion-Yasnippet68t1fl6184j0
:END:
2022-04-06 16:50:46 +00:00
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.
2021-07-30 16:44:15 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package yasnippet
:defer t
:straight (:build t)
:init
(yas-global-mode)
:hook ((prog-mode . yas-minor-mode)
(text-mode . yas-minor-mode)))
2021-07-30 16:44:15 +00:00
#+end_src
2023-03-20 16:17:57 +00:00
Of course, yasnippet wouldn’ t be as awesome as it is without pre-made
2022-04-06 16:50:46 +00:00
snippets.
2021-07-30 16:44:15 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package yasnippet-snippets
:defer t
:after yasnippet
:straight (:build t))
2021-07-30 16:44:15 +00:00
#+end_src
2023-03-20 16:17:57 +00:00
Similarly, yatemplate offers pre-made files rather than just strings.
2022-04-06 16:50:46 +00:00
That’ s still yasnippet by the way.
2021-07-30 16:44:15 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package yatemplate
:defer t
:after yasnippet
:straight (:build t))
2021-07-30 16:44:15 +00:00
#+end_src
2023-03-20 16:17:57 +00:00
And finally, with ivy you can choose your snippets from a menu if
2022-04-06 16:50:46 +00:00
you’ re not sure or if you don’ t remember what your snippet is.
2021-07-30 16:44:15 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package ivy-yasnippet
:defer t
:after (ivy yasnippet)
2022-04-06 16:50:46 +00:00
:straight (:build t)
:general
(phundrak/leader-key
:infix "i"
:packages 'ivy-yasnippet
"y" #'ivy-yasnippet))
2021-07-30 16:44:15 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
** Applications
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications94i0fl6184j0
:END:
2022-03-04 13:26:33 +00:00
*** Bitwarden
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Bitwarden-cjme4wv0rdj0
:END:
This package is still a very much work in progress one I’ m developing
in order to interact with Bitwarden in Emacs with the help of the
[[https://github.com/bitwarden/cli ][Bitwarden CLI ]]. Use at your own risks.
#+begin_src emacs-lisp
(use-package bitwarden
:defer t
:straight (bitwarden :build t
:type git
:host nil
:repo "https://labs.phundrak.com/phundrak/bitwarden.el"))
#+end_src
2021-05-23 23:18:51 +00:00
*** Docker
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Docker5ul0fl6184j0
:END:
2021-10-12 09:30:00 +00:00
Docker is an awesome tool for reproducible development environments.
Due to this, I absolutely need a mode for editing Dockerfiles.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package dockerfile-mode
:defer t
:straight (:build t)
2021-12-17 15:45:57 +00:00
:hook (dockerfile-mode . lsp-deferred)
2021-10-12 09:31:20 +00:00
:init
(put 'docker-image-name 'safe-local-variable #'stringp)
2023-01-23 09:45:46 +00:00
:mode "Dockerfile\\'"
:general
(phundrak/major-leader-key
:keymaps 'general-mode-map
:packages 'lsp-mode
"l" '(:keymap lsp-command-map :which-key "lsp")))
2021-05-21 11:59:48 +00:00
#+end_src
2022-04-06 16:50:46 +00:00
The ~docker~ package also provides interactivity with Docker and
2021-10-12 09:30:00 +00:00
docker-compose from Emacs.
#+begin_src emacs-lisp
(use-package docker
:defer t
:straight (:build t))
#+end_src
2021-05-23 23:18:51 +00:00
*** Elfeed
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Elfeedoip0fl6184j0
:END:
2021-10-20 11:58:20 +00:00
Elfeed is a nice Atom and RSS reader for Emacs. The only thing I want
to change for now is the default search filter: I want to see not only
unread news but read news as well, a bit like my emails; and where the
database is to be stored.
2021-10-14 18:07:08 +00:00
#+begin_src emacs-lisp
(use-package elfeed
:defer t
2021-10-18 15:30:12 +00:00
:straight (:build t)
2022-02-04 16:00:36 +00:00
:config
<<elfeed-open-youtube-with-mpv >>
2021-10-18 15:30:12 +00:00
:custom
2021-10-20 11:58:20 +00:00
((elfeed-search-filter "@6-months-ago")
(elfeed-db-directory (expand-file-name ".elfeed-db"
user-emacs-directory))))
2021-10-14 18:07:08 +00:00
#+end_src
2022-02-05 11:25:35 +00:00
I don’ t want YouTube videos to be open with my web browser when I
2023-03-20 16:17:57 +00:00
invoke ~elfeed-show-visit~ , so I’ ll advise this function to make it
possible to modify the behavior of said function. Oh, and I already
made [[#Packages-Configuration-Misc-Ytplay-wxm9weq0r4j0 ][a neat package ]] for playing YouTube videos and friends through
[[https://ytdl-org.github.io/youtube-dl/ ][youtube-dl ]] or its superior fork [[https://github.com/yt-dlp/yt-dlp ][yt-dlp ]] in mpv.
2022-02-04 16:00:36 +00:00
#+name : elfeed-open-youtube-with-mpv
#+begin_src emacs-lisp
(defun my/elfeed-filter-youtube-videos (orig-fun &rest args)
"Open with mpv the video leading to PATH"
(let ((link (elfeed-entry-link elfeed-show-entry)))
(when link
(if (string-match-p ".*youtube\.com.*watch.* " link)
;; This is a YouTube video, open it with mpv
2022-02-05 11:42:33 +00:00
(progn
(require 'ytplay)
(ytplay link))
2022-02-04 16:00:36 +00:00
(apply orig-fun args)))))
(advice-add 'elfeed-show-visit :around #'my/elfeed-filter-youtube-videos)
#+end_src
A future improvement to be made is to let the user chose the
resolution of the video before it is launched. I may not always have
the best internet connection, and viewing 4K videos on a 1080p display
is not something very useful.
2021-10-20 11:58:20 +00:00
Elfeed-goodies is a package which enhances the Elfeed experience.
Aside from running its setup command as soon as possible, I also set
in this code block all my keybinds for Elfeed here.
2021-10-14 18:07:08 +00:00
#+begin_src emacs-lisp
(use-package elfeed-goodies
:defer t
:after elfeed
:commands elfeed-goodies/setup
:straight (:build t)
:init
2021-10-18 15:30:12 +00:00
(elfeed-goodies/setup)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/undefine
:keymaps '(elfeed-show-mode-map elfeed-search-mode-map)
2021-11-07 14:54:20 +00:00
:packages 'elfeed
2021-11-07 01:27:04 +00:00
"DEL" nil
"s" nil)
(phundrak/evil
:keymaps 'elfeed-show-mode-map
2021-11-07 14:54:20 +00:00
:packages 'elfeed
2021-11-28 21:51:48 +00:00
<<general-keybindings-gen(table=elfeed-keybinds-show-mode) >>)
2021-11-07 01:27:04 +00:00
(phundrak/evil
:keymaps 'elfeed-search-mode-map
2021-11-07 14:54:20 +00:00
:packages 'elfeed
2021-11-28 21:51:48 +00:00
<<general-keybindings-gen(table=elfeed-keybinds-search-mode) >>)
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
:keymaps 'elfeed-search-mode-map
2021-11-07 14:54:20 +00:00
:packages 'elfeed
2021-11-28 21:51:48 +00:00
<<general-keybindings-gen(table=elfeed-keybinds-search-mode-prefixed) >>))
2021-10-14 18:07:08 +00:00
#+end_src
2021-10-20 11:58:20 +00:00
Last but not least, my Elfeed configuration is stored in an org file
thanks to ~elfeed-org~ .
2021-10-14 18:07:08 +00:00
#+begin_src emacs-lisp
(use-package elfeed-org
:defer t
:after elfeed
:straight (:build t)
2021-10-18 15:30:12 +00:00
:init
(elfeed-org)
2021-10-14 18:07:08 +00:00
:config
(setq rmh-elfeed-org-files '("~/org/elfeed.org")))
#+end_src
2021-11-28 21:51:48 +00:00
**** Keybinds
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Elfeed-Keybinds-9oeijjs0baj0
:END:
First, here are the keybinds for Elfeed’ s ~elfeed-show-mode~ . They
aren’ t prefixed by ~SPC~ like most of my keybinds, a direct keypress
will directly launch the function.
#+name : elfeed-keybinds-show-mode
| Key | Function | Comment |
|-----+-------------------------------+---------|
| + | elfeed-show-tag | |
| - | elfeed-show-untag | |
| « | elfeed-show-prev | |
| » | elfeed-show-next | |
| b | elfeed-show-visit | |
| C | elfeed-kill-link-url-at-point | |
| d | elfeed-show-save-enclosure | |
| l | elfeed-show-next-link | |
| o | elfeed-goodies/show-ace-link | |
| q | elfeed-kill-buffer | |
| S | elfeed-show-new-live-search | |
| u | elfeed-show-tag--unread | |
| y | elfeed-show-yank | |
Same thing, different mode, here are my keybinds for
~elfeed-search-mode~ .
#+name : elfeed-keybinds-search-mode
| Key | Function | Comment |
|-----+-----------------------------+---------|
| « | elfeed-search-first-entry | |
| » | elfeed-search-last-entry | |
| b | elfeed-search-browse-url | |
| f | | filter |
| fc | elfeed-search-clear-filter | |
| fl | elfeed-search-live-filter | |
| fs | elfeed-search-set-filter | |
| u | | update |
| us | elfeed-search-fetch | |
| uS | elfeed-search-update | |
| uu | elfeed-update | |
| uU | elfeed-search-update--force | |
| y | elfeed-search-yank | |
I have some additional keybinds for ~elfeed-search-mode~ , but these one
are prefixed with ~,~ (and ~M-m~ ).
#+name : elfeed-keybinds-search-mode-prefixed
| Key | Function | Comment |
|-----+--------------------------------+---------|
| c | elfeed-db-compact | |
| t | | tag |
| tt | elfeed-search-tag-all-unread | |
| tu | elfeed-search-untag-all-unread | |
| tT | elfeed-search-tag-all | |
| tU | elfeed-search-untag-all | |
2021-06-11 14:28:25 +00:00
*** Email
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email9dt0fl6184j0
:END:
2021-06-11 14:28:25 +00:00
**** Basic configuration
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Basic-configurationf7w0fl6184j0
:END:
2021-06-11 14:28:25 +00:00
As seen below, I use ~org-msg~ to compose my emails, which includes by
default my signature. Therefore, there is no need for Emacs itself to
know about it since I don’ t want it to include it a second time after
~org-msg~ already did.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setq message-signature nil
mail-signature nil)
2021-05-21 11:59:48 +00:00
#+end_src
2022-11-11 13:44:02 +00:00
**** Gnus
:PROPERTIES:
:CUSTOM_ID: PackagesConfigurationApplicationsEmailGnus-ucbe71h01nj0
:END:
#+begin_src emacs-lisp
(use-package gnus
:straight (:type built-in)
:defer t
:config
(require 'gnus-topic)
(setq gnus-select-method '(nnnil))
2022-11-18 02:52:46 +00:00
(setq gnus-secondary-select-methods '((nntp "news.gwene.org")))
2022-11-11 13:44:02 +00:00
(setq gnus-asynchronous t ;; async
gnus-use-article-prefetch 15
;; article
gnus-visible-headers (mapcar (lambda (str) (concat "^" str ":"))
'("From" "To" "Cc" "Subject" "Newsgroup"
"Date" "Followup-To" "Reply-To"
"Organization" "X-Newsreader" "X-Mailer"))
gnus-sorted-header-list gnus-visible-headers
gnus-thread-sort-functions '(gnus-thread-sort-by-number
gnus-thread-sort-by-subject
(not gnus-thread-sort-by-date))
;; group
gnus-level-subscribed 6
gnus-level-unsubscribed 7
gnus-level-zombie 8
gnus-group-sort-function '((gnus-group-sort-by-unread)
(gnus-group-sort-by-alphabet)
(gnus-group-sort-by-rank))
gnus-group-line-format "%M%p%P%5y:%B%(%g%)\n"
gnus-group-mode-line-format "%%b"
gnus-topic-display-empty-topics nil
;; summary
gnus-auto-select-first nil
gnus-summary-ignore-duplicates t
gnus-suppress-duplicates t
gnus-summary-to-prefix "To:"
gnus-summary-line-format "%U%R %-18,18&user-date; %4L:%-25,25f %B%s\n"
gnus-summary-mode-line-format "[%U] %p"
gnus-sum-thread-tree-false-root ""
gnus-sum-thread-tree-indent " "
gnus-sum-thread-tree-single-indent ""
gnus-sum-thread-tree-leaf-with-other "+->"
gnus-sum-thread-tree-root ""
gnus-sum-thread-tree-single-leaf "\\->"
gnus-sum-thread-tree-vertical "|")
(add-hook 'dired-mode-hook #'gnus-dired-mode)
(add-hook 'gnus-group-mode-hook #'gnus-topic-mode)
(add-hook 'gnus-select-group-hook #'gnus-group-set-timestamp)
(dolist (mode '(gnus-group-mode-hook gnus-summary-mode-hook gnus-browse-mode-hook))
(add-hook mode #'hl-line-mode))
:general
(phundrak/evil
:keymaps 'gnus-summary-mode-map
:packages 'gnus
"«" #'gnus-summary-prev-article
"»" #'gnus-summary-next-article)
(phundrak/major-leader-key
:keymaps 'gnus-summary-mode-map
:packages 'gnus
"d" #'gnus-summary-delete-article
"f" #'gnus-summary-mail-forward
"r" '(:ignore t :wk "reply")
"rr" #'gnus-summary-reply-with-original
"rl" #'gnus-summary-reply-to-list-with-original
"rw" #'gnus-summary-wide-reply-with-original
"rW" #'gnus-summary-very-wide-reply-with-original)
(phundrak/evil
:keymaps 'gnus-group-mode-map
:packages 'gnus
"«" #'gnus-group-prev-group
"»" #'gnus-group-next-group)
(phundrak/major-leader-key
:keymaps '(gnus-group-mode-map)
:packages 'gnus
"SPC" #'gnus-topic-read-group
"c" '(gnus-topic-catchup-articles :which-key "catchup")
"f" '(gnus-fetch-group :which-key "fetch")
"j" '(:ignore t :which-key "jump")
"jg" #'gnus-group-jump-to-group
"jt" #'gnus-topic-jump-to-topic
"L" #'gnus-group-list-all-groups
"n" #'gnus-group-news
"t" '(gnus-group-topic-map :which-key "topics")
"u" #'gnus-group-unsubscribe))
#+end_src
2021-05-21 11:59:48 +00:00
2021-06-11 14:28:25 +00:00
**** Mu4e
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e5kx0fl6184j0
:END:
2021-06-11 14:28:25 +00:00
Mu4e is a very eye-pleasing email client for Emacs, built around ~mu~
2021-11-22 15:52:55 +00:00
and which works well with ~mbsync~ (found in Arch’ s ~isync~ package). For
me, the main advantage of mu4e is it has a modern interface for
2021-06-11 14:28:25 +00:00
emailing, and quite straightforward. I tried a couple of other email
clients for Emacs, and I even was for some time a Gnus user, but in
the end, mu4e really works best for me. Below you’ ll find my
configuration for the ~mu4e~ package itself.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package mu4e
:after all-the-icons
:straight (:build t :location site)
:commands mu4e mu4e-compose-new
:init
2022-07-05 13:44:23 +00:00
(csetq mu4e-completing-read-function 'completing-read
mu4e-use-fancy-chars t
message-kill-buffer-on-exit t
mu4e-org-support nil)
(let ((dir (concat (getenv "HOME") "/Downloads/mu4e")))
2021-11-07 16:52:04 +00:00
(when (file-directory-p dir)
2022-07-05 13:44:23 +00:00
(csetq mu4e-attachment-dir dir)))
2021-11-07 16:52:04 +00:00
(defmacro mu4e-view-mode--prepare ()
`(lambda () (visual-line-mode 1)))
:gfhook ('mu4e-view-mode-hook (mu4e-view-mode--prepare))
2022-11-18 02:53:40 +00:00
:general
(phundrak/evil
:keymaps 'mu4e-main-mode-map
:packages 'mu4e
"U" #'mu4e-update-index)
2021-11-30 01:18:13 +00:00
:config
2022-06-28 21:39:56 +00:00
(require 'mu4e-view)
2022-06-26 20:23:41 +00:00
(with-eval-after-load 'mm-decode
2022-01-26 09:05:53 +00:00
(add-to-list 'mm-discouraged-alternatives "text/html")
(add-to-list 'mm-discouraged-alternatives "text-richtext"))
2021-12-04 13:18:01 +00:00
(add-hook 'mu4e-view-mode-hook (lambda () (setq truncate-lines nil)))
(add-hook 'mu4e-headers-mode-hook (lambda () (setq truncate-lines t)))
2021-11-07 14:54:20 +00:00
<<mu4e-keybindings-undef >>
<<mu4e-keybindings-view >>
2021-11-08 13:26:40 +00:00
<<mu4e-keybindings-view-no-prefix >>
2021-11-07 14:54:20 +00:00
<<mu4e-keybindings-header >>
<<mu4e-keybindings-header-no-leader >>
<<mu4e-keybindings-message >>
2021-10-12 09:31:20 +00:00
<<mu4e-mail-service >>
<<mu4e-mail-on-machine >>
<<mu4e-no-signature >>
<<mu4e-bookmarks >>
2022-05-05 14:08:48 +00:00
<<mu4e-maildirs >>
2021-10-12 09:31:20 +00:00
(when (fboundp 'imagemagick-register-types)
(imagemagick-register-types))
(require 'gnus-dired)
(setq gnus-dired-mail-mode 'mu4e-user-agent)
(add-hook 'mu4e-compose-mode-hook (lambda () (use-hard-newlines t 'guess)))
(add-hook 'mu4e-compose-mode-hook 'mml-secure-message-sign-pgpmime)
(setq mu4e-change-filenames-when-moving t
mu4e-update-interval 60
mu4e-compose-format-flowed t
mu4e-view-show-addresses t
mu4e-sent-messages-behaviour 'sent
mu4e-hide-index-messages t
mu4e-view-show-images t ; try to show images
mu4e-view-image-max-width 600
message-send-mail-function #'smtpmail-send-it ; how to send an email
smtpmail-stream-type 'starttls
message-kill-buffer-on-exit t ; close after sending
mu4e-context-policy 'pick-first ; start with first (default) context
mu4e-compose-context-policy 'ask-if-none ; compose with current context, or ask
mu4e-completing-read-function #'ivy-completing-read ; use ivy
mu4e-confirm-quit t ; no need to ask
mu4e-header-fields '((:account . 12)
(:human-date . 12)
(:flags . 4)
(:from . 25)
(:subject)))
;; set mail user agent
(setq mail-user-agent 'mu4e-user-agent)
<<mu4e-fancy-marks >>
<<mu4e-vertical-split >>
<<mu4e-headers-mode >>
(defun mu4e-action-open-as-pdf (msg)
"Export and open MSG as pdf."
(let* ((date (mu4e-message-field msg :date))
(infile (mu4e~write-body-to-html msg))
(outfile (format-time-string "/tmp/ %Y-%m-%d-%H-%M-%S.pdf" date)))
(with-temp-buffer
(shell-command
(format "wkhtmltopdf %s %s" infile outfile) t))
(find-file outfile))))
2021-06-14 12:39:20 +00:00
#+end_src
2021-10-20 17:08:42 +00:00
Quick sidenote: on ArchLinux, you’ ll need to install either ~mu~ or
~mu-git~ from the AUR in order to use mu4e. I also have a ~.desktop~ file
2023-03-20 16:17:57 +00:00
to make it possible to open mu4e directly from my program picker. It
uses the shell script ~emacsmail~ I’ ve written [[file:bin.org::#Emacsmail-afffb7cd ][here ]].
2021-12-19 14:24:43 +00:00
#+header : :mkdirp yes
2021-10-20 17:08:42 +00:00
#+begin_src conf-desktop :tangle ~/.local/share/applications/mu4e.desktop
[Desktop Entry]
Name=Mu4e
GenericName=Mu4e
Comment=Maildir Utils for Emacs
MimeType=x-scheme-handler/mailto;
Exec=/home/phundrak/ .local/bin/emacsmail %U
Icon=emacs
Type=Application
Terminal=false
Categories=Network;Email;TextEditor
StartupWMClass=Gnus
Keywords=Text;Editor;
#+end_src
2021-06-14 12:39:20 +00:00
***** Basic configuration
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Basic-configurationfxy0fl6184j0
:END:
2021-06-14 12:39:20 +00:00
First, let’ s inform Emacs how it can send emails, using which service
and how. In my case, I use my own mail server.
#+name : mu4e-mail-service
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq smtpmail-smtp-server "mail.phundrak.com"
smtpmail-smtp-service 587
smtpmail-stream-type 'starttls
message-send-mail-function 'smtpmail-send-it)
2021-06-14 12:39:20 +00:00
#+end_src
We also need to inform it on where my emails are stored on my machine,
and how to retrieve them.
#+name : mu4e-mail-on-machine
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq mu4e-get-mail-command "mbsync -a"
2021-11-08 13:25:17 +00:00
mu4e-root-maildir "~/Mail"
2021-10-12 09:31:20 +00:00
mu4e-trash-folder "/Trash"
mu4e-refile-folder "/Archive"
mu4e-sent-folder "/Sent"
mu4e-drafts-folder "/Drafts")
2021-06-14 12:39:20 +00:00
#+end_src
In the same vein of [[*Basic configuration ][this bit of configuration ]], I do not want mu4e to
insert my mail signature, ~org-msg~ already does that.
#+name : mu4e-no-signature
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq mu4e-compose-signature nil)
2021-05-23 23:18:51 +00:00
#+end_src
2021-06-11 14:28:25 +00:00
***** Bookmarks
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Bookmarkszo11fl6184j0
:END:
2021-06-11 14:28:25 +00:00
In mu4e, the main focus isn’ t really mail directories such as your
inbox, your sent messages and such, but instead you manipulate
bookmarks which will show you emails depending on tags. This mean you
can create some pretty customized bookmarks that go way beyound your
simple inbox, outbox and all. Actually, four of my bookmarks have a
couple of filtering:
- anything in my inbox linked to my university
- the [[https://emacs-doctor.com/lists/listinfo ][emacs-doctor mailing list ]] (French Emacs mailing list)
2023-02-05 22:04:56 +00:00
- emails related to my internship
2021-06-11 14:28:25 +00:00
- and my inbox for any mail not caught by any of these filters
And all of them will have the requirement not to display any trashed
email. Actually, all of my bookmarks will have this requirement,
except for the bookmark dedicated to them as well as my sent emails.
I’ ll add these latter requirements later.
Here are the requirements for my university bookmark. The regex
matches any email address which contains either ~up8.edu~ or
~univ-paris8~ , which can be found in email addresses from the University
Paris 8 (my university).
2021-10-12 13:46:16 +00:00
#+name : mu4e-bookmarks-from-copy-to-gen
2021-10-18 14:27:50 +00:00
#+begin_src emacs-lisp :tangle no :exports none :var regex="test"
2021-10-12 13:46:16 +00:00
(mapconcat (lambda (x) (concat x ":" regex))
'("f" "c" "t")
" OR ")
#+end_src
2022-01-04 17:16:34 +00:00
#+name : mu4e-bookmarks-mailing-lists
2022-02-12 11:50:07 +00:00
#+header : :tangle no :exports none
2022-01-04 17:16:34 +00:00
#+begin_src emacs-lisp :var lists=mu4e-emacs-mailing-lists
(mapconcat (lambda (list)
2023-03-11 17:37:38 +00:00
(let ((address (string-replace (regexp-quote "~")
""
(if (stringp list) list (car list)))))
2022-01-04 17:16:34 +00:00
(mapconcat (lambda (flag)
(concat flag ":" address))
2022-03-15 17:19:41 +00:00
'("list" "t" "f" "contact")
2022-01-04 17:16:34 +00:00
" OR ")))
lists
" OR ")
#+end_src
2021-06-11 14:28:25 +00:00
#+name : mu4e-bookmarks-filter-uni
2022-02-12 11:50:07 +00:00
#+header : :tangle no :cache yes
2021-06-11 14:28:25 +00:00
#+begin_src emacs-lisp
2021-10-12 13:46:16 +00:00
(let ((regex "/.*up8\\.edu|.*univ-paris8.*/ "))
2022-10-26 11:08:27 +00:00
(concat
<<mu4e-bookmarks-from-copy-to-gen >>
" OR maildir:/Univ/Inbox OR maildir:/Univ/Junk"))
2021-10-12 13:46:16 +00:00
#+end_src
2022-10-26 11:08:27 +00:00
#+RESULTS[083992a66ea6339d3a55773108e520a6024102c5]: mu4e-bookmarks-filter-uni
: f:/.*up8\.edu|.*univ-paris8.*/ OR c:/.*up8\.edu|.*univ-paris8.*/ OR t:/.*up8\.edu|.*univ-paris8.*/ OR maildir:/Univ/Inbox OR maildir:/Univ/Junk
2021-10-12 13:46:16 +00:00
Next I need an inbox dedicated to the association I’ m part of.
#+name : mu4e-bookmarks-filter-asso
2022-02-12 11:50:07 +00:00
#+header : :tangle no :cache yes
2021-10-12 13:46:16 +00:00
#+begin_src emacs-lisp
(let ((regex "/.*supran\\.fr/ "))
<<mu4e-bookmarks-from-copy-to-gen >>)
2021-06-11 14:28:25 +00:00
#+end_src
2022-01-04 17:16:34 +00:00
#+RESULTS[e04566a9d56624e063b3dd4e2c639e87cf9683aa]: mu4e-bookmarks-filter-asso
2021-10-12 13:46:16 +00:00
: f:/.*supran\.fr/ OR c:/.*supran\.fr/ OR t:/.*supran\.fr/
2021-06-11 14:28:25 +00:00
As for the Emacs-doctor list, I need to match both the current, modern
2021-12-27 17:35:08 +00:00
mailing list address but also its old address. The same applies for
2023-03-20 16:17:57 +00:00
the emacs-devel mailing list as well as GitHub emails related to my
2022-01-04 17:16:34 +00:00
package ~eshell-info-banner.el~ ([[#Packages-Configuration-Emacs-built-ins-Eshell-Visual-configuratione7c2fl6184j0 ][see here ]]). Here are the addresses to
match:
#+name : mu4e-emacs-mailing-lists
- ~/ateliers.*emacs.*/~
- ~/emacs-.*@gnu.org/~
- ~/.*eshell-info-banner.*/~
2022-05-01 16:01:44 +00:00
- ~/.*emacsfr.*/~
2022-01-04 17:16:34 +00:00
2021-06-11 14:28:25 +00:00
#+name : mu4e-bookmarks-filter-emacs-list
2022-02-12 11:50:07 +00:00
#+header : :tangle no :cache yes
2021-06-11 14:28:25 +00:00
#+begin_src emacs-lisp
2022-01-04 17:16:34 +00:00
"<<mu4e-bookmarks-mailing-lists(lists=mu4e-emacs-mailing-lists) >>"
2021-06-11 14:28:25 +00:00
#+end_src
2022-05-01 16:01:44 +00:00
#+RESULTS[88c964fba64459a050055bc5614bbd65f8740bfb]: mu4e-bookmarks-filter-emacs-list
: list:/ateliers.*emacs.*/ OR t:/ateliers.*emacs.*/ OR f:/ateliers.*emacs.*/ OR contact:/ateliers.*emacs.*/ OR list:/emacs-.*@gnu.org/ OR t:/emacs-.*@gnu.org/ OR f:/emacs-.*@gnu.org/ OR contact:/emacs-.*@gnu.org/ OR list:/.*eshell-info-banner.*/ OR t:/.*eshell-info-banner.*/ OR f:/.*eshell-info-banner.*/ OR contact:/.*eshell-info-banner.*/ OR list:/.*emacsfr.*/ OR t:/.*emacsfr.*/ OR f:/.*emacsfr.*/ OR contact:/.*emacsfr.*/
2021-06-11 14:28:25 +00:00
2021-10-12 15:00:04 +00:00
Another bookmark I wish to have is one dedicated to emails related to
2023-03-20 16:17:57 +00:00
more general development topics, including issues and PRs from GitHub.
2022-01-04 17:16:34 +00:00
#+name : mu4e-github-mailing-lists
- ~/.*\\.github\\.com/~
2022-06-10 08:40:31 +00:00
- ~/.*\\.gitlab\\.com/~
2022-02-26 14:37:42 +00:00
- ~stumpwm-devel@nongnu.org~
2022-05-01 16:01:44 +00:00
- ~/.*sr\\.ht/~
2022-01-04 17:16:34 +00:00
2021-10-12 15:00:04 +00:00
#+name : mu4e-bookmarks-filter-github-list
2022-02-12 11:50:07 +00:00
#+header : :tangle no :cache yes
2021-10-12 15:00:04 +00:00
#+begin_src emacs-lisp
2022-05-01 16:01:44 +00:00
;; "<<mu4e-bookmarks-mailing-lists(lists=mu4e-github-mailing-lists) >> AND NOT ()"
(string-join '("<<mu4e-bookmarks-mailing-lists(lists=mu4e-github-mailing-lists) >>"
"AND NOT ("
<<mu4e-bookmarks-filter-emacs-list >>
")")
" ")
2021-10-12 15:00:04 +00:00
#+end_src
2022-06-10 08:40:31 +00:00
#+RESULTS[673f76e7a682ed64f98dbe6d4a06810436ba6799]: mu4e-bookmarks-filter-github-list
: list:/.*\.github\.com/ OR t:/.*\.github\.com/ OR f:/.*\.github\.com/ OR contact:/.*\.github\.com/ OR list:/.*\.gitlab\.com/ OR t:/.*\.gitlab\.com/ OR f:/.*\.gitlab\.com/ OR contact:/.*\.gitlab\.com/ OR list:stumpwm-devel@nongnu.org OR t:stumpwm-devel@nongnu.org OR f:stumpwm-devel@nongnu.org OR contact:stumpwm-devel@nongnu.org OR list:/.*sr\.ht/ OR t:/.*sr\.ht/ OR f:/.*sr\.ht/ OR contact:/.*sr\.ht/ AND NOT ( list:/ateliers.*emacs.*/ OR t:/ateliers.*emacs.*/ OR f:/ateliers.*emacs.*/ OR contact:/ateliers.*emacs.*/ OR list:/emacs-.*@gnu.org/ OR t:/emacs-.*@gnu.org/ OR f:/emacs-.*@gnu.org/ OR contact:/emacs-.*@gnu.org/ OR list:/.*eshell-info-banner.*/ OR t:/.*eshell-info-banner.*/ OR f:/.*eshell-info-banner.*/ OR contact:/.*eshell-info-banner.*/ OR list:/.*emacsfr.*/ OR t:/.*emacsfr.*/ OR f:/.*emacsfr.*/ OR contact:/.*emacsfr.*/ )
2021-10-12 15:00:04 +00:00
2023-02-05 22:04:56 +00:00
When it comes to my internship, all emails will contain an address containing ~aubay.com~ (that’ s where my internship takes place).
- ~/.*aubay.com/~
2022-01-04 17:16:34 +00:00
2023-02-05 22:04:56 +00:00
#+name : mu4e-bookmarks-filter-aubay
2022-02-12 11:50:07 +00:00
#+header : :tangle no :cache yes
2021-06-11 14:28:25 +00:00
#+begin_src emacs-lisp
2023-02-05 22:04:56 +00:00
(let ((regex "/.*aubay\\.com/ "))
<<mu4e-bookmarks-from-copy-to-gen >>)
2021-06-11 14:28:25 +00:00
#+end_src
2023-02-05 22:04:56 +00:00
#+RESULTS[06105e10cf2addb8e11360ff2629023fad946ddf]: mu4e-bookmarks-filter-aubay
: f:/.*aubay\.com/ OR c:/.*aubay\.com/ OR t:/.*aubay\.com/
2021-06-11 14:28:25 +00:00
As I said earlier, something that will often come back in my bookmarks
is the emails must not be trashed to appear. I want also to display
junk emails, so I end up with the following rule:
#+name : mu4e-bookmarks-default-filter
2022-02-12 11:50:07 +00:00
#+header : :tangle no :cache yes
2021-06-11 14:28:25 +00:00
#+begin_src emacs-lisp
2021-12-19 12:00:26 +00:00
(mapconcat #'identity
`("NOT flag:trashed"
,(format "(%s)" (mapconcat (lambda (maildir) (concat "maildir:" maildir))
'("/Inbox" "/Junk")
" OR ")))
" AND ")
2021-06-11 14:28:25 +00:00
#+end_src
2021-12-19 12:00:26 +00:00
#+RESULTS[f3f96c07b8341c1b7b3d02688aa6faa2ceeca16f]: mu4e-bookmarks-default-filter
2021-06-11 14:28:25 +00:00
: NOT flag:trashed AND (maildir:/Inbox OR maildir:/Junk)
And for the last string-generating code, let’ s describe my main inbox:
#+name : mu4e-bookmarks-inbox-filters
2022-02-12 11:50:07 +00:00
#+header : :tangle no :cache yes
2021-06-11 14:28:25 +00:00
#+begin_src emacs-lisp
2021-12-19 12:00:26 +00:00
(mapconcat #'identity
(cons "<<mu4e-bookmarks-default-filter() >>"
`(,(format "(%s)"
2023-02-05 22:04:56 +00:00
<<mu4e-bookmarks-filter-aubay >>)
2021-12-19 12:00:26 +00:00
,(format "(%s)" "<<mu4e-bookmarks-filter-asso() >>")
,(format "(%s)"
<<mu4e-bookmarks-filter-emacs-list >>)
2021-12-27 17:35:08 +00:00
,(format "(%s)"
<<mu4e-bookmarks-filter-github-list >>)
2021-12-19 12:00:26 +00:00
,(format "(%s)"
<<mu4e-bookmarks-filter-uni >>)))
" AND NOT ")
2021-06-11 14:28:25 +00:00
#+end_src
2023-02-05 22:04:56 +00:00
#+RESULTS[94290b02a0da24cffeba43e1d47395e801bc0158]: mu4e-bookmarks-inbox-filters
: NOT flag:trashed AND (maildir:/Inbox OR maildir:/Junk) AND NOT (f:/ .*aubay\.com/ OR c:/ .*aubay\.com/ OR t:/ .*aubay\.com/) AND NOT (f:/ .*supran.fr/ OR c:/ .*supran.fr/ OR t:/ .*supran.fr/) AND NOT (list:/ateliers.*emacs.*/ OR t:/ateliers.*emacs.*/ OR f:/ateliers.*emacs.*/ OR contact:/ateliers.*emacs.*/ OR list:/emacs-.*@gnu.org/ OR t:/emacs-.*@gnu.org/ OR f:/emacs-.*@gnu.org/ OR contact:/emacs-.*@gnu.org/ OR list:/.*eshell-info-banner.*/ OR t:/.*eshell-info-banner.*/ OR f:/.*eshell-info-banner.*/ OR contact:/.*eshell-info-banner.*/ OR list:/.*emacsfr.*/ OR t:/.*emacsfr.*/ OR f:/.*emacsfr.*/ OR contact:/.*emacsfr.*/ ) AND NOT (list:/.*\.github\.com/ OR t:/.*\.github\.com/ OR f:/.*\.github\.com/ OR contact:/.*\.github\.com/ OR list:/.*\.gitlab\.com/ OR t:/.*\.gitlab\.com/ OR f:/.*\.gitlab\.com/ OR contact:/.*\.gitlab\.com/ OR list:stumpwm-devel@nongnu.org OR t:stumpwm-devel@nongnu.org OR f:stumpwm-devel@nongnu.org OR contact:stumpwm-devel@nongnu.org OR list:/.*sr\.ht/ OR t:/.*sr\.ht/ OR f:/.*sr\.ht/ OR contact:/.*sr\.ht/ AND NOT ( list:/ateliers.*emacs.*/ OR t:/ateliers.*emacs.*/ OR f:/ateliers.*emacs.*/ OR contact:/ateliers.*emacs.*/ OR list:/emacs-.*@gnu.org/ OR t:/emacs-.*@gnu.org/ OR f:/emacs-.*@gnu.org/ OR contact:/emacs-.*@gnu.org/ OR list:/.*eshell-info-banner.*/ OR t:/.*eshell-info-banner.*/ OR f:/.*eshell-info-banner.*/ OR contact:/.*eshell-info-banner.*/ OR list:/.*emacsfr.*/ OR t:/.*emacsfr.*/ OR f:/.*emacsfr.*/ OR contact:/.*emacsfr.*/ )) AND NOT (f:/.*up8\.edu|.*univ-paris8.*/ OR c:/.*up8\.edu|.*univ-paris8.*/ OR t:/.*up8\.edu|.*univ-paris8.*/ OR maildir:/Univ/Inbox OR maildir:/Univ/Junk)
2021-06-11 14:28:25 +00:00
We can finally define our bookmarks! The code reads as follows:
#+name : mu4e-bookmarks
2022-01-04 17:16:34 +00:00
#+begin_src emacs-lisp :tangle no :cache yes :results none
2021-10-12 09:31:20 +00:00
(setq mu4e-bookmarks
`((:name "Inbox"
:key ?i
:query ,(format "%s"
<<mu4e-bookmarks-inbox-filters >>))
2023-02-05 22:04:56 +00:00
(:name "Internship"
:key ?a
:query ,(format "(%s) AND (%s)"
"<<mu4e-bookmarks-default-filter() >>"
<<mu4e-bookmarks-filter-aubay >>))
2021-10-12 13:46:16 +00:00
(:name "University"
:key ?u
2021-10-12 09:31:20 +00:00
:query ,(format "%s AND %s"
2021-10-12 15:00:04 +00:00
"<<mu4e-bookmarks-default-filter() >>"
"<<mu4e-bookmarks-filter-uni() >>"))
2022-02-26 14:37:42 +00:00
(:name "Dev"
:key ?d
:query ,(format "%s AND (%s)"
2021-10-12 15:00:04 +00:00
"<<mu4e-bookmarks-default-filter() >>"
2022-02-26 14:37:42 +00:00
"<<mu4e-bookmarks-filter-github-list() >>"))
2021-10-12 09:31:20 +00:00
(:name "Emacs"
:key ?e
:query ,(format "%s AND %s"
2021-10-12 15:00:04 +00:00
"<<mu4e-bookmarks-default-filter() >>"
2021-10-12 09:31:20 +00:00
<<mu4e-bookmarks-filter-emacs-list >>))
2022-02-26 14:37:42 +00:00
(:name "Supran"
:key ?s
:query ,(format "%s AND %s"
"<<mu4e-bookmarks-default-filter() >>"
"<<mu4e-bookmarks-filter-asso() >>"))
2022-10-26 11:08:27 +00:00
(:name "Sent" :key ?S :query "maildir:/Sent OR maildir:/Univ/Sent")
2021-10-12 09:31:20 +00:00
(:name "All Unread" :key ?U :query "flag:unread AND NOT flag:trashed")
(:name "Today" :key ?t :query "date:today..now AND NOT flag:trashed")
(:name "This Week" :key ?w :query "date:7d..now AND NOT flag:trashed")
(:name "This Month" :key ?m :query "date:1m..now AND NOT flag:trashed")
(:name "This Year" :key ?y :query "date:1y..now AND NOT flag:trashed")))
#+end_src
2022-05-05 14:08:48 +00:00
***** Maildirs
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Maildirs-miy134713gj0
:END:
Sometimes, bookmarks are a bit too restrictive when I want to search
for stuff. Simply jumping to a mail directory, or maildir, is more
than enough. In mu4e, with my current setup, I can jump to any maildir
with the shortcut ~Jo~ in normal-mode, and I just need to chose in a
list the maildir I want to jump to. But it can be faster.
With this piece of code, I can simply jump to my inbox maildir with
~Ji~ , to my sent messages with ~Js~ , and so on.
#+name : mu4e-maildirs
#+begin_src emacs-lisp :tangle no
(setq mu4e-maildir-shortcuts
'((:maildir "/Inbox" :key ?i)
(:maildir "/Sent" :key ?s)
(:maildir "/Junk" :key ?j)
(:maildir "/Trash" :key ?t)))
#+end_src
2021-09-18 13:45:53 +00:00
***** Dealing with spammers
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Dealing-with-spammers-tid4mw51l7j0
:END:
I’ m sure you have received at least one email recently from a sketchy
email address asking you something that might be completely unrelated
to what you do, or at least somewhat related. Fortunately, [[https://twitter.com/Boris/status/1360208504544444417][we have a
2023-03-20 16:17:57 +00:00
hero]]! Now, let me write a function that will insert their
pre-written text at point to avoid me going back to their Twitter
thread each time I want to shut spammers up.
2021-09-18 13:45:53 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defun reply-to-bill ()
(interactive)
(insert "Please forward this email to bill@noprocurement.com,
and delete my email, as I’ ll be changing jobs soon, and this
email address will no longer be active.
2021-09-18 13:45:53 +00:00
2021-10-12 09:31:20 +00:00
Bill Whiskoney is a senior partner at Nordic Procurement
Services, and he handles our budget and will help you further or
introduce you to someone who can."))
2021-09-18 13:45:53 +00:00
#+end_src
If you want the full story, make sure to read the whole thread, I
guarantee it, it’ s worth your time! And in case the Twitter thread
disappear in the future, [[https://threader.app/thread/1360208504544444417 ][here is a backup ]].
2021-06-11 14:28:25 +00:00
***** Getting Fancy
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Getting-Fancyg731fl6184j0
:END:
2021-06-11 14:28:25 +00:00
I’ m not a huge fan of mu4e’ s default icons marking my emails, so I’ ll
redefine them as follows. Be aware the name of these icons are from
/faicon/ in the package ~all-the-icons~ .
#+name : mu4e-fancy-marks-tbl
| Mark | Flag | Icon |
|-----------+------+-------------|
| draft | D | pencil |
| flagged | F | flag |
| new | N | rss |
| passed | P | check |
| replied | R | reply |
| seen | S | eye |
| unread | u | eye-slash |
| trashed | T | trash |
| attach | a | paperclip |
| encrypted | x | lock |
| signed | s | certificate |
#+name : mu4e-fancy-marks-gen
2021-06-14 12:39:20 +00:00
#+header : :tangle no :exports none :results value :cache yes
2021-06-11 14:28:25 +00:00
#+begin_src emacs-lisp :var table=mu4e-fancy-marks-tbl
2021-10-12 09:31:20 +00:00
(mapconcat (lambda (line)
(let ((mark (car line))
(flag (cadr line))
(icon (caddr line)))
(format "mu4e-headers-%s-mark `(\"%s\" . ,(all-the-icons-faicon \"%s\" :height 0.8))"
mark
flag
icon)))
table
"\n")
2021-06-11 14:28:25 +00:00
#+end_src
2021-06-14 12:39:20 +00:00
#+RESULTS[c6ed5d4bec4c10339a7de52a70822af74d782e62]: mu4e-fancy-marks-gen
2021-06-11 14:28:25 +00:00
#+begin_example
mu4e-headers-draft-mark `("D" . ,(all-the-icons-faicon "pencil" :height 0.8))
mu4e-headers-flagged-mark `("F" . ,(all-the-icons-faicon "flag" :height 0.8))
mu4e-headers-new-mark `("N" . ,(all-the-icons-faicon "rss" :height 0.8))
mu4e-headers-passed-mark `("P" . ,(all-the-icons-faicon "check" :height 0.8))
mu4e-headers-replied-mark `("R" . ,(all-the-icons-faicon "reply" :height 0.8))
mu4e-headers-seen-mark `("S" . ,(all-the-icons-faicon "eye" :height 0.8))
mu4e-headers-unread-mark `("u" . ,(all-the-icons-faicon "eye-slash" :height 0.8))
mu4e-headers-trashed-mark `("T" . ,(all-the-icons-faicon "trash" :height 0.8))
mu4e-headers-attach-mark `("a" . ,(all-the-icons-faicon "paperclip" :height 0.8))
mu4e-headers-encrypted-mark `("x" . ,(all-the-icons-faicon "lock" :height 0.8))
mu4e-headers-signed-mark `("s" . ,(all-the-icons-faicon "certificate" :height 0.8))
#+end_example
Let’ s enable them and set them:
#+name : mu4e-fancy-marks
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq mu4e-use-fancy-chars t
<<mu4e-fancy-marks-gen() >>)
2021-06-11 14:28:25 +00:00
#+end_src
2021-09-18 13:45:53 +00:00
#+name : mu4e-vertical-split
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(defun my/set-mu4e-headers-width ()
(let ((width (window-body-width))
(threshold (+ 120 80)))
(setq mu4e-split-view (if (> width threshold)
'vertical
2022-06-10 08:39:43 +00:00
'horizontal))))
2021-09-18 13:45:53 +00:00
2021-10-12 09:31:20 +00:00
(setq mu4e-headers-visible-columns 120
mu4e-headers-visible-lines 15)
(add-hook 'mu4e-headers-mode-hook #'my/set-mu4e-headers-width)
2021-09-18 13:45:53 +00:00
#+end_src
2021-06-11 14:28:25 +00:00
***** Headers mode
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Headers-modeum41fl6184j0
:END:
2021-06-11 14:28:25 +00:00
#+name : mu4e-headers-mode
2021-06-14 12:39:20 +00:00
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(add-hook 'mu4e-headers-mode-hook (lambda () (visual-line-mode -1)))
(add-hook 'mu4e-headers-mode-hook (lambda () (toggle-truncate-lines -1)))
2021-06-11 14:28:25 +00:00
#+end_src
***** Keybindings
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Keybindingsh161fl6184j0
:END:
2021-06-11 14:28:25 +00:00
By default, Evil has some pretty annoying keybindings for users of the
bépo layout: ~hjkl~ becomes ~ctsr~ for us. Let’ s undefine some of these:
#+name : mu4e-keybindings-undef
2021-06-14 12:39:20 +00:00
#+begin_src emacs-lisp :tangle no
2021-11-07 01:27:04 +00:00
(phundrak/undefine
2021-11-07 14:54:20 +00:00
:keymaps 'mu4e-view-mode-map
:packages 'mu4e
"S" nil
"r" nil
"c" nil
"gu" nil)
2021-11-07 01:27:04 +00:00
(phundrak/undefine
:keymaps '(mu4e-view-mode-map mu4e-headers-mode-map)
2021-11-07 14:54:20 +00:00
:packages 'mu4e
"s" nil)
2021-06-11 14:28:25 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
2021-06-11 14:28:25 +00:00
Now, let’ s define some keybindings for mu4e’ s view mode, that is when
we are viewing an email. All these keybindings will reside between the
major-mode specific leader key ~,~ and most of these keybindings can be
described with a simple function:
#+name : mu4e-keybindings-view-tbl
| Keybinding | Function | Description |
|------------+--------------------------------------+--------------------|
| & | mu4e-view-pipe | |
| . | mu4e-headers-split-adjust-width/body | mu4e-headers width |
| a | nil | attachments |
| a& | mu4e-view-pipe-attachment | |
| aa | mu4e-view-attachment-action | |
| ao | mu4e-view-open-attachment | |
| aO | mu4e-view-open-attachment-with | |
| c | nil | compose |
| cc | mu4e-compose-new | |
| ce | mu4e-compose-edit | |
| cf | mu4e-compose-forward | |
| cr | mu4e-compose-reply | |
| cR | mu4e-compose-resend | |
| l | mu4e-show-log | |
| m | nil | mark |
| md | mu4e-view-mark-for-trash | |
| mD | mu4e-view-mark-for-delete | |
| mm | mu4e-view-mark-for-move | |
| mr | mu4e-view-mark-for-refile | |
| mR | mu4e-view-mark-for-read | |
| mu | mu4e-view-mark-for-unread | |
| mU | mu4e-view-mark-for-unmark | |
2021-10-12 15:00:04 +00:00
| t | mu4e-view-mark-thread | mark thread |
2021-06-11 14:28:25 +00:00
| T | nil | toggle |
| Tc | mu4e-view-toggle-hide-cited | |
| Th | mu4e-view-toggle-html | |
| n | mu4e-view-headers-next | |
| N | mu4e-view-headers-next-unread | |
| p | mu4e-view-headers-prev | |
| P | mu4e-view-headers-prev-unread | |
2021-12-06 16:07:52 +00:00
| u | nil | url |
| uf | mu4e-view-go-to-url | |
| uF | mu4e-view-fetch-url | |
2021-06-11 14:28:25 +00:00
#+name : mu4e-keybindings-view
2021-06-14 12:39:20 +00:00
#+begin_src emacs-lisp :tangle no
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:keymaps 'mu4e-view-mode-map
:packages 'mu4e
<<general-keybindings-gen(table=mu4e-keybindings-view-tbl) >>)
2021-06-11 14:28:25 +00:00
#+end_src
2021-11-08 13:26:40 +00:00
Two other keybinds are added without a prefix, just for the sake of
convenience.
#+name : mu4e-keybindings-view-no-prefix
#+begin_src emacs-lisp
(phundrak/evil
:keymaps 'mu4e-view-mode-map
:packages 'mu4e
"«" #'mu4e-view-headers-prev
"»" #'mu4e-view-headers-next)
#+end_src
2021-10-12 15:00:04 +00:00
I’ ll also declare two keybinds for mu4e’ s headers mode.
2021-06-11 14:28:25 +00:00
#+name : mu4e-keybindings-header
2021-06-14 12:39:20 +00:00
#+begin_src emacs-lisp :tangle no
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:keymaps 'mu4e-headers-mode-map
:packages 'mu4e
"t" '(mu4e-view-mark-thread :which-key "mark thread")
"s" 'swiper)
2021-06-11 14:28:25 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
2021-06-11 14:28:25 +00:00
I will also redefine without a leader key ~ctsr~ in order to be able to
move freely (remember, bépo layout for me).
2021-11-28 21:51:48 +00:00
#+name : mu4e-keybindings-header-no-leader-table
2022-10-19 13:04:55 +00:00
| Key | Function | Comment |
|-----+---------------------------+---------|
| c | evil-backward-char | |
| t | evil-next-visual-line | |
| s | evil-previous-visual-line | |
| r | evil-forward-char | |
2021-11-28 21:51:48 +00:00
2021-06-11 14:28:25 +00:00
#+name : mu4e-keybindings-header-no-leader
2021-06-14 12:39:20 +00:00
#+begin_src emacs-lisp :tangle no
2021-11-07 01:27:04 +00:00
(phundrak/evil
2021-11-07 14:54:20 +00:00
:keymaps 'mu4e-headers-mode-map
:packages 'mu4e
2021-11-28 21:51:48 +00:00
<<general-keybindings-gen(table=mu4e-keybindings-header-no-leader-table) >>)
2021-06-11 14:28:25 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
2021-06-11 14:28:25 +00:00
Finally, let’ s declare a couple of keybindings for when we are
composing a message. This time, all my keybindings are prefixed with
the major-mode leader and call a simple function.
#+name : mu4e-keybindings-message-tbl
| Key | Function | Description |
|-----+-----------------------+-------------|
| , | message-send-and-exit | |
| c | message-send-and-exit | |
| a | message-kill-buffer | |
| k | message-kill-buffer | |
| s | message-dont-send | |
2021-11-07 01:27:04 +00:00
| f | mml-attach-file | |
2021-06-11 14:28:25 +00:00
#+name : mu4e-keybindings-message
#+begin_src emacs-lisp :tangle no
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:keymaps 'message-mode-map
:packages 'mu4e
<<general-keybindings-gen(table=mu4e-keybindings-message-tbl) >>)
2021-05-23 23:18:51 +00:00
#+end_src
2021-06-11 14:28:25 +00:00
**** Composing messages
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Composing-messagesth71fl6184j0
:END:
2021-11-28 22:01:48 +00:00
Org mime is cool and all, you can write some org-mode and then export
2023-03-20 16:17:57 +00:00
it to either a plain-text or an HTML email. BUT, have you considered
skipping the export part and write your emails directly in org-mode?
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package org-msg
2022-07-06 10:55:15 +00:00
:after (mu4e)
2021-10-12 09:31:20 +00:00
:straight (:build t)
:hook ((mu4e-compose-pre . org-msg-mode))
:custom-face
(mu4e-replied-face ((t (:weight normal :foreground "#b48ead"))))
:config
(defun my/org-msg-signature-convert (orig-fun &rest args)
"Tweak my signature when replying as plain/text only."
(let ((res (apply orig-fun args)))
(when (equal (cadr args) '(text))
(setf (alist-get 'signature res)
(replace-regexp-in-string "\n+" "\n" org-msg-signature)))
res))
(advice-add 'org-msg-composition-parameters
:around 'my/org-msg-signature-convert)
(add-hook 'mu4e-headers-mode (lambda () (toggle-truncate-lines -1)))
(setq org-msg-startup "inlineimages"
2022-12-16 13:41:27 +00:00
org-msg-default-alternatives '((new . (text))
(reply-to-html . (text))
2021-10-12 09:31:20 +00:00
(reply-to-text . (text)))
org-msg-greeting-name-limit 3
org-msg-signature (format "\n--\n#+begin_signature\n%s\n#+end_signature"
2022-07-03 10:24:28 +00:00
(with-temp-buffer
(insert-file-contents mail-signature-file)
(while (re-search-forward "\n" nil t)
(replace-match "\n\n"))
(buffer-string))))
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:keymaps 'org-msg-edit-mode-map
:packages 'org-msg
2021-11-28 21:51:48 +00:00
<<general-keybindings-gen(table=org-msg-edit-mode-keybinds) >>))
2021-05-23 23:18:51 +00:00
#+end_src
2021-11-28 21:51:48 +00:00
The keybinds are relatively simple ~org-msg-edit-mode~ :
#+name : org-msg-edit-mode-keybinds
| Key | Function | Description |
|-----+-----------------------+-------------|
| , | message-send-and-exit | |
| c | message-send-and-exit | |
| a | message-kill-buffer | |
| k | message-kill-buffer | |
| s | message-dont-send | |
| f | org-msg-attach | |
2021-06-11 16:33:19 +00:00
**** Email alerts
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Email-Email-alertsfx81fl6184j0
:END:
2021-06-11 16:33:19 +00:00
There is also a package for mu4e which generates desktop notifications
when new emails are received. By default, I want to be notified by all
messages in my inbox and junk folder. Also, I’ ll use Emacs’ default
notification system, and I’ ll activate the modeline notification.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package mu4e-alert
:straight (:build t)
2021-11-24 22:43:28 +00:00
:after mu4e
2021-10-12 09:31:20 +00:00
:defer t
:init
(add-hook 'after-init-hook #'mu4e-alert-enable-notifications)
(add-hook 'after-init-hook #'mu4e-alert-enable-mode-line-display)
(mu4e-alert-set-default-style 'notifications)
:config
(setq mu4e-alert-interesting-mail-query "flag:unread"))
2021-05-23 23:18:51 +00:00
#+end_src
2021-10-22 10:09:22 +00:00
*** EMMS and Media
2021-10-20 12:00:01 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-EMMS-ij71fr61v8j0
:END:
EMMS, also known as the /Emacs MultiMedia System/ , allows the user to
interact through Emacs with multimedia elements such as music and
videos. My main use for it will be for music with MPD (see its
configuration [[file:mpd.org ][here ]]).
#+begin_src emacs-lisp
(use-package emms
:defer t
2021-10-22 10:09:22 +00:00
:after all-the-icons
2021-10-20 12:00:01 +00:00
:straight (:build t)
:init
(require 'emms-setup)
2021-11-28 22:02:35 +00:00
(require 'emms-mark)
2021-10-20 12:00:01 +00:00
(emms-all)
(add-to-list 'emms-info-functions 'emms-info-mpd)
(add-to-list 'emms-player-list 'emms-player-mpd)
2021-11-09 12:39:34 +00:00
(emms-player-mpd-sync-from-mpd)
2021-10-20 12:00:01 +00:00
(emms-player-mpd-connect)
2021-11-28 22:02:35 +00:00
<<emms-fd-name >>
<<emms-fd-function >>
<<emms-search-set-variable >>
2021-10-22 10:09:22 +00:00
<<emms-media-hydra >>
2021-11-09 12:39:34 +00:00
(defun emms-player-toggle-pause ()
(interactive)
(shell-command-and-echo "mpc toggle"))
2021-10-20 12:00:01 +00:00
:custom
((emms-source-file-default-directory (expand-file-name "~/Music"))
(emms-player-mpd-server-name "localhost")
(emms-player-mpd-server-port "6600")
2021-11-28 22:02:35 +00:00
(emms-player-mpd-music-directory (expand-file-name "~/Music"))
(emms-browser-thumbnail-small-size 64)
(emms-browser-thumbnail-medium-size 128)
(emms-browser-covers #'emms-browser-cache-thumbnail-async)
(emms-playlist-default-major-mode 'emms-mark-mode))
2021-11-07 14:54:20 +00:00
:general
(phundrak/undefine
:keymaps 'emms-browser-mode-map
:packages 'emms
"s" nil
"r" nil)
(phundrak/evil
:keymaps 'emms-browser-mode-map
:packages 'emms
"a" #'emms-browser-add-tracks
"A" #'emms-browser-add-tracks-and-play
2021-11-28 21:51:48 +00:00
"b" '(:ignore t :which-key "browse by")
2021-11-07 14:54:20 +00:00
"bA" #'emms-browse-by-album
"ba" #'emms-browse-by-artist
"bg" #'emms-browse-by-genre
"bs" #'emms-smart-browse
"by" #'emms-browse-by-year
"c" #'emms-browser-clear-playlist
2021-11-28 21:51:48 +00:00
"S" '(:ignore t :which-key "search")
2021-11-07 14:54:20 +00:00
"SA" '(emms-browser-search-by-album :which-key "by album")
"Sa" '(emms-browser-search-by-artist :which-key "by artist")
"Ss" '(emms-browser-search-by-names :which-key "by name")
"St" '(emms-browser-search-by-names :which-key "by title")
"q" #'kill-this-buffer)
(phundrak/evil
:keymaps 'emms-playlist-mode-map
:packages 'emms
"d" #'emms-playlist-mode-kill-track
"p" #'emms-playlist-mode-play-smart
"q" #'kill-this-buffer)
(phundrak/leader-key
:infix "m"
:packages 'emms
2021-11-28 21:51:48 +00:00
"" '(:ignore t :which-key "media")
2021-11-07 14:54:20 +00:00
"." #'hydra-media/body
"«" #'emms-player-mpd-previous
"»" #'emms-player-mpd-next
"c" #'emms-player-mpd-clear
2021-11-28 21:51:48 +00:00
"e" '(:ignore t :which-key "emms")
2021-11-07 14:54:20 +00:00
"eb" #'emms-browser
"ep" #'emms-playlist-mode-go
"es" #'emms-player-mpd-show
"p" '((lambda ()
(interactive)
(shell-command-and-echo "mpc toggle"))
:which-key "mpc toggle")
2021-11-27 18:29:55 +00:00
"s" #'emms-stop
2021-11-28 21:51:48 +00:00
"u" '(:ignore t :which-key "update")
2021-11-07 14:54:20 +00:00
"um" #'emms-player-mpd-update-all
"uc" #'emms-cache-set-from-mpd-all))
2021-10-20 12:00:01 +00:00
#+end_src
2021-11-28 22:02:35 +00:00
**** Finding files from EMMS
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-EMMS-and-Media-Finding-files-from-EMMS-as6fgpv0baj0
:header-args:emacs-lisp: :tangle no
:END:
EMMS has two default ways of finding files: either a built-in function
relatively slow but portable, or with ~find~ which is arguably faster
but less portable. Honestly, I don’ t care about portability, I’ ll
always use this Emacs config on Linux, but I don’ t want to use ~find~
either since there is something even faster: ~fd~ .
First we’ ll declare a variable that can hold the path to the ~fd~
executable:
#+name : emms-fd-name
#+begin_src emacs-lisp
(defvar emms-source-file-fd (executable-find "fd"))
#+end_src
Then, we need to declare a new function that will use ~fd~ to find
files. The function, as specified by the documentation of
~emms-source-file-directory-tree-function~ , receives two arguments ~dir~
and ~regex~ . We can work with that!
#+name : emms-fd-function
#+begin_src emacs-lisp
(defun emms-source-file-directory-tree-fd (dir regex)
"Return a list of all files under DIR that match REGEX.
This function uses the external fd utility. The name for fd may
be supplied using `emms-source-file-fd'."
(with-temp-buffer
(call-process emms-source-file-fd
nil t nil
"-L" ; follow symlinks
regex
"-t f"
(expand-file-name dir))
(delete ""
(split-string (buffer-substring (point-min)
(point-max))
"\n"))))
#+end_src
We can finally set this function as our search function.
#+name : emms-search-set-variable
#+begin_src emacs-lisp
(setq emms-source-file-directory-tree-function #'emms-source-file-directory-tree-fd)
#+end_src
2021-11-28 21:51:48 +00:00
**** Keybinds
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-EMMS-and-Media-Keybinds-ue071zv0baj0
:header-args:emacs-lisp: :tangle no
:END:
2021-10-22 10:09:22 +00:00
I also want to create a small hydra for manipulating MPD:
#+name : emms-media-hydra
2021-11-28 21:51:48 +00:00
#+begin_src emacs-lisp
2021-10-29 14:30:03 +00:00
(defun shell-command-and-echo (command &optional echo prefix)
"Run COMMAND and display the result of ECHO prefixed by PREFIX.
Run COMMAND as a shell command.
If ECHO is non nil, display the result of its execution as a
shell command to the minibuffer through `MESSAGE'.
If PREFIX is non nil, it will prefix the output of ECHO in the
minibuffer, both separated by a single space."
2021-10-25 14:56:58 +00:00
(progn
(with-temp-buffer
(shell-command command
(current-buffer)
(current-buffer))
(when echo
2021-10-29 14:30:03 +00:00
(message "%s%s"
(if prefix
(concat prefix " ")
"")
2021-10-25 14:56:58 +00:00
(string-trim
(shell-command-to-string "mpc volume")))))))
2021-12-12 14:03:36 +00:00
(defhydra hydra-media (:hint nil)
2021-10-25 14:56:58 +00:00
"
2021-12-12 14:03:36 +00:00
%s(all-the-icons-material \"volume_up\" :height 1.0 :v-adjust -0.2)
[_s_ ]
« [_c_ ] _p_ [_r_ ] » [_S_ ] %s(all-the-icons-material \"stop\")
[_t_ ]
%s(all-the-icons-material \"volume_down\" :height 1.0 :v-adjust -0.2)
2021-10-22 10:09:22 +00:00
"
2021-10-25 14:56:58 +00:00
("c" emms-player-mpd-previous)
("r" emms-player-mpd-next)
2021-10-29 14:30:03 +00:00
("t" (shell-command-and-echo "mpc volume -2" "mpc volume" "mpc"))
("s" (shell-command-and-echo "mpc volume +2" "mpc volume" "mpc"))
2021-10-25 14:56:58 +00:00
("p" (shell-command-and-echo "mpc toggle"))
("S" emms-player-mpd-stop)
("q" nil :exit t))
2021-10-22 10:09:22 +00:00
#+end_src
2021-10-20 12:00:01 +00:00
2021-06-11 16:34:08 +00:00
*** Nov
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Nov0da1fl6184j0
:END:
2021-06-22 14:30:09 +00:00
Nov is a major-mode for reading EPUB files within Emacs. Since I have
it, I don’ t need any other Epub reader on my computer! Plus this one
is customizable and programmable, why would I use any other EPUB
reader?
2021-06-11 16:34:08 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package nov
:straight (:build t)
:defer t
:mode ("\\.epub\\'" . nov-mode)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
2021-11-07 14:54:20 +00:00
:keymaps 'nov-mode-map
:packages 'nov
"c" #'nov-previous-document
"t" #'nov-scroll-up
"C-d" #'nov-scroll-up
"s" #'nov-scroll-down
"C-u" #'nov-scroll-down
"r" #'nov-next-document
"gm" #'nov-display-metadata
"gn" #'nov-next-document
"gp" #'nov-previous-document
"gr" #'nov-render-document
"gt" #'nov-goto-toc
"gv" #'nov-view-source
"gV" #'nov-view-content-source)
:config
2021-10-12 09:31:20 +00:00
(setq nov-text-width 95))
2021-06-11 16:34:08 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** PDF Tools
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-PDF-Toolsvqb1fl6184j0
:END:
2021-10-20 11:58:20 +00:00
~pdf-tools~ enables PDF support for Emacs, much better than its built-in
support with DocView. Aside from the classical settings such as
keybinds, I also enable the midnight colors by default; think of it as
an equivalent of Zathura’ s recolor feature which kind of enables a
dark mode for PDFs.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package pdf-tools
:defer t
:magic ("%PDF" . pdf-view-mode)
2022-02-04 16:01:30 +00:00
:straight (:build t)
2021-10-12 09:31:20 +00:00
:hook (pdf-tools-enabled . pdf-view-midnight-minor-mode)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
:keymaps 'pdf-view-mode-map
2021-11-07 14:54:20 +00:00
:packages 'pdf-tools
2021-11-07 01:27:04 +00:00
"y" #'pdf-view-kill-ring-save
"t" #'evil-collection-pdf-view-next-line-or-next-page
"s" #'evil-collection-pdf-view-previous-line-or-previous-page)
(phundrak/major-leader-key
:keymaps 'pdf-view-mode-map
2021-11-07 14:54:20 +00:00
:packages 'pdf-tools
2021-11-28 21:51:48 +00:00
"a" '(:ignore t :which-key "annotations")
2021-10-20 11:58:20 +00:00
"aD" #'pdf-annot-delete
"at" #'pdf-annot-attachment-dired
"ah" #'pdf-annot-add-highlight-markup-annotation
"al" #'pdf-annot-list-annotations
"am" #'pdf-annot-markup-annotation
"ao" #'pdf-annot-add-strikeout-markup-annotation
"as" #'pdf-annot-add-squiggly-markup-annotation
"at" #'pdf-annot-add-text-annotation
"au" #'pdf-annot-add-underline-markup-annotation
2021-11-28 21:51:48 +00:00
"f" '(:ignore t :which-key "fit")
2021-10-20 11:58:20 +00:00
"fw" #'pdf-view-fit-width-to-window
"fh" #'pdf-view-fit-height-to-window
"fp" #'pdf-view-fit-page-to-window
2021-11-28 21:51:48 +00:00
"s" '(:ignore t :which-key "slice/search")
2021-10-20 11:58:20 +00:00
"sb" #'pdf-view-set-slice-from-bounding-box
"sm" #'pdf-view-set-slice-using-mouse
"sr" #'pdf-view-reset-slice
"ss" #'pdf-occur
"o" 'pdf-outline
"m" 'pdf-view-midnight-minor-mode)
2021-11-07 14:54:20 +00:00
:config
2021-10-20 11:58:20 +00:00
(with-eval-after-load 'pdf-view
2022-10-19 13:05:47 +00:00
(csetq pdf-view-midnight-colors '("#d8dee9" . "#2e3440"))))
2021-10-12 09:31:20 +00:00
#+end_src
2021-10-20 11:58:20 +00:00
One thing ~pdf-tools~ doesn’ t handle is restoring the PDF to the last
point it was visited --- in other words, open the PDF where I last
left it.
2021-10-12 09:31:20 +00:00
#+begin_src emacs-lisp
(use-package pdf-view-restore
:after pdf-tools
2021-10-19 19:41:47 +00:00
:defer t
:straight (:build t)
:hook (pdf-view-mode . pdf-view-restore-mode)
:config
(setq pdf-view-restore-filename (expand-file-name ".tmp/pdf-view-restore"
user-emacs-directory)))
2021-06-09 15:22:47 +00:00
#+end_src
2021-06-18 09:11:48 +00:00
*** Project Management
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Project-Managementi9n5fl6184j0
:END:
**** Magit
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Project-Management-Magitvso5fl6184j0
:END:
Magit is an awesome wrapper around Git for Emacs! Very often, I go
from disliking to really hating Git GUI clients because they often
obfuscate which Git commands are used to make things happen. Such a
2023-03-20 16:17:57 +00:00
thing doesn’ t happen with Magit, it’ s pretty transparent, but it still
2021-06-18 09:11:48 +00:00
provides some awesome features and visualizations of what you are
doing and what Git is doing! In short, I absolutely love it!
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package magit
:straight (:build t)
:defer t
2022-05-17 15:24:27 +00:00
:init
2022-07-03 10:26:30 +00:00
(setq forge-add-default-bindings nil)
2021-11-18 19:07:12 +00:00
:config
2022-07-03 10:26:30 +00:00
(csetq magit-clone-default-directory "~/fromGIT/ "
magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)
2022-04-19 12:31:07 +00:00
(with-eval-after-load 'evil-collection
(phundrak/evil
:packages '(evil-collection magit)
:keymaps '(magit-mode-map magit-log-mode-map magit-status-mode-map)
:states 'normal
"t" #'magit-tag
"s" #'magit-stage))
2021-11-07 14:54:20 +00:00
:general
(:keymaps '(git-rebase-mode-map)
:packages 'magit
2021-10-12 09:31:20 +00:00
"C-t" #'evil-next-line
"C-s" #'evil-previous-line)
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
:keymaps 'git-rebase-mode-map
2021-11-07 14:54:20 +00:00
:packages 'magit
2021-11-07 01:27:04 +00:00
"," #'with-editor-finish
"k" #'with-editor-cancel
"a" #'with-editor-cancel)
(phundrak/leader-key
2021-11-07 14:54:20 +00:00
:infix "g"
:packages 'magit
2021-11-28 21:51:48 +00:00
"" '(:ignore t :wk "git")
2021-11-07 14:54:20 +00:00
"b" #'magit-blame
"c" #'magit-clone
"d" #'magit-dispatch
"i" #'magit-init
"s" #'magit-status
2023-03-10 14:22:30 +00:00
"l" #'magit-log
2021-11-07 14:54:20 +00:00
"y" #'my/yadm
"S" #'magit-stage-file
"U" #'magit-unstage-file
2021-11-28 21:51:48 +00:00
"f" '(:ignore t :wk "file")
2021-11-07 14:54:20 +00:00
"fd" #'magit-diff
"fc" #'magit-file-checkout
"fl" #'magit-file-dispatch
"fF" #'magit-find-file))
2021-06-18 09:11:48 +00:00
#+end_src
[[https://github.com/alphapapa ][Alphapapa ]] also created an awesome package for Magit: magit-todos which
display in the Magit buffer a list of TODOs found in the current
project to remind you of what to do next.
2022-01-07 02:37:34 +00:00
2023-03-20 16:17:57 +00:00
First, let’ s se tup our todo keywords with ~hl-todo~ . A good few todo
2022-01-07 02:37:34 +00:00
keywords are already defined in the ~hl-todo-keyword-faces~ variable.
Why not use them? ~hl-todo-mode~ enables fontlock highlight of these
keywords in a buffer. Let’ s enable this mode globally.
#+begin_src emacs-lisp
(use-package hl-todo
:defer t
:straight (:build t)
:init (global-hl-todo-mode 1)
:general
(phundrak/leader-key
:packages '(hl-todo)
:infix "c"
"" '(:ignore t :which-key "todos")
"n" #'hl-todo-next
"p" #'hl-todo-previous))
#+end_src
2022-07-06 19:05:10 +00:00
We can now configure properly ~magit-todos~ . Notice my custom function
hooked to ~magit-mode-hook~ . This is because this package tries to find
TODOs in all files in the current project, and my yadm repository’ s
root is my ~$HOME~ . So, yeah, no ~magit-todos~ in yadm.
2021-06-18 09:11:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package magit-todos
:straight (:build t)
2022-01-07 02:37:34 +00:00
:after (magit hl-todo)
2022-07-06 19:05:10 +00:00
:init
(with-eval-after-load 'magit
(defun my/magit-todos-if-not-yadm ()
"Deactivate magit-todos if in yadm Tramp connection.
If `magit--default-directory' points to a yadm Tramp directory,
deactivate `magit-todos-mode', otherwise enable it."
(if (string-prefix-p "/yadm:" magit--default-directory)
(magit-todos-mode -1)
(magit-todos-mode +1)))
(add-hook 'magit-mode-hook #'my/magit-todos-if-not-yadm))
2021-10-12 09:31:20 +00:00
:config
2022-07-06 19:05:10 +00:00
(csetq magit-todos-ignore-case t))
2021-06-18 09:11:48 +00:00
#+end_src
2021-07-30 16:46:04 +00:00
Finally, it is also possible to use Gitflow’ s framework with Magit
with ~magit-gitflow~ :
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package magit-gitflow
:defer t
:after magit
:straight (magit-gitflow :build t
:type git
:host github
:repo "jtatarik/magit-gitflow")
:hook (magit-mode . turn-on-magit-gitflow))
2021-07-30 16:46:04 +00:00
#+end_src
2021-06-18 09:11:48 +00:00
**** Forge
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Project-Management-Forgelcq5fl6184j0
:END:
2023-03-20 16:17:57 +00:00
Forge acts as an interface for GitHub, Gitlab, and Bitbucket inside
2022-04-06 16:50:46 +00:00
Magit. A lot of possibilities are present, you can read issues and
pull requests, create them, and fork projects among other things.
2021-06-18 09:11:48 +00:00
*NOTE* : Make sure to configure a GitHub token before using this
package!
- [[https://magit.vc/manual/forge/Token-Creation.html#Token-Creation ][Token Creation ]]
- [[https://magit.vc/manual/ghub/Getting-Started.html#Getting-Started ][Getting started ]]
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package forge
:after magit
2022-10-19 13:05:47 +00:00
:straight (:build t)
2022-12-07 15:07:32 +00:00
:init
(evil-collection-forge-setup)
2022-10-19 13:05:47 +00:00
:general
(phundrak/major-leader-key
:keymaps 'forge-topic-mode-map
"c" #'forge-create-post
"e" '(:ignore t :which-key "edit")
"ea" #'forge-edit-topic-assignees
"ed" #'forge-edit-topic-draft
"ek" #'forge-delete-comment
"el" #'forge-edit-topic-labels
"em" #'forge-edit-topic-marks
"eM" #'forge-merge
"en" #'forge-edit-topic-note
"ep" #'forge-edit-post
"er" #'forge-edit-topic-review-requests
"es" #'forge-edit-topic-state
"et" #'forge-edit-topic-title))
2021-06-18 09:11:48 +00:00
#+end_src
**** Projectile
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Project-Management-Projectilesvr5fl6184j0
:END:
2022-04-06 16:50:46 +00:00
First, I need to install ~ripgrep~ , a faster reimplementation of ~grep~ ,
which will be very useful when managing projects.
2021-07-30 16:46:04 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package ripgrep
2022-04-06 16:50:46 +00:00
:if (executable-find "rg")
2021-10-12 09:31:20 +00:00
:straight (:build t)
:defer t)
2021-07-30 16:46:04 +00:00
#+end_src
2022-04-06 16:50:46 +00:00
Now, I can use projectile, which is sort of the /de facto/ standard
2023-03-20 16:17:57 +00:00
project manager in Emacs. I know there’ s ~project.el~ , but… Eh… I’ m used
to projectile.
2021-06-18 09:11:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package projectile
:straight (:build t)
:diminish projectile-mode
:custom ((projectile-completion-system 'ivy))
:init
(setq projectile-switch-project-action #'projectile-dired)
:config
2022-04-06 16:50:46 +00:00
(projectile-mode)
(add-to-list 'projectile-ignored-projects "~/")
2022-08-07 10:55:51 +00:00
(add-to-list 'projectile-globally-ignored-directories "^node_modules$")
2022-04-06 16:50:46 +00:00
:general
(phundrak/leader-key
"p" '(:keymap projectile-command-map :which-key "projectile")))
2021-09-18 13:50:07 +00:00
#+end_src
2021-06-18 09:11:48 +00:00
2022-04-06 16:50:46 +00:00
And of course, there is a counsel package dedicated to projectile.
2021-09-18 13:50:07 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package counsel-projectile
:straight (:build t)
:after (counsel projectile)
:config (counsel-projectile-mode))
2021-06-18 09:11:48 +00:00
#+end_src
2021-12-20 11:03:35 +00:00
**** Recentf
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Project-Management-Recentf-kndiupi04bj0
:END:
The built-in package ~recentf~ keeps track of recently opened files. But
by default, it only follows the twenty most recent files, that not
nearly enough for me, so I raise it to two hundred. I also don’ t want
recentf to follow the Elfeed database, so I add it to the list of
excluded files.
#+begin_src emacs-lisp
(use-package recentf
:straight (:build t :type built-in)
2022-03-06 21:16:15 +00:00
:custom ((recentf-max-saved-items 2000))
2022-03-04 13:26:52 +00:00
:config
2022-05-06 17:48:12 +00:00
(add-all-to-list 'recentf-exclude
`(,(rx (* any)
(or "elfeed-db"
"eln-cache"
"conlanging/content"
"org/config"
"/Mail/Sent"
".cache/")
(* any)
(? (or "html" "pdf" "tex" "epub")))
2023-01-23 09:44:44 +00:00
,(rx (* any)
".elc"
eol)
2022-05-06 17:48:12 +00:00
,(rx "/"
2022-05-20 16:18:08 +00:00
(or "rsync" "ssh" "tmp" "yadm" "sudoedit" "sudo")
2022-05-06 17:48:12 +00:00
(* any)))))
2021-12-20 11:03:35 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** Screenshot
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Screenshot96d1fl6184j0
:END:
2022-04-06 16:50:46 +00:00
~screenshot.el~ is a nice utility package made by TEC. It allows the
user to take a screenshot of a specific area of a buffer and make it
look nice.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package screenshot
:defer t
:straight (screenshot :build t
:type git
:host github
2021-12-12 14:02:34 +00:00
:repo "tecosaur/screenshot")
2022-01-07 02:37:46 +00:00
:config (load-file (locate-library "screenshot.el"))
:general
(phundrak/leader-key
:infix "a"
:packages '(screenshot)
"S" #'screenshot))
2021-05-23 23:18:51 +00:00
#+end_src
*** Shells
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Shellsxke1fl6184j0
:END:
2021-05-23 23:18:51 +00:00
**** Shell-pop
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Shells-Shell-popk0g1fl6184j0
:END:
2021-05-23 23:18:51 +00:00
Shell-pop allows the user to easily call for a new shell in a pop-up
buffer.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package shell-pop
:defer t
:straight (:build t)
:custom
(shell-pop-default-directory "/home/phundrak")
2021-10-12 09:25:39 +00:00
(shell-pop-shell-type (quote ("eshell" "*eshell* " (lambda () (eshell shell-pop-term-shell)))))
2021-10-12 09:31:20 +00:00
(shell-pop-window-size 30)
(shell-pop-full-span nil)
(shell-pop-window-position "bottom")
(shell-pop-autocd-to-working-dir t)
(shell-pop-restore-window-configuration t)
(shell-pop-cleanup-buffer-at-process-exit t))
2021-05-23 23:18:51 +00:00
#+end_src
**** VTerm
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Shells-VTermzfh1fl6184j0
:END:
2022-04-06 16:50:46 +00:00
VTerm gives Emacs access to regular shells with an almost regular
emulator. Be aware you will most likely need to hit ~C-c~ twice to send
an interrupt signal.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package vterm
:defer t
:straight t
:config
(setq vterm-shell "/usr/bin/fish"))
2021-05-23 23:18:51 +00:00
#+end_src
2022-07-03 10:26:04 +00:00
One annoying think with vterm is it only can create one buffer, you
can’ t have multiple vterm buffers by default. ~multi-vterm~ fixes this
issue.
#+begin_src emacs-lisp
(use-package multi-vterm
:after vterm
:defer t
:straight (:build t)
:general
(phundrak/major-leader-key
:packages '(vterm multi-vterm)
:keymap 'vterm-mode-map
"c" #'multi-vterm
"n" #'multi-vterm-next
"p" #'multi-vterm-prev))
#+end_src
2021-06-09 15:33:38 +00:00
*** XWidgets Webkit Browser
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-XWidgets-Webkit-Browsertui1fl6184j0
:END:
2021-11-24 23:53:04 +00:00
I used to use the xwidgets webkit browser in order to view or preview
HTML files from Emacs, but it seems the Cairo background transparency
patch breaks it. So while this isn’ t patched, I will disable Xwidgets
in my Emacs build, and these keybinds *will not* be tangled.
#+begin_src emacs-lisp :tangle no
2021-11-07 01:27:04 +00:00
(phundrak/evil
2021-10-12 09:31:20 +00:00
:keymaps 'xwidget-webkit-mode-map
"<mouse-4 >" #'xwidget-webkit-scroll-down-line
"<mouse-5 >" #'xwidget-webkit-scroll-up-line
2021-11-07 01:27:04 +00:00
"c" #'xwidget-webkit-scroll-backward
"t" #'xwidget-webkit-scroll-up-line
"s" #'xwidget-webkit-scroll-down-line
"r" #'xwidget-webkit-scroll-forward
"h" #'xwidget-webkit-goto-history
"C" #'xwidget-webkit-back
"R" #'xwidget-webkit-forward
"C-r" #'xwidget-webkit-reload
"j" nil
"k" nil
"l" nil
"H" nil
"L" nil
"C-d" #'xwidget-webkit-scroll-up
"C-u" #'xwidget-webkit-scroll-down)
2021-05-23 23:18:51 +00:00
#+end_src
*** Wttr.in
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Wttr-inpak1fl6184j0
:END:
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package wttrin
:defer t
:straight (wttrin :build t
:local-repo "~/fromGIT/emacs-packages/emacs-wttrin"
:type git)
;; :host github
;; :repo "Phundrak/emacs-wttrin"
:config
(setq wttrin-default-cities '("Aubervilliers" "Paris" "Lyon" "Nonières" "Saint Agrève")
wttrin-use-metric t))
2021-05-23 23:18:51 +00:00
#+end_src
**** TODO Derive a major mode for wttrin :noexport:
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Applications-Wttr-in-Derive-a-major-mode-for-wttrinkrl1fl6184j0
:END:
2021-05-23 23:18:51 +00:00
To handle keybindings correctly, a major mode for wttrin could be
derived from ~fundamental-mode~ and get an associated keymap.
2021-07-30 16:44:15 +00:00
** Editing
2021-06-16 12:30:03 +00:00
:PROPERTIES:
2021-07-30 16:44:15 +00:00
:CUSTOM_ID: Packages-Configuration-Editinggnu1fl6184j0
2021-06-16 12:30:03 +00:00
:END:
2021-07-30 16:44:15 +00:00
First, I’ ll define some keybindings for easily inserting pairs when
editing text.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(general-define-key
:states 'visual
"M-[" #'insert-pair
"M-{" #'insert-pair
"M-<" #'insert-pair
"M-'" #'insert-pair
"M-`" #'insert-pair
"M-\"" #'insert-pair)
2021-05-21 11:59:48 +00:00
#+end_src
2021-10-25 15:00:16 +00:00
*** Atomic Chrome
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-Atomic-Chrome-2w5bt8y029j0
:END:
Why write in your browser when you could write with Emacs? Despite its
name, this package isn’ t only geared towards Chrome/Chromium-based
browsers but also towards Firefox since its 2.0 version. I find it a
bit unfortunate Chrome’ s name stuck in the package’ s name though.
#+begin_src emacs-lisp
(use-package atomic-chrome
:straight (:build t)
:init
2022-05-14 22:33:15 +00:00
(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)
2022-05-19 16:19:26 +00:00
("labs\\.phundrak\\.com" . markdown-mode)
2022-05-31 18:59:59 +00:00
("reddit\\.com" . markdown-mode))))
2021-10-25 15:00:16 +00:00
#+end_src
2022-01-07 20:08:51 +00:00
*** Editorconfig
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-Editorconfig-txn4dtx0rbj0
:END:
2022-04-06 16:50:46 +00:00
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.
2022-01-07 20:08:51 +00:00
#+begin_src emacs-lisp
(use-package editorconfig
:defer t
:straight (:build t)
:diminish editorconfig-mode
2023-01-23 09:45:05 +00:00
:init
2022-01-07 20:08:51 +00:00
(editorconfig-mode t))
#+end_src
2021-05-21 11:59:48 +00:00
*** Evil Nerd Commenter
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-Evil-Nerd-Commenterd2w1fl6184j0
:END:
2021-06-18 08:26:28 +00:00
Emacs’ default commenting system is nice, but I don’ t find it smart
enough for me.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package evil-nerd-commenter
:after evil
:straight (:build t))
2021-05-21 11:59:48 +00:00
#+end_src
2021-10-18 15:31:45 +00:00
*** Iedit
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-Iedit-eb98g8q0p8j0
:END:
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
2022-09-19 10:37:57 +00:00
region or in a whole buffer. Since I’ m using evil, I’ ll also use a
compatibility package that adds states for iedit.
2021-10-18 15:31:45 +00:00
#+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
2022-09-19 10:37:57 +00:00
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))
2021-10-18 15:31:45 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
*** Parinfer
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-Parinfermxy1fl6184j0
:END:
2021-06-09 15:22:47 +00:00
Don’ t 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
2021-11-22 10:17:42 +00:00
~parinfer-rust-mode~ is built. Enabling ~parinfer-rust-mode~ should also
automatically disable ~smartparens-mode~ in order to avoid conflicting
behavior.
2021-06-09 15:22:47 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package parinfer-rust-mode
:defer t
2021-10-19 17:17:10 +00:00
:straight (:build t)
2021-10-12 09:31:20 +00:00
: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
2021-11-20 22:10:00 +00:00
"parinfer-rust/"))
2021-11-22 10:17:42 +00:00
(add-hook 'parinfer-rust-mode-hook
(lambda () (smartparens-mode -1)))
2021-11-20 22:10:00 +00:00
:general
(phundrak/major-leader-key
:keymaps 'parinfer-rust-mode-map
"m" #'parinfer-rust-switch-mode
"M" #'parinfer-rust-toggle-disable))
2021-06-09 15:22:47 +00:00
#+end_src
2021-07-30 16:46:04 +00:00
*** Smartparens
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-Smartparens-zve93mk0k4j0
:END:
~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
2021-10-12 09:31:20 +00:00
(use-package smartparens
:defer t
:straight (:build t)
:hook (prog-mode . smartparens-mode))
2021-07-30 16:46:04 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
*** ~string-edit~
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-string-editae02fl6184j0
:END:
2021-05-21 11:59:48 +00:00
~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
2022-11-19 09:03:53 +00:00
(use-package string-edit-at-point
2021-10-12 09:31:20 +00:00
:defer t
:straight (:build t))
2021-05-21 11:59:48 +00:00
#+end_src
*** Writeroom
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Editing-Writeroomxt12fl6184j0
:END:
2021-05-21 11:59:48 +00:00
On the other hand, ~writeroom~ allows the user to enter a
2021-06-18 08:26:28 +00:00
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.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package writeroom-mode
:defer t
:straight (:build t)
2022-02-07 11:05:50 +00:00
:init (global-writeroom-mode 1)
2021-10-12 09:31:20 +00:00
:config
(setq writeroom-width 100
writeroom-fullscreen-effect nil
writeroom-maximize-window nil
2022-02-07 11:05:50 +00:00
writeroom-mode-line t
2022-02-12 11:39:04 +00:00
writeroom-major-modes '(text-mode org-mode markdown-mode nov-mode Info-mode)))
2021-05-21 11:59:48 +00:00
#+end_src
** Emacs built-ins
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-insr832fl6184j0
:END:
2021-05-21 11:59:48 +00:00
*** Dired
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Diredao42fl6184j0
:END:
2021-06-09 15:22:47 +00:00
Dired is Emacs’ built-in file manager. It’ s 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 it’ s the
same thing.
2022-08-07 10:56:25 +00:00
I used to have an extensive configuration for Dired with a couple of
additional packages to make it more usable. Dirvish rendered that
obsolete!
2021-06-09 15:22:47 +00:00
#+begin_src emacs-lisp
2022-08-07 10:56:25 +00:00
(use-package dirvish
:straight (:build t)
2021-10-12 09:31:20 +00:00
:defer t
2022-08-07 10:56:25 +00:00
: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))
2021-11-07 14:54:20 +00:00
:config
2022-08-07 10:56:25 +00:00
(dirvish-peek-mode)
<<dired-drag-and-drop >>
<<dired-listing-flags >>
<<dired-files-and-dirs >>
<<dirvish-exa-offload >>
2023-03-10 14:22:55 +00:00
(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))
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
2022-08-07 10:56:25 +00:00
: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)
2022-11-11 13:44:02 +00:00
"A" #'gnus-dired-attach
2022-08-07 10:56:25 +00:00
"a" #'dirvish-quick-access
2022-08-14 11:14:44 +00:00
"d" #'dirvish-dispatch
2022-08-07 10:56:25 +00:00
"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
2022-08-14 11:14:44 +00:00
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
2022-08-07 10:56:25 +00:00
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, it’ s best to use the long name of flags whenever possible,
otherwise some commands won’ t 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)))
2021-06-09 15:22:47 +00:00
#+end_src
2022-04-06 16:51:14 +00:00
Copying files with Dired is a blocking process. It’ s usually fine when
2023-03-20 16:17:57 +00:00
there’ s 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
2022-04-06 16:51:14 +00:00
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
2021-10-18 14:28:09 +00:00
*** Compilation mode
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Compilation-mode-7nh817m0t8j0
:END:
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, let’ s
redefine some keybinds for this mode. I’ ll also define a general
keybind in order to re-run my programs from other buffers than the
2021-11-07 01:27:04 +00:00
~compilation-mode~ buffer. I also want to follow the output of the
compilation buffer, as well as enable some syntax highlighting.
2021-10-18 14:28:09 +00:00
#+begin_src emacs-lisp
2021-11-07 01:27:04 +00:00
(use-package compile
:defer t
:straight (compile :type built-in)
2023-03-10 14:23:39 +00:00
:hook (compilation-filter . colorize-compilation-buffer)
2021-11-07 01:27:04 +00:00
:init
(require 'ansi-color)
(defun colorize-compilation-buffer ()
(let ((inhibit-read-only t))
(ansi-color-apply-on-region (point-min) (point-max))))
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
2021-11-07 14:54:20 +00:00
:keymaps 'compilation-mode-map
"g" nil
2021-11-22 10:18:16 +00:00
"r" nil
"R" #'recompile
2021-11-07 14:54:20 +00:00
"h" nil)
(phundrak/leader-key
"R" #'recompile)
:config
2021-10-18 14:28:09 +00:00
(setq compilation-scroll-output t))
#+end_src
2021-05-21 11:59:48 +00:00
*** Eshell
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell0662fl6184j0
:END:
2021-11-22 13:32:43 +00:00
#+include : img/emacs-eshell.svg export html
2021-05-21 11:59:48 +00:00
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
2021-10-19 17:17:10 +00:00
(use-package eshell
:defer t
:straight (:type built-in :build t)
2021-11-07 14:54:20 +00:00
:config
2022-02-26 14:38:02 +00:00
(setq eshell-prompt-function
(lambda ()
(concat (abbreviate-file-name (eshell/pwd))
(if (= (user-uid) 0) " # " " λ ")))
eshell-prompt-regexp "^[^#λ\n]* [#λ] ")
2021-10-19 17:17:10 +00:00
<<eshell-alias-file >>
<<eshell-concat-shell-command >>
<<eshell-alias-open >>
2022-05-02 16:49:00 +00:00
<<eshell-alias-clear >>
2021-10-19 17:17:10 +00:00
<<eshell-alias-buffers >>
<<eshell-alias-emacs >>
2022-03-15 17:25:38 +00:00
<<eshell-alias-mkcd >>
:general
(phundrak/evil
:keymaps 'eshell-mode-map
[remap evil-collection-eshell-evil-change] #'evil-backward-char
2022-10-19 13:04:55 +00:00
"c" #'evil-backward-char
"t" #'evil-next-visual-line
"s" #'evil-previous-visual-line
2022-03-15 17:25:38 +00:00
"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))
2021-05-21 11:59:48 +00:00
#+end_src
**** Aliases
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Aliasesom72fl6184j0
:END:
2021-05-21 11:59:48 +00:00
First, let’ s declare our list of “dumb” aliases we’ ll use in
Eshell. You can find them here.
2021-10-19 17:17:10 +00:00
#+name : eshell-alias-file
#+begin_src emacs-lisp :tangle no
2022-06-07 13:46:42 +00:00
(setq eshell-aliases-file (expand-file-name "eshell-alias" user-emacs-directory))
2021-05-21 11:59:48 +00:00
#+end_src
A couple of other aliases will be defined through custom Elisp
functions, but first I’ ll need a function for concatenating a shell
command into a single string:
2021-10-19 17:17:10 +00:00
#+name : eshell-concat-shell-command
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(defun phundrak/concatenate-shell-command (&rest command)
2021-10-12 09:25:39 +00:00
"Concatenate an eshell COMMAND into a single string.
All elements of COMMAND will be joined in a single
2021-10-12 09:31:20 +00:00
space-separated string."
2021-12-19 12:00:26 +00:00
(mapconcat #'identity command " "))
2021-05-21 11:59:48 +00:00
#+end_src
I’ ll 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.
2021-10-19 17:17:10 +00:00
#+name : eshell-alias-open
#+begin_src emacs-lisp :tangle no
2021-11-18 19:07:27 +00:00
(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, let’ s
alias it to ~eshell/clear-scrollback~ which has the correct behavior.
2022-05-02 16:49:00 +00:00
#+name : eshell-alias-clear
#+begin_src emacs-lisp :tangle no
2021-11-18 19:07:27 +00:00
(defalias 'eshell/clear #'eshell/clear-scrollback)
2021-05-21 11:59:48 +00:00
#+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. I’ ll also declare ~list-buffers~ an alias of ~ibuffer~
because naming it that way kind of makes more sense to me.
2021-10-19 17:17:10 +00:00
#+name : eshell-alias-buffers
#+begin_src emacs-lisp :tangle no
2021-05-21 11:59:48 +00:00
(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: I’ m already inside Emacs and I
have all its power available instantly. So, let’ s open each file
passed to these commands.
2021-10-19 17:17:10 +00:00
#+name : eshell-alias-emacs
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(defun eshell/emacs (&rest file)
2021-10-12 09:25:39 +00:00
"Open each FILE and kill eshell.
2021-10-12 09:31:20 +00:00
Old habits die hard."
(when file
(dolist (f (reverse file))
(find-file f t))))
2021-05-21 11:59:48 +00:00
#+end_src
Finally, I’ ll 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 don’ t, similarly to the ~-p~ option passed to ~mkdir~ .
2021-10-19 17:17:10 +00:00
#+name : eshell-alias-mkcd
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(defun eshell/mkcd (dir)
2021-10-12 09:25:39 +00:00
"Create the directory DIR and move there.
If the directory DIR doesn’ t exist, create it and its parents
2021-10-12 09:31:20 +00:00
if needed, then move there."
(mkdir dir t)
(cd dir))
2021-05-21 11:59:48 +00:00
#+end_src
2021-07-30 17:06:25 +00:00
**** Commands
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Commands-n8w3fh2195j0
2021-06-16 12:30:03 +00:00
:END:
2021-05-21 11:59:48 +00:00
When I’ m in Eshell, sometimes I wish to open multiple files at once in
2022-03-15 17:31:56 +00:00
Emacs. For this, when I have several arguments for ~find-file~ , I want
2021-05-21 11:59:48 +00:00
to be able to open them all at once. Let’ s modify ~find-file~ like so:
#+BEGIN_SRC emacs-lisp
2021-10-12 09:31:20 +00:00
(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))
2021-05-21 11:59:48 +00:00
#+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
2021-10-12 09:31:20 +00:00
(defun eshell-new ()
"Open a new instance of eshell."
(interactive)
(eshell 'N))
2021-05-21 11:59:48 +00:00
#+end_src
2023-03-20 16:17:57 +00:00
A very useful command I often use in fish is ~z~ , a port from bash’ s and
2021-07-30 17:06:25 +00:00
zsh’ s command that allows to jump around directories based on how
often we go in various directories.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package eshell-z
:defer t
:after eshell
:straight (:build t)
:hook (eshell-mode . (lambda () (require 'eshell-z))))
2021-07-30 17:06:25 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
**** Environment Variables
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Environment-Variablesmna2fl6184j0
:END:
2021-06-09 15:22:47 +00:00
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.
2021-05-21 11:59:48 +00:00
#+BEGIN_SRC emacs-lisp
2021-10-12 09:31:20 +00:00
(setenv "DART_SDK" "/opt/dart-sdk/bin")
(setenv "ANDROID_HOME" (concat (getenv "HOME") "/Android/Sdk/ "))
2021-05-21 11:59:48 +00:00
#+END_SRC
The ~EDITOR~ variable also needs to be set for git commands, especially the
~yadm~ commands.
#+BEGIN_SRC emacs-lisp
2021-10-12 09:31:20 +00:00
(setenv "EDITOR" "emacsclient -c -a emacs")
2021-05-21 11:59:48 +00:00
#+END_SRC
Finally, for some specific situations I need ~SHELL~ to be set to
something more standard than fish:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(setenv "SHELL" "/bin/sh")
2021-05-21 11:59:48 +00:00
#+end_src
**** Visual configuration
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Visual-configuratione7c2fl6184j0
:END:
2021-05-21 11:59:48 +00:00
I like to have at quick glance some information about my machine when
I fire up a terminal. I haven’ t found anything that does that the way
2021-11-20 22:09:06 +00:00
I like it, so [[https://github.com/Phundrak/eshell-info-banner.el ][I’ ve written a package ]]! It’ s actually available on
MELPA, but since I’ m the main dev of this package, I’ ll keep track of
the git repository.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package eshell-info-banner
2021-10-19 17:17:10 +00:00
:after (eshell)
2021-10-12 09:31:20 +00:00
:defer t
:straight (eshell-info-banner :build t
:type git
:host github
2022-01-05 13:13:39 +00:00
:protocol ssh
2021-10-12 09:31:20 +00:00
:repo "phundrak/eshell-info-banner.el")
:hook (eshell-banner-load . eshell-info-banner-update-banner)
2023-03-14 10:02:29 +00:00
: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")))
2023-03-14 10:12:30 +00:00
:custom
(eshell-info-banner-partition-prefixes ("/dev" "zroot" "tank")))
2021-05-21 11:59:48 +00:00
#+end_src
2021-07-30 17:06:25 +00:00
Another feature I like is fish-like syntax highlight, which brings
some more colors to Eshell.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package eshell-syntax-highlighting
2021-10-19 17:17:10 +00:00
:after (esh-mode eshell)
2021-10-12 09:31:20 +00:00
:defer t
2021-10-19 17:17:10 +00:00
:straight (:build t)
2021-10-12 09:31:20 +00:00
:config
(eshell-syntax-highlighting-global-mode +1))
2021-07-30 17:06:25 +00:00
#+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
2021-10-12 09:31:20 +00:00
(use-package powerline-eshell
2022-09-22 10:49:49 +00:00
:if (string= (string-trim (shell-command-to-string "uname -n")) "leon")
2021-10-12 09:31:20 +00:00
:load-path "~/fromGIT/emacs-packages/powerline-eshell.el/ "
:after eshell)
2021-07-30 17:06:25 +00:00
#+end_src
2021-10-18 15:30:36 +00:00
*** Eww
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eww-m1343rs0t8j0
:END:
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/ ][Prot’ s 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
2022-02-26 14:38:16 +00:00
*** Image-mode
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Image-mode-dchdl251jdj0
:END:
2022-04-06 16:50:46 +00:00
I won’ t modify much for ~image-mode~ (the mode used to display images)
aside from Emacs’ ability to use external converters to display some
images it wouldn’ t be able to handle otherwise.
2022-02-26 14:38:16 +00:00
#+begin_src emacs-lisp
(setq image-use-external-converter t)
#+end_src
2021-07-30 17:07:29 +00:00
*** Info
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Info-r7x90j20c5j0
:END:
2021-10-19 17:17:10 +00:00
Let’ s define some more intuitive keybinds for ~info-mode~ .
2021-07-30 17:07:29 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package info
:defer t
:straight (info :type built-in :build t)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
2021-11-07 14:54:20 +00:00
:keymaps 'Info-mode-map
"c" #'Info-prev
"t" #'evil-scroll-down
"s" #'evil-scroll-up
"r" #'Info-next)
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:keymaps 'Info-mode-map
"?" #'Info-toc
"b" #'Info-history-back
"f" #'Info-history-forward
"m" #'Info-menu
"t" #'Info-top-node
"u" #'Info-up))
2021-07-30 17:07:29 +00:00
#+end_src
2023-01-05 17:56:18 +00:00
*** Tab Bar
:PROPERTIES:
:CUSTOM_ID: PackagesConfigurationEmacsbuiltinsTabBar-zmfhlpb12pj0
:END:
#+begin_src emacs-lisp
(use-package tab-bar
:defer t
:straight (:type built-in)
:custom
(tab-bar-close-button-show nil)
2023-01-08 20:16:38 +00:00
(tab-bar-new-button-show nil)
2023-01-05 17:56:18 +00:00
(tab-bar-new-tab-choice "*dashboard* ")
:custom-face
2023-01-08 20:16:38 +00:00
(tab-bar ((t (:background "#272C36"
2023-01-23 09:45:59 +00:00
:foreground "#272C36"
2023-01-08 20:16:38 +00:00
:box (:line-width (8 . 5) :style flat-button)))))
2023-01-05 17:56:18 +00:00
:init
(advice-add #'tab-new
:after
(lambda (&rest _) (when (y-or-n-p "Rename tab? ")
(call-interactively #'tab-rename)))))
#+end_src
2021-06-09 15:22:47 +00:00
*** Tramp
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Tramplqd2fl6184j0
:END:
2021-06-09 15:22:47 +00:00
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
2021-10-19 17:17:10 +00:00
(use-package tramp
:straight (tramp :type built-in :build t)
2022-03-10 21:27:20 +00:00
:config
2022-09-19 10:38:07 +00:00
<<tramp-add-yadm >>
2022-08-07 10:56:25 +00:00
(csetq tramp-ssh-controlmaster-options nil
tramp-verbose 0
tramp-auto-save-directory (locate-user-emacs-file "tramp/")
tramp-chunksize 2000)
2022-04-05 15:08:44 +00:00
(add-to-list 'backup-directory-alist ; deactivate auto-save with TRAMP
(cons tramp-file-name-regexp nil)))
2021-06-09 15:22:47 +00:00
#+end_src
**** Yadm
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Tramp-Yadma8f2fl6184j0
:END:
2021-06-09 15:22:47 +00:00
[[https://yadm.io/ ][~yadm~ ]] is a git wrapper made to easily manage your dotfiles. It has
loads of features I don’ t use (the main one I like but don’ t use is
its [[https://yadm.io/docs/templates ][Jinja-like host and OS-aware syntax ]]), but unfortunately Magit
doesn’ t play nice with it. Tramp to the rescue, and this page explains
how! Let’ s just insert in my config this code snippet:
2021-10-19 17:17:10 +00:00
#+name : tramp-add-yadm
#+begin_src emacs-lisp :tangle no
2021-06-09 15:22:47 +00:00
(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
I’ ll also create a fuction for connecting to this new Tramp protocol:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(defun my/yadm ()
"Manage my dotfiles through TRAMP."
(interactive)
(magit-status "/yadm::"))
2021-06-09 15:22:47 +00:00
#+end_src
2021-11-27 18:29:26 +00:00
** EXWM
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-EXWM-pr14yxs09aj0
:END:
2021-11-28 01:43:24 +00:00
So, I’ m 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. I’ m 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 haven’ t had
this issue.
2022-04-06 16:50:46 +00:00
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.
2021-11-28 01:43:24 +00:00
First, I need to install the /X protocol Emacs Lisp Bindings/ . It
doesn’ t seem to be available in any repo, so I’ ll install it directly
from Git.
2021-11-27 18:29:26 +00:00
#+begin_src emacs-lisp
(use-package xelb
2022-04-05 15:09:37 +00:00
:if (seq-contains-p command-line-args "--with-exwm")
2021-11-27 18:29:26 +00:00
:straight (xelb :build t
:type git
:host github
2021-12-20 14:24:57 +00:00
:repo "emacs-straight/xelb"
2021-11-28 21:56:59 +00:00
:fork "ch11ng/xelb"))
2021-11-28 01:43:24 +00:00
#+end_src
2021-11-27 18:29:26 +00:00
2021-11-28 01:43:24 +00:00
Next is a function I’ ve +stolen+ copied from Daviwil’ s [[https://config.daviwil.com/desktop][desktop
configuration]]. This allows to launch software in the background
easily.
#+begin_src emacs-lisp
2021-11-27 18:29:26 +00:00
(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)))))
2021-11-28 01:43:24 +00:00
#+end_src
2021-12-17 16:00:52 +00:00
In order to launch Emacs with EXWM with ~startx~ , I need a ~xinit~ file.
This one is exported to ~$HOME/.xinitrc.emacs~ .
2022-08-07 09:11:24 +00:00
#+begin_src sh :tangle ~/.xinitrc.emacs :shebang "#!/bin/sh"
2021-12-17 16:00:52 +00:00
xhost +SI:localuser:$USER
# Set fallback cursor
xsetroot -cursor_name left_ptr
2022-08-07 09:11:24 +00:00
# If Emacs is started in server mode, `emacsclient` is a convenient
# way to edit files in place (used by e.g. `git commit`)
2021-12-17 16:00:52 +00:00
export VISUAL=emacsclient
export EDITOR="$VISUAL"
# in case Java applications display /nothing/
# wmname LG3D
# export _JAVA_AWT_WM_NONREPARENTING=1
2022-08-07 09:11:24 +00:00
autorandr -l home
2021-12-17 16:00:52 +00:00
exec emacs --with-exwm
#+end_src
2021-11-28 01:43:24 +00:00
*** EXWM itself
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-EXWM-EXWM-itself-hhgexz61aaj0
:END:
Now we come to the plat de résistance. Like with ~xelb~ , I’ m 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
don’ t 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.
2023-03-20 16:17:57 +00:00
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:
2021-11-28 01:43:24 +00:00
#+name : exwm-renamed-buffers-list
2021-11-28 21:56:59 +00:00
- Kitty
2021-11-28 01:43:24 +00:00
- Qutebrowser
#+name : exwm-gen-buffers-rename
2022-02-12 11:50:07 +00:00
#+header : :exports none :tangle no
2021-11-28 01:43:24 +00:00
#+begin_src emacs-lisp :var buffers=exwm-renamed-buffers-list :cache yes
2021-11-28 21:56:59 +00:00
(format "%s\n%S"
(mapconcat (lambda (buffer)
2023-03-11 17:37:38 +00:00
(let ((buffer-name (if (stringp buffer)
buffer
(car buffer))))
2021-11-28 21:56:59 +00:00
(format "(\"%s\" %S)"
(downcase buffer-name)
2023-03-11 17:37:38 +00:00
`(exwm-workspace-rename-buffer
(concat ,(concat "EXWM: " buffer-name " - ")
exwm-title)))))
2021-11-28 21:56:59 +00:00
buffers
"\n")
'(_otherwise (exwm-workspace-rename-buffer exwm-title)))
2021-11-28 01:43:24 +00:00
#+end_src
2023-03-11 17:37:38 +00:00
#+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)))
2021-12-01 15:34:29 +00:00
: (_otherwise (exwm-workspace-rename-buffer exwm-title))
2021-11-28 01:43:24 +00:00
#+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
2021-11-28 21:56:59 +00:00
<<exwm-gen-buffers-rename() >>)))
2021-11-28 01:43:24 +00:00
#+end_src
2023-03-20 16:17:57 +00:00
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 I’ m 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.
2021-11-28 01:43:24 +00:00
#+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 aren’ t
sent directly to the X windows but caught by Emacs (and EXWM). I’ ll
use the ~i~ key in normal-mode to enter ~insert-mode~ and have Emacs
2021-11-28 11:41:36 +00:00
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.
2021-11-28 01:43:24 +00:00
#+name : exwm-prefix-keys
#+begin_src emacs-lisp :tangle no
(general-define-key
:keymaps 'exwm-mode-map
:states 'normal
"i" #'exwm-input-release-keyboard)
2021-11-28 11:41:36 +00:00
(exwm-input-set-key (kbd "s-<escape >") #'exwm-input-toggle-keyboard)
2021-11-28 01:43:24 +00:00
(push ?\i exwm-input-prefix-keys)
(push (kbd "C-SPC") exwm-input-prefix-keys)
(push (kbd "M-m") exwm-input-prefix-keys)
#+end_src
2021-11-27 18:29:26 +00:00
2021-11-28 01:43:24 +00:00
As stated a couple of times in my different configuration files, I’ m
using the bépo layout, which means the default keys in the number row
2023-03-20 16:17:57 +00:00
are laid as follows:
2021-11-28 01:43:24 +00:00
#+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)
2021-12-27 17:56:54 +00:00
(exwm-workspace-move-window ,(let ((index (1- i)))
(if (< index 0)
(- 10 index)
;; FIXME: does not work with s-0
index))))))
2021-11-28 01:43:24 +00:00
(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
2023-03-20 16:17:57 +00:00
mode), except for ~s-RET~ which opens an eshell terminal.
2021-11-28 01:43:24 +00:00
#+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")
2022-03-15 17:21:56 +00:00
"d" #'exwm-debug
2021-11-28 01:43:24 +00:00
"k" #'exwm-input-send-next-key
"l" '((lambda ()
(interactive)
(start-process "" nil "plock"))
:which-key "lock")
"r" '(:ignore t :wk "rofi")
"rr" '((lambda () (interactive)
2022-03-15 17:21:56 +00:00
(shell-command "rofi -show drun" (current-buffer) (current-buffer)))
2021-11-28 01:43:24 +00:00
:wk "drun")
"rw" '((lambda () (interactive)
2022-03-15 17:21:56 +00:00
(shell-command "rofi -show window" (current-buffer) (current-buffer)))
2021-11-28 01:43:24 +00:00
: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
2022-03-15 17:21:56 +00:00
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")
2021-11-28 01:43:24 +00:00
#+end_src
Finally, let’ s only initialize and start EXWM once functions from
exwm-randr ran, because otherwise having multiple monitors don’ t 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
2021-11-27 18:29:26 +00:00
(use-package exwm
2022-03-15 17:21:56 +00:00
:if (seq-contains-p command-line-args "--with-exwm")
2021-11-27 18:29:26 +00:00
: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)
2021-11-28 21:56:59 +00:00
(setq exwm-workspace-number 6)
2021-11-27 18:29:26 +00:00
:config
2022-05-17 15:24:54 +00:00
(set-frame-parameter (selected-frame) 'alpha-background 0.7)
2021-11-28 21:56:59 +00:00
<<exwm-randr >>
2021-11-28 01:43:24 +00:00
<<exwm-buffers-name >>
2021-11-27 18:29:26 +00:00
2021-11-28 01:43:24 +00:00
<<exwm-advices-evil >>
<<exwm-prefix-keys >>
2021-11-27 18:29:26 +00:00
2021-11-28 01:43:24 +00:00
<<exwm-bepo-number-row >>
<<exwm-workspace-keybinds >>
<<exwm-keybinds >>
2021-11-27 18:29:26 +00:00
2022-03-15 17:21:56 +00:00
<<exwm-autostart >>
2021-11-27 18:29:26 +00:00
2021-11-28 21:51:48 +00:00
<<exwm-init >>)
2021-11-28 01:43:24 +00:00
#+end_src
2021-11-27 18:29:26 +00:00
2021-11-28 01:43:24 +00:00
*** EXWM-Evil integration
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-EXWM-EXWM-Evil-integration-kwlexz61aaj0
:END:
#+begin_src emacs-lisp
2021-11-27 18:29:26 +00:00
(use-package evil-exwm-state
2022-03-15 17:21:56 +00:00
:if (seq-contains-p command-line-args "--with-exwm")
2021-11-27 18:29:26 +00:00
:defer t
:after exwm
:straight (evil-exwm-state :build t
:type git
:host github
:repo "domenzain/evil-exwm-state"))
2021-11-28 01:43:24 +00:00
#+end_src
2021-11-27 18:29:26 +00:00
2021-11-28 01:43:24 +00:00
*** Multimonitor support
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-EXWM-Multimonitor-support-l5pexz61aaj0
:END:
2021-11-28 21:56:59 +00:00
#+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
2022-03-15 17:21:56 +00:00
"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")
2021-11-28 21:56:59 +00:00
(exwm-randr-enable)
(setq exwm-randr-workspace-monitor-plist '(3 "eDP1"))
2021-11-27 18:29:26 +00:00
#+end_src
2021-11-28 01:43:24 +00:00
*** Keybinds for a desktop environment
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-EXWM-Keybinds-for-a-desktop-environment-q2sexz61aaj0
:END:
#+begin_src emacs-lisp
(use-package desktop-environment
:defer t
:straight (desktop-environment :build t
:type git
:host github
:repo "DamienCassou/desktop-environment")
2021-12-01 15:34:29 +00:00
:after exwm
2021-11-28 01:43:24 +00:00
:diminish t
:config
2021-12-01 15:34:29 +00:00
(add-hook 'exwm-init-hook #'desktop-environment-mode)
2021-11-28 01:43:24 +00:00
(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"
2022-03-27 23:59:32 +00:00
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"
2021-11-28 01:43:24 +00:00
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
2021-11-27 18:29:26 +00:00
*** Bluetooth
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-EXWM-Bluetooth-k0zhpda0aaj0
:END:
#+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)))
2021-12-19 12:00:26 +00:00
`(,(mapconcat #'identity (cddr split-name) " ") . ,(cadr split-name))))
2021-11-27 18:29:26 +00:00
#+end_src
#+begin_src emacs-lisp
2021-12-27 12:43:59 +00:00
(require 'dbus)
2021-11-27 18:29:26 +00:00
(defun bluetooth-get-devices ()
2021-12-27 12:43:59 +00:00
(let ((bus-list (dbus-introspect-get-node-names :system "org.bluez" "/org/bluez/hci0")))
2021-11-27 18:29:26 +00:00
(mapcar (lambda (device)
2021-12-27 12:43:59 +00:00
`(,(dbus-get-property :system
"org.bluez"
(concat "/org/bluez/hci0/ " device)
"org.bluez.Device1"
"Alias")
. ,device))
bus-list)))
2021-11-27 18:29:26 +00:00
#+end_src
#+begin_src emacs-lisp
(defun bluetooth-connect-device ()
(interactive)
(progn
(bluetooth-turn-on)
(let* ((devices (bluetooth-get-devices))
2021-12-27 12:43:59 +00:00
(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)))))))
2021-11-27 18:29:26 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
** Making my life easier
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Making-my-life-easier2kz4fl6184j0
:END:
2021-06-09 15:22:47 +00:00
*** Bufler
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Making-my-life-easier-Buflerw215fl6184j0
:END:
2023-03-20 16:17:57 +00:00
Bufler is a package that organises and lists buffers in a much better
2021-06-09 15:22:47 +00:00
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 let’ s redefine them, and let’ s also rebind ~SPC~
to ~p~ since it would conflict with my main ~general~ prefix.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package bufler
:straight (bufler :build t
:files (:defaults (:exclude "helm-bufler.el")))
:defer t
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
2021-11-07 14:54:20 +00:00
:keymaps 'bufler-list-mode-map
:packages 'bufler
2021-10-12 09:31:20 +00:00
"?" #'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))
2021-06-09 15:22:47 +00:00
#+end_src
*** Helpful
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Making-my-life-easier-Helpfullh25fl6184j0
:END:
2021-06-09 15:22:47 +00:00
As the name tells, ~helpful~ is a really helpful package which greatly
enhances a couple of built-in functions from Emacs, namely:
2021-06-18 08:26:11 +00:00
| Vanilla Emacs Function | Helpful Function | Comment |
|------------------------+------------------+-----------------------------------------------|
| ~describe-function~ | ~helpful-callable~ | Only interactive functions |
2021-06-09 15:22:47 +00:00
| ~describe-function~ | ~helpful-function~ | Only actual functions (including interactive) |
2021-06-18 08:26:11 +00:00
| ~describe-function~ | ~helpful-macro~ | |
| ~describe-command~ | ~helpful-command~ | |
| ~describe-key~ | ~helpful-key~ | |
| ~describe-variable~ | ~helpful-variable~ | |
2021-06-09 15:22:47 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package helpful
:straight (:build t)
:after (counsel ivy)
:custom
2022-11-21 10:36:38 +00:00
(counsel-describe-function-function #'helpful-callable)
(counsel-describe-variable-function #'helpful-variable)
2021-10-12 09:31:20 +00:00
:bind
([remap describe-function] . counsel-describe-function)
([remap describe-command] . helpful-command)
([remap describe-variable] . counsel-describe-variable)
([remap describe-key] . helpful-key))
2021-06-09 15:22:47 +00:00
#+end_src
2022-01-04 17:16:58 +00:00
** LaTeX
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-LaTeX-qfu4g180gbj0
:END:
#+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
2023-01-23 09:45:46 +00:00
(phundrak/major-leader-key
:packages 'lsp-mode
:keymaps '(latex-mode-map LaTeX-mode-map)
"l" '(:keymap lsp-command-map :which-key "lsp"))
2022-01-04 17:16:58 +00:00
(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
2022-06-15 19:42:18 +00:00
#+begin_src emacs-lisp
(use-package tex-mode
2022-01-04 17:16:58 +00:00
:defer t
2022-06-15 19:42:18 +00:00
:straight (:type built-in)
2022-01-04 17:16:58 +00:00
:config
2022-06-15 19:42:18 +00:00
(setq LaTeX-section-hook '(LaTeX-section-heading
LaTeX-section-title
LaTeX-section-toc
LaTeX-section-section
LaTeX-section-label)
2022-01-04 17:16:58 +00:00
LaTeX-fill-break-at-separators nil
LaTeX-item-indent 0))
#+end_src
#+begin_src emacs-lisp
2022-06-15 20:36:00 +00:00
(use-package preview
:defer t
:straight (:type built-in)
:config
2022-01-04 17:16:58 +00:00
(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
2021-06-09 15:22:47 +00:00
** Org-mode
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-modedw35fl6184j0
:END:
2021-10-19 17:17:10 +00:00
Since recently, in order to make ~org-cite~ compile properly, we need
the ~citeproc~ package, a citation processor.
#+begin_src emacs-lisp
(use-package citeproc
:after (org)
:defer t
:straight (:build t))
#+end_src
2021-06-14 14:04:09 +00:00
Org is the main reason I am using Emacs. It is an extremely powerfu
tool when you want to write anything that is not necessarily primarily
programming-related, though it absolutely can be! Org can be a
replacement for anything similar to LibreOffice Writer, LibreOffice
Calc, and LibreOffice Impress. It is a much more powerful (and older)
version of Markdown which can be exported to LaTeX and HTML at least,
rendering writing web pages and technical, scientific documents much
simpler than writing manually HTML and LaTeX code, especially when a
single document source is meant to be exported for both formats. And
since org is an Emacs package, that also means it can be greatly
extended however we like!
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package org
2021-10-19 19:42:28 +00:00
:straight t
2021-10-12 09:31:20 +00:00
:defer t
:commands (orgtbl-mode)
:hook ((org-mode . visual-line-mode)
(org-mode . org-num-mode))
:custom-face
(org-macro ((t (:foreground "#b48ead"))))
:init
(auto-fill-mode -1)
:config
<<org-hydra-babel >>
(require 'ox-beamer)
2022-04-21 10:39:07 +00:00
(require 'org-protocol)
2021-10-12 09:31:20 +00:00
(setq org-hide-leading-stars nil
org-hide-macro-markers t
org-ellipsis " ⤵"
2021-12-27 12:44:19 +00:00
org-image-actual-width 600
2021-10-12 09:31:20 +00:00
org-redisplay-inline-images t
org-display-inline-images t
org-startup-with-inline-images "inlineimages"
org-pretty-entities t
org-fontify-whole-heading-line t
org-fontify-done-headline t
org-fontify-quote-and-verse-blocks t
org-startup-indented t
org-startup-align-all-tables t
org-use-property-inheritance t
org-list-allow-alphabetical t
org-M-RET-may-split-line nil
org-src-window-setup 'split-window-below
org-src-fontify-natively t
org-src-tab-acts-natively t
org-src-preserve-indentation t
org-log-done 'time
org-directory "~/org"
org-default-notes-file (expand-file-name "notes.org" org-directory))
2022-05-01 16:02:53 +00:00
(with-eval-after-load 'oc
(setq org-cite-global-bibliography '("~/org/bibliography/references.bib")))
2021-10-12 09:31:20 +00:00
<<org-agenda-files >>
<<org-behavior-electric >>
2021-12-27 17:51:30 +00:00
<<org-capture-target-files >>
<<org-capture-templates >>
2022-03-10 21:52:31 +00:00
<<org-create-emphasis-functions() >>
2021-10-12 09:31:20 +00:00
<<org-babel-load-languages >>
<<org-use-sub-superscripts >>
<<org-latex-compiler >>
2022-07-05 13:30:35 +00:00
<<org-latex-src-block-backend >>
2021-10-12 09:31:20 +00:00
<<org-latex-default-packages >>
<<org-export-latex-hyperref-format >>
<<org-latex-pdf-process >>
2021-10-19 17:17:10 +00:00
<<org-latex-logfiles-add-extensions >>
2021-11-07 01:27:04 +00:00
<<org-re-reveal >>
2021-10-12 09:31:20 +00:00
<<org-html-validation >>
<<org-latex-classes >>
<<org-publish-projects >>
2021-12-06 16:07:30 +00:00
<<org-mode-visual-prettify-symbols >>
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
2021-11-07 14:54:20 +00:00
:keymaps 'org-mode-map
:packages 'org
"RET" 'org-open-at-point)
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:keymaps 'org-mode-map
:packages 'org
<<general-keybindings-gen(table=org-keybinds-various) >>
<<general-keybindings-gen(table=org-keybinds-babel) >>
<<general-keybindings-gen(table=org-keybinds-dates) >>
<<general-keybindings-gen(table=org-keybinds-insert) >>
<<general-keybindings-gen(table=org-keybinds-jump) >>
<<general-keybindings-gen(table=org-keybinds-tables) >>
<<general-keybindings-gen(table=org-keybinds-toggles) >>)
2021-12-27 17:51:30 +00:00
<<org-capture-keybinds >>
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:packages 'org
:keymaps 'org-src-mode-map
"'" #'org-edit-src-exit
"k" #'org-edit-src-abort))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-14 14:04:09 +00:00
The main feature from ~evil-org~ that I love is how easy it is to modify
some keybindings for keyboards layouts that do not have ~hjkl~ , such as
the bépo layout (or Dvorak or Colemak if you are into that). But it
also adds a ton of default keybindings which are just much more
comfortable than the default ones you get with evil and org naked.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package evil-org
:straight (:build t)
2021-10-19 17:17:10 +00:00
:after (org)
2021-10-12 09:31:20 +00:00
:hook (org-mode . evil-org-mode)
:config
(setq-default evil-org-movement-bindings
'((up . "s")
(down . "t")
(left . "c")
(right . "r")))
(evil-org-set-key-theme '(textobjects navigation calendar additional shift operators))
(require 'evil-org-agenda)
2021-11-18 19:08:32 +00:00
(evil-org-agenda-set-keys))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-14 14:04:09 +00:00
This package is a small package I’ ve written that helps me when
writing conlanging documents, with features such as creating syntax
trees, converting translitterated text to its native script, etc…
2021-06-09 15:22:47 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package conlanging
:straight (conlanging :build t
:type git
:repo "https://labs.phundrak.com/phundrak/conlanging.el")
:after org
:defer t)
2021-06-09 15:22:47 +00:00
#+end_src
2021-05-21 18:37:01 +00:00
Since very recently, the ~contrib/lisp/~ directory of org moved out of
the main repository to [[https://git.sr.ht/~bzg/org-contrib ][this repository ]]. On the other hand,
~contrib/scripts/~ moved to [[https://code.orgmode.org/bzg/worg/src/master/code ][the worg repository ]], but I don’ t need
it. The main reason I want ~org-contrib~ is due to ~ox-extra~ that allow
the usage of the ~:ignore:~ tag in org.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package org-contrib
2021-10-19 17:17:10 +00:00
:after (org)
:defer t
2021-10-12 09:31:20 +00:00
:straight (:build t)
:init
(require 'ox-extra)
(ox-extras-activate '(latex-header-blocks ignore-headlines)))
2021-05-21 18:37:01 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
*** Agenda
2021-05-21 11:59:48 +00:00
:PROPERTIES:
:header-args:emacs-lisp: :tangle no :exports code :results silent
2021-06-16 12:30:03 +00:00
:CUSTOM_ID: Packages-Configuration-Org-mode-Agenda8b55fl6184j0
2021-05-21 11:59:48 +00:00
:END:
#+name : org-agenda-files
#+begin_src emacs-lisp
2022-09-19 10:38:22 +00:00
(setq org-agenda-files (list "~/org/agenda" "~ /org/notes.org"))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-09 15:22:47 +00:00
*** Babel
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Babel9585fl6184j0
:END:
2021-07-30 17:09:00 +00:00
One of the amazing features of org-mode is its literary programming capacities
by running code blocks from within Org-mode itself. But for that, only a couple
of languages are supported directly by Org-mode itself, and they need to be
activated. Here are the languages I activated in my Org-mode configuration:
#+NAME : org-babel-languages-table
| C |
| emacs-lisp |
| gnuplot |
| latex |
| makefile |
2022-10-19 13:06:02 +00:00
| plantuml |
2022-05-14 22:37:24 +00:00
| python |
2021-07-30 17:09:00 +00:00
| sass |
| shell |
2022-11-18 02:53:59 +00:00
| sql |
2021-07-30 17:09:00 +00:00
#+NAME : org-babel-languages-gen
#+header : :cache yes :results replace
#+header : :var languages=org-babel-languages-table[,0]
2021-10-19 17:17:10 +00:00
#+BEGIN_SRC emacs-lisp :exports none :tangle no
2021-10-12 09:31:20 +00:00
(format "'(%s)"
(mapconcat (lambda ($language)
(format "(%s . t)" $language))
languages
"\n "))
2021-07-30 17:09:00 +00:00
#+END_SRC
2022-11-18 02:53:59 +00:00
#+RESULTS[b0a5bea13e6ba99525ad166ea5538e74ba4c6ddc]: org-babel-languages-gen
#+begin_example
'((C . t)
(emacs-lisp . t)
(gnuplot . t)
(latex . t)
(makefile . t)
(plantuml . t)
(python . t)
(sass . t)
(shell . t)
(sql . t))
#+end_example
2021-07-30 17:09:00 +00:00
The corresponding code is as follows:
#+NAME : org-babel-load-languages
#+BEGIN_SRC emacs-lisp :noweb yes :tangle no
2021-10-12 09:31:20 +00:00
(org-babel-do-load-languages
'org-babel-load-languages
<<org-babel-languages-gen() >>)
2021-07-30 17:09:00 +00:00
#+END_SRC
2022-08-07 10:56:44 +00:00
Some languages can run asynchronously with the help of ~ob-async~ .
#+begin_src emacs-lisp
(use-package ob-async
:straight (:build t)
:defer t
:after (org ob))
#+end_src
2021-12-20 10:36:39 +00:00
A package I use from time to time is ~ob-latex-as-png~ which allows me
to easily convert a LaTeX snippet into a PNG, regardless of the
exporter I use afterwards. Its installation is pretty simple:
#+begin_src emacs-lisp
(use-package ob-latex-as-png
:after org
2021-12-27 12:44:36 +00:00
:straight (:build t))
2021-12-20 10:36:39 +00:00
#+end_src
2022-04-06 16:55:42 +00:00
A nice thing to have when working with REST APIs is to have a REST
client. Even better if it can work inside org-mode!
2021-12-20 10:36:39 +00:00
#+begin_src emacs-lisp
(use-package ob-restclient
:straight (:build t)
:defer t
:after (org ob)
:init
(add-to-list 'org-babel-load-languages '(restclient . t)))
#+end_src
2021-11-18 19:10:40 +00:00
*** Behavior
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Behaviorzp65fl6184j0
:END:
A useful package I like is ~toc-org~ which creates automatically a table
of contents. My main usage for this however is not just to create a
table of content of my files to quickly jump around my file (I have
~counsel-org-goto~ for that), but it is for creating table of contents
2023-03-20 16:17:57 +00:00
for org files that will be hosted and viewable on GitHub.
2021-11-18 19:10:40 +00:00
#+begin_src emacs-lisp
(use-package toc-org
:after (org markdown-mode)
:straight (:build t)
:init
(add-to-list 'org-tag-alist '("TOC" . ?T))
:hook (org-mode . toc-org-enable)
:hook (markdown-mode . toc-org-enable))
#+end_src
~electric-mode~ also bothers me a lot when editing org files, so let’ s deactivate it:
#+name : org-behavior-electric
#+begin_src emacs-lisp :tangle no
(add-hook 'org-mode-hook (lambda ()
(interactive)
(electric-indent-local-mode -1)))
#+end_src
As explained in my [[https://blog.phundrak.com/better-custom-ids-orgmode/ ][blog post ]], org-mode is terrible with coming up with
meaningful IDs for its headings. I actually wrote a package for this!
#+begin_src emacs-lisp
(use-package org-unique-id
:straight (org-unique-id :build t
:type git
:host github
:repo "Phundrak/org-unique-id")
:defer t
:after org
2022-08-24 18:08:46 +00:00
:init (add-hook 'before-save-hook #'org-unique-id-maybe))
2021-11-18 19:10:40 +00:00
#+end_src
2021-12-27 17:51:30 +00:00
*** Capture
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Capture-2j6hpyh0u9j0
:END:
Org capture is an amazing tool for taking quick notes, be it simple
text, links, resources, or reminders. They are all organised is
specified org files which are described below.
#+name : org-capture-target-files
#+begin_src emacs-lisp :tangle no
(defvar org-conlanging-file "~/org/conlanging.org")
(defvar org-notes-file "~/org/notes.org")
(defvar org-journal-file "~/org/journal.org")
(defvar org-linguistics-file "~/org/linguistics.org")
(defvar org-novel-file "~/org/novel.org")
(defvar org-agenda-file "~/org/agenda/private.org")
(defvar org-school-file "~/org/agenda/school.org")
(defvar org-worldbuilding-file "~/org/worldbuilding.org")
#+end_src
Let me describe a keybind to invoke org-capture from anywhere within
Emacs.
#+name : org-capture-keybinds
#+begin_src emacs-lisp :tangle no
(phundrak/leader-key
:packages 'org
:infix "o"
"" '(:ignore t :which-key "org")
"c" #'org-capture)
#+end_src
When ~org-capture~ is invoked, it will ask which template we wish to
use. In the table [[org-capture-shortcuts-table ]], the /key/ column
represents which keychord we need to hit, titled with /name/ , we need to
hit in order to use the /template/ , inserted in the designated /file/ in
the manner described by /insertion mode/ .
#+name : org-capture-shortcuts-table
| Shortcut | Name | Title | Insertion mode | file | template |
|----------+---------------+-----------+----------------+-------------------------+--------------------------|
| e | Email | | | | |
| ew | Write Email | Emails | file+headline | org-default-notes-file | email.orgcaptmpl |
| j | Journal | | file+datetree | org-journal-file | journal.orgcaptmpl |
| l | Link | | | | |
| ll | General | | file+headline | org-default-notes-file | link.orgcaptmpl |
| ly | YouTube | | file+headline | org-default-notes-file | youtube.orgcaptmpl |
| L | Protocol Link | Link | file+headline | org-default-notes-file | protocol-link.orgcaptmpl |
| n | Notes | | | | |
| nc | Conlanging | Note | file+headline | org-conlanging-file | notes.orgcaptmpl |
| nn | General | | file+headline | org-default-notes-file | notes.orgcaptmpl |
| nN | Novel | Note | file+headline | org-novel-notes-file | notes.orgcaptmpl |
| nq | Quote | | file+headline | org-default-notes-file | notes-quote.orgcaptmpl |
| nw | Worldbuilding | Note | file+headline | org-wordbuilding-file | notes.orgcaptmpl |
| N | Novel | | | | |
| Ni | Ideas | | file+headline | org-novel-notes-file | notes.orgcaptmpl |
| p | Protocol | Link | file+headline | org-default-notes-file | protocol.orgcaptmpl |
| r | Resources | | | | |
| rc | Conlanging | Resources | file+headline | org-conlanging-file | resource.orgcaptmpl |
| re | Emacs | | file+headline | org-default-notes-file | resource.orgcaptmpl |
| ri | Informatique | | file+headline | org-default-notes-file | resource.orgcaptmpl |
| rl | Linguistics | | file+headline | org-default-notes-file | resource.orgcaptmpl |
| rL | Linux | | file+headline | org-default-notes-file | resource.orgcaptmpl |
| rw | Worldbuilding | Resources | file+headline | org-wordbuilding-file | resource.orgcaptmpl |
| t | Tasks | | | | |
| tb | Birthday | | file+headline | org-private-agenda-file | birthday.orgcaptmpl |
| te | Event | | file+headline | org-private-agenda-file | event.orgcaptmpl |
| th | Health | | file+headline | org-private-agenda-file | health.orgcaptmpl |
| ti | Informatique | | file+headline | org-private-agenda-file | informatique.orgcaptmpl |
All templates can be found [[https://labs.phundrak.com/phundrak/dotfiles/src/branch/master/org/capture ][in my dotfiles’ repository ]].
#+name : org-capture-shortcuts-gen
2022-06-10 08:35:25 +00:00
#+header : :exports none :cache yes :tangle no
2021-12-27 17:51:30 +00:00
#+begin_src emacs-lisp :var entries=org-capture-shortcuts-table
(mapconcat (lambda (entry)
(let ((key (nth 0 entry))
(name (nth 1 entry))
(title (nth 2 entry))
(ins-mode (nth 3 entry))
(file (nth 4 entry))
(template (nth 5 entry)))
(if (string= "" ins-mode)
(format "%S" `(,key ,name))
(format "(\"%s\" \"%s\" entry\n %S\n %S)"
key name
`(,(intern ins-mode) ,(intern file) ,(if (string= "file+datetree" ins-mode)
(intern "")
(if (string= title "")
name
title)))
`(file ,(concat "~/org/capture/ " template))))))
entries
"\n")
#+end_src
2022-06-10 08:39:43 +00:00
#+RESULTS[9f565c3dd73becfad0a99c0cfaf4521762334b40]: org-capture-shortcuts-gen
2021-12-27 17:51:30 +00:00
#+begin_example
("e" "Email")
("ew" "Write Email" entry
(file+headline org-default-notes-file "Emails")
(file "~/org/capture/email.orgcaptmpl"))
("j" "Journal" entry
(file+datetree org-journal-file ##)
(file "~/org/capture/journal.orgcaptmpl"))
("l" "Link")
("ll" "General" entry
(file+headline org-default-notes-file "General")
(file "~/org/capture/link.orgcaptmpl"))
("ly" "YouTube" entry
(file+headline org-default-notes-file "YouTube")
(file "~/org/capture/youtube.orgcaptmpl"))
("L" "Protocol Link" entry
(file+headline org-default-notes-file "Link")
(file "~/org/capture/protocol-link.orgcaptmpl"))
("n" "Notes")
("nc" "Conlanging" entry
(file+headline org-conlanging-file "Note")
(file "~/org/capture/notes.orgcaptmpl"))
("nn" "General" entry
(file+headline org-default-notes-file "General")
(file "~/org/capture/notes.orgcaptmpl"))
("nN" "Novel" entry
(file+headline org-novel-notes-file "Note")
(file "~/org/capture/notes.orgcaptmpl"))
("nq" "Quote" entry
(file+headline org-default-notes-file "Quote")
(file "~/org/capture/notes-quote.orgcaptmpl"))
("nw" "Worldbuilding" entry
(file+headline org-wordbuilding-file "Note")
(file "~/org/capture/notes.orgcaptmpl"))
("N" "Novel")
("Ni" "Ideas" entry
(file+headline org-novel-notes-file "Ideas")
(file "~/org/capture/notes.orgcaptmpl"))
("p" "Protocol" entry
(file+headline org-default-notes-file "Link")
(file "~/org/capture/protocol.orgcaptmpl"))
("r" "Resources")
("rc" "Conlanging" entry
(file+headline org-conlanging-file "Resources")
(file "~/org/capture/resource.orgcaptmpl"))
("re" "Emacs" entry
(file+headline org-default-notes-file "Emacs")
(file "~/org/capture/resource.orgcaptmpl"))
("ri" "Informatique" entry
(file+headline org-default-notes-file "Informatique")
(file "~/org/capture/resource.orgcaptmpl"))
("rl" "Linguistics" entry
(file+headline org-default-notes-file "Linguistics")
(file "~/org/capture/resource.orgcaptmpl"))
("rL" "Linux" entry
(file+headline org-default-notes-file "Linux")
(file "~/org/capture/resource.orgcaptmpl"))
("rw" "Worldbuilding" entry
(file+headline org-wordbuilding-file "Resources")
(file "~/org/capture/resource.orgcaptmpl"))
("t" "Tasks")
("tb" "Birthday" entry
(file+headline org-private-agenda-file "Birthday")
(file "~/org/capture/birthday.orgcaptmpl"))
("te" "Event" entry
(file+headline org-private-agenda-file "Event")
(file "~/org/capture/event.orgcaptmpl"))
("th" "Health" entry
(file+headline org-private-agenda-file "Health")
(file "~/org/capture/health.orgcaptmpl"))
("ti" "Informatique" entry
(file+headline org-private-agenda-file "Informatique")
(file "~/org/capture/informatique.orgcaptmpl"))
#+end_example
The capture templates are set like so:
#+name : org-capture-templates
#+begin_src emacs-lisp :tangle no :results silent
(setq org-capture-templates
'(
<<org-capture-shortcuts-gen() >>))
#+end_src
2022-03-10 21:52:31 +00:00
*** Custom functions
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Custom-functions-h3v07sl02ej0
:END:
**** Emphasize text
:PROPERTIES:
:CUSTOM_ID: Custom-Elisp-Org-Functions-Emphasize-textkilkel6184j0
:END:
Sometimes, I want to emphasize some text in my org-mode documents.
It’ s very possible to just go to the begining of the chosen text, add
the marker, then go to the end of the text than needs emphasis and add
another marker, and I’ m sure most people are fine with that. But I
also like being able to select a region and hit a keybind to emphasize
it that way. The table [[org-emphasis-character ]] lists the emphasis
characters in org-mode, their role, and the character code of each
emphasis character. From that, creating functions that emphasize a
selected text is quite easy.
#+name : org-emphasis-character
| Emphasis | Character | Character code |
|----------------+-----------+----------------|
| bold | ~*~ | 42 |
| italic | ~/~ | 47 |
| underline | ~_~ | 95 |
| verbatim | ~=~ | 61 |
| code | ~~~ | 126 |
| strike-through | ~+~ | 43 |
#+name : org-create-emphasis-functions
2022-04-06 16:50:46 +00:00
#+header : :tangle no :exports results :cache yes
2022-03-10 21:52:31 +00:00
#+header : :wrap "src emacs-lisp :tangle no :exports code"
#+begin_src emacs-lisp :var emphasis-list=org-emphasis-character
(mapconcat (lambda (emphasis)
(let ((type (car emphasis))
(code (nth 2 emphasis)))
(format "(defun org-emphasize-%s ()
\"Emphasize as %s the current region.\"
(interactive)
(org-emphasize %s))"
type
type
code)))
emphasis-list
"\n")
#+end_src
2022-04-06 16:50:46 +00:00
#+RESULTS[dbd10cce4ae05a046838214784f0f4c16765e728]: org-create-emphasis-functions
2022-03-10 21:52:31 +00:00
#+begin_src emacs-lisp :tangle no :exports code
(defun org-emphasize-bold ()
"Emphasize as bold the current region."
(interactive)
(org-emphasize 42))
(defun org-emphasize-italic ()
"Emphasize as italic the current region."
(interactive)
(org-emphasize 47))
(defun org-emphasize-underline ()
"Emphasize as underline the current region."
(interactive)
(org-emphasize 95))
(defun org-emphasize-verbatim ()
"Emphasize as verbatim the current region."
(interactive)
(org-emphasize 61))
(defun org-emphasize-code ()
"Emphasize as code the current region."
(interactive)
(org-emphasize 126))
(defun org-emphasize-strike-through ()
"Emphasize as strike-through the current region."
(interactive)
(org-emphasize 43))
#+end_src
You can find the keybinds for these functions in the chapter
§[[#Packages-Configuration-Org-mode-Keybindingsv0e5fl6184j0 ]].
**** ~phundrak/toggle-org-src-window-split~
:PROPERTIES:
:CUSTOM_ID: Custom-Elisp-Org-Functions-phundrak-toggle-org-src-window-splito2tkel6184j0
:END:
#+begin_src emacs-lisp
(defun phundrak/toggle-org-src-window-split ()
"This function allows the user to toggle the behavior of
`org-edit-src-code'. If the variable `org-src-window-setup' has
the value `split-window-right', then it will be changed to
`split-window-below'. Otherwise, it will be set back to
`split-window-right'"
(interactive)
(if (equal org-src-window-setup 'split-window-right)
(setq org-src-window-setup 'split-window-below)
(setq org-src-window-setup 'split-window-right))
(message "Org-src buffers will now split %s"
(if (equal org-src-window-setup 'split-window-right)
"vertically"
"horizontally")))
#+end_src
2021-11-07 01:28:47 +00:00
*** Exporters
2021-05-21 11:59:48 +00:00
:PROPERTIES:
2021-06-16 12:30:03 +00:00
:CUSTOM_ID: Packages-Configuration-Org-mode-File-exportik95fl6184j0
2021-05-21 11:59:48 +00:00
:END:
I want to disable by default behavior of ~^~ and ~_~ for only one
character, making it compulsory to use instead ~^{}~ and ~_{}~
respectively. This is due to my frequent usage of the underscore in my
org files as a regular character and not a markup one, especially when
describing phonetics evolution. So, let’ s disable it:
#+NAME : org-use-sub-superscripts
2021-06-16 13:05:17 +00:00
#+BEGIN_SRC emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq org-use-sub-superscripts (quote {}))
2021-05-21 11:59:48 +00:00
#+END_SRC
2021-07-30 17:09:00 +00:00
**** Epub
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-File-export-Epub-w5ycfuz095j0
:END:
A backend for exporting files through org I like is ~ox-epub~ which, as
you can guess, exports org files to the [[https://www.w3.org/publishing/epub32/ ][Epub format ]].
2021-06-16 13:05:17 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package ox-epub
2021-10-19 17:17:10 +00:00
:after (org ox)
2021-10-12 09:31:20 +00:00
:straight (:build t))
2021-06-16 13:05:17 +00:00
#+end_src
2022-04-18 19:16:51 +00:00
**** Gemini
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Exporters-Gemini-4td3dk21kej0
:END:
#+begin_src emacs-lisp
(use-package ox-gemini
:defer t
:straight (:build t)
:after (ox org))
#+end_src
2021-07-30 17:09:00 +00:00
**** HTML
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-File-export-HTMLxjc5fl6184j0
:END:
On HTML exports, Org-mode tries to include a validation link for the
exported HTML. Let’ s disable that since I never use it.
#+NAME : org-html-validation
2021-10-19 17:17:10 +00:00
#+BEGIN_SRC emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq org-html-validation-link nil)
2021-07-30 17:09:00 +00:00
#+END_SRC
2021-06-16 13:05:17 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
;; (use-package htmlize
;; :defer t
;; :straight (:build t))
2021-06-16 13:05:17 +00:00
#+end_src
2021-07-30 17:09:00 +00:00
This package allows for live-previewing the HTML export of an org
buffer in an XWidget Webkit browser window. But when testing it, it’ s
not great for large org files, I should keep its usage for smaller org
files.
2021-06-16 13:05:17 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package preview-org-html-mode
:defer t
2021-10-19 17:17:10 +00:00
:after (org)
2021-10-12 09:31:20 +00:00
:straight (preview-org-html-mode :build t
:type git
:host github
:repo "jakebox/preview-org-html-mode")
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
:keymaps 'org-mode-map
2021-11-07 14:54:20 +00:00
:packages 'preview-org-html-mode
:infix "P"
2021-11-28 21:51:48 +00:00
"" '(:ignore t :which-key "preview")
2021-11-07 14:54:20 +00:00
"h" #'preview-org-html-mode
"r" #'preview-org-html-refresh
"p" #'preview-org-html-pop-window-to-frame)
2021-10-12 09:31:20 +00:00
:config
(setq preview-org-html-refresh-configuration 'save))
2021-06-16 13:05:17 +00:00
#+end_src
2021-11-23 14:01:38 +00:00
**** Hugo
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Exporters-Hugo-ca3473613aj0
:END:
I manage [[https://blog.phundrak.com ][my blog ]] with [[https://gohugo.io/ ][Hugo ]]. Although it natively supports the org
format, it’ s not great compared to its markdown support. So, instead,
let’ s directly export our org files as markdown files and let Hugo do
the rest of the job for us!
#+begin_src emacs-lisp
(use-package ox-hugo
:defer t
:after ox
:straight t)
#+end_src
I also have a function for publishing my blog once I exported my
articles with ~ox-hugo~ . It will compile blog into a ~public/~ directory
and copy its content over to my remote server.
#+begin_src emacs-lisp
(defun phundrak/blog-publish ()
"Publish my blog through Hugo to my remote server."
(interactive)
(let* ((default-directory (expand-file-name "~/org/blog"))
(public-path (concat default-directory "/public"))
(target-path "/rsync:Tilo:/home/phundrak/www/phundrak.com/blog"))
(compile "hugo")
(let ((files (mapcar (lambda (file)
(f-relative file public-path))
(f-files public-path nil t))))
(dolist (file files)
(copy-file (concat public-path "/" file)
(concat target-path "/" file)
t nil t)))))
#+end_src
2021-06-09 15:22:47 +00:00
**** LaTeX
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-File-export-LaTeXg2b5fl6184j0
:END:
2021-05-21 11:59:48 +00:00
When it comes to exports, I want the LaTeX and PDF exports to be done
with XeLaTeX only. This implies the modification of the following
variable:
#+NAME : org-latex-compiler
2021-10-19 17:17:10 +00:00
#+BEGIN_SRC emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq org-latex-compiler "xelatex")
2021-05-21 11:59:48 +00:00
#+END_SRC
2022-05-14 22:37:56 +00:00
A new backend that was introduced in org-mode for LaTeX source block
2022-06-26 20:23:41 +00:00
coloring is ~engraved~ .
#+BEGIN_SRC emacs-lisp
2022-05-14 22:37:56 +00:00
(use-package engrave-faces
:defer t
2022-06-26 20:23:41 +00:00
:straight (:build t)
2022-07-05 13:30:35 +00:00
:after org)
2021-05-21 11:59:48 +00:00
#+END_SRC
2022-07-05 13:30:35 +00:00
#+name : org-latex-src-block-backend
#+begin_src emacs-lisp :tangle no
(require 'engrave-faces)
(csetq org-latex-src-block-backend 'engraved)
#+end_src
2021-05-21 11:59:48 +00:00
The default packages break my LaTeX exports: for some reasons, images
are not loaded and exported in PDFs, so I needed to redifine the
2021-07-30 17:09:00 +00:00
default packages excluding the one that broke my exports; namely, I
need to remove ~inputenc~ , ~fontenc~ and ~grffile~ . I also added some default
packages:
- ~cleveref~ for better references to various elements.
- ~svg~ for inserting SVG files in PDF outputs
- ~booktabs~ for nicer tables
- and ~tabularx~ for tabulars with adjustable columns
2021-05-21 11:59:48 +00:00
#+NAME : org-latex-default-packages
2021-10-19 17:17:10 +00:00
#+BEGIN_SRC emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(dolist (package '(("AUTO" "inputenc" t ("pdflatex"))
("T1" "fontenc" t ("pdflatex"))
("" "grffile" t)))
(delete package org-latex-default-packages-alist))
2022-07-05 13:30:35 +00:00
(dolist (package '(("capitalize" "cleveref")
2021-10-12 09:31:20 +00:00
("" "booktabs")
("" "tabularx")))
(add-to-list 'org-latex-default-packages-alist package t))
(setq org-latex-reference-command "\\cref{%s}")
2021-05-21 11:59:48 +00:00
#+END_SRC
2021-07-30 17:09:00 +00:00
By the way, reference links in LaTeX should be written in this format,
since we are using ~cleveref~ :
2021-05-21 11:59:48 +00:00
#+NAME : org-export-latex-hyperref-format
2021-10-19 17:17:10 +00:00
#+BEGIN_SRC emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq org-export-latex-hyperref-format "\\ref{%s}")
2021-05-21 11:59:48 +00:00
#+END_SRC
2022-10-04 11:01:05 +00:00
[[https://tectonic-typesetting.github.io/en-US/ ][Tectonic ]] is awesome for processing LaTeX documents! Look how simple it
is!
2021-05-21 11:59:48 +00:00
#+NAME : org-latex-pdf-process
2021-10-19 17:17:10 +00:00
#+BEGIN_SRC emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(setq org-latex-pdf-process
2022-10-04 11:01:05 +00:00
'("tectonic -Z shell-escape --synctex --outdir=%o %f"))
2021-05-21 11:59:48 +00:00
#+END_SRC
Finally, org-mode is supposed to automatically clean logfiles after it
exports an org file to LaTeX. However, it misses a few, so I need to
add their extension like so:
2021-10-19 17:17:10 +00:00
#+name : org-latex-logfiles-add-extensions
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(dolist (ext '("bbl" "lot"))
(add-to-list 'org-latex-logfiles-extensions ext t))
2021-05-21 11:59:48 +00:00
#+end_src
2021-10-31 13:53:37 +00:00
**** Reveal.js
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-File-export-Reveal-js-mzijhel099j0
:END:
2021-11-07 01:27:04 +00:00
#+NAME : org-re-reveal
2021-10-31 13:53:37 +00:00
#+begin_src emacs-lisp
(use-package org-re-reveal
:defer t
:after org
:straight (:build t)
:init
(add-hook 'org-mode-hook (lambda () (require 'org-re-reveal)))
:config
(setq org-re-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js"
org-re-reveal-revealjs-version "4"))
#+end_src
2021-07-30 17:09:00 +00:00
**** SSH Config
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-File-export-SSH-Config-tatextz095j0
:END:
Yet another exporter I enjoy is [[https://github.com/dantecatalfamo/ox-ssh ][~ox-ssh~ ]] with which I manage my
~$HOME/.ssh/config~ file. You won’ t find my org file for managing my
servers on my repos though.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package ox-ssh
2021-10-19 17:17:10 +00:00
:after (ox org)
2021-10-12 09:31:20 +00:00
:straight (:build t))
2021-07-30 17:09:00 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-06-14 14:04:09 +00:00
*** Keybindings
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Keybindingsv0e5fl6184j0
:END:
2021-06-14 14:04:09 +00:00
Be prepared, I have a lot of keybindings for org-mode! They are all
prefixed with a comma ~,~ in normal mode.
#+name : org-keybinds-various
2022-06-21 14:36:31 +00:00
| Key chord | Function | Description |
|-----------+---------------------------+-------------|
| RET | org-ctrl-c-ret | |
| * | org-ctrl-c-star | |
| , | org-ctrl-c-ctrl-c | |
| ' | org-edit-special | |
| - | org-ctrl-c-minus | |
| a | org-agenda | |
| c | org-capture | |
2022-08-30 23:55:08 +00:00
| C | org-columns | |
2022-06-21 14:36:31 +00:00
| e | org-export-dispatch | |
| l | org-store-link | |
| p | org-priority | |
| r | org-reload | |
2021-06-14 14:04:09 +00:00
I then have a couple of babel-related functions.
#+name : org-keybinds-babel
| Key chord | Function | Description |
|-----------+-------------------------------------+-------------|
| b | nil | babel |
| b. | org-babel-transient/body | |
| bb | org-babel-execute-buffer | |
| bc | org-babel-check-src-block | |
| bC | org-babel-tangle-clean | |
| be | org-babel-execute-maybe | |
| bf | org-babel-tangle-file | |
| bn | org-babel-next-src-block | |
| bo | org-babel-open-src-block-result | |
| bp | org-babel-previous-src-block | |
| br | org-babel-remove-result-one-or-many | |
| bR | org-babel-goto-named-result | |
| bt | org-babel-tangle | |
| bi | org-babel-view-src-block-info | |
The ~org-babel-transient~ hydra allows me to quickly navigate between
code blocks and interact with them. This code block was inspired by
one you can find in Spacemacs.
#+name : org-hydra-babel
#+begin_src emacs-lisp :tangle no
2021-10-12 09:31:20 +00:00
(defhydra org-babel-transient ()
2021-06-14 14:04:09 +00:00
"
2021-10-12 09:31:20 +00:00
^Navigate^ ^Interact
^^^^^^^^^^^------------------------------------------
[_t_ /_s_ ] navigate src blocs [_x_ ] execute src block
[_g_ ]^^ goto named block [_'_ ] edit src block
[_z_ ]^^ recenter screen [_q_ ] quit
"
("q" nil :exit t)
("t" org-babel-next-src-block)
("s" org-babel-previous-src-block)
("g" org-babel-goto-named-src-block)
("z" recenter-top-bottom)
("x" org-babel-execute-maybe)
("'" org-edit-special :exit t))
2021-06-14 14:04:09 +00:00
#+end_src
We next have keybindings related to org-mode’ s agenda capabilities. We
can schedule a todo header for some dates, or set a deadline.
#+name : org-keybinds-dates
| Key chord | Function | Description |
|-----------+-------------------------+-------------|
| d | nil | dates |
| dd | org-deadline | |
| ds | org-schedule | |
| dt | org-time-stamp | |
| dT | org-time-stamp-inactive | |
Let’ s now define some keybinds for inserting stuff in our org buffer:
#+name : org-keybinds-insert
| Key chord | Function | Description |
|-----------+-------------------------------+-------------|
| i | nil | insert |
| ib | org-insert-structure-template | |
| id | org-insert-drawer | |
2022-03-10 21:52:31 +00:00
| ie | nil | emphasis |
| ieb | org-emphasize-bold | |
| iec | org-emphasize-code | |
| iei | org-emphasize-italic | |
| ies | org-emphasize-strike-through | |
| ieu | org-emphasize-underline | |
| iev | org-emphasize-verbatim | |
| iE | org-set-effort | |
2021-06-14 14:04:09 +00:00
| if | org-footnote-new | |
| ih | org-insert-heading | |
2021-12-20 14:24:57 +00:00
| iH | counsel-org-link | |
2021-06-14 14:04:09 +00:00
| ii | org-insert-item | |
| il | org-insert-link | |
| in | org-add-note | |
| ip | org-set-property | |
| is | org-insert-subheading | |
| it | org-set-tags-command | |
There isn’ t a lot of stuff I can jump to yet, but there’ s still some:
#+name : org-keybinds-jump
| Key chord | Function | Description |
|-----------+----------------------+-------------|
| j | nil | jump |
| ja | counsel-org-goto-all | |
| jh | counsel-org-goto | |
Tables get a bit more love:
#+name : org-keybinds-tables
| Key chord | Function | Description |
|-----------+--------------------------------------+-------------|
| t | nil | tables |
2021-09-01 19:47:41 +00:00
| tc | org-table-move-column-left | |
| tt | org-table-move-row-down | |
| ts | org-table-move-row-up | |
| tr | org-table-move-column-right | |
2021-06-14 14:04:09 +00:00
| ta | org-table-align | |
| te | org-table-eval-formula | |
| tf | org-table-field-info | |
2022-03-30 18:24:18 +00:00
| tF | org-table-edit-formulas | |
2021-06-14 14:04:09 +00:00
| th | org-table-convert | |
| tl | org-table-recalculate | |
| tp | org-plot/gnuplot | |
2021-09-01 19:47:41 +00:00
| tS | org-table-sort-lines | |
2021-06-14 14:04:09 +00:00
| tw | org-table-wrap-region | |
2021-09-01 19:47:41 +00:00
| tx | org-table-shrink | |
2021-06-14 14:04:09 +00:00
| tN | org-table-create-with-table.el | |
| td | nil | delete |
| tdc | org-table-delete-column | |
| tdr | org-table-kill-row | |
| ti | nil | insert |
| tic | org-table-insert-column | |
| tih | org-table-insert-hline | |
| tir | org-table-insert-row | |
| tiH | org-table-hline-and-move | |
| tt | nil | toggle |
| ttf | org-table-toggle-formula-debugger | |
| tto | org-table-toggle-coordinate-overlays | |
Finally, let’ s make enabling and disabling stuff accessible:
#+name : org-keybinds-toggles
| Key chord | Function | Description |
|-----------+--------------------------------------+-------------|
| T | nil | toggle |
| Tc | org-toggle-checkbox | |
| Ti | org-toggle-inline-images | |
| Tl | org-latex-preview | |
| Tn | org-num-mode | |
| Ts | phundrak/toggle-org-src-window-split | |
| Tt | org-show-todo-tree | |
| TT | org-todo | |
2021-06-09 15:22:47 +00:00
*** LaTeX formats
2021-05-21 11:59:48 +00:00
:PROPERTIES:
:header-args:emacs-lisp: :tangle no :exports code :results silent
2021-06-16 12:30:03 +00:00
:CUSTOM_ID: Packages-Configuration-Org-mode-LaTeX-formatszjf5fl6184j0
2021-05-21 11:59:48 +00:00
:END:
I currently have two custom formats for my Org-mode exports: one for general use
(initialy for my conlanging files, hence its ~conlang~ name), and one for beamer
exports.
Below is the declaration of the ~conlang~ LaTeX class:
#+NAME : org-latex-class-conlang
#+BEGIN_SRC emacs-lisp
2021-10-12 09:31:20 +00:00
'("conlang"
"\\documentclass{book}"
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
2021-05-21 11:59:48 +00:00
#+END_SRC
And here is the declaration of the ~beamer~ class:
#+NAME : org-latex-class-beamer
#+BEGIN_SRC emacs-lisp
2021-10-12 09:31:20 +00:00
`("beamer"
,(concat "\\documentclass[presentation]{beamer}\n"
"[DEFAULT-PACKAGES]"
"[PACKAGES]"
"[EXTRA]\n")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
2021-05-21 11:59:48 +00:00
#+END_SRC
Both these classes have to be added to ~org-latex-classes~ like so:
#+NAME : org-latex-classes
#+BEGIN_SRC emacs-lisp :noweb yes
2021-10-12 09:31:20 +00:00
(eval-after-load "ox-latex"
'(progn
(add-to-list 'org-latex-classes
<<org-latex-class-conlang >>)
(add-to-list 'org-latex-classes
<<org-latex-class-beamer >>)))
2021-05-21 11:59:48 +00:00
#+END_SRC
2021-06-09 15:22:47 +00:00
*** Projects
2021-05-21 11:59:48 +00:00
:PROPERTIES:
:header-args:emacs-lisp: :tangle no :exports code :results silent
2021-06-16 12:30:03 +00:00
:CUSTOM_ID: Packages-Configuration-Org-mode-Projectsf2h5fl6184j0
2021-05-21 11:59:48 +00:00
:END:
Another great features of Org-mode is the Org projects that allow the user to
easily publish a bunch of org files to a remote location. Here is the current
declaration of my projects, which will be detailed later:
#+NAME : org-publish-projects
2023-03-10 14:25:19 +00:00
#+BEGIN_SRC emacs-lisp :noweb yes :noweb-prefix no
2021-10-12 09:31:20 +00:00
<<org-proj-config-setup >>
<<org-proj-lang-setup >>
(setq org-publish-project-alist
2023-03-10 14:25:19 +00:00
`(<<org-proj-config-html >>
2021-10-12 09:31:20 +00:00
<<org-proj-config-static >>
<<org-proj-config >>
2023-03-10 14:25:19 +00:00
<<org-proj-lang-md >>
2021-10-12 09:31:20 +00:00
<<org-proj-lang >>))
2021-05-21 11:59:48 +00:00
#+END_SRC
2021-06-09 15:22:47 +00:00
**** Configuration website
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Projects-Configuration-websitelki5fl6184j0
:END:
2021-05-21 11:59:48 +00:00
This is my configuration for exporting my dotfiles to my website in a web format
only. No PDFs or anything, just HTML. Please note that I do not use that often
anymore, I much prefer the automatic script that I have which deploys through my
Drone instance my website on git pushes.
2021-10-12 09:28:05 +00:00
2021-05-21 11:59:48 +00:00
And before we get into the actual configuration, I would like to introduce a
couple of variables. This is a bit more verbose than if I declared everything
manually, but now I can change all three values at the same time without a
hasle.
#+NAME : org-proj-config-setup
#+BEGIN_SRC emacs-lisp
2021-10-12 09:31:20 +00:00
(defvar phundrak//projects-config-target
"/ssh:Tilo:~/www/phundrak.com/config"
"Points to where exported files for config.phundrak.com should be put.")
(defvar phundrak//projects-config-source
"~/org/config/ "
"Points to where the sources for config.phundrak.com are.")
(defvar phundrak//projects-config-language
"en"
"Language of the website config.phundrak.com.")
(defvar phundrak//projects-config-recursive
t
"Defines whether subdirectories should be parsed for config.phundrak.com.")
2021-05-21 11:59:48 +00:00
#+END_SRC
Now, here is my configuration. In this snippet, my org files located in my
source directory get exported in the HTML format and published to my target
directory on my remote server through RSYNC via TRAMP. A sitemap is
automatically generated, which comes in handy with the online sitemap that is
available through the navigation bar.
#+NAME : org-proj-config-html
#+BEGIN_SRC emacs-lisp
2023-01-23 09:46:13 +00:00
("config-website-html"
2021-10-12 09:31:20 +00:00
:base-directory ,phundrak//projects-config-source
:base-extension "org"
:publishing-directory ,phundrak//projects-config-target
:recursive ,phundrak//projects-config-recursive
:language ,phundrak//projects-config-language
:publishing-function org-html-publish-to-html
:headline-levels 5
:auto-sitemap t
:auto-preamble t)
2021-05-21 11:59:48 +00:00
#+END_SRC
We also have the component for all the static files needed to run the website
(mostly images tbh).
#+NAME : org-proj-config-static
#+BEGIN_SRC emacs-lisp
2021-10-12 09:31:20 +00:00
("config-website-static"
:base-directory ,phundrak//projects-config-source
:base-extension "png\\|jpg\\|gif\\|webp\\|svg\\|jpeg\\|ttf\\|woff\\|txt\\|epub\\|md"
:publishing-directory ,phundrak//projects-config-target
:recursive ,phundrak//projects-config-recursive
:language ,phundrak//projects-config-language
:publishing-function org-publish-attachment)
2021-05-21 11:59:48 +00:00
#+END_SRC
The project is then defined like so:
#+NAME : org-proj-config
#+BEGIN_SRC emacs-lisp
2021-10-12 09:31:20 +00:00
("config-website"
:components ("config-website-org"
"config-website-static"))
2021-05-21 11:59:48 +00:00
#+END_SRC
2022-03-27 20:17:31 +00:00
**** Conlanging website
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Projects-Linguistics-websitey4k5fl6184j0
:END:
2022-03-27 20:17:31 +00:00
#+begin_info
/Conlangs/ , or /constructed languages/ , are artificial languages created
by individuals or by groups of individuals, unlike natural languages
which evolve and appear naturally from other languages.
#+end_info
2023-03-10 14:25:19 +00:00
My conlanging website is made of only one project, exporting my org
files to GitHub-flavored Markdown. As for the previous project, let’ s
declare a common value.
2021-05-21 11:59:48 +00:00
#+NAME : org-proj-lang-setup
#+BEGIN_SRC emacs-lisp
2023-03-10 14:25:19 +00:00
(defvar phundrak--projects-conlanging-common-root
"~/org/conlanging/docs/ "
"Points to the common root of my source and target for my
conlang.phundrak.com org project.")
2021-05-21 11:59:48 +00:00
#+END_SRC
2023-03-10 14:25:19 +00:00
The only component is the one generating the Markdown files from the
org files.
#+NAME : org-proj-lang-md
2021-05-21 11:59:48 +00:00
#+BEGIN_SRC emacs-lisp
2023-03-10 14:25:19 +00:00
("conlang-phundrak-com-md"
:base-directory ,phundrak--projects-conlanging-common-root
2021-10-12 09:31:20 +00:00
:base-extension "org"
2022-03-06 20:45:52 +00:00
:exclude ,(rx (* print)
(or "CONTRIB"
"README"
2023-03-10 14:25:19 +00:00
"site-map"
2022-03-06 20:45:52 +00:00
"temp"
"private"
"svg-ink")
(* print))
2023-03-10 14:25:19 +00:00
:publishing-directory ,phundrak--projects-conlanging-common-root
:recursive t
:language "en"
:publishing-function org-gfm-publish-to-gfm
2021-10-12 09:31:20 +00:00
:headline-levels 5
2023-03-10 14:25:19 +00:00
:auto-sitemap nil
:auto-preamble nil)
2021-05-21 11:59:48 +00:00
#+END_SRC
The project is then defined like so:
#+NAME : org-proj-lang
#+BEGIN_SRC emacs-lisp
2022-03-06 20:45:52 +00:00
("conlang-phundrak-com"
2023-03-10 14:25:19 +00:00
:components ("conlang-phundrak-com-md"))
2021-05-21 11:59:48 +00:00
#+END_SRC
2021-07-30 17:09:00 +00:00
*** Org-ref and Bibtex configuration
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-org-ref-1h586cd085j0
:END:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package reftex
:commands turn-on-reftex
:init (setq reftex-default-bibliography "~/org/bibliography/references.bib"
reftex-plug-into-AUCTeX t))
#+end_src
#+begin_src emacs-lisp
(use-package org-ref
2021-10-29 15:08:20 +00:00
;; :after (org ox-bibtex pdf-tools)
:after org
:defer t
2021-10-12 09:31:20 +00:00
:straight (:build t)
:custom-face
(org-ref-cite-face ((t (:weight bold))))
:init
(setq org-ref-completion-library 'org-ref-ivy-cite
org-latex-logfiles-extensions '("lof" "lot" "aux" "idx" "out" "log" "fbd_latexmk"
"toc" "nav" "snm" "vrb" "dvi" "blg" "brf" "bflsb"
"entoc" "ps" "spl" "bbl" "pygtex" "pygstyle"))
(add-hook 'org-mode-hook (lambda () (require 'org-ref)))
:config
2021-10-12 17:37:52 +00:00
(setq bibtex-completion-pdf-field "file"
bibtex-completion-notes-path "~/org/bibliography/notes/ "
bibtex-completion-bibliography "~/org/bibliography/references.bib"
bibtex-completion-library-path "~/org/bibliography/bibtex-pdfs/ "
bibtex-completion-pdf-symbol "⌘"
bibtex-completion-notes-symbol "✎")
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
:keymaps 'bibtex-mode-map
2021-11-07 14:54:20 +00:00
:packages 'org-ref
2021-10-12 09:31:20 +00:00
"C-t" #'org-ref-bibtex-next-entry
"C-s" #'org-ref-bibtex-previous-entry
"gt" #'org-ref-bibtex-next-entry
"gs" #'org-ref-bibtex-previous-entry)
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-12 09:31:20 +00:00
:keymaps '(bibtex-mode-map)
2021-11-07 14:54:20 +00:00
:packages 'org-ref
2021-10-12 09:31:20 +00:00
;; Navigation
"t" #'org-ref-bibtex-next-entry
"s" #'org-ref-bibtex-previous-entry
;; Open
"b" #'org-ref-open-in-browser
"n" #'org-ref-open-bibtex-notes
"p" #'org-ref-open-bibtex-pdf
;; Misc
"h" #'org-ref-bibtex-hydra/body
"i" #'org-ref-bibtex-hydra/org-ref-bibtex-new-entry/body-and-exit
"s" #'org-ref-sort-bibtex-entry
2021-11-28 21:51:48 +00:00
"l" '(:ignore t :which-key "lookup")
2021-10-12 09:31:20 +00:00
"la" #'arxiv-add-bibtex-entry
"lA" #'arxiv-get-pdf-add-bibtex-entry
"ld" #'doi-utils-add-bibtex-entry-from-doi
"li" #'isbn-to-bibtex
"lp" #'pubmed-insert-bibtex-from-pmid)
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
:keymaps 'org-mode-map
2021-11-07 14:54:20 +00:00
:pakages 'org-ref
2021-10-12 09:31:20 +00:00
"ic" #'org-ref-insert-link))
2021-07-30 17:09:00 +00:00
#+end_src
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package ivy-bibtex
:defer t
:straight (:build t)
:config
2021-10-12 17:37:52 +00:00
(setq bibtex-completion-pdf-open-function #'find-file)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/leader-key
:keymaps '(bibtex-mode-map)
2021-11-07 14:54:20 +00:00
:packages 'ivy-bibtex
2021-11-07 01:27:04 +00:00
"m" #'ivy-bibtex))
2021-07-30 17:09:00 +00:00
#+end_src
2021-10-20 14:23:09 +00:00
*** Org-present
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Org-present-pw04s240w8j0
:END:
~org-present~ allows its user to create presentations through ~org-mode~ ,
which is really nice! However, most of my configuration will be stolen
[[https://config.daviwil.com/emacs#org-present ][from Daviwil’ s ]] with minor changes.
#+begin_src emacs-lisp
(defun my/org-present-prepare-slide ()
(org-overview)
(org-show-entry)
(org-show-children)
(org-present-hide-cursor))
(defun my/org-present-init ()
(setq header-line-format " ")
(org-display-inline-images)
(my/org-present-prepare-slide))
(defun my/org-present-quit ()
(setq header-line-format nil)
(org-present-small)
(org-present-show-cursor))
(defun my/org-present-prev ()
(interactive)
(org-present-prev)
(my/org-present-prepare-slide))
(defun my/org-present-next ()
(interactive)
(org-present-next)
(my/org-present-prepare-slide))
(use-package org-present
:after org
:defer t
:straight (:build t)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:packages 'org-present
2021-11-07 01:27:04 +00:00
:keymaps 'org-mode-map
2022-02-14 14:31:45 +00:00
"P" #'org-present)
2021-11-07 01:27:04 +00:00
(phundrak/evil
:states 'normal
2021-11-07 14:54:20 +00:00
:packages 'org-present
2021-11-07 01:27:04 +00:00
:keymaps 'org-present-mode-keymap
"+" #'org-present-big
"-" #'org-present-small
"<" #'org-present-beginning
">" #'org-present-end
"«" #'org-present-beginning
"»" #'org-present-end
"c" #'org-present-hide-cursor
"C" #'org-present-show-cursor
"n" #'org-present-next
"p" #'org-present-prev
"r" #'org-present-read-only
"w" #'org-present-read-write
"q" #'org-present-quit)
2021-10-20 14:23:09 +00:00
:hook ((org-present-mode . my/org-present-init)
(org-present-mode-quit . my/org-present-quit)))
#+end_src
2021-06-09 15:22:47 +00:00
*** Visual Configuration
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Visual-Configurationrol5fl6184j0
:END:
2021-05-23 23:51:34 +00:00
While most modes of Emacs are dedicated to development, and therefore
are much more comfortable with a fixed-pitch font, more literary modes
such as org-mode are much more enjoyable if you have a variable pitch
font enabled. *BUT* , these modes can also require some fixed-pitch fonts
for some elements of the buffer, such as code blocks with
org-mode. ~mixed-pitch~ comes to the rescue!
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package mixed-pitch
:after org
2021-10-19 17:17:10 +00:00
:straight (:build t)
2021-10-12 09:31:20 +00:00
:hook
2021-10-20 12:00:01 +00:00
(org-mode . mixed-pitch-mode)
(emms-browser-mode . mixed-pitch-mode)
(emms-playlist-mode . mixed-pitch-mode)
2021-10-12 09:31:20 +00:00
:config
(add-hook 'org-agenda-mode-hook (lambda () (mixed-pitch-mode -1))))
2021-05-21 11:59:48 +00:00
#+end_src
2021-05-23 23:51:34 +00:00
I have an issue with org-mode’ s emphasis markers: I find them ugly. I
can of course hide them if I simply set ~org-hide-emphasis-markers~ to
~t~ , but it makes editing hard since I never know whether I am before or
after the emphasis marker when editing near the beginning/end of an
emphasized region. ~org-appear~ fixes this issue so that it shows the
emphasis markers only when the cursor is in the emphasized region,
otherwise they will remain hidden! Very cool!
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package org-appear
:after org
:straight (:build t)
:hook (org-mode . org-appear-mode)
:config
(setq org-appear-autoemphasis t
org-hide-emphasis-markers t
org-appear-autolinks t
org-appear-autoentities t
org-appear-autosubmarkers t)
(run-at-time nil nil #'org-appear--set-elements))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-16 12:34:09 +00:00
Similarly, LaTeX fragments previews are nice and all, but if I have my
cursor on it, I want to see the LaTeX source code and modify it, not
just the generated image!
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package org-fragtog
:defer t
:after org
:straight (:build t)
:hook (org-mode . org-fragtog-mode))
2021-06-16 12:34:09 +00:00
#+end_src
2022-08-07 10:57:06 +00:00
Org-modern modernizes a bit the appearance of org buffers, including
2023-03-10 14:26:51 +00:00
tables, source blocks, and tags, and it applies settings similar to
2022-08-07 10:57:06 +00:00
~org-superstar~ which I used to use.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2022-08-07 10:57:06 +00:00
(use-package org-modern
2021-10-12 09:31:20 +00:00
:straight (:build t)
2022-08-07 10:57:06 +00:00
:after org
:defer t
:hook (org-mode . org-modern-mode)
:hook (org-agenda-finalize . org-modern-agenda))
2021-05-21 11:59:48 +00:00
#+end_src
2022-03-15 17:31:56 +00:00
~org-fancy-priorities~ change the priority of an org element such as ~#A~
to anything user-defined. Let’ s all-the-iconify this!
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package org-fancy-priorities
:after (org all-the-icons)
:straight (:build t)
:hook (org-mode . org-fancy-priorities-mode)
:hook (org-agenda-mode . org-fancy-priorities-mode)
:config
(setq org-fancy-priorities-list `(,(all-the-icons-faicon "flag" :height 1.1 :v-adjust 0.0)
,(all-the-icons-faicon "arrow-up" :height 1.1 :v-adjust 0.0)
,(all-the-icons-faicon "square" :height 1.1 :v-adjust 0.0))))
2021-05-21 11:59:48 +00:00
#+end_src
2021-06-16 12:34:09 +00:00
/Org Outline Tree/ is a better way of managing my org files’ outline.
2021-05-24 00:18:14 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package org-ol-tree
2021-10-19 17:17:10 +00:00
:after (org avy)
2021-10-12 09:31:20 +00:00
:defer t
:straight (org-ol-tree :build t
:host github
:type git
:repo "Townk/org-ol-tree")
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:packages 'org-ol-tree
:keymaps 'org-mode-map
"O" #'org-ol-tree))
2021-05-24 00:18:14 +00:00
#+end_src
2021-12-06 16:07:30 +00:00
#+name : org-mode-visual-prettify-symbols
#+begin_src emacs-lisp
(add-hook 'org-mode-hook
(lambda ()
(dolist (pair '(("[ ]" . ?☐)
("[X]" . ?☑)
("[-]" . ?❍)
("#+title:" . ?📕)
("#+TITLE:" . ?📕)
("#+author:" . ?✎)
("#+AUTHOR:" . ?✎)
("#+email:" . ?📧)
("#+EMAIL:" . ?📧)
("#+include" . ?⭳)
("#+INCLUDE" . ?⭳)
("#+begin_src" . ?λ)
("#+BEGIN_SRC" . ?λ)
("#+end_src" . ?λ)
("#+END_SRC" . ?λ)))
(add-to-list 'prettify-symbols-alist pair))
(prettify-symbols-mode)))
#+end_src
2021-07-30 16:50:10 +00:00
*** Misc
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Org-mode-Misc-l202k9z0l4j0
:END:
~org-tree-slide~ is a presentation tool for org-mode.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package org-tree-slide
:defer t
:after org
:straight (:build t)
2021-11-07 14:54:20 +00:00
:config
(setq org-tree-slide-skip-done nil)
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
:keymaps 'org-mode-map
2021-11-07 14:54:20 +00:00
:packages 'org-tree-slide
2021-11-07 01:27:04 +00:00
"<f8 >" #'org-tree-slide-mode)
(phundrak/major-leader-key
:keymaps 'org-tree-slide-mode-map
2021-11-07 14:54:20 +00:00
:packages 'org-tree-slide
2021-11-07 01:27:04 +00:00
"d" (lambda () (interactive (setq org-tree-slide-skip-done (not org-tree-slide-skip-done))))
"p" #'org-tree-slide-move-next-tree
"n" #'org-tree-slide-move-previous-tree
"t" #'org-tree-slide-move-next-tree
"s" #'org-tree-slide-move-previous-tree
"u" #'org-tree-slide-content))
2021-07-30 16:50:10 +00:00
#+end_src
2022-06-18 13:47:28 +00:00
~org-roll~ is a simple package for tabletop RPGs for rolling dice.
#+begin_src emacs-lisp
(use-package org-roll
:defer t
:after org
:straight (:build t :type git :host github :repo "zaeph/org-roll"))
#+end_src
2022-04-18 19:17:31 +00:00
** Programming
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages6et5fl6184j0
:END:
2021-07-30 17:01:29 +00:00
*** Tools
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-Tools-w3q5rsg0k4j0
:END:
2022-10-19 13:06:44 +00:00
**** Treesitter
:PROPERTIES:
:CUSTOM_ID: PackagesConfigurationProgrammingToolsTreesitter-pbbjc4a05mj0
:END:
2023-03-10 14:28:36 +00:00
Treesit is a native Emacs [[https://tree-sitter.github.io/tree-sitter/ ][tree-sitter ]] implementation which provides a
very fast and flexible way of performing code-highlighting in Emacs.
2023-03-20 16:17:57 +00:00
It is built-in in Emacs 29 and newer, and I just need to tweak a couple of
variables to install grammars for different languages.
2022-10-19 13:06:44 +00:00
#+begin_src emacs-lisp
2023-03-10 14:28:36 +00:00
(use-package treesit
2022-10-19 13:06:44 +00:00
:defer t
2023-03-10 14:28:36 +00:00
:straight (:type built-in)
:hook ((bash-ts-mode c-ts-mode c++-ts-mode
html-ts-mode js-ts-mode typescript-ts-mode
json-ts-mode rust-ts-mode tsx-ts-mode python-ts-mode
css-ts-mode yaml-ts-mode) . lsp-deferred)
:init
(setq treesit-language-source-alist
'((bash "https://github.com/tree-sitter/tree-sitter-bash")
(c "https://github.com/tree-sitter/tree-sitter-c")
(cmake "https://github.com/uyha/tree-sitter-cmake")
(common-lisp "https://github.com/theHamsta/tree-sitter-commonlisp")
(cpp "https://github.com/tree-sitter/tree-sitter-cpp")
(css "https://github.com/tree-sitter/tree-sitter-css")
(csharp "https://github.com/tree-sitter/tree-sitter-c-sharp")
(elisp "https://github.com/Wilfred/tree-sitter-elisp")
(go "https://github.com/tree-sitter/tree-sitter-go")
(go-mod "https://github.com/camdencheek/tree-sitter-go-mod")
(html "https://github.com/tree-sitter/tree-sitter-html")
(js . ("https://github.com/tree-sitter/tree-sitter-javascript" "master" "src"))
(json "https://github.com/tree-sitter/tree-sitter-json")
(lua "https://github.com/Azganoth/tree-sitter-lua")
(make "https://github.com/alemuller/tree-sitter-make")
(markdown "https://github.com/ikatyang/tree-sitter-markdown")
(python "https://github.com/tree-sitter/tree-sitter-python")
(r "https://github.com/r-lib/tree-sitter-r")
(rust "https://github.com/tree-sitter/tree-sitter-rust")
(toml "https://github.com/tree-sitter/tree-sitter-toml")
(tsx . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "tsx/src"))
(typescript . ("https://github.com/tree-sitter/tree-sitter-typescript" "master" "typescript/src"))
(yaml "https://github.com/ikatyang/tree-sitter-yaml"))))
2022-10-19 13:06:44 +00:00
#+end_src
2022-07-19 09:24:50 +00:00
**** Appwrite
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-Tools-Appwrite-c1e4fh51mij0
:END:
[[https://appwrite.io ][Appwrite ]] is an open-source and self-hostable alternative to Firebase.
I am currently working on a server SDK for Appwrite in Emacs, so here
it is.
#+begin_src emacs-lisp
(use-package appwrite
:defer t
:straight (appwrite :build t
:type git
:host github
:repo "Phundrak/appwrite.el")
:config
(csetq appwrite-endpoint "https://appwrite.phundrak.com"
appwrite-devel t))
#+end_src
2022-07-05 13:30:53 +00:00
**** Databases
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-Tools-Databases-73nhsqt09ij0
:END:
A really cool tool in Emacs for manipulating databases is ~emacsql~ .
It’ s able to manipulate Sqlite databases by default, but it’ s also
possible to manipulate MariaDB and PostgreSQL databases by installing
additional packages. For now, I just need Sqlite and PostgreSQL
interfaces, so let’ s install the relevant packages.
#+begin_src emacs-lisp
(use-package emacsql-psql
:defer t
:after (emacsql)
:straight (:build t))
(with-eval-after-load 'emacsql
(phundrak/major-leader-key
:keymaps 'emacs-lisp-mode-map
:packages '(emacsql)
"E" #'emacsql-fix-vector-indentation))
#+end_src
2021-07-30 17:01:29 +00:00
**** Flycheck
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-Flycheckb446fl6184j0
:END:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package flycheck
:straight (:build t)
:defer t
:init
(global-flycheck-mode)
:config
(setq flycheck-emacs-lisp-load-path 'inherit)
;; Rerunning checks on every newline is a mote excessive.
(delq 'new-line flycheck-check-syntax-automatically)
;; And don’ t recheck on idle as often
(setq flycheck-idle-change-delay 2.0)
;; For the above functionality, check syntax in a buffer that you
;; switched to on briefly. This allows “refreshing” the syntax check
;; state for several buffers quickly after e.g. changing a config
;; file.
(setq flycheck-buffer-switch-check-intermediate-buffers t)
;; Display errors a little quicker (default is 0.9s)
(setq flycheck-display-errors-delay 0.2))
(use-package flycheck-popup-tip
:straight (:build t)
2022-06-18 13:46:42 +00:00
:after (flycheck evil)
2021-10-12 09:31:20 +00:00
:hook (flycheck-mode . flycheck-popup-tip-mode)
:config
(setq flycheck-popup-tip-error-prefix "X ")
2022-06-18 13:46:42 +00:00
(with-eval-after-load 'evil
2021-10-12 09:31:20 +00:00
(add-hook 'evil-insert-state-entry-hook
#'flycheck-popup-tip-delete-popup)
(add-hook 'evil-replace-state-entry-hook
#'flycheck-popup-tip-delete-popup)))
(use-package flycheck-posframe
:straight (:build t)
:hook (flycheck-mode . flycheck-posframe-mode)
:config
(setq flycheck-posframe-warning-prefix "! "
flycheck-posframe-info-prefix "··· "
flycheck-posframe-error-prefix "X "))
2021-07-30 17:01:29 +00:00
#+end_src
2021-11-20 22:10:37 +00:00
**** Langtool
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-Tools-Langtool-sjr1oox0y9j0
:END:
2022-04-06 17:44:02 +00:00
LanguageTool is a great tool for catching typos and grammatical errors
in quite a few languages.
2021-11-20 22:10:37 +00:00
#+begin_src emacs-lisp
(use-package langtool
:defer t
:straight (:build t)
:commands (langtool-check
langtool-check-done
langtool-show-message-at-point
langtool-correct-buffer)
2022-04-06 17:44:02 +00:00
:custom
(langtool-default-language "en-US")
(langtool-mother-tongue "fr")
2021-11-20 22:10:37 +00:00
:config
2022-04-06 17:44:02 +00:00
(setq langtool-java-classpath (string-join '("/usr/share/languagetool"
"/usr/share/java/languagetool/ *")
":"))
:general
(phundrak/leader-key
:packages 'langtool
:infix "l"
"" '(:ignore t :which-key "LangTool")
"B" #'langtool-correct-buffer
"b" #'langtool-check-buffer
"c" #'langtool-check
"d" #'langtool-check-done
"l" #'langtool-switch-default-language
"p" #'langtool-show-message-at-point))
2021-11-20 22:10:37 +00:00
#+end_src
2023-03-20 16:19:31 +00:00
An LSP version of LanguageTools is also available:
#+begin_src emacs-lisp
(use-package lsp-ltex
:defer t
:straight (:build t)
:after lsp-mode
:hook (text-mode . lsp-deferred)
:init
(setq lsp-ltex-java-force-try-system-wide t
lsp-ltex-server-store-path nil
lsp-ltex-version (gethash "ltex-ls"
(json-parse-string
(replace-regexp-in-string
(rx "Picked" (* any) "\n")
""
(shell-command-to-string "ltex-ls -V"))))
lsp-ltex-check-frequency "save"
lsp-ltex-language "auto"
lsp-ltex-mother-tongue "fr"))
#+end_src
Finally, =writegood-mode= detects some simple general rules when writing
in English and can also calculate the Flesh-Kincaid levels of a
document.
2021-11-20 22:10:37 +00:00
#+begin_src emacs-lisp
(use-package writegood-mode
:defer t
:straight (:build t)
:hook org-mode latex-mode
:general
(phundrak/major-leader-key
:keymaps 'writegood-mode-map
"g" #'writegood-grade-level
"r" #'writegood-reading-ease))
#+end_src
**** Spellcheck
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-Tools-Spellcheck-wos8d0y0y9j0
:END:
#+begin_src emacs-lisp
(use-package ispell
2022-06-10 08:41:08 +00:00
:if (executable-find "aspell")
2021-11-20 22:10:37 +00:00
:defer t
:straight (:type built-in)
:config
2021-11-22 10:20:52 +00:00
(add-to-list 'ispell-skip-region-alist '(":\\(PROPERTIES\\|LOGBOOK\\):" . ":END:"))
(add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_SRC" . "#\\+END_SRC"))
(add-to-list 'ispell-skip-region-alist '("#\\+BEGIN_EXAMPLE" . "#\\+END_EXAMPLE"))
2021-11-20 22:10:37 +00:00
(setq ispell-program-name "aspell"
ispell-extra-args '("--sug-mode=ultra" "--run-together")
ispell-aspell-dict-dir (ispell-get-aspell-config-value "dict-dir")
ispell-aspell-data-dir (ispell-get-aspell-config-value "data-dir")
ispell-personal-dictionary (expand-file-name (concat "ispell/" ispell-dictionary ".pws")
user-emacs-directory)))
#+end_src
#+begin_src emacs-lisp
(use-package flyspell
:defer t
:straight (:type built-in)
:ghook 'org-mode 'markdown-mode 'TeX-mode
:init
(defhydra flyspell-hydra ()
"
Spell Commands^^ Add To Dictionary^^ Other
--------------^^---------- -----------------^^------------- -----^^---------------------------
[_b_ ] check whole buffer [_B_ ] add word to dict (buffer) [_t_ ] toggle spell check
[_r_ ] check region [_G_ ] add word to dict (global) [_q_ ] exit
[_d_ ] change dictionary [_S_ ] add word to dict (session) [_Q_ ] exit and disable spell check
[_n_ ] next error
[_c_ ] correct before point
2022-10-19 13:07:28 +00:00
[_s_ ] correct at point
"
2021-11-20 22:10:37 +00:00
("B" nil)
("b" flyspell-buffer)
("r" flyspell-region)
2022-10-19 13:07:28 +00:00
("d" ispell-change-dictionary)
2021-11-20 22:10:37 +00:00
("G" nil)
("n" flyspell-goto-next-error)
("c" flyspell-correct-wrapper)
("Q" flyspell-mode :exit t)
("q" nil :exit t)
("S" nil)
("s" flyspell-correct-at-point)
("t" nil))
:config
(provide 'ispell) ;; force loading ispell
(setq flyspell-issue-welcome-flag nil
flyspell-issue-message-flag nil))
#+end_src
#+begin_src emacs-lisp
(use-package flyspell-correct
:defer t
:straight (:build t)
:general ([remap ispell-word] #'flyspell-correct-at-point)
:config
(require 'flyspell-correct-ivy nil t))
(use-package flyspell-correct-ivy
:defer t
:straight (:build t)
:after flyspell-correct)
#+end_src
#+begin_src emacs-lisp
(use-package flyspell-lazy
:defer t
:straight (:build t)
:after flyspell
:config
(setq flyspell-lazy-idle-seconds 1
flyspell-lazy-window-idle-seconds 3)
(flyspell-lazy-mode +1))
#+end_src
2021-07-30 17:01:29 +00:00
**** LSP-Mode
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-Tools-LSP-Mode-g4v5rsg0k4j0
:END:
[[https://emacs-lsp.github.io/lsp-mode/ ][~lsp-mode~ ]] is a mode for Emacs which implements the [[https://github.com/Microsoft/language-server-protocol/ ][Language Server
Protocol]] and offers Emacs an IDE-like experience. In short, it’ s
awesome!
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package lsp-mode
:defer t
:straight (:build t)
:init
2023-01-31 14:43:48 +00:00
(setq lsp-keymap-prefix "C-c l"
read-process-output-max (* 3 1024 1024))
2021-12-17 15:45:57 +00:00
:hook ((c-mode . lsp-deferred)
2021-10-12 09:31:20 +00:00
(c++-mode . lsp-deferred)
(html-mode . lsp-deferred)
2022-02-17 22:38:01 +00:00
(sh-mode . lsp-deferred)
2021-10-12 09:31:20 +00:00
(lsp-mode . lsp-enable-which-key-integration)
(lsp-mode . lsp-ui-mode))
:commands (lsp lsp-deferred)
:custom
(lsp-rust-analyzer-cargo-watch-command "clippy")
(lsp-eldoc-render-all t)
(lsp-idle-delay 0.6)
2022-02-17 22:38:01 +00:00
(lsp-rust-analyzer-server-display-inlay-hints t)
2022-03-27 20:17:55 +00:00
(lsp-use-plist t)
2022-02-17 22:38:01 +00:00
:config
(lsp-register-client
(make-lsp-client :new-connection (lsp-tramp-connection "shellcheck")
:major-modes '(sh-mode)
:remote? t
:server-id 'shellcheck-remote)))
2021-07-30 17:01:29 +00:00
#+end_src
I also want all the visual enhancements LSP can provide.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package lsp-ui
:after lsp
:defer t
:straight (:build t)
:commands lsp-ui-mode
:custom
(lsp-ui-peek-always-show t)
(lsp-ui-sideline-show-hover t)
(lsp-ui-doc-enable t)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:keymaps 'lsp-ui-peek-mode-map
:packages 'lsp-ui
"c" #'lsp-ui-pook--select-prev-file
"t" #'lsp-ui-pook--select-next
"s" #'lsp-ui-pook--select-prev
"r" #'lsp-ui-pook--select-next-file))
2021-07-30 17:01:29 +00:00
#+end_src
And let’ s enable some intergration with ~ivy~ .
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package lsp-ivy
:straight (:build t)
:defer t
:after lsp
:commands lsp-ivy-workspace-symbol)
2021-07-30 17:01:29 +00:00
#+end_src
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package lsp-treemacs
:defer t
2023-03-10 14:30:17 +00:00
:straight (:build t))
2021-07-30 17:01:29 +00:00
#+end_src
2021-11-28 21:51:48 +00:00
#+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 |
2023-03-10 14:30:17 +00:00
| pa | treemacs-add-project-to-workspace | |
2021-11-28 21:51:48 +00:00
| 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 | |
2021-07-30 17:01:29 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package exec-path-from-shell
:defer t
:straight (:build t)
:init (exec-path-from-shell-initialize))
2021-07-30 17:01:29 +00:00
#+end_src
2021-10-18 15:31:17 +00:00
#+begin_src emacs-lisp
(use-package consult-lsp
:defer t
:after lsp
:straight (:build t)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
:keymaps 'lsp-mode-map
[remap xref-find-apropos] #'consult-lsp-symbols))
2021-10-18 15:31:17 +00:00
#+end_src
2023-03-10 14:32:10 +00:00
~dap-mode~ is an advanced debugging mode that works through LSP. Note
that currently, ~dap-firefox~ and ~dap-chrome~ don’ t work correctly due to
[[https://github.com/emacs-lsp/dap-mode/issues/547 ][this issue ]]. A workaround can be found in [[https://github.com/emacs-lsp/dap-mode/issues/554#issuecomment-1171256089 ][this comment ]] though.
2021-07-30 17:01:29 +00:00
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package dap-mode
:after lsp
:defer t
:straight (:build t)
:config
(dap-ui-mode)
(dap-ui-controls-mode 1)
2023-03-10 14:32:10 +00:00
(add-hook 'dap-stopped-hook
(lambda (arg) (call-interactively #'dap-hydra)))
:init
;; JS/TS
(with-eval-after-load 'web-mode
(require 'dap-firefox)
(require 'dap-chrome)
(require 'dap-node))
;; Rust
(with-eval-after-load 'rustic-mode
(require 'dap-lldb)
(require 'dap-gdb-lldb)
(dap-register-debug-template
"Rust::LLDB Run Configuration"
(list :type "lldb"
:request "launch"
:name "LLDB::Run"
:gdbpath "rust-lldb"
:target nil
:cwd nil))))
2021-07-30 17:01:29 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** DSLs
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLsbwu5fl6184j0
:END:
2021-05-23 23:18:51 +00:00
DSLs, or /Domain Specific Languages/ , are languages dedicated to some
very tasks, such as configuration languages or non-general programming
such as SQL.
2021-05-23 23:25:37 +00:00
2022-08-07 10:57:28 +00:00
**** Makefiles
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-DSLs-Makefiles-2855jdn06jj0
:END:
#+begin_src emacs-lisp
(defun my/local-tab-indent ()
(setq-local indent-tabs-mode 1))
(add-hook 'makefile-mode-hook #'my/local-tab-indent)
#+end_src
2021-05-23 23:18:51 +00:00
**** Caddy
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Caddy0fw5fl6184j0
:END:
2021-05-23 23:18:51 +00:00
[[https://caddyserver.com/ ][Caddy ]] (or /Caddyserver/ ) is a web server akin to Nginx or Apache which I
find much easier to configure that the latter two, plus it has
built-in support for automatically generating SSL certificates with
Letsencrypt! Automatic HTTPS, what more do you want?
2021-05-21 11:59:48 +00:00
2021-05-23 23:18:51 +00:00
All that is nice and all, but Emacs doesn’ t support the syntax of
Caddy files natively, so let’ s install ~caddyfile-mode~ :
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package caddyfile-mode
:defer t
:straight (:build t)
:mode (("Caddyfile\\'" . caddyfile-mode)
("caddy\\.conf\\'" . caddyfile-mode)))
2021-05-23 23:18:51 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-07-30 17:01:29 +00:00
**** CMake
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-CMake-vpqkiyp0m5j0
:END:
CMake is one of the standard tools for indicating how a project should
be built. It is not as standard as some other tools such as automake,
autoconfig, and the likes, but still pretty standard. CMake however
doesn’ t have a major mode available by default, so let’ s provide one.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package cmake-mode
:defer t
:straight (:build t))
2021-07-30 17:01:29 +00:00
#+end_src
Let’ s enable first some autocompletion for it.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package company-cmake
:straight (company-cmake :build t
:type git
:host github
:repo "purcell/company-cmake")
:after cmake-mode
:defer t)
2021-07-30 17:01:29 +00:00
#+end_src
And let’ s also enable a more advanced CMake fontlock.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package cmake-font-lock
:defer t
:after cmake-mode
:straight (:build t))
2021-07-30 17:01:29 +00:00
#+end_src
And finally, let’ s enable some Eldoc integration for CMake.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package eldoc-cmake
:straight (:build t)
:defer t
:after cmake-mode)
2021-07-30 17:01:29 +00:00
#+end_src
2021-12-17 15:30:29 +00:00
**** CSV
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-CSV-z1vh3rt0uaj0
:END:
#+begin_src emacs-lisp
(use-package csv-mode
:straight (:build t)
:defer t
:general
(phundrak/major-leader-key
:keymaps 'csv-mode-map
"a" #'csv-align-fields
"d" #'csv-kill-fields
"h" #'csv-header-line
"i" #'csv-toggle-invisibility
"n" #'csv-forward-field
"p" #'csv-backward-field
"r" #'csv-reverse-region
"s" '(:ignore t :wk "sort")
"sf" #'csv-sort-fields
"sn" #'csv-sort-numeric-fields
"so" #'csv-toggle-descending
"t" #'csv-transpose
"u" #'csv-unalign-fields
"y" '(:ignore t :wk yank)
"yf" #'csv-yank-fields
"yt" #'csv-yank-as-new-table))
#+end_src
2022-07-12 02:30:18 +00:00
**** Dotenv
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-DSLs-Dotenv-b7kb2gr0kij0
:END:
It is not rare to encounter a dotenv file, that is, a file with either
the ~.env~ extension or simply called ~.env~ . They contain environment
variables for projects which might rely on values you do not want to
upload to a public git repository and such. While their syntax is
similar to shell files, they’ re not exactly shell files either since
there’ s rarely any script inside running. So, let’ s install a simple
package which will dumb down a lot ~sh-mode~ for these dotenv files.
#+begin_src emacs-lisp
(use-package dotenv-mode
:defer t
:straight (:build t))
#+end_src
2021-06-09 15:22:47 +00:00
**** Gnuplot
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Gnuplot8zx5fl6184j0
:END:
2021-06-09 15:22:47 +00:00
This package is a front-end and major mode for the programming
language [[http://www.gnuplot.info/ ][Gnuplot ]]. Let’ s make some beautiful graphs, shall we?
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package gnuplot
:straight (:build t)
:defer t)
2021-06-09 15:22:47 +00:00
#+end_src
2021-10-07 16:32:36 +00:00
**** Graphviz
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Graphviz-zifi28c1e8j0
:END:
[[https://graphviz.org/ ][Graphviz ]], often known with ~dot~ , allows to programatically create
visual graphs and networks.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package graphviz-dot-mode
:defer t
2021-11-22 10:18:43 +00:00
:straight (:build t)
2022-06-18 13:46:42 +00:00
:after org
2021-11-22 10:18:43 +00:00
:mode (("\\.diag\\'" . graphviz-dot-mode)
("\\.blockdiag\\'" . graphviz-dot-mode)
("\\.nwdiag\\'" . graphviz-dot-mode)
("\\.rackdiag\\'" . graphviz-dot-mode)
("\\.dot\\'" . graphviz-dot-mode)
("\\.gv\\'" . graphviz-dot-mode))
:init
(setq graphviz-dot-indent-width tab-width)
2022-06-18 13:46:42 +00:00
(with-eval-after-load 'org
2021-11-27 18:30:09 +00:00
(defalias 'org-babel-execute:graphviz-dot #'org-babel-execute:dot)
(add-to-list 'org-babel-load-languages '(dot . t))
(require 'ob-dot)
(setq org-src-lang-modes
(append '(("dot" . graphviz-dot))
(delete '("dot" . fundamental) org-src-lang-modes))))
2021-11-22 10:18:43 +00:00
:general
(phundrak/major-leader-key
:keymaps 'graphviz-dot-mode-map
"=" #'graphviz-dot-indent-graph
"c" #'compile)
2021-10-12 09:31:20 +00:00
:config
(setq graphviz-dot-indent-width 4))
2021-10-07 16:32:36 +00:00
#+end_src
2021-10-23 11:24:04 +00:00
**** Markdown
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Markdown-7sljsrb1y8j0
:END:
Yes, I love org-mode and I largely prefer to use it instead of
Markdown due to its far superior power and abilities. But still,
2023-03-20 16:17:57 +00:00
sometimes I need to use Markdown because not everyone uses org-mode,
2021-10-23 11:24:04 +00:00
unfortunately.
#+begin_src emacs-lisp
(use-package markdown-mode
:defer t
2021-10-25 14:59:07 +00:00
:straight t
2021-10-23 11:24:04 +00:00
:mode
(("\\.mkd\\'" . markdown-mode)
("\\.mdk\\'" . markdown-mode)
("\\.mdx\\'" . markdown-mode))
:hook (markdown-mode . orgtbl-mode)
2022-02-11 10:11:48 +00:00
:hook (markdown-mode . visual-line-mode)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
:keymaps 'markdown-mode-map
2022-06-21 14:36:31 +00:00
:packages '(markdown-mode evil)
2021-11-07 01:27:04 +00:00
"M-RET" #'markdown-insert-list-item
"M-c" #'markdown-promote
"M-t" #'markdown-move-down
"M-s" #'markdown-move-up
2022-06-21 14:36:31 +00:00
"M-r" #'markdown-demote
"t" #'evil-next-visual-line
"s" #'evil-previous-visual-line)
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
:keymaps 'markdown-mode-map
2021-11-07 14:54:20 +00:00
:packages 'markdown-mode
2021-11-07 01:27:04 +00:00
"{" #'markdown-backward-paragraph
"}" #'markdown-forward-paragraph
"]" #'markdown-complete
">" #'markdown-indent-region
"»" #'markdown-indent-region
"<" #'markdown-outdent-region
"«" #'markdown-outdent-region
"n" #'markdown-next-link
"p" #'markdown-previous-link
"f" #'markdown-follow-thing-at-point
"k" #'markdown-kill-thing-at-point
2021-11-28 21:51:48 +00:00
"c" '(:ignore t :which-key "command")
2021-11-07 01:27:04 +00:00
"c]" #'markdown-complete-buffer
"cc" #'markdown-check-refs
"ce" #'markdown-export
"cm" #'markdown-other-window
"cn" #'markdown-cleanup-list-numbers
"co" #'markdown-open
"cp" #'markdown-preview
"cv" #'markdown-export-and-preview
"cw" #'markdown-kill-ring-save
2021-11-28 21:51:48 +00:00
"h" '(:ignore t :which-key "headings")
2021-11-07 01:27:04 +00:00
"hi" #'markdown-insert-header-dwim
"hI" #'markdown-insert-header-setext-dwim
"h1" #'markdown-insert-header-atx-1
"h2" #'markdown-insert-header-atx-2
"h3" #'markdown-insert-header-atx-3
"h4" #'markdown-insert-header-atx-4
"h5" #'markdown-insert-header-atx-5
"h6" #'markdown-insert-header-atx-6
"h!" #'markdown-insert-header-setext-1
"h@" #'markdown-insert-header-setext-2
2021-11-28 21:51:48 +00:00
"i" '(:ignore t :which-key "insert")
2021-11-07 01:27:04 +00:00
"i-" #'markdown-insert-hr
"if" #'markdown-insert-footnote
"ii" #'markdown-insert-image
"il" #'markdown-insert-link
"it" #'markdown-insert-table
"iw" #'markdown-insert-wiki-link
2021-11-28 21:51:48 +00:00
"l" '(:ignore t :which-key "lists")
2021-11-07 01:27:04 +00:00
"li" #'markdown-insert-list-item
2021-11-28 21:51:48 +00:00
"T" '(:ignore t :which-key "toggle")
2021-11-07 01:27:04 +00:00
"Ti" #'markdown-toggle-inline-images
"Tu" #'markdown-toggle-url-hiding
"Tm" #'markdown-toggle-markup-hiding
"Tt" #'markdown-toggle-gfm-checkbox
"Tw" #'markdown-toggle-wiki-links
2021-11-28 21:51:48 +00:00
"t" '(:ignore t :which-key "table")
2021-11-07 01:27:04 +00:00
"tc" #'markdown-table-move-column-left
"tt" #'markdown-table-move-row-down
"ts" #'markdown-table-move-row-up
"tr" #'markdown-table-move-column-right
"ts" #'markdown-table-sort-lines
"tC" #'markdown-table-convert-region
"tt" #'markdown-table-transpose
2021-11-28 21:51:48 +00:00
"td" '(:ignore t :which-key "delete")
2021-11-07 01:27:04 +00:00
"tdc" #'markdown-table-delete-column
"tdr" #'markdown-table-delete-row
2021-11-28 21:51:48 +00:00
"ti" '(:ignore t :which-key "insert")
2021-11-07 01:27:04 +00:00
"tic" #'markdown-table-insert-column
"tir" #'markdown-table-insert-row
2021-11-28 21:51:48 +00:00
"x" '(:ignore t :which-key "text")
2021-11-07 01:27:04 +00:00
"xb" #'markdown-insert-bold
"xB" #'markdown-insert-gfm-checkbox
"xc" #'markdown-insert-code
"xC" #'markdown-insert-gfm-code-block
"xi" #'markdown-insert-italic
"xk" #'markdown-insert-kbd
"xp" #'markdown-insert-pre
"xP" #'markdown-pre-region
"xs" #'markdown-insert-strike-through
"xq" #'markdown-blockquote-region)
2021-11-07 14:54:20 +00:00
:config
2021-10-23 11:24:04 +00:00
(setq markdown-fontify-code-blocks-natively t))
#+end_src
2023-03-20 16:17:57 +00:00
Since most of my Markdown files are related to GitHub, I’ d like to be
2021-10-23 11:24:04 +00:00
able to render Markdown through its API.
#+begin_src emacs-lisp
(use-package gh-md
:defer t
2021-10-25 14:59:07 +00:00
:after markdown-mode
2021-10-23 11:24:04 +00:00
:straight (:build t)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:packages 'gh-md
:keymaps 'markdown-mode-map
"cr" #'gh-md-render-buffer))
2021-10-23 11:24:04 +00:00
#+end_src
2023-03-20 16:17:57 +00:00
Sometimes, I have to work with GitHub’ s markdown flavour, but I’ m not
2022-08-08 18:37:03 +00:00
really a huge fan of writing it by hand. So instead, I’ ll write it in
org-mode and then export it with ~ox-gfm~ .
2022-04-02 13:05:16 +00:00
#+begin_src emacs-lisp
(use-package ox-gfm
:straight (:build t)
:defer t
:after (org ox))
#+end_src
2022-08-08 18:37:25 +00:00
Nuxt has its own flavour of Markdown, called [[https://content.nuxtjs.org/guide/writing/mdc/ ][MDC ]] (/MarkDown Components/ )
which is a godsend to write content for Nuxt websites! However, no
~mdc-mode~ existed when I began working with it, so I’ m working on one.
#+begin_src emacs-lisp
(use-package mdc-mode
:defer t
:after markdown-mode
:straight (mdc-mode :type git
:host github
:repo "Phundrak/mdc-mode"
:build t))
#+end_src
2021-10-23 11:24:04 +00:00
Tables of content are always nice to have for large files, just like
with the ~toc-org~ package for org-mode.
#+begin_src emacs-lisp
(use-package markdown-toc
:defer t
2021-10-25 14:59:07 +00:00
:after markdown-mode
2021-10-23 11:24:04 +00:00
:straight (:build t)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:packages 'markdown-toc
2021-11-07 01:27:04 +00:00
:keymaps 'markdown-mode-map
"iT" #'markdown-toc-generate-toc))
2021-10-23 11:24:04 +00:00
#+end_src
2022-05-14 22:38:11 +00:00
Lastly, ~edit-indirect~ is a package that allows to edit code blocks as
in org-mode but with other major modes, such as code blocks in
Markdown.
#+begin_src emacs-lisp
(use-package edit-indirect
:straight (:build t)
:defer t)
#+end_src
2021-05-23 23:18:51 +00:00
**** Nginx
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Nginxjiz5fl6184j0
:END:
2021-05-23 23:18:51 +00:00
Nginx is another webserver, older and more mature than Caddy. A couple
of packages are required in order to be able to properly work with
Nginx configuration files. First, we need the correct mode for editing
Nginx configuration files.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package nginx-mode
:straight (:build t)
:defer t)
2021-05-23 23:18:51 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-05-23 23:18:51 +00:00
We then also have an autocompletion package that adds to ~company~ the
Nginx syntax.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package company-nginx
2022-02-07 11:06:26 +00:00
:straight (company-nginx :build t
:type git
:host github
:repo "emacsmirror/company-nginx")
2021-10-12 09:31:20 +00:00
:defer t
:config
(add-hook 'nginx-mode-hook (lambda ()
(add-to-list 'company-backends #'company-nginx))))
2021-05-23 23:18:51 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-11-09 16:21:53 +00:00
**** PKGBUILD
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-PKGBUILD-ll37pjt0m9j0
:END:
As I am an ArchLinux user, I sometimes have to interact with PKGBUILD
files, both from the AUR when I want to install something from there
or some I write myself.
#+begin_src emacs-lisp
(use-package pkgbuild-mode
:straight (:build t)
:defer t
:general
(phundrak/major-leader-key
:keymaps 'pkgbuild-mode-map
"c" #'pkgbuild-syntax-check
"i" #'pkgbuild-initialize
"I" #'pkgbuild-increase-release-tag
"m" #'pkgbuild-makepkg
"u" '(:ignore :wk "update")
"us" #'pkgbuild-update-sums-line
"uS" #'pkgbuild-update-srcinfo))
#+end_src
2021-10-31 13:54:00 +00:00
**** PlantUML
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-PlantUML-9zo88og099j0
:END:
#+begin_src emacs-lisp
(use-package plantuml-mode
:defer t
2022-01-05 13:12:37 +00:00
:straight (:build t)
:mode ("\\.\\(pum\\|puml\\)\\'" . plantuml-mode)
2021-11-24 22:43:28 +00:00
:after ob
2021-10-31 13:54:00 +00:00
:init
(add-to-list 'org-babel-load-languages '(plantuml . t))
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
:keymaps 'plantuml-mode-map
2021-11-07 14:54:20 +00:00
:packages 'plantuml-mode
2021-11-28 21:51:48 +00:00
"c" '(:ignore t :which-key "compile")
2021-10-31 13:54:00 +00:00
"cc" #'plantuml-preview
"co" #'plantuml-set-output-type)
2021-11-07 14:54:20 +00:00
:config
2021-10-31 13:54:00 +00:00
(setq plantuml-default-exec-mode 'jar
plantuml-jar-path "~/.local/bin/plantuml.jar"
org-plantuml-jar-path "~/.local/bin/plantuml.jar"))
#+end_src
2023-03-10 14:32:32 +00:00
**** SDLang
:PROPERTIES:
:CUSTOM_ID: PackagesConfigurationProgrammingDSLsSDLang-x4q2uwx05rj0
:END:
I don’ t actually use [[https://sdlang.org/ ][SDLang ]] but [[https://kdl.dev/ ][KDL ]] in order to configure [[https://zellij.dev/ ][Zellij ]], but
KDL doesn’ t have a major mode for Emacs yet. Maybe I should work on
that?
#+begin_src emacs-lisp
(use-package sdlang-mode
:straight (:build t)
:defer t
:mode "\\.kdl\\'")
#+end_src
2021-06-09 15:22:47 +00:00
**** Shells
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Shellsn116fl6184j0
:END:
2021-06-09 15:22:47 +00:00
Aside from Eshell, my main shell on my machine is fish (see my [[file:fish.org][fish
config]]), therefore I need a mode for it.
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package fish-mode
:straight (:build t)
:defer t)
2021-06-09 15:22:47 +00:00
#+end_src
2022-10-19 13:06:44 +00:00
When editing some scripts though, I need to use the built-in ~shell-mode~ .
#+begin_src emacs-lisp
(use-package shell
:defer t
:straight (:type built-in)
:hook (shell-mode . tree-sitter-hl-mode))
#+end_src
2022-02-04 16:01:43 +00:00
**** SSH Config files
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-SSH-Config-files-wt9j1c909cj0
:END:
#+begin_src emacs-lisp
(use-package ssh-config-mode
:defer t
:straight (:build t))
#+end_src
2022-02-26 14:38:54 +00:00
**** Systemd
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Systemd-3a1dt090mdj0
:END:
#+begin_src emacs-lisp
(use-package systemd
:defer t
:straight (:build t)
:general
(phundrak/major-leader-key
:keymaps '(systemd-mode-map)
"d" '(systemd-doc-directives :which-key "directives manpage")
"o" 'systemd-doc-open))
#+end_src
2021-07-30 16:50:10 +00:00
**** Toml
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Toml-txu8xvk0k4j0
:END:
#+begin_src emacs-lisp
2021-10-12 09:31:20 +00:00
(use-package toml-mode
:straight (:build t)
:defer t
:mode "/\\(Cargo.lock\\|\\.cargo/config\\)\\'")
2021-07-30 16:50:10 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
**** Yaml
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Yamlsk26fl6184j0
:END:
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package yaml-mode
:defer t
:straight (:build t)
:mode "\\.yml\\'"
:mode "\\.yaml\\'")
2021-05-23 23:18:51 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-07-30 17:01:29 +00:00
*** General Programming Languages
2021-06-16 12:30:03 +00:00
:PROPERTIES:
2021-07-30 17:01:29 +00:00
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languageszn56fl6184j0
:END:
**** C/C++
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-C-C-2nfcmoz0i5j0
2021-06-16 12:30:03 +00:00
:END:
2021-07-30 17:01:29 +00:00
I know, I know, C and C++ no longer are closely related languages,
each one of them went their own way and learning C won’ t make you a
good C++ programmer, neither will the other way around. But, They are
still somewhat related, and Emacs thinks so too.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package cc-mode
:straight (:type built-in)
:defer t
:init
(put 'c-c++-backend 'safe-local-variable 'symbolp)
2022-10-19 13:06:44 +00:00
(add-hook 'c-mode-hook #'tree-sitter-hl-mode)
(add-hook 'c++-mode-hook #'tree-sitter-hl-mode)
2021-10-19 17:17:10 +00:00
:config
2021-11-07 01:27:04 +00:00
(require 'compile)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/undefine
:keymaps '(c-mode-map c++-mode-map)
";" nil)
(phundrak/major-leader-key
:keymaps '(c-mode-map c++-mode-map)
"l" '(:keymap lsp-command-map :which-key "lsp" :package lsp-mode))
(phundrak/evil
:keymaps '(c-mode-map c++-mode-map)
"ga" #'projectile-find-other-file
"gA" #'projectile-find-other-file-other-window))
2021-07-30 17:01:29 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-07-30 17:01:29 +00:00
Something that is also important when working with these languages is
respecting the ~.clang-format~ file that may be provided by a project.
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package clang-format+
:straight (:build t)
:defer t
:init
(add-hook 'c-mode-common-hook #'clang-format+-mode))
2021-07-30 17:01:29 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-07-30 17:01:29 +00:00
However, Emacs’ notion of C++ is somewhat outdated, so we need to
update its fontlock.
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package modern-cpp-font-lock
:straight (:build t)
:defer t
:hook (c++-mode . modern-c+ +-font-lock-mode))
2021-05-23 23:18:51 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-07-30 17:01:29 +00:00
**** CommonLisp
2021-06-16 12:30:03 +00:00
:PROPERTIES:
2021-07-30 17:01:29 +00:00
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-CommonLisp-gc2a7s31q5j0
2021-06-16 12:30:03 +00:00
:END:
2022-05-14 22:38:31 +00:00
In Lisp buffers, let’ s enable ~parinfer-rust-mode~ .
2021-07-30 17:01:29 +00:00
#+begin_src emacs-lisp
2022-05-14 22:38:31 +00:00
(use-package lisp-mode
:straight (:type built-in)
:defer t
:after parinfer-rust-mode
:hook (lisp-mode . parinfer-rust-mode)
:config
2022-10-26 11:09:27 +00:00
(put 'defcommand 'lisp-indent-function 'defun)
(setq inferior-lisp-program "/usr/bin/sbcl --noinform"))
2021-07-30 17:01:29 +00:00
#+end_src
2021-11-22 10:19:53 +00:00
My current window manager is StumpWM, inspired by Emacs and written in
CommonLisp. ~stumpwm-mode~ offers some integration between Emacs and
2023-03-20 16:17:57 +00:00
StumpWM that makes the user able to evaluate CommonLisp code and see
its effects in StumpWM immediately. Since my only use for CommonLisp
is for my StumpWM configuration, it should be automatically enabled
when entering ~lisp-mode~ .
2021-08-02 12:27:50 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package stumpwm-mode
:straight (:build t)
:defer t
2021-11-22 10:19:53 +00:00
:hook lisp-mode
2021-10-19 17:17:10 +00:00
:config
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-19 17:17:10 +00:00
:keymaps 'stumpwm-mode-map
2021-11-07 14:54:20 +00:00
:packages 'stumpwm-mode
2021-12-07 09:13:43 +00:00
"e" '(:ignore t :which-key "eval")
2021-10-19 17:17:10 +00:00
"ee" #'stumpwm-eval-last-sexp
"ed" #'stumpwm-eval-defun
"er" #'stumpwm-eval-region))
2021-08-02 12:27:50 +00:00
#+end_src
2021-12-17 15:27:09 +00:00
Sly enables some deep interactivity between Emacs and a CommonLisp
application running the Slynk backend. For an example, see [[file:stumpwm.org::#Utilities-Sly-kkok6oi0yaj0][my Sly
configuration for StumpWM]].
#+begin_src emacs-lisp
(use-package sly
:defer t
:straight (:build t))
#+end_src
2021-09-01 19:47:13 +00:00
**** Dart
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Dart-xkr3z8j0m6j0
:END:
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package dart-mode
:straight (:build t)
:defer t
2021-12-17 15:45:57 +00:00
:hook (dart-mode . lsp-deferred)
2021-10-19 17:17:10 +00:00
:mode "\\.dart\\'")
2021-09-01 19:47:13 +00:00
#+end_src
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package lsp-dart
:straight (:build t)
2023-01-23 09:45:46 +00:00
:defer t
:general
(phundrak/major-leader-key
:keymaps 'dart-mode-map
:packages '(lsp-mode lsp-dart)
"l" '(:keymap lsp-command-map :which-key "lsp")))
2021-09-01 19:47:13 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
**** EmacsLisp
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-EmacsLispo876fl6184j0
:END:
2021-05-24 00:18:14 +00:00
This package displays the function’ s arglist or variable’ s docstring
in the echo area at the bottom of the frame. Quite useful indeed.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package eldoc
:defer t
:after company
:init
(eldoc-add-command 'company-complete-selection
'company-complete-common
'company-capf
'company-abort))
2021-05-23 23:18:51 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-07-30 17:01:29 +00:00
#+begin_src emacs-lisp
2023-03-10 14:32:55 +00:00
(use-package elisp-mode
:straight (:type built-in)
:requires smartparens
:config
(add-hook 'emacs-lisp-mode-hook (lambda () (smartparens-mode -1))))
2021-07-30 17:01:29 +00:00
#+end_src
2022-04-06 17:01:41 +00:00
Still on the topic of documentation, I sometimes find it lacks
examples on how to use Elisp functions. ~elisp-demos~ got you covered!
#+begin_src emacs-lisp
(use-package elisp-demos
:defer t
:straight (:build t)
:config
(advice-add 'helpful-update :after #'elisp-demos-advice-helpful-update))
#+end_src
2022-06-15 19:50:04 +00:00
#+begin_src emacs-lisp
(use-package epdh
:straight (epdh :type git
:host github
:repo "alphapapa/emacs-package-dev-handbook"
:build t)
:defer t)
#+end_src
2021-05-24 00:18:14 +00:00
Let’ s also declare some Elisp-dedicated keybindings, prefixed by a
comma.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-19 17:17:10 +00:00
:keymaps 'emacs-lisp-mode-map
"'" #'ielm
"c" '(emacs-lisp-byte-compile :which-key "Byte compile")
2021-12-07 09:13:43 +00:00
"C" '(:ignore t :which-key "checkdoc")
2021-11-08 13:26:40 +00:00
"Cc" #'checkdoc
"Cs" #'checkdoc-start
2021-12-07 09:13:43 +00:00
"e" '(:ignore t :which-key "eval")
2021-10-19 17:17:10 +00:00
"eb" #'eval-buffer
"ed" #'eval-defun
"ee" #'eval-last-sexp
"er" #'eval-region
2021-05-23 23:18:51 +00:00
2021-11-28 21:51:48 +00:00
"h" '(:ignore t :which-key "help")
2021-10-19 17:17:10 +00:00
"hh" #'helpful-at-point
2021-05-23 23:18:51 +00:00
2021-11-28 21:51:48 +00:00
"t" '(:ignore t :wk "toggle")
"tP" '(:ignore t :wk "parinfer")
2021-10-19 17:17:10 +00:00
"tPs" #'parinfer-rust-switch-mode
"tPd" #'parinfer-rust-mode-disable
"tPp" #'parinfer-rust-toggle-paren-mode)
2021-05-21 11:59:48 +00:00
#+end_src
2022-04-06 17:01:41 +00:00
Package linting is important when you want to publish your packages to
the world.
2021-11-08 13:27:10 +00:00
#+begin_src emacs-lisp
(use-package package-lint
:defer t
:straight (:build t)
:general
(phundrak/major-leader-key
:keymaps 'emacs-lisp-mode-map
:packages 'package-lint
"l" #'package-lint-current-buffer))
#+end_src
2022-05-31 19:00:57 +00:00
If I need to run CI on a package, [[https://github.com/cask/cask ][Cask ]] manages its dependencies.
#+begin_src emacs-lisp
(use-package cask-mode
:defer t
:straight (:build t))
#+end_src
2022-08-08 18:37:12 +00:00
However, I recently began using [[https://github.com/emacs-eask/eask ][Eask ]] more and more, I find it nicer to
2023-03-20 16:17:57 +00:00
work with, and it has a lot more features than Cask.
2022-08-08 18:37:12 +00:00
#+begin_src emacs-lisp
2022-11-19 09:03:53 +00:00
(use-package eask-api
:defer t
:straight (eask-api :type git
:host github
:repo "emacs-eask/eask-api"))
2022-08-08 18:37:12 +00:00
(use-package eask-mode
:defer t
:straight (eask-mode :type git
:host github
:repo "emacs-eask/eask-mode"))
#+end_src
2023-03-10 14:27:50 +00:00
**** Java
:PROPERTIES:
:CUSTOM_ID: PackagesConfigurationProgrammingGeneralProgrammingLanguagesJava-7p420oc0rqj0
:END:
Emacs has built-in support for Java, but it still lacks some features.
The main one is being able to replace an IDE, so let’ s install its LSP
package.
#+begin_src emacs-lisp
(use-package lsp-java
:requires lsp
:straight (:build t)
:after lsp
:hook (java-mode . lsp-deferred))
#+end_src
2021-09-01 19:47:13 +00:00
**** Python
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Python-7mwd2yq0z6j0
:END:
2021-12-17 15:28:49 +00:00
First, we need to set up the main Python mode. With this, we’ ll also
add Python to the list of LSP languages and to the list of languages
org-babel supports.
2021-09-01 19:47:13 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package python
:defer t
:straight (:build t)
2021-11-24 22:43:28 +00:00
:after ob
2021-10-19 17:17:10 +00:00
:mode (("SConstruct\\'" . python-mode)
("SConscript\\'" . python-mode)
("[./]flake8\\'" . conf-mode)
("/Pipfile\\'" . conf-mode))
:init
(setq python-indent-guess-indent-offset-verbose nil)
(add-hook 'python-mode-local-vars-hook #'lsp)
:config
(setq python-indent-guess-indent-offset-verbose nil)
(when (and (executable-find "python3")
2021-12-17 15:28:49 +00:00
(string= python-shell-interpreter "python"))
2023-01-23 09:45:46 +00:00
(setq python-shell-interpreter "python3"))
:general
(phundrak/major-leader-key
:keymaps 'python-mode-map
:packages 'lsp-mode
"l" '(:keymap lsp-command-map :which-key "lsp")))
2021-09-01 19:47:13 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Now let’ s add a package for [[https://docs.pytest.org/en/latest/ ][pytest ]].
2021-09-01 19:47:13 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package pytest
:defer t
:straight (:build t)
:commands (pytest-one
pytest-pdb-one
pytest-all
pytest-pdb-all
pytest-last-failed
pytest-pdb-last-failed
pytest-module
pytest-pdb-module)
:config
(add-to-list 'pytest-project-root-files "setup.cfg")
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-19 17:17:10 +00:00
:keymaps 'python-mode-map
2021-11-07 14:54:20 +00:00
:infix "t"
:packages 'pytest
2021-12-07 09:13:43 +00:00
"" '(:ignore t :which-key "test")
2021-11-07 14:54:20 +00:00
"a" #'python-pytest
"f" #'python-pytest-file-dwim
"F" #'python-pytest-file
"t" #'python-pytest-function-dwim
"T" #'python-pytest-function
"r" #'python-pytest-repeat
"p" #'python-pytest-dispatch))
2021-09-01 19:47:13 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Poetry is a nice tool with which we can manage our Python runtime
version as well as our dependencies.
2021-09-01 19:47:13 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package poetry
:defer t
:straight (:build t)
:commands (poetry-venv-toggle
poetry-tracking-mode)
:config
(setq poetry-tracking-strategy 'switch-buffer)
(add-hook 'python-mode-hook #'poetry-tracking-mode))
2021-09-01 19:47:13 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
This package will bring a new major mode for editing pip requirements.
2021-09-01 19:47:13 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package pip-requirements
:defer t
:straight (:build t))
2021-09-01 19:47:13 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Why use the command line to interact with pip when we can do it with
an Emacs frontend?
#+begin_src emacs-lisp
(use-package pippel
:defer t
:straight (:build t)
:general
(phundrak/major-leader-key
:keymaps 'python-mode-map
:packages 'pippel
"P" #'pippel-list-packages))
#+end_src
This is a [[https://github.com/pypa/pipenv ][pipenv ]] porcelain
2021-09-01 19:47:13 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package pipenv
:defer t
:straight (:build t)
:commands (pipenv-activate
pipenv-deactivate
pipenv-shell
pipenv-open
pipenv-install
pipenv-uninstall)
:hook (python-mode . pipenv-mode)
:init (setq pipenv-with-projectile nil)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-19 17:17:10 +00:00
:keymaps 'python-mode-map
2021-11-07 14:54:20 +00:00
:packages 'pipenv
:infix "e"
2021-12-07 09:13:43 +00:00
"" '(:ignore t :which-key "pipenv")
2021-11-07 14:54:20 +00:00
"a" #'pipenv-activate
"d" #'pipenv-deactivate
"i" #'pipenv-install
"l" #'pipenv-lock
"o" #'pipenv-open
"r" #'pipenv-run
"s" #'pipenv-shell
"u" #'pipenv-uninstall))
2021-09-01 19:47:13 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
This integrates ~pyenv~ into ~python-mode~ .
2021-09-01 19:47:13 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package pyenv
:defer t
:straight (:build t)
:config
(add-hook 'python-mode-hook #'pyenv-track-virtualenv)
(add-to-list 'global-mode-string
'(pyenv-virtual-env-name (" venv:" pyenv-virtual-env-name " "))
'append))
2021-09-01 19:47:13 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Let’ s also add a mode for ~pyenv~ :
2021-09-01 19:47:13 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package pyenv-mode
:defer t
:after python
:straight (:build t)
:if (executable-find "pyenv")
:commands (pyenv-mode-versions)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:packages 'pyenv-mode
:keymaps 'python-mode-map
:infix "v"
"u" #'pyenv-mode-unset
"s" #'pyenv-mode-set))
2021-09-01 19:47:13 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
This package automatically imports packages we forgot to import.
2021-09-01 19:47:13 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package pyimport
:defer t
:straight (:build t)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-11-07 14:54:20 +00:00
:packages 'pyimport
:keymaps 'python-mode-map
:infix "i"
2021-12-07 09:13:43 +00:00
"" '(:ignore t :which-key "imports")
2021-11-07 14:54:20 +00:00
"i" #'pyimport-insert-missing
"r" #'pyimport-remove-unused))
2021-10-19 17:17:10 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
On the other hand, this one sorts our imports to make them more readable.
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package py-isort
:defer t
:straight (:build t)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-19 17:17:10 +00:00
:keymaps 'python-mode-map
2021-11-07 14:54:20 +00:00
:packages 'py-isort
:infix "i"
2021-12-07 09:13:43 +00:00
"" '(:ignore t :which-key "imports")
2021-11-07 14:54:20 +00:00
"s" #'py-isort-buffer
"R" #'py-isort-region))
2021-10-19 17:17:10 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Access pydoc through counsel.
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package counsel-pydoc
:defer t
:straight (:build t))
#+end_src
2021-12-17 15:28:49 +00:00
This generates Python documentation that is meant to be compatible
with Sphinx, a documentation generaton for Python.
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package sphinx-doc
:defer t
:straight (:build t)
:init
(add-hook 'python-mode-hook #'sphinx-doc-mode)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-19 17:17:10 +00:00
:keymaps 'python-mode-map
2021-11-07 14:54:20 +00:00
:packages 'sphinx-doc
:infix "S"
2021-12-07 09:13:43 +00:00
"" '(:ignore t :which-key "sphinx-doc")
2021-11-07 14:54:20 +00:00
"e" #'sphinx-doc-mode
"d" #'sphinx-doc))
2021-10-19 17:17:10 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Cython is a Python to C compiler. It also introduces the extended
Cython programming language which makes writing C for Python easier.
This package is a major mode for the Cython programming language.
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package cython-mode
:defer t
:straight (:build t)
:mode "\\.p\\(yx\\|x[di]\\)\\'"
:config
(setq cython-default-compile-format "cython -a %s")
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-19 17:17:10 +00:00
:keymaps 'cython-mode-map
2021-11-07 14:54:20 +00:00
:packages 'cython-mode
:infix "c"
2021-12-07 09:13:43 +00:00
"" '(:ignore t :which-key "cython")
2021-11-07 14:54:20 +00:00
"c" #'cython-compile))
2021-10-19 17:17:10 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Flycheck can also be enabled for Cython:
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package flycheck-cython
:defer t
:straight (:build t)
:after cython-mode)
#+end_src
2021-12-17 15:28:49 +00:00
Blacken uses the ~black~ formatter backend to format Python buffers.
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package blacken
:defer t
:straight (:build t)
:init
(add-hook 'python-mode-hook #'blacken-mode))
#+end_src
2021-12-17 15:28:49 +00:00
Finally, I’ m using [[https://github.com/microsoft/pyright ][Pyright ]] as my LSP backend for Python.
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package lsp-pyright
:after lsp-mode
:defer t
:straight (:buidl t))
2021-09-01 19:47:13 +00:00
#+end_src
2021-07-30 17:01:29 +00:00
**** Rust
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Rust-n3jhh5h0k4j0
:END:
Rust is a general programming language, akin to C++ in some ways, but
much more oriented towards safe code, and much better suited for web
development. First, let’ s install the most important package,
~rustic~ .
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package rustic
:defer t
:straight (:build t)
2021-12-12 14:06:00 +00:00
:mode ("\\.rs\\'" . rustic-mode)
2021-12-17 15:45:57 +00:00
:hook (rustic-mode-local-vars . rustic-setup-lsp)
:hook (rustic-mode . lsp-deferred)
2021-10-19 17:17:10 +00:00
:init
2022-06-18 13:46:42 +00:00
(with-eval-after-load 'org
2021-10-19 17:17:10 +00:00
(defalias 'org-babel-execute:rust #'org-babel-execute:rustic)
(add-to-list 'org-src-lang-modes '("rust" . rustic)))
2021-12-17 15:45:57 +00:00
(setq rustic-lsp-client 'lsp-mode)
2022-10-19 13:06:44 +00:00
(add-hook 'rustic-mode-hook #'tree-sitter-hl-mode)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(general-define-key
:keymaps 'rustic-mode-map
2021-11-07 14:54:20 +00:00
:packages 'lsp
2021-11-07 01:27:04 +00:00
"M-t" #'lsp-ui-imenu
"M-?" #'lsp-find-references)
2023-01-23 09:45:46 +00:00
(phundrak/major-leader-key
:keymaps 'rustic-mode-map
:packages 'lsp-mode
"l" '(:keymap lsp-command-map :which-key "lsp"))
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
:keymaps 'rustic-mode-map
2021-11-07 14:54:20 +00:00
:packages 'rustic
2021-12-07 09:13:43 +00:00
"b" '(:ignore t :which-key "build")
2021-10-19 17:17:10 +00:00
"bb" #'rustic-cargo-build
"bB" #'rustic-cargo-bench
"bc" #'rustic-cargo-check
"bC" #'rustic-cargo-clippy
"bd" #'rustic-cargo-doc
"bf" #'rustic-cargo-fmt
"bn" #'rustic-cargo-new
"bo" #'rustic-cargo-outdated
"br" #'rustic-cargo-run
2021-12-07 09:13:43 +00:00
"t" '(:ignore t :which-key "cargo test")
2021-10-19 17:17:10 +00:00
"ta" #'rustic-cargo-test
"tt" #'rustic-cargo-current-test)
2021-11-07 14:54:20 +00:00
:config
2021-10-19 17:17:10 +00:00
(setq rustic-indent-method-chain t
rustic-babel-format-src-block nil
rustic-format-trigger nil)
(remove-hook 'rustic-mode-hook #'flycheck-mode)
(remove-hook 'rustic-mode-hook #'flymake-mode-off)
2021-12-17 15:45:57 +00:00
(remove-hook 'rustic-mode-hook #'rustic-setup-lsp))
2021-07-30 17:01:29 +00:00
#+end_src
**** Web programming
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Web-programming-7ca40po085j0
:END:
2021-12-17 15:28:49 +00:00
[[https://emmet.io/ ][Emmet ]] is a powerful templating engine that can generate through simple
2023-03-20 16:17:57 +00:00
CSS-like expression some HTML to avoid the user writing everything by
2021-12-17 15:28:49 +00:00
hand.
2021-07-30 17:01:29 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package emmet-mode
:straight (:build t)
:defer t
:hook ((css-mode . emmet-mode)
(html-mode . emmet-mode)
(web-mode . emmet-mode)
(sass-mode . emmet-mode)
(scss-mode . emmet-mode)
(web-mode . emmet-mode))
:config
(general-define-key
:keymaps 'emmet-mode-keymap
2022-06-10 08:41:48 +00:00
"M-RET" #'emmet-expand-yas)
(phundrak/major-leader-key
:keymaps 'web-mode-map
:packages '(web-mode emmet-mode)
"e" '(:ignore t :which-key "emmet")
"ee" #'emmet-expand-line
"ep" #'emmet-preview
2022-06-15 19:40:08 +00:00
"eP" #'emmet-preview-mode
2022-06-10 08:41:48 +00:00
"ew" #'emmet-wrap-with-markup))
2021-10-19 17:17:10 +00:00
#+end_src
2023-03-20 16:17:57 +00:00
Impatient mode serves web buffers live over HTTP, including your live
modifications.
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package impatient-mode
:straight (:build t)
:defer t)
#+end_src
2021-12-17 15:28:49 +00:00
Web mode is a sort of hybrid major mode that allows editing several
languages in the same buffer, mainly HTML, CSS, and Javascript.
2021-10-19 17:17:10 +00:00
#+begin_src emacs-lisp
(use-package web-mode
:defer t
:straight (:build t)
2022-08-16 11:36:03 +00:00
:hook html-mode
:hook (web-mode . prettier-js-mode)
2022-08-16 11:39:29 +00:00
:hook (web-mode . lsp-deferred)
2021-10-19 17:17:10 +00:00
:mode (("\\.phtml\\'" . web-mode)
("\\.tpl\\.php\\'" . web-mode)
("\\.twig\\'" . web-mode)
("\\.xml\\'" . web-mode)
("\\.html\\'" . web-mode)
("\\.htm\\'" . web-mode)
("\\.[gj]sp\\'" . web-mode)
("\\.as[cp]x?\\'" . web-mode)
("\\.eex\\'" . web-mode)
("\\.erb\\'" . web-mode)
("\\.mustache\\'" . web-mode)
("\\.handlebars\\'" . web-mode)
("\\.hbs\\'" . web-mode)
("\\.eco\\'" . web-mode)
("\\.ejs\\'" . web-mode)
("\\.svelte\\'" . web-mode)
("\\.ctp\\'" . web-mode)
2022-06-10 08:41:48 +00:00
("\\.djhtml\\'" . web-mode)
("\\.vue\\'" . web-mode))
2022-06-26 20:24:49 +00:00
:config
(csetq web-mode-markup-indent-offset 2
web-mode-code-indent-offset 2
web-mode-css-indent-offset 2
web-mode-style-padding 0
web-mode-script-padding 0)
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/major-leader-key
2021-10-19 17:17:10 +00:00
:keymaps 'web-mode-map
2021-11-07 14:54:20 +00:00
:packages 'web-mode
2021-11-28 21:51:48 +00:00
"=" '(:ignore t :which-key "format")
"E" '(:ignore t :which-key "errors")
2021-10-19 17:17:10 +00:00
"El" #'web-mode-dom-errors-show
"gb" #'web-mode-element-beginning
2021-11-28 21:51:48 +00:00
"g" '(:ignore t :which-key "goto")
2021-10-19 17:17:10 +00:00
"gc" #'web-mode-element-child
"gp" #'web-mode-element-parent
"gs" #'web-mode-element-sibling-next
2021-11-28 21:51:48 +00:00
"h" '(:ignore t :which-key "dom")
2021-10-19 17:17:10 +00:00
"hp" #'web-mode-dom-xpath
2021-11-28 21:51:48 +00:00
"r" '(:ignore t :which-key "refactor")
2021-10-19 17:17:10 +00:00
"rc" #'web-mode-element-clone
"rd" #'web-mode-element-vanish
"rk" #'web-mode-element-kill
"rr" #'web-mode-element-rename
"rw" #'web-mode-element-wrap
2022-06-15 19:40:08 +00:00
"z" #'web-mode-fold-or-unfold)
(phundrak/major-leader-key
:keymaps 'web-mode-map
:packages '(lsp-mode web-mode)
"l" '(:keymap lsp-command-map :which-key "lsp")))
2021-07-30 17:01:29 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Auto-completion for ~emmet-mode~ , ~html-mode~ , and ~web-mode~ .
#+begin_src emacs-lisp
(use-package company-web
:defer t
:straight (:build t)
:after (emmet-mode web-mode))
#+end_src
2021-11-20 22:11:22 +00:00
***** CSS
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Web-programming-CSS-que40po085j0
:END:
2021-12-17 15:28:49 +00:00
Let’ s customize a bit the built-in CSS mode.
2021-11-20 22:11:22 +00:00
#+begin_src emacs-lisp
(use-package css-mode
:defer t
:straight (:type built-in)
:hook (css-mode . smartparens-mode)
2021-12-17 15:28:49 +00:00
:hook (css-mode . lsp-deferred)
2022-10-19 13:06:57 +00:00
:hook (scss-mode . prettier-js-mode)
2021-11-20 22:11:22 +00:00
:init
(put 'css-indent-offset 'safe-local-variable #'integerp)
:general
2023-01-23 09:45:46 +00:00
(phundrak/major-leader-key
:keymaps 'css-mode-map
:packages 'lsp-mode
"l" '(:keymap lsp-command-map :which-key "lsp"))
2021-11-20 22:11:22 +00:00
(phundrak/major-leader-key
:keymaps 'css-mode-map
:packages 'css-mode
"=" '(:ignore :wk "format")
"g" '(:ignore :wk "goto")))
#+end_src
2021-12-17 15:28:49 +00:00
SCSS is much nicer to use than pure CSS in my opinion, so let’ s add a
mode for that.
2021-11-20 22:11:22 +00:00
#+begin_src emacs-lisp
(use-package scss-mode
:straight (:build t)
:hook (scss-mode . smartparens-mode)
2021-12-17 15:28:49 +00:00
:hook (scss-mode . lsp-deferred)
2022-10-19 13:06:57 +00:00
:hook (scss-mode . prettier-js-mode)
2021-11-20 22:11:22 +00:00
:defer t
:mode "\\.scss\\'")
#+end_src
2021-12-17 15:28:49 +00:00
And let’ s add some autocompletion for CSS.
2021-11-20 22:11:22 +00:00
#+begin_src emacs-lisp
(use-package counsel-css
:straight (:build t)
:defer t
:init
(cl-loop for (mode-map . mode-hook) in '((css-mode-map . css-mode-hook)
(scss-mode-map . scss-mode-hook))
do (add-hook mode-hook #'counsel-css-imenu-setup)
(phundrak/major-leader-key
:keymaps mode-map
"gh" #'counsel-css)))
#+end_src
2022-11-02 15:24:44 +00:00
For some reason, although it is built-in, ~less-css-mode~ does not
activate when I open ~.less~ files by default. Let’ s fix that.
#+begin_src emacs-lisp
(use-package less-css-mode
:straight (:type built-in)
:defer t
:mode "\\.less\\'"
:hook (less-css-mode . smartparens-mode)
:hook (less-css-mode . lsp-deferred)
2023-01-23 09:45:46 +00:00
:hook (less-css-mode . prettier-js-mode)
:general
(phundrak/major-leader-key
:keymaps 'less-css-mode-map
:packages 'lsp-mode
"l" '(:keymap lsp-command-map :which-key "lsp")))
2022-11-02 15:24:44 +00:00
#+end_src
2021-07-30 17:01:29 +00:00
***** Javascript
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Web-programming-Javascript-8k5arup085j0
:END:
2021-12-17 15:28:49 +00:00
~javascript-mode~ is meh at best, while ~rjsx-mode~ (Real JSX) is much
better: it supports both Javascript and ~.jsx~ files for React and
Next.JS.
2021-11-18 19:11:01 +00:00
#+begin_src emacs-lisp
(use-package rjsx-mode
:defer t
:straight (:build t)
2021-11-24 22:43:28 +00:00
:after compile
2022-07-06 10:56:06 +00:00
:mode "\\.[mc]?jsx?\\'"
2021-11-18 19:11:01 +00:00
:mode "\\.es6\\'"
:mode "\\.pac\\'"
:interpreter "node"
:hook (rjsx-mode . rainbow-delimiters-mode)
2021-11-20 22:11:22 +00:00
:hook (rjsx-mode . lsp-deferred)
2021-11-18 19:11:01 +00:00
:init
(add-to-list 'compilation-error-regexp-alist 'node)
(add-to-list 'compilation-error-regexp-alist-alist
'(node "^[[:blank: ]]*at \\(.* (\\|\\)\\(.+?\\):\\([[:digit:]]+ \\):\\([[:digit: ]]+\\)"
2 3 4))
2021-11-20 22:11:22 +00:00
:general
(phundrak/major-leader-key
2023-01-23 09:45:46 +00:00
:keymaps 'rjsx-mode-map
:packages 'lsp-mode
"l" '(:keymap lsp-command-map :which-key "lsp"))
2021-11-18 19:11:01 +00:00
:config
(setq js-chain-indent t
js2-basic-offset 2
;; ignore shebangs
js2-skip-preprocessor-directives t
;; Flycheck handles this already
js2-mode-show-parse-errors nil
js2-mode-show-strict-warnings nil
;; conflicting with eslint, Flycheck already handles this
js2-strict-missing-semi-warning nil
js2-highlight-level 3
js2-idle-timer-delay 0.15))
#+end_src
2021-12-17 15:28:49 +00:00
~js2-refactor~ is an amazing tool for refactoring Javascript code. I
2023-03-20 16:17:57 +00:00
mean, [[https://www.youtube.com/watch?v=-7yMWD1wUu4 ][look at this ]]! And the video is only from 2013, and it still
2021-12-17 15:28:49 +00:00
receives some commits!
2021-11-18 19:11:01 +00:00
#+begin_src emacs-lisp
(use-package js2-refactor
:defer t
:straight (:build t)
:after (js2-mode rjsx-mode)
:hook (js2-mode . js2-refactor-mode)
2021-11-20 22:11:22 +00:00
:hook (rjsx-mode . js2-refactor-mode))
2021-11-18 19:11:01 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Which Emacser prefers the command line over Emacs itself? I don’ t.
2022-07-12 02:30:31 +00:00
Let’ s interact with NPM through Emacs then.
2021-11-18 19:11:01 +00:00
#+begin_src emacs-lisp
2022-07-12 02:30:31 +00:00
(use-package npm-transient
2021-11-18 19:11:01 +00:00
:defer t
2022-07-12 02:30:31 +00:00
:straight (npm-transient :build t
:type git
:host github
:repo "Phundrak/npm-transient"))
;; :general
;; (phundrak/major-leader-key
;; :packages '(npm-transient rjsx-mode web-mode)
;; :keymaps '(rjsx-mode-map web-mode-map)
;; "n" #'npm-transient))
2021-11-18 19:11:01 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
And finally, here is a formatter for Javascript.
2021-07-30 17:01:29 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package prettier-js
:defer t
2021-12-17 15:45:57 +00:00
:straight (:build t)
2022-08-16 11:26:03 +00:00
:after (rjsx-mode web-mode typescript-mode)
2022-08-16 11:36:03 +00:00
:hook ((rjsx-mode typescript-mode) . prettier-js-mode)
2022-06-26 20:24:49 +00:00
:config
2022-12-16 13:42:41 +00:00
(setq prettier-js-args '("--single-quote" "--jsx-single-quote")))
2021-07-30 17:01:29 +00:00
#+end_src
2021-11-20 22:11:22 +00:00
***** Typescript
2021-07-30 17:01:29 +00:00
:PROPERTIES:
2021-11-20 22:11:22 +00:00
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Web-programming-Typescript-o0e8nh30z9j0
2021-07-30 17:01:29 +00:00
:END:
2021-12-17 15:45:57 +00:00
Typescript is a safer alternative to Javascript. Let’ s install its major mode then.
2021-07-30 17:01:29 +00:00
#+begin_src emacs-lisp
2021-11-20 22:11:22 +00:00
(use-package typescript-mode
2021-11-07 01:27:04 +00:00
:defer t
2021-11-20 22:11:22 +00:00
:straight (:build t)
2021-12-17 15:45:57 +00:00
:hook (typescript-mode . rainbow-delimiters-mode)
2021-11-20 22:11:22 +00:00
:hook (typescript-tsx-mode . rainbow-delimiters-mode)
2022-12-07 15:08:05 +00:00
:hook (typescript-mode . lsp-deferred)
2021-12-17 15:45:57 +00:00
:hook (typescript-tsx-mode . lsp-deferred)
2022-12-07 15:08:05 +00:00
:hook (typescript-mode . prettier-js-mode)
:hook (typescript-tsx-mode . prettier-js-mode)
2021-11-20 22:11:22 +00:00
:commands typescript-tsx-mode
2021-12-17 15:45:57 +00:00
:after flycheck
2021-11-07 01:27:04 +00:00
:init
2021-12-07 09:14:41 +00:00
(add-to-list 'auto-mode-alist '("\\.tsx\\'" . typescript-tsx-mode))
:general
(phundrak/major-leader-key
2023-01-23 09:45:46 +00:00
:keymaps '(typescript-mode-map typescript-tsx-mode-map)
:packages 'lsp-mode
"l" '(:keymap lsp-command-map :which-key "lsp"))
2021-12-07 09:14:41 +00:00
(phundrak/major-leader-key
:packages 'typescript-mode
:keymaps '(typescript-mode-map typescript-tsx-mode-map)
"n" '(:keymap npm-mode-command-keymap :which-key "npm"))
2021-11-20 22:11:22 +00:00
:config
2022-06-28 21:41:35 +00:00
(with-eval-after-load 'flycheck
2021-11-20 22:11:22 +00:00
(flycheck-add-mode 'javascript-eslint 'web-mode)
(flycheck-add-mode 'javascript-eslint 'typescript-mode)
(flycheck-add-mode 'javascript-eslint 'typescript-tsx-mode)
(flycheck-add-mode 'typescript-tslint 'typescript-tsx-mode))
(when (fboundp 'web-mode)
(define-derived-mode typescript-tsx-mode web-mode "TypeScript-TSX"))
(autoload 'js2-line-break "js2-mode" nil t))
2021-07-30 17:01:29 +00:00
#+end_src
2021-12-17 15:28:49 +00:00
Tide enabled interactivity with Typescript.
2021-07-30 17:01:29 +00:00
#+begin_src emacs-lisp
2021-11-20 22:11:22 +00:00
(use-package tide
2021-10-19 17:17:10 +00:00
:defer t
:straight (:build t)
2021-11-20 22:11:22 +00:00
:hook (tide-mode . tide-hl-identifier-mode)
:config
(setq tide-completion-detailed t
tide-always-show-documentation t
tide-server-may-response-length 524288
tide-completion-setup-company-backend nil)
(advice-add #'tide-setup :after #'eldoc-mode)
:general
(phundrak/major-leader-key
:keymaps 'tide-mode-map
"R" #'tide-restart-server
"f" #'tide-format
"rrs" #'tide-rename-symbol
"roi" #'tide-organize-imports))
2021-07-30 17:01:29 +00:00
#+end_src
2022-01-26 09:06:12 +00:00
**** Zig
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Zig-ud8a6q504cj0
:END:
[[https://ziglang.org/ ][Zig ]] is to C kind of what Rust is to C++: a modern replacement without
sacrificing performance. It is much safer than C while providing
interop with it. Plus, its [[https://ziglang.org/documentation/master/std/ ][standard library ]] is pretty complete.
First, here is its major mode.
#+begin_src emacs-lisp
(use-package zig-mode
:defer t
:straight (:build t)
:after flycheck
:hook (zig-mode . lsp-deferred)
:config
;; This is from DoomEmacs
(flycheck-define-checker zig
"A zig syntax checker using the zig-fmt interpreter."
:command ("zig" "fmt" (eval (buffer-file-name)))
:error-patterns
((error line-start (file-name) ":" line ":" column ": error: " (mesage) line-end))
:modes zig-mode)
(add-to-list 'flycheck-checkers 'zig)
:general
2023-01-23 09:45:46 +00:00
(phundrak/major-leader-key
:keymaps 'zip-mode-map
:packages 'lsp-mode
"l" '(:keymap lsp-command-map :which-key "lsp"))
2022-01-26 09:06:12 +00:00
(phundrak/major-leader-key
:packages 'zig-mode
:keymaps 'zig-mode-map
"c" #'zig-compile
"f" #'zig-format-buffer
"r" #'zig-run
"t" #'zig-test-buffer))
#+end_src
2023-01-23 09:46:26 +00:00
For LSP to work, we need ~zls~ to be installed. In my case, as I am on
ArchLinux, I can install it from the AUR, and my AUR helper is ~paru~ .
2022-01-26 09:06:12 +00:00
#+begin_src fish :results raw :wrap "src text" :exports code
paru --skipreview --noconfirm -S zls-bin 2>&1
#+end_src
#+RESULTS :
#+begin_src text
:: Resolving dependencies...
:: Calculating conflicts...
:: Calculating inner conflicts...
Aur (1) zls-bin-0.9.0-2
:: Proceed with installation? [Y/n]:
:: Downloading PKGBUILDs...
PKGBUILDs up to date
fetching devel info...
==> Making package: zls-bin 0.9.0-2 (2022-01-17T00:43:50 CET)
==> Retrieving sources...
-> Found zls-LICENSE.txt
-> Found zls-bin-0.9.0.tar.gz
==> Validating source files with sha256sums...
zls-LICENSE.txt ... Passed
==> Validating source_x86_64 files with sha256sums...
zls-bin-0.9.0.tar.gz ... Passed
==> Making package: zls-bin 0.9.0-2 (2022-01-17T00:43:51 CET)
==> Checking runtime dependencies...
==> Checking buildtime dependencies...
==> Retrieving sources...
-> Found zls-LICENSE.txt
-> Found zls-bin-0.9.0.tar.gz
==> Validating source files with sha256sums...
zls-LICENSE.txt ... Passed
==> Validating source_x86_64 files with sha256sums...
zls-bin-0.9.0.tar.gz ... Passed
==> Removing existing $srcdir/ directory...
==> Extracting sources...
-> Extracting zls-bin-0.9.0.tar.gz with bsdtar
==> Sources are ready.
zls-bin-0.9.0-2: parsing pkg list...
:: zls-bin-0.9.0-2 is up to date -- skipping build
warning: zls-bin-0.9.0-2 is up to date -- reinstalling
loading packages...
resolving dependencies...
looking for conflicting packages...
Package (1) Old Version New Version Net Change
zls-bin 0.9.0-2 0.9.0-2 0,00 MiB
Total Installed Size: 1,16 MiB
Net Upgrade Size: 0,00 MiB
:: Proceed with installation? [Y/n]
checking keyring...
checking package integrity...
loading package files...
checking for file conflicts...
checking available disk space...
:: Processing package changes...
reinstalling zls-bin...
Consider re-running 'zls config' to reconfigure the language server
Some options may have changed when upgrading from 0.9.0-2 -> 0.9.0-2
Make sure to backup your old configuration!
:: Running post-transaction hooks...
(1/2) Arming ConditionNeedsUpdate...
(2/2) Refreshing PackageKit...
#+end_src
2021-05-23 23:18:51 +00:00
** Visual Configuration
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configurationxr86fl6184j0
:END:
2021-05-23 23:18:51 +00:00
*** Dashboard
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Dashboardnba6fl6184j0
:END:
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package dashboard
:straight (:build t)
:ensure t
:after all-the-icons
:config
(setq dashboard-banner-logo-title "Phundrak’ s 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)
2022-08-30 23:55:36 +00:00
(agenda . 10)
2021-10-19 17:17:10 +00:00
(projects . 10)))
(dashboard-setup-startup-hook)
:init
(add-hook 'after-init-hook 'dashboard-refresh-buffer))
2021-05-21 11:59:48 +00:00
#+end_src
2021-07-30 16:50:10 +00:00
*** Fringe
:PROPERTIES:
:CUSTOM_ID: Basic-configuration-Visual-Configuration-Fringe-glc9ch1195j0
:END:
It’ s nice to know which lines were modified since the last commit in a
file.
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(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)))
2021-07-30 16:50:10 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** Icons? Did someone say icons?
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Icons-Did-someone-say-iconsfye6fl6184j0
:END:
2021-05-23 23:18:51 +00:00
/*YES! ALL OF THEM!*/
2021-05-21 11:59:48 +00:00
2021-05-23 23:18:51 +00:00
Ahem…
2021-05-21 11:59:48 +00:00
2021-05-23 23:18:51 +00:00
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* ! I’ ll
(ab)use this feature in my config, be warned! *NOTE* : The first time a
2021-11-20 22:08:38 +00:00
configuration with ~all-the-icons~ loads on a machine, the needed fonts
might not be available, so you’ ll need to install them with the
2021-05-23 23:18:51 +00:00
command ~M-x all-the-icons-install-fonts~ .
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package all-the-icons
2021-10-19 19:42:28 +00:00
:defer t
:straight t)
2021-05-23 23:18:51 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
2021-05-23 23:18:51 +00:00
~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
2021-12-06 16:07:30 +00:00
character of my choice! First, let’ s declare the general symbols that
will be used everywhere.
#+begin_src emacs-lisp
(defun prog-mode-set-symbols-alist ()
2023-03-10 14:33:20 +00:00
(setq prettify-symbols-alist '(("lambda" . ?λ)))
2021-12-06 16:07:30 +00:00
(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, let’ s
declare some symbols for the Lisp languages.
#+begin_src emacs-lisp
(setq-default lisp-prettify-symbols-alist '(("lambda" . ?λ)
("defun" . ?𝑓 )
("defvar" . ?𝑣 )
("defcustom" . ?𝑐 )
2022-03-30 18:32:33 +00:00
("defconst" . ?𝐶 )))
2021-12-06 16:07:30 +00:00
(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, let’ s show the real string
of our symbols when the cursor is on it.
2021-05-23 23:18:51 +00:00
#+begin_src emacs-lisp
2021-12-06 16:07:30 +00:00
(setq prettify-symbols-unprettify-at-point t)
2021-05-21 11:59:48 +00:00
#+end_src
2021-10-20 11:59:26 +00:00
*** Ligatures
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Ligatures-2v50x451v8j0
:END:
The font I’ m using (see
§[[#Basic-configuration-Visual-Configuration-Fontsxfkjel6184j0 ]]) supports
ligatures, but Emacs in GUI mode does not. And of course, there’ s a
package for that.
#+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
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Modelineavb6fl6184j0
:END:
2021-12-17 15:28:49 +00:00
The DoomEmacs modeline looks nice in my opinion, let’ s use it.
2021-10-20 11:59:26 +00:00
#+begin_src emacs-lisp
(use-package doom-modeline
:straight (:build t)
:defer t
:init (doom-modeline-mode 1)
2022-06-15 19:52:03 +00:00
:config
(csetq doom-modeline-height 15
doom-modeline-enable-word-count t
2022-11-11 13:44:14 +00:00
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))
2021-10-20 11:59:26 +00:00
#+end_src
2022-02-26 14:39:44 +00:00
*** Pixel-perfect alignment of Markdown and org-mode tables
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Pixel-perfect-alignment-of-Markdown-and-org-mode-tables-u9rjl661bdj0
: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 I’ ll 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 won’ t exactly fit. Unless?
Unless ~valign-fancy-bar~ is set to ~t~ .
2022-03-04 13:29:17 +00:00
For now, I disabled the hook with org-mode and markdown-mode because
it slows down opening these files quite a lot. I’ ll re-enable the hook
once it is fixed.
2022-02-26 14:39:44 +00:00
#+begin_src emacs-lisp
(use-package valign
:defer t
:straight (:build t)
:after (org markdown-mode)
2022-03-04 13:29:17 +00:00
;; :hook ((org-mode markdown-mode) . valign-mode)
2022-02-26 14:39:44 +00:00
:custom ((valign-fancy-bar t)))
#+end_src
2021-10-20 11:59:26 +00:00
*** Secret mode
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Secret-mode-b2e9hp51v8j0
:END:
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
2022-01-04 17:31:15 +00:00
*** Solaire: Incandescent Emacs
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Solaire-Incandescent-Emacs-ah27z1q0obj0
:END:
A common issue when you have a lot of windows opened in Emacs is
sometimes there’ s just too much. Is the first window source code? Is
the other one just an open email? Oh, let’ s 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? I’ m not sure.)
#+begin_src emacs-lisp
(use-package solaire-mode
:defer t
:straight (:build t)
:init (solaire-global-mode +1))
#+end_src
2021-10-20 11:59:26 +00:00
*** Theme
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Themeded6fl6184j0
:END:
2021-12-17 15:28:49 +00:00
You may have noticed I use the Nord theme pretty much everywhere on my
2022-09-19 10:38:34 +00:00
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.
2021-10-20 11:59:26 +00:00
#+begin_src emacs-lisp
(use-package doom-themes
:straight (:build t)
:defer t
2022-09-19 10:38:34 +00:00
:init (load-theme 'doom-nord-aurora t))
2021-10-20 11:59:26 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** Rainbow Delimiters
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Rainbow-Delimiters3lg6fl6184j0
:END:
2021-12-17 15:28:49 +00:00
This makes Lisp especially more readable, but it’ s also nice to have
for any language that has delimiters like brackets too.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package rainbow-delimiters
:straight (:build t)
:defer t
:hook (prog-mode . rainbow-delimiters-mode))
2021-05-21 11:59:48 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** Y’ all want some more /COLORS/?
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Y-all-want-some-more-COLORSs6i6fl6184j0
:END:
2021-07-30 16:50:10 +00:00
It is possible to make info buffers much more colorful (and imo easier
to read) with this simple package:
2021-05-21 23:51:45 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(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))
2021-05-21 23:51:45 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
** Misc
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc0sj6fl6184j0
:END:
2021-07-30 16:50:10 +00:00
*** ArchWiki pages
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-ArchWiki-pages-nha3jhq0r4j0
:END:
A small package I’ ve 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
2021-10-19 17:17:10 +00:00
(use-package archwiki
:defer t
:straight (archwiki :build t
:type git
:repo "https://labs.phundrak.com/phundrak/archwiki.el"))
2021-07-30 16:50:10 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** ~avy~
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-avyral6fl6184j0
:END:
2022-07-24 09:41:50 +00:00
~avy~ is a really convenient way of jumping around and performing
actions on these selections, but I’ ll need some configuration to make
it bépo-compatible.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package avy
:defer t
2021-10-19 19:42:28 +00:00
:straight t
2021-10-19 17:17:10 +00:00
:config
2022-07-24 09:41:50 +00:00
(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)))
2022-01-07 20:09:04 +00:00
(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))
2021-11-07 14:54:20 +00:00
:general
2021-11-07 01:27:04 +00:00
(phundrak/evil
2022-07-24 09:41:50 +00:00
:pakages 'avy
"gc" #'evil-avy-goto-char-timer
"gl" #'evil-avy-goto-line)
2022-01-07 20:09:04 +00:00
(phundrak/leader-key
:packages 'avy
:infix "j"
2022-07-24 09:41:50 +00:00
"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))
2021-05-21 11:59:48 +00:00
#+end_src
2021-05-23 23:18:51 +00:00
*** Calc
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-Calc3vm6fl6184j0
:END:
2021-05-23 23:18:51 +00:00
Let’ s give ~calc-mode~ some better defaults.
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(setq calc-angle-mode 'rad
calc-symbolic-mode t)
2021-05-21 11:59:48 +00:00
#+end_src
2021-05-21 23:52:15 +00:00
2021-05-23 23:18:51 +00:00
*** Elcord
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-Elcord7eo6fl6184j0
:END:
2021-05-23 23:18:51 +00:00
What’ s the point of using Emacs if you can’ t tell everyone?
2021-05-21 11:59:48 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package elcord
:straight (:built t)
:defer t
:config
2022-07-06 10:56:26 +00:00
(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: ")))))
2021-05-21 11:59:48 +00:00
#+end_src
*** ~ivy-quick-find-files.el~
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-ivy-quick-find-files-el2yp6fl6184j0
:END:
2021-05-21 11:59:48 +00:00
This package is a small utility package I’ ve written in order to
quickly find files across my filesystem.
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(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"))))
2021-05-21 11:59:48 +00:00
#+end_src
2021-07-30 16:50:10 +00:00
*** Keycast
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-Keycast-nsqgl431t4j0
:END:
2021-12-17 15:28:49 +00:00
In case I am sharing my screen with people and I want to show which
functions are called on my keystrokes since I don’ t exactly use
standard keybindings.
2021-07-30 16:50:10 +00:00
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package keycast
2021-10-19 19:42:28 +00:00
:defer t
:straight (:build t)
2021-10-19 17:17:10 +00:00
: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 " ")))
2021-07-30 16:50:10 +00:00
#+end_src
2022-11-21 10:37:07 +00:00
*** Keyfreq
:PROPERTIES:
:CUSTOM_ID: PackagesConfigurationMiscKeyfreq-6ib0ovv0cnj0
:END:
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
2022-12-07 15:07:51 +00:00
*** Mastodon
:PROPERTIES:
:CUSTOM_ID: PackagesConfigurationMiscMastodon-3jtkg080znj0
:END:
#+begin_src emacs-lisp
(use-package mastodon
:defer t
:ensure t
:straight (mastodon :type git
:host nil
2022-12-16 13:42:08 +00:00
:repo "https://codeberg.org/rougier/mastodon.el"
:branch "alt-timeline")
2022-12-07 15:07:51 +00:00
:config
(setq mastodon-instance-url "https://fosstodon.org"
2022-12-16 13:42:08 +00:00
mastodon-active-user "phundrak")
(require 'mastodon-alt-tl)
(mastodon-alt-tl-activate))
2022-12-07 15:07:51 +00:00
#+end_src
2022-12-16 13:42:57 +00:00
*** Mediawiki
:PROPERTIES:
:CUSTOM_ID: PackagesConfigurationMiscMediawiki-3oaekxb03oj0
:END:
#+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
2021-07-30 16:50:10 +00:00
*** SICP
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-SICP-96u6ukz0l4j0
:END:
Who would get interested in Emacs and not want to read the SICP?
Moreover, inside Emacs?
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package sicp
2021-10-19 19:42:28 +00:00
:straight (:build t)
2021-10-19 17:17:10 +00:00
:defer t)
2021-07-30 16:50:10 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
*** Winum
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-Winumvir6fl6184j0
:END:
2021-05-21 11:59:48 +00:00
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
2021-10-19 17:17:10 +00:00
(use-package winum
:straight (:build t)
:init (winum-mode))
2021-05-21 11:59:48 +00:00
#+end_src
2021-07-30 16:50:10 +00:00
*** Ytplay
:PROPERTIES:
:CUSTOM_ID: Packages-Configuration-Misc-Ytplay-wxm9weq0r4j0
:END:
~ytplay~ is a small package I’ ve written with which you can choose at
which resolution to play a YouTube video in an external video player.
#+begin_src emacs-lisp
2021-10-19 17:17:10 +00:00
(use-package ytplay
:defer t
:straight (ytplay :build t
:type git
:repo "https://labs.phundrak.com/phundrak/ytplay.el"))
2021-07-30 16:50:10 +00:00
#+end_src
2021-05-21 11:59:48 +00:00
* Keybindings
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Keybindings3ps6fl6184j0
:END:
2021-05-21 11:59:48 +00:00
Undefining some stuff to make keybind prefixes work correctly.
#+begin_src emacs-lisp
2021-10-18 15:29:15 +00:00
(general-define-key
:keymaps 'global-map
"<mouse-2 >" nil
"<mouse-3 >" nil)
2021-11-07 01:27:04 +00:00
(phundrak/evil
2022-07-05 13:31:14 +00:00
:packages '(counsel)
"U" #'evil-redo
"C-a" #'beginning-of-line
"C-e" #'end-of-line
"C-y" #'yank
"M-y" #'counsel-yank-pop)
2021-05-21 11:59:48 +00:00
#+end_src
#+begin_src emacs-lisp
2023-03-10 14:34:19 +00:00
(general-define-key
"<f5 >" #'compile
"<f6 >" #'recompile)
2021-11-07 01:27:04 +00:00
(phundrak/leader-key
2021-10-19 17:17:10 +00:00
"SPC" '(counsel-M-x :wk "M-x")
"'" #'shell-pop
2022-12-18 16:07:37 +00:00
<<general-keybindings-gen(table=keybinds-tabs, prefix="TAB ") >>
2021-11-28 21:51:48 +00:00
<<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")
2021-10-19 17:17:10 +00:00
"cl" #'evilnc-comment-or-uncomment-lines
2021-12-12 14:04:35 +00:00
<<keybindings-flycheck >>
2021-11-28 21:51:48 +00:00
<<general-keybindings-gen(table=keybinds-files, prefix="f") >>
<<keybinds-specific-files >>
<<general-keybindings-gen(table=keybinds-help, prefix="h") >>
"i" '(:ignore t :wk "insert")
2021-12-20 14:24:57 +00:00
"iu" #'counsel-unicode-char
2021-11-28 21:51:48 +00:00
<<general-keybindings-gen(table=keybinds-jump, prefix="j") >>
2023-01-08 20:16:38 +00:00
<<general-keybindings-gen(table=keybinds-toggle, prefix="t ") >>
2021-11-28 21:51:48 +00:00
<<general-keybindings-gen(table=keybinds-text, prefix="T") >>
<<general-keybindings-gen(table=keybinds-windows, prefix="w") >>
<<general-keybindings-gen(table=keybinds-quit, prefix="q") >>
2021-10-19 17:17:10 +00:00
"u" #'universal-argument
2021-11-28 21:51:48 +00:00
"U" #'undo-tree-visualize)
#+end_src
** Apps
:PROPERTIES:
:CUSTOM_ID: Keybindings-Apps-wz2ajup0baj0
:END:
Here are my apps keybinds. Each one of them is prefixed by ~a~ .
#+name : keybinds-apps
| Key | Function | Description |
|-----+------------------+-------------|
| | | apps |
| c | calc | |
| d | docker | |
2021-12-12 14:04:35 +00:00
| E | elfeed | |
| e | | email |
2021-12-17 15:30:16 +00:00
| ec | mu4e-compose-new | |
| em | mu4e | |
2021-11-28 21:51:48 +00:00
| k | keycast-mode | |
| K | keycast-log-mode | |
| T | tetris | |
| w | wttrin | |
| C | calendar | |
I also have two main shell-related functions, prefixed with ~as~ .
#+name : keybinds-apps-shell
2022-07-03 10:26:04 +00:00
| Key | Function | Description |
|-----+-------------+-------------|
| | | shells |
| e | eshell-new | |
| v | vterm | |
| V | multi-vterm | |
2021-11-28 21:51:48 +00:00
** Buffers
:PROPERTIES:
:CUSTOM_ID: Keybindings-Buffers-rj5ajup0baj0
:END:
My buffer-related keybinds are all prefixed by ~b~ .
#+name : keybinds-buffers
2022-02-13 18:47:12 +00:00
| 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 | |
2022-05-01 16:02:28 +00:00
| n | next-buffer | |
| p | previous-buffer | |
2022-02-13 18:47:12 +00:00
| r | counsel-buffer-or-recentf | |
| s | switch-to-scratch-buffer | |
2021-11-28 21:51:48 +00:00
2021-12-12 14:04:35 +00:00
** Errors
2021-11-28 21:51:48 +00:00
:PROPERTIES:
:CUSTOM_ID: Keybindings-Email-gv0ltxp0baj0
:END:
2021-12-12 14:04:35 +00:00
#+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")
2021-12-20 14:24:57 +00:00
"el" #'counsel-flycheck
2021-12-12 14:04:35 +00:00
"ee" '(:keymap flycheck-command-map :wk "flycheck")
2022-02-04 16:02:01 +00:00
"ef" '(:keymap flyspell-mode-map :wk "flyspell")
"eF" #'flyspell-hydra/body
2021-12-12 14:04:35 +00:00
#+end_src
2021-11-28 21:51:48 +00:00
** Files
:PROPERTIES:
:CUSTOM_ID: Keybindings-Files-9lj2j9q0baj0
:END:
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")
2022-03-04 13:49:01 +00:00
"fR" '((lambda ()
(interactive)
(counsel-find-file ""
(concat user-emacs-directory
(file-name-as-directory "straight")
(file-name-as-directory "repos"))))
:which-key "straight package")
2021-11-28 21:51:48 +00:00
"fS" '((lambda ()
(interactive)
(find-file "~/org/config/stumpwm.org"))
:which-key "stumpwm.org")
#+end_src
** Help
:PROPERTIES:
:CUSTOM_ID: Keybindings-Help-ock4suq0baj0
:END:
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
:PROPERTIES:
:CUSTOM_ID: Keybindings-Jump-dt56n1r0baj0
:END:
My keybinds for jumping around are prefixed by ~j~ .
#+name : keybinds-jump
| Key | Function | Description |
|-----+-------------------------+-------------|
| | | jump |
| f | counsel-file-jump | |
2022-08-07 10:56:25 +00:00
| d | dirvish-dwim | |
2021-11-28 21:51:48 +00:00
| D | dired-jump-other-window | |
** Project
:PROPERTIES:
:CUSTOM_ID: Keybindings-Project-yfo8z3r0baj0
:END:
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 | |
2022-12-18 16:07:37 +00:00
** Tabs
:PROPERTIES:
:CUSTOM_ID: KeybindingsTabs-kx5gn8b0foj0
:END:
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 |
2022-12-28 17:13:41 +00:00
| TAB | tab-switch | |
2022-12-18 16:07:37 +00:00
| » | tab-next | |
| « | tab-previous | |
2022-12-28 17:13:41 +00:00
| c | tab-new | |
| C | tab-new-to | |
| d | tab-close | |
| n | tab-next | |
| p | tab-previous | |
2022-12-18 16:07:37 +00:00
| r | tab-rename | |
2021-11-28 21:51:48 +00:00
** Text
:PROPERTIES:
:CUSTOM_ID: Keybindings-Text-yf0cb4s0baj0
:END:
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
:PROPERTIES:
:CUSTOM_ID: Keybindings-Toggles-9hoj2br0baj0
:END:
My toggle keybinds are prefixed by ~t~ .
#+name : keybinds-toggle
2022-06-21 14:36:31 +00:00
| Key | Function | Description |
|-----+---------------------------------------+--------------|
| | | toggles |
2023-01-08 20:16:38 +00:00
| TAB | tab-bar-mode | |
2022-06-21 14:36:31 +00:00
| 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 | |
2022-10-04 11:01:31 +00:00
| is | set-input-method | |
2021-11-28 21:51:48 +00:00
** Windows
:PROPERTIES:
:CUSTOM_ID: Keybindings-Windows-fbgcper0baj0
:END:
A couple of keybinds are hidden from which-key, otherwise there’ s 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
:PROPERTIES:
:CUSTOM_ID: Keybindings-Quit-bs8kh6s0baj0
:END:
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 | |
2021-05-21 11:59:48 +00:00
2022-07-12 02:30:50 +00:00
* TODOs :noexport:
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Various-TODOsnwt6fl6184j0
:END:
2021-05-21 11:59:48 +00:00
** TODO advise ~evil-insert~ in eshell
2021-06-16 12:30:03 +00:00
:PROPERTIES:
:CUSTOM_ID: Various-TODOs-advise-evil-insert-in-eshellc4v6fl6184j0
:END:
2021-05-21 11:59:48 +00:00
Advise ~evil-insert~ to go to the end of the buffer while in
~eshell-mode~ .
2022-07-12 02:30:50 +00:00
** TODO Get started with org-roam
:PROPERTIES:
:CUSTOM_ID: TODOs-Get-started-with-org-roam-6w2jh671kij0
:END: