This is a copy of my literate configuration for Emacs and if you’re
viewing this anywhere else, don’t! Because you can find a readable
version on my website. You can also find a source-based version with
the rest of my ~/.emacs.d
on my sourcehut.
1 Other init files #
These are in my ~/.emacs.d
and help load this main configuration.
1.1 Early init #
This creates a file, early-init.el
, in ~/.emacs.d
. This was stolen
from Protesilaos some time back. It still needs work - it’s not
tangled (by default) yet.
;;; early-init.el --- Early Init File -*- lexical-binding: t -*-
;; Copyright (c) 2021-2022 pereginator
;; Author: peregrinator <brihadeesh@protonmail.com>
;; URL: https://git.sr.ht/~peregrinator/dotfiles Version: 0.1.0
;; Package-Requires: ((emacs "28.1"))
;; This file is NOT part of GNU Emacs.
;; This file is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version. This file is distributed in
;; the hope that it will be useful, but WITHOUT ANY WARRANTY; without
;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A
;; PARTICULAR PURPOSE. See the GNU General Public License for more
;; details. You should have received a copy of the GNU General Public
;; License along with this file. If not, see
;; <http://www.gnu.org/licenses/>.
;;; Commentary:
;; Prior to Emacs 27, the `init.el' was supposed to handle the
;; initialisation of the package manager, by means of calling
;; `package-initialize'. Starting with Emacs 27, the default
;; behaviour is to start the package manager before loading the init
;; file.
;;; Code:
;; Don't initialise installed packages cause package.el sucks balls
(setq package-enable-at-startup nil)
;; Do not resize the frame at this early stage. (setq
frame-inhibit-implied-resize t)
;; Disable GUI elements ; Disable menu-bar, tool-bar, and scroll-bar.
;;(if (fboundp 'menu-bar-mode) (menu-bar-mode -1)) (if (fboundp
;;'tool-bar-mode) (tool-bar-mode -1)) (if (fboundp 'scroll-bar-mode)
;;(scroll-bar-mode -1)) (setq inhibit-splash-screen t) (setq
;;use-dialog-box nil) ; only for mouse events (setq use-file-dialog
;;nil)
(setq inhibit-startup-screen t) (setq inhibit-startup-buffer-menu t)
;; for when I upgrade to emacs28 with native compilation (setq
native-comp-async-report-warnings-errors nil)
;;; early-init.el ends here
1.2 init.el #
I’ve changed things up a little - this now includes the package
management code and the code for org
installation.
;;; init.el --- Initialization. -*- lexical-binding: t; -*-
;; Copyright (C) 2022 peregrinator
;; This file is NOT part of GNU Emacs.
;; This file is free software.
;; Author: peregrinator <brihadeesh@protonmail.com>
;; URL: https://git.sr.ht/~peregrinator/.emacs.d
;; Package-Requires: ((emacs "28.1"))
;;; Commentary:
;; This file provides the initialization configuration.
;;; Code:
;; Make emacs startup faster
(defvar startup/file-name-handler-alist file-name-handler-alist)
(setq file-name-handler-alist nil)
(defun startup/revert-file-name-handler-alist ()
"Revert file name handler alist."
(setq file-name-handler-alist startup/file-name-handler-alist))
(add-hook 'emacs-startup-hook 'startup/revert-file-name-handler-alist)
;; For performance
(setq read-process-output-max (* 1024 1024)) ;; 1mb
(setq process-adaptive-read-buffering nil)
;; Load newer .elc or .el
(setq load-prefer-newer t)
1.2.1 Package management #
Update: init.el
. See the initial org-mode installation section below
for more.
1.2.1.1 Setup straight.el
#
I’ll be using use-package
to organise and configure individual
packages into neater code blocks although the download will be handled
by straight.el
. I’ve included the org-installation here since there’s somehow always
an issue with version mismatch.
;;; Configure `straight.el'
;; fetch developmental version of `straight.el'
(setq straight-repository-branch "develop"
;; redirect all package repos and builddirs elsewhere
straight-base-dir "~/.cache/")
;; Bootstrap straight.el
(defvar bootstrap-version)
(let ((bootstrap-file
(expand-file-name "straight/repos/straight.el/bootstrap.el" "~/.cache"))
(bootstrap-version 6))
(unless (file-exists-p bootstrap-file)
(with-current-buffer
(url-retrieve-synchronously
"https://raw.githubusercontent.com/raxod502/straight.el/develop/install.el"
'silent 'inhibit-cookies)
(goto-char (point-max))
(eval-print-last-sexp)))
(load bootstrap-file nil 'nomessage))
;;; Configure straight.el (contd.)
;; make all use-package instances use straight.el
(setq straight-use-package-by-default t
;; clone depth (probably to save space)
straight-vc-git-default-clone-depth 1
;; Define when to check for package modifications,
;; for improved straight.el startup time.
straight-check-for-modifications nil
;; use elpa
straight-recipes-gnu-elpa-use-mirror t
straight-host-usernames
'((github . "brihadeesh")
(gitlab . "peregrinator")))
1.2.1.2 Install and configure use-package
#
use-package
is installed and managed by straight.el
and in turn
packages used in this config are managed/organized by
use-package
. There’s something to do with integration with use-package
on the straight.el readme
;; Install use-package with straight.el
(straight-use-package 'use-package)
DISABLED 1.2.1.3 Use-package v2 related changes #
Need to figure this out - I think maybe use-package
might not be updated
(eval-when-compile
(require 'use-package))
(require 'diminish)
(require 'bind-key)
DISABLED 1.2.1.4 Minimal package.el
setup only to browse packages #
Running package-list-packages
includes them only for browsing
(require 'package)
(add-to-list 'package-archives
'("melpa" . "https://melpa.org/packages/"))
1.2.2 Initial Org-mode installation #
I use the latest version of Org, pulled from the gnu-elpa
repositories
and have to install it early on so straight.el
/ use-package
don’t
give me trouble with version conflicts because it loads the built in
(older) version first.
;; install org & org-contrib
(straight-use-package 'org)
;; (require 'org)
(straight-use-package 'org-contrib)
;; Load configuration.org
(when (file-readable-p
(concat user-emacs-directory "configuration.org"))
(org-babel-load-file
(concat user-emacs-directory "configuration.org")))
1.2.3 End #
;;; init.el ends here
2 Header #
Just the usual header for elisp files that Emacs keeps complaining about.
;;; configuration.el --- Initialisation. -*- lexical-binding: t; -*-
;; Copyright (C) 2022 peregrinator
;; Author: peregrinator <brihadeesh@protonmail.com>
;; URL: https://git.sr.ht/~peregrinator/.emacs.d
;; Package-Requires: ((emacs "28.1"))
;; This file is NOT part of GNU Emacs.
;; This file is free software: you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published
;; by the Free Software Foundation, either version 3 of the License,
;; or (at your option) any later version. This file is distributed in
;; the hope that it will be useful, but WITHOUT ANY WARRANTY; without
;; even the implied warranty of MERCHANTABILITY or FITNESS FOR A
;; PARTICULAR PURPOSE. See the GNU General Public License for more
;; details. You should have received a copy of the GNU General Public
;; License along with this file. If not, see
;; <http://www.gnu.org/licenses/>.
;;; Commentary:
;; This file provides the initialization configuration tangled this
;; file.
;;; Code:
3 Prerequisites #
3.1 Reload Emacs configuration #
I’m not sure I understand how this works entirely but joseph8th’s repo
suggests using M-: (load-file user-init-file) RET
or evaluating that
same function interactively. I’ve modified the sanemacs reload config
function below hoping that it works but in that doesn’t happen, this
first code block can be evaluated using C-c C-c
:
(defun reload-config ()
(interactive)
(load-file user-init-file))
3.2 Ensure UTF-8 #
(set-language-environment 'utf-8)
(prefer-coding-system 'utf-8)
3.3 Whoami #
(setq user-full-name "peregrinator"
user-mail-address "brihadeesh@protonmail.com")
4 Writing #
4.1 Org-mode #
- Get the damn thing first
- Organise the thing - needs splitting into multiple code blocks.
Moved the installation to init.el
along with the straight.el
bootstrap
to avoid conflicts with the bundled version of the package. I think
this can go back to being a regular use-package
function but I’m
desperately avoiding having to debug init any further.
(require 'org)
(setq initial-major-mode 'org-mode
org-display-inline-images t
org-redisplay-inline-images t
org-image-actual-width nil
org-startup-with-inline-images "inlineimages"
org-catch-invisible-edits 'smart
org-pretty-entities t
;; sub-headings inherit properties set at parent level
;; headings
org-use-property-inheritance t
;; org-ellipsis " ▾"
;; hide markers for bold, italic, etc and trailing stars
org-hide-emphasis-markers t
;; fontify code in code blocks
org-src-fontify-natively t
org-fontify-quote-and-verse-blocks t
;; org-src-tab-acts-natively t
;; org-edit-src-content-indentation 2
org-hide-block-startup nil
org-src-preserve-indentation nil
org-edit-src-content-indentation 0
;; allow for increased space between org
;; org-cycle-separator-lines -1
;; hard indentation
;; org-adapt-indentation t
;; increase indentation by using odd header levels only
;; org-odd-levels-only t
;; org-startup-folded 'content
org-capture-bookmark nil
org-hide-leading-stars t
;; org-modern
org-tags-column -80
org-ellipsis " ▾"
org-special-ctrl-a/e t
;; org-insert-heading-respect-content t
;; display numbers instead of bullets for headings
;; org-num-mode t
;; faster (single-key) navigation in org-mode
;; type `?' for help
;; org-use-speed-commands t
)
4.1.1 Refile #
;;(setq org-modules
;; '(org-crypt
;; org-habit
;; org-bookmark
;; org-eshell
;; org-irc))
(setq org-refile-targets '((nil :maxlevel . 5)
(org-agenda-files :maxlevel . 5)))
(setq org-outline-path-complete-in-steps nil)
(setq org-refile-use-outline-path t)
;; get something like this for regular emacs bindings
;;(evil-define-key '(normal insert visual) org-mode-map (kbd "C-j") 'org-next-visible-heading)
;;(evil-define-key '(normal insert visual) org-mode-map (kbd "C-k") 'org-previous-visible-heading)
;;(evil-define-key '(normal insert visual) org-mode-map (kbd "M-j") 'org-metadown)
;;(evil-define-key '(normal insert visual) org-mode-map (kbd "M-k") 'org-metaup)
;; Replace list hyphen with dot
;; (font-lock-add-keywords 'org-mode
;; '(("^ *\\([-]\\) "
;; (0 (prog1 () (compose-region (match-beginning 1) (match-end 1) "•"))))))
4.1.2 Fixed pitch for everything code #
;; Make sure org-indent face is available
(require 'org-indent)
;; Ensure that anything that should be fixed-pitch in Org files appears that way
(set-face-attribute 'org-block nil :inherit 'fixed-pitch)
(set-face-attribute 'org-table nil :inherit 'fixed-pitch)
(set-face-attribute 'org-formula nil :inherit 'fixed-pitch)
(set-face-attribute 'org-code nil :inherit '(shadow fixed-pitch))
(set-face-attribute 'org-indent nil :inherit '(org-hide fixed-pitch))
(set-face-attribute 'org-verbatim nil :inherit '(shadow fixed-pitch))
(set-face-attribute 'org-special-keyword nil :inherit '(font-lock-comment-face fixed-pitch))
(set-face-attribute 'org-meta-line nil :inherit '(font-lock-comment-face fixed-pitch))
(set-face-attribute 'org-checkbox nil :inherit 'fixed-pitch)
4.1.3 Quick source block templates #
These can be run by typing an angle bracket with the shortcut and
hitting <TAB>
.
;; block templates
;; This is needed as of Org 9.2
(require 'org-tempo)
(add-to-list 'org-structure-template-alist '("sh" . "src sh"))
(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
(add-to-list 'org-structure-template-alist '("li" . "src lisp"))
(add-to-list 'org-structure-template-alist '("sc" . "src scheme"))
(add-to-list 'org-structure-template-alist '("r" . "src R"))
(add-to-list 'org-structure-template-alist '("py" . "src python"))
(add-to-list 'org-structure-template-alist '("lua" . "src lua"))
(add-to-list 'org-structure-template-alist '("yml" . "src yaml"))
(add-to-list 'org-structure-template-alist '("json" . "src json"))
(add-to-list 'org-structure-template-alist '("aw" . "src awk"))
This creates a unique problem wherein the auto-pairing functionality
(electric-pair-mode
) creates matching right angle bracket at the end
of the block, messing with Org syntax. This doesn’t work as intended
and needs some debugging.
;; disable electric pairing for angle bracket
(add-hook 'org-mode-hook (lambda ()
(setq-local electric-pair-inhibit-predicate
`(lambda (c)
(if (char-equal c ?<) t (,electric-pair-inhibit-predicate c)))))))
TODO 4.1.4 Babel #
This might require org-contrib
.
(org-babel-do-load-languages
'org-babel-load-languages
'((emacs-lisp . t)
(R . t)
(lisp . t)
(shell . t)
(org .t)
(awk . t)))
4.1.5 New folding backend #
This came with the Org 9.6 release on changes post. This is optimised for files that are large, and usually more than a few MB in size. I know this file is only a few kilobytes but I kinda feel it lagging once in a while. Probably some unrelated issue.
and I got the tea from the Org
(setq org-fold-core-style 'overlays)
TODO 4.1.6 Sources for agenda tasks #
Generates an agenda from wildcarded org files from the specified directory
(setq org-agenda-files
(file-expand-wildcards "~/docmuents/denotes/*.org"))
4.1.7 Tags and todo-keywords config #
Todo-keywords are things like TODO
and DONE
and so on. Tags are for
classifying stuff by the general theme of what’s being talked about.
4.1.7.1 todo-keywords #
(setq org-todo-keywords
'((sequence "TODO(t)" "|" "DISABLED(f)")
(sequence "TODO(t)" "|" "CANCELLED(c)")
(sequence "DRAFT(e)" "|" "DONE(d)")))
Add property drawer disabling source block when TODO
-state is
DISABLED
(defun peremacs/autodisable-srcblock-on-disabled ()
(interactive)
(when (equal (org-get-todo-state) "DISABLED")
(org-set-property "HEADER_ARGS" "tangle no"))
;; (org-set-property "VISIBIITY" "folded")
(unless (equal (org-get-todo-state) "DISABLED")
(org-delete-property "HEADER_ARGS")))
;; (org-delete-property "VISIBILITY")))
(add-hook 'org-after-todo-state-change-hook 'peremacs/autodisable-srcblock-on-disabled)
DISABLED 4.1.7.2 tags #
(setq org-tag-alist '((("misc" . ?m)
("emacs" . ?e)
("dotfiles" . ?d)
("work" . ?w)
("chore" . ?c)
("blog" . ?b)
)))
4.1.8 Org-capture and agenda #
Global keybinding for org-capture
;; (global-set-key (kbd "C-c l") #'org-store-link)
(global-set-key (kbd "C-c a") #'org-agenda)
(global-set-key (kbd "C-c c") #'org-capture)
This will need to be looked at carefully. Roughly, I need to work out
if I’m going to be using org-agenda
and if so, how will I be using
it. Adding tasks can be made much easier with this. I can also use
this for entering entries into org-journal
, making it a whole deal
easier. Perhaps to start off, the org-mode tutorial might be a good
place to start. I’ve also got a simple enough config from a reddit
post in my unused local elisp libs too.
DISABLED 4.1.9 em- and en-dashes #
I realised I use em-dashes a lot — this is perhaps one way to make
sure that em-dashes can be generated with double dashes in sequence. I
actually just use a remapped compose key (R_ALT
is remapped to
compose
) and compose + ---
gives me an em-dash.
;; Replace two consecutive hyphens with the en-dash
;; (add-hook 'org-mode-hook (lambda () (push '("--" . ?–) prettify-symbols-alist)))
;; Replace two consecutive hyphens with the em-dash
(add-hook 'org-mode-hook (lambda () (push '("--" . ?—) prettify-symbols-alist)))
DISABLED 4.1.10 Write org-log into drawer #
Every time I change the TODO-keywords for a heading, there’s a list entry added on top of the text under the heading with a state-change date stamp and more information. This should ensure such logs should be entered into a drawer like those that ox-hugo uses.
(setq org-log-into-drawer LOGBOOK)
4.1.11 Backlinks / org-super-links #
(use-package org-super-links
:straight (org-super-links :type git :host github :repo "toshism/org-super-links" :branch "develop")
:bind (("C-c s s" . org-super-links-link)
("C-c s l" . org-super-links-store-link)
("C-c s C-l" . org-super-links-insert-link)))
4.1.12 Display features #
In the spirit of reclaiming some semblance of organisation in this file, I’ve tried to group settings by the what aspect they change. Hopefully this continues and the rest of the Org mode configuration can be split up.
4.1.12.1 Autoindent/autofill turned on automatically #
(add-hook 'org-mode-hook 'org-indent-mode)
(setq org-indent-indentation-per-level 3)
(setq org-startup-indented t)
;; organise paragraphs automatically
(add-hook 'org-mode-hook 'turn-on-auto-fill)
4.1.12.2 Minad’s modern UI for org-mode #
Was maintaining a fork but I guess it’s too much work - should
considering getting back at it sometime. I was having issues with TODO
keywords and tags/categories being rendered absurdly small but
apparently setting org-modern-label-border
to nil should make them
full sized (see this issue). I really must consider using a
variable-pitch font for rich text and headers while restricting
fixed-pitch fonts to header arguments, source blocks and explicitly
code segments in text.
(use-package org-modern
;; currently outdated/unmaintained fork
;; :straight (:host github :repo "brihadeesh/org-modern")
:config
;; Add frame borders and window dividers
(modify-all-frames-parameters
'((right-divider-width . 10)
(internal-border-width . 5)))
(dolist (face '(window-divider
window-divider-first-pixel
window-divider-last-pixel))
(face-spec-reset-face face)
(set-face-foreground face (face-attribute 'default :background)))
(set-face-background 'fringe (face-attribute 'default :background))
;; `org-modern' specific config
(setq org-modern-star ["◉ " "○ " "● " "○ " "● " "○ " "● "]
org-modern-label-border nil)
;; enable the global mode
(global-org-modern-mode t))
4.1.12.3 Display emphasis markers on hover #
This package makes it much easier to edit Org documents when org-hide-emphasis-markers is turned on. It temporarily shows the emphasis markers around certain markup elements when you place your cursor inside of them. No more fumbling around with = and * characters!
(use-package org-appear
:hook (org-mode . org-appear-mode))
4.1.12.4 Better commenting in org-mode code-blocks #
Got this from a Stack Exchange answer to work around messed up
commenting using the default C-x C-;
command. The older/default
command messes up lines, undos, and sometimes comment syntax as well.
;; allow comment region in the code edit buffer (according to language)
(defun my-org-comment-dwim (&optional arg)
(interactive "P")
(or (org-babel-do-key-sequence-in-edit-buffer (kbd "M-;"))
(comment-dwim arg)))
;; make `C-c C-v C-x M-;' more convenient
(define-key org-mode-map
(kbd "M-;") 'my-org-comment-dwim)
4.1.12.5 TOC for org-mode files #
(use-package toc-org
:after org
:hook (org-mode . toc-org-enable))
Alternatively
(use-package org-make-toc
:hook (org-mode . org-make-toc-mode))
4.1.12.6 Convert all org-keywords/block identifiers to lowercase #
It’s always nice to see random people online that are crazy like you and are nice enough to write elisp code for the shit you need. Stolen from Kaushal Modi
(defun peremacs/lower-case-org-keywords ()
"Lower case Org keywords and block identifiers.
Example: \"#+TITLE\" -> \"#+title\"
\"#+BEGIN_EXAMPLE\" -> \"#+begin_example\"
Inspiration:
https://code.orgmode.org/bzg/org-mode/commit/13424336a6f30c50952d291e7a82906c1210daf0."
(interactive)
(save-excursion
(goto-char (point-min))
(let ((case-fold-search nil)
(count 0))
;; Match examples: "#+foo bar", "#+foo:", "=#+foo=", "~#+foo~",
;; "‘#+foo’", "“#+foo”", ",#+foo bar",
;; "#+FOO_bar<eol>", "#+FOO<eol>".
(while (re-search-forward "\\(?1:#\\+[A-Z_]+\\(?:_[[:alpha:]]+\\)*\\)\\(?:[ :=~’”]\\|$\\)" nil :noerror)
(setq count (1+ count))
(replace-match (downcase (match-string-no-properties 1)) :fixedcase nil nil 1))
(message "Lower-cased %d matches" count))))
4.2 AUCTex for LaTex editing + completion #
;; FIXME:
;; (use-package auctex
;; :init
;; (setq TeX-auto-save t)
;; (setq TeX-parse-self t)
;; (setq-default TeX-master nil))
(use-package auctex
:demand t
:no-require t
:mode ("\\.tex\\'" . TeX-latex-mode)
:config
(defun latex-help-get-cmd-alist () ;corrected version:
"Scoop up the commands in the index of the latex info manual.
The values are saved in `latex-help-cmd-alist' for speed."
;; mm, does it contain any cached entries
(if (not (assoc "\\begin" latex-help-cmd-alist))
(save-window-excursion
(setq latex-help-cmd-alist nil)
(Info-goto-node (concat latex-help-file "Command Index"))
(goto-char (point-max))
(while (re-search-backward "^\\* \\(.+\\): *\\(.+\\)\\." nil t)
(let ((key (buffer-substring (match-beginning 1) (match-end 1)))
(value (buffer-substring (match-beginning 2)
(match-end 2))))
(add-to-list 'latex-help-cmd-alist (cons key value))))))
latex-help-cmd-alist)
(add-hook 'TeX-after-compilation-finished-functions
#'TeX-revert-document-buffer))
;; (use-package company-auctex)
4.3 Spellcheck #
4.3.1 Hunspell #
Finally figured this out from a reddit post from 2019.
;; flyspell + aspell??
(setq ispell-dictionary "en_GB")
(setq ispell-program-name "hunspell")
;; below two lines reset the the hunspell to it STOPS querying locale!
;; (setq ispell-local-dictionary "en_GB") ; "en_GB" is key to lookup in `ispell-local-dictionary-alist`
;; tell ispell that apostrophes are part of words
;; and select Bristish dictionary
;; (setq ispell-local-dictionary-alist
;; (quote ("UK_English" "[[:alpha:]]" "[^[:alpha:]]" "['’]" t ("-d" "en_GB") nil utf-8)))
;; hook for text mode
(add-hook 'text-mode-hook 'flyspell-mode)
;; hook to check spelling for comments in code
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
4.3.2 Aspell based spellchecking #
… because Void linux keeps complaining about not being able to find a British English dictionary
(setq ispell-program-name "aspell")
;; Please note ispell-extra-args contains ACTUAL parameters passed to aspell
(setq ispell-extra-args '("--sug-mode=ultra" "--lang=en_GB"))
;; hook for text mode
(add-hook 'text-mode-hook 'flyspell-mode)
;; hook to check spelling for comments in code
(add-hook 'prog-mode-hook 'flyspell-prog-mode)
4.3.3 flyspell-correct provides a more refines UI for spelling checking #
This shows a popup like for completions when it finds a misspelled word which makes it somewhat more accessible when writing, rather than having to look down at the message area.
(use-package flyspell-correct
:after flyspell
:bind (:map flyspell-mode-map ("C-;" . flyspell-correct-wrapper)))
(use-package flyspell-correct-popup
:after flyspell-correct)
4.4 Something like scrivener from Mac #
…cause I’m gonna become a novelist and/or write large books in the near future
(use-package binder)
;; (use-package binder-tutorial)
4.5 Blogging #
I’ve defined some stuff necessary to make editing a Hugo website easier.
4.5.1 ox-hugo
since the go-org keep wrecking up links #
My personal static site was/is written with this. I might have to add additional setup to add some of this functionality for project pages but then I hope to eventually move everything to sourcehut or atleast using it to host a website on my own domain.
This source block continues into the next section.
(use-package ox-hugo
:after ox)
Additional setup for streamlining writing posts on the static site:
4.5.1.1 Blogging flow #
Based on the capture templates documentation.
This function is called on invoking the org-capture (see next
section). This particular function adds a date below the header marked
CLOSED
which on export to markdown is converted to a regular date
field by ox-hugo and is included in the single page view/posts list on
the final export. It also changes the TODO
tag to DONE
. I’m still
trying to figure out bundles so this might change soon.
Since the provided template runs independent of my git repo for the
website, I’ll have to figure out the file
variable and how to point it
to the /content-org/blog/posts.org
file in the repo. From the original
ox-hugo docs code, this is the first template provided, (from under
the entry variable in the source block below):
It is assumed that below file is present in
org-directory
and that it has a “Blog Ideas” heading. It can even be a symlink pointing to the actual location of all-posts.org!
So I’ll change the target
to point to my file in the repo directly
until I can assign specific (programmatic ?) definitions for the repo
in this configuration somewhere.
(with-eval-after-load 'org-capture
(defun org-hugo-new-post-capture ()
"Returns `org-capture' template string for new Hugo post.
See `org-capture-templates' for more information."
;; http://www.holgerschurig.de/en/emacs-blog-from-org-to-hugo/
(let* ((date (format-time-string (org-time-stamp-format :long :inactive) (org-current-time)))
(title (read-from-minibuffer "Post Title: ")) ;Prompt to enter the post title
(fname (org-hugo-slug title))
(section (plist-get org-capture-plist :section)))
(mapconcat #'identity
`(
,(concat "* DRAFT " title)
":PROPERTIES:"
,(concat "" section)
,(concat ":EXPORT_FILE_NAME: " fname)
;; ,(concat ":EXPORT_HUGO_AUTO_SET_LASTMOD: " lastmod)
;; Enter current date and time
,(concat ":EXPORT_DATE: " date)
":END:"
;; Place the cursor here finally
"%?\n")
"\n")))
(setq org-capture-templates
;;`org-capture' binding + h
'(("b"
"Hugo blog post"
entry
(file+olp "~/my_gits/blog/content-org/blog/posts.org" "Posts")
(function org-hugo-new-post-capture)
:section ":EXPORT_HUGO_SECTION: blog"
)
;; `org-capture' binding + m
("m"
"Hugo miscellaneous blog post"
entry
(file+olp "~/my_gits/blog/content-org/blog/posts.org" "Miscellaneous")
(function org-hugo-new-post-capture)
:section ":EXPORT_HUGO_SECTION: misc"
))))
4.6 Olivetti / distraction-free writing #
(use-package olivetti
:init
(setq olivetti-body-width .67)
:config
(defun distraction-free ()
"Distraction-free writing environment"
(interactive)
(if (equal olivetti-mode nil)
(progn
(window-configuration-to-register 1)
(delete-other-windows)
;; (text-scale-increase 2)
(olivetti-mode t))
(progn
(jump-to-register 1)
(olivetti-mode 0)
(text-scale-decrease 2))))
:bind
(("<f9>" . distraction-free)))
5 Work #
5.1 Emacs Speaks Statistics for R and python(?) #
Figure out babel/org-tangle or whatever because Emacs sucks for RMarkdown and org-mode is generally better (see next bit for RMarkdown)
(use-package ess)
;; :ensure t
(require `ess-r-mode)
TODO 5.1.1 Polymodes for R #
This helps integrate ESS into markdown so editing RMarkdown files is
easy. As an added benefit syntax for regular markdown files is
supported. I won’t have to install polymode
itself explicitly since
it’s a dependency for the poly-R
modes and will be pulled
automatically. I do vaguely remember some issues this caused, will
have to
(use-package poly-R
:config
(add-to-list 'auto-mode-alist '("\\.md" . poly-markdown-mode))
(add-to-list 'auto-mode-alist '("\\.Rmd" . poly-markdown+r-mode))
:hook
(poly-markdown-mode . flyspell-mode)
(poly-markdown-mode . visual-line-mode)
(poly-markdown-mode . auto-fill-mode))
TODO 5.1.2 defining org-skeleton for org-babel + R #
Got this from worg documentation but I vaguely remember reading about more options for individual source blocks so will have to change / append accordingly. This defines a skeleton or a format for an org file header that’s specific to writing and running R code. It’s bound to a keybind so it can be accessed easily on opening a fresh org-babel document.
The other resource was: R source blocks in Org Mode
More info from the page:
- The
#+INFOJS_OPT
option will generate a HTML document that is foldable and follows the style of GNU/INFO document. - The
:session *R*
option makes sure all the R code is run in the same session so objects generated in one code block can be accessed from other code blocks. - the
:cache yes
option is used to avoid re-evaluating unchanged code blocks. This can save significant time when you revise a document with a lot of R code frequently. - The
:results output graphics :exports both
option will put both the R code and its text and graphics output in the generated document. - The
:tangle yes
option allows the document to be “tangled” to generate pure code file. The short-cut key for tangling isC-c C-v t
, which generates a .R file with all the R code extracted. - Note the
–—
string will generate a horizontal line in HTML file. - Finally, a hotkey
C-S-f4
(while pressing Ctrl and Shift keys, press F4 key) is assigned to invoke this skeleton quickly.
(define-skeleton org-skeleton
"Header info for a emacs-org file."
"Title: "
"#+TITLE:" str " \n"
"#+AUTHOR: Brihaadeesh S \n"
"#+email: brihadeesh.santharam@gmail.com\n"
"#+INFOJS_OPT: \n"
"#+BABEL: :session *R* :cache yes :results output graphics :exports both :tangle yes \n"
"-----"
)
(global-set-key [C-S-f4] 'org-skeleton)
5.2 org-present for presentations #
See dawiwil’s section on this from his literate init for more about this.
TODO 5.3 Citar for reference management? #
If I ever get down to writing papers, of course, I’d write them in
org-mode
or LaTeX so this should be useful considering Mendeley desktop
is bloat and I haven’t a clue if FreeBSD even has
Zotero
. This has additional setup stuff to do with Embark and the
rest of that family. This particular config only works with
org-mode
. Needs a shit ton of work to properly setup.
Also perhaps check out org-ref - it seems a lot simpler. Introduction to org-ref - a video ontroduction
;;(use-package citar
;;:no-require
;;:custom
;;(org-cite-global-bibliography '("~/bib/references.bib"))
;;(org-cite-insert-processor 'citar)
;;(org-cite-follow-processor 'citar)
;;(org-cite-activate-processor 'citar)
;; optional: org-cite-insert is also bound to C-c C-x C-@
;;:bind
;;(:map org-mode-map :package org ("C-c b" . #'org-cite-insert)))
6 Project management and navigation - projectile #
;; project management
(use-package projectile
;; :ensure t
:demand t
:init (setq projectile-completion-system 'default)
:bind-keymap
("C-c p" . projectile-command-map)
;; :diminish projectile-mode
:config
(setq projectile-project-search-path '("~/my_gits/" "~/journal/"))
(projectile-mode +1))
;; (use-package ibuffer-projectile
;; :after ibuffer
;; :preface
;; (defun my/ibuffer-projectile ()
;; (ibuffer-projectile-set-filter-groups)
;; (unless (eq ibuffer-sorting-mode 'alphabetic)
;; (ibuffer-do-sort-by-alphabetic)))
;; :hook (ibuffer . my/ibuffer-projectile))
7 Denote for note-taking #
I hope this is considerably simpler than org-roam and easier to setup. I don’t particularly like the way org-roam is unnecessarily cluttered and excruciatingly tedious to even get started with.
7.1 Basic setup #
(use-package denote
:straight (:source gnu-elpa-mirror)
:config
;; Remember to check the doc strings of those variables.
(setq denote-directory (expand-file-name "~/documents/denotes/")
;; keywords
denote-known-keywords '("emacs" "work" "thoughts" "journal")
;; check
denote-infer-keywords t
;; check
denote-sort-keywords t
;; Org is the default, set others here
denote-file-type nil
;; entry prompt asks for title and keywords
denote-prompts '(title keywords)
;; Pick dates, where relevant, with Org's advanced interface:
denote-date-prompt-use-org-read-date t
;; We allow multi-word keywords by default. The author's
;; personal preference is for single-word keywords for a more
;; rigid workflow.
denote-allow-multi-word-keywords t
;; read doc string
denote-date-format nil
;; By default, we fontify backlinks in their bespoke buffer.
denote-link-fontify-backlinks t)
;; Also see `denote-link-backlinks-display-buffer-action'
;; which is a bit advanced.
;; If you use Markdown or plain text files (Org renders links as buttons
;; right away)
(add-hook 'find-file-hook #'denote-link-buttonize-buffer)
;; We use different ways to specify a path for demo purposes.
(setq denote-dired-directories
(list denote-directory
(thread-last denote-directory (expand-file-name "attachments"))
(expand-file-name "~/documents/denotes/books")))
;; Generic (great if you rename files Denote-style in lots of places):
;; (add-hook 'dired-mode-hook #'denote-dired-mode)
;;
;; OR if only want it in `denote-dired-directories':
(add-hook 'dired-mode-hook #'denote-dired-mode-in-directories)
DISABLED 7.2 Keeping my org-agenda updated #
I’ve switched to using denote for managing my notes and tasks and
since I need a reliable system to manage tasks I’ve decided to give
org-agenda
a go. This should make it easier for me to track tasks from
TODO
tagged headers in my denote notes.
(defvar peremacs/denote-to-agenda-regexp "_project"
"Denote file names that are added to the agenda.
See `my-add-denote-to-agenda'.")
(defun peremacs/denote-add-to-agenda ()
"Add current file to the `org-agenda-files', if needed.
The file's name must match the `peremacs/denote-to-agenda-regexp'.
Add this to the `after-save-hook' or call it interactively."
(interactive)
(when-let* ((file (buffer-file-name))
((denote-file-is-note-p file))
((string-match-p peremacs/denote-to-agenda-regexp (buffer-file-name))))
(add-to-list 'org-agenda-files file)))
;; Example to add the file automatically. Uncomment it:
;; (add-hook 'after-save-hook #'my-denote-add-to-agenda)
(defun peremacs/denote-remove-from-agenda ()
"Remove current file from the `org-agenda-files'.
See `peremacs/denote-add-to-agenda' for how to add files to the Org
agenda."
(interactive)
(when-let* ((file (buffer-file-name))
((string-match-p peremacs/denote-to-agenda-regexp (buffer-file-name))))
(setq org-agenda-files (delete file org-agenda-files))))
TODO 7.3 Denote templates #
This should replace capture templates because the interactive denote
call seems a lot more flexible and versatile. Still WIP
(setq denote-templates
`((note . "* Some heading\n\n* Another heading")
(memo . ,(concat "* Some heading"
"\n\n"
"* Another heading"
"\n\n"))
(journal-entry . "* Date\n\n** Time")))
7.4 Journaling with Denote #
(defun peremacs/denote-journal-entry ()
"Create an entry tagged 'journal' with the date as its title."
(interactive)
(denote
;; format like June 14 2022 Tuesday
nil
'("journal")
nil
"~/my_gits/journal/entries/")
;; multiple keywords are a list of strings: '("one" "two")
(insert (concat "* " (format-time-string "(%R)") " ")))
DISABLED 7.5 “convenience commands” for journal entries #
;; (defun peremacs/denote-journal-entry ()
;; "Create journal entry and prompt for a subdirectory.
;; This is equivalent to calling `denote' when `denote-prompts' is
;; set to '(template subdirectory title keywords)."
;; (declare (interactive-only t))
;; (interactive)
;; (let ((denote-prompts '(subdirectory keywords)))
;; (denote-)
;; (call-interactively #'denote)))
(defun peremacs/denote-journal-entry ()
"Create an entry tagged 'journal' with the date as its title."
(interactive)
(denote
;; format title like Tuesday 14 June 2022
(format-time-string "%A %e %B %Y")
;; add 'journal' keywords; multiple is a list of strings: '("one" "two")
'("journal")
;; prompt for subdirectory (?)
(denote--subdirectory-prompt)))
Stolen from somewhere
(defun journal-day-exists-p ( target )
"check if journal for a day already exists"
(file-expand-wildcards (concat "~/my_gits/journal/entries/" target "*.org")))
(defun find-previous-journal ()
"Find most recent journal"
(let* ((today (format-time-string "%Y%m%d"))
(all_journals (sort (directory-files "~/my_gits/journal/entries" nil "^[0-9].*.*org$") #'string>)))
(dolist (journal all_journals)
(when (string< (substring journal 0 8) today)
(return journal)))))
(defun my-denote-journal-today ()
"Create an entry tagged 'journal' with the date as its title."
(interactive)
(let* ((today (format-time-string "%Y%m%d"))
(filename (car (journal-day-exists-p today)))
(prev (find-previous-journal)))
(if filename
(find-file filename)
(progn
(denote
(denote--title-prompt)
;; (format-time-string "%d %m %Y %a %H:%M")
'("journal")
"~/my_gits/journal/entries")
(insert "* ")
(save-buffer)))))
(defun my-denote-journal-date()
(declare (interactive-only t))
(interactive)
(let* ((date (org-read-date nil t))
(filename (car (journal-day-exists-p (format-time-string "%Y%m%d" date)))))
(if filename
(find-file filename)
(progn
(denote
(denote--title-prompt)
;; (format-time-string "%d %m %Y %a %H:%M")
'("journal")
"~/my_gits/journal/entries")
(insert "* ")))))
TODO 7.6 Keybindings #
Denote DOES NOT define any key bindings. It requires arguments
acceptable to the bind-keys
macro. I’m not entirely sure some of these
are necessary since I’m using a capture template.
;; :bind
;; (("C-c n n" . denote)
;; ("C-c n N" . denote-type)
;; ("C-c n d" , denote-date)
;; ("C-c n s" . denote-subdirectory)
;; ("C-c n t" . denote-template)
;; ;; renames don't work with `dired-mode', hence placed here
;; ("C-c n r" . denote-rename-file)
;; ("C-c n R" . denote-rename-file-using-front-matter)
;; ;; org-mode specifics (group with `global-mode-map' for multiple formats
;; ;; or add for each `markdown'/`text'/`org' if using single format)
;; :map org-mode-map
;; ("C-c n i" . denote-link) ; "insert" mnemonic
;; ("C-c n I" . denote-link-add-links)
;; ("C-c n b" . denote-link-backlinks)
;; ("C-c n f f" . denote-link-find-file)
;; ("C-c n f b" . denote-link-find-backlink)
;; ;; specific to dired
;; :map dired-mode-map
;; ("C-c C-d C-i" . denote-link-dired-marked-notes)
;; ("C-c C-d C-r" . denote-dired-rename-marked-files)
;; ("C-c C-d C-R" . denote-dired-rename-marked-files-using-front-matter)
;; ;; Also check the commands `denote-link-after-creating',
;; ;; `denote-link-or-create'. You may want to bind them to keys as well.
;; )
)
TODO 7.7 org-journal
for journaling requirements #
This needs better setting up and integration with either Orgzly
or
GitJournal
for android. iOS seems to have better apps though. Or
just make this workable with the termux version of Emacs.
(use-package org-journal
:init
;; Change default prefix key; needs to be set before loading org-journal
(setq org-journal-prefix-key "C-c j ")
:bind
;; (("C-c t" . journal-file-today)
;; ("C-c y" . journal-file-yesterday))
:config
;; Journal directory and files
(setq org-journal-dir "~/journal/entries/"
org-journal-file-format "%Y%m%d.org"
org-journal-file-type 'daily
org-journal-find-file 'find-file)
;; Journal file content
(setq org-journal-date-format "%e %b %Y (%A)"
org-journal-time-format "(%R)"
org-journal-file-header "#+title: Daily Journal\n#+startup: showeverything")
)
8 Version control #
8.1 Git with Magit and gists with gist.el
#
(use-package magit
:bind ("C-x g" . magit-status))
gist.el
to manage github gists from here
(use-package gist)
8.2 Undo tree #
Helps revert to older versions of files in case I fuck up something somewhere. Hmm. I doubt I ever use it so disabling it now.
(use-package undo-tree
:init
(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo"))
undo-tree-auto-save-history nil)
(global-undo-tree-mode)
:diminish undo-tree-mode)
TODO 8.3 SSH for personal packages and magit #
This needs a ton of work
(use-package keychain-environment
:config
(keychain-refresh-environment))
;; ;; import ssh deets from profile
;; (use-package exec-path-from-shell
;; :config
;; (exec-path-from-shell-copy-env "SSH_AGENT_PID")
;; (exec-path-from-shell-copy-env "SSH_AUTH_SOCK"))
9 Minibuffer completion #
9.1 Access a list of recently edited files #
Helps jump back into whatever I was doing before closing Emacs. Or my laptop more like it.
(use-package recentf
:init
(setq recentf-max-menu-items 25
recentf-auto-cleanup 'never
recentf-keep '(file-remote-p file-readable-p))
(recentf-mode 1))
9.2 Vertico for completions UI #
;; Enable vertico
(use-package vertico
;; pulls extensions as well?
;; :straight (:host github :repo "minad/vertico")
:init
(vertico-mode)
:config
(setq
;; Grow and shrink the Vertico minibuffer
vertico-resize t
;; No prefix with number of entries
vertico-count-format nil)
(advice-add #'tmm-add-prompt :after #'minibuffer-hide-completions)
(Continuing from previous block)
Completion-at-point and completion-in-region with Vertico. Use
`consult-completion-in-region’ if Vertico is enabled. Otherwise use
the default `completion–in-region’ function. Disabled because I use
corfu for completion-at-point
.
;; (setq completion-in-region-function
;; (lambda (&rest args)
;; (apply (if vertico-mode
;; #'consult-completion-in-region
;; #'completion--in-region)
;; args)))
Prefix the current candidate (See relevant section on the wiki)
(defun minibuffer-format-candidate (orig cand prefix suffix index _start)
(let ((prefix (if (= vertico--index index)
" "
" ")))
(funcall orig cand prefix suffix index _start)))
(advice-add #'vertico--format-candidate
:around #'minibuffer-format-candidate)
Completions for M-:
as well; closes the use-package function started
at Vertico header.
(defun minibuffer-vertico-setup ()
(setq truncate-lines t)
(setq completion-in-region-function
(if vertico-mode
#'consult-completion-in-region
#'completion--in-region)))
(add-hook 'vertico-mode-hook #'minibuffer-vertico-setup)
(add-hook 'minibuffer-setup-hook #'minibuffer-vertico-setup)
)
TODO 9.2.1 Vertico extensions #
Again stolen from Karthik Chikmaglur and needs heavy work, hence not enabled
(use-package vertico-multiform
:load-path "~/.emacs.d/lisp/vertico-extensions/"
:commands vertico-multiform-mode
:after vertico-flat
:bind (:map vertico-map
("M-q" . vertico-multiform-grid)
("C-l" . vertico-multiform-unobtrusive)
("C-M-l" . embark-export))
:init (vertico-multiform-mode 1)
:config
(setq vertico-multiform-categories
'((file my/vertico-grid-mode reverse)
(project-file my/vertico-grid-mode reverse)
(imenu buffer)
(consult-location buffer)
(consult-grep buffer)
(notmuch-result reverse)
(minor-mode reverse)
(reftex-label reverse)
(bib-reference reverse)
(xref-location reverse)
(t unobtrusive)))
(setq vertico-multiform-commands
'((load-theme my/vertico-grid-mode reverse)
(my/toggle-theme my/vertico-grid-mode reverse)
(consult-dir-maybe reverse)
(consult-dir reverse)
(consult-history reverse)
(consult-completion-in-region reverse)
(completion-at-point reverse)
(org-roam-node-find reverse)
(embark-completing-read-prompter reverse)
(embark-act-with-completing-read reverse)
(embark-prefix-help-command reverse)
(tmm-menubar reverse)))
(defun vertico-multiform-unobtrusive ()
"Toggle the quiet display."
(interactive)
(vertico-multiform--display-toggle 'vertico-unobtrusive-mode)
(if vertico-unobtrusive-mode
(vertico-multiform--temporary-mode 'vertico-reverse-mode -1)
(vertico-multiform--temporary-mode 'vertico-reverse-mode 1))))
(use-package vertico-unobtrusive
:load-path "~/.local/share/git/vertico/extensions/"
:after vertico-flat)
#+name vertico-grid
(use-package vertico-grid
:load-path "~/.emacs.d/lisp/vertico-extensions/"
:after vertico
;; :bind (:map vertico-map ("M-q" . vertico-grid-mode))
:config
(defvar my/vertico-count-orig vertico-count)
(define-minor-mode my/vertico-grid-mode
"Vertico-grid display with modified row count."
:global t :group 'vertico
(cond
(my/vertico-grid-mode
(setq my/vertico-count-orig vertico-count)
(setq vertico-count 4)
(vertico-grid-mode 1))
(t (vertico-grid-mode 0)
(setq vertico-count my/vertico-count-orig))))
(setq vertico-grid-separator " ")
(setq vertico-grid-lookahead 50))
(use-package vertico-quick
:load-path "~/.emacs.d/lisp/vertico-extensions/"
:after vertico
:bind (:map vertico-map
("M-i" . vertico-quick-insert)
("C-'" . vertico-quick-exit)
("C-o" . vertico-quick-embark))
:config
(defun vertico-quick-embark (&optional arg)
"Embark on candidate using quick keys."
(interactive)
(when (vertico-quick-jump)
(embark-act arg))))
(use-package vertico-directory
:load-path "~/.emacs.d/lisp/vertico-extensions/"
:hook (rfn-eshadow-update-overlay vertico-directory-tidy)
:after vertico
:bind (:map vertico-map
("DEL" . vertico-directory-delete-char)
("M-DEL" . vertico-directory-delete-word)
("C-w" . vertico-directory-delete-word)
("RET" . vertico-directory-enter)))
(use-package vertico-repeat
:load-path "~/.emacs.d/lisp/vertico-extensions/"
:after vertico
:bind (("C-x ." . vertico-repeat)))
(use-package vertico-reverse
;; :disabled
:load-path "~/.emacs.d/lisp/vertico-extensions/"
:after vertico)
(use-package vertico-flat
:load-path "~/.emacs.d/lisp/vertico-extensions/"
;; :bind (:map vertico-map
;; ("M-q" . vertico-flat-mode))
:after vertico)
(use-package vertico-buffer
:load-path "~/.emacs.d/lisp/vertico-extensions/"
:after vertico
;; :hook (vertico-buffer-mode . vertico-buffer-setup)
:config
(setq vertico-buffer-display-action 'display-buffer-reuse-window))
9.3 Orderless completion #
Search for commands, buffers, etc with vertico without having to match the order of words in the command. Adding spaces between keywords can match commands with those words anywhere in them. This config was bootlegged from minad’s config at the consult wiki.
(use-package orderless
:config
(defvar +orderless-dispatch-alist
'((?% . char-fold-to-regexp)
(?! . orderless-without-literal)
(?`. orderless-initialism)
(?= . orderless-literal)
(?~ . orderless-flex)))
;; Recognizes the following patterns:
;; * ~flex flex~
;; * =literal literal=
;; * %char-fold char-fold%
;; * `initialism initialism`
;; * !without-literal without-literal!
;; * .ext (file extension)
;; * regexp$ (regexp matching at end)
(defun +orderless-dispatch (pattern index _total)
(cond
;; Ensure that $ works with Consult commands, which add disambiguation suffixes
((string-suffix-p "$" pattern)
`(orderless-regexp . ,(concat (substring pattern 0 -1) "[\x100000-\x10FFFD]*$")))
;; File extensions
((and
;; Completing filename or eshell
(or minibuffer-completing-file-name
(derived-mode-p 'eshell-mode))
;; File extension
(string-match-p "\\`\\.." pattern))
`(orderless-regexp . ,(concat "\\." (substring pattern 1) "[\x100000-\x10FFFD]*$")))
;; Ignore single !
((string= "!" pattern) `(orderless-literal . ""))
;; Prefix and suffix
((if-let (x (assq (aref pattern 0) +orderless-dispatch-alist))
(cons (cdr x) (substring pattern 1))
(when-let (x (assq (aref pattern (1- (length pattern))) +orderless-dispatch-alist))
(cons (cdr x) (substring pattern 0 -1)))))))
;; Define orderless style with initialism by default
(orderless-define-completion-style +orderless-with-initialism
(orderless-matching-styles '(orderless-initialism orderless-literal orderless-regexp)))
;; You may want to combine the `orderless` style with `substring` and/or `basic`.
;; There are many details to consider, but the following configurations all work well.
;; Personally I (@minad) use option 3 currently. Also note that you may want to configure
;; special styles for special completion categories, e.g., partial-completion for files.
;;
;; 1. (setq completion-styles '(orderless))
;; This configuration results in a very coherent completion experience,
;; since orderless is used always and exclusively. But it may not work
;; in all scenarios. Prefix expansion with TAB is not possible.
;;
;; 2. (setq completion-styles '(substring orderless))
;; By trying substring before orderless, TAB expansion is possible.
;; The downside is that you can observe the switch from substring to orderless
;; during completion, less coherent.
;;
;; 3. (setq completion-styles '(orderless basic))
;; Certain dynamic completion tables (completion-table-dynamic)
;; do not work properly with orderless. One can add basic as a fallback.
;; Basic will only be used when orderless fails, which happens only for
;; these special tables.
;;
;; 4. (setq completion-styles '(substring orderless basic))
;; Combine substring, orderless and basic.
;;
(setq completion-styles '(orderless)
completion-category-defaults nil
;;; Enable partial-completion for files.
;;; Either give orderless precedence or partial-completion.
;;; Note that completion-category-overrides is not really an override,
;;; but rather prepended to the default completion-styles.
;; completion-category-overrides '((file (styles orderless partial-completion))) ;; orderless is tried first
completion-category-overrides '((file (styles partial-completion)) ;; partial-completion is tried first
;; enable initialism by default for symbols
(command (styles +orderless-with-initialism))
(variable (styles +orderless-with-initialism))
(symbol (styles +orderless-with-initialism)))
orderless-component-separator #'orderless-escapable-split-on-space ;; allow escaping space with backslash!
orderless-style-dispatchers '(+orderless-dispatch)))
9.4 Persistent command history #
Persist history over Emacs restarts. Vertico sorts by history position.
(use-package savehist
:init
(savehist-mode))
9.5 A few more useful configurations #
;; (use-package emacs
;; :init
;; Add prompt indicator to `completing-read-multiple'.
;; Alternatively try `consult-completing-read-multiple'.
(defun crm-indicator (args)
(cons (concat "[CRM] " (car args)) (cdr args)))
(advice-add #'completing-read-multiple :filter-args #'crm-indicator)
;; Do not allow the cursor in the minibuffer prompt
(setq minibuffer-prompt-properties
'(read-only t cursor-intangible t face minibuffer-prompt))
(add-hook 'minibuffer-setup-hook #'cursor-intangible-mode)
;; Emacs 28: Hide commands in M-x which do not work in the current mode.
;; Vertico commands are hidden in normal buffers.
;; (setq read-extended-command-predicate
;; #'command-completion-default-include-p)
;; Enable recursive minibuffers
(setq enable-recursive-minibuffers t)
;; )
9.6 Richer annotations in minubuffer #
(use-package marginalia
:after vertico
;; The :init configuration is always executed (Not lazy!)
:init
;; Must be in the :init section of use-package such that the mode gets
;; enabled right away. Note that this forces loading the package.
(marginalia-mode)
;; When using Selectrum, ensure that Selectrum is refreshed when cycling annotations.
;; (advice-add #'marginalia-cycle :after
;; (lambda () (when (bound-and-true-p selectrum-mode) (selectrum-exhibit 'keep-selected))))
;; Prefer richer, more heavy, annotations over the lighter default variant.
;; E.g. M-x will show the documentation string additional to the keybinding.
;; By default only the keybinding is shown as annotation.
;; Note that there is the command `marginalia-cycle' to
;; switch between the annotators.
;; (setq marginalia-annotators '(marginalia-annotators-heavy marginalia-annotators-light nil))
)
9.7 Consult adds more minibuffer functionality #
(use-package consult
;; Replace bindings. Lazily loaded due by `use-package'.
:bind
(("C-x B" . consult-buffer)
("C-x 4 b" . consult-buffer-other-window)
("C-x 5 b" . consult-buffer-other-frame)
("M-g i" . consult-imenu)
("M-g I" . consult-project-imenu)
;; searching for files
("M-s f" . consult-find)
("M-s F" . consult-git-grep)
("M-s g" . consult-grep)
("M-s r" . consult-ripgrep)
("C-c f r" . consult-recent-file)
("C-x C-" . consult-recent-file)
;; Isearch integration
("C-s" . consult-isearch-history)
("C-c L" . consult-outline)
("C-c h l" . consult-org-heading)
;; yank from kill-ring
("M-y" . consult-yank-pop)
)
;; Enable automatic preview at point in the *Completions* buffer. This is
;; relevant when you use the default completion UI. You may want to also
;; enable `consult-preview-at-point-mode` in Embark Collect buffers.
:hook (completion-list-mode . consult-preview-at-point-mode)
:config
;; Configure the narrowing key.
(setq consult-narrow-key "<") ;; (kbd "C-+")
;; Configure a function which returns the project
;; root directory - projectile.el (projectile-project-root)
(autoload 'projectile-project-root "projectile")
(setq consult-project-root-function #'projectile-project-root)
;; use consult with perspective.el
(consult-customize consult--source-buffer :hidden t :default nil)
(defvar consult--source-perspective
(list :name "Perspective"
:narrow ?s
:category 'buffer
:state #'consult--buffer-state
:default t
:items #'persp-get-buffer-names))
(push consult--source-perspective consult-buffer-sources)
)
;; Optionally add the `consult-flycheck' command.
(use-package consult-flycheck
:bind (:map flycheck-command-map
("!" . consult-flycheck)))
TODO 9.8 Consult interface for denote #
I haven’t really figured out how to programmatically add additional functionality/features for consult, nor have I figured out denote. I got this from one random blog post about denote while looking for how people use denote to work with sub-directories. I’ve just grabbed the files from their package for now but I might need to extend this if I end up switching to using denote for journaling.
(use-package consult-denote
:straight (consult-denote :type git :host codeberg :repo "whhone/consult-denote"))
TODO 9.9 Embark - actions; reorganise #
This I’ve not used yet but makes a lot of stuff easier like
searchingfor the definition
or the help/info
page a highlighted
word from within the buffer or the minibuffer or even the minibuffer
completion list.
Group with the rest of the packages from this family?
(use-package embark
:bind
(("C-S-a" . embark-act) ;; pick some comfortable binding
("C-h B" . embark-bindings)) ;; alternative for `describe-bindings'
:init
;; Optionally replace the key help with a completing-read interface
(setq prefix-help-command #'embark-prefix-help-command)
:config
;; Hide the mode line of the Embark live/completions buffers
(add-to-list 'display-buffer-alist
'("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
nil
(window-parameters (mode-line-format . none)))))
;; Consult users will also want the embark-consult package.
(use-package embark-consult
:ensure t
:after (embark consult)
:demand t ; only necessary if you have the hook below
;; if you want to have consult previews as you move around an
;; auto-updating embark collect buffer
:hook
(embark-collect-mode . consult-preview-at-point-mode))
10 Corfu for completion in buffer #
This might need some more work - integration with minad’s cape
for
various kinds of completions although he alleges this works well with
base Emacs.
(use-package corfu
:bind
(:map corfu-map
;; ??? :states 'insert
("TAB" . corfu-next)
([tab] . corfu-next)
("S-TAB" . corfu-previous)
([backtab] . corfu-previous)
("<escape>" . corfu-quit)
("<return>" . corfu-insert)
("M-d" . corfu-show-documentation)
("M-l" . 'corfu-show-location)
("SPC" . corfu-insert-separator))
:custom
;; Only use `corfu' when calling `completion-at-point' or
;; (corfu-auto t)
;; `indent-for-tab-command'
;; (corfu-auto-prefix 3)
;; (corfu-auto-delay 0.2)
;; size
(corfu-min-width 80)
;; Always have the same width
(corfu-max-width corfu-min-width)
(corfu-count 14)
(corfu-scroll-margin 4)
(corfu-cycle t)
;; Show documentation in echo area?
(corfu-echo-documentation t)
;; Preselect first candidate?
(corfu-preselect-first nil)
;; Preview current candidate?
(corfu-preview-current 'insert)
;; quit if no match
(corfu-quit-no-match t)
:init
(global-corfu-mode))
10.1 CAPE - extensions for corfu #
Corfu needs cape
to provide completion backends because it’s extremely
stripped down. Will have to check what other backends I’ll need to
enable.
(use-package cape
:config
(setq cape-dabbrev-min-length 2)
:init
;; Add `completion-at-point-functions', used by `completion-at-point'.
(dolist (backend '( cape-file cape-dabbrev cape-keyword cape-abbrev
cape-ispell cape-dict cape-symbol cape-line ))
(add-to-list 'completion-at-point-functions backend)))
(add-to-list 'completion-at-point-functions #'cape-file)
(add-to-list 'completion-at-point-functions #'cape-keyword)
(add-to-list 'completion-at-point-functions #'cape-ispell)
(add-to-list 'completion-at-point-functions #'cape-dict)
(add-to-list 'completion-at-point-functions #'cape-symbol)
11 Look #
11.1 Font configuration #
11.1.1 Setting a font #
;; first set default
(set-face-attribute 'default nil :family "Hack" :height 70)
;; then set variable-pitch fonts
(set-face-attribute 'variable-pitch nil :family "Iosevka Aile" :height 1.1)
;; finally set fixed-pitch
(set-face-attribute 'fixed-pitch nil :family "Hack" :height 1.0)
11.1.2 Line spacing #
Usually 0, less if possible but Emacs doesn’t allow for that.
;; Line spacing, can be 0 for code and 1 or 2 for text
(setq-default line-spacing 0.1)
11.2 Editor theme #
Update: Debugger entered--Lisp error: (wrong-number-of-arguments (1 . 2) 8)
This is based on Adam Spiers’s comment - the theme should be
loaded before custom.el
is pulled in to avoid issues with version
mismatch like the shit with the org
package.
11.2.1 ef-themes #
(use-package ef-themes
:config
;; If you like two specific themes and want to switch between them, you
;; can specify them in `ef-themes-to-toggle' and then invoke the command
;; `ef-themes-toggle'. All the themes are included in the variable
;; `ef-themes-collection'.
(setq ef-themes-to-toggle '(ef-night ef-duo-dark ef-winter))
(setq ef-themes-headings ; read the manual's entry or the doc string
'((0 . (variable-pitch light 1.2))
(1 . (variable-pitch light 1.1))
(2 . (variable-pitch regular))
(3 . (variable-pitch regular))
(4 . (variable-pitch regular))
(5 . (variable-pitch)) ; absence of weight means `bold'
(6 . (variable-pitch))
(7 . (variable-pitch))
(t . (variable-pitch))))
;; They are nil by default...
(setq ef-themes-mixed-fonts t
ef-themes-variable-pitch-ui t)
;; Read the doc string or manual for this one. The symbols can be
;; combined in any order.
(setq ef-themes-region '(intense no-extend neutral))
;; Disable all other themes to avoid awkward blending:
(mapc #'disable-theme custom-enabled-themes)
;; Load the theme of choice:
;; (load-theme 'ef-summer :no-confirm)
;; OR use this to load the theme which also calls `ef-themes-post-load-hook':
;; (ef-themes-select 'ef-winter)
;; The themes we provide are recorded in the `ef-themes-dark-themes',
;; `ef-themes-light-themes'.
;; We also provide these commands, but do not assign them to any key:
;;
;; - `ef-themes-toggle'
;; - `ef-themes-select'
;; - `ef-themes-load-random'
;; - `ef-themes-preview-colors'
;; - `ef-themes-preview-colors-current'
)
11.2.2 Modus from Protesilaos! #
This might need additional setting since modus themes are now included within Emacs
(use-package modus-themes
:straight (:source gnu-elpa-mirror)
:init
(setq modus-themes-mixed-fonts t
modus-themes-bold-constructs t
modus-themes-italic-constructs t
modus-themes-region '(no-extend)
modus-themes-mode-line '(accented)
modus-themes-prompts '(backgound bold intense)
;; modus-themes-hl-line 'accented
modus-themes-intense-markup t
modus-themes-region '(no-extend bg-only)
modus-themes-subtle-line-numbers t
modus-themes-fringes '(subtle)
modus-themes-language-checkers '(straight-underline faint)
modus-themes-org-blocks '(gray-background)
modus-themes-completions
'((matches . (bold background intense))
(selection . (bold background intense))
(popup . (accented))))
(defun peremacs/call-modus-operandi ()
(interactive)
;; heading backgrounds work better here
(disable-theme 'modus-vivendi)
(setq modus-themes-headings
'((1 . (overline background variable-pitch bold 1.1))
(2 . (overline background variable-pitch bold))
(3 . (overline background variable-pitch semibold))
(4 . (overline background variable-pitch semibold))
(t . (overline variable-pitch semibold))))
(modus-themes-load-operandi))
(defun peremacs/call-modus-vivendi ()
(interactive)
(disable-theme 'modus-operandi)
(setq modus-themes-headings
'((1 . (overline monochrome variable-pitch bold 1.1))
(2 . (overline monochrome variable-pitch bold))
(3 . (overline monochrome variable-pitch semibold))
(4 . (overline monochrome variable-pitch semibold))
(t . (overline variable-pitch semibold))))
(modus-themes-load-vivendi))
;; set semibold as the bold face
;; (for those fonts that provide this face)
;; (set-face-attribute 'bold nil :weight 'semibold)
;; :config
;; Load the theme files before enabling a theme
(modus-themes-load-themes)
;; Load the theme of your choice:
;; (peremacs/call-modus-operandi)
(peremacs/call-modus-vivendi)
)
11.2.3 Commentary #
An elegant theme highlighting comments only
(use-package commentary-theme
;;:config
;;(load-theme 'commentary t)
)
11.2.4 My themes #
Neither of these work using straight.el
or use-package
, together
or separately (afaik). If these work, I could maybe add some more of
my own.
Forked from the colorless-themes macro. This includes my version of the macro, original themes from Thomas Letan, and some additional themes of my own that use this macro.
(use-package colourless-themes
:straight (:host gitlab :repo "peregrinator/colourless-themes-el")
;;:config
;;(load-theme 'beelzebub t)
)
DISABLED 11.2.5 unused #
DISABLED 11.2.5.1 Wilmersdorf #
I saw this on doom-themes but I don’t want to pull all of those just
for this, so installing from it’s GitHub using straight.el
. But it
fails to load with use-package
so I’m going to have to do it manually.
(use-package wilmersdorf
:straight (:host github :repo "ianyepan/wilmersdorf-emacs-theme")
;; :config
;; (load-theme 'wilmersdorf t)
)
DISABLED 11.2.5.2 Tao #
Monochrome theme with minimal bold highlights and boxes?
(use-package tao-theme
:config
;; load theme
(load-theme 'tao-yang t)
;; (load-theme 'tao-yin t)
)
DISABLED 11.2.5.3 Expresso #
(use-package espresso-theme
:straight (:host github :repo "dgutov/espresso-theme")
;;:config
(load-theme 'espresso t)
)
DISABLED 11.2.5.4 Github dark #
(use-package github-dark-vscode-theme
:config
(load-theme 'github-dark-vscode t)
;; fixed upstream
;; unrelated but the cursor colour really needs improvement
;; (set-cursor-color "#ffffff")
)
DISABLED 11.2.5.5 Github modern (light) #
(use-package github-modern-theme
:config
(load-theme 'github-modern t)
)
DISABLED 11.2.5.6 Vale #
(use-package vale
:straight (:type git :repo "https://codeberg.org/ext0l/vale.el")
:config
;; (load-theme 'vale t)
)
DISABLED 11.2.5.7 Parchment #
Based on the screenshot of Haskell code on the Pragmata Pro website.
(use-package Parchment-theme
:straight (:host github :repo "brihadeesh/emacs-parchment-theme")
:config
;; (load-theme 'Parchment t)
)
DISABLED 11.2.5.8 Almost mono #
(use-package almost-mono-themes
:config
;; (load-theme 'almost-mono-black t)
;; (load-theme 'almost-mono-gray t)
;; (load-theme 'almost-mono-cream t)
;; (load-theme 'almost-mono-white t)
)
DISABLED 11.2.5.9 Stimmung themes for nearly monochrome appearance #
(use-package stimmung-themes
;; :straight (stimmung-themes :host github :repo "motform/stimmung-themes") ; if you are a straight shooter
:config
;; (stimmung-themes-load-dark)
)
11.3 Highlighted line-mode #
;; cursorline
(global-hl-line-mode 1)
11.4 Solid window dividers #
;; (setq window-divider-default-right-width 1)
;; (setq window-divider-default-bottom-width 1)
;; (setq window-divider-default-places 'all)
;; (window-divider-mode)
(setq window-divider-default-right-width 1)
(setq window-divider-default-bottom-width 1)
(setq window-divider-default-places 'right-only)
(add-hook 'after-init-hook #'window-divider-mode)
11.5 Something about underlines #
Underline line at descent position, not baseline position
(setq x-underline-at-descent-line t)
11.6 Cursor configuration #
(set-default 'cursor-type '(bar . 2))
(blink-cursor-mode 1)
11.7 Line-number format #
(setq linum-format "%4d ")
11.8 Visual not audible bell #
Flashes modeline for warnings from purcell
;; No sound
(setq ring-bell-function 'ignore)
(use-package mode-line-bell
:config
(mode-line-bell-mode))
11.9 No Tooltips #
(tooltip-mode 0)
11.10 Minibuffer appearance? #
As per Hamilton9508’s comment he makes a single minibuffer-only frame across the bottom of the Emacs window and so the rest of the frames have only a single buffer (i.e. the buffer being edited/used) and no minubuffer of it’s own. Not sure if this will work for me but I’ll perhaps give it a shot.
(setq minibuffer-frame-alist '(
(name . "minibuf")
(menu-bar-lines . 0)
(vertical-scroll-bars . nil)
(auto-raise . t)
(sticky . t)
(left . 0)
(top . -1)
(height . 1)
(internal-border-width . 0)
(minibuffer . only)))
11.11 Minimalist and ordered mode-line #
People seem to use packages for this. I’ve considered using the doom-modeline but it seems to be pretty heavy in terms of dependencies and I’d like a mode-line with a much more fundamental interface although it’s still a good contender considering it’s very simple to configure. I’m also considering simple-mode-line.
11.11.1 Mood-line because I’m fucking tired #
(use-package mood-line
:config
(mood-line-mode)
)
11.12 Pulse to locate cursor with Protesilaos’s pulsar #
(use-package pulsar
:straight (:host gitlab :repo "protesilaos/pulsar")
:custom
(pulsar-pulse-functions ; Read the doc string for why not `setq'
'(recenter-top-bottom
move-to-window-line-top-bottom
reposition-window
;; bookmark-jump
;; other-window
;; delete-window
;; delete-other-windows
forward-page
backward-page
scroll-up-command
scroll-down-command
;; windmove-right
;; windmove-left
;; windmove-up
;; windmove-down
;; windmove-swap-states-right
;; windmove-swap-states-left
;; windmove-swap-states-up
;; windmove-swap-states-down
;; tab-new
;; tab-close
;; tab-next
org-next-visible-heading
org-previous-visible-heading
org-forward-heading-same-level
org-backward-heading-same-level
outline-backward-same-level
outline-forward-same-level
outline-next-visible-heading
outline-previous-visible-heading
outline-up-heading))
:config
(setq pulsar-pulse-on-window-change t
pulsar-pulse t
pulsar-delay 0.055
pulsar-iterations 10
pulsar-face 'pulsar-cyan)
(pulsar-global-mode 1)
:bind
(("C-c l" . pulsar-pulse-line)
("C-c h l" . pulsar-highlight-line))
:hook
(consult-after-jump . pulsar-recenter-top)
(consult-after-jump . pulsar-reveal-entry))
11.13 Display complex key-binding suggestions #
(use-package which-key
:diminish which-key-mode
:config
(which-key-mode))
11.14 Diminish for a cleaner modeline #
org-indent-mode
doesn’t get disabled by the default method.
(use-package diminish
:diminish auto-fill-function
:diminish flyspell-mode
:diminish visual-line-mode
)
(defun peremacs/diminish-org-indent ()
(interactive)
(diminish 'org-indent-mode ""))
(add-hook 'org-indent-mode-hook 'peremacs/diminish-org-indent)
11.15 Pixel scroll precision mode (Emacs 29+) #
(pixel-scroll-precision-mode +1)
11.16 Make “Emacs” the window title #
(setq-default frame-title-format '("Emacs"))
11.17 Make scratch buffer and minibuffer blank #
(setq initial-scratch-message "")
(setq inhibit-startup-echo-area-message t)
(setq inhibit-startup-message t)
(setq initial-scratch-message nil)
11.18 Show keystrokes #
Stolen from Karthik Chikmaglur’s emacs.d; shows what is typed immediately.
(setq echo-keystrokes 0.01)
12 Window Management #
12.1 EXWM #
This ofc doesn’t work on wayland and pgtk
emacs but am I willing
to learn C++ and emacs-lisp well enough to contribute to porting this
to wayland/wlroots or something?
(use-package exwm
;; :ensure t
:diminish
:custom
(exwm-workspace-number 4)
;; (defun exwm-start-process (command)
;; "Start a process via a shell COMMAND."
;; (interactive (list (read-shell-command "$ ")))
;; (start-process-shell-command command nil command))
;; ((kbd "<s-return>") #'exwm-start-process)
;; (exwm-input-set-key (kbd "<s-return>") #'exwm-start-process)
:config
;; This now has to be toggled separately in the `~/.xinitrc'
;; see https://www.reddit.com/r/emacs/comments/mjx2qd/conditional_loading_for_exwm_with_usepackage/gte7puu/
(require 'exwm-config)
;; (exwm-config-default)
;; Effective use of EXWM requires the ability to return from char-mode to line-mode.
;; This will be performed with s-r.
(exwm-input-set-key (kbd "s-r") #'exwm-reset)
;; Hide all windows except the current one.
(exwm-input-set-key (kbd "s-o") #'delete-other-windows)
;; Close the current window and kill its buffer.
(exwm-input-set-key (kbd "C-s-x") #'kill-buffer-and-window)
;; Close the current window without killing its buffer.
(exwm-input-set-key (kbd "s-x") #'delete-window)
;; Open an Eshell buffer in the current buffer’s location.
(exwm-input-set-key (kbd "C-z") #'eshell-find-eshell-here)
;; Move point to the windows immediately around the current window.
(exwm-input-set-key (kbd "s-h") #'windmove-left)
(exwm-input-set-key (kbd "s-j") #'windmove-down)
(exwm-input-set-key (kbd "s-k") #'windmove-up)
(exwm-input-set-key (kbd "s-l") #'windmove-right)
(exwm-input-set-key (kbd "s-w") #'exwm-workspace-switch))
12.2 Workspaces with perspective-el #
Independent workspaces for different projects like profiles on RStudio but perhaps a lot more dynamic. This might need more work hence adding a link to the project page here.
(use-package perspective
:demand t
:init
;; apparently it's essential to define a prefix on Emacs=28
(setq persp-mode-prefix-key (kbd "C-x x"))
:bind
;; these work with selectrum/vertico i.e. `completing-read'
;; type completion systems that are appararently closer to
;; base Emacs functioning.
(("C-x b" . persp-switch-to-buffer*)
;;("C-x k" . persp-kill-buffer*)
)
:config
;; Running `persp-mode' multiple times resets the perspective list...
(unless (equal (default-value 'persp-mode) t)
(persp-mode 1)))
12.2.1 persp-projectile for proper workspace window management #
(use-package persp-projectile
:bind
("C-x x s". persp-projectile-switch-project))
12.3 Undo disrupted window/frame arrangement after using some shit #
Stolen from Karthik Chikmaglur’s emacs.d
(use-package winner
:disabled
:commands winner-undo
:bind (("C-x C-/" . winner-undo)
("s-/" . winner-undo)
("s-S-/" . winner-redo))
:config
(winner-mode +1))
12.4 Ace-window helps with navigation between multiple windows #
Simpler navigation between open Emacs windows
(use-package ace-window
:init
(setq aw-keys '(?a ?s ?d ?f ?j ?k ?l ?o))
:bind (("C-x o" . ace-window)
("M-o" . other-window)
("M-o" . ace-window))
:diminish ace-window-mode)
TODO 12.4.0.1 Other actions that ace-window
handles: #
(defvar aw-dispatch-alist
'((?x aw-delete-window "Delete Window")
(?m aw-swap-window "Swap Windows")
(?M aw-move-window "Move Window")
(?c aw-copy-window "Copy Window")
(?j aw-switch-buffer-in-window "Select Buffer")
(?n aw-flip-window)
(?u aw-switch-buffer-other-window "Switch Buffer Other Window")
(?c aw-split-window-fair "Split Fair Window")
(?v aw-split-window-vert "Split Vert Window")
(?b aw-split-window-horz "Split Horz Window")
(?o delete-other-windows "Delete Other Windows")
(?? aw-show-dispatch-help))
"List of actions for `aw-dispatch-default'.")
TODO 12.5 Sane native window management #
Focuses new windows when created.
;; Window management
;; focus new windows once created
(use-package window
:straight (:type 'built-in)
:bind (("C-x 3" . hsplit-last-buffer)
("C-x 2" . vsplit-last-buffer))
:preface
(defun hsplit-last-buffer ()
"Gives the focus to the last created horizontal window."
(interactive)
(split-window-horizontally)
(other-window 1))
(defun vsplit-last-buffer ()
"Gives the focus to the last created vertical window."
(interactive)
(split-window-vertically)
(other-window 1)))
12.6 Better popups with popper #
(use-package popper
:bind (("C-`" . popper-toggle-latest)
("M-`" . popper-cycle)
("C-M-`" . popper-toggle-type))
:init
;; assign windows to popper (to appear as popups)
(setq popper-reference-buffers
'("\\*Messages\\*"
"Output\\*$"
"\\*Backtrace\\*"
"\\*Warnings\\*"
"^Calc:"
"^\\*ielm\\*"
;; terminals as popups
"^\\*eshell.*\\*$" eshell-mode
"^\\*shell.*\\*$" shell-mode
"^\\*term.*\\*$" term-mode
"^\\*vterm.*\\*$" vterm-mode
help-mode
compilation-mode
;; magit stuff
"^magit:*" magit-mode
"^\\*Ilist\\*$"
;; R console that comes with ESS
"^\\*iESS" iESS-mode
"^\\*R\\*"
;; R-help windows
"^\\*help\\[R\\]([a-z]*)\\*"
))
;;grouping popups by projectile groups
(setq popper-group-function #'popper-group-by-projectile)
;; popper UI configguration
(setq popper-modeline nil)
(popper-mode +1)
;; echo area hints?
(popper-echo-mode +1)
)
13 Garbage #
13.0.1 from customize API #
This keeps the init.el cleaner and without junk from customize.el
API allows for an option to gitignore your custom.el
cause it’s
junk.
;; Offload the custom-set-variables to a separate file
;; (setq custom-file "~/.emacs.d/custom.el")
(setq custom-file (concat user-emacs-directory "/custom.el"))
(unless (file-exists-p custom-file)
(write-region "" nil custom-file))
;; Load custom file. Don't hide errors. Hide success message
;; OR DON'T EVEN BOTHER WITH IT
;; (load custom-file nil t)
13.0.2 from backups and autosaves(?) #
;;; Put Emacs auto-save and backup files to one folder
(defconst emacs-tmp-dir (expand-file-name (format "emacs%d" (user-uid)) temporary-file-directory))
(setq
backup-by-copying t ; Avoid symlinks
delete-old-versions t
kept-new-versions 6
kept-old-versions 2
version-control t
auto-save-list-file-prefix emacs-tmp-dir
auto-save-file-name-transforms `((".*" ,emacs-tmp-dir t)) ; Change autosave dir to tmp
backup-directory-alist `((".*" . ,emacs-tmp-dir)))
;;; Lockfiles unfortunately cause more pain than benefit
(setq create-lockfiles nil)
14 Defaults #
Primarily bootlegged from Sanemacs and changed when appropriate (and when I thought I understood what I was doing)
14.1 Disable native popups(?) and bell #
;; not sure what this is about
;; (setq-default indent-tabs-mode nil)
;; disable popups?
;; (setq pop-up-windows nil)
;; Disable bell sound
(setq ring-bell-function 'ignore)
14.2 Only y or n prompts for speed #
Apparently there is a short-answers
variable
;; (fset 'yes-or-no-p 'y-or-n-p)
(setq-default
use-short-answers t
;; Ok to visit non existent files (no confirmation reqd)
confirm-nonexistent-file-or-buffer nil)
14.3 Merge Emacs and system clipboards #
;; Merge system's and Emacs' clipboard
(setq-default select-enable-clipboard t)
14.4 Overwrite selected text #
(delete-selection-mode 1)
14.5 Join line to following line #
Plagiarised from pragmatic emacs. For the reverse, emacs has a
slightly obscurely named command delete-indentation
which is bound
to M-^
which can be rather useful. From the help for the function
(which you can always look up using C-h k M-^
or C-h f delete-indentation
)
;; join line to next line
(global-set-key (kbd "C-j")
(lambda ()
(interactive)
(join-line -1)))
14.6 Simpler kill buffer behaviour #
(defun peremacs/kill-this-buffer ()
(interactive) (kill-buffer (current-buffer)))
(global-set-key (kbd "C-x k") 'peremacs/kill-this-buffer)
14.7 Kill without accessing clipboard - reassess if this is really necessary #
(defun peremacs/backward-kill-word ()
(interactive "*")
(push-mark)
(backward-word)
(delete-region (point) (mark)))
(global-set-key (kbd "M-DEL") 'peremacs/backward-kill-word)
(global-set-key (kbd "C-DEL") 'peremacs/backward-kill-word)
14.8 Return to last position in buffer #
Opens files at last position used. Something about this on Emacs Wiki
(save-place-mode 1)
14.9 Prompt before closing Emacs #
;; Confirm when killing Emacs
(setq confirm-kill-emacs (lambda (prompt)
(y-or-n-p-with-timeout prompt 2 nil)))
14.10 Prevent angle braces from throwing errors #
(modify-syntax-entry ?< ".")
(modify-syntax-entry ?> ".")
DISABLED 14.11 Don’t follow symlinks #
;; don't follow symlinks? hopefully this solves the
;; `symbols function definition is void: org-file-name-concat' error
(setq vc-follow-symlinks nil)
15 Code utilities #
TODO 15.1 Templates and snippets with minad’s tempel #
Seems a lot simpler than yasnippet but will have to work on templates.
(use-package tempel
;; Require trigger prefix before template name when completing.
;; :custom
;; (tempel-trigger-prefix "<")
:bind (("M-+" . tempel-complete) ;; Alternative tempel-expand
("M-*" . tempel-insert))
Configuration: I’m setting the tempel-path
because it defaults to
~/.config/emacs/templates
which I don’t use. But I think I’ll
eventually switch to something like that.
:init
(setq tempel-path "~/.emacs.d/templates")
Setup completion at point
(defun tempel-setup-capf ()
;; Add the Tempel Capf to `completion-at-point-functions'.
;; `tempel-expand' only triggers on exact matches. Alternatively use
;; `tempel-complete' if you want to see all matches, but then you
;; should also configure `tempel-trigger-prefix', such that Tempel
;; does not trigger too often when you don't expect it. NOTE: We add
;; `tempel-expand' *before* the main programming mode Capf, such
;; that it will be tried first.
(setq-local completion-at-point-functions
(cons #'tempel-expand
completion-at-point-functions)))
Hooks
:hook
(prog-mode . tempel-setup-capf)
(text-mode . tempel-setup-capf)
;; Optionally make the Tempel templates available to Abbrev,
;; either locally or globally. `expand-abbrev' is bound to C-x '.
;; (add-hook 'prog-mode-hook #'tempel-abbrev-mode)
;; (global-tempel-abbrev-mode)
)
15.2 Snippets #
(use-package yasnippet
:disabled
:config
(yas-global-mode 1)
:diminish yas-minor-mode)
15.3 Syntax checking with Flycheck #
(use-package flycheck
:defer t
:hook
(prog-mode . flycheck-mode)
(org-mode . flycheck-mode)
(sh-mode . flycheck-mode)
:diminish flycheck-mode
)
15.4 Bash - use tabs instead of spaces #
Maybe this needs to be universal but this is especially annoying when I edit void-packages ’template’s which specifically need tabs in the custom functions below.
(add-hook 'sh-mode-hook
(lambda ()
(setq-default indent-tabs-mode t)
(setq-default tab-width 8)
(add-to-list 'write-file-functions 'delete-trailing-whitespace)))
15.5 Auto-paired parens #
(electric-pair-mode 1)
(setq electric-pair-preserve-balance nil)
15.6 Show matching parens #
(show-paren-mode 1)
;; Worst possible setting with this theme - it sucks balls
;; (setq show-paren-style 'expression)
15.7 CUA mode #
(setq cua-enable-cua-keys nil)
;; for rectangles, CUA is nice
(cua-mode t)
15.8 Aggressive indentation coz OCD #
…and I hate doing it manually and Emacs usually refuses to do it by itself
(use-package aggressive-indent
:config (global-aggressive-indent-mode 1)
:diminish aggressive-indent-mode)
15.9 Bug-hunter #
…except those that you can eat
(use-package bug-hunter)
15.10 cl-libify #
Convert all (deperecated) cl
symbols to cl-lib
(use-package cl-libify
:disabled)
15.11 Iedit #
A more intuitive way to alter all the occurrences of a word/keyword at once
(use-package iedit)
15.12 Show line numbers in programming modes #
(add-hook 'prog-mode-hook
(if (and (fboundp 'display-line-numbers-mode) (display-graphic-p))
#'display-line-numbers-mode
#'linum-mode))
15.13 Files from script directories default to shell-mode #
Scope for adding more such shit?
(add-to-list 'auto-mode-alist '("/bin/" . sh-mode))
(add-to-list 'auto-mode-alist '("/srcpkgs/[[:ascii:]]+/template" . sh-mode))
15.14 Editing root files & privelege escalation for TRAMP if I ever use it #
(use-package su
;; :config
;; (su-mode +1)
)
15.15 Whitespace mopup #
(add-hook 'before-save-hook
'delete-trailing-whitespace) ;; Delete trailing whitespace on save
15.16 Multiple cursors #
This is like C-v
, a visual mode in vim/neovim. I stole this from
pragmatic emacs.
(global-set-key (kbd "C-c m c") 'peremacs/edit-lines)
15.17 Delete blank lines and whitespace interactively #
Plagiarised from pragmatic emacs
(global-set-key (kbd "M-SPC") 'shrink-whitespace)
15.18 Autoupdate buffer if files has changed on disk #
(global-auto-revert-mode t)
16 Languages #
16.1 Vimscript for editing neovim init #
…cause neovim sucks and I don’t like leaving Emacs in the ideal case. I might end up replacing this with a lua config
;; vimrc syntax
(use-package vimrc-mode)
;; :ensure t
(add-to-list 'auto-mode-alist '("\\.vim\\(rc\\)?\\'" . vimrc-mode))
16.2 Lua mode? #
I intend to learn and use lua for my neovim config.
(use-package lua-mode)
16.3 C and C++ ??? #
Like really?
;; (use-package cc-mode)
16.4 El Doc for help in echo area #
(use-package eldoc
:straight (:type built-in)
:hook
((emacs-lisp-mode-hook . eldoc-mode)
(lisp-interaction-mode-hook . eldoc-mode)
(ielm-mode-hook . eldoc-mode)
(org-mode . eldoc-mode)))
16.5 Zig mode #
(use-package zig-mode
:config
(add-to-list 'auto-mode-alist '("\\.zig\\'" . zig-mode)))
16.6 Yaml #
(use-package yaml-mode
:config
;;autoloads
(add-to-list 'auto-mode-alist '("\\.yml\\'" . yaml-mode))
;; indent and new-line on return; the mode enforces spaces instead
;; of tabs
(add-hook 'yaml-mode-hook
(lambda ()
(define-key yaml-mode-map "\C-m" 'newline-and-indent))))
17 Terminal #
Vterm ftw
(use-package vterm
;; :ensure t
:load-path "/usr/lib/libvterm.so.0.0.3"
:init
;; (setq vterm-term-environment-variable "eterm-256color")
(setq vterm-disable-bold-font t)
(setq vterm-kill-buffer-on-exit t)
(setq vterm-module-cmake-args "-DUSE_SYSTEM_LIBVTERM=no")
(setq vterm-always-compile-module t)
(setq vterm-copy-exclude-prompt t))
Make vterm behave like a guake terminal and open below the main window. This can be toggled and opens only one instance per window (afaik). Considering using this feature to not provide a dedicated buffer to vterm so it sticks to the window it was launched with.
(use-package vterm-toggle
:bind
(("C-M-'" . vterm-toggle-cd))
:config
;; reset window layout after kill
(setq vterm-toggle-reset-window-configration-after-exit t)
;; toggle behaviour - like a toggle keep it running
(setq vterm-toggle-hide-method nil)
Show vterm in a window at the bottom
(setq vterm-toggle-fullscreen-p nil)
(add-to-list 'display-buffer-alist
'((lambda(bufname _) (with-current-buffer bufname (equal major-mode 'vterm-mode)))
(display-buffer-reuse-window display-buffer-at-bottom)
;;(display-buffer-reuse-window display-buffer-in-direction)
;;display-buffer-in-direction/direction/dedicated is added in emacs27
;;(direction . bottom)
;;(dedicated . t) ;dedicated is supported in emacs27
(reusable-frames . visible)
(window-height . 0.3)))
Make counsel use the correct function to yank in vterm buffers.
(defun vterm-counsel-yank-pop-action (orig-fun &rest args)
(if (equal major-mode 'vterm-mode)
(let ((inhibit-read-only t)
(yank-undo-function (lambda (_start _end) (vterm-undo))))
(cl-letf (((symbol-function 'insert-for-yank)
(lambda (str) (vterm-send-string str t))))
(apply orig-fun args)))
(apply orig-fun args)))
(advice-add 'counsel-yank-pop-action :around #'vterm-counsel-yank-pop-action))
18 Multimedia #
18.1 EMMS for music #
(use-package emms
:commands emms
:config
(require 'emms-setup)
(emms-standard)
(emms-default-players)
(emms-mode-line-disable)
(setq emms-source-file-default-directory "~/Music/")
;;(dw/leader-key-def
;;"am" '(:ignore t :which-key "media")
;;"amp" '(emms-pause :which-key "play / pause")
;;"amf" '(emms-play-file :which-key "play file"))
)
TODO 18.2 View ePubs and PDFs in Emacs #
(use-package nov
:mode ("\\.epub\\'" . nov-mode)
:config (nov-text-width 75))
(use-package pdf-tools
:magic ("%PDF" . pdf-view-mode)
:mode ("\\.pdf\\'" . pdf-view-mode)
:config (pdf-tools-install :no-query))
;; TODO this needs fixing idk why even
;; (use-package pdf-view
;; :ensure nil
;; :after pdf-tools
;; :bind (:map pdf-view-mode-map
;; ("C-s" . isearch-forward)
;; ("d" . pdf-annot-delete)
;; ("h" . pdf-annot-add-highlight-markup-annotation)
;; ("t" . pdf-annot-add-text-annotation))
;; :custom
;; (pdf-view-display-size 'fit-page)
;; (pdf-view-resize-factor 1.1)
;; (pdf-view-use-unicode-ligther nil))
19 Web #
Got most of these from daviwil’s literate configuration
19.1 Gemini #
(use-package elpher)
TODO 19.2 mail with mu4e #
see daviwil’s mail.org and the configuration in his literate config.
TODO 19.3 Browser #
19.4 Elfeed for RSS #
(use-package elfeed
:commands elfeed
:config
(setq elfeed-feeds
'("https://drewdevault.com/blog/index.xml"
"https://sourcehut.org/blog/index.xml"
"https://ambikamath.com/feed/"
"https://emersion.fr/blog/atom.xml"
"https://popagandhi.com/index.xml")))
20 Footer #
;;; configuration.el ends here