[Misc] switching to new repo for org files
This commit is contained in:
377
docs/emacs/basic-config.org
Normal file
377
docs/emacs/basic-config.org
Normal file
@@ -0,0 +1,377 @@
|
||||
#+title: Emacs — Basic Configuration
|
||||
#+setupfile: ../headers
|
||||
#+property: header-args:emacs-lisp :mkdirp yes :lexical t :exports code
|
||||
#+property: header-args:emacs-lisp+ :tangle ~/.config/emacs/lisp/basic-config.el
|
||||
#+property: header-args:emacs-lisp+ :mkdirp yes :noweb no-export
|
||||
|
||||
* Basic Configuration
|
||||
** Early Init
|
||||
:PROPERTIES:
|
||||
:header-args:emacs-lisp: :tangle ~/.config/emacs/early-init.el :mkdirp yes
|
||||
:header-args:emacs-lisp+: :exports code :results silent :lexical t
|
||||
:END:
|
||||
The early init file is the file loaded before anything else in
|
||||
Emacs. This is where I put some options in order to disable as quickly
|
||||
as possible some built-in features of Emacs before they can be even
|
||||
loaded, speeding Emacs up a bit.
|
||||
#+begin_src emacs-lisp :mkdirp yes
|
||||
(setq package-enable-at-startup nil
|
||||
inhibit-startup-message t
|
||||
frame-resize-pixelwise t ; fine resize
|
||||
package-native-compile t) ; native compile packages
|
||||
(scroll-bar-mode -1) ; disable scrollbar
|
||||
(tool-bar-mode -1) ; disable toolbar
|
||||
(tooltip-mode -1) ; disable tooltips
|
||||
(set-fringe-mode 10) ; give some breathing room
|
||||
(menu-bar-mode -1) ; disable menubar
|
||||
(blink-cursor-mode 0) ; disable blinking cursor
|
||||
(setq gc-cons-threshold (* 1024 1024 1024))
|
||||
#+end_src
|
||||
|
||||
** Emacs Behavior
|
||||
*** Editing Text in Emacs
|
||||
I *never* want to keep trailing spaces in my files, which is why 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
|
||||
Emacs usually considers a word can be understood as several words, as
|
||||
in camelCase words, and allows us to jump words on this finer level.
|
||||
#+begin_src emacs-lisp
|
||||
(global-subword-mode 1)
|
||||
#+end_src
|
||||
|
||||
Changing half my screen each time my cursor goes too high or too low
|
||||
is not exactly ideal. Fortunately, if we set ~scroll-conservatively~
|
||||
high enough we can have the cursor stay on top or at the bottom of the
|
||||
screen while the text scrolls progressively.
|
||||
#+begin_src emacs-lisp
|
||||
(setq scroll-conservatively 1000)
|
||||
#+end_src
|
||||
|
||||
Lastly, I want the default mode for Emacs to be Emacs Lisp.
|
||||
#+begin_src emacs-lisp
|
||||
(setq-default initial-major-mode 'emacs-lisp-mode)
|
||||
#+end_src
|
||||
|
||||
**** Indentation
|
||||
I 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 tangent 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 anyway, so
|
||||
I’ll stick with spaces by default and change it where needed.
|
||||
|
||||
*** Programming Modes
|
||||
First off, my definition of what makes 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
|
||||
#+header: :cache yes :exports none :tangle no
|
||||
#+begin_src emacs-lisp :var modes=line-number-modes-table
|
||||
(mapconcat (lambda (mode) (format "%s-hook" (car mode)))
|
||||
modes
|
||||
" ")
|
||||
#+end_src
|
||||
|
||||
**** Line Number
|
||||
Since version 26, Emacs has a built-in capacity of displaying line
|
||||
numbers on the left-side of the buffer. This is a fantastic feature
|
||||
that should actually be the default for all programming modes.
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(dolist (mode '(<<prog-modes-gen()>>))
|
||||
(add-hook mode #'display-line-numbers-mode))
|
||||
#+end_src
|
||||
|
||||
**** Folding code
|
||||
Most programming languages can usually have their code folded, be it
|
||||
code between curly braces, chunks of comments or code on another level
|
||||
of indentation (Python, why…?). The minor-mode that enables that is
|
||||
~hs-minor-mode~, 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!
|
||||
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 access.
|
||||
#+begin_src emacs-lisp
|
||||
(setq backup-directory-alist `(("." . ,(expand-file-name ".tmp/backups/"
|
||||
user-emacs-directory))))
|
||||
#+end_src
|
||||
|
||||
It also loves to litter its ~init.el~ with custom variables here and
|
||||
there, but the thing is: I regenerate my ~init.el~ each time I tangle
|
||||
this file! How can I keep Emacs from adding stuff that will be almost
|
||||
immediately lost? Did someone say /custom file/?
|
||||
#+begin_src emacs-lisp
|
||||
(setq-default custom-file (expand-file-name ".custom.el" user-emacs-directory))
|
||||
(when (file-exists-p custom-file) ; 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!
|
||||
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
|
||||
|
||||
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
|
||||
Let’s raise Emacs undo memory to 10 MB, and make Emacs auto-save our
|
||||
files by default.
|
||||
#+begin_src emacs-lisp
|
||||
(setq undo-limit 100000000
|
||||
auto-save-default t)
|
||||
#+end_src
|
||||
|
||||
#+begin_src emacs-lisp
|
||||
(setq window-combination-resize t) ; take new window space from all other windows
|
||||
#+end_src
|
||||
|
||||
** Personal Information
|
||||
Emacs needs to know its master! For various reasons by the way, some
|
||||
packages rely on these variables to know who it is talking to or
|
||||
dealing with, such as ~mu4e~ which will guess who you are if you 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
|
||||
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
|
||||
(with-eval-after-load 'mule-util
|
||||
(setq truncate-string-ellipsis "…"))
|
||||
#+end_src
|
||||
|
||||
With Emacs 29.0.50 onwards, a new frame parameter exists:
|
||||
~alpha-background~. Unlike ~alpha~, this frame parameter only makes Emacs’
|
||||
background transparent, excluding images and text.
|
||||
#+begin_src emacs-lisp
|
||||
(add-to-list 'default-frame-alist '(alpha-background . 0.9))
|
||||
#+end_src
|
||||
|
||||
*** Modeline Modules
|
||||
I sometimes use Emacs in fullscreen, meaning my usual taskbar will be
|
||||
hidden. This is why I want the current date and time to be displayed,
|
||||
in an ISO-8601 style, although not exactly ISO-8601 (this is the best
|
||||
time format, fight me).
|
||||
#+begin_src emacs-lisp
|
||||
(require 'time)
|
||||
(setq display-time-format "%Y-%m-%d %H:%M")
|
||||
(display-time-mode 1) ; display time in modeline
|
||||
#+end_src
|
||||
|
||||
Something my taskbar 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
|
||||
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.")
|
||||
|
||||
(defvar phundrak/default-font-name "Cascadia Code"
|
||||
"Default font.")
|
||||
|
||||
(defun my/set-font ()
|
||||
(when (find-font (font-spec :name phundrak/default-font-name))
|
||||
(set-face-attribute 'default nil
|
||||
:font phundrak/default-font-name
|
||||
:height phundrak/default-font-size)))
|
||||
|
||||
(my/set-font)
|
||||
(add-hook 'server-after-make-frame-hook #'my/set-font)
|
||||
#+end_src
|
||||
|
||||
*** Frame Title
|
||||
This is straight-up copied from [[https://tecosaur.github.io/emacs-config/config.html#window-title][TEC]]’s configuration. See their comment
|
||||
on the matter.
|
||||
#+begin_src emacs-lisp
|
||||
(setq frame-title-format
|
||||
'(""
|
||||
"%b"
|
||||
(:eval
|
||||
(let ((project-name (projectile-project-name)))
|
||||
(unless (string= "-" project-name)
|
||||
(format (if (buffer-modified-p) " ◉ %s" " ● %s - Emacs") project-name))))))
|
||||
#+end_src
|
||||
|
||||
** A better custom variable setter
|
||||
Something people often forget about custom variables in Elisp is they
|
||||
can have a custom setter that will run some code if we set the
|
||||
variable properly with ~customize-set-variable~, so ~setq~ shouldn’t be
|
||||
the user’s choice by default. But repeatedly writing
|
||||
~customize-set-variable~ can get tiring and boring. So why not take the
|
||||
best of both world and create ~csetq~, a ~setq~ that uses
|
||||
~customize-set-variable~ under the hood while it keeps a syntax similar
|
||||
to the one ~setq~ uses?
|
||||
#+begin_src emacs-lisp
|
||||
(defmacro csetq (&rest forms)
|
||||
"Bind each custom variable FORM to the value of its VAL.
|
||||
|
||||
FORMS is a list of pairs of values [FORM VAL].
|
||||
`customize-set-variable' is called sequentially on each pairs
|
||||
contained in FORMS. This means `csetq' has a similar behaviour as
|
||||
`setq': each VAL expression are evaluated sequentially, i.e. the
|
||||
first VAL is evaluated before the second, and so on. This means
|
||||
the value of the first FORM can be used to set the second FORM.
|
||||
|
||||
The return value of `csetq' is the value of the last VAL.
|
||||
|
||||
\(fn [FORM VAL]...)"
|
||||
(declare (debug (&rest sexp form))
|
||||
(indent 1))
|
||||
;; Check if we have an even number of arguments
|
||||
(when (= (mod (length forms) 2) 1)
|
||||
(signal 'wrong-number-of-arguments (list 'csetq (1+ (length forms)))))
|
||||
;; Transform FORMS into a list of pairs (FORM . VALUE)
|
||||
(let (sexps)
|
||||
(while forms
|
||||
(let ((form (pop forms))
|
||||
(value (pop forms)))
|
||||
(push `(customize-set-variable ',form ,value)
|
||||
sexps)))
|
||||
`(progn ,@(nreverse sexps))))
|
||||
#+end_src
|
||||
|
||||
I first got inspired by [[https://oremacs.com/2015/01/17/setting-up-ediff/][this blog article]] (archived article, just in
|
||||
case) but it seems the code snippet no longer works properly, so not
|
||||
only did I have to modify it to make it work with an arbitrary amount
|
||||
of arguments (as long as it’s pairs of variables and their value), but
|
||||
I also had to make the code simply work.
|
||||
Reference in New Issue
Block a user