emacs-config/config.org

2504 lines
101 KiB
Org Mode
Raw Normal View History

#+TITLE: Doom Emacs Configuration
#+AUTHOR: tecosaur
#+PROPERTY: header-args:emacs-lisp :tangle yes :cache yes :results silent :comments link
#+HTML_HEAD: <link rel='shortcut icon' type='image/png' href='https://www.gnu.org/software/emacs/favicon.png'>
#+BEGIN_QUOTE
Let us change our traditional attitude to the construction of programs:
Instead of imagining that our main task is to instruct a computer what to do,
let us concentrate rather on explaining to human beings what we want a
computer to do. --- Donald Knuth
#+END_QUOTE
2020-01-20 18:08:07 +00:00
* Intro
Customising an editor can be very rewarding ... until you have to leave it.
For years I have been looking for ways to avoid this pain.
2020-02-03 18:16:07 +00:00
Then I discovered [[https://github.com/cknadler/vim-anywhere][vim-anywhere]], and found that it had an emacs companion,[[https://github.com/zachcurry/emacs-anywhere][
2020-01-20 18:08:07 +00:00
emacs-anywhere]]. To me, this looked most attractive.
Separately, online I have seen the following statement enough times I think it's a catchphrase
#+BEGIN_QUOTE
Redditor1: I just discovered this thing, isn't it cool.
Redditor2: Oh, there's an emacs mode for that.
#+END_QUOTE
I tried out the =spacemacs= distribution a bit, but it wasn't quite to my liking.
Then I heard about =doom emacs= and thought I may as well give that a try.
TLDR; it's great.
Now I've discovered the wonders of literate programming, and am becoming more
settled by the day. This is my config.
* Rudimentary configuration
2020-02-03 05:28:15 +00:00
Make this file run (slightly) faster with lexical binding (see [[https://nullprogram.com/blog/2016/12/22/][this blog post]]
for more info).
#+BEGIN_SRC emacs-lisp
;;; config.el -*- lexical-binding: t; -*-
#+END_SRC
** Personal Information
It's useful to have some basic personal information
#+BEGIN_SRC emacs-lisp
(setq user-full-name "tecosaur"
user-mail-address "tecosaur@gmail.com")
#+END_SRC
Apparently this is used by ~GPG~, and all sorts of other things.
** Better defaults
*** Simple settings
Browsing the web and seeing [[https://github.com/angrybacon/dotemacs/blob/master/dotemacs.org#use-better-defaults][angrybacon/dotemacs]] and comparing with the values
shown by =SPC h v= and selecting what I thought looks good, I've ended up adding the following:
#+BEGIN_SRC emacs-lisp
(setq-default
delete-by-moving-to-trash t ; Delete files to trash
tab-width 4 ; Set width for tabs
uniquify-buffer-name-style 'forward ; Uniquify buffer names
window-combination-resize t ; take new window space from all other windows (not just current)
x-stretch-cursor t) ; Stretch cursor to the glyph width
2020-02-02 18:21:19 +00:00
(setq undo-limit 80000000 ; Raise undo-limit to 80Mb
2020-03-04 15:27:08 +00:00
evil-want-fine-undo t ; By default while in insert all changes are one big blob. Be more granular
auto-save-default t ; Nobody likes to loose work, I certainly don't
inhibit-compacting-font-caches t) ; When there are lots of glyphs, keep them in memory
(delete-selection-mode 1) ; Replace selection when inserting text
(display-time-mode 1) ; Enable time in the mode-line
2020-01-09 18:04:48 +00:00
(display-battery-mode 1) ; On laptops it's nice to know how much power you have
(global-subword-mode 1) ; Iterate through CamelCase words
#+END_SRC
*** Fullscreen
I also like the idea of fullscreen-ing when opened by ~emacs~ or the ~.desktop~ file.
#+BEGIN_SRC emacs-lisp
(if (eq initial-window-system 'x) ; if started by emacs command or desktop file
(toggle-frame-maximized)
(toggle-frame-fullscreen))
#+END_SRC
*** Auto-customisations
By default changes made via a customisation interface are added to =init.el=.
I prefer the idea of using a separate file for this. We just need to change a
setting, and load it if it exists.
#+BEGIN_SRC emacs-lisp
2020-02-26 12:50:01 +00:00
(setq-default custom-file (expand-file-name ".custom.el" doom-private-dir))
(when (file-exists-p custom-file)
(load custom-file))
#+END_SRC
*** Windows
I find it rather handy to be asked which buffer I want to see after splitting
the window. Let's make that happen.
First, we'll enter the new window
#+BEGIN_SRC emacs-lisp
(setq evil-vsplit-window-right t
evil-split-window-below t)
#+END_SRC
Then, we'll pull up ~ivy~
#+BEGIN_SRC emacs-lisp
(defadvice! prompt-for-buffer (&rest _)
:after '(evil-window-split evil-window-vsplit)
2020-02-09 15:16:25 +00:00
(+ivy/switch-buffer))
#+END_SRC
2020-01-29 12:46:48 +00:00
*** Buffer defaults
I'd much rather have my new buffers in ~org-mode~ than ~fundamental-mode~, hence
#+BEGIN_SRC emacs-lisp
;; (setq-default major-mode 'org-mode)
2020-01-29 12:46:48 +00:00
#+END_SRC
For some reason this + the mixed pitch hook causes issues with hydra and so I'll
just need to resort to =SPC b o= for now.
** Doom configuration
*** Visual Settings
**** Font Face
'Fira Code' is nice, and 'Overpass' makes for a nice sans companion. We just need to
fiddle with the font sizes a tad so that they visually match.
#+BEGIN_SRC emacs-lisp
2020-01-29 12:37:14 +00:00
(setq doom-font (font-spec :family "Fira Code" :size 22)
2020-01-09 17:52:29 +00:00
doom-big-font (font-spec :family "Fira Code" :size 36)
2020-01-29 12:37:14 +00:00
doom-variable-pitch-font (font-spec :family "Overpass" :size 24))
#+END_SRC
**** Theme
~doom-one~ is nice and all, but I find the ~vibrant~ variant nicer.
#+BEGIN_SRC emacs-lisp
(setq doom-theme 'doom-vibrant)
#+END_SRC
However, by default ~red~ text is used in the ~modeline~, so let's make that orange
so I don't feel like something's gone /wrong/ when editing files.
#+BEGIN_SRC emacs-lisp
(custom-set-faces!
'(doom-modeline-buffer-modified :foreground "orange"))
#+END_SRC
**** Miscellaneous
Relative line numbers are fantastic for knowing how far away line numbers are,
then =ESC 12 <UP>= gets you exactly where you think.
#+BEGIN_SRC emacs-lisp
(setq display-line-numbers-type 'relative)
#+END_SRC
2020-02-06 17:11:35 +00:00
I'd like some slightly nicer default buffer names
#+BEGIN_SRC emacs-lisp
(setq doom-fallback-buffer-name "► Doom"
+doom-dashboard-name "► Doom")
#+END_SRC
There's a bug with the modeline in insert mode for org documents ([[https://github.com/seagle0128/doom-modeline/issues/300][issue]]), so
2020-02-09 00:12:19 +00:00
#+BEGIN_SRC emacs-lisp
(custom-set-faces! '(doom-modeline-evil-insert-state :weight bold :foreground "#339CDB"))
2020-02-09 00:12:19 +00:00
#+END_SRC
*** Some helper macros
There are a few handy macros added by doom, namely
- ~load!~ for loading external ~.el~ files relative to this one
- ~use-package~ for configuring packages
- ~add-load-path!~ for adding directories to the ~load-path~ where ~emacs~ looks when
you load packages with ~require~ or ~use-package~
- ~map~ for binding new keys
To find more,
** Other things
*** Editor interaction
**** Mouse buttons
#+BEGIN_SRC emacs-lisp
(map! :n [mouse-8] #'better-jumper-jump-backward
:n [mouse-9] #'better-jumper-jump-forward)
#+END_SRC
2020-02-06 15:31:44 +00:00
*** Window title
I'd like to have just the buffer name, then if applicable the project folder
#+BEGIN_SRC emacs-lisp
(setq frame-title-format
'(""
"%b"
(:eval
(let ((project-name (projectile-project-name)))
(unless (string= "-" project-name)
2020-02-16 05:23:19 +00:00
(format (if (buffer-modified-p) " ◉ %s" "  ●  %s") project-name))))))
2020-02-06 15:31:44 +00:00
#+END_SRC
2020-03-27 04:20:42 +00:00
*** Splash screen
Emacs can render an image as the splash screen, and [[https://github.com/MarioRicalde][@MarioRicalde]] came up with a
cracker! He's also provided me with a nice emacs-style /E/, which is good for
smaller windows. *@MarioRicalde* you have my sincere thanks, you're great!
[[file:misc/splash-images/blackhole-lines.svg]]
By incrementally stripping away the outer layers of the logo one can obtain
quite a nice resizing effect.
2020-03-27 04:20:42 +00:00
#+BEGIN_SRC emacs-lisp
(defvar fancy-splash-image-template
(expand-file-name "misc/splash-images/blackhole-lines-template.svg" doom-private-dir)
"Default template svg used for the splash image, with substitutions from ")
(defvar fancy-splash-image-nil
(expand-file-name "misc/splash-images/transparent-pixel.png" doom-private-dir)
"An image to use at minimum size, usually a transparent pixel")
(setq fancy-splash-sizes
`((:height 500 :min-height 50 :padding (0 . 2) :template ,(expand-file-name "misc/splash-images/blackhole-lines-0.svg" doom-private-dir))
(:height 440 :min-height 42 :padding (1 . 4) :template ,(expand-file-name "misc/splash-images/blackhole-lines-0.svg" doom-private-dir))
(:height 400 :min-height 38 :padding (1 . 4) :template ,(expand-file-name "misc/splash-images/blackhole-lines-1.svg" doom-private-dir))
(:height 350 :min-height 36 :padding (1 . 3) :template ,(expand-file-name "misc/splash-images/blackhole-lines-2.svg" doom-private-dir))
(:height 300 :min-height 34 :padding (1 . 3) :template ,(expand-file-name "misc/splash-images/blackhole-lines-3.svg" doom-private-dir))
(:height 250 :min-height 32 :padding (1 . 2) :template ,(expand-file-name "misc/splash-images/blackhole-lines-4.svg" doom-private-dir))
(:height 200 :min-height 30 :padding (1 . 2) :template ,(expand-file-name "misc/splash-images/blackhole-lines-5.svg" doom-private-dir))
(:height 100 :min-height 24 :padding (1 . 2) :template ,(expand-file-name "misc/splash-images/emacs-e-template.svg" doom-private-dir))
(:height 0 :min-height 0 :padding (0 . 0) :file ,fancy-splash-image-nil)))
(defvar fancy-splash-sizes
`((:height 500 :min-height 50 :padding (0 . 2))
(:height 440 :min-height 42 :padding (1 . 4))
(:height 330 :min-height 35 :padding (1 . 3))
(:height 200 :min-height 30 :padding (1 . 2))
(:height 0 :min-height 0 :padding (0 . 0) :file ,fancy-splash-image-nil))
"list of plists with the following properties
:height the height of the image
:min-height minimum `frame-height' for image
:padding `+doom-dashboard-banner-padding' to apply
:template non-default template file
:file file to use instead of template")
(defvar fancy-splash-template-colours
'(("$colour1" . keywords) ("$colour2" . type) ("$colour3" . base5) ("$colour4" . base8))
"list of colour-replacement alists of the form (\"$placeholder\" . 'theme-colour) which applied the template")
(unless (file-exists-p (expand-file-name "theme-splashes" doom-cache-dir))
(make-directory (expand-file-name "theme-splashes" doom-cache-dir) t))
(defun fancy-splash-filename (theme-name height)
(expand-file-name (concat (file-name-as-directory "theme-splashes")
(symbol-name doom-theme)
"-" (number-to-string height) ".svg")
doom-cache-dir))
(defun fancy-splash-clear-cache ()
"Delete all cached fancy splash images"
(interactive)
(delete-directory (expand-file-name "theme-splashes" doom-cache-dir) t)
(message "Cache cleared!"))
(defun fancy-splash-generate-image (template height)
"Read TEMPLATE and create an image if HEIGHT with colour substitutions as ;described by `fancy-splash-template-colours' for the current theme"
(with-temp-buffer
(insert-file-contents template)
(re-search-forward "$height" nil t)
(replace-match (number-to-string height) nil nil)
(dolist (substitution fancy-splash-template-colours)
(beginning-of-buffer)
(while (re-search-forward (car substitution) nil t)
(replace-match (doom-color (cdr substitution)) nil nil)))
2020-03-28 04:18:03 +00:00
(write-region nil nil
(fancy-splash-filename (symbol-name doom-theme) height) nil nil)))
(defun fancy-splash-generate-images ()
"Perform `fancy-splash-generate-image' in bulk"
(dolist (size fancy-splash-sizes)
(unless (plist-get size :file)
(fancy-splash-generate-image (or (plist-get size :file)
(plist-get size :template)
fancy-splash-image-template)
(plist-get size :height)))))
(defun ensure-theme-splash-images-exist (&optional height)
(unless (file-exists-p (fancy-splash-filename
(symbol-name doom-theme)
(or height
(plist-get (car fancy-splash-sizes) :height))))
(fancy-splash-generate-images)))
(defun get-appropriate-splash ()
(let ((height (frame-height)))
(cl-some (lambda (size) (when (>= height (plist-get size :min-height)) size))
fancy-splash-sizes)))
(setq fancy-splash-last-size nil)
(setq fancy-splash-last-theme nil)
2020-03-27 04:20:42 +00:00
(defun set-appropriate-splash (&optional frame)
(let ((appropriate-image (get-appropriate-splash)))
(unless (and (equal appropriate-image fancy-splash-last-size)
(equal doom-theme fancy-splash-last-theme)))
(unless (plist-get appropriate-image :file)
(ensure-theme-splash-images-exist (plist-get appropriate-image :height)))
(setq fancy-splash-image
(or (plist-get appropriate-image :file)
(fancy-splash-filename (symbol-name doom-theme) (plist-get appropriate-image :height))))
(setq +doom-dashboard-banner-padding (plist-get appropriate-image :padding))
(setq fancy-splash-last-size appropriate-image)
(setq fancy-splash-last-theme doom-theme)
(+doom-dashboard-reload)))
2020-03-27 04:20:42 +00:00
(add-hook 'window-size-change-functions #'set-appropriate-splash)
(add-hook 'doom-load-theme-hook #'set-appropriate-splash)
2020-03-27 04:20:42 +00:00
#+END_SRC
2020-02-16 05:12:36 +00:00
*** Systemd daemon
For running a systemd service for a emacs server I have the following
#+BEGIN_SRC systemd :tangle ~/.config/systemd/user/emacs.service
[Unit]
Description=Emacs server daemon
Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
[Service]
Type=forking
ExecStart=/usr/bin/emacs --daemon
ExecStop=/usr/bin/emacsclient --eval "(progn (setq kill-emacs-hook nil) (kill emacs))"
Environment=SSH_AUTH_SOCK=%t/keyring/ssh
Restart=on-failure
[Install]
WantedBy=default.target
#+END_SRC
which is then enabled by
#+BEGIN_SRC sh :tangle no
systemctl --user enable emacs.service
#+END_SRC
* Package loading
:PROPERTIES:
2020-04-10 04:31:36 +00:00
:header-args:emacs-lisp: :tangle "packages.el" :comments link
:END:
This file shouldn't be byte compiled.
#+BEGIN_SRC emacs-lisp :tangle "packages.el"
;; -*- no-byte-compile: t; -*-
#+END_SRC
** Loading instructions
:PROPERTIES:
2020-03-23 02:59:27 +00:00
:header-args:emacs-lisp: :tangle no
:END:
This is where you install packages, by declaring them with the ~package!~
macro, then running ~doom refresh~ on the command line. You'll need to
restart Emacs for your changes to take effect! Or at least, run =M-x doom/reload=.
WARNING: Don't disable core packages listed in ~~/.emacs.d/core/packages.el~.
Doom requires these, and disabling them may have terrible side effects.
*** Packages in MELPA/ELPA/emacsmirror
To install ~some-package~ from MELPA, ELPA or emacsmirror:
#+BEGIN_SRC emacs-lisp
(package! some-package)
#+END_SRC
*** Packages from git repositories
To install a package directly from a particular repo, you'll need to specify
a ~:recipe~. You'll find documentation on what ~:recipe~ accepts [[https://github.com/raxod502/straight.el#the-recipe-format][here]]:
#+BEGIN_SRC emacs-lisp
(package! another-package
:recipe (:host github :repo "username/repo"))
#+END_SRC
If the package you are trying to install does not contain a ~PACKAGENAME.el~
file, or is located in a subdirectory of the repo, you'll need to specify
~:files~ in the ~:recipe~:
#+BEGIN_SRC emacs-lisp
(package! this-package
:recipe (:host github :repo "username/repo"
:files ("some-file.el" "src/lisp/*.el")))
#+END_SRC
2020-01-09 18:00:50 +00:00
*** Disabling built-in packages
If you'd like to disable a package included with Doom, for whatever reason,
you can do so here with the ~:disable~ property:
#+BEGIN_SRC emacs-lisp
(package! builtin-package :disable t)
#+END_SRC
You can override the recipe of a built in package without having to specify
all the properties for ~:recipe~. These will inherit the rest of its recipe
from Doom or MELPA/ELPA/Emacsmirror:
#+BEGIN_SRC emacs-lisp
(package! builtin-package :recipe (:nonrecursive t))
(package! builtin-package-2 :recipe (:repo "myfork/package"))
#+END_SRC
Specify a ~:branch~ to install a package from a particular branch or tag.
This is required for some packages whose default branch isn't 'master' (which
our package manager can't deal with; see [[https://github.com/raxod502/straight.el/issues/279][raxod502/straight.el#279]])
#+BEGIN_SRC emacs-lisp
(package! builtin-package :recipe (:branch "develop"))
#+END_SRC
*** Updating all pins in file
2020-04-10 04:31:36 +00:00
#+BEGIN_SRC emacs-lisp :tangle yes
(defun +doom/update-all-pinned-package-form ()
"Call `doom/update-pinned-package-form' on every package! statement in the buffer"
(interactive)
(beginning-of-buffer)
(let ((progress 0) (total (how-many "package!")) (updated 0))
(while (search-forward "package!" nil t)
(setq progress (1+ progress))
(forward-char) ;; move cursor to package name "package! |name"
(message (format "Re-pinning package: %s/%s (%s)" progress total (current-word)))
(backward-char)
(evil-scroll-line-to-center (line-number-at-pos))
(redisplay)
(if (s-contains-p "Updated" (condition-case nil
(doom/update-pinned-package-form)
(user-error "")))
(setq updated (1+ updated)))
(search-forward "package!" nil t)) ;; because of cursor-moving done
(message (format "%s packages updated" updated))))
#+END_SRC
2020-02-16 06:13:35 +00:00
** General packages
*** Auto-complete
#+BEGIN_SRC emacs-lisp
(package! company-tabnine ; tab9 autocomplete
:recipe (:host github :repo "TommyX12/company-tabnine"
2020-04-09 17:16:13 +00:00
:files ("company-tabnine.el" "fetch-binaries.sh")) :pin "e986a4ad0d")
#+END_SRC
*** Prettification
~prettify-mode~ is nice and all, but adding substitutions is a little verbose.
This helps with that.
#+BEGIN_SRC emacs-lisp
(package! prettify-utils ; simplify messing with prettify-mode
2020-04-09 17:16:13 +00:00
:recipe (:host github :repo "Ilazki/prettify-utils.el") :pin "8b783d316c")
#+END_SRC
2020-01-20 18:08:53 +00:00
*** Window management
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! rotate :pin "091b5ac4fc")
2020-01-20 18:08:53 +00:00
#+END_SRC
*** Fun
Sometimes one just wants a little fun.
XKCD comics are fun.
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! xkcd :pin "66e928706f")
2020-01-20 18:08:53 +00:00
#+END_SRC
Every so often, you want everyone else to /know/ that you're typing, or just to
amuse oneself. Introducing: typewriter sounds!
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! selectric-mode :pin "bb9e66678f")
2020-01-20 18:08:53 +00:00
#+END_SRC
Hey, let's get the weather in here while we're at it.
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! wttrin :pin "df5427ce2a")
2020-01-20 18:08:53 +00:00
#+END_SRC
Why not flash words on the screen. Why not --- hey, it could be fun.
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! spray :pin "00638bc916")
2020-01-20 18:08:53 +00:00
#+END_SRC
With all our fancy emacs themes, my terminal is missing out!
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! theme-magic :pin "844c4311bd")
2020-01-20 18:08:53 +00:00
#+END_SRC
2020-04-09 17:15:17 +00:00
What's even the point of using Emacs unless you're constantly telling everyone
about it?
#+BEGIN_SRC emacs-lisp
(package! elcord :pin "94b0afb9ba")
#+END_SRC
2020-01-20 18:08:53 +00:00
*** Other
**** Flyspell-lazy
2020-01-09 18:01:52 +00:00
To alleviate some [[Flyspell][issues with flyspell]]
#+BEGIN_SRC emacs-lisp
(package! flyspell-lazy)
#+END_SRC
2020-02-03 04:57:08 +00:00
**** CalcTeX
This is a nice extension to ~calc~
#+BEGIN_SRC emacs-lisp
(package! calctex :recipe (:host github :repo "johnbcoughlin/calctex"
2020-04-09 17:16:13 +00:00
:files ("*.el")) :pin "542b628eb4")
2020-02-03 04:57:08 +00:00
#+END_SRC
2020-02-16 06:13:35 +00:00
**** ESS
View dataframes better with
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! ess-view :pin "d4e5a340b7")
2020-02-16 06:13:35 +00:00
#+END_SRC
** Language packages
*** Systemd
2020-02-03 04:57:08 +00:00
For editing systemd unit files
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! systemd :pin "51c148e09a")
2020-02-03 04:57:08 +00:00
#+END_SRC
2020-02-16 06:13:35 +00:00
*** Org Mode
**** Improve agenda/capture
The agenda is nice, but a souped up version is nicer.
#+BEGIN_SRC emacs-lisp
(package! org-super-agenda :pin "dd0d104c26")
#+END_SRC
Similarly ~doct~ (Declarative Org Capture Templates) seems to be a nicer way to
set up org-capture.
#+BEGIN_SRC emacs-lisp
(package! doct
:recipe (:host github :repo "progfolio/doct")
:pin "6cf1943ad7")
#+END_SRC
2020-04-12 05:49:54 +00:00
**** Visuals
2020-02-16 06:13:35 +00:00
Org tables aren't the prettiest thing to look at. This package is supposed to
redraw them in the buffer with box-drawing characters. Sounds like an
improvement to me! Just need to get it working...
2020-02-03 04:57:08 +00:00
#+BEGIN_SRC emacs-lisp
2020-02-16 06:13:35 +00:00
(package! org-pretty-table-mode
2020-04-09 17:16:13 +00:00
:recipe (:host github :repo "Fuco1/org-pretty-table") :pin "88380f865a")
2020-02-16 06:13:35 +00:00
#+END_SRC
2020-04-12 05:49:54 +00:00
For automatically toggling LaTeX fragment previews there's this nice package
#+BEGIN_SRC emacs-lisp
(package! org-fragtog :pin "8eca8084cc")
#+END_SRC
~org-superstar-mode~ seems better than ~org-bullets~, so let's switch to that
instead. Since we're making stuff look nicer we may as well make priorities and
tags prettier as well :)
#+BEGIN_SRC emacs-lisp
(package! org-bullets :disable t :pin "767f55feb5")
(package! org-superstar
:recipe (:host github :repo "integral-dw/org-superstar-mode")
:pin "4659cfc120")
(package! org-fancy-priorities :pin "819bb993b7")
(package! org-pretty-tags :pin "40fd72f3e7")
#+END_SRC
**** Extra functionality
2020-02-16 06:13:35 +00:00
Because of the /[[https://github.com/commonmark/commonmark-spec/wiki/markdown-flavors][lovely variety in markdown implementations]]/ there isn't actually
such a thing a standard table spec ... or standard anything really. Because
~org-md~ is a goody-two-shoes, it just uses HTML for all these non-standardised
elements (a lot of them). So ~ox-gfm~ is handy for exporting markdown with all the
features that GitHub has. Initialised in [[Exporting to GFM]].
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! ox-gfm :pin "99f93011b0")
2020-02-16 06:13:35 +00:00
#+END_SRC
2020-02-26 11:05:41 +00:00
Now and then citations need to happen
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! org-ref :pin "5bb9be2232")
2020-02-26 11:05:41 +00:00
#+END_SRC
2020-02-16 06:13:35 +00:00
Came across this and ... it's cool
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! org-graph-view :recipe (:host github :repo "alphapapa/org-graph-view") :pin "13314338d7")
2020-02-03 04:57:08 +00:00
#+END_SRC
I *need* this in my life. It take a URL to a recipe from a common site, and
inserts an org-ified version at point. Isn't that just great.
#+BEGIN_SRC emacs-lisp
2020-04-09 17:16:13 +00:00
(package! org-chef :pin "67f50aa2a2")
#+END_SRC
* Package configuration
** Abbrev mode
Thanks to [[https://emacs.stackexchange.com/questions/45462/use-a-single-abbrev-table-for-multiple-modes/45476#45476][use a single abbrev-table for multiple modes? - Emacs Stack Exchange]] I
have the following.
#+BEGIN_SRC emacs-lisp
(use-package abbrev
:init
(setq-default abbrev-mode t)
;; a hook funtion that sets the abbrev-table to org-mode-abbrev-table
;; whenever the major mode is a text mode
(defun tec/set-text-mode-abbrev-table ()
(if (derived-mode-p 'text-mode)
(setq local-abbrev-table org-mode-abbrev-table)))
:commands abbrev-mode
:hook
(abbrev-mode . tec/set-text-mode-abbrev-table)
:config
(setq abbrev-file-name (expand-file-name "abbrev.el" doom-private-dir))
(setq save-abbrevs 'silently))
#+END_SRC
** Centaur Tabs
We want to make the tabs a nice, comfy size (~36~), with icons. The modifier
marker is nice, but the particular default Unicode one causes a lag spike, so
let's just switch to an ~o~, which still looks decent but doesn't cause any
issues.
A 'active-bar' is nice, so let's have one of those. If we have it ~under~ needs us to
turn on ~x-underline-at-decent~ though. For some reason this didn't seem to work
inside the ~(after! ... )~ block ¯\_(ツ)_/¯.
Then let's change the font to a sans serif, but the default one doesn't fit too
well somehow, so let's switch to 'P22 Underground Book'; it looks much nicer.
#+BEGIN_SRC emacs-lisp
(after! centaur-tabs
2020-04-09 18:29:06 +00:00
(centaur-tabs-mode -1)
(setq centaur-tabs-height 36
centaur-tabs-set-icons t
centaur-tabs-modified-marker "o"
2020-01-09 18:02:20 +00:00
centaur-tabs-close-button "×"
centaur-tabs-set-bar 'above)
centaur-tabs-gray-out-icons 'buffer
(centaur-tabs-change-fonts "P22 Underground Book" 160))
;; (setq x-underline-at-descent-line t)
#+END_SRC
** Company
It's nice to have completions almost all the time, in my opinion. Key strokes
are just waiting to be saved!
#+BEGIN_SRC emacs-lisp
(after! company
(setq company-idle-delay 0.5
company-minimum-prefix-length 2)
2020-02-26 12:49:02 +00:00
(setq company-show-numbers t)
(add-hook 'evil-normal-state-entry-hook #'company-abort)) ;; make aborting less annoying.
#+END_SRC
Now, the improvements from ~precident~ are mostly from remembering history, so
let's improve that memory.
#+BEGIN_SRC emacs-lisp
(setq-default history-length 1000)
(setq-default prescient-history-length 1000)
#+END_SRC
*** Plain Text
~ispell~ is nice, let's have it in ~text~, ~markdown~, and ~GFM~.
#+BEGIN_SRC emacs-lisp
(set-company-backend! '(text-mode
markdown-mode
gfm-mode)
'(:seperate company-ispell
company-files
company-yasnippet))
#+END_SRC
2020-03-19 09:00:06 +00:00
We then configure the dictionary we're using in [[*ispell][ispell]].
*** ESS
~company-dabbrev-code~ is nice. Let's have it.
#+BEGIN_SRC emacs-lisp
(set-company-backend! 'ess-r-mode '(company-R-args company-R-objects company-dabbrev-code :separate))
#+END_SRC
** [[https://github.com/zachcurry/emacs-anywhere][Emacs Anywhere]] configuration
2020-02-06 17:11:58 +00:00
# NB: install with curl -fsSL https://raw.github.com/zachcurry/emacs-anywhere/master/install | bash
It's nice to recognise GitHub (so we can use ~GFM~), and other apps which we know
take markdown
#+BEGIN_SRC emacs-lisp
(defun markdown-window-p (window-title)
"Judges from WINDOW-TITLE whether the current window likes markdown"
(string-match-p (rx (or "Stack Exchange" "Stack Overflow"
"Pull Request" "Issue" "Discord"))
window-title))
#+END_SRC
When the window opens, we generally want text so let's use a nice sans serif font,
a position the window below and to the left. Oh, and don't forget about checking
for ~GFM~, otherwise let's just use ~markdown~.
#+BEGIN_SRC emacs-lisp
(define-minor-mode emacs-anywhere-mode
"To tweak the current buffer for some emacs-anywhere considerations"
:init-value nil
:keymap (list
;; Finish edit, but be smart in org mode
(cons (kbd "C-c C-c") (lambda! (if (and (eq major-mode 'org-mode)
(org-in-src-block-p))
(org-ctrl-c-ctrl-c)
(delete-frame))))
;; Abort edit. emacs-anywhere saves the current edit for next time.
(cons (kbd "C-c C-k") (lambda! (setq ea-on nil)
(delete-frame))))
(when emacs-anywhere-mode
2020-03-24 04:45:07 +00:00
;; line breaking
(turn-off-auto-fill)
(visual-line-mode t)
;; DEL/C-SPC to clear (first keystroke only)
(set-transient-map (let ((keymap (make-sparse-keymap)))
(define-key keymap (kbd "DEL") (lambda! (delete-region (point-min) (point-max))))
(define-key keymap (kbd "C-SPC") (lambda! (delete-region (point-min) (point-max))))
keymap))
;; I'll be honest with myself, I /need/ spellcheck
(flyspell-buffer)
;; disable tabs
(when (bound-and-true-p centaur-tabs-mode)
(centaur-tabs-local-mode t))))
(defun ea-popup-handler (app-name window-title x y w h)
(interactive)
(set-frame-size (selected-frame) 80 12)
;; position the frame near the mouse
(let* ((mousepos (split-string (shell-command-to-string "xdotool getmouselocation | sed -E \"s/ screen:0 window:[^ ]*|x:|y://g\"")))
(mouse-x (- (string-to-number (nth 0 mousepos)) 100))
(mouse-y (- (string-to-number (nth 1 mousepos)) 50)))
(set-frame-position (selected-frame) mouse-x mouse-y))
(set-frame-name (concat "Quick Edit ∷ " ea-app-name " — "
(truncate-string-to-width
(string-trim
(string-trim-right window-title
(format "-[A-Za-z0-9 ]*%s" ea-app-name))
"[\s-]+" "[\s-]+")
45 nil nil "…")))
(message "window-title: %s" window-title)
;; set major mode
(cond
((markdown-window-p window-title) (gfm-mode))
(t (org-mode)) ; default major mode
)
(when (gui-get-selection 'PRIMARY) (insert (gui-get-selection 'PRIMARY)))
(evil-insert-state) ; start in insert
(emacs-anywhere-mode 1))
(add-hook 'ea-popup-hook 'ea-popup-handler)
#+END_SRC
** Flyspell
At one point, typing became noticably laggy, Profiling revealed
~flyspell-post-command-hook~ was responsible for 47% of CPU cycles by itself!
So I'm going to make use of ~flyspell-lazy~
#+BEGIN_SRC emacs-lisp
(after! flyspell (require 'flyspell-lazy) (flyspell-lazy-mode 1))
#+END_SRC
** Tramp
Let's try to make tramp handle prompts better
#+BEGIN_SRC emacs-lisp
(after! tramp
(setenv "SHELL" "/bin/bash")
(setq tramp-shell-prompt-pattern "\\(?:^\\| \\)[^]#$%>\n]*#?[]#$%>] *\\(\\[[0-9;]*[a-zA-Z] *\\)*")) ;; defult + 
#+END_SRC
**** Troubleshooting
In case the remote shell is misbehaving, here are some things to try
***** Zsh
There are some escape code you don't want, let's make it behave more considerately.
#+BEGIN_SRC shell :eval no :tangle no
if [[ "$TERM" == "dumb" ]]; then
unset zle_bracketed_paste
unset zle
PS1='$ '
return
fi
#+END_SRC
2020-03-17 17:12:17 +00:00
** Treemacs
Quite often there are superfluous files I'm not that interested in. There's no
2020-03-23 03:00:23 +00:00
good reason for them to take up space. Let's add a mechanism to ignore them.
#+BEGIN_SRC emacs-lisp
(after! treemacs
(defvar treemacs-file-ignore-extensions '()
"File extension which `treemacs-ignore-filter' will ensure are ignored")
(defvar treemacs-file-ignore-globs '()
"Globs which will are transformed to `treemacs-file-ignore-regexps' which `treemacs-ignore-filter' will ensure are ignored")
(defvar treemacs-file-ignore-regexps '()
"RegExps to be tested to ignore files, generated from `treeemacs-file-ignore-globs'")
(defun treemacs-file-ignore-generate-regexps ()
"Generate `treemacs-file-ignore-regexps' from `treemacs-file-ignore-globs'"
(setq treemacs-file-ignore-regexps (mapcar 'dired-glob-regexp treemacs-file-ignore-globs)))
(if (equal treemacs-file-ignore-globs '()) nil (treemacs-file-ignore-generate-regexps))
(defun treemacs-ignore-filter (file full-path)
"Ignore files specified by `treemacs-file-ignore-extensions', and `treemacs-file-ignore-regexps'"
(or (member (file-name-extension file) treemacs-file-ignore-extensions)
(let ((ignore-file nil))
(dolist (regexp treemacs-file-ignore-regexps ignore-file)
(setq ignore-file (or ignore-file (if (string-match-p regexp full-path) t nil)))))))
(add-to-list 'treemacs-ignored-file-predicates #'treemacs-ignore-filter))
#+END_SRC
Now, we just identify the files in question.
2020-03-17 17:12:17 +00:00
#+BEGIN_SRC emacs-lisp
2020-03-18 16:48:47 +00:00
(setq treemacs-file-ignore-extensions '(;; LaTeX
"aux"
"ptc"
"fdb_latexmk"
"fls"
"synctex.gz"
"toc"
;; LaTeX - glossary
"glg"
"glo"
"gls"
"glsdefs"
"ist"
"acn"
"acr"
"alg"
;; LaTeX - pgfplots
"mw"
;; LaTeX - pdfx
"pdfa.xmpi"
))
(setq treemacs-file-ignore-globs '(;; LaTeX
"*/_minted-*"
;; AucTeX
"*/.auctex-auto"
"*/_region_.log"
2020-03-23 03:00:23 +00:00
"*/_region_.tex"))
#+END_SRC
2020-02-29 11:09:06 +00:00
** Miscellaneous
*** calc
Radians are just better
#+BEGIN_SRC emacs-lisp
2020-04-12 05:47:21 +00:00
(setq calc-angle-mode 'rad ;; radians are rad
calc-algebraic-mode t ;; allows '2*x instead of 'x<RET>2*
calc-symbolic-mode t) ;; keeps stuff like √2 irrational for as long as possible
(after! calctex
(setq calctex-format-latex-header (concat calctex-format-latex-header
"\n\\usepackage{arevmath}")))
(add-hook 'calc-mode-hook #'calctex-mode)
#+END_SRC
*** electric pair mode
We want this everywhere
#+BEGIN_SRC emacs-lisp
(electric-pair-mode t)
#+END_SRC
*** ispell
2020-03-19 09:00:06 +00:00
Let's get a nice big dictionary from [[http://app.aspell.net/create][SCOWL Custom List/Dictionary Creator]] with
the following configuration
- size :: 80 (huge)
- spellings :: British(-ise) and Australian
- spellling variants level :: 0
- diacritics :: keep
- extra lists :: hacker, roman numerals
#+BEGIN_SRC emacs-lisp
(setq ispell-dictionary "en_GBs_au_SCOWL_80_0_k_hr")
2020-03-19 09:00:06 +00:00
#+END_SRC
Oh, and by the way, if ~company-ispell-dictionary~ is ~nil~, then
2020-03-28 04:18:24 +00:00
~ispell-complete-word-dict~ is used instead, which once again when ~nil~ is
~ispell-alternate-dictionary~, which at the moment maps to a plaintext version of
the above.
2020-03-19 09:00:06 +00:00
It seems reasonable to want to keep an eye on my personal dict, let's have it
nearby (also means that if I change the 'main' dictionary I keep my addition).
#+BEGIN_SRC emacs-lisp
(setq ispell-personal-dictionary (expand-file-name ".hunspell_personal" doom-private-dir))
#+END_SRC
*** spray
Let's make this suit me slightly better.
#+BEGIN_SRC emacs-lisp
(setq spray-wpm 500
spray-height 700)
#+END_SRC
*** theme magic
Let's automatically update terminals on theme change
#+BEGIN_SRC emacs-lisp
(add-hook 'doom-load-theme-hook 'theme-magic-from-emacs)
#+END_SRC
*** wttrin
Set the default city. It's initially ~Taipei~ but I find the IP-locating that's
done perfectly acceptable, so let's make that happen.
2020-03-15 16:31:28 +00:00
#+BEGIN_SRC emacs-lisp
(setq wttrin-default-cities '(""))
2020-03-15 16:31:28 +00:00
#+END_SRC
2020-04-09 17:15:17 +00:00
*** elcord
#+BEGIN_SRC emacs-lisp
(setq elcord-use-major-mode-as-main-icon t)
#+END_SRC
* Language configuration
*** File Templates
For some file types, we overwrite defaults in the [[file:./snippets][snippets]] directory, others
need to have a template assigned.
#+BEGIN_SRC emacs-lisp
(set-file-template! "\\.tex$" :trigger "__" :mode 'latex-mode)
#+END_SRC
** Org Mode
*** System config
Org mode isn't recognised as it's own mime type by default, but that can easily
be changed with the following file. For system-wide changes try
~~/usr/share/mime/packages/org.xml~.
#+BEGIN_SRC xml :tangle ~/.local/share/mime/packages/org.xml
<?xml version="1.0" encoding="utf-8"?>
<mime-info xmlns='http://www.freedesktop.org/standards/shared-mime-info'>
<mime-type type="text/org">
<comment>Emacs Org-mode File</comment>
<glob pattern="*.org"/>
<alias type="text/org"/>
</mime-type>
</mime-info>
#+END_SRC
What's nice is that Papirus [[https://github.com/PapirusDevelopmentTeam/papirus-icon-theme/commit/a10fb7f2423d5e30b9c4477416ccdc93c4f3849d][now]] has an icon for =text/org=.
One simply needs to refresh their mime database
2020-03-23 02:59:27 +00:00
#+BEGIN_SRC shell :results silent
update-mime-database ~/.local/share/mime
#+END_SRC
Then set emacs as the default editor
2020-03-23 02:59:27 +00:00
#+BEGIN_SRC shell :results silent
xdg-mime default emacs.desktop text/org
#+END_SRC
*** Behaviour
2020-03-23 11:07:40 +00:00
**** Tweaking defaults
#+BEGIN_SRC emacs-lisp
(setq org-directory "~/.org" ; let's put files here
org-use-property-inheritance t ; it's convenient to have properties inherited
org-log-done 'time ; having the time a item is done sounds convininet
org-list-allow-alphabetical t ; have a. A. a) A) list bullets
org-export-in-background t ; run export processes in external emacs process
org-catch-invisible-edits 'smart) ; try not to accidently do weird stuff in invisible regions
#+END_SRC
2020-03-23 11:07:40 +00:00
I also like the ~:comments~ header-argument, so let's make that a default.
#+BEGIN_SRC emacs-lisp
(setq org-babel-default-header-args '((:session . "none")
(:results . "replace")
(:exports . "code")
(:cache . "no")
(:noweb . "no")
(:hlines . "no")
(:tangle . "no")
(:comments . "link")))
#+END_SRC
**** Extra functionality
Let's also make creating an org buffer just that little bit easier.
#+BEGIN_SRC emacs-lisp
(evil-define-command evil-buffer-org-new (count file)
"Creates a new ORG buffer replacing the current window, optionally
editing a certain FILE"
:repeat nil
(interactive "P<f>")
(if file
(evil-edit file)
(let ((buffer (generate-new-buffer "*new org*")))
(set-window-buffer nil buffer)
(with-current-buffer buffer
(org-mode)))))
(map! :leader
(:prefix "b"
:desc "New empty ORG buffer" "o" #'evil-buffer-org-new))
#+END_SRC
2020-02-29 10:46:14 +00:00
I think it makes sense to have list bullets change with depth
#+BEGIN_SRC emacs-lisp
(setq org-list-demote-modify-bullet '(("+" . "-") ("-" . "+") ("*" . "+")))
#+END_SRC
2020-02-26 11:05:41 +00:00
Occasionally I want to cite something.
#+BEGIN_SRC emacs-lisp
(use-package! org-ref
2020-02-26 11:05:41 +00:00
:after org
:config
(setq org-ref-completion-library 'org-ref-ivy-cite))
#+END_SRC
It's also nice to be able to use ~cdlatex~.
#+BEGIN_SRC emacs-lisp
(after! org (add-hook 'org-mode-hook 'turn-on-org-cdlatex))
#+END_SRC
At some point in the future it could be good to investigate [[https://scripter.co/splitting-an-org-block-into-two/][splitting org blocks]].
Likewise [[https://archive.casouri.cat/note/2020/insert-math-symbol-in-emacs/][this]] looks good for symbols.
2020-03-23 03:01:31 +00:00
My spelling is atrocious, so let's get flycheck going.
#+BEGIN_SRC emacs-lisp
(after! org (add-hook 'org-mode-hook 'turn-on-flyspell))
#+END_SRC
**** Super agenda
#+BEGIN_SRC emacs-lisp
(use-package! org-super-agenda
:commands (org-super-agenda-mode))
(after! org-agenda
(org-super-agenda-mode))
(setq org-agenda-skip-scheduled-if-done t
org-agenda-skip-deadline-if-done t
org-agenda-include-deadlines t
org-agenda-block-separator nil
org-agenda-compact-blocks t)
(setq org-agenda-custom-commands
'(("o" "Overview"
((agenda "" ((org-agenda-span 'day)
(org-super-agenda-groups
'((:name "Today"
:time-grid t
:date today
:todo "TODAY"
:scheduled today
:order 1)))))
(alltodo "" ((org-agenda-overriding-header "")
(org-super-agenda-groups
'((:name "Next to do"
:todo "NEXT"
:order 1)
(:name "Important"
:tag "Important"
:priority "A"
:order 6)
(:name "Due Today"
:deadline today
:order 2)
(:name "Due Soon"
:deadline future
:order 8)
(:name "Overdue"
:deadline past
:face error
:order 7)
(:name "Assignments"
:tag "Assignment"
:order 10)
(:name "Issues"
:tag "Issue"
:order 12)
(:name "Projects"
:tag "Project"
:order 14)
(:name "Emacs"
:tag "Emacs"
:order 13)
(:name "Research"
:tag "Research"
:order 15)
(:name "To read"
:tag "Read"
:order 30)
(:name "Waiting"
:todo "WAITING"
:order 20)
(:name "Trivial"
:priority<= "E"
:tag ("Trivial" "Unimportant")
:todo ("SOMEDAY" )
:order 90)
(:discard (:tag ("Chore" "Routine" "Daily")))))))))))
#+END_SRC
**** Capture
Let's setup some org-capture templates
#+BEGIN_SRC emacs-lisp :noweb yes
(use-package! doct
:commands (doct))
(after! org-capture
<<prettify-capture>>
(setq +org-capture-uni-units (split-string (f-read-text "~/.org/.uni-units")))
(add-transient-hook! 'org-capture-select-template
(setq org-capture-templates
(doct `((,(format "%s\tPersonal todo" (all-the-icons-octicon "checklist" :face 'all-the-icons-green :v-adjust 0.01))
:keys "t"
:file +org-capture-todo-file
:prepend t
:headline "Inbox"
:type entry
:template ("* TODO %?"
"%i %a")
)
(,(format "%s\tPersonal note" (all-the-icons-faicon "sticky-note-o" :face 'all-the-icons-green :v-adjust 0.01))
:keys "n"
:file +org-capture-todo-file
:prepend t
:headline "Inbox"
:type entry
:template ("* %?"
"%i %a")
)
(,(format "%s\tUniversity" (all-the-icons-faicon "graduation-cap" :face 'all-the-icons-purple :v-adjust 0.01))
:keys "u"
:file +org-capture-todo-file
:headline "University"
:unit-prompt ,(format "%%^{Unit|%s}" (string-join +org-capture-uni-units "|"))
:prepend t
:type entry
:children ((,(format "%s\tTest" (all-the-icons-material "timer" :face 'all-the-icons-red :v-adjust 0.01))
:keys "t"
:template ("* TODO [#C] %{unit-prompt} %? :uni:tests:"
"SCHEDULED: %^{Test date:}T"
"%i %a"))
(,(format "%s\tAssignment" (all-the-icons-material "library_books" :face 'all-the-icons-orange :v-adjust 0.01))
:keys "a"
:template ("* TODO [#B] %{unit-prompt} %? :uni:assignments:"
"DEADLINE: %^{Due date:}T"
"%i %a"))
(,(format "%s\tLecture" (all-the-icons-fileicon "keynote" :face 'all-the-icons-orange :v-adjust 0.01))
:keys "l"
:template ("* TODO [#C] %{unit-prompt} %? :uni:lecture:"
"%i %a"))
(,(format "%s\tMiscellaneous task" (all-the-icons-faicon "list" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "u"
:template ("* TODO [#D] %{unit-prompt} %? :uni:"
"%i %a"))))
(,(format "%s\tEmail" (all-the-icons-faicon "envelope" :face 'all-the-icons-blue :v-adjust 0.01))
:keys "e"
:file +org-capture-todo-file
:prepend t
:headline "Inbox"
:type entry
:template ("* TODO %? :email:"
"%i %a"))
(,(format "%s\tInteresting" (all-the-icons-faicon "eye" :face 'all-the-icons-lcyan :v-adjust 0.01))
:keys "i"
:file +org-capture-todo-file
:prepend t
:headline "Interesting"
:type entry
:template ("* [ ] %{desc}%? :%{i-type}:"
"%i %a")
:children ((,(format "%s\tWebpage" (all-the-icons-faicon "globe" :face 'all-the-icons-green :v-adjust 0.01))
:keys "w"
:desc "%(org-cliplink-capture) "
:i-type "read:web"
)
(,(format "%s\tArticle" (all-the-icons-octicon "file-text" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "a"
:desc ""
:i-type "read:reaserch"
)
(,(format "%s\tInformation" (all-the-icons-faicon "info-circle" :face 'all-the-icons-blue :v-adjust 0.01))
:keys "i"
:desc ""
:i-type "read:info"
)
(,(format "%s\tIdea" (all-the-icons-material "bubble_chart" :face 'all-the-icons-silver :v-adjust 0.01))
:keys "I"
:desc ""
:i-type "idea"
)))
(,(format "%s\tTasks" (all-the-icons-octicon "inbox" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "k"
:file +org-capture-todo-file
:prepend t
:headline "Tasks"
:type entry
:template ("* TODO %? %^G%{extra}"
"%i")
:children ((,(format "%s\tGeneral Task" (all-the-icons-octicon "inbox" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "k"
:extra ""
)
(,(format "%s\tTask with deadline" (all-the-icons-material "timer" :face 'all-the-icons-orange :v-adjust -0.1))
:keys "d"
:extra "\nDEADLINE: %^{Deadline:}t"
)
(,(format "%s\tScheduled Task" (all-the-icons-octicon "calendar" :face 'all-the-icons-orange :v-adjust 0.01))
:keys "s"
:extra "\nSCHEDULED: %^{Start time:}t"
)
))
(,(format "%s\tProject" (all-the-icons-octicon "repo" :face 'all-the-icons-silver :v-adjust 0.01))
:keys "p"
:prepend t
:type entry
:headline "Inbox"
:template ("* %{time-or-todo} %?"
"%i"
"%a")
:file ""
:custom (:time-or-todo "")
:children ((,(format "%s\tProject-local todo" (all-the-icons-octicon "checklist" :face 'all-the-icons-green :v-adjust 0.01))
:keys "t"
:time-or-todo "TODO"
:file +org-capture-project-todo-file)
(,(format "%s\tProject-local note" (all-the-icons-faicon "sticky-note" :face 'all-the-icons-yellow :v-adjust 0.01))
:keys "n"
:time-or-todo "%U"
:file +org-capture-project-notes-file)
(,(format "%s\tProject-local changelog" (all-the-icons-faicon "list" :face 'all-the-icons-blue :v-adjust 0.01))
:keys "c"
:time-or-todo "%U"
:heading "Unreleased"
:file +org-capture-project-changelog-file))
)
("\tCentralised project templates"
:keys "o"
:type entry
:prepend t
:template ("* %{time-or-todo} %?"
"%i"
"%a")
:children (("Project todo"
:keys "t"
:prepend nil
:time-or-todo "TODO"
:heading "Tasks"
:file +org-capture-central-project-todo-file)
("Project note"
:keys "n"
:time-or-todo "%U"
:heading "Notes"
:file +org-capture-central-project-notes-file)
("Project changelog"
:keys "c"
:time-or-todo "%U"
:heading "Unreleased"
:file +org-capture-central-project-changelog-file))
))))))
#+END_SRC
It would also be nice to improve how the capture dialouge looks
#+NAME: prettify-capture
#+BEGIN_SRC emacs-lisp :tangle no
(defun org-capture-select-template-prettier (&optional keys)
"Select a capture template, in a prettier way than default
Lisp programs can force the template by setting KEYS to a string."
(let ((org-capture-templates
(or (org-contextualize-keys
(org-capture-upgrade-templates org-capture-templates)
org-capture-templates-contexts)
'(("t" "Task" entry (file+headline "" "Tasks")
"* TODO %?\n %u\n %a")))))
(if keys
(or (assoc keys org-capture-templates)
(error "No capture template referred to by \"%s\" keys" keys))
(org-mks org-capture-templates
"Select a capture template\n━━━━━━━━━━━━━━━━━━━━━━━━━"
"Template key: "
`(("q" ,(concat (all-the-icons-octicon "stop" :face 'all-the-icons-red :v-adjust 0.01) "\tAbort")))))))
(advice-add 'org-capture-select-template :override #'org-capture-select-template-prettier)
(defun org-mks-pretty (table title &optional prompt specials)
"Select a member of an alist with multiple keys. Prettified.
TABLE is the alist which should contain entries where the car is a string.
There should be two types of entries.
1. prefix descriptions like (\"a\" \"Description\")
This indicates that `a' is a prefix key for multi-letter selection, and
that there are entries following with keys like \"ab\", \"ax\"…
2. Select-able members must have more than two elements, with the first
being the string of keys that lead to selecting it, and the second a
short description string of the item.
The command will then make a temporary buffer listing all entries
that can be selected with a single key, and all the single key
prefixes. When you press the key for a single-letter entry, it is selected.
When you press a prefix key, the commands (and maybe further prefixes)
under this key will be shown and offered for selection.
TITLE will be placed over the selection in the temporary buffer,
PROMPT will be used when prompting for a key. SPECIALS is an
alist with (\"key\" \"description\") entries. When one of these
is selected, only the bare key is returned."
(save-window-excursion
(let ((inhibit-quit t)
(buffer (org-switch-to-buffer-other-window "*Org Select*"))
(prompt (or prompt "Select: "))
case-fold-search
current)
(unwind-protect
(catch 'exit
(while t
(setq-local evil-normal-state-cursor (list nil))
(erase-buffer)
(insert title "\n\n")
(let ((des-keys nil)
(allowed-keys '("\C-g"))
(tab-alternatives '("\s" "\t" "\r"))
(cursor-type nil))
;; Populate allowed keys and descriptions keys
;; available with CURRENT selector.
(let ((re (format "\\`%s\\(.\\)\\'"
(if current (regexp-quote current) "")))
(prefix (if current (concat current " ") "")))
(dolist (entry table)
(pcase entry
;; Description.
(`(,(and key (pred (string-match re))) ,desc)
(let ((k (match-string 1 key)))
(push k des-keys)
;; Keys ending in tab, space or RET are equivalent.
(if (member k tab-alternatives)
(push "\t" allowed-keys)
(push k allowed-keys))
(insert (propertize prefix 'face 'font-lock-comment-face) (propertize k 'face 'bold) (propertize "" 'face 'font-lock-comment-face) " " desc "…" "\n")))
;; Usable entry.
(`(,(and key (pred (string-match re))) ,desc . ,_)
(let ((k (match-string 1 key)))
(insert (propertize prefix 'face 'font-lock-comment-face) (propertize k 'face 'bold) " " desc "\n")
(push k allowed-keys)))
(_ nil))))
;; Insert special entries, if any.
(when specials
(insert "─────────────────────────\n")
(pcase-dolist (`(,key ,description) specials)
(insert (format "%s %s\n" (propertize key 'face '(bold all-the-icons-red)) description))
(push key allowed-keys)))
;; Display UI and let user select an entry or
;; a sub-level prefix.
(goto-char (point-min))
(unless (pos-visible-in-window-p (point-max))
(org-fit-window-to-buffer))
(let ((pressed (org--mks-read-key allowed-keys prompt)))
(setq current (concat current pressed))
(cond
((equal pressed "\C-g") (user-error "Abort"))
;; Selection is a prefix: open a new menu.
((member pressed des-keys))
;; Selection matches an association: return it.
((let ((entry (assoc current table)))
(and entry (throw 'exit entry))))
;; Selection matches a special entry: return the
;; selection prefix.
((assoc current specials) (throw 'exit current))
(t (error "No entry available")))))))
(when buffer (kill-buffer buffer))))))
(advice-add 'org-mks :override #'org-mks-pretty)
#+END_SRC
The [[file:~/.emacs.d/bin/org-capture][org-capture bin]] is rather nice, but I'd be nicer with a smaller frame, and
no modeline.
#+BEGIN_SRC emacs-lisp
(setf (alist-get 'height +org-capture-frame-parameters) 15)
;; (alist-get 'name +org-capture-frame-parameters) "❖ Capture") ;; ATM hardcoded in other places, so changing breaks stuff
(setq +org-capture-fn
(lambda ()
(interactive)
(set-window-parameter nil 'mode-line-format 'none)
(org-capture)))
#+END_SRC
**** Nicer headings
Thanks to alphapapa's [[https://github.com/alphapapa/unpackaged.el#export-to-html-with-useful-anchors][unpackaged.el]].
Unfortunately this currently seems to break some of the other modifications I've made.
#+BEGIN_SRC emacs-lisp :tangle no
(define-minor-mode unpackaged/org-export-html-with-useful-ids-mode
"Attempt to export Org as HTML with useful link IDs.
Instead of random IDs like \"#orga1b2c3\", use heading titles,
made unique when necessary."
:global t
(if unpackaged/org-export-html-with-useful-ids-mode
(advice-add #'org-export-get-reference :override #'unpackaged/org-export-get-reference)
(advice-remove #'org-export-get-reference #'unpackaged/org-export-get-reference)))
(defun unpackaged/org-export-get-reference (datum info)
"Like `org-export-get-reference', except uses heading titles instead of random numbers."
(let ((cache (plist-get info :internal-references)))
(or (car (rassq datum cache))
(let* ((crossrefs (plist-get info :crossrefs))
(cells (org-export-search-cells datum))
;; Preserve any pre-existing association between
;; a search cell and a reference, i.e., when some
;; previously published document referenced a location
;; within current file (see
;; `org-publish-resolve-external-link').
;;
;; However, there is no guarantee that search cells are
;; unique, e.g., there might be duplicate custom ID or
;; two headings with the same title in the file.
;;
;; As a consequence, before re-using any reference to
;; an element or object, we check that it doesn't refer
;; to a previous element or object.
(new (or (cl-some
(lambda (cell)
(let ((stored (cdr (assoc cell crossrefs))))
(when stored
(let ((old (org-export-format-reference stored)))
(and (not (assoc old cache)) stored)))))
cells)
(when (org-element-property :raw-value datum)
;; Heading with a title
(unpackaged/org-export-new-title-reference datum cache))
;; NOTE: This probably breaks some Org Export
;; feature, but if it does what I need, fine.
(org-export-format-reference
(org-export-new-reference cache))))
(reference-string new))
;; Cache contains both data already associated to
;; a reference and in-use internal references, so as to make
;; unique references.
(dolist (cell cells) (push (cons cell new) cache))
;; Retain a direct association between reference string and
;; DATUM since (1) not every object or element can be given
;; a search cell (2) it permits quick lookup.
(push (cons reference-string datum) cache)
(plist-put info :internal-references cache)
reference-string))))
(defun unpackaged/org-export-new-title-reference (datum cache)
"Return new reference for DATUM that is unique in CACHE."
(cl-macrolet ((inc-suffixf (place)
`(progn
(string-match (rx bos
(minimal-match (group (1+ anything)))
(optional "--" (group (1+ digit)))
eos)
,place)
;; HACK: `s1' instead of a gensym.
(-let* (((s1 suffix) (list (match-string 1 ,place)
(match-string 2 ,place)))
(suffix (if suffix
(string-to-number suffix)
0)))
(setf ,place (format "%s--%s" s1 (cl-incf suffix)))))))
(let* ((title (org-element-property :raw-value datum))
(ref (url-hexify-string (substring-no-properties title)))
(parent (org-element-property :parent datum)))
(while (--any (equal ref (car it))
cache)
;; Title not unique: make it so.
(if parent
;; Append ancestor title.
(setf title (concat (org-element-property :raw-value parent)
"--" title)
ref (url-hexify-string (substring-no-properties title))
parent (org-element-property :parent parent))
;; No more ancestors: add and increment a number.
(inc-suffixf ref)))
ref)))
#+END_SRC
**** Nicer ~org-return~
Once again, from [[https://github.com/alphapapa/unpackaged.el#org-return-dwim][unpackaged.el]]
#+BEGIN_SRC emacs-lisp
(after! org
(defun unpackaged/org-element-descendant-of (type element)
"Return non-nil if ELEMENT is a descendant of TYPE.
TYPE should be an element type, like `item' or `paragraph'.
ELEMENT should be a list like that returned by `org-element-context'."
;; MAYBE: Use `org-element-lineage'.
(when-let* ((parent (org-element-property :parent element)))
(or (eq type (car parent))
(unpackaged/org-element-descendant-of type parent))))
;;;###autoload
(defun unpackaged/org-return-dwim (&optional default)
"A helpful replacement for `org-return-indent'. With prefix, call `org-return-indent'.
On headings, move point to position after entry content. In
lists, insert a new item or end the list, with checkbox if
appropriate. In tables, insert a new row or end the table."
;; Inspired by John Kitchin: http://kitchingroup.cheme.cmu.edu/blog/2017/04/09/A-better-return-in-org-mode/
(interactive "P")
(if default
(org-return t)
(cond
;; Act depending on context around point.
;; NOTE: I prefer RET to not follow links, but by uncommenting this block, links will be
;; followed.
;; ((eq 'link (car (org-element-context)))
;; ;; Link: Open it.
;; (org-open-at-point-global))
((org-at-heading-p)
;; Heading: Move to position after entry content.
;; NOTE: This is probably the most interesting feature of this function.
(let ((heading-start (org-entry-beginning-position)))
(goto-char (org-entry-end-position))
(cond ((and (org-at-heading-p)
(= heading-start (org-entry-beginning-position)))
;; Entry ends on its heading; add newline after
(end-of-line)
(insert "\n\n"))
(t
;; Entry ends after its heading; back up
(forward-line -1)
(end-of-line)
(when (org-at-heading-p)
;; At the same heading
(forward-line)
(insert "\n")
(forward-line -1))
;; FIXME: looking-back is supposed to be called with more arguments.
(while (not (looking-back (rx (repeat 3 (seq (optional blank) "\n")))))
(insert "\n"))
(forward-line -1)))))
((org-at-item-checkbox-p)
;; Checkbox: Insert new item with checkbox.
(org-insert-todo-heading nil))
((org-in-item-p)
;; Plain list. Yes, this gets a little complicated...
(let ((context (org-element-context)))
(if (or (eq 'plain-list (car context)) ; First item in list
(and (eq 'item (car context))
(not (eq (org-element-property :contents-begin context)
(org-element-property :contents-end context))))
(unpackaged/org-element-descendant-of 'item context)) ; Element in list item, e.g. a link
;; Non-empty item: Add new item.
(org-insert-item)
;; Empty item: Close the list.
;; TODO: Do this with org functions rather than operating on the text. Can't seem to find the right function.
(delete-region (line-beginning-position) (line-end-position))
(insert "\n"))))
((when (fboundp 'org-inlinetask-in-task-p)
(org-inlinetask-in-task-p))
;; Inline task: Don't insert a new heading.
(org-return t))
((org-at-table-p)
(cond ((save-excursion
(beginning-of-line)
;; See `org-table-next-field'.
(cl-loop with end = (line-end-position)
for cell = (org-element-table-cell-parser)
always (equal (org-element-property :contents-begin cell)
(org-element-property :contents-end cell))
while (re-search-forward "|" end t)))
;; Empty row: end the table.
(delete-region (line-beginning-position) (line-end-position))
(org-return t))
(t
;; Non-empty row: call `org-return-indent'.
(org-return t))))
(t
;; All other cases: call `org-return-indent'.
(org-return t)))))
(advice-add #'org-return-indent :override #'unpackaged/org-return-dwim))
#+END_SRC
*** Visuals
**** In editor
***** Font Display
Mixed pitch is great. As is ~+org-pretty-mode~, let's use them.
#+BEGIN_SRC emacs-lisp
(add-hook! 'org-mode-hook #'+org-pretty-mode #'mixed-pitch-mode)
#+END_SRC
2020-01-09 17:58:01 +00:00
Earlier I loaded the ~org-pretty-table~ package, let's enable it everywhere!
#+BEGIN_SRC emacs-lisp
(setq global-org-pretty-table-mode t)
#+END_SRC
2020-03-14 15:30:49 +00:00
Let's make headings a bit bigger
#+BEGIN_SRC emacs-lisp
(custom-set-faces!
'(outline-1 :weight extra-bold :height 1.2)
'(outline-2 :weight bold :height 1.12)
'(outline-3 :weight bold :height 1.1)
'(outline-4 :weight semi-bold :height 1.08)
'(outline-5 :weight semi-bold :height 1.05)
'(outline-6 :weight semi-bold :height 1.02)
'(outline-8 :weight semi-bold)
'(outline-9 :weight semi-bold))
#+END_SRC
***** Symbols
2020-01-09 17:58:01 +00:00
It's also nice to change the character used for collapsed items (by default ~…~),
I think ~▾~ is better for indicating 'collapsed section'.
and add an extra ~org-bullet~ to the default list of four.
I've also added some fun alternatives, just commented out.
#+BEGIN_SRC emacs-lisp
(use-package! org-superstar ; "prettier" bullets
:hook (org-mode . org-superstar-mode))
(use-package org-fancy-priorities
:diminish
:defines org-fancy-priorities-list
:hook (org-mode . org-fancy-priorities-mode)
:config
(unless (char-displayable-p ?❗)
(setq org-fancy-priorities-list '("HIGH" "MID" "LOW" "OPTIONAL"))))
(after! org
(use-package org-pretty-tags
:config
(setq org-pretty-tags-surrogate-strings
2020-04-12 07:06:26 +00:00
'(("uni" . "🎓")
("assignment" . "📓")
("email" . "🖂")
("read" . "🕮")
("article" . "🖹")
("web" . "🌐")
("info" . "🛈")
("issue" . "🐛")
("emacs" . "ɛ")))
(org-pretty-tags-global-mode)))
(after! org
(setq org-ellipsis " ▾ "
org-superstar-headline-bullets-list '("◉" "○" "✸" "✿" "✤" "✜" "◆" "▶")
2020-04-12 05:50:29 +00:00
org-fancy-priorities-list '((?A . "⚑") ;; ASAP
(?B . "⬆") ;; High
(?C . "■") ;; Medium
(?D . "⬇") ;; Low
(?E . "❓")) ;; Optional
org-priority-faces '((?A . all-the-icons-red)
(?B . all-the-icons-orange)
(?C . all-the-icons-yellow)
(?D . all-the-icons-green)
(?E . all-the-icons-blue))
org-priority-highest ?A
2020-04-12 05:50:29 +00:00
org-priority-lowest ?E
;; org-superstar-headline-bullets-list '("" "Ⅱ" "Ⅲ" "Ⅳ" "" "Ⅵ" "Ⅶ" "Ⅷ" "Ⅸ" "")
))
2020-01-09 17:58:01 +00:00
#+END_SRC
It's also nice to make use of the unicode characters for check boxes, and other commands.
#+BEGIN_SRC emacs-lisp
(after! org
(appendq! +pretty-code-symbols
2020-01-29 13:20:41 +00:00
'(:checkbox "☐"
:pending "◼"
:checkedbox "☑"
:results "🠶"
:property "☸"
2020-03-01 13:14:06 +00:00
:properties "⚙"
:end "∎"
:options "⌥"
2020-01-29 13:20:41 +00:00
:title "𝙏"
:author "𝘼"
:date "𝘿"
2020-01-09 17:58:01 +00:00
:begin_quote ""
2020-01-29 13:20:41 +00:00
:end_quote ""
:em_dash "—"))
2020-01-09 17:58:01 +00:00
(set-pretty-symbols! 'org-mode
:merge t
2020-01-29 13:20:41 +00:00
:checkbox "[ ]"
:pending "[-]"
:checkedbox "[X]"
:results "#+RESULTS:"
:property "#+PROPERTY:"
2020-03-01 13:14:06 +00:00
:property ":PROPERTIES:"
:end ":END:"
2020-03-04 15:27:37 +00:00
:options "#+OPTIONS:"
2020-01-29 13:20:41 +00:00
:title "#+TITLE:"
:author "#+AUTHOR:"
:date "#+DATE:"
2020-01-09 17:58:01 +00:00
:begin_quote "#+BEGIN_QUOTE"
2020-01-29 13:20:41 +00:00
:end_quote "#+END_QUOTE"
:em_dash "---")
2020-01-09 17:58:01 +00:00
)
(plist-put +pretty-code-symbols :name "⁍") ; or could be good?
#+END_SRC
2020-02-16 08:13:17 +00:00
We also like ~org-fragtog~, and that wants a hook.
#+BEGIN_SRC emacs-lisp
(add-hook 'org-mode-hook 'org-fragtog-mode)
#+END_SRC
2020-02-03 05:01:57 +00:00
***** LaTeX Fragments
It's nice to customise the look of LaTeX fragments so they fit better in the
text --- like this \(\sqrt{\beta^2+3}-\sum_{\phi=1}^\infty \frac{x^\phi-1}{\Gamma(a)}\). Let's start by adding a sans font.
2020-02-03 05:01:57 +00:00
#+BEGIN_SRC emacs-lisp
(setq org-format-latex-header "\\documentclass{article}
\\usepackage[usenames]{color}
\\usepackage[T1]{fontenc}
\\usepackage{mathtools}
\\usepackage{textcomp,amssymb}
2020-02-26 11:05:41 +00:00
\\usepackage[makeroom]{cancel}
2020-02-03 05:01:57 +00:00
\\pagestyle{empty} % do not remove
% The settings below are copied from fullpage.sty
\\setlength{\\textwidth}{\\paperwidth}
\\addtolength{\\textwidth}{-3cm}
\\setlength{\\oddsidemargin}{1.5cm}
\\addtolength{\\oddsidemargin}{-2.54cm}
\\setlength{\\evensidemargin}{\\oddsidemargin}
\\setlength{\\textheight}{\\paperheight}
\\addtolength{\\textheight}{-\\headheight}
\\addtolength{\\textheight}{-\\headsep}
\\addtolength{\\textheight}{-\\footskip}
\\addtolength{\\textheight}{-3cm}
\\setlength{\\topmargin}{1.5cm}
\\addtolength{\\topmargin}{-2.54cm}
% my custom stuff
2020-02-09 00:36:59 +00:00
\\usepackage{arev}
2020-02-03 05:01:57 +00:00
\\usepackage{arevmath}")
#+END_SRC
We can either render from a ~dvi~ or ~pdf~ file, so let's benchmark ~latex~ and
~pdflatex~.
| ~latex~ time | ~pdflatex~ time |
|------------+---------------|
| 135±2 ms | 215±3 ms |
2020-02-03 05:01:57 +00:00
On the rendering side, there are two ~.dvi~-to-image convertors which I am
interested in: ~dvipng~ and ~dvisvgm~. Then with the a ~.pdf~ we have ~pdf2svg~.
For inline preview we care about speed, while for exporting we care about file
size and preffer a vector graphic.
Using the above latex expression and benchmarking lead to the following results:
| ~dvipng~ time | ~dvisvgm~ time | ~pdf2svg~ time |
|-------------+--------------+--------------|
| 89±2 ms | 178±2 ms | 12±2 ms |
Now let's combine this to see what's best
| Tool chain | Total time | Resultant file size |
|--------------------+------------+---------------------|
| ~latex~ + ~dvipng~ | 226±2 ms | 7 KiB |
| ~latex~ + ~dvisvgm~ | 392±4 ms | 8 KiB |
| ~pdflatex~ + ~pdf2svg~ | 230±2 ms | 16 KiB |
2020-02-03 05:01:57 +00:00
So, let's use ~dvipng~ for previewing LaTeX fragments in-emacs, but ~dvisvgm~ for [[
Exporting to HTML][LaTeX Rendering]].
/Unfortunately: it seems that svg sizing is annoying ATM, so let's actually not do this right now./
2020-02-03 05:01:57 +00:00
As well as having a sans font, there are a few other tweaks which can make them
look better. Namely making sure that the colours switch when the theme does.
2020-02-03 05:01:57 +00:00
#+BEGIN_SRC emacs-lisp
(after! org
;; make background of fragments transparent
;; (let ((dvipng--plist (alist-get 'dvipng org-preview-latex-process-alist)))
;; (plist-put dvipng--plist :use-xcolor t)
;; (plist-put dvipng--plist :image-converter '("dvipng -D %D -bg 'transparent' -T tight -o %O %f")))
2020-02-09 15:14:21 +00:00
(add-hook! 'doom-load-theme-hook
(defun +org-refresh-latex-background ()
(plist-put! org-format-latex-options
:background
(face-attribute (or (cadr (assq 'default face-remapping-alist))
'default)
:background nil t))))
2020-02-03 05:01:57 +00:00
)
#+END_SRC
It'd be nice to make ~mhchem~ equations able to be rendered.
NB: This doesn't work at the moment.
#+BEGIN_SRC emacs-lisp
(after! org
(add-to-list 'org-latex-regexps '("\\ce" "^\\\\ce{\\(?:[^\000{}]\\|{[^\000}]+?}\\)}" 0 nil)))
#+END_SRC
***** Stolen from [[https://github.com/jkitchin/scimax][scimax]] (semi-working right now)
I want fragment justification
#+BEGIN_SRC emacs-lisp
(after! org
(defun scimax-org-latex-fragment-justify (justification)
"Justify the latex fragment at point with JUSTIFICATION.
JUSTIFICATION is a symbol for 'left, 'center or 'right."
(interactive
(list (intern-soft
(completing-read "Justification (left): " '(left center right)
nil t nil nil 'left))))
(let* ((ov (ov-at))
(beg (ov-beg ov))
(end (ov-end ov))
(shift (- beg (line-beginning-position)))
(img (overlay-get ov 'display))
(img (and (and img (consp img) (eq (car img) 'image)
(image-type-available-p (plist-get (cdr img) :type)))
img))
space-left offset)
(when (and img
;; This means the equation is at the start of the line
(= beg (line-beginning-position))
(or
(string= "" (s-trim (buffer-substring end (line-end-position))))
(eq 'latex-environment (car (org-element-context)))))
(setq space-left (- (window-max-chars-per-line) (car (image-size img)))
offset (floor (cond
((eq justification 'center)
(- (/ space-left 2) shift))
((eq justification 'right)
(- space-left shift))
(t
0))))
(when (>= offset 0)
(overlay-put ov 'before-string (make-string offset ?\ ))))))
(defun scimax-org-latex-fragment-justify-advice (beg end image imagetype)
"After advice function to justify fragments."
(scimax-org-latex-fragment-justify (or (plist-get org-format-latex-options :justify) 'left)))
(defun scimax-toggle-latex-fragment-justification ()
"Toggle if LaTeX fragment justification options can be used."
(interactive)
(if (not (get 'scimax-org-latex-fragment-justify-advice 'enabled))
(progn
(advice-add 'org--format-latex-make-overlay :after 'scimax-org-latex-fragment-justify-advice)
(put 'scimax-org-latex-fragment-justify-advice 'enabled t)
(message "Latex fragment justification enabled"))
(advice-remove 'org--format-latex-make-overlay 'scimax-org-latex-fragment-justify-advice)
(put 'scimax-org-latex-fragment-justify-advice 'enabled nil)
(message "Latex fragment justification disabled"))))
#+END_SRC
There's also this lovely equation numbering stuff I'll nick
#+BEGIN_SRC emacs-lisp
;; Numbered equations all have (1) as the number for fragments with vanilla
;; org-mode. This code injects the correct numbers into the previews so they
;; look good.
(after! org
(defun scimax-org-renumber-environment (orig-func &rest args)
"A function to inject numbers in LaTeX fragment previews."
(let ((results '())
(counter -1)
(numberp))
(setq results (loop for (begin . env) in
(org-element-map (org-element-parse-buffer) 'latex-environment
(lambda (env)
(cons
(org-element-property :begin env)
(org-element-property :value env))))
collect
(cond
((and (string-match "\\\\begin{equation}" env)
(not (string-match "\\\\tag{" env)))
(incf counter)
(cons begin counter))
((string-match "\\\\begin{align}" env)
(prog2
(incf counter)
(cons begin counter)
(with-temp-buffer
(insert env)
(goto-char (point-min))
;; \\ is used for a new line. Each one leads to a number
(incf counter (count-matches "\\\\$"))
;; unless there are nonumbers.
(goto-char (point-min))
(decf counter (count-matches "\\nonumber")))))
(t
(cons begin nil)))))
(when (setq numberp (cdr (assoc (point) results)))
(setf (car args)
(concat
(format "\\setcounter{equation}{%s}\n" numberp)
(car args)))))
(apply orig-func args))
(defun scimax-toggle-latex-equation-numbering ()
"Toggle whether LaTeX fragments are numbered."
(interactive)
(if (not (get 'scimax-org-renumber-environment 'enabled))
(progn
(advice-add 'org-create-formula-image :around #'scimax-org-renumber-environment)
(put 'scimax-org-renumber-environment 'enabled t)
(message "Latex numbering enabled"))
(advice-remove 'org-create-formula-image #'scimax-org-renumber-environment)
(put 'scimax-org-renumber-environment 'enabled nil)
(message "Latex numbering disabled.")))
(advice-add 'org-create-formula-image :around #'scimax-org-renumber-environment)
(put 'scimax-org-renumber-environment 'enabled t))
#+END_SRC
**** Exporting (general)
#+BEGIN_SRC emacs-lisp
(after! org (setq org-export-headline-levels 5)) ; I like nesting
#+END_SRC
**** Exporting to HTML
***** Custom CSS/JS
There is a fantastic exporter config ([[https://github.com/fniessen/org-html-themes][fniessen/org-html-themes]]) which we can
setup to be used with all our org files. Since most of the syntax highlighting
colours from our [[Theme]] gets used, we benefit from customising the code block style.
#+NAME: orgHtmlStyle
#+BEGIN_SRC web :exports none :tangle no
<link rel='stylesheet' type='text/css' href='https://fniessen.github.io/org-html-themes/styles/readtheorg/css/htmlize.css'/>
<link rel='stylesheet' type='text/css' href='https://fniessen.github.io/org-html-themes/styles/readtheorg/css/readtheorg.css'/>
<script src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script>
<script src='https://maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js'></script>
<script type='text/javascript' src='https://fniessen.github.io/org-html-themes/styles/lib/js/jquery.stickytableheaders.min.js'></script>
<script type='text/javascript' src='https://fniessen.github.io/org-html-themes/styles/readtheorg/js/readtheorg.js'></script>
<style>
pre.src {
background-color: var(--theme-bg);
color: var(--theme-fg);
scrollbar-color:#bbb6#9992;
scrollbar-width: thin;
margin: 0;
border: none;
}
div.org-src-container {
border-radius: 12px;
overflow: hidden;
margin-bottom: 24px;
margin-top: 1px;
border: 1px solid#e1e4e5;
}
pre.src::before {
background-color:#6666;
top: 8px;
border: none;
border-radius: 5px;
line-height: 1;
border: 2px solid var(--theme-bg);
opacity: 0;
transition: opacity 200ms;
}
pre.src:hover::before { opacity: 1; }
pre.src:active::before { opacity: 0; }
pre.example {
border-radius: 12px;
background: var(--theme-bg-alt);
color: var(--theme-fg);
}
code {
border-radius: 5px;
background:#e8e8e8;
font-size: 80%;
}
kbd {
display: inline-block;
padding: 3px 5px;
font: 80% SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;
line-height: normal;
line-height: 10px;
color:#444d56;
vertical-align: middle;
background-color:#fafbfc;
border: 1px solid#d1d5da;
border-radius: 3px;
box-shadow: inset 0 -1px 0#d1d5da;
}
table {
max-width: 100%;
overflow-x: auto;
display: block;
border-top: none;
}
a {
text-decoration: none;
background-image: linear-gradient(#d8dce9, #d8dce9);
background-position: 0% 100%;
background-repeat: no-repeat;
background-size: 0% 2px;
transition: background-size .3s;
}
\#table-of-contents a {
background-image: none;
}
a:hover, a:focus {
background-size: 100% 2px;
}
a[href^='#'] { font-variant-numeric: oldstyle-nums; }
a[href^='#']:visited { color:#3091d1; }
li .checkbox {
display: inline-block;
width: 0.9em;
height: 0.9em;
border-radius: 3px;
margin: 3px;
top: 4px;
position: relative;
}
2020-01-20 18:11:50 +00:00
li.on > .checkbox { background: var(--theme-green); box-shadow: 0 0 2px var(--theme-green); }
li.trans > .checkbox { background: var(--theme-orange); box-shadow: 0 0 2px var(--theme-orange); }
li.off > .checkbox { background: var(--theme-red); box-shadow: 0 0 2px var(--theme-red); }
li.on > .checkbox::after {
content: '';
height: 0.45em;
width: 0.225em;
-webkit-transform-origin: left top;
transform-origin: left top;
transform: scaleX(-1) rotate(135deg);
border-right: 2.8px solid#fff;
border-top: 2.8px solid#fff;
opacity: 0.9;
left: 0.10em;
top: 0.45em;
position: absolute;
}
2020-01-20 18:11:50 +00:00
li.trans > .checkbox::after {
content: '';
font-weight: bold;
font-size: 1.6em;
position: absolute;
top: 0.23em;
left: 0.09em;
width: 0.35em;
height: 0.12em;
background:#fff;
opacity: 0.9;
border-radius: 0.1em;
}
2020-01-20 18:11:50 +00:00
li.off > .checkbox::after {
content: '✖';
color:#fff;
opacity: 0.9;
position: relative;
top: -0.40rem;
left: 0.17em;
font-size: 0.75em;
}
span.timestamp {
color: #003280;
background: #647CFF44;
border-radius: 3px;
line-height: 1.25;
}
\#table-of-contents { overflow-y: auto; }
blockquote p { margin: 8px 0px 16px 0px; }
\#postamble .date { color: var(--theme-green); }
::-webkit-scrollbar { width: 10px; height: 8px; }
::-webkit-scrollbar-track { background:#9992; }
::-webkit-scrollbar-thumb { background:#ccc; border-radius: 10px; }
::-webkit-scrollbar-thumb:hover { background:#888; }
</style>
#+END_SRC
#+NAME: orgHtmlScript
We also want to make the background and foreground colours of the ~<pre>~ blocks
match out theme (they don't by default), so I scraped some code from ~emacs.stackexchange~.
#+BEGIN_SRC emacs-lisp :noweb yes
(defun my-org-inline-css-hook (exporter)
"Insert custom inline css to automatically set the
background of code to whatever theme I'm using's background"
(when (eq exporter 'html)
(setq
org-html-head-extra
(concat
org-html-head-extra
(format "
<style type=\"text/css\">
:root {
--theme-bg: %s;
--theme-bg-alt: %s;
--theme-base0: %s;
--theme-base1: %s;
--theme-base2: %s;
--theme-base3: %s;
--theme-base4: %s;
--theme-base5: %s;
--theme-base6: %s;
--theme-base7: %s;
--theme-base8: %s;
--theme-fg: %s;
--theme-fg-alt: %s;
--theme-grey: %s;
--theme-red: %s;
--theme-orange: %s;
--theme-green: %s;
--theme-teal: %s;
--theme-yellow: %s;
--theme-blue: %s;
--theme-dark-blue: %s;
--theme-magenta: %s;
--theme-violet: %s;
--theme-cyan: %s;
--theme-dark-cyan: %s;
}
</style>"
(doom-color 'bg)
(doom-color 'bg-alt)
(doom-color 'base0)
(doom-color 'base1)
(doom-color 'base2)
(doom-color 'base3)
(doom-color 'base4)
(doom-color 'base5)
(doom-color 'base6)
(doom-color 'base7)
(doom-color 'base8)
(doom-color 'fg)
(doom-color 'fg-alt)
(doom-color 'grey)
(doom-color 'red)
(doom-color 'orange)
(doom-color 'green)
(doom-color 'teal)
(doom-color 'yellow)
(doom-color 'blue)
(doom-color 'dark-blue)
(doom-color 'magenta)
(doom-color 'violet)
(doom-color 'cyan)
(doom-color 'dark-cyan))
"
<<orgHtmlStyle>>
"
))))
(add-hook 'org-export-before-processing-hook 'my-org-inline-css-hook)
#+END_SRC
***** Make verbatim different to code
Since we have =verbatim= and ~code~, let's use =verbatim= for key strokes.
#+BEGIN_SRC emacs-lisp
(setq org-html-text-markup-alist
'((bold . "<b>%s</b>")
(code . "<code>%s</code>")
(italic . "<i>%s</i>")
(strike-through . "<del>%s</del>")
(underline . "<span class=\"underline\">%s</span>")
(verbatim . "<kbd>%s</kbd>")))
#+END_SRC
***** Change checkbox type
We also want to use HTML checkboxes, however we want to get a bit fancier than default
#+BEGIN_SRC emacs-lisp
(after! org
(appendq! org-html-checkbox-types '((html-span .
((on . "<span class='checkbox'></span>")
(off . "<span class='checkbox'></span>")
(trans . "<span class='checkbox'></span>")))))
(setq org-html-checkbox-type 'html-span))
#+END_SRC
- [ ] I'm yet to do this
- [-] Work in progress
- [X] This is done
2020-02-03 05:01:57 +00:00
***** LaTeX Rendering
On the maths side of things, I consider ~dvisvgm~ to be a rather compelling
option. However this isn't sized very well at the moment.
#+BEGIN_SRC emacs-lisp
;; (setq-default org-html-with-latex `dvisvgm)
#+END_SRC
**** Exporting to LaTeX
I like automatically using spaced small caps for acronyms. For strings I want to
be unaffected lest's use ~;~ as a prefix to prevent the transformation --- i.e.
~;JFK~ (as one would want for two-letter geographic locations and names).
#+BEGIN_SRC emacs-lisp
;; TODO make this /only/ apply to text (i.e. not URL)
(after! org
(defun tec/org-export-latex-filter-acronym (text backend info)
(when (org-export-derived-backend-p backend 'latex)
(let ((case-fold-search nil))
(replace-regexp-in-string
";?\\b[A-Z][A-Z]+s?"
(lambda (all-caps-str)
; only \acr if str doesn't start with ";"
(if (equal (aref all-caps-str 0) 59) (substring all-caps-str 1)
(if (equal (aref all-caps-str (- (length all-caps-str) 1)) ?s)
(concat "\\textls*[70]{\\textsc{" (s-downcase (substring all-caps-str 0 -1)) "}\\protect\\scalebox{.91}[.84]{s}}")
(concat "\\textls*[70]{\\textsc{" (s-downcase all-caps-str) "}}"))))
text t t))))
(add-to-list 'org-export-filter-plain-text-functions
'tec/org-export-latex-filter-acronym)
(add-to-list 'org-export-filter-headline-functions
'tec/org-export-latex-filter-acronym))
#+END_SRC
Now for a few more adjustments.
#+BEGIN_SRC emacs-lisp
2020-03-23 03:01:56 +00:00
(after! ox-latex
(add-to-list 'org-latex-classes
'("fancy-article"
2020-03-23 03:01:56 +00:00
"\\documentclass{scrartcl}\n\
\\usepackage[T1]{fontenc}\n\
\\usepackage[osf,largesc,helvratio=0.9]{newpxtext}\n\
\\usepackage[scale=0.92]{sourcecodepro}\n\
\\usepackage[varbb]{newpxmath}\n\
\\usepackage[activate={true,nocompatibility},final,tracking=true,kerning=true,spacing=true,factor=2000]{microtype}\n\
\\usepackage{xcolor}\n\
\\setlength{\\parskip}{\\baselineskip}\n\
\\setlength{\\parindent}{0pt}"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
(add-to-list 'org-latex-classes
'("blank"
"[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
2020-02-29 11:09:06 +00:00
(add-to-list 'org-latex-classes
2020-02-26 11:05:41 +00:00
'("bmc-article"
"\\documentclass[article,code,maths]{bmc}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]
[EXTRA]"
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
2020-02-29 11:09:06 +00:00
(add-to-list 'org-latex-classes
2020-02-26 11:05:41 +00:00
'("bmc"
"\\documentclass[code,maths]{bmc}
[NO-DEFAULT-PACKAGES]
[NO-PACKAGES]
[EXTRA]"
("\\chapter{%s}" . "\\chapter*{%s}")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
2020-03-23 03:01:56 +00:00
(setq org-latex-default-class "fancy-article")
2020-02-29 11:09:06 +00:00
(add-to-list 'org-latex-packages-alist '("" "minted"))
(setq org-latex-listings 'minted)
2020-03-01 13:22:15 +00:00
(setq org-latex-minted-options
'(("frame" "lines")
("fontsize" "\\scriptsize")
("linenos" "")
("breakanywhere" "true")
("breakautoindent" "true")
("breaklines" "true")
("autogobble" "true")
("obeytabs" "true")
("python3" "true")
("breakbefore" "\\\\\\.+")
("breakafter" "\\,")
("style" "autumn")
("breaksymbol" "\\tiny\\ensuremath{\\hookrightarrow}")
("breakanywheresymbolpre" "\\,\\footnotesize\\ensuremath{{}_{\\rfloor}}")
("breakbeforesymbolpre" "\\,\\footnotesize\\ensuremath{{}_{\\rfloor}}")
("breakaftersymbolpre" "\\,\\footnotesize\\ensuremath{{}_{\\rfloor}}")))
2020-03-23 03:01:56 +00:00
(setq org-latex-hyperref-template "\\hypersetup{
pdfauthor={%a},
pdftitle={%t},
pdfkeywords={%k},
pdfsubject={%d},
pdfcreator={%c},
pdflang={%L},
breaklinks=true,
colorlinks=true,
linkcolor=,
urlcolor=blue!70!green,
citecolor=green!60!blue\n}
\\urlstyle{same}\n")
2020-02-29 11:09:06 +00:00
(setq org-latex-pdf-process
'("latexmk -shell-escape -interaction=nonstopmode -f -pdf -output-directory=%o %f")))
#+END_SRC
2020-01-20 18:15:09 +00:00
**** Exporting to Beamer
It's nice to use a different theme
#+BEGIN_SRC emacs-lisp
(setq org-beamer-theme "[progressbar=foot]metropolis")
#+END_SRC
Then customise it a bit
#+BEGIN_SRC emacs-lisp
#+END_SRC
And I think that it's natural to divide a presentation into sections, e.g.
Introduction, Overview... so let's set bump up the headline level that becomes a
frame from ~1~ to ~2~.
#+BEGIN_SRC emacs-lisp
(setq org-beamer-frame-level 2)
2020-01-20 18:17:20 +00:00
#+END_SRC
**** Exporting to GFM
We just need to load ~ox-gfm~ for org-mode documents
#+BEGIN_SRC emacs-lisp
(eval-after-load "org"
'(require 'ox-gfm nil t))
#+END_SRC
2020-01-09 18:02:54 +00:00
*** Babel
2020-02-09 03:06:01 +00:00
Doom lazy-loads babel languages, with is lovely.
We need to tell babel to use python3. Who uses python2 anymore anyway? And why
2020-01-20 18:17:00 +00:00
doesn't ~python~ refer to the latest version!?
#+BEGIN_SRC emacs-lisp
(setq org-babel-python-command "python3")
#+END_SRC
We also like autocompletion here
#+BEGIN_SRC emacs-lisp
(defun tec-org-python ()
(if (eq major-mode 'python-mode)
(progn (anaconda-mode t)
(company-mode t)))
)
(add-hook 'org-src-mode-hook 'tec-org-python)
#+END_SRC
2020-01-09 18:03:18 +00:00
*** ESS
We don't want ~R~ evaluation to hang the editor, hence
#+BEGIN_SRC emacs-lisp
(setq ess-eval-visibly 'nowait)
#+END_SRC
2020-01-09 18:03:42 +00:00
Syntax highlighting is nice, so let's turn all of that on
#+BEGIN_SRC emacs-lisp
(setq ess-R-font-lock-keywords '((ess-R-fl-keyword:keywords . t)
(ess-R-fl-keyword:constants . t)
(ess-R-fl-keyword:modifiers . t)
(ess-R-fl-keyword:fun-defs . t)
(ess-R-fl-keyword:assign-ops . t)
(ess-R-fl-keyword:%op% . t)
(ess-fl-keyword:fun-calls . t)
(ess-fl-keyword:numbers . t)
(ess-fl-keyword:operators . t)
(ess-fl-keyword:delimiters . t)
(ess-fl-keyword:= . t)
(ess-R-fl-keyword:F&T . t)))
#+END_SRC
** LaTeX
2020-03-23 03:12:19 +00:00
*** To-be-implemented ideas
- Paste image from clipboard
+ Determine first folder in ~graphicspath~ if applicable
+ Ask for file name
+ Use ~xclip~ to save file to graphics folder, or current directory (whichever applies)
#+BEGIN_SRC shell :eval no
command -v xclip >/dev/null 2>&1 || { echo >&1 "no xclip"; exit 1; }
if
xclip -selection clipboard -target image/png -o >/dev/null 2>&1
then
xclip -selection clipboard -target image/png -o >$1 2>/dev/null
echo $1
else
echo "no image"
fi
#+END_SRC
+ Insert figure, with filled in details as a result (activate =yasnippet= with
filename as variable maybe?)
2020-04-09 18:06:28 +00:00
*** Compilation
#+BEGIN_SRC emacs-lisp
(setq TeX-save-query nil
TeX-show-compilation t
TeX-command-extra-options "-shell-escape")
(after! latex
(add-to-list 'TeX-command-list '("XeLaTeX" "%`xelatex%(mode)%' %t" TeX-run-TeX nil t)))
#+END_SRC
*** Snippet value
For use in the new-file template, let's set out a nice preamble we may want to use.
#+NAME: latex-nice-preable
#+BEGIN_SRC latex :tangle no
\\usepackage[pdfa,unicode=true,hidelinks]{hyperref}
\\usepackage[dvipsnames,svgnames,table,hyperref]{xcolor}
\\renewcommand{\\UrlFont}{\\ttfamily\\small}
\\usepackage[a-2b]{pdfx} % why not be archival
\\usepackage[T1]{fontenc}
\\usepackage[osf,helvratio=0.9]{newpxtext} % pallatino
\\usepackage[scale=0.92]{sourcecodepro}
\\usepackage[varbb]{newpxmath}
\\usepackage{mathtools}
\\usepackage{amssymb}
\\usepackage[activate={true,nocompatibility},final,tracking=true,kerning=true,spacing=true,factor=2000]{microtype}
% microtype makes text look nicer
\\usepackage{graphicx} % include graphics
\\usepackage{grffile} % fix allowed graphicx filenames
\\usepackage{booktabs} % nice table rules
#+END_SRC
Then let's bind the content to a function, and define some nice helpers.
#+BEGIN_SRC emacs-lisp :noweb yes
(setq tec/yas-latex-template-preamble "
<<latex-nice-preable>>
")
(defun tec/yas-latex-get-class-choice ()
"Prompt user for LaTeX class choice"
(setq tec/yas-latex-class-choice (ivy-read "Select document class: " '("article" "scrartcl" "bmc") :def "bmc")))
(defun tec/yas-latex-preamble-if ()
"Based on class choice prompt for insertion of default preamble"
(if (equal tec/yas-latex-class-choice "bmc") 'nil
(eq (read-char-choice "Include default preamble? [Type y/n]" '(?y ?n)) ?y)))
#+END_SRC
2020-03-14 16:26:06 +00:00
*** Editor visuals
2020-03-23 03:06:55 +00:00
Once again, /all hail mixed pitch mode!/
#+BEGIN_SRC emacs-lisp
(add-hook 'LaTeX-mode-hook #'mixed-pitch-mode)
#+END_SRC
2020-03-14 16:26:06 +00:00
Let's enhance ~TeX-fold-math~ a bit
#+BEGIN_SRC emacs-lisp
2020-04-09 18:28:04 +00:00
(after! latex
(setcar (assoc "⋆" LaTeX-fold-math-spec-list) "★")) ;; make \star bigger
2020-03-14 16:26:06 +00:00
(setq TeX-fold-math-spec-list
2020-04-09 18:06:28 +00:00
`(;; missing/better symbols
2020-03-14 16:26:06 +00:00
("≤" ("le"))
("≥" ("ge"))
("≠" ("ne"))
;; conviniance shorts
("" ("left"))
("" ("right"))
;; private macros
("" ("RR"))
("" ("NN"))
("" ("ZZ"))
("" ("QQ"))
("" ("CC"))
("" ("PP"))
("" ("HH"))
("𝔼" ("EE"))
("𝑑" ("dd"))
2020-03-16 13:28:37 +00:00
;; known commands
2020-03-14 16:26:06 +00:00
("" ("phantom"))
2020-03-30 05:43:51 +00:00
("❪{1}{2}❫" ("frac"))
2020-04-09 18:06:28 +00:00
(,(lambda (arg) (concat "√" (TeX-fold-parenthesize-as-neccesary arg))) ("sqrt"))
(,(lambda (arg) (concat "⭡" (TeX-fold-parenthesize-as-neccesary arg))) ("vec"))
2020-03-14 16:26:06 +00:00
("{1}" ("text"))
2020-03-16 13:28:37 +00:00
;; private commands
2020-03-14 16:26:06 +00:00
("|{1}|" ("abs"))
("‖{1}‖" ("norm"))
("⌊{1}⌋" ("floor"))
("⌈{1}⌉" ("ceil"))
("⌊{1}⌉" ("round"))
2020-03-30 05:43:51 +00:00
("𝑑{1}/𝑑{2}" ("dv"))
("∂{1}/∂{2}" ("pdv"))
;; fancification
("{1}" ("mathrm"))
2020-04-09 18:06:28 +00:00
(,(lambda (word) (string-offset-roman-chars 119743 word)) ("mathbf"))
(,(lambda (word) (string-offset-roman-chars 119951 word)) ("mathcal"))
(,(lambda (word) (string-offset-roman-chars 120003 word)) ("mathfrak"))
(,(lambda (word) (string-offset-roman-chars 120055 word)) ("mathbb"))
(,(lambda (word) (string-offset-roman-chars 120159 word)) ("mathsf"))
(,(lambda (word) (string-offset-roman-chars 120367 word)) ("mathtt"))
2020-03-16 13:28:37 +00:00
)
TeX-fold-macro-spec-list
'(
;; as the defaults
("[f]" ("footnote" "marginpar"))
("[c]" ("cite"))
("[l]" ("label"))
("[r]" ("ref" "pageref" "eqref"))
("[i]" ("index" "glossary"))
("..." ("dots"))
("{1}" ("emph" "textit" "textsl" "textmd" "textrm" "textsf" "texttt"
"textbf" "textsc" "textup"))
;; tweaked defaults
("©" ("copyright"))
("®" ("textregistered"))
("™" ("texttrademark"))
("[1]:||►" ("item"))
("❡❡ {1}" ("part" "part*"))
("❡ {1}" ("chapter" "chapter*"))
("§ {1}" ("section" "section*"))
("§§ {1}" ("subsection" "subsection*"))
("§§§ {1}" ("subsubsection" "subsubsection*"))
("¶ {1}" ("paragraph" "paragraph*"))
("¶¶ {1}" ("subparagraph" "subparagraph*"))
;; extra
("⬖ {1}" ("begin"))
("⬗ {1}" ("end"))
2020-03-14 16:26:06 +00:00
))
2020-03-30 05:43:51 +00:00
(defun string-offset-roman-chars (offset word)
"Shift the codepoint of each charachter in WORD by OFFSET with an extra -6 shift if the letter is lowercase"
(apply 'string
(mapcar (lambda (c) (+ (if (>= c 97) (- c 6) c) offset)) word)))
2020-04-09 18:06:28 +00:00
(defun TeX-fold-parenthesize-as-neccesary (tokens &optional suppress-left suppress-right)
"Add ❪ ❫ parenthesis as if multiple LaTeX tokens appear to be present"
(if (string-match-p "^\\\\?\\w+$" tokens) tokens
(concat (if suppress-left "" "❪")
tokens
(if suppress-right "" "❫"))))
2020-03-14 16:26:06 +00:00
#+END_SRC
2020-03-15 16:19:17 +00:00
Some local keybindings to make life a bit easier
#+BEGIN_SRC emacs-lisp
(after! tex
(map!
:map LaTeX-mode-map
:ei [C-return] #'LaTeX-insert-item
;; normal stuff here
:localleader
:desc "View" "v" #'TeX-view)
2020-03-15 16:19:17 +00:00
(setq TeX-electric-math '("\\(" . "")))
#+END_SRC
2020-03-14 16:26:06 +00:00
Maths deliminators can be de-emphasised a bit
#+BEGIN_SRC emacs-lisp
;; Making \( \) less visible
(defface unimportant-latex-face
'((t
2020-03-15 16:19:17 +00:00
:inherit font-lock-comment-face :family "Overpass" :weight light))
2020-03-14 16:26:06 +00:00
"Face used to make \\(\\), \\[\\] less visible."
:group 'LaTeX-math)
(font-lock-add-keywords
'latex-mode
`((,(rx (and "\\" (any "()[]"))) 0 'unimportant-latex-face prepend))
'end)
(font-lock-add-keywords
'latex-mode
`((,"\\\\[[:word:]]+" 0 'font-lock-keyword-face prepend))
'end)
#+END_SRC
And enable shell escape for the preview
#+BEGIN_SRC emacs-lisp
(setq preview-LaTeX-command '("%`%l \"\\nonstopmode\\nofiles\
\\PassOptionsToPackage{" ("," . preview-required-option-list) "}{preview}\
\\AtBeginDocument{\\ifx\\ifPreview\\undefined"
preview-default-preamble "\\fi}\"%' \"\\detokenize{\" %t \"}\""))
#+END_SRC
2020-03-15 16:19:17 +00:00
*** CDLaTeX
The symbols and modifies are very nice by default, but could do with a bit of
fleshing out. Let's change the prefix to a key which is similarly rarely used,
but more convinient, like =;=.
#+BEGIN_SRC emacs-lisp
(after! cdlatex
(setq ;; cdlatex-math-symbol-prefix ?\; ;; doesn't work at the moment :(
cdlatex-math-symbol-alist
'( ;; adding missing functions to 3rd level symbols
(?_ ("\\downarrow" "" "\\inf"))
(?^ ("\\uparrow" "" "\\sup"))
(?k ("\\kappa" "" "\\ker"))
(?m ("\\mu" "" "\\lim"))
(?c ("" "\\circ" "\\cos"))
(?d ("\\delta" "\\partial" "\\dim"))
(?D ("\\Delta" "\\nabla" "\\deg"))
;; no idea why \Phi isnt on 'F' in first place, \phi is on 'f'.
(?F ("\\Phi"))
;; now just conveniance
(?. ("\\cdot" "\\dots"))
(?: ("\\vdots" "\\ddots"))
(?* ("\\times" "\\star" "\\ast")))
cdlatex-math-modify-alist
'( ;; my own stuff
(?B "\\mathbb" nil t nil nil)
(?a "\\abs" nil t nil nil))))
2020-03-15 16:19:17 +00:00
#+END_SRC
*** SyncTeX
#+BEGIN_SRC emacs-lisp
(after! tex
(add-to-list 'TeX-view-program-list '("Evince" "evince %o"))
(add-to-list 'TeX-view-program-selection '(output-pdf "Evince")))
#+END_SRC
2020-01-09 18:03:42 +00:00
** R
*** Editor Visuals
#+BEGIN_SRC emacs-lisp
(after! ess-r-mode
(appendq! +pretty-code-symbols
2020-02-03 05:03:39 +00:00
'(:assign "⟵"
:multiply "×"))
2020-01-09 18:03:42 +00:00
(set-pretty-symbols! 'ess-r-mode
;; Functional
:def "function"
;; Types
:null "NULL"
:true "TRUE"
:false "FALSE"
:int "int"
:floar "float"
:bool "bool"
;; Flow
:not "!"
:and "&&" :or "||"
:for "for"
:in "%in%"
:return "return"
;; Other
2020-02-03 05:03:39 +00:00
:assign "<-"
:multiply "%*%"))
2020-01-09 18:03:42 +00:00
#+END_SRC
2020-02-03 05:04:00 +00:00
** hledger
~ledger-mode~ is great and all, but ~hledger~ seems to be more actively maintained.
For example, from 2018--2020, the most prolific contributor to ~ledger~ produced
31 commits. For ~hledger~ this statistic is 1800 commits. In addition, over the
last decade, ~ledger~ seems to have lost steam, while ~hledger~ seems as actively
developed as ever. From this basic comparison ~hledger~ looks to have a more
promising outlook. It also has a few extra nicities that ~ledger~ doesn't, but is
2020-02-17 08:16:56 +00:00
a little slower (~haskell~ vs. ~c++~).
2020-02-03 05:04:00 +00:00
Since this uses the same format, and ~ledger-mode~ is well integrated into emacs,
2020-02-17 08:16:56 +00:00
and produced by John Wiegley --- author of ~ledger~ and current Emacs maintainer
2020-02-03 05:04:00 +00:00
--- using this seems like a good idea. Thankfully we can, with a little modification.
#+BEGIN_SRC emacs-lisp
(setq ledger-mode-should-check-version nil
ledger-report-links-in-register nil
ledger-binary-path "hledger")
#+END_SRC
** Markdown
Let's use mixed pitch, because it's great
#+BEGIN_SRC emacs-lisp
(add-hook! (gfm-mode markdown-mode) #'mixed-pitch-mode)
#+END_SRC
Most of the time when I write markdown, it's going into some app/website which
will do it's own line wrapping, hence we /only/ want to use visual line wrapping. No hard stuff.
#+BEGIN_SRC emacs-lisp
(add-hook! (gfm-mode markdown-mode) #'visual-line-mode #'turn-off-auto-fill)
#+END_SRC
2020-02-03 05:04:00 +00:00
** Beancount
2020-02-14 17:25:59 +00:00
The [[https://bitbucket.org/blais/beancount/src/tip/editors/emacs/beancount.el][beancount package]] online has been put into ~./lisp~, we just need to load and
enable it for ~.beancount~ files.
2020-02-03 05:04:00 +00:00
#+BEGIN_SRC emacs-lisp
(use-package! beancount
2020-03-18 16:49:23 +00:00
:load-path "~/.config/doom/lisp"
:mode ("\\.beancount\\'" . beancount-mode)
:config
(setq beancount-electric-currency t)
2020-03-18 16:49:23 +00:00
(defun beancount-bal ()
"Run bean-report bal."
(interactive)
(let ((compilation-read-command nil))
(beancount--run "bean-report"
(file-relative-name buffer-file-name) "bal")))
;; TODO make the following *work*
:bind (:map beancount-mode-map ("S-RET" . #'beancount-align-to-previous-number)))
2020-02-03 05:04:00 +00:00
#+END_SRC
# Local variables:
# eval: (add-hook 'after-save-hook 'org-html-export-to-html t t)
# end: