Emacs literate configuration

42 minute read

Ducks

Introduction

To compile literate configuration setup init.el to point to this file. Make sure this file is not named `init.org` as org-babel will generate a .el file too and we don’t want it to be init

Core

This will generate a header at the top of the tangled file to indicate it is generated and is not meant to be modified directly.

 1;; -*- lexical-binding: t -*-
 2;; This file has been generated from dotemacs.org file. DO NOT EDIT.
 3;; Sources are available from https://github.com/shravantata/org
 4
 5;; Copyright (C) 2024 Shravan Tata Ramalingasetty
 6
 7;; This file is free software; you can redistribute it and/or modify
 8;; it under the terms of the GNU General Public License as published by
 9;; the Free Software Foundation; either version 3, or (at your option)
10;; any later version.
11
12;; This file is distributed in the hope that it will be useful,
13;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15;; GNU General Public License for more details.
16
17;; For a full copy of the GNU General Public License
18;; see <https://www.gnu.org/licenses/>.
1(defvar rougier/init-start-time (current-time) "Time when init.el was started")
2(defvar rougier/section-start-time (current-time) "Time when section was started")
3(defun rougier/report-time (section)
4  (message "%-36s %.2fs"
5           (concat section " " "section time: ")
6           (float-time (time-subtract (current-time) rougier/section-start-time))))
7(message "---------------------------------------------------------------")

Basic information

Set basic information such as name and contact details of the primary user

1(setq user-full-name    "Shravan Tata Ramalingasetty"
2      user-mail-address "shravantr@gmail.com")

Early init

This file is loaded before the package system and GUI is initialized, so in it you can customize variables that affect the package initialization process, such as package-enable-at-startup, package-load-list, and package-user-dir

 1;; Early initialization before running the init script
 2(setq
 3 site-run-file nil                         ; No site-wide  run-time initializations
 4 inhibit-default-init t                    ; No site-wide default library
 5 gc-cons-threshold most-positive-fixnum    ; Very large threshold for garbage collector during init
 6 package-enable-at-startup nil)            ; We'll use straight.el
 7
 8(setq native-comp-eln-load-path
 9      (list (expand-file-name "eln-cache" user-emacs-directory)))
10
11;; Reset garbage collector limit after init process has ended (8Mo)
12(add-hook 'after-init-hook
13          #'(lambda () (setq gc-cons-threshold (* 8 1024 1024))))
14
15(setq package-enable-at-startup nil)

Defaults

 1(setq
 2 ;; Confirm before exiting emacs
 3 confirm-kill-emacs 'yes-or-no-p
 4 ;;  Do not echo
 5 inhibit-startup-echo-area-message nil
 6 ;; Don't describe a scratch message
 7 initial-scratch-message nil
 8 ;; Start full screen and maximized
 9 initial-frame-alist (quote ((fullscreen . maximized)))
10 ;; start every frame maximized
11 default-frame-alist (quote ((fullscreen . maximized)))
12 ;; Never ding at me, ever.
13 ring-bell-function 'ignore
14 ;; Save existing clipboard text into the kill ring before replacing it.
15 save-interprogram-paste-before-kill t
16 ;; Prompts should go in the minibuffer, not in a GUI.
17 use-dialog-box nil
18 ;; Fix undo in commands affecting the mark.
19 mark-even-if-inactive nil
20 ;; Let C-k delete the whole line.
21 kill-whole-line t
22 ;; search should be case-sensitive by default
23 case-fold-search nil
24 ;; I want to close these fast, so switch to it so I can just hit 'q'
25 help-window-select t
26 ;; this certainly can't hurt anything
27 delete-by-moving-to-trash t
28 ;; keep the point in the same place while scrolling
29 scroll-preserve-screen-position t
30 ;; highlight error messages more aggressively
31 next-error-message-highlight t
32 ;; don't let the minibuffer muck up my window tiling
33 read-minibuffer-restore-windows t
34 ;; scope save prompts to individual projects
35 save-some-buffers-default-predicate 'save-some-buffers-root
36 ;; don't keep duplicate entries in kill ring
37 kill-do-not-save-duplicates t
38   ;;; Performance
39 ;; Prefer loading newer compiled files
40 load-prefer-newer t
41 ;; Increase how much is read from processes in a single chunk (default is 4kb).
42 read-process-output-max (* 512 1024) ; 512kb
43 ;; Reduce rendering/line scan work by not rendering cursors or regions in
44 ;; non-focused windows.
45 highlight-nonselected-windows nil
46 ;; Disable warnings from the legacy advice API. They aren't useful.
47 ad-redefinition-action 'accept
48 ;; Don't ping things that look like domain names.
49 ffap-machine-p-known 'reject
50 ;; By default, Emacs "updates" its ui more often than it needs to
51 idle-update-delay 1.0
52 ;; The title bar
53 ns-use-proxy-icon nil
54 frame-title-format nil)
55
56
57(setq-default cursor-in-non-selected-windows nil)
58
59(defvar minimal-emacs-frame-title-format "%b – Emacs"
60  "Template for displaying the title bar of visible and iconified frame.")
61
62(defvar minimal-emacs-debug nil
63  "Non-nil to enable debug.")
64
65;; Suppress compiler warnings and don't inundate users with their popups.
66(setq native-comp-async-report-warnings-errors
67      (or minimal-emacs-debug 'silent))
68(setq native-comp-warning-on-missing-source minimal-emacs-debug)
69
70(setq debug-on-error minimal-emacs-debug
71      jka-compr-verbose minimal-emacs-debug)
72
73(setq byte-compile-warnings minimal-emacs-debug)
74(setq byte-compile-verbose minimal-emacs-debug)
75
76(add-to-list 'default-frame-alist '(ns-transparent-titlebar . t))
77(add-to-list 'default-frame-alist '(ns-appearance . light))

Welcome message

1(let ((inhibit-message t))
2  (message "Welcome Shravan Tata! /  Don't just get used to your tool, make it get used to you! ")
3  (message (format "Initialization time: %s" (emacs-init-time))))

Package management

Setup the package management used by emacs to manage and install the necessary packages on the fly at the load time.

1(message "Setting up emacs package management...")

Bootstrap straight.el

Using straight.el for package management and disable checking (for speedup).

1(setq straight-check-for-modifications nil)
 1(defvar bootstrap-version)
 2(let ((bootstrap-file
 3       (expand-file-name "straight/repos/straight.el/bootstrap.el" user-emacs-directory))
 4      (bootstrap-version 6))
 5  (unless (file-exists-p bootstrap-file)
 6    (with-current-buffer
 7        (url-retrieve-synchronously
 8         "https://raw.githubusercontent.com/radian-software/straight.el/develop/install.el"
 9         'silent 'inhibit-cookies)
10      (goto-char (point-max))
11      (eval-print-last-sexp)))
12  (load bootstrap-file nil 'nomessage))

Custom paths

 1;; User path for saving files
 2;; (setq prelude-savefile-dir (expand-file-name "lisp" user-emacs-directory))
 3
 4;; path to store lisp byte code
 5(add-to-list 'load-path
 6             (expand-file-name "lisp" user-emacs-directory))
 7;; path to store custom themes
 8(add-to-list 'custom-theme-load-path
 9             (expand-file-name "themes" user-emacs-directory))
10
11
12;; store all backup and autosave files in the tmp dir
13(setq backup-directory-alist
14      `((".*" . ,temporary-file-directory)))
15(setq auto-save-file-name-transforms
16      `((".*" ,temporary-file-directory t)))

Package profiling

1(setq use-package-compute-statistics t)

Packages installation

List all the packages that are required to be installed for the current configuration of emacs

  1(setq package-list
  2      '(
  3        ;; package configuration
  4        use-package                     ; A configuration macro for simplifying your .emacs
  5        ;; emacs
  6        gcmh                            ; Garbage collector magic hack
  7        esup                            ; Emacs profiler
  8        ;; editing
  9        crux                            ; A Collection of Ridiculously Useful eXtensions for Emacs.
 10        multiple-cursors                ; Edit multiple cursors
 11        ;; interface
 12        eyebrowse                       ; A simple-minded way of managing window configs
 13        orderless                       ; Use space-separated search terms in any order when completing with Icomplete or the default interface
 14        smartparens                     ; Smart parentheses
 15        ag                              ; faster search (requires system installation)
 16        ;; visual
 17        zone                            ; Mode to avoid zoning out
 18        olivetti                        ; Pleasant reading
 19        ;; themes
 20        nano-theme                      ; Nano theme from rougier
 21        spacemacs-theme                 ; Spacemacs theme
 22        catppuccin-theme                ; Catppuccin theme
 23        ;; navigation
 24        imenu-list                      ; Show imenu entries in a separate buffer
 25        ;; mini-buffer
 26        ;; helm                            ; A powerful completion and selection narrowing framework
 27        corfu                           ; Completion Overlay Region FUnction
 28        orderless                       ; orderless completion style
 29        vertico                         ; a performant and minimalistic vertical completion UI
 30        cape                            ; Cape provides Completion At Point Extensions which can be used in combination with the Corfu
 31        marginalia                      ; Show document of function in ==M-x=,
 32        consult                         ; provides various practical commands
 33        mini-frame                      ; Show minibuffer in child frame on read-from-minibuffer
 34        ;; minibuffer-header
 35        ;; modeline
 36        spaceline                       ; Spacemacs themed modeline
 37        ;; parsing
 38        tree-sitter                     ; tree-sitter
 39        tree-sitter-langs               ; tree-sitter-langs
 40        ;; versioning
 41        magit                           ; A Git porcelain inside Emacs
 42        diff-hl                         ; Highlights uncommitted changes in the gutter
 43        git-gutter                      ; Show git line status
 44        ;; history
 45        undo-tree                       ; Shows a tree like structure of the history
 46        ;; file
 47        dired-subtree                   ; Dired extensions
 48        openwith                        ; Open files appropriately using external apps
 49        ;; project management
 50        projectile                      ; Project interaction library for Emacs
 51        consult-projectile
 52        consult-project-extra           ; extra features for project management
 53        ;; citations
 54        citar                           ; Citation-related commands for org, latex, markdown
 55        citeproc                        ; A CSL 1.0.2 Citation Processor
 56        ;; orgmode
 57        org-bullets                     ; Shows org-mode bullets as pretty UTF-8 characters
 58        svg-lib                         ; svg tags and icons from rougier
 59        svg-tag-mode                    ; svg tags and icons from rougier
 60        bibtex                          ; for reference management
 61        org-ref                         ; Reference manager for orgmode
 62        ox-hugo                         ; Hugo exporter for org mode
 63        org-modern                      ; Modern theming for org mode language
 64        langtool                        ; English grammar and spelling check
 65        flycheck-languagetool           ; Text suggestions for english
 66        ;; proselint                    ; a linter for English prose
 67        writegood-mode                  ; Text analysis
 68        smog
 69        ;; powerthesaurus                  ; Finding synonyms, antonyms, and related terms
 70        ;; programming
 71        ;; general
 72        ;; lsp-mode
 73        guess-language                  ; Robust automatic language detection
 74        rainbow-delimiters              ; Adds colors to delimiters
 75        yasnippet                       ; yet another snippet
 76        yasnippet-snippets              ; snippets for many programming languages
 77        flycheck                        ; Modern on-the-fly syntax checking
 78        whitespace                      ; Mode for remove whitespaces
 79        ;; workflow
 80        snakemake-mode                  ; Major mode for snakemake files
 81        ;; python
 82        elpy                            ; Python Development Environment
 83        jedi                            ; Python auto-completion package
 84        sphinx-doc                      ; Doc pages for python
 85        cython-mode                     ; Cython major mode
 86        flycheck-cython                 ; Syntax checking for cython
 87        fill-column-indicator           ; Column indicator for python
 88        column-enforce-mode             ; Column enforcement for python
 89        pyenv-mode                      ; Environments for python
 90        pyvenv                          ; Activate virtual environments for python
 91        isortify                        ; For formating python imports
 92        ;; GL
 93        glsl-mode                       ; model GLSL shaders
 94        ;; godot
 95        gdscript-mode                   ; Godot programming mode
 96        ;; lisp
 97        paredit                         ; paredit
 98        ;; html
 99        htmlize                         ; Convert buffer text and decorations to HTML
100        markdown-mode                   ; Major mode for Markdown-formatted text
101        ;; yaml
102        yaml-mode                       ; Major mode for editing yaml files
103        ;; latex
104        company-auctex                  ; auto-completion for latex
105        ;; help
106        ;; flyspell-correct-popup          ; Correcting words with flyspell via popup interface
107        ;; flyspell-popup                  ; Correcting words with Flyspell in popup menus
108        helpful                         ; A better help buffer
109        which-key                       ; shows you possible keybindings when you type a partial keybinding
110        ;; remote
111        ssh                             ; ssh mode remote file connection
112        ;; misc
113        all-the-icons                   ; Excellent library of icons for filetypes
114        all-the-icons-completion        ;
115        mode-icons                      ; Icons for filetypes in modeline
116        exec-path-from-shell		    ; Reflect system paths in Emacs
117        ;; whisper                      ; Speech to text
118        ;; AI
119        gptel                           ; AI LLM interface for emacs
120        ;; fun
121        xkcd                            ; xkcd config
122        ;; versioning
123        llama                           ; requirement for magit
124        )
125      )
126
127;; Exception for org to use system org version
128(straight-use-package '(org :type built-in))
129
130;; Install packages that are not yet installed
131(dolist (package package-list)
132  (straight-use-package package))
133
134;; Special case for ospl-mode
135(straight-use-package
136 '(ospl-mode :type git :host github :repo "arrdem/ospl-mode"))
137
138;; Special case for pdf-tools that has recently (2022) changed maintainer
139(straight-use-package
140 '(pdf-tools :type git :host github :repo "vedang/pdf-tools"))
141
142;; Display org properties in the agenda buffer (modified version)
143(straight-use-package
144 '(org-agenda-property :type git :host github :repo "Malabarba/org-agenda-property"))
145
146(straight-use-package
147 '(shell-maker :type git :host github :repo "xenodium/chatgpt-shell" :files ("shell-maker.el")))
148
149(straight-use-package
150 '(chatgpt-shell :type git :host github :repo "xenodium/chatgpt-shell" :files ("chatgpt-shell.el")))
151
152(straight-use-package
153 '(indent-bars :type git :host github :repo "jdtsmith/indent-bars"))
154
155
156(straight-use-package
157 '(org-appear :type git :host github :repo "awth13/org-appear"))
158
159(straight-use-package
160 '(pinerose-emacs :type git :host github :repo "konrad1977/pinerose-emacs"))
161
162(straight-use-package
163 '(aider :type git :host github :repo "tninja/aider.el"))

Customization

Since init.el will be generated from this file, we save customization in a dedicated file.

1(setq custom-file (concat user-emacs-directory "custom.el"))
2
3(when (file-exists-p custom-file)
4  (load custom-file nil t))

A GNU Emacs library to ensure environment variables inside Emacs look the same as in the user’s shell.

This sets $MANPATH, $PATH and exec-path from your shell, but only when executed in a GUI frame on OS X and Linux.

https://github.com/purcell/exec-path-from-shell

1(when (memq window-system '(mac ns x))
2  (exec-path-from-shell-initialize))

Encoding

We tell emacs to use UTF-8 encoding as much as possible.

1(set-default-coding-systems 'utf-8)     ; Default to utf-8 encoding
2(prefer-coding-system       'utf-8)     ; Add utf-8 at the front for automatic detection.
3(set-terminal-coding-system 'utf-8)     ; Set coding system of terminal output
4(set-keyboard-coding-system 'utf-8)     ; Set coding system for keyboard input on TERMINAL
5(set-language-environment "UTF-8")      ;

Global

1(add-hook 'after-init-hook #'global-flycheck-mode)

Recent files

50 Recents files with some exclusion (regex patterns).

 1(require 'recentf)
 2
 3(setq recentf-max-menu-items 10
 4      recentf-max-saved-items 100
 5      recentf-exclude '()
 6      ;; disable recentf-cleanup on Emacs start, because it can cause
 7      ;; problems with remote files
 8      recentf-auto-cleanup 'never
 9      )
10
11(let (message-log-max)
12  (recentf-mode 1))

History

Remove text properties for kill ring entries (see https://emacs.stackexchange.com/questions/4187). This saves a lot of time when loading it.

1(defun unpropertize-kill-ring ()
2  (setq kill-ring (mapcar 'substring-no-properties kill-ring)))
3
4(add-hook 'kill-emacs-hook 'unpropertize-kill-ring)

We save every possible history we can think of.

 1(require 'savehist)
 2
 3(setq kill-ring-max 50
 4      history-length 50)
 5
 6(setq savehist-additional-variables
 7      '(kill-ring
 8        command-history
 9        set-variable-value-history
10        custom-variable-history
11        query-replace-history
12        read-expression-history
13        minibuffer-history
14        read-char-history
15        face-name-history
16        bookmark-history
17        file-name-history))
18
19 (put 'minibuffer-history         'history-length 50)
20 (put 'file-name-history          'history-length 50)
21 (put 'set-variable-value-history 'history-length 25)
22 (put 'custom-variable-history    'history-length 25)
23 (put 'query-replace-history      'history-length 25)
24 (put 'read-expression-history    'history-length 25)
25 (put 'read-char-history          'history-length 25)
26 (put 'face-name-history          'history-length 25)
27 (put 'bookmark-history           'history-length 25)

No duplicates in history

1(setq history-delete-duplicates t)

Start history mode.

1(let (message-log-max)
2  (savehist-mode))

Server

Server start.

1(require 'server)
2
3(unless (server-running-p)
4  (server-start))

Post

1;; Make gc pauses faster by decreasing the threshold.
2(setq gc-cons-threshold (* 2 1000 1000))

Garbage

Used by DOOM to manage garbage collection

1(use-package gcmh
2  :demand
3  :config
4  (gcmh-mode 1))

Definitions

Local function definitions to facilitate emacs setup

1(defun waveparticle/langtool-autosave-hook ()
2  ;; Check grammar with langtool before save
3  (add-hook 'before-save-hook 'langtool-check-buffer nil 'local))

Benchmark

1(rougier/report-time "Core")

Interface

1(setq rougier/section-start-time (current-time))

Frame

1;; Disable horizontal scroll bars in GUI
2(when (fboundp 'horizontal-scroll-bar-mode)
3  (horizontal-scroll-bar-mode 0))

Window

Winner mode is a global minor mode that records the changes in the window configuration

1(winner-mode t)
1(setq-default window-divider-default-right-width 6 ; Vertical window divider
2              window-divider-default-places 'right-only
3              left-margin-width 0
4              right-margin-width 0
5              window-combination-resize nil) ; Do not resize windows proportionally
6
7(window-divider-mode 1)

Setup windmove to easily move between windows

1(require 'windmove)
2
3;; use command key on Mac
4(windmove-default-keybindings 'super)
5;; wrap around at edges
6(setq windmove-wrap-around t)

Setup eyebrowse to create and interact with workspaces

 1(require 'eyebrowse)
 2
 3;; Enable eyebrowse mode
 4(eyebrowse-mode t)
 5;; Start the new window to be as empty as possible
 6(setq eyebrowse-new-workspace t)
 7;; bind keys for easier movement between windows
 8(bind-key "M-1" #'eyebrowse-switch-to-window-config-1 'eyebrowse-mode-map)
 9(bind-key "M-2" #'eyebrowse-switch-to-window-config-2 'eyebrowse-mode-map)
10(bind-key "M-3" #'eyebrowse-switch-to-window-config-3 'eyebrowse-mode-map)
11(bind-key "M-4" #'eyebrowse-switch-to-window-config-4 'eyebrowse-mode-map)

Buffers

Set unique buffer names

1(message "Personal config :. uniquify...")
2;; meaningful names for buffers with the same name
3;; from prelude
4;; https://github.com/bbatsov/prelude
5(require 'uniquify)
6(setq uniquify-buffer-name-style 'forward)
7(setq uniquify-separator "/")
8(setq uniquify-after-kill-buffer-p t)    ; rename after killing uniquified
9(setq uniquify-ignore-buffers-re "^\\*") ; don't muck with special buffers

Dialog

Pop up windows are needed for `display-buffer` to able to split window. For example, for magit to create a new window for writing the commit message.

1(tool-bar-mode -1)                      ; remove tool bar
2(scroll-bar-mode -1)                    ; remove scroll bar
3(tooltip-mode -1)                       ; remove tooltips
4
5(setq-default show-help-function nil    ; No help text
6              use-file-dialog nil       ; No file dialog
7              use-dialog-box nil        ; No dialog box
8              ;; pop-up-windows nil        ; No pop windows
9)

Specific case for OSX since menubar is desktop-wide (see emacs.stackexchange.com/questions/28121) and emacs-mac documentation.

1(menu-bar-mode 1)

Key bindings

Section to remap general keybindings. Should be used sparingly!

1;; Stop opening buffer list accidently
2(unbind-key "C-x C-b")
1;; (global-set-key (kbd "C-S-<left>")  'tabbar-backward)
2;; (global-set-key (kbd "C-S-<right>") 'tabbar-forward)
3;; (global-set-key (kbd "C-S-<up>")    'tabbar-backward-group)
4;; (global-set-key (kbd "C-S-<down>")  'tabbar-forward-group)
5;; (global-set-key (kbd "C-h")  'delete-backward-char)
6;; (global-set-key (kbd "M-h")  'delete-backward-word)

Keyboard

The mode displays the key bindings following your currently entered incomplete command (a ;; prefix) in a popup.

1
2(require 'which-key)
3
4(which-key-mode)

Mouse

Mouse avoidance to move the mouse pointer away from the cursor

1
2(setq-default mouse-yank-at-point t) ; Yank at point rather than pointer
3'(mouse-avoidance-mode (quote animate) nil (avoid))

Mouse active in tty mode.

1
2(unless (display-graphic-p)
3  (xterm-mouse-mode 1)
4  (global-set-key (kbd "<mouse-4>") #'scroll-down-line)
5  (global-set-key (kbd "<mouse-5>") #'scroll-up-line))

Sound

Disable the bell (auditory or visual).

1(setq-default visible-bell nil             ; No visual bell
2              ring-bell-function 'ignore)  ; No bell

Scroll

Smoother scrolling

1(pixel-scroll-precision-mode)
1(setq-default scroll-conservatively 101       ; Avoid recentering when scrolling far
2              scroll-margin 2                 ; Add a margin when scrolling vertically
3              recenter-positions '(5 bottom)) ; Set re-centering positions

Clipboard

Allows system and Emacs clipboard to communicate smoothly (both ways)

1(setq-default select-enable-clipboard t) ; Merge system's and Emacs' clipboard

Make sure clipboard works properly in tty mode on OSX.

 1(defun my/paste-from-osx ()
 2  (shell-command-to-string "pbpaste"))
 3
 4(defun my/copy-to-osx (text &optional push)
 5  (let ((process-connection-type nil))
 6    (let ((proc (start-process "pbcopy" "*Messages*" "pbcopy")))
 7      (process-send-string proc text)
 8      (process-send-eof proc))))
 9
10(when (and (not (display-graphic-p))
11           (eq system-type 'darwin))
12  (setq interprogram-cut-function   #'my/copy-to-osx
13        interprogram-paste-function #'my/paste-from-osx))

Help

Helpful is an alternative to the built-in Emacs help that provides much more contextual information. It is a bit slow to load so we do need load it explicitly.

1(setq help-window-select t)             ; Focus new help windows when opened
2
3(bind-key "C-h f"   #'helpful-callable) ; Look up callable
4(bind-key "C-h v"   #'helpful-variable) ; Look up variable
5(bind-key "C-h k"   #'helpful-key)      ; Look up key
6(bind-key "C-c C-d" #'helpful-at-point) ; Look up the current symbol at point
7(bind-key "C-h F"   #'helpful-function) ; Look up *F*unctions (excludes macros).
8(bind-key "C-h C"   #'helpful-command)  ; Look up *C*ommands.

Widgets

1;; No ugly button for checkboxes
2(setq widget-image-enable nil)

Text

Shorten confirmation inputs

1(setq-default
2 use-short-answers t                    ; Replace yes/no prompts with y/n
3 confirm-nonexistent-file-or-buffer nil ; Ok to visit non existent files
4 )

Replace text when writing over a region

1;; overwrite selected text
2(delete-selection-mode t)

Some other defaults

1;; Double-spaces after periods is morally wrong.
2(setq sentence-end-double-space nil)

Typography

  • Column width increased to 88 from default 80. Black (python linter) suggests this to be a better default over the legacy 80 chars
  • Nicer and cleaner ellipsis
1(setq-default
2 fill-column 88                          ; Default line width increased by 8 chars
3 sentence-end-double-space nil           ; Use a single space after dots
4 bidi-paragraph-direction 'left-to-right ; Faster
5 truncate-string-ellipsis "…"            ; Nicer ellipsis
6 )
 1;; Nicer glyphs for continuation and wrap
 2
 3(defface my-wrap-symbol-face
 4  '((t (:family "JetBrains Mono"
 5                :weight light)))
 6  "Specific face for wrap symbol")
 7
 8(set-display-table-slot standard-display-table
 9                        'truncation (make-glyph-code ?… 'my-wrap-symbol-face))
10
11(set-display-table-slot standard-display-table
12                        'wrap (make-glyph-code ?↩ 'my-wrap-symbol-face))

Fix a bug on OSX in term mode & zsh (spurious “%” after each command)

1(when (eq system-type 'darwin)
2    (add-hook 'term-mode-hook
3              (lambda ()
4                (setq buffer-display-table (make-display-table)))))

Make sure underline is positionned at the very bottom.

1(setq x-underline-at-descent-line nil
2        x-use-underline-position-properties t
3        underline-minimum-offset 10)

Project

Use projectile to navigate easily between projects

 1(require 'projectile)
 2
 3(projectile-mode +1)
 4
 5(if (eq system-type 'darwin)
 6    ;; Recommended keymap prefix on macOS
 7    (define-key projectile-mode-map (kbd "s-p") 'projectile-command-map)
 8  ;; Recommended keymap prefix on Windows/Linux
 9  (define-key projectile-mode-map (kbd "C-c p") 'projectile-command-map)
10  )

Use projectile to launch dired when invoked

1(setq projectile-switch-project-action #'projectile-dired)

Disable projectile when using tramp to speed things

1(defadvice projectile-on (around exlude-tramp activate)
2  "This should disable projectile when visiting a remote file"
3  (unless  (--any? (and it (file-remote-p it))
4                   (list
5                    (buffer-file-name)
6                    list-buffers-directory
7                    default-directory
8                    dired-directory))
9    ad-do-it))

Setup projecticle to automatically discover projects

1(setq projectile-auto-discover nil)
2(add-hook 'after-init-hook #'(lambda () (projectile-discover-projects-in-directory "~/projects" 7)))

Files

Filesystems, autosaves and backups

Emacs is super fond of littering filesystems with backups and autosaves, since it was built with the assumption that multiple users could be using the same Emacs instance on the same filesystem. This was valid in 1980. It is no longer the case.

1(setq make-backup-files nil auto-save-default nil create-lockfiles nil)

Configure dired

 1(message "Personal config :. dired-subtree...")
 2
 3(require 'dired-subtree)
 4
 5(bind-keys :map dired-mode-map
 6           ("i" . dired-subtree-insert)
 7           (";" . dired-subtree-remove))
 8
 9(when (eq system-type 'darwin)
10  (setq insert-directory-program "gls" dired-use-ls-dired t)
11  (setq dired-listing-switches "-al --group-directories-first")
12 )
13
14(when (eq system-type 'gnu/linux)
15  (setq dired-listing-switches "-aBhl  --group-directories-first")
16 )
17
18(setq dired-kill-when-opening-new-dired-buffer t)

configure ssh for remote files

1(require 'ssh)
2
3(add-hook 'ssh-mode-hook
4          (lambda ()
5            (setq ssh-directory-tracking-mode t)
6            (shell-dirtrack-mode t)
7            (setq dirtrackp nil)))
1;; tramp, for sudo access
2(require 'tramp)
3;; keep in mind known issues with zsh - see emacs wiki
4(setq tramp-default-method "ssh")

Benchmark

1
2(rougier/report-time "Interface")

Use ag as alternate to default search. Requires system installation

1; Highlight search results when using ag
2(setq ag-highlight-search t)

Visual

1
2(setq rougier/section-start-time (current-time))

Font

Some defaults for EMACS

It’s good that Emacs supports the wide variety of file encodings it does, but UTF-8 should always, always be the default.

1(set-charset-priority 'unicode)
2(prefer-coding-system 'utf-8-unix)

This is the font stack we install:

  • Default font: JetBrains Mono 12pt Regular
  • Italic font: JetBrains Mono 12pt Light
  • Bold font: JetBrains Mono 12pt Bold
  • Unicode font: jetBrains Mono 14pt Light
  • Icon font: JetBrains Mono Nerd 12pt Light

┌───────────────────────────────────────────────┐ │  The quick brown fox jumps over the lazy dog │ │  The quick brown fox jumps over the lazy dog ┼─ JetBrains Mono Italic │  The quick brown fox jumps over the lazy dog ├─ JetBrains Mono Bold └─┼───────────────────────────┼─────────────────┘ JetBrains Mono Nerd JetBrains Mono

 1(set-face-attribute 'default nil
 2                    :family "JetBrains Mono"
 3                    :weight 'regular
 4                    :height 128)
 5
 6(set-face-attribute 'bold nil
 7                    :family "JetBrains Mono"
 8                    :weight 'bold)
 9
10(set-face-attribute 'italic nil
11                    :family "JetBrains Mono"
12                    :weight 'light
13                    :slant 'italic)
14
15(set-fontset-font t 'unicode
16                  (font-spec :name "Jetbrains Mono"
17                             :weight 'light
18                             :size 13) nil)
19
20(set-fontset-font t '(#xe000 . #xffdd)
21                  (font-spec :name "JetBrainsMono Nerd Font"
22                             :size 13) nil)

Splash screen

Add a splash screen image and welcome message with some stats

1(add-to-list 'load-path "~/fork/emacs-splash/")
2(require 'splash-screen)

Colors

Themes

Catppuccin

1(load-theme 'catppuccin :no-confirm)
2(setq catppuccin-flavor 'latte);; or 'latte, 'macchiato, or 'mocha or 'frappe
3
4;; ;; Change colors
5;; (catppuccin-set-color 'base "#000000") ;; change base to #000000 for the currently active flavor
6;; (catppuccin-set-color 'crust "#222222" 'frappe) ;; change crust to #222222 for frappe
7;; (set-face-attribute 'region nil :background "#434C5E")
8(catppuccin-reload)

Leuven

1(load-theme 'leuven t)

Nord theme

1(load-theme 'nord t)

Typography

1(setq x-underline-at-descent-line nil
2      x-use-underline-position-properties t
3      underline-minimum-offset 10)

Fancy icons

Enable mode-icons

1(require 'mode-icons)
2(mode-icons-mode t)

Configure all-the-icons to work with required types

In order for the icons to work it is very important that you install the Resource Fonts included in this package, they are available in the fonts directory.

1(all-the-icons-completion-mode)
2(add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup)

Focus

Use zone mode is avoid blank staring at the screen

1(require 'zone)
2(zone-when-idle 30000)

Misc

1;; No ugly button for checkboxes
2(setq widget-image-enable nil)

Benchmark

1(rougier/report-time "Visual")

Editing

1(setq rougier/section-start-time (current-time))

Default mode

Default & initial mode is text.

1(setq-default initial-major-mode 'text-mode   ; Initial mode is text
2              default-major-mode 'text-mode)  ; Default mode is text

Visual line mode for prog and text modes

1(add-hook 'text-mode-hook 'visual-line-mode)
2(add-hook 'prog-mode-hook 'visual-line-mode)

Tree-sitter

1(setq major-mode-remap-alist
2 '((python-mode . python-ts-mode)))
3
4;; (yaml-mode . yaml-ts-mode)
5;;    (bash-mode . bash-ts-mode)
6;;    (js2-mode . js-ts-mode)
7;;    (typescript-mode . typescript-ts-mode)
8;;    (json-mode . json-ts-mode)
9;;    (css-mode . css-ts-mode)

Text

Subword movement lets us treat “EmacsIsAwesome” as three words ─“Emacs”, “Is”, and “Awesome”─ which is desirable since such naming is common among coders. Now, for example, M-f moves along each subword.

1(global-subword-mode 1)
2;; (diminish 'subword-mode)

Multiple cursors for editing

1(require 'multiple-cursors)
2(multiple-cursors-mode t)
3(bind-key "C-S-c C-S-c" #'mc/edit-lines)
4(bind-key "C->" #'mc/mark-next-like-this)
5(bind-key "C-<" #'mc/mark-previous-like-this)
6(bind-key "C-c C-<" #'mc/mark-all-like-this)
 1(require 'indent-bars)
 2
 3;; indent-bars will not attempt stipple display, but instead use simple characters e.g. |; see an example
 4;; M-x version should say Carbon, not NS.
 5;; The NS build has partial stipple support in master, which may be released in Emacs v30.
 6(setq indent-bars-prefer-character t
 7      indent-bars-display-on-blank-lines nil
 8      indent-bars-width-frac 0.5
 9 )
10
11;; modes to enabel indent bars by default
12(add-hook 'python-mode-hook 'indent-bars-mode)
13(setq indent-bars-treesit-support t
14      indent-bars-treesit-wrap '((python function_definition
15                                         class_definition
16                                         for_statement
17                                         if_statement
18                                         with_statement
19                                         while_statement
20                                         argument_list
21                                         parameters
22                                         list
23                                         list_comprehension
24                                         dictionary
25                                         dictionary_comprehension
26                                         parenthesized_expression
27                                         subscript))
28      indent-bars-treesit-ignore-blank-lines-types '("module")
29 )
30(add-hook 'yaml-mode-hook 'indent-bars-mode)

whitespace-mode config

1;; whitespace-mode config
2(require 'whitespace)
3(setq whitespace-line-column 80) ;; limit line length
4(setq whitespace-style '(face tabs empty trailing lines-tail))
5(add-hook 'before-save-hook 'whitespace-cleanup)
1(require 'ospl-mode)

History

Setup undo-tree

1(global-undo-tree-mode)
2(setq undo-tree-limit 240000)
3
4;; Prevent undo tree files from polluting your git repo
5(setq undo-tree-history-directory-alist '(("." . "~/.emacs.d/undo")))

Tabulations

No tabulation, ever.

1(setq-default indent-tabs-mode nil        ; Stop using tabs to indent
2              tab-always-indent 'complete ; Indent first then try completions
3              tab-width 4)                ; Smaller width for tab characters
4
5;; Let Emacs guess Python indent silently
6(setq python-indent-guess-indent-offset t
7      python-indent-guess-indent-offset-verbose nil)

Parenthesis

Paren mode for highlighting matching parenthesis

1(require 'paren)
2;; (setq show-paren-style 'expression)
3(setq show-paren-style 'parenthesis)
4(setq show-paren-when-point-in-periphery t)
5(setq show-paren-when-point-inside-paren nil)
6(show-paren-mode)
1(electric-pair-mode)

Rainbow delimiters

1(require 'rainbow-delimiters)
2(add-hook 'prog-mode-hook #'rainbow-delimiters-mode)

Disable blinking matching paren

1;; disable annoying blink-matching-paren
2(setq blink-matching-paren nil)

Imenu list

Imenu setup

 1(require 'imenu-list)
 2(setq-default imenu-max-item-length 1000)
 3(bind-key "M-'" #'imenu-list-smart-toggle)
 4(setq-default imenu-auto-rescan t)
 5(setq imenu-list-size 0.15)
 6(set-default 'imenu-auto-rescan t)
 7
 8;; Focus window on imenu immediately after activation
 9(setq imenu-list-focus-after-activation t)
10;; Depth of org headings in the imenu buffer
11(setq org-imenu-depth 3)

Highlight

Highlighting of the current line (native mode)

1(require 'hl-line)
2(global-hl-line-mode)

PDF Tools

For retina display (OSX)

1;; (require 'pdf-tools)
2
3(add-hook 'doc-view-mode-hook 'pdf-tools-install)
4
5;; Using line numbers breaks the pdf-viewer
6(add-hook 'pdf-view-mode-hook (lambda () (nlinum-mode -1)))
7
8(setq-default pdf-view-use-scaling t
9              pdf-view-use-imagemagick nil)

Benchmark

1(rougier/report-time "Editing")

Minibuffer & Modeline

1(setq rougier/section-start-time (current-time))

General

Display time in modeline

1(display-time-mode 1)                   ; display time in minibar

Consult

We replace some of emacs functions with their consult equivalent

1(require 'consult)
2(setq consult-preview-key nil) ; No live preview
3
4(bind-key "C-x C-r" #'consult-recent-file)
5(bind-key "C-x h"   #'consult-outline)
6(bind-key "C-x b"   #'consult-buffer)
7(bind-key "C-c h"   #'consult-history)
8;; (bind-key "M-:"     #'consult-complex-command)

For the consult-goto-line and consult-line commands, we define our owns with live preview (independently of the consult-preview-key)

1(defun rougier/consult-line ()
2  "Consult line with live preview"
3
4  (interactive)
5  (let ((consult-preview-key 'any)
6        (mini-frame-resize 'grow-only)) ;; !! Important
7    (consult-line)))
8
9(bind-key "C-s" #'rougier/consult-line)

1(defun rougier/consult-goto-line ()
2  "Consult goto line with live preview"
3
4  (interactive)
5  (let ((consult-preview-key 'any))
6    (consult-goto-line)))
7
8(bind-key "M-g g"   #'rougier/consult-goto-line)
9(bind-key "M-g M-g" #'rougier/consult-goto-line)

Extra packages for consult projects

1(require 'consult-project-extra)

Enable binding with projectile (project-management)

1(require 'consult-projectile)
2(consult projectile)

Vertico

Vertico provides a performant and minimalistic vertical completion UI based on the default completion system but aims to be highly flexible, extensible and modular.

1(require 'vertico)
2;; (setq completion-styles '(basic substring partial-completion flex))
3(setq vertico-resize nil        ; How to resize the Vertico minibuffer window.
4      vertico-count 8           ; Maximal number of candidates to show.
5      vertico-count-format nil) ; No prefix with number of entries
6
7(vertico-mode)

Tweaking settings

 1(setq vertico-grid-separator
 2      #("  |  " 2 3 (display (space :width (1))
 3                             face (:background "#ECEFF1")))
 4
 5      vertico-group-format
 6      (concat #(" " 0 1 (face vertico-group-title))
 7              #(" " 0 1 (face vertico-group-separator))
 8              #(" %s " 0 4 (face vertico-group-title))
 9              #(" " 0 1 (face vertico-group-separator
10                          display (space :align-to (- right (-1 . right-margin) (- +1)))))))
11
12(set-face-attribute 'vertico-group-separator nil
13                    :strike-through t)
14(set-face-attribute 'vertico-current nil
15                    :inherit '(default shadow))
16(set-face-attribute 'completions-first-difference nil
17                    :inherit '(default))

Bind shift-tab for completion

1(bind-key "<backtab>" #'minibuffer-complete vertico-map)

Completion-at-point and completion-in-region (see https://github.com/minad/vertico#completion-at-point-and-completion-in-region)

1(setq completion-in-region-function
2      (lambda (&rest args)
3        (apply (if vertico-mode
4                   #'consult-completion-in-region
5                 #'completion--in-region)
6               args)))

Prefix the current candidate (See https://github.com/minad/vertico/wiki#prefix-current-candidate-with-arrow)

1(defun minibuffer-format-candidate (orig cand prefix suffix index _start)
2  (let ((prefix (if (= vertico--index index)
3                    "  "
4                  "   ")))
5    (funcall orig cand prefix suffix index _start)))
6
7(advice-add #'vertico--format-candidate
8           :around #'minibuffer-format-candidate)

See https://kristofferbalintona.me/posts/vertico-marginalia-all-the-icons-completion-and-orderless/#vertico

1(defun vertico--prompt-selection ()
2  "Highlight the prompt"
3
4  (let ((inhibit-modification-hooks t))
5    (set-text-properties (minibuffer-prompt-end) (point-max)
6                         '(face (bold highlight)))))

See https://github.com/minad/vertico/issues/145

 1(defun minibuffer-vertico-setup ()
 2
 3  (setq truncate-lines t)
 4  (setq completion-in-region-function
 5        (if vertico-mode
 6            #'consult-completion-in-region
 7          #'completion--in-region)))
 8
 9(add-hook 'vertico-mode-hook #'minibuffer-vertico-setup)
10(add-hook 'minibuffer-setup-hook #'minibuffer-vertico-setup)

Recommended settings to work with vertico for tramp-ssh remote files

1(setq completion-styles '(orderless basic)
2      completion-category-overrides '((file (styles basic partial-completion))))

Marginalia

Pretty straightforward.

1(require 'marginalia)
2
3(setq-default marginalia-ellipsis "…"     ; Nicer ellipsis
4              marginalia-align 'right     ; right alignment
5              marginalia-align-offset -1) ; one space on the right
6
7(marginalia-mode)

Minibuffer

Miniframe

 1(require 'mini-frame)
 2
 3(defcustom rougier/minibuffer-position 'bottom
 4  "Minibuffer position, one of 'top or 'bottom"
 5  :type '(choice (const :tag "Top"    top)
 6                 (const :tag "Bottom" bottom))
 7  :group 'nano-minibuffer)
 8
 9
10(defun rougier/minibuffer--frame-parameters ()
11  "Compute minibuffer frame size and position."
12
13  ;; Quite precise computation to align the minibuffer and the
14  ;; modeline when they are both at top position
15  (let* ((edges (window-pixel-edges)) ;; (left top right bottom)
16         (body-edges (window-body-pixel-edges)) ;; (left top right bottom)
17         (left (nth 0 edges)) ;; Take margins into account
18         (top (nth 1 edges)) ;; Drop header line
19         (right (nth 2 edges)) ;; Take margins into account
20         (bottom (nth 3 body-edges)) ;; Drop header line
21         (left (if (eq left-fringe-width 0)
22                   left
23                 (- left (frame-parameter nil 'left-fringe))))
24         (right (nth 2 edges))
25         (right (if (eq right-fringe-width 0)
26                    right
27                  (+ right (frame-parameter nil 'right-fringe))))
28         (border 1)
29         (width (- right left (* 1 border)))
30
31         ;; Window divider mode
32         (width (- width (if (and (bound-and-true-p window-divider-mode)
33                                  (or (eq window-divider-default-places 'right-only)
34                                      (eq window-divider-default-places t))
35                                  (window-in-direction 'right (selected-window)))
36                             window-divider-default-right-width
37                           0)))
38         (y (- top border)))
39
40    (append `((left-fringe . 0)
41              (right-fringe . 0)
42              (user-position . t)
43              (foreground-color . ,(face-foreground 'highlight nil 'default))
44              (background-color . ,(face-background 'highlight nil 'default)))
45            (cond ((and (eq rougier/minibuffer-position 'bottom))
46                   `((top . -1)
47                     (left . 0)
48                     (width . 1.0)
49                     (child-frame-border-width . 0)
50                     (internal-border-width . 0)))
51                  (t
52                   `((left . ,(- left border))
53                     (top . ,y)
54
55                     (width . (text-pixels . ,width))
56                     (child-frame-border-width . ,border)
57                     (internal-border-width . 0)))))))
58
59  (set-face-background 'child-frame-border (face-foreground 'shadow))
60  (setq mini-frame-default-height 3)
61  (setq mini-frame-create-lazy t)
62  (setq mini-frame-show-parameters 'rougier/minibuffer--frame-parameters)
63  (setq mini-frame-ignore-commands
64        '("edebug-eval-expression" debugger-eval-expression))
65  (setq mini-frame-internal-border-color (face-foreground 'shadow))
66
67  (setq mini-frame-resize-min-height 3)
68  (setq mini-frame-resize t)
69  ;; (setq mini-frame-resize 'grow-only)
70  ;; (setq mini-frame-default-height (+ 1 vertico-count))
71  ;; (setq mini-frame-resize-height (+ 1 vertico-count))
72  ;; (setq mini-frame-resize nil)

Mini-frame mode OFF

1;; (mini-frame-mode 1)

More a hack than a fix but the code below improve the mini-frame resize by setting position explicity. CURRENTLY INACTIVE

 1(defun rougier/mini-frame--resize-mini-frame (frame)
 2  "Resize FRAME vertically only.
 3This function used as value for `resize-mini-frames' variable."
 4  (funcall mini-frame--fit-frame-function
 5           frame
 6           mini-frame-resize-max-height
 7           (if (eq mini-frame-resize 'grow-only)
 8               (max (frame-parameter frame 'height)
 9                    mini-frame-resize-min-height)
10             mini-frame-resize-min-height)
11           ;; A max-width must be included to work around a bug in Emacs which
12           ;; causes wrapping to not be taken into account in some situations
13           ;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=56102
14           (window-body-width)
15           nil
16           'vertically)
17
18  (if (eq rougier/minibuffer-position 'top)
19      (modify-frame-parameters  mini-frame-completions-frame `((top . 0)))
20    (modify-frame-parameters  mini-frame-completions-frame `((top . (- 1))))))

Modeline

Get modeline from spaceline

1(require 'spaceline)
2(require 'spaceline-config)
3
4(spaceline-spacemacs-theme)
5
6(spaceline-toggle-minor-modes-off)
7
8(setq powerline-default-separator 'arrow-fade)

Benchmark

1(rougier/report-time "Modeline")

Programming

1(setq rougier/section-start-time (current-time))

General

Use yasnippets for generating useful snippets very useful in tandem with yasnippet-snippets package

1(require 'yasnippet)
2(yas-global-mode 1)                     ; Enable yasnippets globally
3(setq yas-indent-line 'auto)            ; the other option is the value: 'fixed
1(add-to-list 'auto-mode-alist '("[Mm]akefile\\'" . makefile-gmake-mode))

Workflow

Snakemake

1(require 'snakemake-mode)
2;; Enable snake mode
3(add-to-list 'auto-mode-alist '("\\.smk\\'" . snakemake-mode))
4(add-to-list 'auto-mode-alist '("[Ss]nakefile\\'" . snakemake-mode))

C/C++

Linux C standards

 1(defun linux-c-mode ()
 2"C mode with adjusted defaults for use with the Linux
 3kernel."
 4(interactive)
 5(c-mode)
 6(setq c-indent-level 8)
 7(setq c-brace-imaginary-offset 0)
 8(setq c-brace-offset -8)
 9(setq c-argdecl-indent 8)
10(setq c-label-offset -8)
11(setq c-continued-statement-offset 8)
12(setq indent-tabs-mode nil)
13(setq tab-width 8))
14This will define the M-x linux-c-mode command. When hacking on a module, if
15you put the string -*- linux-c -*- somewhere on the first two lines, this mode
16will be automatically invoked. Also, you may want to add
17(setq auto-mode-alist (cons '("/usr/src/linux.*/.*\\.[ch]
18$" . linux-c-mode)
19auto-mode-alist))

Lisp

Python

Configuration that helps writing python code a better experience.

List of requirements are:

  • Code completion
  • Documentation
  • Jump to definition
  • Send region/buffer to REPL (interpreted languages)
  • Identification of code issues
  • Auto format/organize/clean code
  • https://github.com/dadadel/pyment

Set python environment path

1(setenv "PYTHONPATH" (shell-command-to-string "$SHELL --login -c 'echo -n $PYTHONPATH'"))

Setup elpy, in order to use all the features (such as navigation with M-.), you’ll need to install some python libraries:

1pip install flake8 snakeviz
2# For linux
3sudo apt install python3-jedi black python3-autopep8 yapf3 python3-yapf
4# For mac
5brew install python3-jedi black python3-autopep8 yapf3 python3-yapf

Use snakeviz to profile code with `elpy-profile-buffer-or-region`

 1(require 'elpy)
 2(with-eval-after-load 'elpy
 3  (delete 'elpy-module-yasnippet elpy-modules))
 4
 5(elpy-enable)
 6
 7(setq elpy-rpc-python-command "python")
 8(setq elpy-remove-modeline-lighter nil)
 9(setq elpy-rpc-backend "jedi")          ; auto-completed backend
10(setq python-check-command "flake8")    ; Syntax checker
11
12(setq python-shell-interpreter "ipython"
13      python-shell-interpreter-args "-i --simple-prompt"
14      python-shell-prompt-detect-failure-warning nil)
15(add-to-list 'python-shell-completion-native-disabled-interpreters
16             "ipython")
17
18;; remove highlight-indentation
19(setq elpy-modules (delq 'elpy-module-highlight-indentation elpy-modules))

Setup flycheck with elpy

1(require 'flycheck)
2
3(when (require 'flycheck nil t)
4  (setq elpy-modules (delq 'elpy-module-flymake elpy-modules))
5  (add-hook 'elpy-mode-hook 'flycheck-mode))

Enforce column limits

1;; COLUMN ENFORCEMENT
2(require 'fill-column-indicator)
3(add-hook 'python-mode-hook 'fci-mode)
4(require 'column-enforce-mode)
5(add-hook 'python-mode-hook 'column-enforce-mode)
6(setq column-enforce-column 88)

Setup python virtual environments

1(require 'pyenv-mode)
2(pyenv-mode)
3
4;; remove default keybindings
5(unbind-key "C-c C-s" pyenv-mode-map)
6(unbind-key "C-c C-u" pyenv-mode-map)
7
8(setenv "WORKON_HOME" (concat (expand-file-name "~/.virtualenvs/versions/") (shell-command-to-string "echo $(pyenv version-name) | tr -d '\n'")))
9(setenv "VIRTUALENVWRAPPER_HOOK_DIR" (concat (expand-file-name "~/.virtualenvs/versions/") (shell-command-to-string "echo $(pyenv version-name) | tr -d '\n'")))

Setup pyvenv

1;; (setq pyvenv-exec-shell "/bin/zsh")
2;; (setq pyvenv-virtualenvwrapper-python (shell-command-to-string "echo $(pyenv which python)"))

Setup sphinx-doc for sphinx compatible docstrings and documenting

1(add-hook 'python-mode-hook (lambda ()
2                              (require 'sphinx-doc)
3                              (sphinx-doc-mode t)))
4(setq sphinx-doc-include-types t)

Add python code folding hook with hideshow minor mode

1(add-hook 'python-mode-hook 'hs-minor-mode)

Use isortify to sort python imports according to pep8 standards.

1(require 'isortify)

Cython

Setup for cython mode

1
2(require 'cython-mode)
3
4(autoload 'cython-mode "cython-mode" "Mode for editing Cython source files")
5
6(add-to-list 'auto-mode-alist '("\\.pyx\\'" . cython-mode))
7(add-to-list 'auto-mode-alist '("\\.pxd\\'" . cython-mode))
8(add-to-list 'auto-mode-alist '("\\.pxi\\'" . cython-mode))

Setup flycheck for cython mode

1
2(require 'flycheck)
3
4(add-hook 'cython-mode-hook 'flycheck-mode)

xml

Configure nxml mode

1;; (add-hook 'nxml-mode-hook (lambda () (line-number-mode 0)))
2;; (add-hook 'nxml-mode-hook (lambda () (linum-mode 0)))
3(add-hook 'nxml-mode-hook (lambda () (undo-tree-mode -1)))

yaml

1(require 'yaml-mode)
2
3; If you wish to have Return key automatically indent cursor on new line
4(add-hook 'yaml-mode-hook
5          (lambda ()
6            (define-key yaml-mode-map "\C-m" 'newline-and-indent))
7          )

Latex

 1(require 'smartparens-latex)
 2
 3(defun apm-latex-mode-setup ()
 4  "Tweaks and customisations for LaTeX mode."
 5  (turn-on-auto-fill)
 6  (abbrev-mode +1)
 7  ;; smartparens latex support
 8  (smartparens-mode +1)
 9  ;; Enable source-correlate for Control-click forward/reverse search.
10  (TeX-source-correlate-mode 1)
11  ;; enable math mode in latex
12  (LaTeX-math-mode 1)
13  ;; Enable reftex
14  (turn-on-reftex)
15  ;; integrate with company
16  (company-auctex-init)
17  )
18
19(require 'tex-site)
20
21(require 'company-auctex)
22(company-auctex-init)
23
24(setq-default TeX-auto-save t
25              TeX-parse-self t
26              TeX-PDF-mode t
27              reftex-plug-into-AUCTeX t
28              TeX-source-correlate-start-server t
29              TeX-master nil
30              )
31
32(add-hook 'LaTeX-mode-hook #'apm-latex-mode-setup)
33
34(add-hook 'LaTeX-mode-hook
35          (lambda ()
36            (font-latex-add-keywords '(("citep" "*[[{")) 'reference)
37            (font-latex-add-keywords '(("citet" "*[[{")) 'reference)
38            (font-latex-add-keywords '(("autoref" "*[[{")) 'reference))
39          )
40
41(setq TeX-command-extra-options "-shell-escape")

Add support for formatting latex text to one sentence per line with ospl mode. This helps tracking changes easier and better.

1(add-hook 'LaTeX-mode-hook 'ospl-mode)
1(add-hook 'LaTeX-mode-hook 'olivetti-mode)

nim

1;; (require 'nim-mode)

Jinja

 1(message "Personal config :. jinja...")
 2;; Jinja
 3(use-package mmm-jinja2
 4  :straight t)
 5(use-package jinja2-mode
 6  :straight t)
 7(load "~/.emacs.d/elpa/mmm-jinja2-20170313.1420/mmm-jinja2.el")
 8(add-to-list 'auto-mode-alist '("\\.jinja2\\.wbt'" . html-mode))
 9(mmm-add-mode-ext-class 'html-mode "\\.jinja2\\.wbt'" 'jinja2)
10
11
12(add-to-list 'auto-mode-alist '("\\.jinja2\\'" . yaml-mode))
13(mmm-add-mode-ext-class 'yaml-mode "\\.jinja2\\'" 'jinja2)

Godot

Formatting code with gdformat requires installing gdtoolkit

1pip install gdtoolkit
1(setq gdscript-godot-executable "/path/to/godot")

GL

GLSL

1(require 'glsl-mode)
2(add-to-list 'auto-mode-alist '("\\.glsl\\'" . glsl-mode))

Benchmark

1
2(rougier/report-time "Programming")

Completion

1
2(setq rougier/section-start-time (current-time))

Company

Company is a text completion framework for Emacs. The name stands for “complete anything”. It uses pluggable back-ends and front-ends to retrieve and display completion candidates.

http://company-mode.github.io/

 1;; (add-hook 'after-init-hook 'global-company-mode)
 2
 3(bind-key "C-c i" #'company-complete)
 4
 5(add-hook 'emacs-lisp-mode-hook
 6          (lambda ()
 7            (paredit-mode t)
 8            (rainbow-delimiters-mode t)
 9            (show-paren-mode 1)
10            ))
11
12(add-hook 'lisp-interaction-mode
13          (lambda ()
14            (paredit-mode t)
15            (rainbow-delimiters-mode t)
16            (show-paren-mode 1)
17            ))

Corfu

Corfu enhances completion at point with a small completion popup.

 1
 2(require 'corfu)
 3
 4(setq corfu-cycle t                ; Enable cycling for `corfu-next/previous'
 5      corfu-auto t                 ; Enable auto completion
 6      corfu-auto-delay 60.0        ; Delay before auto-completion shows up
 7      corfu-separator ?\s          ; Orderless field separator
 8      corfu-quit-at-boundary nil   ; Never quit at completion boundary
 9      corfu-quit-no-match t        ; Quit when no match
10      corfu-preview-current nil    ; Disable current candidate preview
11      corfu-preselect-first nil    ; Disable candidate preselection
12      corfu-on-exact-match nil     ; Configure handling of exact matches
13      corfu-echo-documentation nil ; Disable documentation in the echo area
14      corfu-scroll-margin 5)       ; Use scroll margin
15
16(global-corfu-mode)

A few more useful configurations…

 1
 2;; TAB cycle if there are only few candidates
 3(setq completion-cycle-threshold 3)
 4
 5;; Emacs 28: Hide commands in M-x which do not apply to the current mode.
 6;; Corfu commands are hidden, since they are not supposed to be used via M-x.
 7(setq read-extended-command-predicate
 8      #'command-completion-default-include-p)
 9
10;; Enable indentation+completion using the TAB key.
11;; completion-at-point is often bound to M-TAB.
12(setq tab-always-indent 'complete)
13
14;; Completion in source blocks
15(require 'cape)
16
17(add-to-list 'completion-at-point-functions 'cape-symbol)

Orderless

Allow completion based on space-separated tokens, out of order.

1
2(require 'orderless)
3
4(setq completion-styles '(substring orderless basic)
5      orderless-component-separator 'orderless-escapable-split-on-space
6      read-file-name-completion-ignore-case t
7      read-buffer-completion-ignore-case t
8      completion-ignore-case t)

Benchmark

1
2(rougier/report-time "Completion")

Writing

1(setq rougier/section-start-time (current-time))

English

Tools and setup for making writing articles enjoyable and easy

Whisper

 1;; Speech to text
 2(require 'whisper)
 3
 4(bind-key "C-c r" #'whisper-run)
 5(bind-key "C-c f" #'whisper-file)
 6
 7(setq whisper-install-directory "~/softwares/install/speech2text/" ;; "/tmp/"
 8      whisper-model "base" ;; "medium" was tested but is too slow
 9      whisper-language "en"
10      whisper-translate nil)

Langtool

 1(require 'langtool)
 2
 3(bind-key "\C-x4w" #'langtool-check)
 4(bind-key "\C-x4W" #'langtool-check-done)
 5(bind-key "\C-x4l" #'langtool-switch-default-language)
 6(bind-key "\C-x44" #'langtool-show-message-at-point)
 7(bind-key "\C-x4c" #'langtool-correct-buffer)
 8
 9(setq langtool-java-classpath "/opt/homebrew/Cellar/languagetool:/opt/homebrew/Cellar/languagetool/6.5/*")
10(setq langtool-language-tool-jar "/opt/homebrew/Cellar/languagetool/6.5/libexec/languagetool-commandline.jar")
11(setq langtool-language-tool-server-jar "/opt/homebrew/Cellar/languagetool/6.5/libexec/languagetool-server.jar")
12(setq langtool-server-user-arguments '("-p" "8081" "--config" "~/.config/server.properties"))
13(setq langtool-http-server-host "localhost")
14(setq langtool-http-server-port 8081)
15
16;; Text suggestions
17(require 'flycheck-languagetool)
18
19(setq flycheck-languagetool-server-jar "/opt/homebrew/Cellar/languagetool/6.5/libexec/languagetool-server.jar")
20(setq flycheck-languagetool-server-port "8081")
21(setq flycheck-languagetool-language "en-GB")
22
23;; (add-hook 'text-mode-hook #'flycheck-languagetool-setup)
24;; (add-hook 'LaTeX-mode-hook #'flycheck-languagetool-setup)
25;; (add-hook 'org-mode-hook #'flycheck-languagetool-setup)
26;; (add-hook 'org-mode-hook 'waveparticle/langtool-autosave-hook)
27;; (add-hook 'text-mode-hook 'waveparticle/langtool-autosave-hook)
28;; (add-hook 'LaTeX-mode-hook 'waveparticle/langtool-autosave-hook)

Proselint : Requires system installation first

`pip install proselint`

 1(require 'flycheck)
 2
 3(flycheck-define-checker proselint
 4  "A linter for prose."
 5  :command ("proselint" source-inplace)
 6  :error-patterns
 7  ((warning line-start (file-name) ":" line ":" column ": "
 8            (id (one-or-more (not (any " ")))) (message) line-end))
 9  :modes (gfm-mode
10          markdown-mode
11          org-mode
12          text-mode
13          latex-mode))
14  ;; :next-checkers ((warning . valec)))

Vale: Requires system installation first

`brew install vale`

 1(flycheck-define-checker valec
 2  "A checker for prose"
 3  :command ("vale" "--output" "line" source)
 4  :standard-input nil
 5  :error-patterns
 6  ((error line-start (file-name) ":" line ":" column ":"
 7          (id (one-or-more (not (any ":")))) ":" (message) line-end))
 8  :modes (markdown-mode
 9          org-mode
10          text-mode
11          latex-mode))
12(add-to-list 'flycheck-checkers 'valec 'append)

Writegood-mode

1(require 'writegood-mode)
2
3(bind-key "C-c g" #'writegood-mode)
4(bind-key "C-c C-g C-g" #'writegood-grade-level)
5(bind-key "C-c C-g C-e" #'writegood-reading-ease)
6
7(add-hook 'org-mode-hook #'writegood-mode)

Smog: Requires system installation first

`brew install style`

1(require 'smog)
2
3(setq smog-command "style -L en")

Powerthesaurus

Markdown

1(add-hook 'markdown-mode-hook #'ospl-mode)

Benchmark

1(rougier/report-time "Writing")

AI

GPTel

1;; Use Ollama models instead of ChatGPT
2;; OPTIONAL configuration
3(setq
4 gptel-model '"deepseek-coder:6.7b"
5 gptel-backend (gptel-make-ollama "Ollama"
6                 :host "localhost:11434"
7                 :stream t
8                 :models '("deepseek-coder:6.7b")))

RESOURCES

https://github.com/captainflasmr/ollama-buddy

A friendly Emacs interface for interacting with Ollama models. This package provides a convenient way to integrate Ollama’s local LLM capabilities directly into your Emacs workflow with little or no configuration required.

Org

1(setq rougier/section-start-time (current-time))

General

 1(setq-default
 2 org-directory "~/projects/personal/org/core" ; Default org files
 3 org-ellipsis "  ·"                           ; Nicer ellipsis
 4 org-hide-emphasis-markers t                  ; Hide markers
 5 org-hide-leading-stars t                     ; Hide leading stars
 6 org-adapt-indentation nil
 7 org-cycle-separator-lines 0                  ; Number of empty lines between sections
 8 org-use-tag-inheritance nil                  ; Tags ARE NOT inherited
 9 org-use-property-inheritance t               ; Properties ARE inherited
10 org-indent-indentation-per-level 2           ; Indentation per level
11 org-indent-mode nil                          ; Org identation for better readability
12 org-startup-indented t                       ; Startup indent
13 org-startup-folded 'show2levels              ; Startup in folded view.
14 org-link-use-indirect-buffer-for-internals t ; Indirect buffer for internal links
15 org-fontify-quote-and-verse-blocks t         ; Specific face for quote and verse blocks
16 org-src-fontify-natively t                   ; fontify src blocks
17 org-src-tab-acts-natively t
18 org-src-preserve-indentation nil             ; Preserve indentation for exporting
19 org-fontify-whole-block-delimiter-line t     ; Fontify whole block
20 org-edit-src-content-indentation 0
21 org-return-follows-link nil                  ; Follow links when hitting return
22 org-image-actual-width nil                   ; Resize image to window width
23 org-indirect-buffer-display 'other-window    ; Tab on a task expand it in a new window
24 org-outline-path-complete-in-steps nil       ; No steps in path display
25 org-list-allow-alphabetical t                ; Allow alphabets in org list
26 org-fold-catch-invisible-edits nil           ; Avoid editing invisible fields in org-mode
27 org-list-demote-modify-bullet '(("+" . "-") ("-" . "+") ("*" . "+") ("1." . "a."))            ; Set the order of list symbols
28 org-tags-column -80                          ; Set the tags alignment (88 following black!)
29 org-auto-align-tags t
30 org-catch-invisible-edits 'show-and-error    ; Disable invisible edits
31 org-pretty-entities t                        ; insert special characters LaTeX-style
32 org-confirm-babel-evaluate nil               ; No confirmation before executing code
33 org-blank-before-new-entry '((heading) (plain-list-item . auto))
34 org-archive-location ".%s_archive::"         ; Org archive files are hidden
35 )

Better latex preview (see https://stackoverflow.com/questions/30151338)

1(setq org-latex-create-formula-image-program 'dvisvgm)

We adapt fill functions according to the indent level.

 1(defun rougier/calc-offset-on-org-level ()
 2  "Calculate offset (in chars) on current level in org mode file."
 3
 4  (* (or (org-current-level) 0) org-indent-indentation-per-level))
 5
 6(defun rougier/org-fill-paragraph (&optional justify region)
 7  "Calculate apt fill-column value and fill paragraph."
 8
 9  (let* ((fill-column (- fill-column (rougier/calc-offset-on-org-level))))
10    (org-fill-paragraph justify region)))
11
12(defun rougier/org-auto-fill-function ()
13  "Calculate apt fill-column value and do auto-fill"
14
15  (let* ((fill-column (- fill-column (rougier/calc-offset-on-org-level))))
16    (org-auto-fill-function)))
17
18(defun rougier/org-mode-hook ()
19  (setq fill-paragraph-function #'rougier/org-fill-paragraph
20        normal-auto-fill-function #'rougier/org-auto-fill-function))
21
22(add-hook 'org-load-hook 'rougier/org-mode-hook)
23(add-hook 'org-mode-hook 'rougier/org-mode-hook)

Org bullets to replace stars * with better symbols

1(require 'org-bullets)
2(add-hook 'org-mode-hook (lambda () (org-bullets-mode 1)))
1;; Hide org markup for README
2(setq org-hide-emphasis-markers t)

Add better looking icons for org tasks

 1(defun org-icons ()
 2  "Beautify org mode keywords."
 3  (setq prettify-symbols-alist '(("TODO" . "")
 4                                 ("WAIT" . "")
 5                                 ("NOPE" . "")
 6                                 ("DONE" . "")
 7                                 ("CONTACT" . "")
 8                                 ("[#A]" . "")
 9                                 ("[#B]" . "")
10                                 ("[#C]" . "")
11                                 ("[ ]" . "")
12                                 ("[X]" . "")
13                                 ("[-]" . "")
14                                 ("#+BEGIN_SRC" . "")
15                                 ("#+END_SRC" . "―")
16                                 ("#+begin_src" . "")
17                                 ("#+end_src" . "―")
18                                 (":PROPERTIES:" . "")
19                                 (":END:" . "―")
20                                 ("#+STARTUP:" . "")
21                                 ("#+TITLE: " . "")
22                                 ("#+RESULTS:" . "")
23                                 ("#+NAME:" . "")
24                                 ("#+ROAM_TAGS:" . "")
25                                 ("#+FILETAGS:" . "")
26                                 ("#+HTML_HEAD:" . "")
27                                 ("#+SUBTITLE:" . "")
28                                 ("#+AUTHOR:" . "")
29                                 (":Effort:" . "")
30                                 ("SCHEDULED:" . "")
31                                 ("DEADLINE:" . "")
32                                 ))
33  (prettify-symbols-mode))
34
35(add-hook 'org-mode-hook 'org-icons)

org modern look

1(with-eval-after-load 'org (global-org-modern-mode))

Fix for missing unicode symbol in org-modern

1(setq org-modern-fold-stars
2  '(("▶" . "▼")
3    ("▷" . "▽")
4    ("⏵" . "⏷")
5    ("▹" . "▿")
6    ("▸" . "▾")))
1(setq org-modern-table nil)
2(setq org-modern-table-vertical nil)
3(setq org-modern-table-horizontal nil)
1(add-hook 'org-mode-hook 'org-appear-mode)
1(add-hook 'org-mode-hook 'olivetti-mode)
1(add-hook 'org-mode-hook 'ospl-mode)

Key bindings

Org mode specific keybindings

1(bind-key "C-c !" #'org-time-stamp-inactive)

Encryption

 1;; Enable org-crypt
 2(require 'org-crypt)
 3(org-crypt-use-before-save-magic)
 4
 5;; Set default GPG key to use for encryption
 6;; Replace with your key ID from gpg --list-secret-keys
 7(setq org-crypt-key "shravantr@gmail.com")
 8
 9;; Disable backup files for encrypted .org files
10(setq backup-directory-alist
11      `((".*" . ,temporary-file-directory)))
12(setq auto-save-file-name-transforms
13      `((".*" ,temporary-file-directory t)))
14
15;; Don't write sensitive data to disk in clear text
16(setq auth-sources
17    '((:source "~/.emacs.d/secrets/.authinfo.gpg")))
18
19;; Encrypt all entries with the "crypt" tag
20(setq org-tags-exclude-from-inheritance (quote ("crypt")))
21
22;; Use minibuffer for GPG password prompt
23(setq epg-pinentry-mode 'loopback)
24
25;; Allow GPG to prompt for passphrase in Emacs
26(setenv "GPG_AGENT_INFO" nil)
27
28;; Force GPG to use minibuffer for password
29(setq epg-gpg-program "gpg")  ; or "gpg" depending on your system
30
31;; GPG key selection options
32(setq epa-file-encrypt-to nil)
33(setq epa-file-select-keys nil)
34
35;; Auto-save settings for encrypted files
36(setq org-crypt-disable-auto-save t)
37
38;; Function to encrypt all marked regions in a file
39(defun org-encrypt-all-entries ()
40  "Encrypt all top-level entries in the current file."
41  (interactive)
42  (org-map-entries
43   (lambda ()
44     (org-encrypt-entry)
45     (message "Encrypted entry %s" (org-get-heading t t t t)))
46   "crypt" 'file))
47
48;; Function to decrypt all entries temporarily
49(defun org-decrypt-all-entries ()
50  "Decrypt all entries in the current file."
51  (interactive)
52  (org-map-entries
53   (lambda ()
54     (org-decrypt-entry)
55     (message "Decrypted entry %s" (org-get-heading t t t t)))
56   "crypt" 'file))

echo GETPIN | pinentry-mac

Fixes

Have to downgrade to version 2.4.0 or below. Currently the easiest to do on MacOS is brew install gnupg@2.2.0

For documentation,

Resources

  • Useful commands

    • gpg-connect-agent reloadagent /bye

Templates

 1;; This is needed as of Org 9.2
 2(require 'org-tempo)
 3
 4(add-to-list 'org-structure-template-alist '("sh" . "src sh"))
 5(add-to-list 'org-structure-template-alist '("el" . "src emacs-lisp"))
 6(add-to-list 'org-structure-template-alist '("py" . "src python"))
 7(add-to-list 'org-structure-template-alist '("tex" . "src latex"))
 8(add-to-list 'org-structure-template-alist '("go" . "src go"))
 9(add-to-list 'org-structure-template-alist '("yaml" . "src yaml"))
10(add-to-list 'org-structure-template-alist '("json" . "src json"))

Babel

 1;; Set languages org-babel supports
 2(org-babel-do-load-languages
 3 'org-babel-load-languages
 4 (quote
 5  ((awk .t)
 6   (ditaa .t)
 7   (shell .t)
 8   (python .t)
 9   (latex .t)
10   (emacs-lisp .t)))
11 )

Citations

Org 9.5 and above has native support for citations with `org-cite` package.

Links for reference:

1
2(require 'bibtex)
3
4(setq org-cite-export-processors
5      '((md . (csl "chicago-fullnote-bibliography.csl"))   ; Footnote reliant
6        (latex . biblatex)                                 ; For humanities
7        (odt . (csl "chicago-fullnote-bibliography.csl"))  ; Footnote reliant
8        (t . (csl "modern-language-association.csl"))      ; Fallback
9        ))
1(require 'org-ref)

Notes

Writing and reading notes with org

Exports

Setup default list of exporters

1
2(setq org-export-backends '(ascii beamer html icalendar latex md odt))

Setup latex exports

1;; Setup to run with minted packages to embed code in latex exports
2(setq org-latex-pdf-process
3      '("pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
4        "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"
5        "pdflatex -shell-escape -interaction nonstopmode -output-directory %o %f"))

Export code with syntax highlighting using minted. Has a system dependency!

1(setq org-latex-listings 'minted)
2(setq org-latex-minted-options
3      '(("frame" "lines") ("linenos=true")))

Blog

1(require 'ox-hugo)

Getting Things Done (GTD)

Configure the refile file location to capture the notes

1(setq org-directory "~/projects/personal/org/core/")
2(setq org-agenda-files (list "refile.org"))

Setup a simple org capture template

1(setq org-capture-templates
2       `(("i" "Inbox" entry  (file "refile.org")
3        ,(concat "* TODO %?\n" "/Entered on/ %U"))))

and setup a keyboard shortcut (C-c c):

1(define-key global-map (kbd "C-c c") 'org-capture)

TASKS

1(setq org-todo-keywords
2      (quote ((sequence "TODO(t)" "WORKING(w)" "|" "DONE(d)" "DELEGATED(e@)")
3              (sequence "HOLD(h@/!)" "FUTURE(f@/!)" "|" "CANCELLED(c@/!)" "PHONE(p@)" "MEETING(m@)")
4              (sequence "BUY(b)" "|" "DROPPED(x@/!)" "BOUGHT(o)")
5              (sequence "CONTACT(k)" "|" "DROPPED(x@/!)" "CONTACTED(j@/!)")
6              )))
 1(setq org-todo-keyword-faces
 2      (quote (("TODO" :foreground "red" :weight bold)
 3              ("WORKING" :foreground "orange" :weight bold)
 4              ("DONE" :foreground "forest green" :weight bold)
 5              ("HOLD" :foreground "yellow" :weight bold)
 6              ("FUTURE" :foreground "magenta" :weight bold)
 7              ("CANCELLED" :foreground "forest green" :weight bold)
 8              ("MEETING" :foreground "forest green" :weight bold)
 9              ("PHONE" :foreground "forest green" :weight bold)
10              ("CONTACT" :foreground "blue" :weight bold)
11              )
12             )
13      )

RESOURCES

Benchmark

1(rougier/report-time "Org")

Agenda

General

Load libraries.

1(require 'org-agenda)
2(require 'org-agenda-property)

Open agenda(s)

1(bind-key "C-c a" #'org-agenda)

Files

 1(setq org-agenda-files
 2      '(
 3       "~/projects/personal/org/work/"
 4       "~/projects/personal/org/work/career/"
 5       "~/projects/personal/org/work/dev/"
 6       "~/projects/personal/org/work/research/"
 7       "~/projects/personal/org/personal/"
 8       "~/projects/personal/org/personal/daily/"
 9       "~/projects/personal/org/personal/lifestyle/"
10       "~/projects/personal/org/projects/"
11       "~/projects/personal/org/library/"
12       )
13      )

Settings

 1(setq org-agenda-window-setup 'current-window
 2      org-agenda-restore-windows-after-quit t
 3      org-agenda-show-all-dates nil
 4      org-agenda-time-in-grid t
 5      org-agenda-show-current-time-in-grid t
 6      org-agenda-start-on-weekday 1
 7      org-agenda-span 7
 8      org-agenda-hide-tags-regexp "." ; No tags
 9    ; org-agenda-hide-tags-regexp nil) ; All tags
10      org-agenda-tags-column 0
11    ; org-agenda-tags-column -79)      ; Left aling
12      org-agenda-block-separator nil
13      org-agenda-category-icon-alist nil
14      org-agenda-skip-deadline-if-done t
15      org-agenda-skip-scheduled-if-done t
16      org-agenda-sticky t)

Prefix format

1(setq org-agenda-prefix-format
2      '((agenda . "%i %?-12t%s")
3        (todo .   "%i")
4        (tags .   "%i")
5        (search . "%i")))

Sorting strategy

1(setq org-agenda-sorting-strategy
2      '((agenda deadline-down scheduled-down todo-state-up time-up
3                habit-down priority-down category-keep)
4        (todo   priority-down category-keep)
5        (tags   timestamp-up priority-down category-keep)
6        (search category-keep)))

Minimal time grid

1(setq org-agenda-time-grid
2      '((daily today require-timed)
3        ()
4        "......" "----------------"))
5
6(setq org-agenda-current-time-string "   now")

Holidays

 1(require 'cal-iso)
 2(require 'holidays)
 3
 4(defvar us-holidays nil
 5  "US holidays")
 6
 7(defvar india-holidays nil
 8  "India holidays")
 9
10(defvar birthdays nil
11  "Birthdays")
12
13(setq us-holidays
14      `((holiday-fixed 1 1 "New year's Day")
15            (holiday-fixed 5 1 "Labour Day")
16            (holiday-fixed 5 8 "Victory in Europe Day")
17            (holiday-fixed 7 14 "Bastille day")
18            (holiday-fixed 8 15 "Assumption of Mary")
19            (holiday-fixed 11 11 "Armistice 1918")
20            (holiday-fixed 11 1 "All Saints' Day")
21            (holiday-fixed 12 25 "Christmas Day")
22            (holiday-easter-etc 0 "Easter Sunday")
23        (holiday-easter-etc 1 "Easter Monday")
24        (holiday-easter-etc 39 "Ascension Day")
25        (holiday-easter-etc 50 "Whit Monday")
26        (holiday-sexp
27         '(if (equal
28               (holiday-easter-etc 49)
29               (holiday-float 5 0 -1 nil))
30              (car (car (holiday-float 6 0 1 nil)))
31            (car (car (holiday-float 5 0 -1 nil))))
32         "Mother's Day")))
33
34(setq calendar-holidays french-holidays     ; French holidays
35      calendar-week-start-day 1             ; Week starts on Monday
36      calendar-mark-diary-entries-flag nil) ; Do not show diary entries
37
38; Mark today in calendar
39(add-hook 'calendar-today-visible-hook  #'calendar-mark-today)

Week day name with holidays

 1(defun rougier/org-agenda-format-date (date)
 2  "Org agenda date format displaying holidays"
 3  (let* ((dayname (calendar-day-name date))
 4         (day (cadr date))
 5         (month (car date))
 6         (monthname (calendar-month-name month))
 7         (year (nth 2 date))
 8         (holidays (calendar-check-holidays date)))
 9    (concat "\n"
10            dayname " "
11            (format "%d " day)
12            monthname " "
13            (format "%d" year)
14            (if holidays (format " (%s)" (nth 0 holidays)))
15            "\n")))
16
17(setq org-agenda-format-date #'rougier/org-agenda-format-date)

Daily agenda

The daily agenda

1(add-to-list 'org-agenda-custom-commands
2             '("a" "Agenda"
3               ((agenda "Agenda"
4                        ((org-agenda-todo-keyword-format "%s")
5                         (org-agenda-skip-deadline-if-done nil)
6                         (org-deadline-warning-days 3)
7                         (org-agenda-overriding-header nil))))))

Some decorations for the agenda

 1(defun rougier/org-agenda-highlight-todo (x)
 2  (let* ((done (string-match-p (regexp-quote ":DONE:") x))
 3         (canceled (string-match-p (regexp-quote "~") x))
 4         (x (replace-regexp-in-string ":TODO:" "" x))
 5         (x (replace-regexp-in-string ":DONE:" "" x))
 6         (x (replace-regexp-in-string "~" "" x))
 7         (x (if (and (boundp 'org-agenda-dim) org-agenda-dim)
 8                (propertize x 'face 'nano-faded) x))
 9         (x (if done (propertize x 'face 'nano-faded) x))
10         (x (if canceled (propertize x 'face 'nano-faded) x)))
11    x))
12
13(advice-add 'org-agenda-highlight-todo
14            :filter-return #'rougier/org-agenda-highlight-todo)

Timestamp tags for the agenda (bold means inverse video below):

now -> now 9:00 -> 9h00 9:30-10:00 -> 9h30 | 30mn -> ANYTIME

 1(require 'svg-lib)
 2(require 'svg-tag-mode)
 3
 4(defun rougier/svg-tag-timestamp (&rest args)
 5  "Create a timestamp SVG tag for the time at point."
 6
 7  (interactive)
 8  (let ((inhibit-read-only t))
 9
10    (goto-char (point-min))
11    (while (search-forward-regexp
12            "\\(\([0-9]/[0-9]\):\\)" nil t)
13              (set-text-properties (match-beginning 1) (match-end 1)
14                             `(display ,(svg-tag-make "ANYTIME"
15                                                      :face 'nano-faded
16                                                      :inverse nil
17                                                      :padding 3 :alignment 0))))
18
19    (goto-char (point-min))
20    (while (search-forward-regexp
21            "\\([0-9]+:[0-9]+\\)\\(\\.+\\)" nil t)
22
23              (set-text-properties (match-beginning 1) (match-end 2)
24                             `(display ,(svg-tag-make (match-string 1)
25                                                       :face 'nano-faded
26                                                       :margin 4 :alignment 0))))
27
28    (goto-char (point-min))
29    (while (search-forward-regexp
30            "\\([0-9]+:[0-9]+\\)\\(\\.*\\)" nil t)
31
32              (set-text-properties (match-beginning 1) (match-end 2)
33                             `(display ,(svg-tag-make (match-string 1)
34                                                      :face 'nano-default
35                                                      :inverse t
36                                                      :margin 4 :alignment 0))))
37    (goto-char (point-min))
38    (while (search-forward-regexp
39            "\\([0-9]+:[0-9]+\\)\\(-[0-9]+:[0-9]+\\)" nil t)
40      (let* ((t1 (parse-time-string (match-string 1)))
41             (t2 (parse-time-string (substring (match-string 2) 1)))
42             (t1 (+ (* (nth 2 t1) 60) (nth 1 t1)))
43             (t2 (+ (* (nth 2 t2) 60) (nth 1 t2)))
44             (d  (- t2 t1)))
45
46        (set-text-properties (match-beginning 1) (match-end 1)
47                                `(display ,(svg-tag-make (match-string 1)
48                                                         :face 'nano-faded
49                                                         :crop-right t)))
50        ;; 15m: ¼, 30m:½, 45m:¾
51        (if (< d 60)
52             (set-text-properties (match-beginning 2) (match-end 2)
53                                  `(display ,(svg-tag-make (format "%2dm" d)
54                                                           :face 'nano-faded
55                                                           :crop-left t :inverse t)))
56           (set-text-properties (match-beginning 2) (match-end 2)
57                                `(display ,(svg-tag-make (format "%1dH" (/ d 60))
58                                                         :face 'nano-faded
59                                                         :crop-left t :inverse t
60                                                         :padding 2 :alignment 0))))))))
1(add-hook 'org-agenda-mode-hook #'rougier/svg-tag-timestamp)
2(advice-add 'org-agenda-redo :after #'rougier/svg-tag-timestamp)

Tasks agenda

A custom date format function using svg tags (progress pies) for the task agenda.

 1(defun rougier/org-agenda-custom-date ()
 2  (interactive)
 3  (let* ((timestamp (org-entry-get nil "TIMESTAMP"))
 4         (timestamp (or timestamp (org-entry-get nil "DEADLINE"))))
 5    (if timestamp
 6        (let* ((delta (- (org-time-string-to-absolute (org-read-date nil nil timestamp))
 7                         (org-time-string-to-absolute (org-read-date nil nil ""))))
 8               (delta (/ (+ 1 delta) 30.0))
 9               (face (cond ;; ((< delta 0.25) 'nano-popout)
10                           ;; ((< delta 0.50) 'nano-salient)
11                           ((< delta 1.00) 'nano-default)
12                           (t 'nano-faded))))
13          (concat
14           (propertize " " 'face nil
15                       'display (svg-lib-progress-pie
16                                 delta nil
17                                 :background (face-background face nil 'default)
18                                 :foreground (face-foreground face)
19                                 :margin 0 :stroke 2 :padding 1))
20           " "
21           (propertize
22            (format-time-string "%d/%m" (org-time-string-to-time timestamp))
23            'face 'nano-popout)))
24      "     ")))

The task agenda

 1(add-to-list 'org-agenda-custom-commands
 2        '("x" "Tasks"
 3          ((todo "TODO" ;; "PROJECT"
 4                 ( (org-agenda-todo-keyword-format ":%s:")
 5                   (org-agenda-prefix-format '((todo   . " ")))
 6                   (org-agenda-skip-function '(org-agenda-skip-entry-if 'timestamp))
 7                   (org-agenda-overriding-header (propertize " Todo \n" 'face 'nano-strong))))
 8
 9           (tags "+TALK+TIMESTAMP>=\"<now>\""
10                 ((org-agenda-span 90)
11                  (org-agenda-max-tags 5)
12                  (org-agenda-prefix-format '((tags   . " %(rougier/org-agenda-custom-date) ")))
13                  (org-agenda-overriding-header "\n Upcoming talks\n")))
14
15           (tags "TEACHING+TIMESTAMP>=\"<now>\""
16                 ((org-agenda-span 90)
17                  (org-agenda-max-tags 5)
18                  (org-agenda-prefix-format '((tags   . " %(rougier/org-agenda-custom-date) ")))
19                  (org-agenda-overriding-header "\n Upcoming lessons\n")))
20
21           (tags "TRAVEL+TIMESTAMP>=\"<now>\""
22                 ((org-agenda-span 90)
23                  (org-agenda-max-tags 5)
24                  (org-agenda-prefix-format '((tags .  " %(rougier/org-agenda-custom-date) ")))
25                  (org-agenda-overriding-header "\n Upcoming travels\n")))
26
27           (tags "DEADLINE>=\"<today>\""
28                  ((org-agenda-span 90)
29                   (org-agenda-max-tags 5)
30                   (org-agenda-prefix-format '((tags .  " %(rougier/org-agenda-custom-date) ")))
31                   (org-agenda-overriding-header "\n Upcoming deadlines\n"))))))

Update

We install a time to refresh the daily agenda (a) at regular intervals such that the current time is up to date.

 1(defvar rougier/org-agenda-update-delay 60)
 2(defvar rougier/org-agenda-update-timer nil)
 3
 4(defun rougier/org-agenda-update ()
 5  "Refresh daily agenda view"
 6
 7  (when rougier/org-agenda-update-timer
 8    (cancel-timer rougier/org-agenda-update-timer))
 9
10  (let ((window (get-buffer-window "*Org Agenda(a)*" t)))
11    (when window
12      (with-selected-window window
13        (let ((inhibit-message t))
14          (org-agenda-redo)))))
15
16  (setq rougier/org-agenda-update-timer
17    (run-with-idle-timer
18     (time-add (current-idle-time) rougier/org-agenda-update-delay)
19     nil
20     'rougier/org-agenda-update)))
21
22(run-with-idle-timer rougier/org-agenda-update-delay t 'rougier/org-agenda-update)

Versioning

Git

1
2(require 'git-gutter)
3
4(global-git-gutter-mode +1)

Configure ediff

1
2(setq ediff-window-setup-function 'ediff-setup-windows-plain)

Magit

Set keybindings for magit

1(require 'llama)
1;; Taken from prelude
2;; Magit creates some global keybindings by default
3;; but it's a nice to complement them with this one
4(global-set-key (kbd "C-c g") 'magit-file-dispatch)
5(global-set-key (kbd "C-=") 'er/expand-region)

Prevent magit from writing in the header line.

1(advice-add 'magit-set-header-line-format :override #'ignore)

Add fringe on the left side of magit windows such that we can highlight region using the fringe.

1(add-hook 'magit-mode-setup-hook
2          #'(lambda ()
3              (interactive)
4              (set-window-fringes nil (* 2 (window-font-width)) 0)))

System

1(require 'openwith)
2(openwith-mode t)
3(setq openwith-associations '(("\\.mp4\\'" "vlc" (file))))