Lucien Cartier-Tilet
d1dbae1915
For some reason, some keybinds in mu4e weren’t getting undefined anymore, this is now fixed. Add automatic vertical split if the screen is considered wide enough (120 characters for the headers mode and 80 characters for the message view mode). If the screen or the headers mode window are not wide enough, the window will split horizontally instead of vertically. This commit also adds a function to quickly insert a response to spammers to get them trapped in an infinite loop of emails. See the new links in this commit.
5264 lines
189 KiB
Org Mode
5264 lines
189 KiB
Org Mode
#+title: Vanilla Emacs Configuration
|
||
#+setupfile: ~/org/config/headers
|
||
#+options: auto-id:t
|
||
#+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
|
||
#+property: header-args:emacs-lisp+ :tangle ~/.emacs.vanilla/init.el
|
||
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
|
||
|
||
* Introduction
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Introduction7gzhel6184j0
|
||
:END:
|
||
#+begin_center
|
||
*STOP* Read this first!
|
||
|
||
You just landed on my vanilla Emacs configuration. However, this URL
|
||
was used until recently for my Spacemacs configuration. If you want my
|
||
complete, working Emacs configuration, I recommend you to head over
|
||
there. /*This document is still a work in progress!*/
|
||
#+end_center
|
||
|
||
After a couple of years using Spacemacs and a failed attempt at
|
||
switching to DoomEmacs, I’m finally switching back to a vanilla
|
||
configuration! Be aware though this document is still very much a work
|
||
in progress document, lots of comments on existing configuration are
|
||
missing, and lots of functionnalities are still not implemented. I’m
|
||
still in the process of porting my [[file:spacemacs.org][Spacemacs]] configuration over here.
|
||
|
||
* Basic configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configurationzt3iel6184j0
|
||
:END:
|
||
** Early Init
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Early-Inityj7iel6184j0
|
||
:END:
|
||
The early init file is the file loaded before anything else in
|
||
Emacs. This is where I put some options in order to disable as quickly
|
||
as possible some built-in features of Emacs before they can be even
|
||
loaded, speeding Emacs up a bit.
|
||
#+begin_src emacs-lisp :mkdirp yes :tangle ~/.emacs.vanilla/early-init.el :exports code :results silent :lexical t
|
||
(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
|
||
#+end_src
|
||
|
||
** Emacs Behavior
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior6gbiel6184j0
|
||
:END:
|
||
*** Editing Text in Emacs
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Editing-Text-in-Emacsy2fiel6184j0
|
||
:END:
|
||
I *never* want to keep trailing spaces in my files, which is why I’m
|
||
doing this:
|
||
#+begin_src emacs-lisp
|
||
(add-hook 'before-save-hook #'whitespace-cleanup)
|
||
#+end_src
|
||
|
||
I don’t understand why some people add two spaces behind a full stop,
|
||
I sure don’t. Let’s tell Emacs.
|
||
#+begin_src emacs-lisp
|
||
(setq-default sentence-end-double-space nil)
|
||
#+end_src
|
||
|
||
There is a minor mode in Emacs which allows to have a finer way of
|
||
jumping from word to word: ~global-subword-mode~. It detects if what
|
||
would usually be considered by Emacs a word can be understood as
|
||
several modes, as in camelCase words, and allows us to jump words on
|
||
this finer level.
|
||
#+begin_src emacs-lisp
|
||
(global-subword-mode 1)
|
||
#+end_src
|
||
|
||
Lastly, I want the default mode for Emacs to be Emacs Lisp.
|
||
#+begin_src emacs-lisp
|
||
(setq-default initial-major-mode 'emacs-lisp-mode)
|
||
#+end_src
|
||
|
||
**** Indentation
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Editing-Text-in-Emacs-Indentationauiiel6184j0
|
||
:END:
|
||
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
|
||
(setq-default indent-tabs-mode nil)
|
||
(add-hook 'prog-mode-hook (lambda () (setq indent-tabs-mode nil)))
|
||
#+end_src
|
||
|
||
Just to go on a little tangeant here: I don’t exactly /hate/ tabs, but I
|
||
find them really annoying when your text editor knows only them. Sure,
|
||
for indentation they work great and they allow different people
|
||
getting different settings in their text editor depending on their
|
||
preferred tastes —some may prefer 2 spaces tabs, some may prefer 4
|
||
spaces tabs, some deranged people prefer 8 spaces tabs, and some
|
||
monsters prefer 3!
|
||
|
||
But the thing is, once you indented your code and then you need
|
||
alignment, tabs 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
|
||
formatters’ config file, and tabs look bat in EmacsLisp anyways, so
|
||
I’ll stick with spaces by default and change it where needed.
|
||
|
||
*** Programming Modes
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Programming-Modesfnmiel6184j0
|
||
:END:
|
||
First off, my definition of what makes a a “programming mode” doesn’t exactly
|
||
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
|
||
#+headers: :cache yes :exports none :tangle no
|
||
#+begin_src emacs-lisp :var modes=line-number-modes-table
|
||
(mapconcat (lambda (mode) (format "%s-hook" (car mode)))
|
||
modes
|
||
" ")
|
||
#+end_src
|
||
|
||
#+RESULTS[b551840c279e88374f47f047e599b8d8686fd8bf]: prog-modes-gen
|
||
: prog-mode-hook latex-mode-hook
|
||
|
||
**** Line Number
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Programming-Modes-Line-Numbermcqiel6184j0
|
||
:END:
|
||
Since version 26, Emacs has a built-in capacity of displaying line
|
||
numbers on the left-side of the buffer. This is a fantastic feature
|
||
that should actually be the default for all programming modes.
|
||
|
||
#+begin_src emacs-lisp
|
||
(dolist (mode '(<<prog-modes-gen()>>))
|
||
(add-hook mode #'display-line-numbers-mode))
|
||
#+end_src
|
||
|
||
**** Folding code
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Programming-Modes-Folding-code16uiel6184j0
|
||
:END:
|
||
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
|
||
(dolist (mode '(<<prog-modes-gen()>>))
|
||
(add-hook mode #'hs-minor-mode))
|
||
#+end_src
|
||
|
||
*** Stay Clean, Emacs!
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Stay-Clean-Emacs7wxiel6184j0
|
||
:END:
|
||
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
|
||
keep its backup files to itself in a directory it only will acces.
|
||
#+begin_src emacs-lisp
|
||
(setq backup-directory-alist `(("." . ,(expand-file-name ".tmp/backups/" user-emacs-directory))))
|
||
#+end_src
|
||
|
||
It also loves to litter its ~init.el~ with custom variables here and
|
||
there, but the thing is: I regenerate my ~init.el~ each time I tangle
|
||
this file! How can I keep Emacs from adding stuff that will be almost
|
||
immediately lost? Did someone say /custom file/?
|
||
#+begin_src emacs-lisp
|
||
(setq-default custom-file (expand-file-name ".custom.el" user-emacs-directory))
|
||
(when (file-exists-p custom-file) ; Don’t forget to load it, we still need it
|
||
(load custom-file))
|
||
#+end_src
|
||
|
||
If we delete a file, we want it moved to the trash, not simply deleted.
|
||
#+begin_src emacs-lisp
|
||
(setq delete-by-moving-to-trash t)
|
||
#+end_src
|
||
|
||
Finally, the scatch buffer always has some message at its beginning, I
|
||
don’t want it!
|
||
#+begin_src emacs-lisp
|
||
(setq-default initial-scratch-message nil)
|
||
#+end_src
|
||
|
||
*** Stay Polite, Emacs!
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Stay-Polite-Emacszp1jel6184j0
|
||
:END:
|
||
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
|
||
(defalias 'yes-or-no-p 'y-or-n-p)
|
||
#+end_src
|
||
|
||
This will make Emacs ask us for either hitting the ~y~ key for “yes”, or
|
||
the ~n~ key for “no”. Much more polite!
|
||
|
||
It is also very impolite to keep a certain version of a file in its
|
||
buffer when said file has changed on disk. Let’s change this behavior:
|
||
#+begin_src emacs-lisp
|
||
(global-auto-revert-mode 1)
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
: t
|
||
|
||
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!
|
||
|
||
*** Misc
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Emacs-Behavior-Misc9j5jel6184j0
|
||
:END:
|
||
Let’s raise Emacs undo memory to 10MB, and make Emacs auto-save our
|
||
files by default.
|
||
#+begin_src emacs-lisp
|
||
(setq undo-limit 100000000
|
||
auto-save-default t)
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(setq window-combination-resize t) ; take new window space from all other windows
|
||
#+end_src
|
||
|
||
** Personal Information
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Personal-Informationi59jel6184j0
|
||
:END:
|
||
Emacs needs to know its master! For various reasons by the way, some
|
||
packages rely of these variables to know who it is talking to or
|
||
dealing with, such as ~mu4e~ which will guess who you are if you haven’t
|
||
set it up correctly.
|
||
#+begin_src emacs-lisp
|
||
(setq user-full-name "Lucien Cartier-Tilet"
|
||
user-real-login-name "Lucien Cartier-Tilet"
|
||
user-login-name "phundrak"
|
||
user-mail-address "lucien@phundrak.com")
|
||
#+end_src
|
||
|
||
** Visual Configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Visual-Configurationzvcjel6184j0
|
||
:END:
|
||
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
|
||
(setq visible-bell t)
|
||
#+end_src
|
||
|
||
It is nicer to see a cursor cover the actual space of a character.
|
||
#+begin_src emacs-lisp
|
||
(setq x-stretch-cursor t)
|
||
#+end_src
|
||
|
||
When text is ellipsed, I want the ellipsis marker to be a single
|
||
character of three dots. Let’s make it so:
|
||
#+begin_src emacs-lisp
|
||
(setq truncate-string-ellipsis "…")
|
||
#+end_src
|
||
|
||
*** Modeline Modules
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Visual-Configuration-Modeline-Modules9kgjel6184j0
|
||
:END:
|
||
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
|
||
(setq display-time-format "%Y-%m-%d %H:%M")
|
||
(display-time-mode 1) ; display time in modeline
|
||
#+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
|
||
(let ((battery-str (battery)))
|
||
(unless (or (equal "Battery status not available" battery-str)
|
||
(string-match-p (regexp-quote "N/A") battery-str))
|
||
(display-battery-mode 1)))
|
||
#+end_src
|
||
|
||
This 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
|
||
(column-number-mode)
|
||
#+end_src
|
||
|
||
The following code is, as will several chunks of code in this config,
|
||
borrowed from [[https://tecosaur.github.io/emacs-config/#theme-modeline][TEC’s configuration]]. It hides the encoding information
|
||
of the file if the file itself is a regular UTF-8 file with ~\n~ line
|
||
ending. Be aware the ~doom-modeline-buffer-encoding~ variable is usabel
|
||
here only because I use the Doom modeline as seen below.
|
||
#+begin_src emacs-lisp
|
||
(defun modeline-contitional-buffer-encoding ()
|
||
"Hide \"LF UTF-8\" in modeline.
|
||
|
||
It is expected of files to be encoded with LF UTF-8, so only show
|
||
the encoding in the modeline if the encoding is worth notifying
|
||
the user."
|
||
(setq-local doom-modeline-buffer-encoding
|
||
(unless (and (memq (plist-get (coding-system-plist buffer-file-coding-system) :category)
|
||
'(coding-category-undecided coding-category-utf-8))
|
||
(not (memq (coding-system-eol-type buffer-file-coding-system) '(1 2))))
|
||
t)))
|
||
#+end_src
|
||
|
||
Now, 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
|
||
(add-hook 'after-change-major-mode-hook #'modeline-contitional-buffer-encoding)
|
||
#+end_src
|
||
|
||
*** Fonts
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Visual-Configuration-Fontsxfkjel6184j0
|
||
:END:
|
||
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]].
|
||
#+begin_src emacs-lisp
|
||
(defvar phundrak/default-font-size 90
|
||
"Default font size.")
|
||
|
||
(when (equal system-type 'gnu/linux)
|
||
(set-face-attribute 'default nil :font "Cascadia Code" :height phundrak/default-font-size))
|
||
#+end_src
|
||
|
||
*** Frame Title
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Visual-Configuration-Frame-Titlej7ojel6184j0
|
||
:END:
|
||
This is straight-up copied from [[https://tecosaur.github.io/emacs-config/config.html#window-title][TEC]]’s configuration. See their comment
|
||
on the matter.
|
||
#+begin_src emacs-lisp
|
||
(setq frame-title-format
|
||
'(""
|
||
"%b"
|
||
(:eval
|
||
(let ((project-name (projectile-project-name)))
|
||
(unless (string= "-" project-name)
|
||
(format (if (buffer-modified-p) " ◉ %s" " ● %s") project-name))))))
|
||
#+end_src
|
||
|
||
** Nice Macros From Doom-Emacs
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Basic-configuration-Nice-Macros-From-Doom-Emacsgyrjel6184j0
|
||
:END:
|
||
Doom-Emacs has some really nice macros that can come in really handy,
|
||
but since I prefer to rely on my own configuration, I’ll instead just
|
||
copy their code here. First we get the ~after!~ macro:
|
||
#+begin_src emacs-lisp
|
||
(require 'cl)
|
||
(defmacro after! (package &rest body)
|
||
"Evaluate BODY after PACKAGE have loaded.
|
||
|
||
PACKAGE is a symbol or list of them. These are package names, not modes,
|
||
functions or variables. It can be:
|
||
|
||
- An unquoted package symbol (the name of a package)
|
||
(after! helm BODY...)
|
||
- An unquoted list of package symbols (i.e. BODY is evaluated once both magit
|
||
and git-gutter have loaded)
|
||
(after! (magit git-gutter) BODY...)
|
||
- An unquoted, nested list of compound package lists, using any combination of
|
||
:or/:any and :and/:all
|
||
(after! (:or package-a package-b ...) BODY...)
|
||
(after! (:and package-a package-b ...) BODY...)
|
||
(after! (:and package-a (:or package-b package-c) ...) BODY...)
|
||
Without :or/:any/:and/:all, :and/:all are implied.
|
||
|
||
This is a wrapper around `eval-after-load' that:
|
||
|
||
1. Suppresses warnings for disabled packages at compile-time
|
||
2. Supports compound package statements (see below)
|
||
3. Prevents eager expansion pulling in autoloaded macros all at once"
|
||
(declare (indent defun) (debug t))
|
||
(if (symbolp package)
|
||
(list (if (or (not (bound-and-true-p byte-compile-current-file))
|
||
(require package nil 'noerror))
|
||
#'progn
|
||
#'with-no-warnings)
|
||
;; We intentionally avoid `with-eval-after-load' to prevent eager
|
||
;; macro expansion from pulling (or failing to pull) in autoloaded
|
||
;; macros/packages.
|
||
`(eval-after-load ',package ',(macroexp-progn body)))
|
||
(let ((p (car package)))
|
||
(cond ((not (keywordp p))
|
||
`(after! (:and ,@package) ,@body))
|
||
((memq p '(:or :any))
|
||
(macroexp-progn
|
||
(cl-loop for next in (cdr package)
|
||
collect `(after! ,next ,@body))))
|
||
((memq p '(:and :all))
|
||
(dolist (next (cdr package))
|
||
(setq body `((after! ,next ,@body))))
|
||
(car body))))))
|
||
#+end_src
|
||
|
||
* Custom Elisp
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elispksvjel6184j0
|
||
:END:
|
||
** Dired functions
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elisp-Dired-functionsm8zjel6184j0
|
||
:END:
|
||
*** ~phundrak/open-marked-files~
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elisp-Dired-functions-phundrak-open-marked-filesdw2kel6184j0
|
||
:END:
|
||
This function allows the user to open all marked files from a dired
|
||
buffer as new Emacs buffers.
|
||
#+begin_src emacs-lisp
|
||
(defun phundrak/open-marked-files (&optional files)
|
||
"Open all marked FILES in dired buffer as new Emacs buffers."
|
||
(interactive)
|
||
(let* ((file-list (if files
|
||
(list files)
|
||
(if (equal major-mode "dired-mode")
|
||
(dired-get-marked-files)
|
||
(list (buffer-file-name))))))
|
||
(mapc (lambda (file-path)
|
||
(find-file file-path))
|
||
(file-list))))
|
||
#+end_src
|
||
|
||
*** ~xah/open-in-external-app~
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elisp-Dired-functions-xah-open-in-external-appnm6kel6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(defun xah/open-in-external-app (&optional file)
|
||
"Open FILE or dired marked FILE in external app.
|
||
The app is chosen from the user’s OS preference."
|
||
(interactive)
|
||
(let ((file-list (if file
|
||
(list file)
|
||
(if (equal major-mode "dired-mode")
|
||
(dired-get-marked-files)
|
||
(list (buffer-file-name)))))
|
||
(do-it-p (if (<= (length file-list) 5)
|
||
t
|
||
(y-or-n-p "Open more than 5 files? "))))
|
||
(when do-it-p
|
||
(mapc (lambda (file-path)
|
||
(let ((process-connection-type nil))
|
||
(start-process "" nil "xdg-open" file-path)))
|
||
file-list))))
|
||
#+end_src
|
||
|
||
*** ~xah/dired-sort~
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elisp-Dired-functions-xah-dired-sort9fakel6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(defun xah/dired-sort ()
|
||
"Sort dired dir listing in different ways.
|
||
Prompt for a choice."
|
||
(interactive)
|
||
(let (sort-by arg)
|
||
(setq sort-by (completing-read "Sort by:" '("name" "size" "date" "extension")))
|
||
(pcase sort-by
|
||
("name" (setq arg "-ahl --group-directories-first"))
|
||
("date" (setq arg "-ahl -t --group-directories-first"))
|
||
("size" (setq arg "-ahl -S --group-directories-first"))
|
||
("extension" (setq arg "ahlD -X --group-directories-first"))
|
||
(otherwise (error "Dired-sort: unknown option %s" otherwise)))
|
||
(dired-sort-other arg)))
|
||
#+end_src
|
||
|
||
** Switch between buffers
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elisp-Switch-between-buffersp4ekel6184j0
|
||
:END:
|
||
Two default shortcuts I really like from Spacemacs are ~SPC b m~ and ~SPC
|
||
b s~, which bring the user directly to the ~*Messages*~ buffer and the
|
||
~*scratch*~ buffer respectively. These functions do exactly this.
|
||
#+begin_src emacs-lisp
|
||
(defun switch-to-messages-buffer ()
|
||
"Switch to Messages buffer."
|
||
(interactive)
|
||
(switch-to-buffer "*Messages*"))
|
||
|
||
(defun switch-to-scratch-buffer ()
|
||
"Switch to Messages buffer."
|
||
(interactive)
|
||
(switch-to-buffer "*scratch*"))
|
||
#+end_src
|
||
|
||
** Org Functions
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elisp-Org-Functionsyshkel6184j0
|
||
:END:
|
||
*** Emphasize text
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elisp-Org-Functions-Emphasize-textkilkel6184j0
|
||
:END:
|
||
| / | <c> | <c> |
|
||
| Emphasis | Character | Character code |
|
||
|----------+-----------+----------------|
|
||
| Bold | ~*~ | 42 |
|
||
| Italic | ~/~ | 47 |
|
||
| Code | ~~~ | 126 |
|
||
|
||
#+begin_src emacs-lisp
|
||
(defun org-mode-emphasize-bold ()
|
||
"Emphasize as bold the current region.
|
||
|
||
See also `org-emphasize'."
|
||
(interactive)
|
||
(org-emphasize 42))
|
||
#+end_src
|
||
|
||
*** Handle new windows
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Custom-Elisp-Org-Functions-Handle-new-windowst7pkel6184j0
|
||
:END:
|
||
The two functions below allow the user to not only create a new window
|
||
to the right or below the current window (respectively), but also to
|
||
focus the new window immediately.
|
||
#+begin_src emacs-lisp
|
||
(defun split-window-right-and-focus ()
|
||
(interactive)
|
||
(split-window-right)
|
||
(windmove-right)
|
||
(when (and (boundp 'golden-ratio-mode)
|
||
(symbol-value golden-ratio-mode))
|
||
(golden-ratio)))
|
||
|
||
(defun split-window-below-and-focus ()
|
||
(interactive)
|
||
(split-window-below)
|
||
(windmove-down)
|
||
(when (and (boundp 'golden-ratio-mode)
|
||
(symbol-value golden-ratio-mode))
|
||
(golden-ratio)))
|
||
#+end_src
|
||
|
||
*** ~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
|
||
|
||
* Package Management
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Package-Managementqpwkel6184j0
|
||
:END:
|
||
** Repositories
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Package-Management-Repositoriesab0lel6184j0
|
||
:END:
|
||
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,
|
||
so let’s add them! Note that the /Elpa/ repository has been renamed to
|
||
the /gnu/ repository 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 were renamed in order to avoid any
|
||
confusion between the two of them.
|
||
#+begin_src emacs-lisp
|
||
(setq package-archives '(("melpa" . "https://melpa.org/packages/")
|
||
("org" . "https://orgmode.org/elpa/")
|
||
("gnu" . "https://elpa.gnu.org/packages/")
|
||
("nongnu" . "https://elpa.nongnu.org/nongnu/")))
|
||
#+end_src
|
||
|
||
** Straight
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Package-Management-Straightry3lel6184j0
|
||
:END:
|
||
For my package management, I prefer to use ~straight~ ([[https://github.com/raxod502/straight.el][Github]]). This is
|
||
due to its capacity of integrating nicely with ~use-package~, which is
|
||
also supported by ~general~ which I use for my keybindings (see below),
|
||
but also because with it I can specify where to retrieve packages that
|
||
are not on MELPA or ELPA but on Github and other online Git
|
||
repositories too.
|
||
#+begin_src emacs-lisp
|
||
(defvar bootstrap-version)
|
||
(defvar comp-deferred-compilation-deny-list ()) ; workaround, otherwise straight shits itself
|
||
(let ((bootstrap-file
|
||
(expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
|
||
(bootstrap-version 5))
|
||
(unless (file-exists-p bootstrap-file)
|
||
(with-current-buffer
|
||
(url-retrieve-synchronously
|
||
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
|
||
'silent 'inhibit-cookies)
|
||
(goto-char (point-max))
|
||
(eval-print-last-sexp)))
|
||
(load bootstrap-file nil 'nomessage))
|
||
|
||
(package-initialize)
|
||
(unless package-archive-contents
|
||
(package-refresh-contents))
|
||
|
||
;; Initialize use-package on non-Linux platforms
|
||
(unless (package-installed-p 'use-package)
|
||
(package-install 'use-package))
|
||
|
||
(require 'use-package)
|
||
(setq use-package-always-ensure t)
|
||
#+end_src
|
||
|
||
* Keybinding Management
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Keybinding-Management728lel6184j0
|
||
:END:
|
||
** Which-key
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Keybinding-Management-Which-keymsblel6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package which-key
|
||
:straight (:build t)
|
||
:defer t
|
||
:init (which-key-mode)
|
||
:diminish which-key-mode
|
||
:config
|
||
(setq which-key-idle-delay 1))
|
||
#+end_src
|
||
|
||
** General
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Keybinding-Management-Generalycflel6184j0
|
||
:END:
|
||
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,
|
||
my keybinds that are not bound to a specific mode will be prefixed
|
||
with ~SPC~, but when I want to get more specific in terms of mode, I'll
|
||
prefix them with a comma (I’ve taken this habit from Spacemacs).
|
||
#+begin_src emacs-lisp
|
||
(use-package general
|
||
:defer t
|
||
:straight (:build t)
|
||
:init
|
||
(general-auto-unbind-keys))
|
||
#+end_src
|
||
|
||
#+name: general-keybindings-gen
|
||
#+header: :tangle no :exports none :results value :cache yes
|
||
#+begin_src emacs-lisp :var table=mu4e-keybindings-view-tbl
|
||
(mapconcat (lambda (line)
|
||
(let* ((key (car line))
|
||
(function (cadr line))
|
||
(function (if (or (string= "nil" function)
|
||
(string= "" function))
|
||
":ignore"
|
||
function))
|
||
(comment (caddr line)))
|
||
(format "\"%s\" %s" key
|
||
(if (string= "" comment)
|
||
(if (string= "nil" function)
|
||
"nil"
|
||
(concat "#'" function))
|
||
(format "'(%s :which-key \"%s\")"
|
||
function
|
||
(if (string= "" function)
|
||
"nil"
|
||
comment))))))
|
||
table
|
||
"\n")
|
||
#+end_src
|
||
|
||
#+RESULTS[fa2948b693499edc6458f60c46357955b8ace1fb]: general-keybindings-gen
|
||
#+begin_example
|
||
"&" #'mu4e-view-pipe
|
||
"." '(mu4e-headers-split-adjust-width/body :which-key "mu4e-headers width")
|
||
"a" '(:ignore :which-key "attachments")
|
||
"a&" #'mu4e-view-pipe-attachment
|
||
"aa" #'mu4e-view-attachment-action
|
||
"ao" #'mu4e-view-open-attachment
|
||
"aO" #'mu4e-view-open-attachment-with
|
||
"c" '(:ignore :which-key "compose")
|
||
"cc" #'mu4e-compose-new
|
||
"ce" #'mu4e-compose-edit
|
||
"cf" #'mu4e-compose-forward
|
||
"cr" #'mu4e-compose-reply
|
||
"cR" #'mu4e-compose-resend
|
||
"g" '(:ignore :which-key "go to")
|
||
"gu" #'mu4e-view-go-to-url
|
||
"gX" #'mu4e-view-fetch-url
|
||
"l" #'mu4e-show-log
|
||
"m" '(:ignore :which-key "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
|
||
"t" '(:ignore :which-key "thread")
|
||
"T" '(:ignore :which-key "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
|
||
#+end_example
|
||
|
||
** Evil
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Keybinding-Management-Eviljg30fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package evil
|
||
:straight (:build t)
|
||
:init
|
||
(progn
|
||
(setq evil-want-integration t
|
||
evil-want-keybinding nil
|
||
evil-want-C-u-scroll t
|
||
evil-want-C-i-jump nil)
|
||
(require 'evil-vars)
|
||
(evil-set-undo-system 'undo-tree))
|
||
:config
|
||
(evil-mode 1)
|
||
(setq evil-want-fine-undo t) ; more granular undo with evil
|
||
(evil-set-initial-state 'messages-buffer-mode 'normal)
|
||
(evil-set-initial-state 'dashboard-mode 'normal)
|
||
|
||
;; Use visual line motions even outside of visual-line-mode buffers
|
||
(evil-global-set-key 'motion "t" 'evil-next-visual-line)
|
||
(evil-global-set-key 'motion "s" 'evil-previous-visual-line)
|
||
|
||
(define-key evil-normal-state-map "c" nil)
|
||
(define-key evil-normal-state-map "C" nil)
|
||
(define-key evil-normal-state-map "t" nil)
|
||
(define-key evil-normal-state-map "T" nil)
|
||
(define-key evil-normal-state-map "s" nil)
|
||
(define-key evil-normal-state-map "S" nil)
|
||
(define-key evil-normal-state-map "r" nil)
|
||
(define-key evil-normal-state-map "R" nil)
|
||
(define-key evil-normal-state-map "h" nil)
|
||
(define-key evil-normal-state-map "H" nil)
|
||
(define-key evil-normal-state-map "j" nil)
|
||
(define-key evil-normal-state-map "J" nil)
|
||
(define-key evil-normal-state-map "k" nil)
|
||
(define-key evil-normal-state-map "K" nil)
|
||
(define-key evil-normal-state-map "l" nil)
|
||
(define-key evil-normal-state-map "L" nil)
|
||
|
||
(define-key evil-motion-state-map "h" 'evil-replace)
|
||
(define-key evil-motion-state-map "H" 'evil-replace-state)
|
||
(define-key evil-motion-state-map "j" 'evil-find-char-to)
|
||
(define-key evil-motion-state-map "J" 'evil-find-char-to-backward)
|
||
(define-key evil-motion-state-map "k" 'evil-substitute)
|
||
(define-key evil-motion-state-map "K" 'evil-smart-doc-lookup)
|
||
(define-key evil-motion-state-map "l" 'evil-change)
|
||
(define-key evil-motion-state-map "L" 'evil-change-line)
|
||
|
||
(define-key evil-motion-state-map "c" 'evil-backward-char)
|
||
(define-key evil-motion-state-map "C" 'evil-window-top)
|
||
(define-key evil-motion-state-map "t" 'evil-next-line)
|
||
(define-key evil-motion-state-map "T" 'evil-join)
|
||
(define-key evil-motion-state-map "s" 'evil-previous-line)
|
||
(define-key evil-motion-state-map "S" 'evil-lookup)
|
||
(define-key evil-motion-state-map "r" 'evil-forward-char)
|
||
(define-key evil-motion-state-map "R" 'evil-window-bottom))
|
||
|
||
|
||
(use-package evil-collection
|
||
:after evil
|
||
:straight (:build t)
|
||
:config
|
||
(evil-collection-init))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package undo-tree
|
||
:defer t
|
||
:straight (:build t)
|
||
:init
|
||
(global-undo-tree-mode))
|
||
#+end_src
|
||
|
||
** Hydra
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Keybinding-Management-Hydra0970fl6184j0
|
||
:END:
|
||
[[https://github.com/abo-abo/hydra][Hydra]] is a simple menu creator for keybindings.
|
||
#+begin_src emacs-lisp
|
||
(use-package hydra
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
*** Hydras
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Keybinding-Management-Hydra-Hydrasvya0fl6184j0
|
||
:END:
|
||
The following hydra allows me to quickly zoom in and out in the
|
||
current buffer.
|
||
#+begin_src emacs-lisp
|
||
(defhydra hydra-zoom ()
|
||
"
|
||
^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))
|
||
#+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
|
||
(defhydra writeroom-buffer-width ()
|
||
"
|
||
^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"))
|
||
#+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
|
||
(defhydra mu4e-headers-split-adjust-width ()
|
||
"
|
||
^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"))
|
||
#+end_src
|
||
|
||
Similarly still, this one allows me to manage the size my Emacs
|
||
windows.
|
||
#+begin_src emacs-lisp
|
||
(defhydra windows-adjust-size ()
|
||
"
|
||
^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))
|
||
#+end_src
|
||
|
||
* Packages Configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configurationije0fl6184j0
|
||
:END:
|
||
** Autocompletion
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Autocompletionr8n1fl6184j0
|
||
:END:
|
||
*** Code Autocompletion
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Autocompletion-Code-Autocompletion4no1fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package company
|
||
:straight (:build t)
|
||
:defer t
|
||
:hook (company-mode . evil-normalize-keymaps)
|
||
:init (global-company-mode)
|
||
:config
|
||
(setq company-minimum-prefix-length 2
|
||
company-toolsip-limit 14
|
||
company-tooltip-align-annotations t
|
||
company-require-match 'never
|
||
company-global-modes '(not erc-mode message-mode help-mode gud-mode)
|
||
company-frontends
|
||
'(company-pseudo-tooltip-frontend ; always show candidates in overlay tooltip
|
||
company-echo-metadata-frontend) ; show selected candidate docs in echo area
|
||
|
||
;; Buffer-local backends will be computed when loading a major
|
||
;; mode, so only specify a global default here.
|
||
company-backends '(company-capf)
|
||
|
||
;; These auto-complete the current selection when
|
||
;; `company-auto-complete-chars' is typed. This is too
|
||
;; magical. We already have the much more explicit RET and
|
||
;; TAB.
|
||
company-auto-complete nil
|
||
company-auto-complete-chars nil
|
||
|
||
;; Only search the current buffer for `company-dabbrev' (a
|
||
;; backend that suggests text you open buffers). This prevents
|
||
;; Company from causing lag once you have a lot of buffers
|
||
;; open.
|
||
company-dabbrev-other-buffers nil
|
||
|
||
;; Make `company-dabbrev' fully case-sensitive, to improve UX
|
||
;; with domai-specific words with particular casing.
|
||
company-dabbrev-ignore-case nil
|
||
company-dabbrev-downcase nil))
|
||
|
||
(use-package company-dict
|
||
:after company
|
||
:straight (:build t)
|
||
:config
|
||
(setq company-dict-dir (expand-file-name "dicts" user-emacs-directory)))
|
||
|
||
(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))
|
||
`((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
|
||
|
||
#+RESULTS:
|
||
: t
|
||
|
||
*** Ivy
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Autocompletion-Ivy84q1fl6184j0
|
||
:END:
|
||
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~.
|
||
#+begin_src emacs-lisp
|
||
(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)
|
||
:map ivy-switch-buffer-map
|
||
("C-t" . ivy-next-line)
|
||
("C-s" . ivy-previous-line)
|
||
("C-l" . ivy-done)
|
||
("C-d" . ivy-switch-buffer-kill)
|
||
:map ivy-reverse-i-search-map
|
||
("C-t" . ivy-next-line)
|
||
("C-s" . ivy-previous-line)
|
||
("C-d" . ivy-reverse-i-search-kill))
|
||
:config
|
||
(ivy-mode 1)
|
||
(setq ivy-wrap t
|
||
ivy-height 17
|
||
ivy-sort-max-size 50000
|
||
ivy-fixed-height-minibuffer t
|
||
ivy-read-action-functions #'ivy-hydra-read-action
|
||
ivy-read-action-format-function #'ivy-read-action-format-columns
|
||
projectile-completion-system 'ivy
|
||
ivy-on-del-error-function #'ignore
|
||
ivy-use-selectable-prompt t))
|
||
#+end_src
|
||
|
||
There is also [[https://github.com/raxod502/prescient.el][~prescient.el~]] that offers some nice features when
|
||
coupled with ~ivy~, guess what was born out of it? ~ivy-prescient~, of
|
||
course!
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-prescient
|
||
:after ivy
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
I warned you I’d use too much ~all-the-icons~, I did!
|
||
#+begin_src emacs-lisp
|
||
(use-package all-the-icons-ivy
|
||
:straight (:build t)
|
||
:after (ivy all-the-icons)
|
||
:hook (after-init . all-the-icons-ivy-setup))
|
||
#+end_src
|
||
|
||
A buffer popping at the bottom of the screen is nice and all, but have
|
||
you considered a floating buffer in the center of your frame?
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-posframe
|
||
:defer t
|
||
:after (:any ivy helpful)
|
||
:hook (ivy-mode . ivy-posframe-mode)
|
||
:straight (:build t)
|
||
:init
|
||
(ivy-posframe-mode 1)
|
||
:config
|
||
(setq ivy-fixed-height-minibuffer nil
|
||
ivy-posframe-border-width 10
|
||
ivy-posframe-parameters
|
||
`((min-width . 90)
|
||
(min-height . ,ivy-height))))
|
||
#+end_src
|
||
|
||
Finally, let’s make ~ivy~ richer:
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-rich
|
||
:straight (:build t)
|
||
:after ivy
|
||
:init
|
||
(ivy-rich-mode 1))
|
||
#+end_src
|
||
|
||
*** Counsel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Autocompletion-Counselorr1fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package counsel
|
||
:straight (:build t)
|
||
:defer t
|
||
:after ivy
|
||
:bind (("M-x" . counsel-M-x)
|
||
("C-x b" . counsel-ibuffer)
|
||
("C-x C-f" . counsel-find-file)
|
||
:map minibuffer-local-map
|
||
("C-r" . 'counsel-minibuffer-history)))
|
||
#+end_src
|
||
|
||
*** Yasnippet
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Autocompletion-Yasnippet68t1fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package yasnippet
|
||
:defer t
|
||
:straight (:build t)
|
||
:init
|
||
(yas-global-mode)
|
||
:hook ((prog-mode . yas-minor-mode)
|
||
(text-mode . yas-minor-mode)))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package yasnippet-snippets
|
||
:defer t
|
||
:after yasnippet
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package yatemplate
|
||
:defer t
|
||
:after yasnippet
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-yasnippet
|
||
:defer t
|
||
:after (ivy yasnippet)
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
** Applications
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications94i0fl6184j0
|
||
:END:
|
||
*** Docker
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Docker5ul0fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package docker
|
||
:defer t
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package dockerfile-mode
|
||
:defer t
|
||
:straight (:build t)
|
||
:init
|
||
(put 'docker-image-name 'safe-local-variable #'stringp)
|
||
:mode "Dockerfile\\'")
|
||
#+end_src
|
||
|
||
*** Elfeed
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Elfeedoip0fl6184j0
|
||
:END:
|
||
*** Email
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email9dt0fl6184j0
|
||
:END:
|
||
**** Basic configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Basic-configurationf7w0fl6184j0
|
||
:END:
|
||
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.
|
||
#+begin_src emacs-lisp
|
||
(setq message-signature nil
|
||
mail-signature nil)
|
||
#+end_src
|
||
|
||
**** Mu4e
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e5kx0fl6184j0
|
||
:END:
|
||
Mu4e is a very eye-pleasing email client for Emacs, built around ~mu~
|
||
and which works very well with ~mbsync~ (found in Arch’s ~isync~ package).
|
||
For me, the main advantage of mu4e is it has a modern interface for
|
||
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.
|
||
|
||
Quick sidenote: on ArchLinux, you’ll need to install either ~mu~ or
|
||
~mu-git~ from the AUR in order to use mu4e.
|
||
#+begin_src emacs-lisp
|
||
(use-package mu4e
|
||
:after all-the-icons
|
||
:straight (:build t :location site)
|
||
:commands mu4e mu4e-compose-new
|
||
:init
|
||
(progn
|
||
(setq mu4e-completing-read-function 'completing-read
|
||
mu4e-use-fancy-chars t
|
||
mu4e-view-show-images t
|
||
message-kill-buffer-on-exit t
|
||
mu4e-org-support nil)
|
||
(let ((dir "~/Downloads/mu4e"))
|
||
(when (file-directory-p dir)
|
||
(setq mu4e-attachment-dir dir))))
|
||
|
||
:config
|
||
<<mu4e-mail-service>>
|
||
<<mu4e-mail-on-machine>>
|
||
<<mu4e-no-signature>>
|
||
|
||
<<mu4e-bookmarks>>
|
||
|
||
;; Keybindings
|
||
<<mu4e-keybindings-undef>>
|
||
<<mu4e-keybindings-view>>
|
||
<<mu4e-keybindings-header>>
|
||
<<mu4e-keybindings-header-no-leader>>
|
||
<<mu4e-keybindings-message>>
|
||
|
||
(when (fboundp 'imagemagick-register-types)
|
||
(imagemagick-register-types))
|
||
|
||
(add-to-list 'mu4e-view-actions '("View in browser" . mu4e-action-view-in-browser) t)
|
||
(add-to-list 'mu4e-view-actions '("PDF view" . mu4e-action-open-as-pdf) t)
|
||
|
||
(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)
|
||
|
||
;; Use fancy icons
|
||
<<mu4e-fancy-marks>>
|
||
|
||
;; Vertical split
|
||
<<mu4e-vertical-split>>
|
||
|
||
;; mu4e-headers-mode config
|
||
<<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))))
|
||
#+end_src
|
||
|
||
***** Basic configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Basic-configurationfxy0fl6184j0
|
||
:END:
|
||
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
|
||
(setq smtpmail-smtp-server "mail.phundrak.com"
|
||
smtpmail-smtp-service 587
|
||
smtpmail-stream-type 'starttls
|
||
message-send-mail-function 'smtpmail-send-it)
|
||
#+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
|
||
(setq mu4e-get-mail-command "mbsync -a"
|
||
mu4e-maildir "~/Mail"
|
||
mu4e-trash-folder "/Trash"
|
||
mu4e-refile-folder "/Archive"
|
||
mu4e-sent-folder "/Sent"
|
||
mu4e-drafts-folder "/Drafts")
|
||
#+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
|
||
(setq mu4e-compose-signature nil)
|
||
#+end_src
|
||
|
||
***** Actions on messages
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Actions-on-messageskb01fl6184j0
|
||
:END:
|
||
|
||
***** Bookmarks
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Bookmarkszo11fl6184j0
|
||
:END:
|
||
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)
|
||
- the conlang mailing lists
|
||
- 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).
|
||
#+name: mu4e-bookmarks-filter-uni
|
||
#+headers: :tangle no :cache yes
|
||
#+begin_src emacs-lisp
|
||
(string-join '("f:/.*up8\.edu|.*univ-paris8.*/"
|
||
"c:/.*up8\.edu|.*univ-paris8.*/"
|
||
"t:/.*up8\.edu|.*univ-paris8.*/")
|
||
" OR ")
|
||
#+end_src
|
||
|
||
#+RESULTS[6f0c2005657e701b0a992061981317febcdd6200]: mu4e-bookmarks-filter-uni
|
||
: f:/.*up8.edu|.*univ-paris8.*/ OR c:/.*up8.edu|.*univ-paris8.*/ OR t:/.*up8.edu|.*univ-paris8.*/
|
||
|
||
As for the Emacs-doctor list, I need to match both the current, modern
|
||
mailing list address but also its old address.
|
||
#+name: mu4e-bookmarks-filter-emacs-list
|
||
#+headers: :tangle no :cache yes
|
||
#+begin_src emacs-lisp
|
||
(mapconcat (lambda (address)
|
||
(mapconcat (lambda (flag)
|
||
(concat flag ":" address))
|
||
'("list" "to" "from")
|
||
" OR "))
|
||
'("ateliers-emacs.framalistes.org" "ateliers-paris.emacs-doctor.com")
|
||
" OR ")
|
||
#+end_src
|
||
|
||
#+RESULTS[cff1b5e400cca47c06057bf236d099db01411cd7]: mu4e-bookmarks-filter-emacs-list
|
||
: list:ateliers-emacs.framalistes.org OR to:ateliers-emacs.framalistes.org OR from:ateliers-emacs.framalistes.org OR list:ateliers-paris.emacs-doctor.com OR to:ateliers-paris.emacs-doctor.com OR from:ateliers-paris.emacs-doctor.com
|
||
|
||
When it comes to the conlang mailing list, let’s not match anything
|
||
from or to them. I’ll also include the auxlang mailing list –I’m not
|
||
subscribed anymore, but it’ll keep my inbox clean.
|
||
#+name: mu4e-bookmarks-filter-conlang-list
|
||
#+headers: :tangle no :cache yes
|
||
#+begin_src emacs-lisp
|
||
(mapconcat (lambda (address)
|
||
(mapconcat (lambda (flag)
|
||
(concat flag ":" address))
|
||
'("from" "to" "list")
|
||
" OR "))
|
||
'("CONLANG@LISTSERV.BROWN.EDU" "AUXLANG@LISTSERV.BROWN.EDU")
|
||
" OR ")
|
||
#+end_src
|
||
|
||
#+RESULTS[129026cfdaeb910562b800b659ad8d2d13773932]: mu4e-bookmarks-filter-conlang-list
|
||
: from:CONLANG@LISTSERV.BROWN.EDU OR to:CONLANG@LISTSERV.BROWN.EDU OR list:CONLANG@LISTSERV.BROWN.EDU OR from:AUXLANG@LISTSERV.BROWN.EDU OR to:AUXLANG@LISTSERV.BROWN.EDU OR list:AUXLANG@LISTSERV.BROWN.EDU
|
||
|
||
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
|
||
#+headers: :tangle no :cache yes
|
||
#+begin_src emacs-lisp
|
||
(string-join `("NOT flag:trashed"
|
||
,(format "(%s)" (mapconcat (lambda (maildir) (concat "maildir:" maildir))
|
||
'("/Inbox" "/Junk")
|
||
" OR ")))
|
||
" AND ")
|
||
#+end_src
|
||
|
||
#+RESULTS[ccf162e159f77ccf87ff4fae220106f0a91ad256]: mu4e-bookmarks-default-filter
|
||
: 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
|
||
#+headers: :tangle no :cache yes
|
||
#+begin_src emacs-lisp
|
||
(string-join (cons
|
||
<<mu4e-bookmarks-default-filter>>
|
||
`(
|
||
,(format "(%s)"
|
||
<<mu4e-bookmarks-filter-conlang-list>>)
|
||
,(format "(%s)"
|
||
<<mu4e-bookmarks-filter-emacs-list>>)
|
||
,(format "(%s)"
|
||
<<mu4e-bookmarks-filter-uni>>)))
|
||
" AND NOT ")
|
||
#+end_src
|
||
|
||
#+RESULTS[2bd917f15a55a2a509f5710c6a4db5f8a8e7a596]: mu4e-bookmarks-inbox-filters
|
||
: NOT flag:trashed AND (maildir:/Inbox OR maildir:/Junk) AND NOT (from:CONLANG@LISTSERV.BROWN.EDU OR to:CONLANG@LISTSERV.BROWN.EDU OR list:CONLANG@LISTSERV.BROWN.EDU OR from:AUXLANG@LISTSERV.BROWN.EDU OR to:AUXLANG@LISTSERV.BROWN.EDU OR list:AUXLANG@LISTSERV.BROWN.EDU) AND NOT (list:ateliers-emacs.framalistes.org OR to:ateliers-emacs.framalistes.org OR from:ateliers-emacs.framalistes.org OR list:ateliers-paris.emacs-doctor.com OR to:ateliers-paris.emacs-doctor.com OR from:ateliers-paris.emacs-doctor.com) AND NOT (f:/.*up8.edu|.*univ-paris8.*/ OR c:/.*up8.edu|.*univ-paris8.*/ OR t:/.*up8.edu|.*univ-paris8.*/)
|
||
|
||
We can finally define our bookmarks! The code reads as follows:
|
||
#+name: mu4e-bookmarks
|
||
#+begin_src emacs-lisp :tangle no :cache yes
|
||
(setq mu4e-bookmarks
|
||
`((:name "Inbox"
|
||
:key ?i
|
||
:query ,(format "%s"
|
||
<<mu4e-bookmarks-inbox-filters>>))
|
||
(:name "Linguistics"
|
||
:key ?l
|
||
:query ,(format "%s AND %s"
|
||
<<mu4e-bookmarks-inbox-filters>>
|
||
<<mu4e-bookmarks-filter-conlang-list>>))
|
||
(:name "Emacs"
|
||
:key ?e
|
||
:query ,(format "%s AND %s"
|
||
<<mu4e-bookmarks-inbox-filters>>
|
||
<<mu4e-bookmarks-filter-emacs-list>>))
|
||
(:name "University"
|
||
:key ?u
|
||
:query ,(format "%s AND %s"
|
||
<<mu4e-bookmarks-inbox-filters>>
|
||
<<mu4e-bookmarks-filter-uni>>))
|
||
(:name "eshell-info-banner"
|
||
:key ?E
|
||
:query ,(format "%s AND %s"
|
||
<<mu4e-bookmarks-inbox-filters>>
|
||
"list:eshell-info-banner.el.Phundrak.github.com"))
|
||
(:name "Sent" :key ?s :query "maildir:/Sent")
|
||
(: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
|
||
|
||
#+RESULTS[4a18e1cfa32f399203b300f7cbd986a553a1b234]: mu4e-bookmarks
|
||
| :name | Inbox | :key | 105 | :query | NOT flag:trashed AND (maildir:/Inbox OR maildir:/Junk) AND NOT (from:CONLANG@LISTSERV.BROWN.EDU OR to:CONLANG@LISTSERV.BROWN.EDU OR list:CONLANG@LISTSERV.BROWN.EDU OR from:AUXLANG@LISTSERV.BROWN.EDU OR to:AUXLANG@LISTSERV.BROWN.EDU OR list:AUXLANG@LISTSERV.BROWN.EDU) AND NOT (list:ateliers-emacs.framalistes.org OR to:ateliers-emacs.framalistes.org OR from:ateliers-emacs.framalistes.org OR list:ateliers-paris.emacs-doctor.com OR to:ateliers-paris.emacs-doctor.com OR from:ateliers-paris.emacs-doctor.com) AND NOT (f:/.*up8.edu | .*univ-paris8.*/ OR c:/.*up8.edu | .*univ-paris8.*/ OR t:/.*up8.edu | .*univ-paris8.*/) | | | |
|
||
| :name | Linguistics | :key | 108 | :query | NOT flag:trashed AND (maildir:/Inbox OR maildir:/Junk) AND NOT (from:CONLANG@LISTSERV.BROWN.EDU OR to:CONLANG@LISTSERV.BROWN.EDU OR list:CONLANG@LISTSERV.BROWN.EDU OR from:AUXLANG@LISTSERV.BROWN.EDU OR to:AUXLANG@LISTSERV.BROWN.EDU OR list:AUXLANG@LISTSERV.BROWN.EDU) AND NOT (list:ateliers-emacs.framalistes.org OR to:ateliers-emacs.framalistes.org OR from:ateliers-emacs.framalistes.org OR list:ateliers-paris.emacs-doctor.com OR to:ateliers-paris.emacs-doctor.com OR from:ateliers-paris.emacs-doctor.com) AND NOT (f:/.*up8.edu | .*univ-paris8.*/ OR c:/.*up8.edu | .*univ-paris8.*/ OR t:/.*up8.edu | .*univ-paris8.*/) AND from:CONLANG@LISTSERV.BROWN.EDU OR to:CONLANG@LISTSERV.BROWN.EDU OR list:CONLANG@LISTSERV.BROWN.EDU OR from:AUXLANG@LISTSERV.BROWN.EDU OR to:AUXLANG@LISTSERV.BROWN.EDU OR list:AUXLANG@LISTSERV.BROWN.EDU | | | |
|
||
| :name | Emacs | :key | 101 | :query | NOT flag:trashed AND (maildir:/Inbox OR maildir:/Junk) AND NOT (from:CONLANG@LISTSERV.BROWN.EDU OR to:CONLANG@LISTSERV.BROWN.EDU OR list:CONLANG@LISTSERV.BROWN.EDU OR from:AUXLANG@LISTSERV.BROWN.EDU OR to:AUXLANG@LISTSERV.BROWN.EDU OR list:AUXLANG@LISTSERV.BROWN.EDU) AND NOT (list:ateliers-emacs.framalistes.org OR to:ateliers-emacs.framalistes.org OR from:ateliers-emacs.framalistes.org OR list:ateliers-paris.emacs-doctor.com OR to:ateliers-paris.emacs-doctor.com OR from:ateliers-paris.emacs-doctor.com) AND NOT (f:/.*up8.edu | .*univ-paris8.*/ OR c:/.*up8.edu | .*univ-paris8.*/ OR t:/.*up8.edu | .*univ-paris8.*/) AND list:ateliers-emacs.framalistes.org OR to:ateliers-emacs.framalistes.org OR from:ateliers-emacs.framalistes.org OR list:ateliers-paris.emacs-doctor.com OR to:ateliers-paris.emacs-doctor.com OR from:ateliers-paris.emacs-doctor.com | | | |
|
||
| :name | University | :key | 117 | :query | NOT flag:trashed AND (maildir:/Inbox OR maildir:/Junk) AND NOT (from:CONLANG@LISTSERV.BROWN.EDU OR to:CONLANG@LISTSERV.BROWN.EDU OR list:CONLANG@LISTSERV.BROWN.EDU OR from:AUXLANG@LISTSERV.BROWN.EDU OR to:AUXLANG@LISTSERV.BROWN.EDU OR list:AUXLANG@LISTSERV.BROWN.EDU) AND NOT (list:ateliers-emacs.framalistes.org OR to:ateliers-emacs.framalistes.org OR from:ateliers-emacs.framalistes.org OR list:ateliers-paris.emacs-doctor.com OR to:ateliers-paris.emacs-doctor.com OR from:ateliers-paris.emacs-doctor.com) AND NOT (f:/.*up8.edu | .*univ-paris8.*/ OR c:/.*up8.edu | .*univ-paris8.*/ OR t:/.*up8.edu | .*univ-paris8.*/) AND f:/.*up8.edu | .*univ-paris8.*/ OR c:/.*up8.edu | .*univ-paris8.*/ OR t:/.*up8.edu | .*univ-paris8.*/ |
|
||
| :name | eshell-info-banner | :key | 69 | :query | NOT flag:trashed AND (maildir:/Inbox OR maildir:/Junk) AND NOT (from:CONLANG@LISTSERV.BROWN.EDU OR to:CONLANG@LISTSERV.BROWN.EDU OR list:CONLANG@LISTSERV.BROWN.EDU OR from:AUXLANG@LISTSERV.BROWN.EDU OR to:AUXLANG@LISTSERV.BROWN.EDU OR list:AUXLANG@LISTSERV.BROWN.EDU) AND NOT (list:ateliers-emacs.framalistes.org OR to:ateliers-emacs.framalistes.org OR from:ateliers-emacs.framalistes.org OR list:ateliers-paris.emacs-doctor.com OR to:ateliers-paris.emacs-doctor.com OR from:ateliers-paris.emacs-doctor.com) AND NOT (f:/.*up8.edu | .*univ-paris8.*/ OR c:/.*up8.edu | .*univ-paris8.*/ OR t:/.*up8.edu | .*univ-paris8.*/) AND list:eshell-info-banner.el.Phundrak.github.com | | | |
|
||
| :name | Sent | :key | 115 | :query | maildir:/Sent | | | | | | |
|
||
| :name | All Unread | :key | 85 | :query | flag:unread AND NOT flag:trashed | | | | | | |
|
||
| :name | Today | :key | 116 | :query | date:today..now AND NOT flag:trashed | | | | | | |
|
||
| :name | This Week | :key | 119 | :query | date:7d..now AND NOT flag:trashed | | | | | | |
|
||
| :name | This Month | :key | 109 | :query | date:1m..now AND NOT flag:trashed | | | | | | |
|
||
| :name | This Year | :key | 121 | :query | date:1y..now AND NOT flag:trashed | | | | | | |
|
||
|
||
***** 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
|
||
hero]]! Now, let me write a function that will insert their pre-written
|
||
text at point so I don’t have to go back to their Twitter thread each
|
||
time I want to shut spammers up.
|
||
#+begin_src emacs-lisp
|
||
(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.
|
||
|
||
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."))
|
||
#+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]].
|
||
|
||
***** Getting Fancy
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Getting-Fancyg731fl6184j0
|
||
:END:
|
||
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
|
||
#+header: :tangle no :exports none :results value :cache yes
|
||
#+begin_src emacs-lisp :var table=mu4e-fancy-marks-tbl
|
||
(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")
|
||
#+end_src
|
||
|
||
#+RESULTS[c6ed5d4bec4c10339a7de52a70822af74d782e62]: mu4e-fancy-marks-gen
|
||
#+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
|
||
#+begin_src emacs-lisp :tangle no
|
||
(setq mu4e-use-fancy-chars t
|
||
<<mu4e-fancy-marks-gen()>>)
|
||
#+end_src
|
||
|
||
#+name: mu4e-vertical-split
|
||
#+begin_src emacs-lisp
|
||
(defun my/set-mu4e-headers-width ()
|
||
(let ((width (window-body-width))
|
||
(threshold (+ 120 80)))
|
||
(setq mu4e-split-view (if (> width threshold)
|
||
'vertical
|
||
'horizontal))
|
||
(message "Window width: %d\tthreshold: %d\nSplit: %S"
|
||
width
|
||
threshold
|
||
mu4e-split-view)))
|
||
|
||
(setq mu4e-headers-visible-columns 120
|
||
mu4e-headers-visible-lines 15)
|
||
(add-hook 'mu4e-headers-mode-hook #'my/set-mu4e-headers-width)
|
||
#+end_src
|
||
|
||
#+RESULTS: mu4e-vertical-split
|
||
| (lambda nil (toggle-truncate-lines -1)) | (lambda nil (visual-line-mode -1)) | my/set-mu4e-headers-width |
|
||
|
||
***** Headers mode
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Headers-modeum41fl6184j0
|
||
:END:
|
||
#+name: mu4e-headers-mode
|
||
#+begin_src emacs-lisp :tangle no
|
||
(add-hook 'mu4e-headers-mode-hook (lambda () (visual-line-mode -1)))
|
||
(add-hook 'mu4e-headers-mode-hook (lambda () (toggle-truncate-lines -1)))
|
||
#+end_src
|
||
|
||
***** Keybindings
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Mu4e-Keybindingsh161fl6184j0
|
||
:END:
|
||
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
|
||
#+begin_src emacs-lisp :tangle no
|
||
(general-define-key
|
||
:keymaps '(mu4e-headers-mode-map mu4e-view-mode-map)
|
||
"SPC" nil
|
||
"s" nil)
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps '(mu4e-headers-mode-map mu4e-view-mode-map)
|
||
"SPC" nil
|
||
"s" nil
|
||
"," nil)
|
||
(general-define-key
|
||
:keymaps 'mu4e-view-mode-map
|
||
"SPC" nil
|
||
"S" nil
|
||
"r" nil
|
||
"c" nil)
|
||
(general-define-key
|
||
:keymaps 'mu4e-view-mode-map
|
||
:states 'normal
|
||
"SPC" nil
|
||
"S" nil
|
||
"r" nil
|
||
"c" nil
|
||
"gu" nil)
|
||
#+end_src
|
||
|
||
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 | |
|
||
| g | nil | go to |
|
||
| gu | mu4e-view-go-to-url | |
|
||
| gX | mu4e-view-fetch-url | |
|
||
| 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 | |
|
||
| t | nil | thread |
|
||
| 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 | |
|
||
|
||
Some functions are however lambdas. They all are written as actions on
|
||
the current thread. They all begin with ~,t~, and below you can see each
|
||
one of the possible following key can act on a thread:
|
||
#+name: mu4e-keybindings-view-lambdas-tbl
|
||
| Key | Mark thread as |
|
||
|-----+----------------|
|
||
| td | trash |
|
||
| tD | delete |
|
||
| tm | move |
|
||
| tr | refile |
|
||
| tR | read |
|
||
| tu | unread |
|
||
| tU | unmark |
|
||
|
||
#+name: mu4e-keybindings-view-lambdas-gen
|
||
#+header: :tangle no :exports none :results value
|
||
#+begin_src emacs-lisp :var table=mu4e-keybindings-view-lambdas-tbl mode="view"
|
||
(mapconcat (lambda (line)
|
||
(let ((key (car line))
|
||
(mark (cadr line)))
|
||
(format "\"%s\" '((lambda ()
|
||
(interactive)
|
||
(mu4e-%s-mark-thread '%s))
|
||
:wk \"Mark as %s\")"
|
||
key mode mark mark)))
|
||
table
|
||
"\n")
|
||
#+end_src
|
||
|
||
#+RESULTS: mu4e-keybindings-view-lambdas-gen
|
||
#+begin_example
|
||
"td" '((lambda ()
|
||
(interactive)
|
||
(mu4e-view-mark-thread 'trash))
|
||
:wk "Mark as trash")
|
||
"tD" '((lambda ()
|
||
(interactive)
|
||
(mu4e-view-mark-thread 'delete))
|
||
:wk "Mark as delete")
|
||
"tm" '((lambda ()
|
||
(interactive)
|
||
(mu4e-view-mark-thread 'move))
|
||
:wk "Mark as move")
|
||
"tr" '((lambda ()
|
||
(interactive)
|
||
(mu4e-view-mark-thread 'refile))
|
||
:wk "Mark as refile")
|
||
"tR" '((lambda ()
|
||
(interactive)
|
||
(mu4e-view-mark-thread 'read))
|
||
:wk "Mark as read")
|
||
"tu" '((lambda ()
|
||
(interactive)
|
||
(mu4e-view-mark-thread 'unread))
|
||
:wk "Mark as unread")
|
||
"tU" '((lambda ()
|
||
(interactive)
|
||
(mu4e-view-mark-thread 'unmark))
|
||
:wk "Mark as unmark")
|
||
#+end_example
|
||
|
||
#+name: mu4e-keybindings-view
|
||
#+begin_src emacs-lisp :tangle no
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps 'mu4e-view-mode-map
|
||
:prefix ","
|
||
<<general-keybindings-gen(table=mu4e-keybindings-view-tbl)>>
|
||
<<mu4e-keybindings-view-lambdas-gen(mode="view")>>)
|
||
#+end_src
|
||
|
||
Some simple keybindings are defined for mu4e’s header mode:
|
||
#+name: mu4e-keybindings-headers-tbl
|
||
| Key | Function | Description |
|
||
|-----+----------+-------------|
|
||
| s | swiper | |
|
||
| t | nil | thread |
|
||
|
||
The keybindings from table [[mu4e-keybindings-view-lambdas-tbl]] will also
|
||
be reused for this mode.
|
||
|
||
#+name: mu4e-keybindings-header
|
||
#+begin_src emacs-lisp :tangle no
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps 'mu4e-headers-mode-map
|
||
:prefix ","
|
||
<<general-keybindings-gen(table=mu4e-keybindings-headers-tbl)>>
|
||
<<mu4e-keybindings-view-lambdas-gen(mode="headers")>>)
|
||
#+end_src
|
||
|
||
#+RESULTS: mu4e-keybindings-header
|
||
|
||
I will also redefine without a leader key ~ctsr~ in order to be able to
|
||
move freely (remember, bépo layout for me).
|
||
#+name: mu4e-keybindings-header-no-leader
|
||
#+begin_src emacs-lisp :tangle no
|
||
(general-define-key
|
||
:keymaps 'mu4e-headers-mode-map
|
||
:states 'normal
|
||
"c" #'evil-backward-char
|
||
"t" #'evil-next-line
|
||
"s" #'evil-previous-line
|
||
"r" #'evil-forward-char)
|
||
#+end_src
|
||
|
||
#+RESULTS: mu4e-keybindings-header-no-leader
|
||
|
||
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 | |
|
||
| f | mml-attach-file) | |
|
||
|
||
#+name: mu4e-keybindings-message
|
||
#+begin_src emacs-lisp :tangle no
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps 'message-mode-map
|
||
:prefix ","
|
||
<<general-keybindings-gen(table=mu4e-keybindings-message-tbl)>>
|
||
#+end_src
|
||
|
||
#+RESULTS: mu4e-keybindings-message
|
||
|
||
**** Composing messages
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Composing-messagesth71fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package org-msg
|
||
:after (org mu4e)
|
||
:straight (:build t)
|
||
:hook ((mu4e-compose-pre . org-msg-mode))
|
||
:general (:keymaps 'org-msg-edit-mode-map
|
||
:prefix ","
|
||
:states 'normal
|
||
"," #'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)
|
||
: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"
|
||
org-msg-default-alternatives '((new . (text html))
|
||
(reply-to-html . (text html))
|
||
(reply-to-text . (text)))
|
||
org-msg-convert-citation t
|
||
org-msg-greeting-name-limit 3
|
||
org-msg-signature (format "\n--\n#+begin_signature\n%s\n#+end_signature"
|
||
(replace-regexp-in-string (regexp-quote "\n") "\n\n"
|
||
(with-temp-buffer
|
||
(insert-file-contents mail-signature-file)
|
||
(buffer-string))))))
|
||
#+end_src
|
||
|
||
**** Email alerts
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Email-Email-alertsfx81fl6184j0
|
||
:END:
|
||
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.
|
||
#+begin_src emacs-lisp
|
||
(use-package mu4e-alert
|
||
:straight (:build t)
|
||
: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"))
|
||
#+end_src
|
||
|
||
*** Nov
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Nov0da1fl6184j0
|
||
:END:
|
||
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?
|
||
#+begin_src emacs-lisp
|
||
(use-package nov
|
||
:straight (:build t)
|
||
:defer t
|
||
:mode ("\\.epub\\'" . nov-mode)
|
||
:config
|
||
(general-define-key
|
||
:keymaps 'nov-mode-map
|
||
:states 'normal
|
||
"SPC" nil
|
||
"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)
|
||
(setq nov-text-width 95))
|
||
#+end_src
|
||
|
||
*** PDF Tools
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-PDF-Toolsvqb1fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package pdf-tools
|
||
:defer t
|
||
:magic ("%PDF" . pdf-view-mode)
|
||
:straight (:build t)
|
||
:mode (("\\.pdf\\'" . pdf-view-mode))
|
||
:hook (pdf-tools-enabled . pdf-view-midnight-minor-mode)
|
||
:config
|
||
(progn
|
||
(with-eval-after-load 'pdf-view
|
||
(setq pdf-view-midnight-colors '("#d8dee9" . "#2e3440")))
|
||
(general-define-key
|
||
:keymaps 'pdf-view-mode-map
|
||
"SPC" nil
|
||
"," nil)
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps 'pdf-view-mode-map
|
||
"SPC" nil
|
||
"," nil
|
||
"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)
|
||
(general-define-key
|
||
:states 'motion
|
||
:keymaps 'pdf-view-mode-map
|
||
:prefix ","
|
||
"a" '(nil :which-key "annotations")
|
||
"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
|
||
|
||
"f" '(nil :which-key "fit")
|
||
"fw" #'pdf-view-fit-width-to-window
|
||
"fh" #'pdf-view-fit-height-to-window
|
||
"fp" #'pdf-view-fit-page-to-window
|
||
|
||
"s" '(nil :which-key "slice/search")
|
||
"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)))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package pdf-view-restore
|
||
:after pdf-tools
|
||
:hook (pdf-view-mode . pdf-view-restore-mode))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(setq pdf-view-restore-filename (expand-file-name ".tmp/pdf-view-restore"
|
||
user-emacs-directory))
|
||
#+end_src
|
||
|
||
*** 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
|
||
thing doesn’t happen with Magit, it’s pretty transparent but it still
|
||
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
|
||
(use-package magit
|
||
:straight (:build t)
|
||
:defer t
|
||
:custom
|
||
(magit-display-buffer-function #'magit-display-buffer-same-window-except-diff-v1)
|
||
:general
|
||
(:keymaps '(git-rebase-mode-map)
|
||
"C-t" #'evil-next-line
|
||
"C-s" #'evil-previous-line)
|
||
(:keymaps 'git-rebase-mode-map
|
||
:states 'normal
|
||
:prefix ","
|
||
"," #'with-editor-finish
|
||
"k" #'with-editor-cancel
|
||
"a" #'with-editor-cancel)
|
||
(:states 'normal
|
||
:prefix "SPC"
|
||
"g" '(nil :wk "git")
|
||
"gb" #'magit-blame
|
||
"gc" #'magit-clone
|
||
"gd" #'magit-dispatch
|
||
"gi" #'magit-init
|
||
"gs" #'magit-status
|
||
"gy" #'my/yadm
|
||
"gS" #'magit-stage-file
|
||
"gU" #'magit-unstage-file
|
||
|
||
"gf" '(nil :wk "file")
|
||
"gfd" #'magit-diff
|
||
"gfc" #'magit-file-checkout
|
||
"gfl" #'magit-file-dispatch
|
||
"gfF" #'magit-find-file))
|
||
#+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.
|
||
#+begin_src emacs-lisp
|
||
(use-package magit-todos
|
||
:straight (:build t)
|
||
:after magit
|
||
:config
|
||
(setq magit-todos-ignore-case t))
|
||
#+end_src
|
||
|
||
Finally, it is also possible to use Gitflow’s framework with Magit
|
||
with ~magit-gitflow~:
|
||
#+begin_src emacs-lisp
|
||
(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))
|
||
#+end_src
|
||
|
||
**** Forge
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Project-Management-Forgelcq5fl6184j0
|
||
:END:
|
||
*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
|
||
(use-package forge
|
||
:after magit
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
**** Projectile
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Project-Management-Projectilesvr5fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package ripgrep
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package projectile
|
||
:straight (:build t)
|
||
:defer t
|
||
:diminish projectile-mode
|
||
:config (projectile-mode)
|
||
:custom ((projectile-completion-system 'ivy))
|
||
:bind-keymap
|
||
("C-c p" . projectile-command-map)
|
||
:init
|
||
;; NOTE: Set this to the folder where you keep your Git repos!
|
||
(setq projectile-switch-project-action #'projectile-dired))
|
||
|
||
(use-package counsel-projectile
|
||
:straight (:build t)
|
||
:after (counsel projectile)
|
||
:config (counsel-projectile-mode))
|
||
#+end_src
|
||
|
||
*** Screenshot
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Screenshot96d1fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package screenshot
|
||
:defer t
|
||
:straight (screenshot :build t
|
||
:type git
|
||
:host github
|
||
:repo "tecosaur/screenshot"))
|
||
#+end_src
|
||
|
||
*** Shells
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Shellsxke1fl6184j0
|
||
:END:
|
||
**** Shell-pop
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Shells-Shell-popk0g1fl6184j0
|
||
:END:
|
||
Shell-pop allows the user to easily call for a new shell in a pop-up
|
||
buffer.
|
||
#+begin_src emacs-lisp
|
||
(use-package shell-pop
|
||
:defer t
|
||
:straight (:build t)
|
||
:custom
|
||
(shell-pop-default-directory "/home/phundrak")
|
||
(shell-pop-shell-type (quote ("eshell" "*eshell*" (lambda nil (eshell shell-pop-term-shell)))))
|
||
(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))
|
||
#+end_src
|
||
|
||
**** VTerm
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Shells-VTermzfh1fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package vterm
|
||
:defer t
|
||
:straight t
|
||
:config
|
||
(setq vterm-shell "/usr/bin/fish"))
|
||
#+end_src
|
||
|
||
*** XWidgets Webkit Browser
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-XWidgets-Webkit-Browsertui1fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(general-define-key
|
||
:keymaps 'xwidget-webkit-mode-map
|
||
:states 'normal
|
||
"<mouse-4>" #'xwidget-webkit-scroll-down-line
|
||
"<mouse-5>" #'xwidget-webkit-scroll-up-line
|
||
|
||
"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
|
||
"j" nil
|
||
"k" nil
|
||
"l" nil
|
||
|
||
"H" nil
|
||
"L" nil
|
||
"C-d" #'xwidget-webkit-scroll-up
|
||
"C-u" #'xwidget-webkit-scroll-down)
|
||
|
||
(general-define-key
|
||
:keymaps 'xwidget-webkit-mode-map
|
||
:states 'normal
|
||
:prefix ","
|
||
"b" #'xwidget-webkit-back
|
||
"f" #'xwidget-webkit-forward
|
||
"r" #'xwidget-webkit-reload)
|
||
#+end_src
|
||
|
||
*** Wttr.in
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Wttr-inpak1fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(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))
|
||
#+end_src
|
||
|
||
**** TODO Derive a major mode for wttrin :noexport:
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Applications-Wttr-in-Derive-a-major-mode-for-wttrinkrl1fl6184j0
|
||
:END:
|
||
To handle keybindings correctly, a major mode for wttrin could be
|
||
derived from ~fundamental-mode~ and get an associated keymap.
|
||
|
||
** Editing
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Editinggnu1fl6184j0
|
||
:END:
|
||
First, I’ll define some keybindings for easily inserting pairs when
|
||
editing text.
|
||
#+begin_src emacs-lisp
|
||
(general-define-key
|
||
:states 'visual
|
||
"M-[" #'insert-pair
|
||
"M-{" #'insert-pair
|
||
"M-<" #'insert-pair
|
||
"M-'" #'insert-pair
|
||
"M-`" #'insert-pair
|
||
"M-\"" #'insert-pair)
|
||
#+end_src
|
||
|
||
*** Evil Nerd Commenter
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Editing-Evil-Nerd-Commenterd2w1fl6184j0
|
||
:END:
|
||
Emacs’ default commenting system is nice, but I don’t find it smart
|
||
enough for me.
|
||
#+begin_src emacs-lisp
|
||
(use-package evil-nerd-commenter
|
||
:after evil
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
*** Parinfer
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Editing-Parinfermxy1fl6184j0
|
||
:END:
|
||
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
|
||
~parinfer-rust-mode~ is built.
|
||
#+begin_src emacs-lisp
|
||
(use-package parinfer-rust-mode
|
||
:defer t
|
||
:diminish parinfer-rust-mode
|
||
:hook emacs-lisp-mode common-lisp-mode scheme-mode
|
||
:init
|
||
(setq parinfer-rust-auto-download t
|
||
parinfer-rust-library-directory (concat user-emacs-directory
|
||
"parinfer-rust/")))
|
||
#+end_src
|
||
|
||
*** 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
|
||
(use-package smartparens
|
||
:defer t
|
||
:straight (:build t)
|
||
:hook (prog-mode . smartparens-mode))
|
||
#+end_src
|
||
|
||
*** ~string-edit~
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Editing-string-editae02fl6184j0
|
||
:END:
|
||
~string-edit~ is a cool package that allows the user to write naturally
|
||
a string and get it automatically escaped for you. No more manually
|
||
escaping your strings!
|
||
#+begin_src emacs-lisp
|
||
(use-package string-edit
|
||
:defer t
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
*** Writeroom
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Editing-Writeroomxt12fl6184j0
|
||
:END:
|
||
On the other hand, ~writeroom~ allows the user to enter a
|
||
distraction-free mode of Emacs, and I like that! But the default width
|
||
is a bit too small for me, and I prefer not to go fullscren.
|
||
#+begin_src emacs-lisp
|
||
(use-package writeroom-mode
|
||
:defer t
|
||
:straight (:build t)
|
||
:config
|
||
(setq writeroom-width 100
|
||
writeroom-fullscreen-effect nil
|
||
writeroom-maximize-window nil
|
||
writeroom-mode-line t))
|
||
#+end_src
|
||
|
||
** Emacs built-ins
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-insr832fl6184j0
|
||
:END:
|
||
*** Dired
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Diredao42fl6184j0
|
||
:END:
|
||
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.
|
||
However, the only thing I lack still is thumbnails. In any case, I
|
||
need still to make some tweaks in order to make it usable for
|
||
me.
|
||
#+begin_src emacs-lisp
|
||
(use-package dired
|
||
:straight (:type built-in)
|
||
:defer t
|
||
:hook (dired-mode . turn-on-gnus-dired-mode)
|
||
:general
|
||
(:keymaps 'dired-mode-map
|
||
:states 'normal
|
||
"(" #'dired-hide-details-mode
|
||
"n" #'evil-next-line
|
||
"p" #'evil-previous-line)
|
||
:config
|
||
(setq dired-dwim-target t
|
||
dired-recursive-copies t
|
||
dired-recursive-deletes t
|
||
dired-listing-switches "-ahl --group-directories-first"))
|
||
#+end_src
|
||
|
||
Note that I am activating by default ~gnus-dired-mode~. This is just for
|
||
the sake of convenience, since I’m not penalized with activating this
|
||
mode when it is not needed, but I don’t have to manually activate it
|
||
each time I need it.
|
||
|
||
Dired-x stands for “dired extra” which provides a couple more features
|
||
that are for some reason not included in dired yet.
|
||
#+begin_src emacs-lisp
|
||
(use-package dired-x
|
||
:straight (:type built-in)
|
||
:after dired
|
||
:commands (dired-jump dired-jump-other-window dired-omit-mode)
|
||
:general
|
||
(:keymaps 'dired-mode-map
|
||
:states 'normal
|
||
"«" #'dired-omit-mode))
|
||
#+end_src
|
||
~dired-du~ provides the user with the option to be able to see the size
|
||
of directories as they are, rather than just the size of their
|
||
inode. However, I will not enable it by default as it can take some
|
||
time to get the actual size of a directory.
|
||
#+begin_src emacs-lisp
|
||
(use-package dired-du
|
||
:after dired
|
||
:straight (:build t)
|
||
:general
|
||
(:keymaps 'dired-mode-map
|
||
:states 'normal
|
||
"»" #'dired-du-mode))
|
||
#+end_src
|
||
|
||
This package on the other hand provides Git information to the user in
|
||
the current dired buffer in a similar way to how Github and Gitea
|
||
display the latest commit message and its age about a file in the file
|
||
tree. And by default, I want ~dired-git-info~ to hide file details.
|
||
#+begin_src emacs-lisp
|
||
(use-package dired-git-info
|
||
:after dired
|
||
:hook (dired-after-reading . dired-git-info-auto-enable)
|
||
:general
|
||
(:keymaps 'dired-mode-map
|
||
:states 'normal
|
||
")" #'dired-git-info-mode)
|
||
:config
|
||
(setq dgi-auto-hide-details-p t))
|
||
#+end_src
|
||
|
||
Diredfl makes dired colorful, and much more readable in my opinion.
|
||
#+begin_src emacs-lisp
|
||
(use-package diredfl
|
||
:straight (:build t)
|
||
:after dired
|
||
:init
|
||
(diredfl-global-mode 1))
|
||
#+end_src
|
||
|
||
And let’s add some fancy icons in dired!
|
||
#+begin_src emacs-lisp
|
||
(use-package all-the-icons-dired
|
||
:straight (:build t)
|
||
:hook (dired-mode . all-the-icons-dired-mode))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package image-dired+
|
||
:after image-dired
|
||
:init (image-diredx-adjust-mode 1))
|
||
#+end_src
|
||
|
||
*** Eshell
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell0662fl6184j0
|
||
:END:
|
||
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
|
||
(general-define-key
|
||
:keymaps 'eshell-mode-map
|
||
:states 'insert
|
||
"C-a" #'eshell-bol
|
||
"C-e" #'end-of-line)
|
||
#+end_src
|
||
|
||
**** Aliases
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Aliasesom72fl6184j0
|
||
:END:
|
||
First, let’s declare our list of “dumb” aliases we’ll use in
|
||
Eshell. You can find them here.
|
||
#+begin_src emacs-lisp
|
||
(setq eshell-aliases-file (expand-file-name "eshell-aliases" user-emacs-directory))
|
||
#+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:
|
||
#+begin_src emacs-lisp
|
||
(defun phundrak/concatenate-shell-command (&rest command)
|
||
"Concatenate an eshell `COMMAND' into a single string.
|
||
|
||
All elements of `COMMAND' will be joined in a single
|
||
space-separated string."
|
||
(string-join command " "))
|
||
#+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.
|
||
#+begin_src emacs-lisp
|
||
(defalias 'open 'find-file)
|
||
(defalias 'openo 'find-file-other-window)
|
||
#+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.
|
||
#+begin_src emacs-lisp
|
||
(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.
|
||
#+begin_src emacs-lisp
|
||
(defun eshell/emacs (&rest file)
|
||
"Open each `FILE' and kill eshell.
|
||
|
||
Old habits die hard."
|
||
(when file
|
||
(dolist (f (reverse file))
|
||
(find-file f t))))
|
||
#+end_src
|
||
|
||
Finally, 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~.
|
||
#+begin_src emacs-lisp
|
||
(defun eshell/mkcd (dir)
|
||
"Create the directory `DIR' and move there.
|
||
|
||
If the directory `DIR' doesn’t exist, create it and its parents
|
||
if needed, then move there."
|
||
(mkdir dir t)
|
||
(cd dir))
|
||
#+end_src
|
||
|
||
**** Autosuggestion
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Autosuggestion-kf6ipm1195j0
|
||
:END:
|
||
I really like fish’s autosuggestion feature, so let’s reproduce it
|
||
here!
|
||
#+begin_src emacs-lisp
|
||
(use-package esh-autosuggest
|
||
:defer t
|
||
:after eshell
|
||
:straight (:build t)
|
||
:hook (eshell-mode . esh-autosuggest-mode)
|
||
:general
|
||
(:keymaps 'esh-autosuggest-active-map
|
||
"C-e" #'company-complete-selection))
|
||
#+end_src
|
||
|
||
**** Commands
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Commands-n8w3fh2195j0
|
||
:END:
|
||
When I’m in Eshell, sometimes I wish to open multiple files at once in
|
||
Emacs. For this, when I have several arguments for ~find-file~, I want
|
||
to be able to open them all at once. Let’s modify ~find-file~ like so:
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defadvice find-file (around find-files activate)
|
||
"Also find all files within a list of files. This even works recursively."
|
||
(if (listp filename)
|
||
(cl-loop for f in filename do (find-file f wildcards))
|
||
ad-do-it))
|
||
#+END_SRC
|
||
|
||
I also want to be able to have multiple instances of Eshell opened at
|
||
once. For that, I declared the function ~eshell-new~ that does exactly
|
||
that.
|
||
#+begin_src emacs-lisp
|
||
(defun eshell-new ()
|
||
"Open a new instance of eshell."
|
||
(interactive)
|
||
(eshell 'N))
|
||
#+end_src
|
||
|
||
A very useful command I use often in fish is ~z~, a port from bash’s and
|
||
zsh’s command that allows to jump around directories based on how
|
||
often we go in various directories.
|
||
#+begin_src emacs-lisp
|
||
(use-package eshell-z
|
||
:defer t
|
||
:after eshell
|
||
:straight (:build t)
|
||
:hook (eshell-mode . (lambda () (require 'eshell-z))))
|
||
#+end_src
|
||
|
||
**** Environment Variables
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Environment-Variablesmna2fl6184j0
|
||
:END:
|
||
Some environment variables need to be correctly set so Eshell can
|
||
correctly work. I would like to set two environment variables related
|
||
to Dart development: the ~DART_SDK~ and ~ANDROID_HOME~ variables.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setenv "DART_SDK" "/opt/dart-sdk/bin")
|
||
(setenv "ANDROID_HOME" (concat (getenv "HOME") "/Android/Sdk/"))
|
||
#+END_SRC
|
||
|
||
The ~EDITOR~ variable also needs to be set for git commands, especially the
|
||
~yadm~ commands.
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setenv "EDITOR" "emacsclient -c -a emacs")
|
||
#+END_SRC
|
||
|
||
Finally, for some specific situations I need ~SHELL~ to be set to
|
||
something more standard than fish:
|
||
#+begin_src emacs-lisp
|
||
(setenv "SHELL" "/bin/sh")
|
||
#+end_src
|
||
|
||
**** Visual configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Eshell-Visual-configuratione7c2fl6184j0
|
||
:END:
|
||
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
|
||
I like it, so [[https://github.com/Phundrak/eshell-info-banner.el][I’ve written a package]]!
|
||
#+begin_src emacs-lisp
|
||
(use-package eshell-info-banner
|
||
:defer t
|
||
:straight (eshell-info-banner :build t
|
||
:type git
|
||
:host github
|
||
:repo "phundrak/eshell-info-banner.el")
|
||
:hook (eshell-banner-load . eshell-info-banner-update-banner)
|
||
:config
|
||
(setq eshell-info-banner-width 80
|
||
eshell-info-banner-partition-prefixes '("/dev" "zroot" "tank")))
|
||
#+end_src
|
||
|
||
Another feature I like is fish-like syntax highlight, which brings
|
||
some more colors to Eshell.
|
||
#+begin_src emacs-lisp
|
||
(use-package eshell-syntax-highlighting
|
||
:after esh-mode
|
||
:defer t
|
||
:config
|
||
(eshell-syntax-highlighting-global-mode +1))
|
||
#+end_src
|
||
|
||
Powerline prompts are nice, git-aware prompts are even better!
|
||
~eshell-git-prompt~ is nice, but I prefer to write my own package for
|
||
that.
|
||
#+begin_src emacs-lisp
|
||
(use-package powerline-eshell
|
||
:load-path "~/fromGIT/emacs-packages/powerline-eshell.el/"
|
||
:after eshell)
|
||
#+end_src
|
||
|
||
*** Info
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Info-r7x90j20c5j0
|
||
:END:
|
||
Something that irks me as I use evil and a leader key is that the
|
||
space bar is already bound to a function, ~Info-scroll-up~. Same goes
|
||
for my local leader ~,~ which is bound to ~Info-index-next~. I don’t want
|
||
that, so let’s unbind them:
|
||
#+begin_src emacs-lisp
|
||
(general-define-key
|
||
:keymaps '(Info-mode-map)
|
||
"SPC" nil
|
||
"," nil)
|
||
(general-define-key
|
||
:keymaps '(Info-mode-map)
|
||
:states 'normal
|
||
"SPC" nil
|
||
"," nil)
|
||
#+end_src
|
||
|
||
Alright, now that we correctly unbound them, my global leader key
|
||
works again, and I’m free to use the comma as a local leader, so let’s
|
||
do that:
|
||
#+begin_src emacs-lisp
|
||
(general-define-key
|
||
:keymaps 'Info-mode-map
|
||
:states 'normal
|
||
"c" #'Info-prev
|
||
"t" #'evil-scroll-down
|
||
"s" #'evil-scroll-up
|
||
"r" #'Info-next)
|
||
|
||
(general-define-key
|
||
:keymaps 'Info-mode-map
|
||
:states 'normal
|
||
:prefix ","
|
||
"?" #'Info-toc
|
||
"b" #'Info-history-back
|
||
"f" #'Info-history-forward
|
||
"m" #'Info-menu
|
||
"t" #'Info-top-node
|
||
"u" #'Info-up)
|
||
#+end_src
|
||
|
||
*** Tramp
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Tramplqd2fl6184j0
|
||
:END:
|
||
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
|
||
(require 'tramp)
|
||
#+end_src
|
||
|
||
**** Yadm
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Emacs-built-ins-Tramp-Yadma8f2fl6184j0
|
||
:END:
|
||
[[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:
|
||
#+begin_src emacs-lisp
|
||
(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
|
||
(defun my/yadm ()
|
||
"Manage my dotfiles through TRAMP."
|
||
(interactive)
|
||
(magit-status "/yadm::"))
|
||
#+end_src
|
||
|
||
** EXWM
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-EXWM6vx4fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(defvar phundrak/exwm-enabled (and (seq-contains command-line-args "--with-exwm")))
|
||
|
||
(use-package xelb
|
||
:if phundrak/exwm-enabled
|
||
:straight (:build t))
|
||
|
||
(use-package exwm
|
||
:straight (:build t)
|
||
:if phundrak/exwm-enabled
|
||
:after xelb
|
||
:init
|
||
(setq mouse-autoselect-window nil
|
||
focus-follows-mouse t
|
||
exwm-workspace-warp-cursor t)
|
||
:config
|
||
(when phundrak/exwm-enabled
|
||
(setq exwm-input-global-keys
|
||
`(([?\s-r] . exwm-reset)
|
||
([?\s-w] . exwm-workspace-switch)
|
||
,@(mapcar (lambda (i)
|
||
`(,(kbd (format "s-%s" (car i))) .
|
||
(lambda ()
|
||
(interactive)
|
||
(exwm-workspace-switch-create ,(cdr i)))))
|
||
'(("\"" . 1)
|
||
("«" . 2)
|
||
("»" . 3)
|
||
("(" . 4)
|
||
(")" . 5)
|
||
("@" . 6)
|
||
("+" . 7)
|
||
("-" . 8)
|
||
("/" . 9)
|
||
("*" . 0)))))
|
||
(add-hook 'exwm-update-class-hook
|
||
(lambda ()
|
||
(exwm-workspace-rename-buffer exwm-class-name)))
|
||
(require 'exwm-config)
|
||
(exwm-config-default)
|
||
(exwm-enable)))
|
||
|
||
|
||
|
||
(use-package desktop-environment
|
||
:if phundrak/exwm-enabled
|
||
:after exwm
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
|
||
** Making my life easier
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Making-my-life-easier2kz4fl6184j0
|
||
:END:
|
||
*** Bufler
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Making-my-life-easier-Buflerw215fl6184j0
|
||
:END:
|
||
Bufler is a package that organizes and lists buffers in a much better
|
||
way than how they are usually sorted. You can easily and quickly find
|
||
buffers by their group, not only by their name, and THIS is great
|
||
news! Also, no ~helm~ please! And for some reasons the keybindings are
|
||
borked by default, so 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
|
||
(use-package bufler
|
||
:straight (bufler :build t
|
||
:files (:defaults (:exclude "helm-bufler.el")))
|
||
:defer t
|
||
:general
|
||
(:keymaps 'bufler-list-mode-map
|
||
:states 'normal
|
||
"?" #'hydra:bufler/body
|
||
"g" #'bufler
|
||
"f" #'bufler-list-group-frame
|
||
"F" #'bufler-list-group-make-frame
|
||
"N" #'bufler-list-buffer-name-workspace
|
||
"k" #'bufler-list-buffer-kill
|
||
"p" #'bufler-list-buffer-peek
|
||
"s" #'bufler-list-buffer-save
|
||
"RET" #'bufler-list-buffer-switch))
|
||
#+end_src
|
||
|
||
*** Helpful
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Making-my-life-easier-Helpfullh25fl6184j0
|
||
:END:
|
||
As the name tells, ~helpful~ is a really helpful package which greatly
|
||
enhances a couple of built-in functions from Emacs, namely:
|
||
| Vanilla Emacs Function | Helpful Function | Comment |
|
||
|------------------------+------------------+-----------------------------------------------|
|
||
| ~describe-function~ | ~helpful-callable~ | Only interactive functions |
|
||
| ~describe-function~ | ~helpful-function~ | Only actual functions (including interactive) |
|
||
| ~describe-function~ | ~helpful-macro~ | |
|
||
| ~describe-command~ | ~helpful-command~ | |
|
||
| ~describe-key~ | ~helpful-key~ | |
|
||
| ~describe-variable~ | ~helpful-variable~ | |
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package helpful
|
||
:straight (:build t)
|
||
:after (counsel ivy)
|
||
:custom
|
||
(counsel-describe-function-function #'helpfull-callable)
|
||
(counsel-describe-variable-function #'helpfull-variable)
|
||
:bind
|
||
([remap describe-function] . counsel-describe-function)
|
||
([remap describe-command] . helpful-command)
|
||
([remap describe-variable] . counsel-describe-variable)
|
||
([remap describe-key] . helpful-key))
|
||
#+end_src
|
||
|
||
** Org-mode
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-modedw35fl6184j0
|
||
:END:
|
||
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
|
||
(use-package org
|
||
:straight (org :build t
|
||
:type built-in)
|
||
:defer t
|
||
:commands (orgtbl-mode)
|
||
:hook ((org-mode . visual-line-mode)
|
||
(org-mode . org-num-mode))
|
||
:init
|
||
(auto-fill-mode -1)
|
||
:config
|
||
<<org-hydra-babel>>
|
||
(require 'ox-beamer)
|
||
(setq org-hide-leading-stars nil
|
||
org-hide-macro-markers t
|
||
org-ellipsis " ⤵"
|
||
org-image-actual-width 550
|
||
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-log-done 'time
|
||
org-directory "~/org"
|
||
org-default-notes-file (expand-file-name "notes.org" org-directory))
|
||
<<org-agenda-files>>
|
||
<<org-behavior-electric>>
|
||
<<org-babel-load-languages>>
|
||
<<org-use-sub-superscripts>>
|
||
<<org-latex-compiler>>
|
||
<<org-latex-listings>>
|
||
<<org-latex-default-packages>>
|
||
<<org-export-latex-hyperref-format>>
|
||
<<org-latex-pdf-process>>
|
||
<<org-re-reveal-root>>
|
||
<<org-html-validation>>
|
||
<<org-latex-classes>>
|
||
<<org-publish-projects>>
|
||
:general
|
||
(:states 'normal
|
||
:keymaps 'org-mode-map
|
||
"RET" 'org-open-at-point)
|
||
(:states 'normal
|
||
:prefix ","
|
||
:keymaps 'org-mode-map
|
||
<<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)>>)
|
||
|
||
(:states 'normal
|
||
:keymaps 'org-src-mode-map
|
||
:prefix ","
|
||
"'" #'org-edit-src-exit
|
||
"k" #'org-edit-src-abort))
|
||
#+end_src
|
||
|
||
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.
|
||
#+begin_src emacs-lisp
|
||
(use-package evil-org
|
||
:straight (:build t)
|
||
:after org
|
||
: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)
|
||
(evil-org-agenda-set-keys))
|
||
#+end_src
|
||
|
||
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…
|
||
#+begin_src emacs-lisp
|
||
(use-package conlanging
|
||
:straight (conlanging :build t
|
||
:type git
|
||
:host nil
|
||
:repo "https://labs.phundrak.com/phundrak/conlanging.el")
|
||
:after org
|
||
:defer t)
|
||
#+end_src
|
||
|
||
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
|
||
(use-package org-contrib
|
||
:straight (:build t)
|
||
:init
|
||
(require 'ox-extra)
|
||
(ox-extras-activate '(latex-header-blocks ignore-headlines)))
|
||
#+end_src
|
||
|
||
*** Agenda
|
||
:PROPERTIES:
|
||
:header-args:emacs-lisp: :tangle no :exports code :results silent
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-Agenda8b55fl6184j0
|
||
:END:
|
||
#+name: org-agenda-files
|
||
#+begin_src emacs-lisp
|
||
(setq-default org-agenda-files (list "~/org/agenda" "~/org/notes.org"))
|
||
#+end_src
|
||
|
||
*** 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
|
||
for org files that will be hosted and viewable on Github.
|
||
#+begin_src emacs-lisp
|
||
(use-package toc-org
|
||
:after org
|
||
: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
|
||
(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
|
||
:init
|
||
(add-hook 'org-mode-hook
|
||
(lambda ()
|
||
(add-hook 'before-save-hook
|
||
(lambda ()
|
||
(when (and (eq major-mode 'org-mode)
|
||
(eq buffer-read-only nil))
|
||
(org-unique-id)))))))
|
||
#+end_src
|
||
|
||
*** Babel
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-Babel9585fl6184j0
|
||
:END:
|
||
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
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ob-restclient
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
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 |
|
||
| dot |
|
||
| emacs-lisp |
|
||
| gnuplot |
|
||
| latex |
|
||
| makefile |
|
||
| plantuml |
|
||
| python |
|
||
| sass |
|
||
| shell |
|
||
|
||
#+NAME: org-babel-languages-gen
|
||
#+header: :cache yes :results replace
|
||
#+header: :var languages=org-babel-languages-table[,0]
|
||
#+BEGIN_SRC emacs-lisp :exports none
|
||
(format "'(%s)"
|
||
(mapconcat (lambda ($language)
|
||
(format "(%s . t)" $language))
|
||
languages
|
||
"\n "))
|
||
#+END_SRC
|
||
|
||
#+RESULTS[52f5db378c4060c5ce47e6228e95feefba4fe24d]: org-babel-languages-gen
|
||
#+begin_example
|
||
'((C . t)
|
||
(dot . t)
|
||
(emacs-lisp . t)
|
||
(gnuplot . t)
|
||
(latex . t)
|
||
(latex-as-png . t)
|
||
(makefile . t)
|
||
(plantuml . t)
|
||
(python . t)
|
||
(restclient . t)
|
||
(sass . t)
|
||
(shell . t))
|
||
#+end_example
|
||
|
||
The corresponding code is as follows:
|
||
#+NAME: org-babel-load-languages
|
||
#+BEGIN_SRC emacs-lisp :noweb yes :tangle no
|
||
(org-babel-do-load-languages
|
||
'org-babel-load-languages
|
||
<<org-babel-languages-gen()>>)
|
||
#+END_SRC
|
||
|
||
*** File export
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-File-exportik95fl6184j0
|
||
: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
|
||
#+BEGIN_SRC emacs-lisp :tangle no
|
||
(setq org-use-sub-superscripts (quote {}))
|
||
#+END_SRC
|
||
|
||
|
||
**** 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]].
|
||
#+begin_src emacs-lisp
|
||
(use-package ox-epub
|
||
:after ox
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
**** HTML
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-File-export-HTMLxjc5fl6184j0
|
||
:END:
|
||
For Reveal.JS exports, I need to set where to find the framework by
|
||
default:
|
||
#+NAME: org-re-reveal-root
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq org-re-reveal-root "https://cdn.jsdelivr.net/npm/reveal.js")
|
||
#+END_SRC
|
||
|
||
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
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq org-html-validation-link nil)
|
||
#+END_SRC
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package htmlize
|
||
:defer t)
|
||
#+end_src
|
||
|
||
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.
|
||
#+begin_src emacs-lisp
|
||
(use-package preview-org-html-mode
|
||
:defer t
|
||
:after org
|
||
:straight (preview-org-html-mode :build t
|
||
:type git
|
||
:host github
|
||
:repo "jakebox/preview-org-html-mode")
|
||
:general
|
||
(:keymaps '(org-mode-map)
|
||
:states 'normal
|
||
:prefix ","
|
||
"P" '(:ignore :which-key "preview")
|
||
"Ph" #'preview-org-html-mode
|
||
"Pr" #'preview-org-html-refresh
|
||
"Pp" #'preview-org-html-pop-window-to-frame)
|
||
:config
|
||
(setq preview-org-html-refresh-configuration 'save))
|
||
#+end_src
|
||
|
||
**** LaTeX
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-File-export-LaTeXg2b5fl6184j0
|
||
:END:
|
||
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
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq org-latex-compiler "xelatex")
|
||
#+END_SRC
|
||
|
||
I also want to get by default ~minted~ for LaTeX listings so I can have
|
||
syntax highlights:
|
||
#+NAME: org-latex-listings
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq org-latex-listings 'minted)
|
||
#+END_SRC
|
||
|
||
The default packages break my LaTeX exports: for some reasons, images
|
||
are not loaded and exported in PDFs, so I needed to redifine the
|
||
default packages excluding the one that broke my exports; namely, I
|
||
need to remove ~inputenc~, ~fontenc~ and ~grffile~. I also added some default
|
||
packages:
|
||
- ~minted~ for syntax highlighting
|
||
- ~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
|
||
#+NAME: org-latex-default-packages
|
||
#+BEGIN_SRC emacs-lisp
|
||
(dolist (package '(("AUTO" "inputenc" t ("pdflatex"))
|
||
("T1" "fontenc" t ("pdflatex"))
|
||
("" "grffile" t)))
|
||
(delete package org-latex-default-packages-alist))
|
||
|
||
(dolist (package '(("" "minted")
|
||
("capitalize" "cleveref")
|
||
("" "svg")
|
||
("" "booktabs")
|
||
("" "tabularx")))
|
||
(add-to-list 'org-latex-default-packages-alist package t))
|
||
|
||
(setq org-latex-reference-command "\\cref{%s}")
|
||
#+END_SRC
|
||
|
||
By the way, reference links in LaTeX should be written in this format,
|
||
since we are using ~cleveref~:
|
||
#+NAME: org-export-latex-hyperref-format
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq org-export-latex-hyperref-format "\\ref{%s}")
|
||
#+END_SRC
|
||
|
||
And Minted should be default break lines if a line is too long:
|
||
#+name: org-export-latex-minted-options
|
||
#+begin_src emacs-lisp
|
||
(setq org-latex-minted-options '(("breaklines")
|
||
("tabsize" "2")
|
||
("frame" "single")
|
||
("autogobble")))
|
||
#+end_src
|
||
|
||
When it comes to the export itself, the latex file needs to be
|
||
processed several times through XeLaTeX in order to get some
|
||
references right. Don’t forget to also run bibtex!
|
||
#+NAME: org-latex-pdf-process
|
||
#+BEGIN_SRC emacs-lisp
|
||
(setq org-latex-pdf-process
|
||
'("xelatex -8bit -shell-escape -interaction nonstopmode -output-directory %o %f"
|
||
"bibtex %b"
|
||
"xelatex -8bit -shell-escape -interaction nonstopmode -output-directory %o %f"
|
||
"xelatex -8bit -shell-escape -interaction nonstopmode -output-directory %o %f"))
|
||
#+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:
|
||
#+begin_src emacs-lisp
|
||
(dolist (ext '("bbl" "lot"))
|
||
(add-to-list 'org-latex-logfiles-extensions ext t))
|
||
#+end_src
|
||
|
||
**** Markdown
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-File-export-Markdown-g2vh5vz095j0
|
||
:END:
|
||
There’s not really any unified Markdown specification, meaning
|
||
everyone can pretty much do whatever they want with the syntax and
|
||
still call it Markdown. Great… But something I appreciate is Github
|
||
supports some extra HTML to make our files extra spicy! And lucky me,
|
||
there’s a package for exporting my org files to Github-flavored
|
||
Markdown!
|
||
#+begin_src emacs-lisp
|
||
(use-package ox-gfm
|
||
:after ox
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
**** 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
|
||
(use-package ox-ssh
|
||
:after ox
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
*** Keybindings
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-Keybindingsv0e5fl6184j0
|
||
:END:
|
||
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
|
||
| 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 | |
|
||
| e | org-export-dispatch | |
|
||
| l | org-store-link | |
|
||
| p | org-priority | |
|
||
| r | org-reload | |
|
||
|
||
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
|
||
(defhydra org-babel-transient ()
|
||
"
|
||
^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))
|
||
#+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 | |
|
||
| ie | org-set-effort | |
|
||
| if | org-footnote-new | |
|
||
| ih | org-insert-heading | |
|
||
| 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 |
|
||
| tc | org-table-move-column-left | |
|
||
| tt | org-table-move-row-down | |
|
||
| ts | org-table-move-row-up | |
|
||
| tr | org-table-move-column-right | |
|
||
| ta | org-table-align | |
|
||
| te | org-table-eval-formula | |
|
||
| tf | org-table-field-info | |
|
||
| th | org-table-convert | |
|
||
| tl | org-table-recalculate | |
|
||
| tp | org-plot/gnuplot | |
|
||
| tS | org-table-sort-lines | |
|
||
| tw | org-table-wrap-region | |
|
||
| tx | org-table-shrink | |
|
||
| 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 | |
|
||
|
||
*** LaTeX formats
|
||
:PROPERTIES:
|
||
:header-args:emacs-lisp: :tangle no :exports code :results silent
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-LaTeX-formatszjf5fl6184j0
|
||
: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
|
||
'("conlang"
|
||
"\\documentclass{book}"
|
||
("\\chapter{%s}" . "\\chapter*{%s}")
|
||
("\\section{%s}" . "\\section*{%s}")
|
||
("\\subsection{%s}" . "\\subsection*{%s}")
|
||
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
|
||
#+END_SRC
|
||
|
||
And here is the declaration of the ~beamer~ class:
|
||
#+NAME: org-latex-class-beamer
|
||
#+BEGIN_SRC emacs-lisp
|
||
`("beamer"
|
||
,(concat "\\documentclass[presentation]{beamer}\n"
|
||
"[DEFAULT-PACKAGES]"
|
||
"[PACKAGES]"
|
||
"[EXTRA]\n")
|
||
("\\section{%s}" . "\\section*{%s}")
|
||
("\\subsection{%s}" . "\\subsection*{%s}")
|
||
("\\subsubsection{%s}" . "\\subsubsection*{%s}"))
|
||
#+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
|
||
(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>>)))
|
||
#+END_SRC
|
||
|
||
*** Projects
|
||
:PROPERTIES:
|
||
:header-args:emacs-lisp: :tangle no :exports code :results silent
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-Projectsf2h5fl6184j0
|
||
: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
|
||
#+BEGIN_SRC emacs-lisp :noweb yes
|
||
<<org-proj-config-setup>>
|
||
<<org-proj-lang-setup>>
|
||
(setq org-publish-project-alist
|
||
`(
|
||
<<org-proj-config-html>>
|
||
<<org-proj-config-static>>
|
||
<<org-proj-config>>
|
||
<<org-proj-lang-html>>
|
||
<<org-proj-lang-pdf>>
|
||
<<org-proj-lang-static>>
|
||
<<org-proj-lang>>))
|
||
#+END_SRC
|
||
|
||
**** Configuration website
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-Projects-Configuration-websitelki5fl6184j0
|
||
:END:
|
||
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.
|
||
|
||
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
|
||
(defvar phundrak//projects-config-target
|
||
"/rsync: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 config.phundrak.com")
|
||
(defvar phundrak//projects-config-recursive
|
||
t
|
||
"Defines whether subdirectories should be parsed for config.phundrak.com")
|
||
#+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
|
||
("config-website-org"
|
||
: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)
|
||
#+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
|
||
("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)
|
||
#+END_SRC
|
||
|
||
The project is then defined like so:
|
||
#+NAME: org-proj-config
|
||
#+BEGIN_SRC emacs-lisp
|
||
("config-website"
|
||
:components ("config-website-org"
|
||
"config-website-static"))
|
||
#+END_SRC
|
||
|
||
**** Linguistics website
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-Projects-Linguistics-websitey4k5fl6184j0
|
||
:END:
|
||
My linguistics website is made out of three projects. As for the previous
|
||
project, let’s declare the common values for these.
|
||
#+NAME: org-proj-lang-setup
|
||
#+BEGIN_SRC emacs-lisp
|
||
(defvar phundrak//projects-conlanging-target
|
||
"/rsync:Tilo:~/www/phundrak.com/langue/"
|
||
"Points to where exported files for langue.phundrak.com should be put")
|
||
(defvar phundrak//projects-conlanging-source
|
||
"~/Documents/conlanging/content/"
|
||
"Points to where the sources for langue.phundrak.com are")
|
||
(defvar phundrak//projects-conlanging-language
|
||
"fr"
|
||
"Language of langue.phundrak.com")
|
||
(defvar phundrak//projects-conlanging-recursive
|
||
t
|
||
"Defines whether subdirectories should be parsed for langue.phundrak.com")
|
||
#+END_SRC
|
||
|
||
The first component is the one generating the HTML files from the org files.
|
||
#+NAME: org-proj-lang-html
|
||
#+BEGIN_SRC emacs-lisp
|
||
("langue-phundrak-com-org"
|
||
:base-directory ,phundrak//projects-conlanging-source
|
||
:base-extension "org"
|
||
:exclude "\\./\\(CONTRIB\\|README\\|head\\|temp\\|svg-ink\\).*"
|
||
:publishing-directory ,phundrak//projects-conlanging-target
|
||
:recursive ,phundrak//projects-conlanging-recursive
|
||
:language ,phundrak//projects-conlanging-language
|
||
:publishing-function org-html-publish-to-html
|
||
:headline-levels 5
|
||
:auto-sitemap t
|
||
:auto-preamble t)
|
||
#+END_SRC
|
||
|
||
We also have the component for the LaTeX and PDF part of the website:
|
||
#+NAME: org-proj-lang-pdf
|
||
#+BEGIN_SRC emacs-lisp
|
||
("langue-phundrak-com-pdf"
|
||
:base-directory ,phundrak//projects-conlanging-source
|
||
:base-extension "org"
|
||
:exclude "\\./\\(CONTRIB\\|README\\|index\\|head\\|temp\\|svg-ink\\).*"
|
||
:publishing-directory ,phundrak//projects-conlanging-target
|
||
:recursive ,phundrak//projects-conlanging-recursive
|
||
:language ,phundrak//projects-conlanging-language
|
||
:publishing-function org-latex-publish-to-pdf
|
||
:headline-levels 5
|
||
:auto-preamble t)
|
||
#+END_SRC
|
||
|
||
And lastly, we have the component for all the static files needed to run the
|
||
website:
|
||
#+NAME: org-proj-lang-static
|
||
#+BEGIN_SRC emacs-lisp
|
||
("langue-phundrak-com-static"
|
||
:base-directory ,phundrak//projects-conlanging-source
|
||
:base-extension "png\\|jpg\\|gif\\|webp\\|svg\\|jpeg\\|ttf\\|woff\\|txt\\|epub"
|
||
:publishing-directory ,phundrak//projects-conlanging-target
|
||
:recursive ,phundrak//projects-conlanging-recursive
|
||
:language ,phundrak//projects-conlanging-language
|
||
:publishing-function org-publish-attachment)
|
||
#+END_SRC
|
||
|
||
The project is then defined like so:
|
||
#+NAME: org-proj-lang
|
||
#+BEGIN_SRC emacs-lisp
|
||
("langue-phundrak-com"
|
||
:components ("langue-phundrak-com-org"
|
||
"langue-phundrak-com-static"
|
||
"langue-phundrak-com-pdf"))
|
||
#+END_SRC
|
||
|
||
*** Org-ref and Bibtex configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-org-ref-1h586cd085j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(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
|
||
:straight (:build t)
|
||
:after (org ox-bibtex)
|
||
:demand t
|
||
:custom-face
|
||
(org-ref-cite-face ((t (:weight bold))))
|
||
:init
|
||
(setq org-ref-completion-library 'org-ref-ivy-cite
|
||
org-ref-bibliography-notes "~/org/bibliography/notes.org"
|
||
org-ref-default-bibliography "~/org/bibliography/references.bib"
|
||
org-ref-pdf-directory "~/org/bibliography/bibtex-pdfs/"
|
||
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
|
||
(setq bibtex-completion-pdf-field "file")
|
||
(general-define-key
|
||
:keymaps '(bibtex-mode-map)
|
||
:states 'normal
|
||
"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)
|
||
(general-define-key
|
||
:keymaps '(bibtex-mode-map)
|
||
:states 'normal
|
||
:prefix ","
|
||
;; 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
|
||
|
||
"l" '(:ignore :which-key "lookup")
|
||
"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)
|
||
(general-define-key
|
||
:keymaps '(org-mode-map)
|
||
:states 'normal
|
||
:prefix ","
|
||
"ic" #'org-ref-insert-link))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-bibtex
|
||
:defer t
|
||
:straight (:build t)
|
||
:config
|
||
(setq org-ref-bibliography-notes "~/org/bibliography/notes.org"
|
||
org-ref-default-bibliography "~/org/bibliography/references.bib"
|
||
org-ref-pdf-directory "~/org/bibliography/bibtex-pdfs/"
|
||
bibtex-completion-pdf-open-function #'find-file)
|
||
|
||
(general-define-key
|
||
:keymaps '(bibtex-mode-map)
|
||
:states 'normal
|
||
:prefix "SPC"
|
||
"m" #'ivy-bibtex))
|
||
#+end_src
|
||
|
||
*** Visual Configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Org-mode-Visual-Configurationrol5fl6184j0
|
||
:END:
|
||
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!
|
||
#+begin_src emacs-lisp
|
||
(use-package mixed-pitch
|
||
:after org
|
||
:straight t
|
||
:hook
|
||
(org-mode . mixed-pitch-mode)
|
||
:config
|
||
(add-hook 'org-agenda-mode-hook (lambda () (mixed-pitch-mode -1))))
|
||
#+end_src
|
||
|
||
With this, I also use ~org-pretty-tables~ in order to use some
|
||
capabilities of Unicode in order to make tables nicer to look at.
|
||
#+begin_src emacs-lisp
|
||
(use-package org-pretty-table
|
||
:defer t
|
||
:after org
|
||
:straight (org-pretty-table :type git
|
||
:host github
|
||
:repo "Fuco1/org-pretty-table"
|
||
:build t)
|
||
:hook (org-mode . org-pretty-table-mode)
|
||
:commands (org-pretty-table-mode global-org-pretty-table-mode))
|
||
#+end_src
|
||
|
||
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!
|
||
#+begin_src emacs-lisp
|
||
(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))
|
||
#+end_src
|
||
|
||
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
|
||
(use-package org-fragtog
|
||
:defer t
|
||
:after org
|
||
:straight (:build t)
|
||
:hook (org-mode . org-fragtog-mode))
|
||
#+end_src
|
||
|
||
Tired of seeing lots of actual stars ~*~ in your headers, and you want a
|
||
fancier remplacement? Or you are still using ~org-bullets~ but just
|
||
found out how out-of-date and abandoned it is? (Last commit was on
|
||
September 18th, 2014… damn…) Search no more, ~org-superstar~ will take
|
||
care of that for you!
|
||
#+begin_src emacs-lisp
|
||
(use-package org-superstar
|
||
:after org
|
||
:straight (:build t)
|
||
:hook (org-mode . org-superstar-mode)
|
||
:config
|
||
(setq org-superstar-leading-bullet ?\s
|
||
org-superstar-leading-fallback ?\s
|
||
org-hide-leading-stars nil
|
||
org-superstar-todo-bullet-alist
|
||
'(("TODO" . 9744)
|
||
("[ ]" . 9744)
|
||
("DONE" . 9745)
|
||
("[X]" . 9745))))
|
||
#+end_src
|
||
~org-fancy-priorities~ change the priority of an org element such such
|
||
as ~#A~ to anything user-defined. Let’s make this anything all-the-icons
|
||
icons!
|
||
#+begin_src emacs-lisp
|
||
(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))))
|
||
#+end_src
|
||
/Org Outline Tree/ is a better way of managing my org files’ outline.
|
||
#+begin_src emacs-lisp
|
||
(use-package org-ol-tree
|
||
:defer t
|
||
:after org
|
||
:straight (org-ol-tree :build t
|
||
:host github
|
||
:type git
|
||
:repo "Townk/org-ol-tree")
|
||
:general
|
||
(:keymaps 'org-mode-map
|
||
:states 'normal
|
||
:prefix ","
|
||
"O" #'org-ol-tree))
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
|
||
*** 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
|
||
(use-package org-tree-slide
|
||
:defer t
|
||
:after org
|
||
:straight (:build t)
|
||
:init
|
||
(general-define-key
|
||
:keymaps 'org-mode-map
|
||
:states 'normal
|
||
"<f8>" #'org-tree-slide-mode)
|
||
:config
|
||
(setq org-tree-slide-skip-done nil)
|
||
(general-define-key
|
||
:keymaps 'org-tree-slide-mode-map
|
||
:states 'normal
|
||
:prefix ","
|
||
"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))
|
||
#+end_src
|
||
|
||
** Programming languages
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages6et5fl6184j0
|
||
:END:
|
||
*** Tools
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-Tools-w3q5rsg0k4j0
|
||
:END:
|
||
**** Flycheck
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-Flycheckb446fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(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)
|
||
:after flycheck
|
||
:hook (flycheck-mode . flycheck-popup-tip-mode)
|
||
:config
|
||
(setq flycheck-popup-tip-error-prefix "X ")
|
||
(after! evil
|
||
(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 "))
|
||
#+end_src
|
||
|
||
**** 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
|
||
(use-package lsp-mode
|
||
:defer t
|
||
:straight (:build t)
|
||
:init
|
||
(setq lsp-keymap-prefix "C-c l")
|
||
;; (dolist (hook '(rust-mode-hook
|
||
;; c-mode-hook
|
||
;; c++-mode-hook
|
||
;; css-mode-hook
|
||
;; html-mode-hook
|
||
;; lua-mode-hook
|
||
;; rust-mode-hook
|
||
;; dockerfile-mode-hook))
|
||
;; (add-hook hook #'lsp-deferred))
|
||
|
||
;; (dolist (mode '(#'lsp-enable-which-key-integration
|
||
;; #'lsp-ui-mode))
|
||
;; (add-hook 'lsp-mode-hook mode))
|
||
:hook ((rust-mode . lsp-deferred)
|
||
(c-mode . lsp-deferred)
|
||
(c++-mode . lsp-deferred)
|
||
(css-mode . lsp-deferred)
|
||
(dart-mode . lsp-deferred)
|
||
(html-mode . lsp-deferred)
|
||
(lua-mode . lsp-deferred)
|
||
(rust-mode . lsp-deferred)
|
||
(dockerfile-mode . lsp-deferred)
|
||
(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)
|
||
(lsp-rust-analyzer-server-display-inlay-hints t))
|
||
#+end_src
|
||
|
||
I also want all the visual enhancements LSP can provide.
|
||
#+begin_src emacs-lisp
|
||
(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)
|
||
:config
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps 'lsp-ui-peek-mode-map
|
||
:prefix ","
|
||
"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))
|
||
#+end_src
|
||
|
||
And let’s enable some intergration with ~ivy~.
|
||
#+begin_src emacs-lisp
|
||
(use-package lsp-ivy
|
||
:straight (:build t)
|
||
:defer t
|
||
:after lsp
|
||
:commands lsp-ivy-workspace-symbol)
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package lsp-treemacs
|
||
:defer t
|
||
:straight (:build t)
|
||
:requires treemacs)
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package exec-path-from-shell
|
||
:defer t
|
||
:straight (:build t)
|
||
:init (exec-path-from-shell-initialize))
|
||
#+end_src
|
||
~dap-mode~ is an advanced debugging mode that works through lsp.
|
||
#+begin_src emacs-lisp
|
||
(use-package dap-mode
|
||
:after lsp
|
||
:defer t
|
||
:straight (:build t)
|
||
:config
|
||
(dap-ui-mode)
|
||
(dap-ui-controls-mode 1)
|
||
|
||
(require 'dap-lldb)
|
||
(require 'dap-gdb-lldb)
|
||
|
||
(dap-gdb-lldb-setup)
|
||
(dap-register-debug-template
|
||
"Rust::LLDB Run Configuration"
|
||
(list :type "lldb"
|
||
:request "launch"
|
||
:name "LLDB::Run"
|
||
:gdbpath "rust-lldb"
|
||
:target nil
|
||
:cwd nil)))
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
|
||
*** DSLs
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLsbwu5fl6184j0
|
||
:END:
|
||
DSLs, or /Domain Specific Languages/, are languages dedicated to some
|
||
very tasks, such as configuration languages or non-general programming
|
||
such as SQL.
|
||
|
||
**** Caddy
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Caddy0fw5fl6184j0
|
||
:END:
|
||
[[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?
|
||
|
||
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
|
||
(use-package caddyfile-mode
|
||
:defer t
|
||
:straight (:build t)
|
||
:mode (("Caddyfile\\'" . caddyfile-mode)
|
||
("caddy\\.conf\\'" . caddyfile-mode)))
|
||
#+end_src
|
||
|
||
**** 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
|
||
(use-package cmake-mode
|
||
:defer t
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
|
||
Let’s enable first some autocompletion for it.
|
||
#+begin_src emacs-lisp
|
||
(use-package company-cmake
|
||
:straight (company-cmake :build t
|
||
:type git
|
||
:host github
|
||
:repo "purcell/company-cmake")
|
||
:after cmake-mode
|
||
:defer t)
|
||
#+end_src
|
||
|
||
And let’s also enable a more advanced CMake fontlock.
|
||
#+begin_src emacs-lisp
|
||
(use-package cmake-font-lock
|
||
:defer t
|
||
:after cmake-mode
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
And finally, let’s enable some Eldoc integration for CMake.
|
||
#+begin_src emacs-lisp
|
||
(use-package eldoc-cmake
|
||
:straight (:build t)
|
||
:defer t
|
||
:after cmake-mode)
|
||
#+end_src
|
||
|
||
**** Gnuplot
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Gnuplot8zx5fl6184j0
|
||
:END:
|
||
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
|
||
(use-package gnuplot
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
**** Nginx
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Nginxjiz5fl6184j0
|
||
:END:
|
||
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
|
||
(use-package nginx-mode
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
We then also have an autocompletion package that adds to ~company~ the
|
||
Nginx syntax.
|
||
#+begin_src emacs-lisp
|
||
(use-package company-nginx
|
||
:straight (:build t)
|
||
:defer t
|
||
:config
|
||
(add-hook 'nginx-mode-hook (lambda ()
|
||
(add-to-list 'company-backends #'company-nginx))))
|
||
#+end_src
|
||
|
||
**** Shells
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Shellsn116fl6184j0
|
||
:END:
|
||
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
|
||
(use-package fish-mode
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
**** Toml
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Toml-txu8xvk0k4j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package toml-mode
|
||
:straight (:build t)
|
||
:defer t
|
||
:mode "/\\(Cargo.lock\\|\\.cargo/config\\)\\'")
|
||
#+end_src
|
||
|
||
**** Yaml
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-DSLs-Yamlsk26fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package yaml-mode
|
||
:defer t
|
||
:straight (:build t)
|
||
:mode "\\.yml\\'"
|
||
:mode "\\.yaml\\'")
|
||
#+end_src
|
||
|
||
*** General Programming Languages
|
||
:PROPERTIES:
|
||
: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
|
||
:END:
|
||
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.
|
||
#+begin_src emacs-lisp
|
||
(use-package cc-mode
|
||
:straight (:type built-in)
|
||
:defer t
|
||
:init
|
||
(put 'c-c++-backend 'safe-local-variable 'symbolp)
|
||
:config
|
||
(progn
|
||
(require 'compile)
|
||
(general-define-key
|
||
:keymaps '(c-mode-map c++-mode-map)
|
||
"," nil
|
||
";" nil)
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps '(c-mode-map c++-mode-map)
|
||
:prefix ","
|
||
"l" '(:keymap lsp-command-map :which-key "lsp" :package lsp-mode))
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps '(c-mode-map c++-mode-map)
|
||
"ga" #'projectile-find-other-file
|
||
"gA" #'projectile-find-other-file-other-window)))
|
||
#+end_src
|
||
|
||
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
|
||
(use-package clang-format+
|
||
:straight (:build t)
|
||
:defer t
|
||
:init
|
||
(add-hook 'c-mode-common-hook #'clang-format+-mode))
|
||
#+end_src
|
||
|
||
However, Emacs’ notion of C++ is somewhat outdated, so we need to
|
||
update its fontlock.
|
||
#+begin_src emacs-lisp
|
||
(use-package modern-cpp-font-lock
|
||
:straight (:build t)
|
||
:defer t
|
||
:hook (c++-mode . modern-c++-font-lock-mode))
|
||
#+end_src
|
||
|
||
**** CommonLisp
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-CommonLisp-gc2a7s31q5j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(add-hook 'lisp-mode-hook #'parinfer-rust-mode)
|
||
(add-hook 'lisp-mode-hook (lambda () (smartparens-mode -1)))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package stumpwm-mode
|
||
:straight (:build t)
|
||
:defer t
|
||
:config
|
||
(general-define-key
|
||
:keymaps 'stumpwm-mode-map
|
||
:states 'normal
|
||
:prefix ","
|
||
"e" '(:ignore :which-key "eval")
|
||
"ee" #'stumpwm-eval-last-sexp
|
||
"ed" #'stumpwm-eval-defun
|
||
"er" #'stumpwm-eval-region))
|
||
#+end_src
|
||
|
||
**** Dart
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Dart-xkr3z8j0m6j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package dart-mode
|
||
:straight (:build t)
|
||
:defer t
|
||
:mode "\\.dart\\'")
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package lsp-dart
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
**** EmacsLisp
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-EmacsLispo876fl6184j0
|
||
:END:
|
||
This package displays the function’s arglist or variable’s docstring
|
||
in the echo area at the bottom of the frame. Quite useful indeed.
|
||
#+begin_src emacs-lisp
|
||
(use-package eldoc
|
||
:defer t
|
||
:after company
|
||
:init
|
||
(eldoc-add-command 'company-complete-selection
|
||
'company-complete-common
|
||
'company-capf
|
||
'company-abort))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(add-hook 'emacs-lisp-mode-hook (lambda () (smartparens-mode -1)))
|
||
#+end_src
|
||
|
||
Let’s also declare some Elisp-dedicated keybindings, prefixed by a
|
||
comma.
|
||
#+begin_src emacs-lisp
|
||
(general-define-key
|
||
:states 'motion
|
||
:keymaps 'emacs-lisp-mode-map
|
||
:prefix ","
|
||
|
||
"'" #'ielm
|
||
"c" '(emacs-lisp-byte-compile :which-key "Byte compile")
|
||
|
||
"e" '(nil :which-key "eval")
|
||
"eb" #'eval-buffer
|
||
"ed" #'eval-defun
|
||
"ee" #'eval-last-sexp
|
||
"er" #'eval-region
|
||
|
||
"h" '(nil :which-key "help")
|
||
"hh" #'helpful-at-point
|
||
|
||
"t" '(nil :wk "toggle")
|
||
"tP" '(nil :wk "parinfer")
|
||
"tPs" #'parinfer-rust-switch-mode
|
||
"tPd" #'parinfer-rust-mode-disable
|
||
"tPp" #'parinfer-rust-toggle-paren-mode)
|
||
#+end_src
|
||
|
||
**** Lua
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Lua-p2odc7p0t4j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package lua-mode
|
||
:defer t
|
||
:straight (:build t)
|
||
:mode "\\.lua$"
|
||
:interpreter "lua"
|
||
:init
|
||
(setq lua-indent-level 2
|
||
lua-indent-string-contents t))
|
||
;; (general-define-key
|
||
;; :keymaps lua-mode-map
|
||
;; :states 'normal
|
||
;; :prefix ","
|
||
;; "'" #'lua-show-process-buffer
|
||
;; "h" '(:ignore :wk "help")
|
||
;; "hd" #'lua-search-documentation
|
||
;; "s" '(:ignore :wk "REPL")
|
||
;; "sb" #'lua-send-buffer
|
||
;; "sf" #'lua-send-defun
|
||
;; "sl" #'lua-send-current-line
|
||
;; "sr" #'lua-send-region))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package lsp-lua-emmy
|
||
:defer t
|
||
:after (lua-mode lsp-mode)
|
||
:straight (lsp-lua-emmy :build t
|
||
:type git
|
||
:host github
|
||
:repo "EmmyLua/EmmyLua-LanguageServer")
|
||
:hook (lua-mode . lsp-deferred)
|
||
:config
|
||
(setq lsp-lua-emmy-jar-path (expand-file-name "EmmyLua-LS-all.jar" user-emacs-directory)))
|
||
|
||
#+end_src
|
||
|
||
**** Python
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Python-7mwd2yq0z6j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package python
|
||
:defer t
|
||
:straight (:build t)
|
||
: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")
|
||
(string= python-shell-interpreter "python"))
|
||
(setq python-shell-interpreter "python3")))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(after! org
|
||
(add-to-list 'org-babel-load-languages '(python . t)))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(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")
|
||
(general-define-key
|
||
:states 'normal
|
||
:prefix ","
|
||
:keymaps 'python-mode-map
|
||
"t" '(:ignore :which-key "test")
|
||
"ta" #'python-pytest
|
||
"tf" #'python-pytest-file-dwim
|
||
"tF" #'python-pytest-file
|
||
"tt" #'python-pytest-function-dwim
|
||
"tT" #'python-pytest-function
|
||
"tr" #'python-pytest-repeat
|
||
"tp" #'python-pytest-dispatch))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(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))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package pip-requirements
|
||
:defer t
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(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)
|
||
:config
|
||
(general-define-key
|
||
:states 'normal
|
||
:prefix ","
|
||
:keymaps 'python-mode-map
|
||
"e" '(:ignore :which-key "pipenv")
|
||
"ea" #'pipenv-activate
|
||
"ed" #'pipenv-deactivate
|
||
"ei" #'pipenv-install
|
||
"el" #'pipenv-lock
|
||
"eo" #'pipenv-open
|
||
"er" #'pipenv-run
|
||
"es" #'pipenv-shell
|
||
"eu" #'pipenv-uninstall))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(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))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package pyenv-mode
|
||
:defer t
|
||
:after python
|
||
:straight (:build t)
|
||
:if (executable-find "pyenv")
|
||
:commands (pyenv-mode-versions)
|
||
:config
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps 'python-mode-map
|
||
:prefix ","
|
||
"vu" #'pyenv-mode-unset
|
||
"vs" #'pyenv-mode-set))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package pippel
|
||
:defer t
|
||
:straight (:build t)
|
||
:init
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps 'python-mode-map
|
||
:prefix ","
|
||
"P" #'pippel-list-packages))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package pyimport
|
||
:defer t
|
||
:straight (:build t)
|
||
:config
|
||
(general-define-key
|
||
:states 'normal
|
||
:prefix ","
|
||
:keymaps 'python-mode-map
|
||
"i" '(:ignore :which-key "imports")
|
||
"ii" #'pyimport-insert-missing
|
||
"ir" #'pyimport-remove-unused))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package py-isort
|
||
:defer t
|
||
:straight (:build t)
|
||
:config
|
||
(general-define-key
|
||
:prefix ","
|
||
:states 'normal
|
||
:keymaps 'python-mode-map
|
||
"i" '(:ignore :which-key "imports")
|
||
"is" #'py-isort-buffer
|
||
"iR" #'py-isort-region))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package counsel-pydoc
|
||
:defer t
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package sphinx-doc
|
||
:defer t
|
||
:straight (:build t)
|
||
:init
|
||
(add-hook 'python-mode-hook #'sphinx-doc-mode)
|
||
(general-define-key
|
||
:states 'normal
|
||
:keymaps 'python-mode-map
|
||
:prefix ","
|
||
"S" '(:ignore :which-key "sphinx-doc")
|
||
"Se" #'sphinx-doc-mode
|
||
"Sd" #'sphinx-doc))
|
||
#+end_src
|
||
|
||
#+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")
|
||
(general-define-key
|
||
:prefix ","
|
||
:states 'normal
|
||
:keymaps 'cython-mode-map
|
||
"c" '(:ignore :which-key "cython")
|
||
"cc" #'cython-compile))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package flycheck-cython
|
||
:defer t
|
||
:straight (:build t)
|
||
:after cython-mode)
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package blacken
|
||
:defer t
|
||
:straight (:build t)
|
||
:init
|
||
(add-hook 'python-mode-hook #'blacken-mode))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package lsp-pyright
|
||
:after lsp-mode
|
||
:defer t
|
||
:straight (:buidl t))
|
||
#+end_src
|
||
|
||
**** 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
|
||
(use-package rustic
|
||
:defer t
|
||
:straight (:build t)
|
||
:mode ("\\.rs$" . rustic-mode)
|
||
:init
|
||
(after! org-src
|
||
(defalias 'org-babel-execute:rust #'org-babel-execute:rustic)
|
||
(add-to-list 'org-src-lang-modes '("rust" . rustic)))
|
||
:general
|
||
(:keymaps 'rustic-mode-map
|
||
"M-t" #'lsp-ui-imenu
|
||
"M-?" #'lsp-find-references)
|
||
(:keymaps 'rustic-mode-map
|
||
:states 'normal
|
||
:prefix ","
|
||
"b" '(:ignore :which-key "build")
|
||
"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
|
||
"l" '(:ignore :which-key "lsp")
|
||
"la" #'lsp-execute-code-action
|
||
"lr" #'lsp-rename
|
||
"lq" #'lsp-workspace-restart
|
||
"lQ" #'lsp-workspace-shutdown
|
||
"ls" #'lsp-rust-analyzer-status
|
||
"t" '(:ignore :which-key "cargo test")
|
||
"ta" #'rustic-cargo-test
|
||
"tt" #'rustic-cargo-current-test)
|
||
:config
|
||
(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)
|
||
(remove-hook 'rustic-mode-hook #'rustic-setup-lsp)
|
||
(add-hook 'rustic-mode-local-vars-hook #'rustic-setup-lsp)
|
||
(setq rustic-lsp-client 'lsp-mode))
|
||
#+end_src
|
||
|
||
#+RESULTS:
|
||
|
||
**** Web programming
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Web-programming-7ca40po085j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package company-web
|
||
:defer t
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(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
|
||
"C-RET" #'emmet-expand-yas))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package impatient-mode
|
||
:straight (:build t)
|
||
:defer t)
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package slim-mode
|
||
:defer t
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package web-mode
|
||
:defer t
|
||
:straight (:build t)
|
||
:hook ((html-mode . web-mode))
|
||
: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)
|
||
("\\.djhtml\\'" . web-mode))
|
||
:config
|
||
(general-define-key
|
||
:states 'normal
|
||
:prefix ","
|
||
:keymaps 'web-mode-map
|
||
"=" '(nil :which-key "format")
|
||
"E" '(nil :which-key "errors")
|
||
"El" #'web-mode-dom-errors-show
|
||
"gb" #'web-mode-element-beginning
|
||
"g" '(nil :which-key "goto")
|
||
"gc" #'web-mode-element-child
|
||
"gp" #'web-mode-element-parent
|
||
"gs" #'web-mode-element-sibling-next
|
||
"h" '(nil :which-key "dom")
|
||
"hp" #'web-mode-dom-xpath
|
||
"r" '(nil :which-key "refactor")
|
||
"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
|
||
"z" #'web-mode-fold-or-unfold))
|
||
#+end_src
|
||
|
||
***** Javascript
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Web-programming-Javascript-8k5arup085j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package prettier-js
|
||
:defer t
|
||
:straight (:build t))
|
||
#+end_src
|
||
|
||
***** CSS
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Programming-languages-General-Programming-Languages-Web-programming-CSS-que40po085j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(add-hook 'css-mode-hook #'smartparens-mode)
|
||
(put 'css-indent-offset 'safe-local-variable #'integerp)
|
||
(after! css-mode
|
||
(general-define-key
|
||
:keymaps '(css-mode-map)
|
||
:states 'normal
|
||
:prefix ","
|
||
"=" '(:ignore :wk "format")
|
||
"g" '(:ignore :wk "goto")))
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(use-package scss-mode
|
||
:straight (:build t)
|
||
:hook (scss-mode . smartparens-mode)
|
||
:defer t
|
||
:mode "\\.scss\\'")
|
||
#+end_src
|
||
|
||
#+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)
|
||
(general-define-key
|
||
:keymaps mode-map
|
||
:states 'normal
|
||
:prefix ","
|
||
"gh" #'counsel-css)))
|
||
#+end_src
|
||
|
||
** Visual Configuration
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Visual-Configurationxr86fl6184j0
|
||
:END:
|
||
*** Dashboard
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Dashboardnba6fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(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)))))))
|
||
|
||
(setq dashboard-items '((recents . 15)
|
||
(projects . 10)))
|
||
(dashboard-setup-startup-hook)
|
||
:init
|
||
(add-hook 'after-init-hook 'dashboard-refresh-buffer))
|
||
#+end_src
|
||
|
||
*** 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
|
||
(use-package git-gutter-fringe
|
||
:straight (:build t)
|
||
:hook ((prog-mode . git-gutter-mode)
|
||
(org-mode . git-gutter-mode)
|
||
(markdown-mode . git-gutter-mode)
|
||
(latex-mode . git-gutter-mode)))
|
||
#+end_src
|
||
|
||
*** Modeline
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Modelineavb6fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package doom-modeline
|
||
:straight (:build t)
|
||
:defer t
|
||
:init (doom-modeline-mode 1)
|
||
:custom ((doom-modeline-height 15)))
|
||
#+end_src
|
||
|
||
*** Theme
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Themeded6fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package doom-themes
|
||
:straight (:build t)
|
||
:defer t
|
||
:init (load-theme 'doom-nord t))
|
||
#+end_src
|
||
|
||
*** Icons? Did someone say icons?
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Icons-Did-someone-say-iconsfye6fl6184j0
|
||
:END:
|
||
/*YES! ALL OF THEM!*/
|
||
|
||
Ahem…
|
||
|
||
The package ~all-the-icons~ allows us to use a wide variety of icons in
|
||
Emacs for various purposes, wherever we want, and /THAT/ is *GREAT*! I’ll
|
||
(ab)use this feature in my config, be warned! *NOTE*: The first time a
|
||
configuration with ~all-the-icons~ is loaded on a machine, the needed
|
||
fonts might not be available, so you’ll need to install them with the
|
||
command ~M-x all-the-icons-install-fonts~.
|
||
#+begin_src emacs-lisp
|
||
(use-package all-the-icons
|
||
:defer t)
|
||
#+end_src
|
||
~prettify-symbols-mode~ is also a nifty feature of Emacs, and it is
|
||
built-in! With that, I can replace strings of my choice by another
|
||
character of my choice!
|
||
#+begin_src emacs-lisp
|
||
(dolist (symbol '(("lambda" . 955)
|
||
("mapc" . 8614)))
|
||
(add-to-list 'prettify-symbols-alist symbol))
|
||
#+end_src
|
||
|
||
Let’s enable this mode for any programming mode:
|
||
#+begin_src emacs-lisp
|
||
(add-hook 'emacs-lisp-mode-hook #'prettify-symbols-mode)
|
||
#+end_src
|
||
|
||
*** Rainbow Delimiters
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Rainbow-Delimiters3lg6fl6184j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package rainbow-delimiters
|
||
:straight (:build t)
|
||
:defer t
|
||
:hook (prog-mode . rainbow-delimiters-mode))
|
||
#+end_src
|
||
|
||
*** Y’all want some more /COLORS/?
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Visual-Configuration-Y-all-want-some-more-COLORSs6i6fl6184j0
|
||
:END:
|
||
It is possible to make info buffers much more colorful (and imo easier
|
||
to read) with this simple package:
|
||
#+begin_src emacs-lisp
|
||
(use-package info-colors
|
||
:straight (:build t)
|
||
:commands info-colors-fnontify-node
|
||
:hook (Info-selection . info-colors-fontify-node)
|
||
:hook (Info-mode . mixed-pitch-mode))
|
||
#+end_src
|
||
|
||
** Misc
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Misc0sj6fl6184j0
|
||
:END:
|
||
*** 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
|
||
(use-package archwiki
|
||
:defer t
|
||
:straight (archwiki :build t
|
||
:type git
|
||
:host nil
|
||
:repo "https://labs.phundrak.com/phundrak/archwiki.el"))
|
||
#+end_src
|
||
|
||
*** ~avy~
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Misc-avyral6fl6184j0
|
||
:END:
|
||
~avy~ is a really convenient way of jumping around, but I’ll need some
|
||
configuration to make it bépo-compatible.
|
||
#+begin_src emacs-lisp
|
||
(use-package avy
|
||
:defer t
|
||
:config
|
||
(setq avy-keys '(?a ?u ?i ?e ?c ?t ?s ?r ?n))
|
||
:general
|
||
(:states 'normal
|
||
"gl" #'avy-goto-line))
|
||
#+end_src
|
||
|
||
*** Calc
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Misc-Calc3vm6fl6184j0
|
||
:END:
|
||
Let’s give ~calc-mode~ some better defaults.
|
||
#+begin_src emacs-lisp
|
||
(setq calc-angle-mode 'rad
|
||
calc-symbolic-mode t)
|
||
#+end_src
|
||
|
||
*** Elcord
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Misc-Elcord7eo6fl6184j0
|
||
:END:
|
||
What’s the point of using Emacs if you can’t tell everyone?
|
||
#+begin_src emacs-lisp
|
||
(use-package elcord
|
||
:straight (:built t)
|
||
:defer t
|
||
:config
|
||
(setq elcord-use-major-mode-as-main-icon t
|
||
elcord-refresh-rate 5
|
||
elcord-display-elapsed nil))
|
||
#+end_src
|
||
|
||
*** ~ivy-quick-find-files.el~
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Misc-ivy-quick-find-files-el2yp6fl6184j0
|
||
:END:
|
||
This package is a small utility package I’ve written in order to
|
||
quickly find files across my filesystem.
|
||
#+begin_src emacs-lisp
|
||
(use-package ivy-quick-find-files
|
||
:defer t
|
||
:straight (ivy-quick-find-files :type git
|
||
:host github
|
||
:repo "phundrak/ivy-quick-find-files.el"
|
||
:build t)
|
||
:config
|
||
(setq ivy-quick-find-files-program 'fd
|
||
ivy-quick-find-files-dirs-and-exts '(("~/org" . "org")
|
||
("~/Documents/conlanging" . "org")
|
||
("~/Documents/university" . "org"))))
|
||
#+end_src
|
||
|
||
*** Keycast
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Misc-Keycast-nsqgl431t4j0
|
||
:END:
|
||
#+begin_src emacs-lisp
|
||
(use-package keycast
|
||
:config
|
||
(define-minor-mode keycast-mode
|
||
"Show current command and its key binding in the mode line."
|
||
:global t
|
||
(if keycast-mode
|
||
(add-hook 'pre-command-hook 'keycast--update t)
|
||
(remove-hook 'pre-command-hook 'keycast--update)))
|
||
(add-to-list 'global-mode-string '("" mode-line-keycast " ")))
|
||
#+end_src
|
||
|
||
*** 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
|
||
(use-package sicp
|
||
:defer t)
|
||
#+end_src
|
||
|
||
*** Winum
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Packages-Configuration-Misc-Winumvir6fl6184j0
|
||
:END:
|
||
Winum allows Emacs to associate windows with a specific number and
|
||
navigate through these windows by directly refering to their
|
||
associated number! This allows for faster window configuration than
|
||
just going to the frame above, then left, left, and up.
|
||
#+begin_src emacs-lisp
|
||
(use-package winum
|
||
:straight (:build t)
|
||
:init (winum-mode))
|
||
#+end_src
|
||
|
||
*** Ytplay
|
||
: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
|
||
(use-package ytplay
|
||
:defer t
|
||
:straight (ytplay :build t
|
||
:type git
|
||
:host nil
|
||
:repo "https://labs.phundrak.com/phundrak/ytplay.el"))
|
||
#+end_src
|
||
|
||
* Keybindings
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Keybindings3ps6fl6184j0
|
||
:END:
|
||
Undefining some stuff to make keybind prefixes work correctly.
|
||
#+begin_src emacs-lisp
|
||
(general-define-key
|
||
:keymaps '(backtrace-mode-map diff-minor-mode-map magit-mode-map
|
||
rmail-mode-map evil-motion-state-map dired-mode-map
|
||
epa-key-list-mode-map special-mode-map splash-screen-keymap
|
||
undo-tree-visualizer-mode-map magit-blame-read-only-mode-map
|
||
org-agenda-keymap org-agenda-mode-map git-rebase-mode-map
|
||
Buffer-menu-mode-map custom-mode-map gfm-view-mode-map
|
||
electric-help-map image-mode-map magit-diff-mode-map)
|
||
"SPC" nil)
|
||
|
||
(general-define-key
|
||
:keymaps 'global-map
|
||
"<mouse-2>" nil
|
||
"<mouse-3>" nil)
|
||
|
||
(general-define-key
|
||
:keymaps 'evil-motion-state-map
|
||
"," nil)
|
||
|
||
(general-define-key
|
||
:keymaps 'evil-insert-state-map
|
||
"C-t" nil)
|
||
|
||
(general-define-key
|
||
:keymaps '(diff-mode-map help-mode-map image-mode-map
|
||
dired-mode-map Man-mode-map eww-mode-map magit-mode-map
|
||
debugger-mode-map dired-mode-map custom-mode-map
|
||
eshell-mode-map)
|
||
:states 'normal
|
||
"SPC" nil)
|
||
|
||
(general-define-key
|
||
:keymaps 'magit-mode-map
|
||
:states 'visual
|
||
"SPC" nil)
|
||
|
||
(general-define-key
|
||
:keymaps '(diff-mode-map org-agenda-keymap org-agenda-mode-map)
|
||
:states 'motion
|
||
"SPC" nil)
|
||
|
||
(general-define-key
|
||
:keymaps 'eshell-mode-map
|
||
:states 'normal
|
||
"c" #'evil-backward-char
|
||
"t" #'evil-next-line
|
||
"s" #'evil-previous-line
|
||
"r" #'evil-forward-char)
|
||
|
||
(general-define-key
|
||
:keymaps 'evil-insert-state-map
|
||
"U" nil
|
||
"C-a" nil
|
||
"C-y" nil
|
||
"C-e" nil)
|
||
|
||
(general-define-key
|
||
:states 'normal
|
||
"U" #'evil-redo
|
||
"C-a" #'beginning-of-line
|
||
"C-e" #'end-of-line
|
||
"C-y" #'yank)
|
||
#+end_src
|
||
|
||
#+begin_src emacs-lisp
|
||
(general-define-key
|
||
:states 'normal
|
||
:prefix "SPC"
|
||
"SPC" '(counsel-M-x :wk "M-x")
|
||
"'" #'shell-pop
|
||
|
||
"a" '(nil :wk "apps")
|
||
"ac" #'calc
|
||
"ad" #'docker
|
||
"ae" #'eww
|
||
"at" #'tetris
|
||
"aw" #'wttrin
|
||
"aC" #'calendar
|
||
|
||
"as" '(nil :wk "shells")
|
||
"ase" #'eshell-new
|
||
"asv" #'vterm
|
||
|
||
"b" '(nil :wk "buffers")
|
||
"bb" #'bufler-switch-buffer
|
||
"bB" #'bury-buffer
|
||
"bl" #'bufler
|
||
"bd" #'kill-this-buffer
|
||
"bD" #'kill-buffer
|
||
"bh" #'dashboard-refresh-buffer
|
||
"bm" #'switch-to-messages-buffer
|
||
"br" #'counsel-buffer-or-recentf
|
||
"bs" #'switch-to-scratch-buffer
|
||
|
||
"c" '(nil :wk "code")
|
||
"cl" #'evilnc-comment-or-uncomment-lines
|
||
|
||
"e" '(nil :wk "email")
|
||
"ec" #'mu4e-compose-new
|
||
"em" #'mu4e
|
||
|
||
"f" '(nil :wk "files")
|
||
"fc" '((lambda ()
|
||
(interactive)
|
||
(find-file (concat (getenv "HOME") "/org/config/emacs.org")))
|
||
:wk "Config file")
|
||
"ff" #'counsel-find-file
|
||
"fF" #'ivy-quick-find-files
|
||
"fh" #'hexl-find-file
|
||
"fi" '((lambda ()
|
||
(interactive)
|
||
(find-file (concat user-emacs-directory "init.el")))
|
||
:which-key "init.el")
|
||
"fr" #'counsel-recentf
|
||
"fs" #'save-buffer
|
||
|
||
"h" '(nil :wk "help")
|
||
"hk" #'which-key-show-top-level
|
||
"hd" '(nil :wk "describe")
|
||
"hdc" #'describe-char
|
||
"hdC" #'helpful-command
|
||
"hdf" #'helpful-callable
|
||
"hdk" #'helpful-key
|
||
"hdm" #'helpful-macro
|
||
"hdM" #'helpful-mode
|
||
"hds" #'helpful-symbol
|
||
"hdv" #'helpful-variable
|
||
|
||
"i" '(nil :wk "insert")
|
||
"iy" #'ivy-yasnippet
|
||
|
||
"j" '(nil :wk "jump")
|
||
"jd" #'dired-jump
|
||
"jD" #'dired-jump-other-window
|
||
|
||
"p" '(nil :wk "project")
|
||
"p!" #'projectile-run-shell-command-in-root
|
||
"p&" #'projectile-run-async-shell-command-in-root
|
||
"pb" #'counsel-projectile-switch-to-buffer
|
||
"pc" #'counsel-projectile
|
||
"pd" #'counsel-projectile-find-dir
|
||
"pe" #'projectile-edit-dir-locals
|
||
"pf" #'counsel-projectile-find-file
|
||
"pg" #'projectile-find-tag
|
||
"pk" #'project-kill-buffers
|
||
"pp" #'counsel-projectile-switch-project
|
||
"pt" #'ivy-magit-todos
|
||
"pv" #'projectile-vc
|
||
|
||
"t" '(nil :wk "toggles")
|
||
"tt" #'counsel-load-theme
|
||
"ti" '(nil :wk "input method")
|
||
"tit" #'toggle-input-method
|
||
"tis" #'set-input-mode
|
||
|
||
"u" #'universal-argument
|
||
"U" #'undo-tree-visualize
|
||
|
||
"w" '(nil :wk "windows")
|
||
"w." #'windows-adjust-size/body
|
||
"w-" #'split-window-below-and-focus
|
||
"w/" #'split-window-right-and-focus
|
||
"w$" #'winum-select-window-by-number
|
||
"w0" '(winum-select-window-0-or-10 :wk nil)
|
||
"w1" '(winum-select-window-1 :wk nil)
|
||
"w2" '(winum-select-window-2 :wk nil)
|
||
"w3" '(winum-select-window-3 :wk nil)
|
||
"w4" '(winum-select-window-4 :wk nil)
|
||
"w5" '(winum-select-window-5 :wk nil)
|
||
"w6" '(winum-select-window-6 :wk nil)
|
||
"w7" '(winum-select-window-7 :wk nil)
|
||
"w8" '(winum-select-window-8 :wk nil)
|
||
"w9" '(winum-select-window-9 :wk nil)
|
||
|
||
"wb" '((lambda ()
|
||
(interactive)
|
||
(progn
|
||
(kill-this-buffer)
|
||
(delete-window)))
|
||
:wk "Kill buffer and window")
|
||
"wd" #'delete-window
|
||
"wo" #'other-window
|
||
"wD" #'delete-other-windows
|
||
"ww" '(nil :wk "writeroom")
|
||
"ww." #'writeroom-buffer-width/body
|
||
"www" #'writeroom-mode
|
||
|
||
"wc" #'evil-window-left
|
||
"wt" #'evil-window-down
|
||
"ws" #'evil-window-up
|
||
"wr" #'evil-window-right
|
||
|
||
"T" '(nil :wk "text")
|
||
"Tz" #'hydra-zoom/body
|
||
"Tu" #'downcase-region
|
||
"TU" #'upcase-region
|
||
"Te" #'string-edit-at-point
|
||
|
||
"q" '(nil :wk "quit")
|
||
"qf" #'delete-frame
|
||
"qq" #'save-buffers-kill-terminal
|
||
"qQ" #'kill-emacs)
|
||
#+end_src
|
||
|
||
* Various TODOs :noexport:
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Various-TODOsnwt6fl6184j0
|
||
:END:
|
||
** TODO advise ~evil-insert~ in eshell
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Various-TODOs-advise-evil-insert-in-eshellc4v6fl6184j0
|
||
:END:
|
||
Advise ~evil-insert~ to go to the end of the buffer while in
|
||
~eshell-mode~.
|
||
** TODO Write macro wrapper around ~general~
|
||
:PROPERTIES:
|
||
:CUSTOM_ID: Various-TODOs-Write-macro-wrapper-around-generalfew6fl6184j0
|
||
:END:
|
||
Write a macro wrapper around ~general~ for when an evil state is used in
|
||
order to make the keybind available when in ~insert-mode~ through ~M-m~.
|