.emacs.d/config.org

418 lines
12 KiB
Org Mode

#+TITLE: Emacs Configuration
#+AUTHOR: Camden Dixie O'Brien
#+ATTR_LATEX: :float t
Shout out to Harry R. Schwartz; A whole bunch of this config
(including the idea of embeddeding the lot in an Org document) is
yanked from [[https://github.com/hrs/dotfiles][his dotfiles repo]].
The rest of this config grabs packages via =use-package=, so that
needs to be set up to install them if they aren't already.
#+begin_src emacs-lisp
(require 'use-package-ensure)
(setq use-package-always-ensure t)
#+end_src
* UI
The start-up message gets pretty annoying, so disable that.
#+begin_src emacs-lisp
(setq inhibit-startup-screen t)
#+end_src
I like a little more line spacing than default.
#+begin_src emacs-lisp
(setq-default line-spacing 0.2)
#+end_src
Also, the menu-, tool- and scroll-bar are ugly, take up space and I
don't use them.
#+begin_src emacs-lisp
(menu-bar-mode -1)
(tool-bar-mode -1)
(scroll-bar-mode -1)
#+end_src
** Colour Scheme
Currently using =spacemacs-theme='s light variant, but I prefer a pure
white background to the off-white it has by default.
#+begin_src emacs-lisp
(use-package spacemacs-theme
:defer t)
(setq spacemacs-theme-custom-colors
'((bg1 . "#ffffff")
(comment-bg . "#ffffff")))
(load-theme 'spacemacs-light t)
#+end_src
* Org-mode
I use a couple non-standard bits and pieces, but not a whole
bunch. I really like the =<s= to insert a source block thing (which
was deprecated); =org-tempo= brings that back.
#+begin_src emacs-lisp
(use-package org
:ensure org-plus-contrib
:config
(require 'org-tempo))
#+end_src
A keybinding to add a new heading is super useful
#+begin_src emacs-lisp
(add-hook 'org-mode-hook
(lambda ()
(define-key org-mode-map
(kbd "<C-M-return>")
'org-insert-heading-after-current)))
#+end_src
** Source Blocks
Pressing tab inside a source block should indent appropriately for its
language.
#+begin_src emacs-lisp
(setq org-src-tab-acts-natively t)
#+end_src
=babel= lets us evaluate Org documents containing source blocks!
I've left the enabling of this for most languages to the section
for that language, but I'll add Emacs Lisp and shell here.
#+begin_src emacs-lisp
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(shell . t)))
#+end_src
By default trying to execute a source block prompts you, which is
super annoying since I'm realistically not going to try to run any
code from Org documents I haven't written, so that needs
disabling. You can do that by setting [[help:org-confirm-babel-evaluate][org-confirm-babel-evaluate]] to
=nil=.
#+begin_src emacs-lisp
(setq org-confirm-babel-evaluate nil)
#+end_src
Another annoying thing that happens by default is the clobbering of
the window layout when you open a source block. You can change that
by setting [[help:org-src-window-setup][org-src-window-setup]].
#+begin_src emacs-lisp
(setq org-src-window-setup 'split-window-below)
#+end_src
** Exporting
I very rarely want a table of contents, as most of my org documents
are pretty short.
#+begin_src emacs-lisp
(setq org-export-with-toc nil)
#+end_src
*** HTML
=htmlize= is needed for decent HTML exporting, but there is no need
for all that stuff at the bottom.
#+begin_src emacs-lisp
(use-package htmlize)
(setq org-html-postamble nil)
#+end_src
*** LaTeX
Use =minted= (LaTeX package) to do syntax highlighting in code blocks:
#+begin_src emacs-lisp
(add-to-list 'org-latex-packages-alist '("" "minted"))
(setq org-latex-listings 'minted)
#+end_src
=minted= actually calls =pygments= through the shell, which =pdflatex=
doesn't like; you have to tell it not to worry, and that everything is
going to be OK.
#+begin_src emacs-lisp
(setq org-latex-pdf-process
'("xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
"xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"
"xelatex -shell-escape -interaction nonstopmode -output-directory %o %f"))
#+end_src
Also, I don't like Emacs' built-in PDF viewer, so open PDFs in Evince instead:
#+begin_src emacs-lisp
(eval-after-load "org"
'(progn
(setcdr (assoc "\\.pdf\\'" org-file-apps) "evince %s")))
#+end_src
* Start up
Org is better suited as scratch space than Funamental, I'd say.
#+begin_src emacs-lisp
(setq initial-major-mode 'org-mode)
(setq initial-scratch-message "")
#+end_src
* Magit
=magit= is truly a wonderful creation! Only deviations from defaults
here are a keybinding for =magit-status= and a maximum length for the
summary line of commit messages (after which the excess is
highlighted).
#+begin_src emacs-lisp
(use-package magit
:bind
("C-x g" . magit-status)
:config
(setq git-commit-summary-max-length 72))
#+end_src
* Language Integrations
Generally, 8-character-wide tabs are not my thing.
#+begin_src emacs-lisp
(setq-default tab-width 4)
(setq-default basic-offset 4)
#+end_src
And generally indenting with spaces is more common, so make that the default:
#+begin_src emacs-lisp
(setq-default indent-tabs-mode nil)
#+end_src
** C
For C, I like to indent with tabs and align with spaces: this
behaviour is provided by =smart-tabs-mode=.
#+begin_src emacs-lisp
(use-package smart-tabs-mode)
(smart-tabs-insinuate 'c)
#+end_src
I'll generally format my code in BSD style but I also use
=clang-format= a lot, so I have a keybinding to run that.
#+begin_src emacs-lisp
(setq c-default-style "bsd")
(use-package clang-format)
(add-hook 'c-mode-hook
(lambda ()
(define-key c-mode-map (kbd "C-M-f")
'clang-format-buffer)))
#+end_src
Meson is my build system of choice for C, but I also use CMake a lot.
#+begin_src emacs-lisp
(use-package meson-mode)
(use-package cmake-mode)
#+end_src
** Haskell
My workflow with Haskell is very REPL-based, so I always want
=interactive-haskell-mode= on.
#+begin_src emacs-lisp
(use-package haskell-mode)
(require 'haskell-interactive-mode)
(add-hook 'haskell-mode-hook 'interactive-haskell-mode)
#+end_src
And, of course, that REPL needs to be taking advantage of parallelism!
#+begin_src emacs-lisp
(require 'haskell-process)
(set-variable 'haskell-process-args-ghci
'("-threaded" "+RTS" "-N8" "-RTS"))
#+end_src
** Idris
The only thing to change from the defaults here is to add a more
convenient way to case-split.
#+begin_src emacs-lisp
(use-package idris-mode)
(add-hook 'idris-mode-hook
(lambda ()
(define-key idris-mode-map (kbd "C-c SPC")
'idris-case-split)))
#+end_src
** Rust
I never really use Rust without Cargo, so always turn on the minor
mode for Cargo in Rust buffers.
#+begin_src emacs-lisp
(use-package rust-mode)
(use-package cargo)
(add-hook 'rust-mode-hook 'cargo-minor-mode)
#+end_src
** Lisps
*** Racket
Get =racket-mode= for some Racket-specific things, like searching documentation
#+begin_src emacs-lisp
(use-package racket-mode)
#+end_src
*** Common Lisp
Use SLIME and Quicklisp for Common Lisp (SBCL), with a convenient
binding for =slime-selector=
#+begin_src emacs-lisp
(use-package slime)
(setq inferior-lisp-program "sbcl")
(global-set-key (kbd "C-c s") 'slime-selector)
(load (expand-file-name "~/quicklisp/slime-helper.el"))
#+end_src
And we also want to enable execution of CL source blocks in Org
mode, which we do by adding an item to [[help:org-babel-load-languages][org-babel-load-languages]].
#+begin_src emacs-lisp
(org-babel-do-load-languages
'org-babel-load-languages
'((lisp . t)))
#+end_src
*** Paredit
=paredit= is generally very useful for balancing parenthesis so we
want that turned on for all the lisps. Additionally, it's nice to have
an entire expression highlighted when the cursor is on one of its
enclosing parens.
#+begin_src emacs-lisp
(use-package paredit)
(setq lispy-mode-hooks
'(emacs-lisp-mode-hook
lisp-mode-hook
racket-mode-hook
scheme-mode-hook
slime-repl-mode-hook))
(dolist (hook lispy-mode-hooks)
(add-hook hook (lambda ()
(setq show-paren-style 'expression)
(paredit-mode))))
#+end_src
** YAML
I don't really like YAML if I'm honest, but it's used a lot so...
#+begin_src emacs-lisp
(use-package yaml-mode)
#+end_src
* Desktop
** EXWM
One must fulfil the meme of doing everything with Emacs... still
got a lot of tweaking to do here before I'm happy.
#+begin_src emacs-lisp
(use-package exwm
:config
(require 'exwm-randr)
(exwm-randr-enable)
(require 'exwm-config)
(exwm-config-default))
#+end_src
When I have my laptop connected to a monitor I want the built-in
display to turn off, but turn back on when it's disconnected. Turns
out this is a total pain.
To start with we need a function to tell whether a monitor's
attached. =exwm-randr= provides [[help:exwm-randr--get-monitors][exwm-randr--get-monitors]], but its
result is not -- as I'd expect -- a list of monitors, but instead a
rather complicated mess that is (as far as I can tell)
undocumented. Rather than trying to figure out what was going on
there, I opted for the search-in-shell-command-output route
#+begin_src emacs-lisp
(defun hdmi-connected-p ()
(string-match-p "HDMI-2 connected"
(shell-command-to-string "xrandr")))
#+end_src
With that defined, an [[help:exwm-randr-screen-change-hook][exwm-randr-screen-change-hook]] can then be
added to turn the built-in display on and off appropriately.
#+begin_src emacs-lisp
(add-hook 'exwm-randr-screen-change-hook
(lambda ()
(let ((xrandr-command
(if (hdmi-connected-p)
"xrandr --output eDP-1 --off --output HDMI-2 --auto"
"xrandr --output eDP-1 --auto")))
(start-process-shell-command "xrandr" nil xrandr-command))))
#+end_src
** Mode Line
*** Clock
The time is a useful thing to know... and 12-hour clock is for
losers.
#+begin_src emacs-lisp
(setq display-time-24hr-format t)
(display-time-mode 1)
#+end_src
*** Battery
Also useful to know, but only on a laptop... once I'm using this
configuration on Mandarax as well I'll probably have to
conditionally disable it.
#+begin_src emacs-lisp
(display-battery-mode 1)
#+end_src
* Passwords
This was a little more work than I expected... =password-store=
provides a nice interface to =pass=, but annoyingly appears to
depend on =f= without declaring so.
#+begin_src emacs-lisp
(use-package password-store)
(use-package f)
#+end_src
However, in order for it to actually work, EasyPG had to be
configured to use loopback for pinentry.
#+begin_src emacs-lisp
(setq epa-pinentry-mode 'loopback)
#+end_src
=gpg-agent= also had to be configured to allow loopback for
pinentry -- this was done by adding =allow-loopback-pinentry= to
[[file:~/.gnupg/gpg-agent.conf::allow-loopback-pinentry][gpg-agent.conf]].
With that all working, all that remains is to add a convenient
keybinding for getting a password, which is done by the function
=password-store-copy=. =C-c C-p= does conflict with /some/ modal
bindings, but I think that's fine as most of the time I'll need a
password it'll be in some X window anyway... and besides, =M-x
pass-co RET= isn't bad for when it does happen to conflict.
#+begin_src emacs-lisp
(global-set-key (kbd "C-c C-p") 'password-store-copy)
#+end_src
* Music Player
MPD is clearly the correct way to build a music player, so all
that's needed is a client for it... after having played around with
a couple of them, [[https://github.com/pft/mingus][Mingus]] is the one I've like the most.
#+begin_src emacs-lisp
(use-package mingus)
#+end_src