summary refs log tree commit diff
diff options
context:
space:
mode:
authorFranck Cuny <franck@fcuny.net>2023-06-01 19:35:59 -0700
committerFranck Cuny <franck@fcuny.net>2023-06-01 19:35:59 -0700
commita187752c824b47052d33d3bc12749b5a7d2e8191 (patch)
treed939397496dcae8a7634a93b159fab57ee1752ec
parentelfeed: add more feeds (diff)
downloademacs.d-a187752c824b47052d33d3bc12749b5a7d2e8191.tar.gz
🤡
Change-Id: I06b104d79deac199f9cd9cdae705e333d23cc852
-rw-r--r--.gitignore26
-rw-r--r--Makefile16
-rw-r--r--README.org7
-rw-r--r--abbrevs.el11
-rw-r--r--emacs/custom/my-completion.el88
-rw-r--r--emacs/custom/my-conf.el32
-rw-r--r--emacs/custom/my-dired.el13
-rw-r--r--emacs/custom/my-edit.el40
-rw-r--r--emacs/custom/my-eldoc.el18
-rw-r--r--emacs/custom/my-elfeed.el48
-rw-r--r--emacs/custom/my-eshell.el112
-rw-r--r--emacs/custom/my-flymake.el25
-rw-r--r--emacs/custom/my-git.el50
-rw-r--r--emacs/custom/my-lang-go.el25
-rw-r--r--emacs/custom/my-lang-nix.el16
-rw-r--r--emacs/custom/my-lang-python.el32
-rw-r--r--emacs/custom/my-lang-rust.el16
-rw-r--r--emacs/custom/my-lsp.el23
-rw-r--r--emacs/custom/my-navigation.el56
-rw-r--r--emacs/custom/my-org.el136
-rw-r--r--emacs/custom/my-packages.el108
-rw-r--r--emacs/custom/my-prog.el63
-rw-r--r--emacs/custom/my-settings.el82
-rw-r--r--emacs/custom/my-text.el53
-rw-r--r--emacs/custom/my-tramp.el24
-rw-r--r--emacs/custom/my-tree-sitter.el21
-rw-r--r--emacs/custom/my-ui.el94
-rw-r--r--emacs/elisp/my-buffers.el39
-rw-r--r--emacs/elisp/my-git-extra.el50
-rw-r--r--emacs/elisp/my-packages-extra.el65
-rw-r--r--emacs/elisp/my-strings.el23
-rw-r--r--emacs/elisp/my-web.el32
-rw-r--r--emacs/elisp/my-work.el21
-rw-r--r--emacs/init.el62
-rw-r--r--etc/elfeed.org (renamed from emacs/etc/elfeed.org)40
-rw-r--r--etc/interview.org (renamed from emacs/etc/interview.org)0
-rw-r--r--etc/new-project.org (renamed from emacs/etc/new-project.org)0
-rw-r--r--etc/weekly_review.org (renamed from emacs/etc/weekly_review.org)0
-rw-r--r--init.org2069
-rw-r--r--lisp/my-cheeseboard.el (renamed from emacs/elisp/my-cheeseboard.el)0
-rw-r--r--lisp/my-uptime.el (renamed from emacs/elisp/my-uptime.el)0
-rw-r--r--snippets/emacs-lisp-mode/defun (renamed from emacs/etc/snippets/emacs-lisp-mode/defun)0
-rw-r--r--snippets/emacs-lisp-mode/format (renamed from emacs/etc/snippets/emacs-lisp-mode/format)0
-rw-r--r--snippets/emacs-lisp-mode/header (renamed from emacs/etc/snippets/emacs-lisp-mode/header)0
-rw-r--r--snippets/go-mode/method (renamed from emacs/etc/snippets/go-mode/method)0
-rw-r--r--snippets/go-mode/test (renamed from emacs/etc/snippets/go-mode/test)0
-rw-r--r--snippets/go-mode/type (renamed from emacs/etc/snippets/go-mode/type)0
-rw-r--r--snippets/markdown-mode/new-blog-entry (renamed from emacs/etc/snippets/markdown-mode/new-blog-entry)0
-rw-r--r--snippets/org-mode/begin (renamed from emacs/etc/snippets/org-mode/begin)0
-rw-r--r--snippets/org-mode/srcsh (renamed from emacs/etc/snippets/org-mode/srcsh)0
-rw-r--r--snippets/python-mode/cli15
-rw-r--r--snippets/python-mode/function (renamed from emacs/etc/snippets/python-mode/function)0
-rw-r--r--snippets/python-mode/main (renamed from emacs/etc/snippets/python-mode/main)0
53 files changed, 2134 insertions, 1517 deletions
diff --git a/.gitignore b/.gitignore
index 4dc9462..9d56bed 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,17 +1,9 @@
-/emacs/auto-save-list/
-/emacs/eln-cache/
-/emacs/elpa/
-/emacs/emacs-custom.el
-/emacs/tramp
-/emacs/projects
-/emacs/var/
-/emacs/transient/
-/emacs/eshell/
-/emacs/forge-database.sqlite
-/emacs/url/
-/emacs/bookmarks
-/emacs/history
-/emacs/places
-/emacs/recentf
-/emacs/.lsp-session-v1
-/emacs/straight/
+*.elc
+*~
+/data*/
+/eln-cache/
+/elpa/
+/init.el
+/early-init.el
+/url/
+/eshell/
diff --git a/Makefile b/Makefile
index ec3c8b2..7a16801 100644
--- a/Makefile
+++ b/Makefile
@@ -1,13 +1,15 @@
-XDG_CONFIG=$(HOME)/.config/
+EMACS	    = emacs
+EMACS_BATCH = $(EMACS) -Q -batch
+XDG_CONFIG  = $(HOME)/.config/
 LN = @ln -sf
-default: all
-
-$(PWD)/emacs/var:
-	@mkdir -p $(PWD)/emacs/var
 
 .PHONY: emacs
-emacs: $(PWD)/emacs/var
-	$(LN) $(PWD)/emacs $(XDG_CONFIG)
+emacs:
+	$(LN) $(PWD) $(XDG_CONFIG)
+
+clean:
+	rm -f init.el *.elc *~ settings.el
+	rm -rf elpa eln-cache
 
 .PHONY: setup
 setup:
diff --git a/README.org b/README.org
deleted file mode 100644
index d81eded..0000000
--- a/README.org
+++ /dev/null
@@ -1,7 +0,0 @@
-#+TITLE: Personal Emacs configurations
-#+AUTHOR: Franck Cuny
-#+EMAIL: franck@fcuny.net
-
-This configuration works for both macos and linux.
-
-To install the configuration, run ~make~.
diff --git a/abbrevs.el b/abbrevs.el
new file mode 100644
index 0000000..28cd089
--- /dev/null
+++ b/abbrevs.el
@@ -0,0 +1,11 @@
+;;-*-coding: utf-8;-*-
+(define-abbrev-table 'global-abbrev-table
+  '(
+    ("btw" "by the way" nil :count 2)
+   ))
+
+(define-abbrev-table 'org-mode-abbrev-table
+  '(
+    ("github" "GitHub" nil :count 1)
+   ))
+
diff --git a/emacs/custom/my-completion.el b/emacs/custom/my-completion.el
deleted file mode 100644
index e66f0ce..0000000
--- a/emacs/custom/my-completion.el
+++ /dev/null
@@ -1,88 +0,0 @@
-;;; my-completion.el --- Configure parts related to completion -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'cape)
-(require 'consult)
-(require 'corfu)
-(require 'corfu-popupinfo)
-(require 'orderless)
-(require 'marginalia)
-(require 'savehist)
-(require 'vertico)
-
-;;; settings
-;; save the mini buffer's history
-(savehist-mode t)
-(setq savehist-file (expand-file-name "var/history" user-emacs-directory))
-
-(setq completion-styles '(orderless basic))
-(setq completion-category-defaults nil)
-
-(setq corfu-cycle t)       ;; Enable cycling for `corfu-next/previous'
-(setq corfu-auto t)        ;; Enable auto completion
-(setq corfu-max-width 80)  ;; Default is 100 and is too wide
-
-(defun corfu-send-shell (&rest _)
-  "Send completion candidate when inside comint/eshell."
-  (cond
-   ((and (derived-mode-p 'eshell-mode) (fboundp 'eshell-send-input))
-    (eshell-send-input))
-   ((and (derived-mode-p 'comint-mode)  (fboundp 'comint-send-input))
-    (comint-send-input))))
-
-(advice-add #'corfu-insert :after #'corfu-send-shell)
-
-;; enable corfu popup mode
-(corfu-popupinfo-mode t)
-
-;; transition quickly
-(setq corfu-popupinfo-delay '(0.25 . 0.1))
-
-;; don't hide the popup when
-;; transitioning between candidates
-(setq corfu-popupinfo-hide nil)
-
-;; Silence the pcomplete capf, no errors or messages!
-(advice-add 'pcomplete-completions-at-point :around #'cape-wrap-silent)
-
-;; Ensure that pcomplete does not write to the buffer
-;; and behaves as a pure `completion-at-point-function'.
-(advice-add 'pcomplete-completions-at-point :around #'cape-wrap-purify)
-
-(vertico-mode t)           ;; Enable vertico globally
-(marginalia-mode t)        ;; Enable marginalia globally
-(global-corfu-mode)        ;; Enable corfu globally
-
-(add-to-list 'completion-at-point-functions #'cape-file)
-(add-to-list 'completion-at-point-functions #'cape-abbrev)
-(add-to-list 'completion-at-point-functions #'cape-ispell)
-
-;;; bindings
-(global-set-key (kbd "C-c m") 'consult-mode-command)
-(global-set-key (kbd "C-x b") 'consult-buffer)
-(global-set-key (kbd "C-x 4 b") 'consult-buffer-other-window)
-(global-set-key (kbd "C-x r b") 'consult-bookmark)
-(global-set-key (kbd "C-x p b") 'consult-project-buffer)
-(global-set-key (kbd "C-c i") 'consult-imenu)
-(global-set-key (kbd "C-c f") 'consult-git-grep)
-(global-set-key (kbd "C-c /") 'consult-ripgrep)
-(global-set-key (kbd "C-c r") 'consult-recent-file)
-(global-set-key (kbd "M-y") 'consult-yank-pop)
-(global-set-key (kbd "M-g e") 'consult-compile-error)
-(global-set-key (kbd "M-g f") 'consult-flymake)
-(global-set-key (kbd "M-g M-g") 'consult-goto-line)
-(global-set-key (kbd "M-g O") 'consult-outline)
-(global-set-key (kbd "M-g o") 'consult-org-heading)
-(global-set-key (kbd "M-g m") 'consult-mark)
-(global-set-key (kbd "M-g k") 'consult-global-mark)
-(global-set-key (kbd "M-s l") 'consult-line)
-(global-set-key (kbd "M-s L") 'consult-line-multi)
-
-;;; hooks
-
-(provide 'my-completion)
-
-;;; my-completion.el ends here
diff --git a/emacs/custom/my-conf.el b/emacs/custom/my-conf.el
deleted file mode 100644
index 7b1dd13..0000000
--- a/emacs/custom/my-conf.el
+++ /dev/null
@@ -1,32 +0,0 @@
-;;; my-conf.el --- Configure modes related to configuration files -*- lexical-binding: t -*-
-
-;;; Commentary:
-;; Provides configuration for modes that are related to configuration
-;; files.
-
-;;; Code:
-
-(add-to-list 'auto-mode-alist '("\\.yml\\'"            . yaml-mode))
-(add-to-list 'auto-mode-alist '("_SWARP10_METADATA\\'" . yaml-mode))  ;; roblox related
-(add-to-list 'auto-mode-alist '("\\.yaml\\'"           . yaml-mode))
-(add-to-list 'auto-mode-alist '("Dockerfile\\'"        . dockerfile-mode))
-(add-to-list 'auto-mode-alist '("\\.tf\\'"             . terraform-mode))
-
-(customize-set-variable 'dockerfile-use-sudo t)
-(customize-set-variable 'dockerfile-use-buildkit t)
-
-(customize-set-variable 'json-reformat:indent-width 2)
-(customize-set-variable 'js-indent-level 2)
-(customize-set-variable 'css-indent-offset 2)
-
-(add-hook 'terraform-mode-hook 'terraform-format-on-save-mode)
-
-(defun my/js-mode-hook ()
-  "Hooks for `js-mode'."
-  ;; format the buffer with `jq'
-  (local-set-key (kbd "C-c C-f") 'jq-format-json-buffer))
-
-(add-hook 'js-mode-hook 'my/js-mode-hook)
-
-(provide 'my-conf)
-;;; my-conf.el ends here
diff --git a/emacs/custom/my-dired.el b/emacs/custom/my-dired.el
deleted file mode 100644
index 92ab5b0..0000000
--- a/emacs/custom/my-dired.el
+++ /dev/null
@@ -1,13 +0,0 @@
-;;; my-dired.el --- Configure `dired'
-
-;;; Commentary:
-
-;;; Code:
-
-(customize-set-variable 'dired-dwim-target t)
-(customize-set-variable 'dired-listing-switches "-ahl --time-style=long-iso --group-directories-first")
-(customize-set-variable 'dired-recursive-deletes 'always)
-(customize-set-variable 'dired-recursive-copies 'always)
-
-(provide 'my-dired)
-;;; my-dired.el ends here
diff --git a/emacs/custom/my-edit.el b/emacs/custom/my-edit.el
deleted file mode 100644
index 6a9911c..0000000
--- a/emacs/custom/my-edit.el
+++ /dev/null
@@ -1,40 +0,0 @@
-;;; my-edit.el --- Configure parts related to editing -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-(require 'autorevert)
-
-;;; settings
-(setq global-auto-revert-non-file-buffers t)
-(setq auto-revert-verbose nil)
-
-(global-auto-revert-mode t)
-
-(setq show-paren-delay 0
-      show-paren-highlight-openparen t
-      show-paren-when-point-inside-paren t
-      show-paren-when-point-in-periphery t)
-(show-paren-mode 1)
-
-;; don't assume that sentences should have two spaces after period.
-(setq sentence-end-double-space nil)
-
-;; switch to view-mode whenever you are in a read-only buffer (e.g.
-;; switched to it using C-x C-q).
-(setq view-read-only t)
-
-;;; bindings
-(global-set-key (kbd "M-j") 'join-line)
-
-;;; hooks
-(defun my/whitespace-setup ()
-  "Configure whitespace mode."
-  (setq-local show-trailing-whitespace t))
-
-;; turn on my configuration for white spaces on a few modes
-(dolist (hook '(prog-mode-hook text-mode-hook conf-mode-hook outline-mode-hook))
-  (add-hook hook 'my/whitespace-setup))
-
-(provide 'my-edit)
-;;; my-edit.el ends here
diff --git a/emacs/custom/my-eldoc.el b/emacs/custom/my-eldoc.el
deleted file mode 100644
index ff3dc0c..0000000
--- a/emacs/custom/my-eldoc.el
+++ /dev/null
@@ -1,18 +0,0 @@
-;;; my-eldoc.el --- eldoc configuration -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(setq eldoc-idle-delay 1
-      eldoc-documentation-strategy #'eldoc-documentation-default
-      eldoc-echo-area-prefer-doc-buffer 'maybe
-      eldoc-echo-area-use-multiline-p nil)
-
-(when (boundp eldoc-echo-area-display-truncation-message)
-  (setq eldoc-echo-area-display-truncation-message nil))
-
-(provide 'my-eldoc)
-
-;;; my-eldoc.el ends here
diff --git a/emacs/custom/my-elfeed.el b/emacs/custom/my-elfeed.el
deleted file mode 100644
index a9ce043..0000000
--- a/emacs/custom/my-elfeed.el
+++ /dev/null
@@ -1,48 +0,0 @@
-;;; my-elfeed.el --- Configure elfeed -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'elfeed)
-(require 'elfeed-org)
-
-(with-eval-after-load 'elfeed-search
-  '(define-key elfeed-search-mode-map (kbd "*") 'elfeed-toggle-star))
-
-(add-hook 'after-init-hook 'elfeed-org)
-
-(customize-set-variable 'elfeed-search-filter "@1-month-ago +unread")
-(customize-set-variable 'rmh-elfeed-org-files (list (expand-file-name "etc/elfeed.org" user-emacs-directory)))
-
-(defalias 'elfeed-toggle-star
-  (elfeed-expose #'elfeed-search-toggle-all 'star))
-
-;; set colors for some specific tags
-(defface elfeed-face-tag-mustread
-  '((t :foreground "#f00"))
-  "This is a custom font face for the `mustread' tag in Elfeed."
-  :group 'elfeed)
-
-(with-eval-after-load 'elfeed
-  (setq elfeed-search-face-alist
-        '((mustread elfeed-face-tag-mustread)
-          (unread elfeed-search-unread-title-face))))
-
-(defun my/elfeed-show-visit-eww ()
-  "Visit the current entry in eww."
-  (interactive)
-  (let ((link (elfeed-entry-link elfeed-show-entry)))
-    (when link
-      (eww link))))
-
-;; disable proportional fonts when displaying HTML content.
-(advice-add #'elfeed-insert-html
-              :around
-              (lambda (fun &rest r)
-                (let ((shr-use-fonts nil))
-                  (apply fun r))))
-
-(provide 'my-elfeed)
-
-;;; my-elfeed.el ends here
diff --git a/emacs/custom/my-eshell.el b/emacs/custom/my-eshell.el
deleted file mode 100644
index 87179ec..0000000
--- a/emacs/custom/my-eshell.el
+++ /dev/null
@@ -1,112 +0,0 @@
-;;; my-eshell.el --- Configure eshell -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'cl-seq)
-(require 'vc)
-(require 'eshell)
-(require 'esh-mode)
-(require 'esh-module)
-
-(setq eshell-modules-list
-      '(eshell-alias
-        eshell-basic
-        eshell-cmpl
-        eshell-dirs
-        eshell-glob
-        eshell-hist
-        eshell-ls
-        eshell-pred
-        eshell-prompt
-        eshell-script
-        eshell-term
-        eshell-tramp
-        eshell-unix))
-
-(require 'em-alias)
-(require 'em-basic)
-(require 'em-dirs)
-(require 'em-glob)
-(require 'em-hist)
-(require 'em-term)
-(require 'em-tramp)
-(require 'em-prompt)
-
-(defun my/eshell-mode-setup ()
-  "Configures various aliases for eshell."
-  (eshell/alias "e" "find-file $1")
-  (eshell/alias "emacs" "find-file $1")
-  (eshell/alias "ee" "find-file-other-window $1")
-  (eshell/alias "ll" "ls -l")
-  (eshell/alias "lla" "ls -la")
-  (eshell/alias "d" "dired $1")
-  (eshell/alias "gs" "vc-diff")
-  (eshell/alias "cal" "calendar")
-  (eshell/alias "agenda" "org-agenda"))
-
-(defvar-local my/eshell-output-buffer "*Exported eshell output*"
-  "Name of buffer with the last output of Eshell command.")
-
-(defvar-local my/eshell-output-delimiter "---"
-  "Delimiter for successive `prot-eshell-export' outputs.")
-
-(defun my/eshell--command-prompt-output ()
-  "Capture last command prompt and its output."
-  (let ((beg (save-excursion
-               (goto-char (eshell-beginning-of-input))
-               (goto-char (pos-bol)))))
-  (when (derived-mode-p 'eshell-mode)
-    (buffer-substring-no-properties beg (eshell-end-of-output)))))
-
-;; https://gitlab.com/protesilaos/dotfiles/-/blob/master/emacs/.emacs.d/prot-lisp/prot-eshell.el#L114
-(defun my/eshell-export ()
-  "Produce a buffer with output of the last Eshell command.
-If `my/eshell-output-buffer' does not exist, create it.  Else
-append to it, while separating multiple outputs with
-`my/eshell-output-delimiter'."
-  (interactive)
-  (let ((eshell-output (my/eshell--command-prompt-output)))
-    (with-current-buffer (get-buffer-create my/eshell-output-buffer)
-      (goto-char (point-max))
-      (unless (eq (point-min) (point-max))
-        (insert (format "\n%s\n\n" my/eshell-output-delimiter)))
-      (goto-char (pos-bol))
-      (insert eshell-output)
-      (switch-to-buffer-other-window (current-buffer)))))
-
-(defun my/short-pwd (path)
-  "Turn a PATH of the form /foo/bar/baz into /f/b/baz, like fish shell."
-  (let* ((home-path (replace-regexp-in-string (expand-file-name "~")
-                                          "~"
-                                          path))
-         (current-dir (split-string home-path "/"))
-         (cdir (last current-dir))
-         (head (butlast current-dir)))
-    (concat (mapconcat (lambda (s)
-                         (if (string= "" s) nil
-                           (substring s 0 1)))
-                       head
-                       "/")
-            (if head "/" nil)
-            (car cdir))))
-
-(defmacro with-face (str &rest properties)
-  "Set the PROPERTIES for the given STR."
-  `(propertize ,str 'face (list ,@properties)))
-
-(define-key eshell-mode-map (kbd "C-c e e") 'my/eshell-export)
-
-(customize-set-variable 'eshell-scroll-to-bottom-on-input 'all)
-(customize-set-variable 'eshell-hist-ignoredups t)
-(customize-set-variable 'eshell-save-history-on-exit t)
-(customize-set-variable 'eshell-cd-on-directory t)
-(customize-set-variable 'eshell-prefer-lisp-functions t)
-(customize-set-variable 'eshell-destroy-buffer-when-process-dies t)
-
-(add-hook 'eshell-mode-hook 'my/eshell-mode-setup)
-
-(provide 'my-eshell)
-
-;;; my-eshell.el ends here
diff --git a/emacs/custom/my-flymake.el b/emacs/custom/my-flymake.el
deleted file mode 100644
index 40f6ab9..0000000
--- a/emacs/custom/my-flymake.el
+++ /dev/null
@@ -1,25 +0,0 @@
-;;; my-flymake.el --- configure flymake -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'flymake)
-
-;;; settings
-(setq flymake-start-on-save-buffer t)
-(setq elisp-flymake-byte-compile-load-path load-path)
-
-;;; bindings
-(define-key flymake-mode-map (kbd "C-c ! n") 'flymake-goto-next-error)
-(define-key flymake-mode-map (kbd "C-c ! p") 'flymake-goto-prev-error)
-(define-key flymake-mode-map (kbd "C-c ! d") 'flymake-show-diagnostics-buffer)
-
-;;; hooks
-(dolist (hook '(prog-mode-hook conf-mode-hook))
-  (add-hook hook 'flymake-mode))
-
-(provide 'my-flymake)
-
-;;; my-flymake.el ends here
diff --git a/emacs/custom/my-git.el b/emacs/custom/my-git.el
deleted file mode 100644
index 2270f91..0000000
--- a/emacs/custom/my-git.el
+++ /dev/null
@@ -1,50 +0,0 @@
-;;; my-git --- configures git for emacs -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'magit)
-(require 'git-link)
-
-;;; settings
-(setq vc-follow-symlinks t)
-
-;; we're not barbarians
-(setq git-commit-summary-max-length 70)
-
-;; open the link in the browser
-(setq git-link-open-in-browser 't)
-
-;; I prefer to have the status buffer in full frame
-(setq magit-display-buffer-function #'magit-display-buffer-fullframe-status-v1)
-
-;; expand a number of sections with magit
-(add-to-list 'magit-section-initial-visibility-alist '(untracked . show))
-(add-to-list 'magit-section-initial-visibility-alist '(unstaged  . show))
-(add-to-list 'magit-section-initial-visibility-alist '(unpulled  . show))
-(add-to-list 'magit-section-initial-visibility-alist '(unpushed  . show))
-
-(add-to-list 'auto-mode-alist '("\\.gitconfig\\'"     . gitconfig-mode))
-(add-to-list 'auto-mode-alist '("\\.git/config\\'"    . gitconfig-mode))
-(add-to-list 'auto-mode-alist '("\\.gitmodules\\'"    . gitconfig-mode))
-(add-to-list 'auto-mode-alist '("\\.gitignore\\'"     . gitconfig-mode))
-(add-to-list 'auto-mode-alist '("\\.dockerignore\\'"  . gitconfig-mode))
-(add-to-list 'auto-mode-alist '("\\.gitattributes\\'" . gitattributes-mode))
-
-;;; bindings
-(global-set-key (kbd "C-x g") 'magit-status)
-(global-set-key (kbd "C-c g l") 'git-link)
-(global-set-key (kbd "C-c g c") 'git-link-commit)
-
-;;; hooks
-(defun my/git-commit-auto-fill ()
-  "Ensures that the commit body does not exceed 72 characters."
-  (setq-local fill-column 72)
-  (setq-local comment-auto-fill-only-comments nil))
-
-(add-hook 'git-commit-mode-hook 'my/git-commit-auto-fill)
-
-(provide 'my-git)
-
-;;; my-git.el ends here
diff --git a/emacs/custom/my-lang-go.el b/emacs/custom/my-lang-go.el
deleted file mode 100644
index 7dde8c4..0000000
--- a/emacs/custom/my-lang-go.el
+++ /dev/null
@@ -1,25 +0,0 @@
-;;; my-lang-go.el --- configure emacs for go -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'go-mode)
-(require 'gotest)
-(require 'eglot)
-
-(add-hook 'go-mode-hook 'eglot-ensure)
-
-(add-hook 'go-mode-hook
-          (lambda ()
-            (setq tab-width 4)
-            (setq compile-command "go build -v && go test -v && go vet")))
-
-(add-hook 'go-mode-hook
-          (lambda()
-            (add-hook 'before-save-hook 'eglot-format-buffer nil t)))
-
-(provide 'my-lang-go)
-
-;;; my-lang-go.el ends here
diff --git a/emacs/custom/my-lang-nix.el b/emacs/custom/my-lang-nix.el
deleted file mode 100644
index 6e17ee3..0000000
--- a/emacs/custom/my-lang-nix.el
+++ /dev/null
@@ -1,16 +0,0 @@
-;;; my-lang-nix.el --- configure emacs for nix -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'eglot)
-(require 'nix-mode)
-
-(add-hook 'nix-mode-hook 'eglot-ensure)
-(add-hook 'nix-mode-hook #'(lambda() (add-hook 'before-save-hook 'eglot-format-buffer nil t)))
-
-(provide 'my-lang-nix)
-
-;;; my-lang-nix.el ends here
diff --git a/emacs/custom/my-lang-python.el b/emacs/custom/my-lang-python.el
deleted file mode 100644
index 10c1cd9..0000000
--- a/emacs/custom/my-lang-python.el
+++ /dev/null
@@ -1,32 +0,0 @@
-;;; my-lang-python.el --- Configures emacs for python -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'python)
-
-(setq python-interpreter "ipython3")
-(setq python-shell-interpreter "python3")
-(setq python-shell-interpreter-args "-i")
-
-;;; bindings
-(define-key python-mode-map (kbd "C-h f") 'python-eldoc-at-point)
-
-;;; hooks
-;; if black is present, enable it
-(when (executable-find "black")
-  (require 'blacken)
-  (add-hook 'python-mode-hook 'blacken-mode))
-
-(when (executable-find "pylsp")
-  (add-hook 'python-mode-hook 'eglot-ensure)
-  ;; https://github.com/python-lsp/python-lsp-server/blob/develop/CONFIGURATION.md
-  (setq-default eglot-workspace-configuration
-                '((pylsp (plugins (flake8      (enabled . :json-false))
-                                  (pycodestyle (enabled . :json-false)))))))
-
-(provide 'my-lang-python)
-
-;;; my-lang-python.el ends here
diff --git a/emacs/custom/my-lang-rust.el b/emacs/custom/my-lang-rust.el
deleted file mode 100644
index b0d3904..0000000
--- a/emacs/custom/my-lang-rust.el
+++ /dev/null
@@ -1,16 +0,0 @@
-;;; my-lang-rust.el --- configure emacs for rust -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'rustic)
-
-(setq rustic-format-on-save t)
-(setq rustic-lsp-client 'eglot)
-(setq rustic-lsp-server 'rust-analyzer)
-
-(provide 'my-lang-rust)
-
-;;; my-lang-rust.el ends here
diff --git a/emacs/custom/my-lsp.el b/emacs/custom/my-lsp.el
deleted file mode 100644
index 40ba785..0000000
--- a/emacs/custom/my-lsp.el
+++ /dev/null
@@ -1,23 +0,0 @@
-;;; my-lsp.el --- Configures emacs for LSP -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'eglot)
-
-;; settings related to performance
-;; https://emacs-lsp.github.io/lsp-mode/page/performance/
-(setq read-process-output-max (* 1024 1024)) ;; 1mb
-(setq gc-cons-threshold 100000000)           ;; 100mb
-
-(global-set-key (kbd "C-c l e") #'eglot)
-(define-key eglot-mode-map (kbd "C-c l s") #'eglot-shutdown)
-(define-key eglot-mode-map (kbd "C-c l r") #'eglot-rename)
-(define-key eglot-mode-map (kbd "C-c l a") #'eglot-code-actions)
-(define-key eglot-mode-map (kbd "C-c l o") #'eglot-code-action-organize-imports)
-
-(provide 'my-lsp)
-
-;;; my-lsp.el ends here
diff --git a/emacs/custom/my-navigation.el b/emacs/custom/my-navigation.el
deleted file mode 100644
index 06de92e..0000000
--- a/emacs/custom/my-navigation.el
+++ /dev/null
@@ -1,56 +0,0 @@
-;;; my-navigation.el --- Configure parts related to navigation -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'bookmark)
-(require 'project)
-(require 'recentf)
-(require 'rg)
-(require 'transient)
-
-;;; settings
-(setq help-window-select t)  ;; select help window when opening it
-
-;; where to store the list of projects
-(setq project-list-file (expand-file-name "var/projects" user-emacs-directory))
-
-(setq project-switch-commands
-      '((?f "File" project-find-file)
-        (?d "Dired" project-dired)
-        (?b "Buffer" project-switch-to-buffer)
-        (?e "Eshell" project-eshell)
-        (?m "Magit status" magit-project-status)
-        (?r "Search" rg-project)))
-
-(setq bookmark-save-flag 1)
-(setq bookmark-default-file (expand-file-name "var/bookmarks" user-emacs-directory))
-
-(setq rg-group-result t)
-(setq rg-show-columns t)
-(setq rg-align-position-numbers t)
-(setq rg-align-line-number-field-length 3)
-(setq rg-align-column-number-field-length 3)
-(setq rg-align-line-column-separator "#")
-(setq rg-align-position-content-separator "|")
-
-;; where to store the list of recent files
-(setq recentf-save-file (expand-file-name "var/recentf" user-emacs-directory))
-(setq recentf-max-saved-items 500)
-(setq recentf-exclude '(".gz" ".xz" ".zip" "tmp/" "/ssh:"))
-
-;; where to store transient's history
-(setq transient-history-file (expand-file-name "var/transient-history.el" user-emacs-directory))
-
-;;; bindings
-(global-set-key (kbd "C-x C-b") 'ibuffer)
-(global-set-key (kbd "M-g i") 'imenu)
-
-;;; hooks
-(add-hook 'after-init-hook 'recentf-mode)
-(add-hook 'after-init-hook 'which-key-mode)
-
-(provide 'my-navigation)
-
-;;; my-navigation.el ends here
diff --git a/emacs/custom/my-org.el b/emacs/custom/my-org.el
deleted file mode 100644
index 85716d3..0000000
--- a/emacs/custom/my-org.el
+++ /dev/null
@@ -1,136 +0,0 @@
-;;; my-org.el --- Configure org-mode -*- lexical-binding: t -*-
-;;; Commentary:
-;;; Code:
-
-(require 'org)
-(require 'org-agenda)
-(require 'org-capture)
-(require 'org-archive)
-(require 'org-cliplink)
-(require 'ox)
-(require 'ox-md)
-
-(defvar my/org-directory
-  (if (memq window-system '(mac ns))
-      (expand-file-name "~/workspace/notebooks/")
-    (expand-file-name "~/documents/notes/")))
-
-(add-hook 'org-mode-hook 'org-indent-mode)
-(add-hook 'org-mode-hook 'org-hide-block-all)
-(add-hook 'org-mode-hook 'visual-line-mode)
-(add-hook 'org-capture-after-finalize-hook 'org-save-all-org-buffers)
-(add-hook 'org-capture-prepare-finalize-hook 'org-save-all-org-buffers)
-
-(global-set-key (kbd "C-c c") 'org-capture)
-(global-set-key (kbd "C-c a") 'org-agenda)
-
-(defvar load-language-list '((emacs-lisp . t)
-                             (python . t)
-                             (shell . t)))
-
-(setq org-directory my/org-directory)
-(setq org-hide-emphasis-markers t)                ;; hide emphasis markup
-(setq org-archive-subtree-add-inherited-tags t)   ;; when archiving, inherit the tags from the parent
-(setq org-pretty-entities t)                      ;; display unicode characters
-(setq org-log-done 'time)                         ;; log the time of completion
-(setq org-log-into-drawer t)                      ;; insert state change in the drawer
-(setq org-cycle-separator-lines 0)
-(setq org-startup-folded 'content)
-(setq org-todo-keywords '((sequence "TODO" "WAITING" "|" "DONE" "CANCELED")))
-
-(setq org-priority-start-cycle-with-default nil) ;; Start one over/under default value.
-(setq org-highest-priority ?A)
-(setq org-lowest-priority ?D)
-(setq org-default-priority ?C)                   ;; Ensures unset tasks have low priority.
-
-(setq org-refile-use-cache nil)
-(setq org-refile-targets `((,(expand-file-name "tasks.org" org-directory) :maxlevel . 1)
-                           (,(expand-file-name "notes.org" org-directory) :maxlevel . 1)))
-(setq org-refile-use-outline-path 'file)
-(setq org-outline-path-complete-in-steps nil)
-(setq org-refile-allow-creating-parent-nodes 'confirm)
-
-;; org babel related
-(setq org-src-fontify-natively t)
-(setq org-src-preserve-indentation t)     ;; prevent the conversion of spaces into tabs (necessary for Python code exports)
-(setq org-edit-src-content-indentation t)
-
-(setq org-return-follows-link t)          ;; I want to follow links on RET
-
-;; some configurations for exporting document
-(setq org-export-with-toc nil)
-(setq org-export-with-section-numbers nil)
-
-;; a few abbreviations I use regularly
-(setq org-link-abbrev-alist
-      '(("src"  . "~/workspace/%s")
-        ("jira" . "https://jira.rbx.com/browse/%s")
-        ("go"   . "http://go/%s")))
-
-(setq org-blank-before-new-entry (quote ((heading . nil) (plain-list-item . nil))))
-(setq org-reverse-note-order t)
-
-(setq org-agenda-files `(,(expand-file-name "inbox.org" org-directory)
-                         ,(expand-file-name "notes.org" org-directory)
-                         ,(expand-file-name "tasks.org" org-directory)
-                         ,(expand-file-name "bookmarks.org" org-directory)
-                         ,(expand-file-name "journal.org" org-directory)))
-(setq org-agenda-show-all-dates t)
-(setq calendar-week-start-day 1)
-(setq org-agenda-custom-commands nil)
-(setq org-agenda-start-on-weekday 1)
-
-(add-to-list 'org-agenda-custom-commands
-             '("A" "Agenda for today"
-               ((agenda "" ((org-agenda-span 'day)
-                            (org-agenda-start-day (org-today))))
-                (todo "TODO"
-                      ((org-agenda-overriding-header "To Refile")
-                       (org-agenda-files `(,(expand-file-name "inbox.org" org-directory)))))
-                (todo "STARTED"
-                      ((org-agenda-overriding-header "In Progress")))
-                (todo "WAITING"
-                      ((org-agenda-overriding-header "Blocked")))
-                (todo "TODO"
-                      ((org-agenda-overriding-header "Not yet started")
-                       (org-agenda-skip-function '(org-agenda-skip-entry-if 'deadline 'scheduled)))))))
-
-(setq org-capture-templates
-`(("t" "tasks" entry (file "inbox.org")
-   "* TODO [#D] %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n")
-
-  ("T" "TIL" entry (file+headline "til.org" "Today I learned")
-   "* %^{title} :%^{tag}:\n:PROPERTIES:\n:CREATED: %U\n:END:\n%?\nSource: %^C")
-
-  ("n" "note" entry (file "notes.org")
-   "* %?\n:PROPERTIES:\n:CREATED: %T\n:END:\n")
-
-  ("f" "feed" entry (file "inbox.org")
-   ,(concat "* TODO [#D] %:elfeed-entry-title :feed:\n"
-            ":PROPERTIES:\n:CREATED: %T\n:END:\n"
-            "%a\n"))
-
-  ("b" "bookmark" entry (file "bookmarks.org")
-   ,(concat "* %(org-cliplink-capture) :%^{tag}:\n"
-            ":PROPERTIES:\n:CREATED: %T\n:END:%?\n") :prepend t :empty-lines 1)
-
-  ("j" "journal" entry (file+olp+datetree "journal.org")
-   "* %?\n:PROPERTIES:\n:CREATED: %T\n:END:\n" :tree-type day)))
-
-;; https://stackoverflow.com/questions/20164918/how-to-untick-checkboxes-in-org-mode-for-the-next-cyclic-repetitive-task
-(defun my/org-reset-checkbox-state-maybe ()
-  "Reset all checkboxes in an entry if the `RESET_CHECK_BOXES' property is set."
-  (interactive "*")
-  (if (org-entry-get (point) "RESET_CHECK_BOXES")
-      (org-reset-checkbox-state-subtree)))
-
-(defun my/org-reset-checkbox-when-done ()
-  "Reset all checkboxes in an entry when the state is DONE."
-  (when (member org-state org-done-keywords) ;; org-state dynamically bound in org.el/org-todo
-    (my/org-reset-checkbox-state-maybe)))
-
-(add-hook 'org-after-todo-state-change-hook 'my/org-reset-checkbox-when-done)
-
-(provide 'my-org)
-
-;;; my-org.el ends here
diff --git a/emacs/custom/my-packages.el b/emacs/custom/my-packages.el
deleted file mode 100644
index 62cfac0..0000000
--- a/emacs/custom/my-packages.el
+++ /dev/null
@@ -1,108 +0,0 @@
-;;; my-packages.el --- List of packages to install -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'package)
-(add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/"))
-
-(defvar my/package-list
-  '(eglot
-    ;; python
-    blacken
-    python-docstring
-    python-mode
-
-    ;; go
-    go-mode
-    gotest
-
-    ;; nix
-    nix-mode
-
-    ;; rust
-    rustic
-
-    ;; various configuration formats
-    chef-mode
-    dockerfile-mode
-    fish-mode
-    hcl-mode
-    jq-format
-    protobuf-mode
-    systemd
-    terraform-doc
-    terraform-mode
-    toml-mode
-    yaml-mode
-
-    ;; git
-    git-commit
-    git-link
-    git-modes
-    magit
-
-    ;; elfeed
-    elfeed
-    elfeed-org
-
-    ;; org-mode
-    org-cliplink
-
-    ;; various text modes
-    markdown-mode
-
-    ;; tree-sitter
-    tree-sitter
-    tree-sitter-langs
-
-    ;; navigation
-    cape
-    consult
-    corfu
-    marginalia
-    orderless
-    vertico
-    which-key
-    yasnippet
-
-    ;; themes
-    standard-themes
-
-    ;; packages to interact with external tools
-    exec-path-from-shell
-    envrc
-    rg)
-  "List of packages to be installed.")
-
-(defun my/packages-installed-p ()
-  "Check if all packages in `my/package-list' are installed."
-  (cl-every #'package-installed-p my/package-list))
-
-(defun my/require-package (package)
-  "Install PACKAGE unless already installed."
-  (unless (memq package my/package-list)
-    (add-to-list 'my/package-list package))
-  (unless (package-installed-p package)
-    (package-install package)))
-
-(defun my/require-packages (packages)
-  "Ensure PACKAGES are installed.
-Missing packages are installed automatically."
-  (mapc #'my/require-package packages))
-
-(defun my/install-packages ()
-  "Install all packages listed in `my/package-list'."
-  (unless (my/packages-installed-p)
-    ;; check for new packages (package versions)
-    (message "%s" "Reloading packages DB...")
-    (package-refresh-contents)
-    (message "%s" " done.")
-    ;; install the missing packages
-    (my/require-packages my/package-list)))
-
-(provide 'my-packages)
-
-;;; my-packages.el ends here
diff --git a/emacs/custom/my-prog.el b/emacs/custom/my-prog.el
deleted file mode 100644
index 8314ab9..0000000
--- a/emacs/custom/my-prog.el
+++ /dev/null
@@ -1,63 +0,0 @@
-;;; my-prog.el --- Configures emacs for various programming languages -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-(customize-set-variable 'Man-notify-method 'aggressive)
-(customize-set-variable 'Man-fontify-manpage-flag t)
-
-;; turn on `electric-pair-mode' on `prog-mode' and `conf-mode-hook'
-(dolist (hook '(prog-mode-hook conf-mode-hook))
-  (add-hook hook 'electric-pair-mode))
-
-;; Skip over warnings and info messages in compilation
-(customize-set-variable 'compilation-skip-threshold 2)
-;; Don't freeze when process reads from stdin
-(customize-set-variable 'compilation-disable-input t)
-;; Show three lines of context around the current message
-(customize-set-variable 'compilation-context-lines 3)
-;; Jump to first error
-(customize-set-variable 'compilation-scroll-output 'first-error)
-
-;; yasnippet is required to support place holders with eglot
-(dolist (hook '(prog-mode-hook conf-mode-hook org-mode-hook))
-  (add-hook hook 'yas-minor-mode))
-
-;; where to wrap comments
-(require 'newcomment)
-(setq comment-fill-column 120)
-(setq comment-auto-fill-only-comments t)
-
-(dolist (hook '(prog-mode-hook conf-mode-hook))
-  (add-hook hook 'auto-fill-mode))
-
-(defun my/sh-mode-hook ()
-  "Hooks for `sh-mode'."
-  ;; shell scripts are made executable
-  (add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)
-  (customize-set-variable 'sh-indentation 2)
-  (customize-set-variable 'sh-basic-offset 2))
-
-(add-hook 'sh-mode-hook 'my/sh-mode-hook)
-
-(defun my/makefile-mode-hook ()
-  "Hooks for `makefile-mode'."
-  ;; I want small tabs when working in a Makefile
-  (setq tab-width 2))
-
-(add-hook 'makefile-mode-hook 'my/makefile-mode-hook)
-
-(defun my/elisp-mode-hook ()
-  "Hooks for `elisp-mode'."
-  (define-key emacs-lisp-mode-map (kbd "C-c C-e") 'eval-buffer)
-  (define-key emacs-lisp-mode-map (kbd "C-c C-r") 'eval-region))
-
-(add-hook 'emacs-lisp-mode-hook 'my/elisp-mode-hook)
-
-(define-key prog-mode-map (kbd "C-c C-h") 'eldoc)
-(dolist (hook '(prog-mode-hook conf-mode-hook))
-  (add-hook hook 'turn-on-eldoc-mode))
-
-(provide 'my-prog)
-
-;;; my-prog.el ends here
diff --git a/emacs/custom/my-settings.el b/emacs/custom/my-settings.el
deleted file mode 100644
index b17f4a6..0000000
--- a/emacs/custom/my-settings.el
+++ /dev/null
@@ -1,82 +0,0 @@
-;;; my-settings.el --- Sets a number of defaults -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'url-cookie)
-
-;; set utf-8 as the default encoding
-(prefer-coding-system 'utf-8-unix)
-(setq locale-coding-system 'utf-8)
-(set-language-environment 'utf-8)
-(set-terminal-coding-system 'utf-8)
-(set-keyboard-coding-system 'utf-8)
-
-;; alias yes-or-no to y-or-n
-(fset 'yes-or-no-p 'y-or-n-p)
-
-(setq auto-save-default nil)                     ;; don't auto save files
-(setq auto-save-list-file-prefix nil)            ;; no backups
-(setq create-lockfiles nil)                      ;; don't use a lock file
-(setq confirm-kill-emacs #'yes-or-no-p)          ;; ask before killing emacs
-(setq make-backup-files nil)                     ;; really no backups
-(setq minibuffer-message-timeout 0.5)            ;; How long to display an echo-area message
-(setq next-screen-context-lines 5)               ;; scroll 5 lines at a time
-(setq require-final-newline t)                   ;; ensure newline exists at the end of the file
-(setq ring-bell-function 'ignore)                ;; really no bell
-(setq tab-always-indent 'complete)               ;; when using TAB, always indent
-(setq visible-bell nil)                          ;; no bell
-(setq column-number-mode t)                      ;; show column number in the mode line
-(setq-default indent-tabs-mode nil)              ;; turn off tab indentation
-(setq-default cursor-type 'box)                  ;; cursor is a horizontal bar
-(setq-default delete-by-moving-to-trash t)       ;; delete files by moving them to the trash
-(setq initial-scratch-message "")                ;; empty scratch buffer
-(setq garbage-collection-messages t)             ;; log when the gc kicks in
-
-;; where to store cookies
-(setq url-cookie-file (expand-file-name "var/url/cookies" user-emacs-directory))
-
-(custom-set-variables
- '(use-file-dialog nil)
- '(use-dialog-box nil)
- '(inhibit-startup-screen t)
- '(inhibit-startup-message t)
- '(inhibit-startup-echo-area-message t))
-
-(setq user-full-name "Franck Cuny"
-      user-mail-address "franck@fcuny.net"
-      add-log-mailing-address "franck@fcuny.net")
-
-(customize-set-variable 'history-length 1000)
-(customize-set-variable 'history-delete-duplicates t)
-
-(add-hook 'after-init-hook 'midnight-mode)
-
-(customize-set-variable 'save-place-forget-unreadable-files t)
-(add-hook 'after-init-hook #'save-place-mode)
-
-(when (memq window-system '(mac ns))
-  (require 'exec-path-from-shell)
-  (exec-path-from-shell-initialize))
-
-(unless (and (fboundp 'server-running-p)
-             (server-running-p))
-  (server-start))
-
-(require 'yasnippet)
-
-;; I want the snippets under `etc'
-(defvar my/yasnippets (expand-file-name "etc/snippets" user-emacs-directory))
-
-(if (and  (file-exists-p my/yasnippets) (not (member my/yasnippets yas-snippet-dirs)))
-    (setq yas--default-user-snippets-dir my/yasnippets))
-
-;; the default (tab) conflicts with corfu for completion
-(define-key yas-minor-mode-map (kbd "C-c y") #'yas-expand)
-
-(yas-global-mode 1)
-
-(provide 'my-settings)
-
-;;; my-settings.el ends here
diff --git a/emacs/custom/my-text.el b/emacs/custom/my-text.el
deleted file mode 100644
index 37f9773..0000000
--- a/emacs/custom/my-text.el
+++ /dev/null
@@ -1,53 +0,0 @@
-;;; my-text.el --- configures modes related to text -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-
-;; BUG: this is a work around for markdown-mode - without this, imenu
-;; won't work in that mode, which is preventing efficient navigation.
-;; The following link has more details:
-;; https://github.com/jrblevin/markdown-mode/issues/578#issuecomment-1126380098
-(require 'comp)
-(setq native-comp-deferred-compilation-deny-list '("markdown-mode\\.el$"))
-
-(require 'markdown-mode)
-(require 'ispell)
-(require 'abbrev)
-
-;;; settings
-(setq ispell-program-name (executable-find "aspell"))
-(setq ispell-dictionary "en_US")
-(setq ispell-extra-args '("--camel-case"))
-
-(add-to-list 'auto-mode-alist
-             '("\\.\\(md\\|markdown\\)$" . markdown-mode) auto-mode-alist)
-
-;; use GitHub's markdown flavor for README files
-(add-to-list 'auto-mode-alist '("README\\.md\\'" . gfm-mode))
-
-(when (executable-find "pandoc")
-  (setq markdown-command "pandoc -f markdown -t html"))
-
-(setq only-global-abbrevs nil)
-(setq abbrev-file-name (expand-file-name "var/abbrev_defs" user-emacs-directory))
-(let ((table text-mode-abbrev-table))
-  (define-abbrev table "github" "GitHub")
-  (define-abbrev table "emacs" "Emacs"))
-
-;;; bindings
-
-;;; hooks
-(add-hook 'text-mode-hook 'flyspell-mode)
-(add-hook 'text-mode-hook 'goto-address-mode)
-
-(dolist (hook '(prog-mode-hook conf-mode-hook))
-  (add-hook hook 'flyspell-prog-mode))
-
-(dolist (hook '(text-mode-hook git-commit-mode-hook))
-  (add-hook hook 'abbrev-mode))
-
-(provide 'my-text)
-
-;;; my-text.el ends here
diff --git a/emacs/custom/my-tramp.el b/emacs/custom/my-tramp.el
deleted file mode 100644
index 897d48c..0000000
--- a/emacs/custom/my-tramp.el
+++ /dev/null
@@ -1,24 +0,0 @@
-;;; my-tramp.el --- Configure tramp -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-(customize-set-variable 'tramp-default-method "ssh")
-(customize-set-variable 'tramp-histfile-override t)
-(customize-set-variable 'tramp-ssh-controlmaster-options "-o ControlMaster=auto -o ControlPath='tramp.%%C'")
-
-(defcustom my/ssh-hosts '("192.168.0.1:9922"
-                          "192.168.0.106")
-  "List of hosts I regularly connect to."
-  :type '(repeat string)
-  :group 'tramp)
-
-(defun my/ssh-cd-home ()
-  "Prompt for an SSH host and open a DIRED buffer on that machine."
-  (interactive)
-  (let ((machine (completing-read "Machine: " my/ssh-hosts)))
-    (find-file (format "/ssh:%s:~" machine))))
-
-(provide 'my-tramp)
-;;; my-tramp.el ends here
diff --git a/emacs/custom/my-tree-sitter.el b/emacs/custom/my-tree-sitter.el
deleted file mode 100644
index d19362e..0000000
--- a/emacs/custom/my-tree-sitter.el
+++ /dev/null
@@ -1,21 +0,0 @@
-;;; my-tree-sitter.el --- configure emacs for tree-sitter -*- lexical-binding: t -*-
-;; Author: Franck Cuny <franck@fcuny.net>
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'tree-sitter)
-(require 'tree-sitter-langs)
-
-;; enable tree-sitter mode for all supported major modes
-(global-tree-sitter-mode)
-
-;; the minor mode tree-sitter-hl-mode provides the framework for syntax
-;; highlighting. It overrides the regex-based highlighting provided by
-;; font-lock-mode, using the syntax tree provided by tree-sitter-mode
-(add-hook 'tree-sitter-after-on-hook #'tree-sitter-hl-mode)
-
-(provide 'my-tree-sitter)
-
-;;; my-tree-sitter.el ends here
diff --git a/emacs/custom/my-ui.el b/emacs/custom/my-ui.el
deleted file mode 100644
index 228baea..0000000
--- a/emacs/custom/my-ui.el
+++ /dev/null
@@ -1,94 +0,0 @@
-;;; my-ui.el --- configure UI elements -*- lexical-binding: t -*-
-
-;;; Commentary:
-
-;;; Code:
-
-;; cleaning up the UI
-(scroll-bar-mode -1)
-(tool-bar-mode -1)
-(menu-bar-mode -1)
-(blink-cursor-mode -1)
-
-;;; no fringe on the right side
-(set-fringe-mode '(8 . 0))
-
-(when (memq window-system '(mac ns))
-  (add-to-list 'default-frame-alist '(font . "Source Code Pro-15"))
-  (add-to-list 'default-frame-alist '(fullscreen . maximized))
-  (add-to-list 'default-frame-alist '(ns-appearance . nil))
-  (add-to-list 'default-frame-alist '(ns-transparent-titlebar . nil))
-  (when (boundp 'ns-use-native-fullscreen)
-    (setq ns-use-native-fullscreen nil))
-  (when (boundp 'mac-allow-anti-aliasing)
-    (setq mac-allow-anti-aliasing t)))
-
-(when (memq window-system '(x pgtk))
-  (set-face-attribute 'default nil :font "Source Code Pro" :height 130)
-  ;; this is a fall back in the case we have Unicode characters.
-  ;; For example, with this settings, the following source is
-  ;; rendered correctly 😇 😀 and 🤢
-  (set-fontset-font t 'symbol "Noto Color Emoji" nil 'append))
-
-(customize-set-variable 'display-time-24hr-format t)
-(customize-set-variable 'display-time-day-and-date t)
-(customize-set-variable 'display-time-format "%a %e %b, %H:%M")
-(customize-set-variable 'display-time-interval 60)
-(customize-set-variable 'display-time-default-load-average nil)
-(customize-set-variable 'zoneinfo-style-world-list
-                        '(("UTC" "UTC")
-                          ("America/Los_Angeles" "Berkeley")
-                          ("America/Denver" "Mountain Time")
-                          ("America/Chicago" "Central Time")
-                          ("America/New_York" "New York")
-                          ("Europe/London" "London")
-                          ("Europe/Paris" "Paris")
-                          ("Asia/Calcutta" "Bangalore")
-                          ("Asia/Tokyo" "Tokyo")))
-
-;; the following setup only works with emacs >=28 I think
-(when (boundp 'world-clock-list)
-  (setq world-clock-list t))
-
-(when (boundp 'world-clock-time-format)
-  ;; UTC      => 02:42 +0000  Wednesday 20 April
-  ;; Berkeley => 19:42 -0700  Tuesday 19 April
-  (setq world-clock-time-format "%R %z  %A %d %B"))
-
-(when (boundp 'world-clock-timer-enable)
-  (setq world-clock-timer-enable t))
-
-(when (boundp 'world-clock-timer-second)
-  (setq world-clock-timer-second 60))
-
-;; Disable help mouse-overs for mode-line as they provide little to no benefits
-(setq mode-line-default-help-echo nil
-      show-help-function nil)
-
-(setq display-buffer-alist
-      `(
-        ("\\*\\(.* # Help.*\\|Help\\|xref\\)\\*" ; See the hooks for `visual-line-mode'
-         (display-buffer-reuse-mode-window display-buffer-in-side-window)
-         (window-width . 0.35)
-         (side . left)
-         (slot . 0))
-        ("\\*\\(Flymake diagnostics\\|Package-Lint\\).*"
-         (display-buffer-in-side-window)
-         (window-height . 0.16)
-         (side . top)
-         (slot . 0))
-        ("\\*\\(Backtrace\\|Warnings\\|Compile-Log\\|Flymake log\\|Async Shell Command\\)\\*"
-         (display-buffer-in-side-window)
-         (window-height . 0.16)
-         (side . top)
-         (slot . 2))
-        ("\\*\\(wclock\\|slo-calculator\\).*"
-         (display-buffer-in-side-window)
-         (window-width . 0.35)
-         (side . left)
-         (slot . 0))))
-
-(add-hook 'help-mode-hook 'visual-line-mode)
-
-(provide 'my-ui)
-;;; my-ui.el ends here
diff --git a/emacs/elisp/my-buffers.el b/emacs/elisp/my-buffers.el
deleted file mode 100644
index 8c03905..0000000
--- a/emacs/elisp/my-buffers.el
+++ /dev/null
@@ -1,39 +0,0 @@
-;;; my-buffers.el --- Functions related to buffer manipulations
-;;; Commentary:
-;;; Code:
-
-(defun my/copy-whole-buffer ()
-  "Select the buffer and copy it."
-  (interactive)
-  (save-excursion
-    (mark-whole-buffer)
-    (copy-region-as-kill 1 (buffer-size))))
-
-(defun my/rename-this-buffer-and-file ()
-  "Renames current buffer and file it is visiting."
-  (interactive)
-  (let ((name (buffer-name))
-        (filename (buffer-file-name))
-        (read-file-name-function 'read-file-name-default))
-    (if (not (and filename (file-exists-p filename)))
-        (error "Buffer '%s' is not visiting a file!" name)
-      (let ((new-name (read-file-name "New name: " filename)))
-        (cond ((get-buffer new-name)
-               (error "A buffer named '%s' already exists!" new-name))
-              (t
-               (rename-file filename new-name 1)
-               (rename-buffer new-name)
-               (set-visited-file-name new-name)
-               (set-buffer-modified-p nil)
-               (message "File '%s' successfully renamed to '%s'" name (file-name-nondirectory new-name))))))))
-
-(defun my/uniquify-region-lines (beg end)
-  "Remove duplicate adjacent lines in region between BEG and END."
-  (interactive "*r")
-  (save-excursion
-    (goto-char beg)
-    (while (re-search-forward "^\\(.*\n\\)\\1+" end t)
-      (replace-match "\\1"))))
-
-(provide 'my-buffers)
-;;; my-buffers.el ends here
diff --git a/emacs/elisp/my-git-extra.el b/emacs/elisp/my-git-extra.el
deleted file mode 100644
index 30fff78..0000000
--- a/emacs/elisp/my-git-extra.el
+++ /dev/null
@@ -1,50 +0,0 @@
-;;; my-git-extra.el --- Extra functions to work with git
-;;; Commentary:
-;;; Code:
-
-(require 'magit)
-(require 'git-link)
-
-(defun my/clone-repo (url)
-  "Clone a repository in the workspace using URL."
-  (interactive "sURL:")
-  (let* ((repo-name (magit-clone--url-to-name url))
-         (target-dir (concat  "~/workspace/" repo-name)))
-    (magit-clone-regular url target-dir nil)))
-
-(defun my/sg-instance (hostname)
-  "Return the base URL for a sourcegraph instance based on HOSTNAME."
-  (cond ((string-match "cl\.fcuny\.net" hostname) (format "cs.fcuny.xyz/%s" hostname))
-        (t (format "sourcegraph.rbx.com/%s" hostname))))
-
-(defun my/git-link-sourcegraph (hostname dirname filename _branch commit start end)
-  "Create a link to sourcegraph given a HOSTNAME DIRNAME FILENAME _BRANCH COMMIT START and END."
-  (let ((sg-base-url (my/sg-instance hostname))
-        ;; Use the default branch of the repository instead of the
-        ;; current one (we might be on a feature branch that is not
-        ;; available on the remote).
-        (main-branch (magit-main-branch))
-        ;; repositories cloned with gerrit have a "a/" prefix which we
-        ;; need to remove, as it's not part of the repository name in
-        ;; sourcegraph.
-        (dirname (replace-regexp-in-string "a\/" "" dirname)))
-    (git-link-sourcegraph sg-base-url dirname filename main-branch commit start end)))
-
-(defun my/git-link-commit-sourcegraph (hostname dirname commit)
-  "Create the link to sourcegraph given a HOSTNAME DIRNAME and COMMIT."
-  (let ((sg-base-url (my/sg-instance hostname))
-        (dirname (replace-regexp-in-string "a\/" "" dirname)))
-    (git-link-commit-sourcegraph sg-base-url dirname commit)))
-
-;; for work related repositories, open them in our instance of sourcegraph
-(add-to-list 'git-link-remote-alist '("github\\.rbx\\.com" my/git-link-sourcegraph))
-(add-to-list 'git-link-commit-remote-alist '("github\\.rbx\\.com" my/git-link-work-sourcegraph))
-
-;; for personal code I use cgit and gerrit
-(add-to-list 'git-link-remote-alist '("git\\.fcuny\\.net" my/git-link-sourcegraph))
-(add-to-list 'git-link-remote-alist '("cl\\.fcuny\\.net" my/git-link-sourcegraph))
-(add-to-list 'git-link-commit-remote-alist '("git\\.fcuny\\.net" my/git-link-commit-sourcegraph))
-(add-to-list 'git-link-commit-remote-alist '("cl\\.fcuny\\.net" my/git-link-commit-sourcegraph))
-
-(provide 'my-git-extra)
-;;; my-git-extra.el ends here
diff --git a/emacs/elisp/my-packages-extra.el b/emacs/elisp/my-packages-extra.el
deleted file mode 100644
index de37752..0000000
--- a/emacs/elisp/my-packages-extra.el
+++ /dev/null
@@ -1,65 +0,0 @@
-;;; my-packages-extra.el --- Provides additional functions related to
-;;; packages
-
-;;; Commentary:
-
-;;; Code:
-
-(require 'package)
-
-;; Original idea: https://www.manueluberti.eu/emacs/2021/09/01/package-report/
-(defun my/package-report ()
-  "Report total package counts grouped by archive."
-  (interactive)
-  (package-refresh-contents)
-  (my/display-package-report
-   (let* ((arch-pkgs (my/archive-packages))
-          (counts (seq-sort-by #'cdr #'> (my/archive-counts arch-pkgs)))
-          (by-arch (seq-group-by #'car arch-pkgs)))
-     (concat
-      (format "Total packages: %s\n\n" (apply #'+ (mapcar #'cdr counts)))
-      (mapconcat
-       (lambda (archive)
-         (concat "• "
-                 (format "%s (%s)" (car archive) (cdr archive))
-                 ": "
-                 (mapconcat (lambda (ap-pair) (cdr ap-pair))
-                            (alist-get (car archive) by-arch)
-                            ", ")))
-       counts
-       "\n\n")))))
-
-(defun my/display-package-report (output)
-  "Display OUTPUT in a popup buffer."
-  (let ((buffer-name "*package-report*"))
-    (with-help-window buffer-name
-      (with-current-buffer buffer-name
-        (visual-line-mode 1)
-        (erase-buffer)
-        (insert output)
-        (goto-char (point-min))))))
-
-(defun my/archive-packages ()
-  "Return a list of (archive . package) cons cells."
-  (seq-reduce
-   (lambda (res package)
-     (let ((archive (package-desc-archive
-                     (cadr (assq package package-archive-contents))))
-           (pkg (symbol-name package)))
-       (push (cons archive pkg) res)))
-   (mapcar #'car package-alist)
-   nil))
-
-(defun my/archive-counts (arch-pkgs)
-  "Return a list of cons cells from alist ARCH-PKGS.
-The cars are package archives, the cdrs are the number of
-packages installed from each archive."
-  (seq-reduce
-   (lambda (counts key)
-     (cons (cons key (+ 1 (or (cdr (assoc key counts)) 0)))
-           (assoc-delete-all key counts)))
-   (mapcar #'car arch-pkgs)
-   nil))
-
-(provide 'my-packages-extra)
-;;; my-packages-extra.el ends here
diff --git a/emacs/elisp/my-strings.el b/emacs/elisp/my-strings.el
deleted file mode 100644
index 40ad888..0000000
--- a/emacs/elisp/my-strings.el
+++ /dev/null
@@ -1,23 +0,0 @@
-;;; my-strings.el --- Functions related to strings manipulation
-;;; Commentary:
-;;; Code:
-
-(defun my/remove-sql-columns ()
-  "Remove \"|\" from strings.
-This is useful when I want to drop the column separator from some
-text coming from a mysql query."
-  (interactive)
-  (while (search-forward-regexp "\s?|\s?")
-    (replace-match " ")))
-
-;; from https://karl-voit.at/2014/08/10/bookmarks-with-orgmode/
-(defun my/string-replace (this withthat in)
-  "Replace THIS with WITHTHAT' in the string IN."
-  (with-temp-buffer
-    (insert in)
-    (goto-char (point-min))
-    (replace-string this withthat)
-    (buffer-substring (point-min) (point-max))))
-
-(provide 'my-strings)
-;;; my-strings.el ends here
diff --git a/emacs/elisp/my-web.el b/emacs/elisp/my-web.el
deleted file mode 100644
index 4e86790..0000000
--- a/emacs/elisp/my-web.el
+++ /dev/null
@@ -1,32 +0,0 @@
-;;; my-web.el --- Functions related to web interactions
-;;; Commentary:
-;;; Code:
-
-(require 'my-strings)
-
-(defun my/get-page-title (url)
-  "Make URL into an 'org-mode' link."
-  (let ((title))
-    (with-current-buffer (url-retrieve-synchronously url)
-      (goto-char (point-min))
-      (re-search-forward "<title>\\([^<]*\\)</title>" nil t 1)
-      (setq title (match-string 1))
-      (goto-char (point-min))
-      (re-search-forward "charset=\\([-0-9a-zA-Z]*\\)" nil t 1)
-      (my/string-replace "&nbsp;" " "
-                         (decode-coding-string title 'utf-8))
-      (concat "[[" url "][" title "]]"))))
-
-(defun my/github-code-search ()
-  "Search code on github for a given language."
-  (interactive)
-  (let ((language (completing-read
-                   "Language: "
-                   '("Emacs Lisp" "Python"  "Go" "Nix")))
-        (code (read-string "Code: ")))
-    (browse-url
-     (concat "https://github.com/search?l=" language
-             "&type=code&q=" code))))
-
-(provide 'my-web)
-;;; my-web.el ends here
diff --git a/emacs/elisp/my-work.el b/emacs/elisp/my-work.el
deleted file mode 100644
index f0c59d8..0000000
--- a/emacs/elisp/my-work.el
+++ /dev/null
@@ -1,21 +0,0 @@
-;;; my-work.el --- Functions related to work
-;;; Commentary:
-;;; Code:
-
-(defun my/check-work-machine-p ()
-  "Return t if this is a work machine."
-  (string-match "HQ\\.*" (system-name)))
-
-(defun my/work-code-search ()
-  "Search code on sourcegraph for a given language."
-  (interactive)
-  (let ((language (completing-read
-                   "Language: "
-                   '("Ruby" "Python"  "Go")))
-        (code (read-string "Code: ")))
-    (browse-url
-     (concat "https://sourcegraph.rbx.com/search?q=context:global+lang:" language
-             "+" code))))
-
-(provide 'my-work)
-;;; my-work.el ends here
diff --git a/emacs/init.el b/emacs/init.el
deleted file mode 100644
index 3a24cdc..0000000
--- a/emacs/init.el
+++ /dev/null
@@ -1,62 +0,0 @@
-;;; init.el --- Initialize my Emacs configuration
-;;; Commentary:
-
-;;; Code:
-
-;; store all the customizations into that file. if the file does not
-;; exists, we create an empty file, and then we load it.
-(setq custom-file (expand-file-name "var/custom.el" user-emacs-directory))
-(when (not (file-exists-p custom-file))
-  (write-region "" nil custom-file))
-(load custom-file)
-
-(invert-face 'default)
-
-(setq gc-cons-threshold 64000000)
-
-;; configure straight to manage packages
-
-(add-to-list 'load-path (expand-file-name "custom/" user-emacs-directory))
-(add-to-list 'load-path (expand-file-name "elisp/" user-emacs-directory))
-
-;; run package installation
-(require 'my-packages)
-(my/install-packages)
-
-(require 'envrc)
-(envrc-global-mode)
-
-(require 'my-settings)
-(require 'my-ui)
-(require 'my-dired)
-(require 'my-navigation)
-(require 'my-completion)
-(require 'my-edit)
-(require 'my-text)
-(require 'my-git)
-(require 'my-org)
-(require 'my-eshell)
-(require 'my-tramp)
-(require 'my-elfeed)
-
-(require 'my-flymake)
-(require 'my-eldoc)
-(require 'my-conf)
-(require 'my-prog)
-(require 'my-tree-sitter)
-(require 'my-lsp)
-(require 'my-lang-go)
-(require 'my-lang-nix)
-(require 'my-lang-python)
-(require 'my-lang-rust)
-
-(require 'my-buffers)
-(require 'my-git-extra)
-(require 'my-strings)
-(require 'my-web)
-(require 'my-work)
-(require 'my-uptime)
-(require 'my-cheeseboard)
-(require 'my-packages-extra)
-
-;;; init.el ends here
diff --git a/emacs/etc/elfeed.org b/etc/elfeed.org
index a26b225..0d1e173 100644
--- a/emacs/etc/elfeed.org
+++ b/etc/elfeed.org
@@ -1,35 +1,37 @@
 #+TITLE: list of feeds
 
-* Tools/Languages                                               :elfeed:tech:
-** entry-title: \(security\)                             :security:mustread:
+
+* Tools/Languages                                                                   :elfeed:tech:
+** entry-title: \(security\)                                                 :security:mustread:
 ** https://git.github.io/feed.xml
-* Bay Area                                                   :elfeed:bayarea:
+* Bay Area                                                                       :elfeed:bayarea:
 ** https://48hills.org/feed/
 ** https://oaklandside.org/feed/
 ** https://www.berkeleyside.com/feed
 ** https://www.indybay.org/syn/generate_rss.php?include_posts=0&include_blurbs=1
-* Music                                                        :elfeed:music:
+* Music                                                                            :elfeed:music:
 ** https://southernlord.com/feed/
 ** [[https://www.theredhandfiles.com/feed/]]
-* Gaming                                                       :elfeed:games:
+* Gaming                                                                           :elfeed:games:
 ** https://www.rockpapershotgun.com/rss
-* Bike                                                          :elfeed:bike:
+* Bike                                                                              :elfeed:bike:
 ** https://somafab.blogspot.com/feeds/posts/default
 ** https://bluelug.com/blog/feed/
 ** https://theradavist.com/feed/
 ** https://droppedchain.com/feed/
-* Aggregator                                                    :elfeed:news:
-** entry-title: \(security\)                             :security:mustread:
+* Aggregator                                                                        :elfeed:news:
+** entry-title: \(security\)                                                 :security:mustread:
 ** https://lwn.net/headlines/rss
-** entry-title: \(emacs\|org-mode\)                                  :emacs:
+** entry-title: \(emacs\|org-mode\)                                                      :emacs:
 ** https://lobste.rs/rss
-* Blogs                                                         :elfeed:blog:
-** entry-title: \(emacs\|org-mode\)                                  :emacs:
-** entry-title: \(security\)                             :security:mustread:
-** https://0pointer.net/blog/index.rss20                          :mustread:
+* Blogs                                                                             :elfeed:blog:
+** entry-title: \(emacs\|org-mode\)                                                      :emacs:
+** entry-title: \(security\)                                                 :security:mustread:
+** https://0pointer.net/blog/index.rss20                                              :mustread:
+** https://pyfound.blogspot.com/feeds/posts/default                                     :python:
 ** https://adamsimpson.net/rss.xml
 ** https://almad.blog/index.xml
-** https://apenwarr.ca/log/rss.php                                :mustread:
+** https://apenwarr.ca/log/rss.php                                                    :mustread:
 ** https://blog.benjojo.co.uk/rss.xml
 ** https://blog.filippo.io/rss/
 ** https://latacora.micro.blog/feed.xml
@@ -37,14 +39,14 @@
 ** https://blog.nelhage.com/atom.xml
 ** https://blog.separateconcerns.com/feed.atom
 ** https://brandur.org/articles.atom
-** https://brooker.co.za/blog/rss.xml                             :mustread:
+** https://brooker.co.za/blog/rss.xml                                                 :mustread:
 ** https://bzg.fr/index.xml
 ** https://chrisdown.name/feed.xml
 ** https://christiantietze.de/feed.atom
 ** https://commaok.xyz/index.xml
 ** https://container42.com/atom.xml
 ** https://crawshaw.io/atom.xml
-** https://danluu.com/atom.xml                                    :mustread:
+** https://danluu.com/atom.xml                                                        :mustread:
 ** https://danwang.co/feed/
 ** https://eli.thegreenplace.net/feeds/all.atom.xml
 ** https://emacsredux.com/atom.xml
@@ -83,11 +85,11 @@
 ** https://venam.nixers.net/blog/feed.xml
 ** https://vincent.bernat.ch/en/blog/atom.xml
 ** https://with-emacs.com/rss.xml
-** https://www.brendangregg.com/blog/rss.xml                      :mustread:
+** https://www.brendangregg.com/blog/rss.xml                                          :mustread:
 ** https://www.hillelwayne.com/index.xml
 ** https://www.masteringemacs.org/feed/
 ** https://www.tbray.org/ongoing/ongoing.atom
 ** https://jack.wrenn.fyi/atom.xml
 ** https://www.tweag.io/rss.xml
-* Reddit                                                      :elfeed:reddit:
-* Mastodon                                                  :elfeed:mastodon:
+* Reddit                                                                          :elfeed:reddit:
+* Mastodon                                                                      :elfeed:mastodon:
diff --git a/emacs/etc/interview.org b/etc/interview.org
index dfb24b1..dfb24b1 100644
--- a/emacs/etc/interview.org
+++ b/etc/interview.org
diff --git a/emacs/etc/new-project.org b/etc/new-project.org
index 3d17d55..3d17d55 100644
--- a/emacs/etc/new-project.org
+++ b/etc/new-project.org
diff --git a/emacs/etc/weekly_review.org b/etc/weekly_review.org
index a7d2581..a7d2581 100644
--- a/emacs/etc/weekly_review.org
+++ b/etc/weekly_review.org
diff --git a/init.org b/init.org
new file mode 100644
index 0000000..5479713
--- /dev/null
+++ b/init.org
@@ -0,0 +1,2069 @@
+#+TITLE: my Emacs configuration
+#+AUTHOR: Franck Cuny
+#+PROPERTY: header-args :tangle-mode o444 :results silent :tangle ~/.config/emacs/init.el
+#+STARTUP: overview indent
+#+AUTO_TANGLE: t
+
+To use this file, run =org-tangle= (or =C-c C-v C-t=).
+
+To exclude specific source blocks from being tangled add =:tangle no= to the header.
+
+* Startup
+** early initialization
+:PROPERTIES:
+:header-args: :tangle-mode o444 :results silent :tangle ~/.config/emacs/early-init.el
+:END:
+
+Using an =early-init.el= file can speedup loading emacs. This is only available after emacs version 27.
+
+#+begin_src emacs-lisp :lexical t
+;;; early-init.el --- Early initialization -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+
+;; disable GUI elements
+(scroll-bar-mode -1)      ; hide the scroll bar
+(tool-bar-mode -1)        ; hide the tool bar
+(menu-bar-mode -1)        ; hide the menu
+(blink-cursor-mode -1)    ; don't blink the cursor
+
+(setq make-pointer-invisible t)  ;; hide cursor while typing
+(setq use-dialog-box nil)        ;; do not show GUI dialogs
+(setq use-file-dialog nil)
+(setq inhibit-startup-screen t)  ;; hide the startup screen
+
+;; don't report warnings and errors related to native compilation
+(setq native-comp-async-report-warnings-errors nil)
+
+;; increase font size
+(set-face-attribute 'default nil :height 130)
+
+;;; early-init.el ends here
+#+end_src
+
+** set headers
+
+#+begin_src emacs-lisp :epilogue (format-time-string ";; Last generated on %c")
+;;; init.el --- This is where all emacs start. -*- lexical-binding: t -*-
+
+;;; Commentary:
+
+;;; Code:
+#+end_src
+
+** garbage collection
+Set the garbage collection threshold.
+
+#+begin_src emacs-lisp
+(setq gc-cons-percentage 0.5
+      gc-cons-threshold (* 128 1024 1024))
+#+end_src
+
+** report time
+
+While I don't restart emacs that often, it's still useful to know how much time was spend loading the modules.
+
+#+begin_src emacs-lisp
+(defconst emacs-start-time (current-time))
+
+(defun report-time-since-load (&optional suffix)
+  (message "Loading init...done (%.3fs)%s"
+	   (float-time (time-subtract (current-time) emacs-start-time))
+	   suffix))
+
+(add-hook 'after-init-hook
+	  #'(lambda () (report-time-since-load " [after-init]"))
+	  t)
+#+end_src
+
+** generic configuration
+
+#+begin_src emacs-lisp
+(fset 'yes-or-no-p 'y-or-n-p)          ; replace yes/no prompts with y/n
+
+;; set utf-8 as the default encoding
+(prefer-coding-system 'utf-8-unix)
+(setq locale-coding-system 'utf-8)
+(set-language-environment 'utf-8)
+(set-terminal-coding-system 'utf-8)
+(set-keyboard-coding-system 'utf-8)
+#+end_src
+
+** load =use-package=
+
+Add MELPA and NonGNU ELPA repositories.
+
+#+begin_src emacs-lisp
+(setq load-prefer-newer t)
+(setq init-file-debug t)
+
+(package-initialize)
+
+(setq package-archives (append
+                        package-archives
+                        '(("melpa" . "https://melpa.org/packages/")
+                          ("elpa" . "https://elpa.nongnu.org/nongnu/"))))
+#+end_src
+
+Then we load =use-package=.
+
+#+begin_src emacs-lisp
+(eval-and-compile
+  (defsubst emacs-path (path)
+    (expand-file-name path user-emacs-directory))
+
+  (setq package-enable-at-startup nil
+	load-path
+	(append (list (emacs-path "use-package"))
+		(delete-dups load-path)
+		(list (emacs-path "lisp")))))
+
+(require 'use-package)
+
+(setq use-package-verbose init-file-debug
+      use-package-expand-minimally (not init-file-debug)
+      use-package-compute-statistics nil
+      debug-on-error init-file-debug)
+#+end_src
+
+*** diminish
+
+Since =use-package= no longer requires =diminish= as a dependency (see [[https://github.com/jwiegley/use-package/blob/a6e856418d2ebd053b34e0ab2fda328abeba731c/NEWS.md?plain=1#LL103C3-L103C62][changelog]]), we need to require it before other packages.
+
+#+begin_src emacs-lisp
+(use-package diminish :ensure t)
+#+end_src
+
+** define data environment
+
+#+begin_src emacs-lisp
+(defconst user-data-directory
+  (emacs-path "data"))
+
+(defun user-data (dir)
+  (expand-file-name dir user-data-directory))
+
+(setq custom-file (user-data "customizations.el"))
+(load custom-file 'noerror)
+#+end_src
+
+* Helper functions
+
+** Push and pop window configurations
+
+#+begin_src emacs-lisp
+(defvar saved-window-configuration nil)
+
+(defun push-window-configuration ()
+  (interactive)
+  (push (current-window-configuration) saved-window-configuration))
+
+(defun pop-window-configuration ()
+  (interactive)
+  (let ((config (pop saved-window-configuration)))
+    (if config
+        (set-window-configuration config)
+      (if (> (length (window-list)) 1)
+          (delete-window)
+        (bury-buffer)))))
+#+end_src
+
+** Rename the current buffer
+
+#+begin_src emacs-lisp
+(defun my/rename-this-buffer-and-file ()
+  "Renames current buffer and file it is visiting."
+  (interactive)
+  (let ((name (buffer-name))
+        (filename (buffer-file-name))
+        (read-file-name-function 'read-file-name-default))
+    (if (not (and filename (file-exists-p filename)))
+        (error "Buffer '%s' is not visiting a file!" name)
+      (let ((new-name (read-file-name "New name: " filename)))
+        (cond ((get-buffer new-name)
+               (error "A buffer named '%s' already exists!" new-name))
+              (t
+               (rename-file filename new-name 1)
+               (rename-buffer new-name)
+               (set-visited-file-name new-name)
+               (set-buffer-modified-p nil)
+               (message "File '%s' successfully renamed to '%s'" name (file-name-nondirectory new-name))))))))
+#+end_src
+
+** Is this my work issued machine
+
+#+begin_src emacs-lisp
+(defun my/check-work-machine-p ()
+  "Return t if this is a work machine."
+  (string-match "HQ\\.*" (system-name)))
+#+end_src
+
+** GitHub's code search
+
+#+begin_src emacs-lisp
+(defun my/github-code-search ()
+  "Search code on github for a given language."
+  (interactive)
+  (let ((language (completing-read
+                   "Language: "
+                   '("Emacs Lisp" "Python"  "Go" "Nix")))
+        (code (read-string "Code: ")))
+    (browse-url
+     (concat "https://github.com/search?lang=" language
+             "&type=code&q=" code))))
+#+end_src
+
+** Search work's repositories
+
+#+begin_src emacs-lisp
+(defun my/work-code-search ()
+  "Search code on sourcegraph for a given language."
+  (interactive)
+  (let ((language (completing-read
+                   "Language: "
+                   '("Ruby" "Python"  "Go")))
+        (code (read-string "Code: ")))
+    (browse-url
+     (concat "https://sourcegraph.rbx.com/search?q=context:global+lang:" language
+             "+" code))))
+#+end_src
+
+* Packages
+** abbrev
+
+If you want 'btw' to expand to 'by the way', type 'btw' followed by =C-x a i g=. The =g= is flow global, and you can define abbreviations per mode.
+
+| keys      | action                                           |
+|-----------+--------------------------------------------------|
+| =C-x a i g= | add a new abbreviation for all modes             |
+| =C-x a i l= | add a new abbreviation local to the current mode |
+
+#+begin_src emacs-lisp
+(use-package abbrev
+  :diminish
+  :hook
+  ((text-mode prog-mode) . abbrev-mode)
+  :custom
+  (abbrev-file-name (emacs-path "abbrevs.el"))
+  ;; save abbrevs when files are saved
+  (save-abbrevs 'silently)
+  :config
+  (if (file-exists-p abbrev-file-name)
+      (quietly-read-abbrev-file)))
+#+end_src
+
+** autorevert
+
+Automatically revert buffers if the file has changed on disk.
+
+#+begin_src emacs-lisp
+(use-package autorevert
+  :custom
+  (auto-revert-use-notify nil)
+  :config
+  (global-auto-revert-mode t))
+#+end_src
+
+** bookmark
+
+| keys    | action                             |
+|---------+------------------------------------|
+| =C-x r m= | add a new bookmark                 |
+| =C-x r l= | list all the bookmarks in a buffer |
+| =C-x r b= | list the bookmarks with consul     |
+
+#+begin_src emacs-lisp
+(use-package bookmark
+  :defer t
+  :custom
+  (bookmark-default-file (user-data "bookmarks")))
+#+end_src
+
+** compile
+
+#+begin_src emacs-lisp
+(use-package compile
+  :bind (:map compilation-mode-map
+              ("z" . delete-window))
+  :custom
+  (compilation-always-kill t)
+  ;; Don't freeze when process reads from stdin
+  (compilation-disable-input t)
+  (compilation-ask-about-save nil)
+  (compilation-context-lines 10)
+  (compilation-scroll-output 'first-error)
+  (compilation-skip-threshold 2)
+  (compilation-window-height 100))
+#+end_src
+
+** completions
+*** consult
+
+#+begin_src emacs-lisp
+(use-package consult
+  :ensure t
+  :bind (("C-c m"   . consult-mode-command)
+	 ("M-g o"   . consult-org-heading)
+	 ("C-x b"   . consult-buffer)
+	 ("C-x 5 b" . consult-buffer-other-frame)
+	 ("C-x r b" . consult-bookmark)
+	 ("C-x p b" . consult-project-buffer)
+	 ("C-c i"   . consult-imenu)
+	 ("M-g e"   . consult-compile-error)
+	 ("M-g g"   . consult-goto-line)
+	 ("M-g M-g" . consult-goto-line)
+	 ("M-g l"   . consult-goto-line)
+	 ("M-g m"   . consult-mark)
+	 ("M-g k"   . consult-global-mark))
+
+  ;; Enable automatic preview at point in the *Completions* buffer. This is
+  ;; relevant when you use the default completion UI.
+  :hook (completion-list-mode . consult-preview-at-point-mode)
+
+  :custom
+  (consult-narrow-key "<")
+
+  :functions
+  (consult-register-format
+   consult-register-window
+   consult-xref)
+
+  :init
+  ;; Optionally configure the register formatting. This improves the register
+  ;; preview for `consult-register', `consult-register-load',
+  ;; `consult-register-store' and the Emacs built-ins.
+  (setq register-preview-delay 0.5
+	register-preview-function #'consult-register-format)
+
+  ;; Optionally tweak the register preview window.
+  ;; This adds thin lines, sorting and hides the mode line of the window.
+  (advice-add #'register-preview :override #'consult-register-window)
+
+  ;; Use Consult to select xref locations with preview
+  (setq xref-show-xrefs-function #'consult-xref
+	xref-show-definitions-function #'consult-xref)
+
+  ;; Configure other variables and modes in the :config section,
+  ;; after lazily loading the package.
+  :config
+  (use-package consult-xref)
+
+  (consult-customize
+   consult-theme
+   :preview-key '(:debounce 0.2 any)
+   consult-ripgrep
+   consult-git-grep
+   consult-grep
+   consult-bookmark
+   consult-recent-file
+   consult-xref
+   consult--source-bookmark
+   consult--source-file-register
+   consult--source-recent-file
+   consult--source-project-recent-file
+   :preview-key '(:debounce 0.4 any)))
+#+end_src
+
+*** corfu
+
+#+begin_src emacs-lisp
+(use-package corfu
+  :ensure t
+  :demand t
+  :bind (("M-/" . completion-at-point)
+	 :map corfu-map
+	 ("C-n"      . corfu-next)
+	 ("C-p"      . corfu-previous)
+	 ("<escape>" . corfu-quit)
+	 ("<return>" . corfu-insert)
+	 ("M-d"      . corfu-info-documentation)
+	 ("M-l"      . corfu-info-location)
+	 ("M-."      . corfu-move-to-minibuffer))
+  :custom
+  ;; Works with `indent-for-tab-command'. Make sure tab doesn't indent when you
+  ;; want to perform completion
+  (tab-always-indent 'complete)
+  (completion-cycle-threshold t)      ; Always show candidates in menu
+
+  (corfu-auto t)
+  (corfu-auto-prefix 2)
+  (corfu-auto-delay 0.25)
+
+  (corfu-min-width 80)
+  (corfu-max-width corfu-min-width)     ; Always have the same width
+  (corfu-count 14)
+  (corfu-scroll-margin 4)
+  (corfu-cycle t)
+
+  ;; `nil' means to ignore `corfu-separator' behavior, that is, use the older
+  ;; `corfu-quit-at-boundary' = nil behavior. Set this to separator if using
+  ;; `corfu-auto' = `t' workflow (in that case, make sure you also set up
+  ;; `corfu-separator' and a keybind for `corfu-insert-separator', which my
+  ;; configuration already has pre-prepared). Necessary for manual corfu usage with
+  ;; orderless, otherwise first component is ignored, unless `corfu-separator'
+  ;; is inserted.
+  (corfu-quit-at-boundary nil)
+  (corfu-separator ?\s)            ; Use space
+  (corfu-quit-no-match 'separator) ; Don't quit if there is `corfu-separator' inserted
+  (corfu-preview-current 'insert)  ; Preview first candidate. Insert on input if only one
+  (corfu-preselect-first t)        ; Preselect first candidate?
+
+  ;; Other
+  (corfu-echo-documentation nil)        ; Already use corfu-popupinfo
+
+  :config
+  (global-corfu-mode))
+#+end_src
+
+**** corfu-popupinfo
+
+#+begin_src emacs-lisp
+(use-package corfu-popupinfo
+  :after corfu
+  :hook (corfu-mode . corfu-popupinfo-mode)
+  :bind (:map corfu-map
+              ("M-n" . corfu-popupinfo-scroll-up)
+              ("M-p" . corfu-popupinfo-scroll-down)
+              ([remap corfu-show-documentation] . corfu-popupinfo-toggle))
+  :custom
+  (corfu-popupinfo-delay 0.5)
+  (corfu-popupinfo-max-width 70)
+  (corfu-popupinfo-max-height 20)
+  ;; Also here to be extra-safe that this is set when `corfu-popupinfo' is
+  ;; loaded. I do not want documentation shown in both the echo area and in
+  ;; the `corfu-popupinfo' popup.
+  (corfu-echo-documentation nil))
+#+end_src
+
+*** cape
+
+#+begin_src emacs-lisp
+(use-package cape
+  :demand t
+  :ensure t
+  :bind (("C-c . p" . completion-at-point)
+	 ("C-c . t" . complete-tag)
+	 ("C-c . d" . cape-dabbrev)
+	 ("C-c . h" . cape-history)
+	 ("C-c . f" . cape-file)
+	 ("C-c . k" . cape-keyword)
+	 ("C-c . s" . cape-symbol)
+	 ("C-c . a" . cape-abbrev)
+	 ("C-c . l" . cape-line)
+	 ("C-c . w" . cape-dict)
+	 ("C-c . \\" . cape-tex)
+	 ("C-c . _" . cape-tex)
+	 ("C-c . ^" . cape-tex)
+	 ("C-c . &" . cape-sgml)
+	 ("C-c . r" . cape-rfc1345))
+  :init
+  ;; Add `completion-at-point-functions', used by `completion-at-point'.
+  (add-to-list 'completion-at-point-functions #'cape-dabbrev)
+  (add-to-list 'completion-at-point-functions #'cape-ispell)
+  (add-to-list 'completion-at-point-functions #'cape-file)
+  (add-to-list 'completion-at-point-functions #'cape-abbrev))
+#+end_src
+
+*** elisp-mode-cape
+
+#+begin_src emacs-lisp
+(use-package elisp-mode-cape
+  :after (cape elisp-mode)
+  :hook (emacs-lisp-mode . my/setup-elisp)
+  :preface
+  (defun my/setup-elisp ()
+    (setq-local completion-at-point-functions
+                `(,(cape-super-capf
+                    #'elisp-completion-at-point
+                    #'cape-dabbrev)
+                  cape-file)
+                cape-dabbrev-min-length 5)))
+#+end_src
+
+*** embark
+
+#+begin_src emacs-lisp
+  (use-package embark
+    :ensure t
+    :bind (("M-."   . embark-act)
+	   ("C-h b" . embark-bindings) ;; alternative for `describe-bindings'
+
+	   :map embark-collect-mode-map
+	   ("C-c C-a" . embark-collect-direct-action-minor-mode))
+    :init
+    ;; Optionally replace the key help with a completing-read interface
+    (setq prefix-help-command #'embark-prefix-help-command)
+
+    ;; Show the Embark target at point via Eldoc.  You may adjust the Eldoc
+    ;; strategy, if you want to see the documentation from multiple providers.
+    (add-hook 'eldoc-documentation-functions #'embark-eldoc-first-target)
+
+    :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)))))
+#+end_src
+
+**** embark-consult
+
+#+begin_src emacs-lisp
+  (use-package embark-consult
+    :ensure t
+    :hook
+    (embark-collect-mode . consult-preview-at-point-mode))
+#+end_src
+
+*** marginalia
+
+
+#+begin_src emacs-lisp
+  (use-package marginalia
+    :ensure t
+    ;; Either bind `marginalia-cycle' globally or only in the minibuffer
+    :bind (("M-A" . marginalia-cycle)
+	   :map minibuffer-local-map
+	   ("M-A" . marginalia-cycle))
+
+    ;; The :init configuration is always executed (Not lazy!)
+    :config
+    ;; 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))
+#+end_src
+
+*** orderless
+
+#+begin_src emacs-lisp
+  (use-package orderless
+    :demand t
+    :ensure t
+    :custom
+    (completion-styles '(orderless basic))
+    (completion-category-defaults nil))
+#+end_src
+
+*** vertico
+
+
+#+begin_src emacs-lisp
+  (use-package vertico
+    :demand t
+    :ensure t
+    :bind (("C-c . ." . vertico-repeat)
+	   :map vertico-map
+	   ("C-j"   . vertico-exit-input)
+	   ("C-M-n" . vertico-next-group)
+	   ("C-M-p" . vertico-previous-group))
+    :hook
+    (minibuffer-setup . vertico-repeat-save)
+    (rfn-eshadow-update-overlay . vertico-directory-tidy)
+    :custom
+    (vertico-count 10)
+    (vertico-resize nil)
+    (vertico-cycle t)
+    :preface
+    (defun crm-indicator (args)
+      (cons (format "[CRM%s] %s"
+		    (replace-regexp-in-string
+		     "\\`\\[.*?]\\*\\|\\[.*?]\\*\\'" ""
+		     crm-separator)
+		    (car args))
+	    (cdr args)))
+    :config
+    (vertico-mode)
+
+    ;; Add prompt indicator to `completing-read-multiple'.
+    ;; We display [CRM<separator>], e.g., [CRM,] if the separator is a comma.
+    (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)
+
+    ;; 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))
+#+end_src
+
+*** yasnippet
+
+#+begin_src emacs-lisp
+  (use-package yasnippet
+    :ensure t
+    :demand t
+    :diminish
+    :commands yas-minor-mode-on
+    :bind (("C-c y d" . yas-load-directory)
+           ("C-c y i" . yas-insert-snippet)
+           ("C-c y f" . yas-visit-snippet-file)
+           ("C-c y n" . yas-new-snippet)
+           ("C-c y t" . yas-tryout-snippet)
+           ("C-c y l" . yas-describe-tables)
+           ("C-c y g" . yas-global-mode)
+           ("C-c y m" . yas-minor-mode)
+           ("C-c y r" . yas-reload-all)
+           ("C-c y x" . yas-expand)
+           :map yas-keymap
+           ("C-i" . yas-next-field-or-maybe-expand))
+    :mode ("/emacs\\.d/snippets/" . snippet-mode)
+    :hook (prog-mode . yas-minor-mode-on)
+    :custom
+    (yas-prompt-functions '(yas-completing-prompt yas-no-prompt))
+    (yas-snippet-dirs (list (emacs-path "snippets")))
+    (yas-triggers-in-field t)
+    (yas-wrap-around-region t)
+    :config
+    (yas-load-directory (emacs-path "snippets")))
+#+end_src
+
+** dired
+
+#+begin_src emacs-lisp
+(use-package dired
+  :diminish
+  :bind (:map dired-mode-map
+              ("j"     . dired)
+              ("z"     . pop-window-configuration)
+              ("^"     . dired-up-directory)
+              ("q"     . pop-window-configuration)
+              ("M-!"   . shell-command)
+              ("<tab>" . dired-next-window))
+  :custom
+  (dired-clean-up-buffers-too nil)
+  (dired-dwim-target t)
+  (dired-hide-details-hide-information-lines nil)
+  (dired-hide-details-hide-symlink-targets nil)
+  (dired-listing-switches "-lah")
+  (dired-no-confirm
+   '(byte-compile chgrp chmod chown copy hardlink symlink touch))
+  (dired-omit-mode nil t)
+  (dired-omit-size-limit 60000)
+  (dired-recursive-copies 'always)
+  (dired-recursive-deletes 'always)
+  :functions (dired-dwim-target-directory))
+#+end_src
+
+** direnv
+Invokes [[https://direnv.net/][direnv]] to obtain environment for the current file.
+
+#+begin_src emacs-lisp
+  (use-package direnv
+    :ensure t
+    :custom
+    (direnv-always-show-summary nil)
+    :config
+    (direnv-mode))
+#+end_src
+
+** docker
+
+#+begin_src emacs-lisp
+(use-package docker
+  :bind ("C-c d" . docker)
+  :diminish
+  :init
+  (use-package docker-image   :commands docker-images)
+  (use-package docker-volume  :commands docker-volumes)
+  (use-package docker-network :commands docker-containers)
+  (use-package docker-compose :commands docker-compose)
+
+  (use-package docker-container
+    :commands docker-containers
+    :custom
+    (docker-containers-shell-file-name "/bin/bash")
+    (docker-containers-show-all nil)))
+#+end_src
+
+*** docker-compose-mode
+
+#+begin_src emacs-lisp
+(use-package docker-compose-mode
+  :mode "docker-compose.*\.yml\\'")
+#+end_src
+
+*** dockerfile-mode
+
+#+begin_src emacs-lisp
+(use-package dockerfile-mode
+  :mode "Dockerfile[a-zA-Z.-]*\\'")
+#+end_src
+
+** elfeed
+
+#+begin_src emacs-lisp
+(use-package elfeed
+  :ensure t
+  :custom
+  (elfeed-db-directory (user-data "elfeed/"))
+  (elfeed-search-filter "@2-weeks-ago +unread")
+  (elfeed-show-entry-switch 'pop-to-buffer)
+  (elfeed-show-entry-delete 'delete-window))
+
+(defface elfeed-face-tag-mustread
+  '((t :foreground "#f00"))
+  "This is a custom font face for the `mustread' tag in Elfeed."
+  :group 'elfeed)
+
+(push '(mustread elfeed-face-tag-mustread) elfeed-search-face-alist)
+#+end_src
+
+*** elfeed-org
+
+#+begin_src emacs-lisp
+(use-package elfeed-org
+  :ensure t
+  :init
+  (setq rmh-elfeed-org-files (list (expand-file-name "etc/elfeed.org" user-emacs-directory)))
+  :config (elfeed-org))
+#+end_src
+
+** emacs
+
+#+begin_src emacs-lisp
+  (use-package emacs
+    :bind* ("M-j" . join-line)
+
+    :custom-face
+    (cursor ((t (:background "hotpink"))))
+    ;; (highlight ((t (:background "blue4"))))
+    ;; (minibuffer-prompt ((t (:foreground "grey80"))))
+    ;; (mode-line-inactive ((t (:background "grey50"))))
+    (nobreak-space ((t nil)))
+
+    :custom
+    (auto-save-default nil)                     ;; don't auto save files
+    (auto-save-list-file-prefix nil)            ;; no backups
+    (create-lockfiles nil)                      ;; don't use a lock file
+    (confirm-kill-emacs #'yes-or-no-p)          ;; ask before killing emacs
+    (make-backup-files nil)                     ;; really no backups
+    (minibuffer-message-timeout 0.5)            ;; How long to display an echo-area message
+    (next-screen-context-lines 5)               ;; scroll 5 lines at a time
+    (require-final-newline t)                   ;; ensure newline exists at the end of the file
+    (ring-bell-function 'ignore)                ;; really no bell
+    (tab-always-indent 'complete)               ;; when using TAB, always indent
+    (visible-bell nil)                          ;; no bell
+    (column-number-mode t)                      ;; show column number in the mode line
+    (electric-pair-mode 1)                      ;; matches parens and brackets
+    (indent-tabs-mode nil)                      ;; turn off tab indentation
+    (cursor-type 'box)                          ;; cursor is a horizontal bar
+    (delete-by-moving-to-trash t)               ;; delete files by moving them to the trash
+    (initial-scratch-message "")                ;; empty scratch buffer
+    (garbage-collection-messages t)             ;; log when the gc kicks in
+
+    ;; bytecomp.el
+    (byte-compile-verbose nil)
+
+    ;; prog-mode.el
+    (prettify-symbols-unprettify-at-point 'right-edge)
+
+    ;; startup.el
+    (auto-save-list-file-prefix (user-data "auto-save-list/.saves-"))
+    (initial-buffer-choice t)
+    (initial-major-mode 'fundamental-mode)
+    (initial-scratch-message "")
+
+    (user-full-name "Franck Cuny")
+    (user-mail-address "franck@fcuny.net")
+    (add-log-mailing-address "franck@fcuny.net")
+
+    (history-length 200)
+    (history-delete-duplicates t)
+    (completion-ignored-extensions
+     '(".class"
+       ".cp"
+       ".elc"
+       ".fmt"
+       ".git/"
+       ".pyc"
+       ".so"
+       "~"))
+
+    ;; paragraphs.el
+    (sentence-end-double-space nil)
+
+    ;; switch to view-mode whenever you are in a read-only buffer (e.g.
+    ;; switched to it using C-x C-q).
+    (view-read-only t)
+
+    ;; window.el
+    (switch-to-buffer-preserve-window-point t)
+
+    ;; warnings.el
+    (warning-minimum-log-level :error)
+
+    ;; frame.el
+    (window-divider-default-bottom-width 1)
+    (window-divider-default-places 'bottom-only)
+
+    ;; paren.el
+    (show-paren-delay 0)
+    (show-paren-highlight-openparen t)
+    (show-paren-when-point-inside-paren t)
+    (show-paren-when-point-in-periphery t)
+
+    :config
+    (add-hook 'after-save-hook
+              #'executable-make-buffer-file-executable-if-script-p))
+#+end_src
+
+** eshell
+#+begin_src emacs-lisp
+(use-package eshell
+  :commands (eshell eshell-command)
+  :custom
+  (eshell-directory-name (emacs-path "eshell"))
+  (eshell-hist-ignoredups t)
+  (eshell-history-size 50000)
+  (eshell-ls-dired-initial-args '("-h"))
+  (eshell-ls-exclude-regexp "~\\'")
+  (eshell-ls-initial-args "-h")
+  (eshell-modules-list
+   '(eshell-alias
+     eshell-basic
+     eshell-cmpl
+     eshell-dirs
+     eshell-glob
+     eshell-hist
+     eshell-ls
+     eshell-pred
+     eshell-prompt
+     eshell-rebind
+     eshell-script
+     eshell-term
+     eshell-unix
+     eshell-xtra))
+  (eshell-prompt-function
+   (lambda nil
+     (concat (abbreviate-file-name (eshell/pwd))
+             (if (= (user-uid) 0)
+                 " # " " $ "))))
+  (eshell-save-history-on-exit t)
+  (eshell-stringify-t nil)
+  (eshell-term-name "ansi")
+
+  :preface
+  (defun eshell-initialize ()
+    (add-hook 'eshell-expand-input-functions #'eshell-spawn-external-command)
+
+  :init
+  (add-hook 'eshell-first-time-mode-hook #'eshell-initialize)))
+#+end_src
+
+** flymake
+
+#+begin_src emacs-lisp
+(use-package flymake
+  :bind (("C-c ! n" . flymake-goto-next-error)
+         ("C-c ! p" . flymake-goto-next-error))
+  :custom
+  (flymake-start-on-save-buffer t)
+  (flymake-fringe-indicator-position 'left-fringe)
+  (flymake-suppress-zero-counters t)
+  (flymake-start-on-flymake-mode t)
+  (flymake-no-changes-timeout nil)
+  (flymake-proc-compilation-prevents-syntax-check t)
+  (flymake-wrap-around nil)
+  (elisp-flymake-byte-compile-load-path load-path))
+#+end_src
+
+** font
+Somehow I need to set the font to a higher height on MacOS.
+
+#+BEGIN_SRC emacs-lisp
+(set-face-attribute 'default nil
+                    :family "JetBrains Mono"
+                    :height 130)
+
+(set-face-attribute 'fixed-pitch nil
+                    :family "JetBrain Mono"
+                    :height 130)
+
+(set-face-attribute 'variable-pitch nil
+                    :family "Roboto"
+                    :height 130)
+
+(use-package default-text-scale
+  :bind
+  (("C-)" . default-text-scale-reset)
+   ("C-=" . default-text-scale-increase)
+   ("C--" . default-text-scale-decrease)))
+#+END_SRC
+
+** fringe
+
+#+begin_src emacs-lisp
+(use-package fringe
+  :config
+  ;;; no fringe on the right side
+  (set-fringe-mode '(8 . 0)))
+#+end_src
+
+** git-link
+
+A convenient package to create link to a code location in GitHub, or other forges. This is very useful to get a link and share with others when looking at some code.
+
+#+begin_src emacs-lisp
+  (use-package git-link
+    :defines git-link-remote-alist
+    :ensure t
+    :bind ("C-c Y" . git-link)
+    :commands (git-link git-link-commit git-link-homepage)
+
+    :custom
+    (git-link-open-in-browser t)
+
+    :preface
+    (defun git-link-fcuny-net (hostname dirname filename branch commit start end)
+      (format "http://git.fcuny.net/%s/tree/%s?id=%s#n%s"
+              (replace-regexp-in-string "^r/\\(.*\\)" "\\1.git" dirname)
+              filename
+              commit
+              start))
+
+    (defun git-link-commit-fcuny-net (hostname dirname commit)
+      (format "http://git.fcuny.net/%s/commit/?id=%s"
+              (replace-regexp-in-string "^r/\\(.*\\)" "\\1.git" dirname)
+              commit))
+
+    :config
+    (add-to-list 'git-link-remote-alist '("git\\.fcuny\\.net" git-link-fcuny-net))
+    (add-to-list 'git-link-commit-remote-alist '("git\\.fcuny\\.net" git-link-commit-fcuny-net))
+
+    ;; sets up roblox git enterprise as a git-link handler
+    (add-to-list 'git-link-remote-alist '("github\\.rblx\\.com" git-link-github))
+    (add-to-list 'git-link-commit-remote-alist '("github\\.rblx\\.com" git-link-commit-github)))
+#+end_src
+
+** ibuffer
+
+#+begin_src emacs-lisp
+(use-package ibuffer
+  :bind ("C-x C-b" . ibuffer)
+  :custom
+  (ibuffer-default-display-maybe-show-predicates t)
+  (ibuffer-expert t)
+  (ibuffer-formats
+   '((mark modified read-only " "
+           (name 16 -1)
+           " "
+           (size 6 -1 :right)
+           " "
+           (mode 16 16)
+           " " filename)
+     (mark " "
+           (name 16 -1)
+           " " filename)))
+  (ibuffer-maybe-show-regexps nil)
+  (ibuffer-saved-filter-groups
+   '(("default"
+      ("Magit"
+       (or
+        (mode . magit-status-mode)
+        (mode . magit-log-mode)
+        (name . "\\*magit")
+        (name . "magit-")
+        (name . "git-monitor")))
+      ("Commands"
+       (or
+        (mode . shell-mode)
+        (mode . eshell-mode)
+        (mode . term-mode)
+        (mode . compilation-mode)))
+      ("Rust"
+       (or
+        (mode . rust-mode)
+        (mode . cargo-mode)
+        (name . "\\*Cargo")
+        (name . "^\\*rls\\(::stderr\\)?\\*")
+        (name . "eglot")))
+      ("Nix"
+       (mode . nix-mode))
+      ("Lisp"
+       (mode . emacs-lisp-mode))
+      ("Dired"
+       (mode . dired-mode))
+      ("Org"
+       (or
+        (name . "^\\*Calendar\\*$")
+        (name . "^\\*Org Agenda")
+        (name . "^ \\*Agenda")
+        (name . "^diary$")
+        (mode . org-mode)))
+      ("Emacs"
+       (or
+        (name . "^\\*scratch\\*$")
+        (name . "^\\*Messages\\*$")
+        (name . "^\\*\\(Customize\\|Help\\)")
+        (name . "\\*\\(Echo\\|Minibuf\\)"))))))
+  (ibuffer-show-empty-filter-groups nil)
+  (ibuffer-shrink-to-minimum-size t t)
+  (ibuffer-use-other-window t)
+  :init
+  (add-hook 'ibuffer-mode-hook
+            #'(lambda ()
+                (ibuffer-switch-to-saved-filter-groups "default"))))
+#+end_src
+
+** indent
+
+#+begin_src emacs-lisp
+(use-package indent
+  :commands indent-according-to-mode
+  :custom
+  (tab-always-indent 'complete))
+#+end_src
+
+** ispell
+
+#+begin_src emacs-lisp
+  (use-package ispell
+    :custom
+    (ispell-program-name (executable-find "aspell"))
+    (ispell-dictionary "en_US")
+    (ispell-extra-args '("--camel-case")))
+#+end_src
+
+** jq-mode
+
+#+begin_src emacs-lisp
+  (use-package jq-mode
+    :ensure t
+    :mode "\\.jq\\'")
+#+end_src
+
+** js2-mode
+** languages
+*** eglot
+
+After experimenting with [[https://emacs-lsp.github.io/lsp-mode/][lsp-mode]] and [[https://github.com/joaotavora/eglot][eglot]] I decided to go with eglot for LSP integration.
+
+For languages where I want to use LSP, I need to add ~:hook (nix-mode . englot-ensure)~ in the ~use-package~ definition for the language.
+
+#+begin_src emacs-lisp
+  (use-package eglot)
+#+end_src
+
+*** tree-sitter
+
+#+begin_src emacs-lisp
+(use-package tree-sitter
+  :ensure t
+  :config
+  (global-tree-sitter-mode))
+#+end_src
+
+**** tree-sitter-langs
+
+#+begin_src emacs-lisp
+(use-package tree-sitter-langs
+  :after tree-sitter
+  :ensure t)
+#+end_src
+
+*** lisp-mode
+
+**** elisp-mode
+
+#+begin_src emacs-lisp
+(use-package emacs-lisp-mode
+  :bind (:map emacs-lisp-mode-map
+              ("C-c C-r" . eval-region)
+              ("C-c C-d" . eval-defun)
+              ("C-c C-b" . eval-buffer))
+  :hook ((emacs-lisp-mode . flymake-mode)))
+#+end_src
+
+**** eldoc
+
+#+begin_src emacs-lisp
+(use-package eldoc
+  :diminish
+  :hook ((c-mode-common emacs-lisp-mode) . eldoc-mode)
+  :custom
+  (eldoc-idle-delay 1)
+  (eldoc-documentation-strategy #'eldoc-documentation-default)
+  (eldoc-echo-area-use-multiline-p 3)
+  (eldoc-echo-area-prefer-doc-buffer 'maybe)
+  (eldoc-echo-area-display-truncation-message nil))
+#+end_src
+
+*** hcl-mode
+
+#+begin_src emacs-lisp
+  (use-package hcl-mode
+    :ensure t
+    :mode "\.nomad\\'")
+#+end_src
+
+*** json-mode
+
+#+begin_src emacs-lisp
+(use-package json-mode
+  :mode "\\.json\\'")
+#+end_src
+
+**** json-reformat
+
+#+begin_src emacs-lisp
+(use-package json-reformat
+  :ensure t
+  :after json-mode)
+#+end_src
+
+*** go-mode
+
+#+begin_src emacs-lisp
+  (use-package go-mode
+    :ensure t
+    :hook ((go-mode . tree-sitter-hl-mode)
+           (go-mode . eglot-ensure)
+           (go-mode . (lambda () (add-hook 'before-save-hook 'eglot-format-buffer nil t))))
+    :bind (:map go-mode-map
+                ("C-c C-c" . compile)))
+#+end_src
+
+**** gotest
+
+#+begin_src emacs-lisp
+(use-package gotest
+  :ensure t
+  :after go-mode
+  :custom
+  (go-test-verbose t))
+#+end_src
+
+*** nix-mode
+
+#+begin_src emacs-lisp
+  (use-package nix-mode
+    :ensure t
+    :hook ((nix-mode . eglot-ensure)
+           (nix-mode . (lambda () (add-hook 'before-save-hook 'eglot-format-buffer nil t))))
+    :custom
+    (nix-indent-function 'nix-indent-line))
+#+end_src
+
+*** protobuf-mode
+
+#+begin_src emacs-lisp
+  (use-package protobuf-mode
+    :ensure t
+    :mode "\\.proto\\'")
+#+end_src
+
+*** python-mode
+
+Enable eglot and tree-sitter when working with python.
+
+#+begin_src emacs-lisp
+(use-package python-mode
+  :hook ((python-mode . tree-sitter-hl-mode)
+         (python-mode . eglot-ensure)
+         (python-mode . (lambda () (add-hook 'before-save-hook 'eglot-format-buffer nil t))))
+  :interpreter "python"
+  :bind (:map python-mode-map
+              ("C-c c")
+              ("C-c C-z" . python-shell)))
+#+end_src
+
+**** blacken
+
+[[https://pypi.org/project/black/][black]] is a code formatter for python.
+
+#+begin_src emacs-lisp
+(use-package blacken
+  :ensure t
+  :hook (python-mode . blacken-mode))
+#+end_src
+
+**** isort
+
+[[https://pypi.org/project/isort/][Sort imports]].
+
+#+begin_src emacs-lisp
+  (use-package py-isort
+    :ensure t
+    :commands (py-isort-buffer py-isort-region))
+#+end_src
+
+*** ruby-mode
+
+#+begin_src emacs-lisp
+  (use-package ruby-mode
+    :mode "\\.rb\\'"
+    :interpreter "ruby"
+    :bind (:map ruby-mode-map
+                ("<return>" . my-ruby-smart-return))
+    :preface
+    (defun my-ruby-smart-return ()
+      (interactive)
+      (when (memq (char-after) '(?\| ?\" ?\'))
+        (forward-char))
+      (call-interactively 'newline-and-indent)))
+#+end_src
+
+*** rustic-mode
+
+#+begin_src emacs-lisp
+(use-package rustic
+  :ensure t
+  :custom
+  (rustic-format-on-save t)
+  (rustic-format-trigger 'on-save)
+  (rustic-lsp-server 'rust-analyzer)
+  (rustic-lsp-client 'eglot))
+#+end_src
+
+*** sh-script
+
+#+begin_src emacs-lisp
+(use-package sh-script
+  :defer t
+  :preface
+  (defvar sh-script-initialized nil)
+
+  (defun initialize-sh-script ()
+    (unless sh-script-initialized
+      (setq sh-script-initialized t)
+      (info-lookup-add-help :mode 'shell-script-mode
+                            :regexp ".*"
+                            :doc-spec '(("(bash)Index")))))
+  :init
+  (add-hook 'shell-mode-hook #'initialize-sh-script))
+#+end_src
+
+*** terraform-mode
+
+#+begin_src emacs-lisp
+(use-package terraform-mode
+  :ensure t
+  :mode "\.tf\\'")
+#+end_src
+
+*** toml-mode
+
+#+begin_src emacs-lisp
+(use-package toml-mode
+  :ensure t)
+#+end_src
+
+*** yaml-mode
+
+#+begin_src emacs-lisp
+(use-package yaml-mode
+  :mode "\\.ya?ml\\'")
+#+end_src
+
+** MacOS specific
+
+#+begin_src emacs-lisp
+(when (memq window-system '(mac ns))
+  (add-to-list 'default-frame-alist '(fullscreen . maximized))
+  (add-to-list 'default-frame-alist '(ns-appearance . nil))
+  (add-to-list 'default-frame-alist '(ns-transparent-titlebar . nil))
+  (when (boundp 'ns-use-native-fullscreen)
+    (setq ns-use-native-fullscreen nil))
+  (when (boundp 'mac-allow-anti-aliasing)
+    (setq mac-allow-anti-aliasing t)))
+#+end_src
+
+** magit
+
+#+begin_src emacs-lisp
+  (use-package magit
+    :ensure t
+    :bind (("C-x g" . magit-status)
+           ("C-x G" . magit-status-with-prefix))
+    :custom
+    (magit-diff-options nil)
+    (magit-diff-refine-hunk t)
+    (magit-fetch-arguments nil)
+    (magit-log-section-commit-count 10)
+    (magit-pre-refresh-hook nil)
+    (magit-process-popup-time 15)
+    (magit-clone-default-directory "~/workspace/")
+    (magit-section-initial-visibility-alist '((untracked . hide)))
+    :hook (magit-mode . hl-line-mode)
+    :config
+    (use-package magit-commit
+      :defer t
+      :config
+      (use-package git-commit
+        :custom
+        (git-commit-major-mode 'markdown-mode)
+        (git-commit-setup-hook
+         '(git-commit-save-message
+           git-commit-turn-on-auto-fill
+           git-commit-turn-on-flyspell
+           bug-reference-mode))))
+
+    (use-package magit-status
+      :defer t
+      :config
+      (dolist (func '(magit-insert-unpushed-to-upstream-or-recent
+                      magit-insert-unpulled-from-pushremote
+                      magit-insert-unpulled-from-upstream
+                      ))
+        (remove-hook 'magit-status-sections-hook func))
+
+      (dolist (func '(magit-insert-diff-filter-header
+                      magit-insert-tags-header))
+        (remove-hook 'magit-status-headers-hook func))))
+#+end_src
+
+** markdown-mode
+
+#+begin_src emacs-lisp
+(use-package markdown-mode
+  :mode (("\\`README\\.md\\'" . gfm-mode)
+         ("\\.md\\'"          . markdown-mode)
+         ("\\.markdown\\'"    . markdown-mode))
+  :custom
+  (markdown-command "pandoc -f markdown_github+smart")
+  (markdown-command-needs-filename t)
+  (markdown-enable-math t)
+  (markdown-open-command "marked")
+  :init
+  (setq markdown-command "multimarkdown"))
+#+end_src
+
+*** markdown-preview-mode
+
+#+begin_src emacs-lisp
+  (use-package markdown-preview-mode
+    :ensure t
+    :after markdown-mode
+    :config
+    (setq markdown-preview-stylesheets
+	  (list (concat "https://github.com/dmarcotte/github-markdown-preview/"
+			"blob/master/data/css/github.css"))))
+#+end_src
+
+** midnight
+
+#+begin_src emacs-lisp
+(use-package midnight
+  :demand t
+  :bind ("C-c z" . clean-buffer-list)
+  :custom
+  (midnight-delay 18000)
+  (clean-buffer-list-kill-never-buffer-names
+   '("*scratch*"
+     "*Messages*"
+     "*server*"
+     "*Group*"
+     "*Org Agenda*"
+     "todo.org"))
+  (clean-buffer-list-kill-never-regexps
+   '("^ \\*Minibuf-.*\\*$"
+     "^\\*Summary"
+     "^\\*Article" "^#"))
+  (clean-buffer-list-kill-regexps '(".*"))
+  :config
+  (midnight-mode t))
+#+end_src
+
+** my-cheeseboard
+
+get the pizzas for this week at cheeseboard.
+
+#+begin_src emacs-lisp
+(use-package my-cheeseboard)
+#+end_src
+
+** my-uptime
+
+an uptime / SLO calculator.
+
+#+begin_src emacs-lisp
+(use-package my-uptime
+  :init
+  (add-to-list 'display-buffer-alist '("\\*slo-calculator\\*"
+                                       (display-buffer-in-side-window)
+                                       (side . left)
+                                       (slot . 0)
+                                       (window-width . 0.35))))
+#+end_src
+
+** org-mode
+
+#+begin_src emacs-lisp
+  (use-package org
+    :commands org-resolve-clocks
+    :bind* (("C-c c" . org-capture)
+            ("C-c a" . org-agenda))
+    :bind (:map
+           org-mode-map
+           ("C-,")
+           ("C-c #"     . org-priority)
+           ("C-c .")
+           ("C-c ,"     . org-priority)
+           ("C-c !"     . org-time-stamp-inactive)
+           ("C-c <"     . org-time-stamp)
+           ("C-c x"     . org-todo)
+           ("C-c C-x @" . visible-mode)
+           ("C-c C-x U" . org-insert-url-link)
+           ("C-c C-x o" . my-org-todoize)
+           ([(control meta return)] . org-insert-heading-after-current))
+    :hook
+    (org-mode . abbrev-mode)
+    (org-mode . turn-on-flyspell)
+    (org-mode . visual-line-mode)
+    (org-mode . org-indent-mode)
+    (org-log-buffer-setup . abbrev-mode)
+    (org-log-buffer-setup . visual-line-mode)
+    (org-log-buffer-setup . turn-on-flyspell)
+    (org-capture-after-finalize . org-save-all-org-buffers)
+    (org-capture-prepare-finalize-hook . org-save-all-org-buffers)
+    :custom
+    ;;; general settings
+    (org-startup-folded t)
+    (org-startup-indented t)
+    (org-hide-emphasis-markers t)
+    (org-hide-leading-stars t)
+    (org-pretty-entities t)
+    (org-return-follows-link t)
+    (org-startup-with-inline-images t)
+    (org-startup-indented t)
+    (org-clone-delete-id t)
+    (org-deadline-warning-days 14)
+    (org-default-notes-file "~/documents/notes/inbox.org")
+    (org-directory "~/documents/notes/")
+    (org-export-backends '(html md))
+    (org-export-use-babel nil)
+    (org-footnote-section nil)
+    (org-icalendar-timezone "America/Los_Angeles")
+    (org-image-actual-width 800)
+    (org-imenu-depth 4)
+    (org-insert-heading-respect-content t)
+    (org-outline-path-complete-in-steps nil)
+    (org-src-fontify-natively t)
+    (org-src-preserve-indentation t)
+    (org-src-tab-acts-natively t)
+    (org-src-window-setup 'current-window)
+    (org-yank-adjusted-subtrees t)
+    (org-structure-template-alist
+        '(("s" . "src")
+          ("E" . "src emacs-lisp")
+          ("p" . "src python")
+          ("e" . "example")
+          ("q" . "quote")
+          ("V" . "verbatim")))
+
+    ;;; refile
+    (org-refile-targets '(("~/documents/notes/tasks.org" :maxlevel . 1)
+                          ("~/documents/notes/notes.org" :maxlevel . 1)))
+    (org-refile-use-cache nil)
+    (org-refile-use-outline-path t)
+    (org-reverse-note-order t)
+    (org-todo-keywords
+     '((sequence "TODO(t)" "STARTED(s)" "|" "DONE(d@)" "CANCELED(x@)")))
+    (org-todo-repeat-to-state "TODO")
+    (org-fontify-done-headline t)
+    (org-fontify-quote-and-verse-blocks t)
+    (org-fontify-todo-headline nil)
+    (org-fontify-whole-block-delimiter-line t)
+    (org-fontify-whole-heading-line nil)
+    (org-enforce-todo-dependencies t)
+    (org-track-ordered-property-with-tag t)
+    (org-highest-priority ?A)
+    (org-lowest-priority ?C)
+    (org-default-priority ?A)
+    (org-confirm-babel-evaluate nil)
+    (org-tags-column -97)
+
+    ;;; log
+    (org-log-done 'time)
+    (org-log-into-drawer t)
+    (org-log-note-clock-out nil)
+    (org-log-redeadline 'time)
+    (org-log-reschedule 'time)
+    (org-read-date-prefer-future 'time)
+
+    ;;; capture
+    (org-capture-templates
+     '(("t" "tasks" entry (file "inbox.org")
+        "* TODO [#D] %?\n:PROPERTIES:\n:CREATED: %U\n:END:\n")
+
+       ("T" "TIL" entry (file+headline "til.org" "Today I learned")
+        "* %^{title} :%^{tag}:\n:PROPERTIES:\n:CREATED: %U\n:END:\n%?\nSource: %^C")
+
+       ("n" "note" entry (file "notes.org")
+        "* %?\n:PROPERTIES:\n:CREATED: %T\n:END:\n")
+
+       ("f" "feed" entry (file "inbox.org")
+        ,(concat "* TODO [#D] %:elfeed-entry-title :feed:\n"
+                 ":PROPERTIES:\n:CREATED: %T\n:END:\n"
+                 "%a\n"))
+
+       ("b" "bookmark" entry (file "bookmarks.org")
+        ,(concat "* %(org-cliplink-capture) :%^{tag}:\n"
+                 ":PROPERTIES:\n:CREATED: %T\n:END:%?\n") :prepend t :empty-lines 1)
+
+       ("j" "journal" entry (file+olp+datetree "journal.org")
+        "* %?\n:PROPERTIES:\n:CREATED: %T\n:END:\n" :tree-type day)))
+
+    :config
+    (font-lock-add-keywords 'org-mode
+                            '(("^ *\\(-\\) "
+                               (0 (ignore (compose-region (match-beginning 1) (match-end 1) "•")))))))
+#+end_src
+
+*** org-agenda
+
+#+begin_src emacs-lisp
+  (use-package org-agenda
+    :commands org-agenda-list
+    :bind* (("C-c a" . org-agenda))
+    :bind (:map
+           org-agenda-mode-map
+           (" "   . org-agenda-tree-to-indirect-buffer)
+           (">"   . org-agenda-filter-by-top-headline)
+           ("C-n" . next-line)
+           ("C-p" . previous-line)
+           ("F"   . org-agenda-follow-mode)
+           ("M-m")
+           ("M-n" . org-agenda-later)
+           ("M-p" . org-agenda-earlier)
+           ("b"   . org-agenda-date-earlier)
+           ("f"   . org-agenda-date-later)
+           ("g"   . org-agenda-redo)
+           ("q"   . delete-window)
+           ("r"   . org-agenda-refile)
+           ("x"   . org-agenda-todo)
+           ("z"   . pop-window-configuration))
+    :custom
+    (org-agenda-auto-exclude-function 'org-my-auto-exclude-function)
+    (org-agenda-cmp-user-defined 'org-compare-todo-age)
+    (org-agenda-compact-blocks t)
+    (org-agenda-deadline-leaders '("!D!: " "D%02d: " "D-%02d:"))
+    (org-agenda-default-appointment-duration 60)
+    (org-agenda-files
+     '("~/documents/notes/inbox.org"
+       "~/documents/notes/notes.org"
+       "~/documents/notes/tasks.org"
+       "~/documents/notes/bookmarks.org"
+       "~/documents/notes/journal.org"))
+    (org-agenda-fontify-priorities t)
+    (org-agenda-include-diary t)
+    (org-agenda-inhibit-startup t)
+    (org-agenda-log-mode-items '(closed clock state))
+    (org-agenda-ndays 1)
+    (org-agenda-persistent-filter t)
+    (org-agenda-prefix-format
+     '((agenda . "  %-11c%?-12t% s")
+       (timeline . "  % s")
+       (todo . "  %-11c")
+       (tags . "  %-11c")))
+    (org-agenda-show-all-dates t)
+    (org-agenda-show-outline-path nil)
+    (org-agenda-skip-deadline-if-done t)
+    (org-agenda-skip-scheduled-if-deadline-is-shown t)
+    (org-agenda-skip-scheduled-if-done t)
+    (org-agenda-skip-unavailable-files t)
+    (org-agenda-sorting-strategy
+     '((agenda habit-down time-up todo-state-up priority-down)
+       (todo priority-down category-keep)
+       (tags priority-down category-keep)
+       (search category-keep)))
+    (org-agenda-span 'day)
+    (org-agenda-start-on-weekday 1)
+    (org-agenda-tags-column -100)
+    (org-agenda-tags-todo-honor-ignore-options t)
+    (org-agenda-text-search-extra-files '(agenda-archives))
+    (org-agenda-todo-ignore-scheduled 'past)
+    (org-agenda-use-time-grid nil)
+    (org-agenda-window-frame-fractions '(0.5 . 0.75)))
+#+end_src
+
+*** org-bullet
+
+This is to make =org-mode= document looks a bit nicer.
+
+#+begin_src emacs-lisp
+(use-package org-bullets
+  :ensure t
+  :hook (org-mode . org-bullets-mode))
+#+end_src
+
+*** org-auto-tangle
+
+#+begin_src emacs-lisp
+(use-package org-auto-tangle
+  :ensure t
+  :hook (org-mode . org-auto-tangle-mode))
+#+end_src
+
+*** org-habit
+
+#+begin_src emacs-lisp
+  (use-package org-habit
+    :after org-agenda
+    :custom
+    (org-habit-preceding-days 42)
+    (org-habit-today-glyph 45))
+#+end_src
+
+*** org-attach
+
+#+begin_src emacs-lisp
+(use-package org-attach
+  :after org
+  :init
+  (defun my-org-attach-visit-headline-from-dired ()
+    "Go to the headline corresponding to this org-attach directory."
+    (interactive)
+    (let* ((id-parts (last (split-string default-directory "/" t) 2))
+           (id (apply #'concat id-parts)))
+      (let ((m (org-id-find id 'marker)))
+        (unless m (user-error "Cannot find entry with ID \"%s\"" id))
+        (pop-to-buffer (marker-buffer m))
+        (goto-char m)
+        (move-marker m nil)))))
+#+end_src
+
+*** org-babel
+
+#+begin_src emacs-lisp
+(use-package org-babel
+  :no-require t
+  :after (org ob-emamux)
+  :config
+  (org-babel-do-load-languages
+   'org-babel-load-languages
+   '((python     . t)
+     (emacs-lisp . t)
+     (calc       . t)
+     (shell      . t)
+     (sql        . t)
+     (dot        . t)))
+
+  (remove-hook 'kill-emacs-hook 'org-babel-remove-temporary-directory)
+
+  (advice-add 'org-babel-edit-prep:emacs-lisp :after
+              #'(lambda (_info) (run-hooks 'emacs-lisp-mode-hook))))
+#+end_src
+
+*** org-bookmark-heading
+
+#+begin_src emacs-lisp
+(use-package org-bookmark-heading
+  :ensure t
+  :after org)
+#+end_src
+
+*** org-download
+
+#+begin_src emacs-lisp
+(use-package org-download
+  :after org
+  :ensure t
+  :bind (:map org-mode-map
+              ("C-c C-x C" . org-download-clipboard)
+              ("C-c C-x Y" . org-download-yank))
+  :custom
+  (org-download-method 'attach))
+#+end_src
+
+*** org-id
+
+#+begin_src emacs-lisp
+(use-package org-id
+  :after org
+  :bind (:map org-mode-map
+              ("C-c C-x i" . org-id-get-create))
+  :custom
+  (org-id-locations-file (user-data "org-id-locations")))
+#+end_src
+
+*** org-protocol
+
+#+begin_src emacs-lisp
+(use-package org-protocol
+  :after org)
+#+end_src
+
+*** org-ql
+
+#+begin_src emacs-lisp
+(use-package org-ql
+  :ensure t
+  :commands org-ql-search)
+#+end_src
+
+*** org-rich-yank
+
+#+begin_src emacs-lisp
+(use-package org-rich-yank
+  :ensure t
+  :bind (:map org-mode-map
+              ("C-M-y" . org-rich-yank)))
+#+end_src
+
+*** org-sticky-header
+
+#+begin_src emacs-lisp
+(use-package org-sticky-header
+  :ensure t
+  :commands org-sticky-header-mode)
+#+end_src
+
+*** org-super-agenda
+
+#+begin_src emacs-lisp
+(use-package org-super-agenda
+  :after org
+  :ensure t
+  :custom
+  (org-super-agenda-groups
+   '((:name "Important" :priority "A")
+     (:name "Needs review" :todo "WAITING" :todo "DELEGATED")
+     (:name "Optional" :priority "C" :order 9)
+     (:name "Tasks" :not (:priority "A" :priority "C"))))
+  (org-super-agenda-header-separator "")
+  :config
+  (org-super-agenda-mode))
+#+end_src
+
+*** org-web-tools
+
+#+begin_src emacs-lisp
+(use-package org-web-tools
+  :ensure t
+  :bind (("C-c w C-y"   . my-org-insert-url)
+         ("C-c w C-M-y" . org-web-tools-insert-web-page-as-entry))
+  :functions (org-web-tools--org-link-for-url
+              org-web-tools--get-first-url)
+  :preface
+  (defun my-org-insert-url (&optional arg)
+    (interactive "P")
+    (require' org-web-tools)
+    (let ((link (org-web-tools--org-link-for-url
+                 (org-web-tools--get-first-url))))
+      (if arg
+          (progn
+            (org-set-property "URL" link)
+            (message "Added pasteboard link to URL property"))
+        (insert link)))))
+#+end_src
+
+*** orgit
+
+#+begin_src emacs-lisp
+(use-package orgit
+  :ensure t
+  :after org)
+#+end_src
+
+*** ox
+
+**** ox-gfm
+
+#+begin_src emacs-lisp
+(use-package ox-gfm
+  :ensure t
+  :after org)
+#+end_src
+
+**** ox-md
+
+#+begin_src emacs-lisp
+(use-package ox-md
+  :after org)
+#+end_src
+
+**** ox-pandoc
+
+#+begin_src emacs-lisp
+(use-package ox-pandoc
+  :ensure t
+  :after org
+  :preface
+  (defun markdown-to-org-region (start end)
+    "Convert region from markdown to org, replacing selection"
+    (interactive "r")
+    (shell-command-on-region start end "pandoc -f markdown -t org" t t)))
+#+end_src
+
+** path setup
+
+#+begin_src emacs-lisp
+(use-package exec-path-from-shell
+  :ensure t
+  :demand t
+  :if (memq window-system '(mac ns))
+  :config
+  (exec-path-from-shell-initialize))
+#+end_src
+
+** project
+#+begin_src emacs-lisp
+  (use-package project
+  :ensure nil
+  :custom
+  (project-switch-commands
+   '((project-dired "Root" ?d)
+     (project-find-file "File" ?f)
+     (project-switch-to-buffer "Buffer" ?b)
+     (project-eshell "Shell" ?e)
+     (magit-project-status "Git" ?g)))
+  :init
+  (setq-default project-list-file (user-data "projects.eld")))
+#+end_src
+
+** recentf
+
+#+begin_src emacs-lisp
+(use-package recentf
+  :demand t
+  :commands (recentf-mode
+             recentf-add-file
+             recentf-apply-filename-handlers)
+  :custom
+  (recentf-auto-cleanup 60)
+  (recentf-exclude
+   '("~\\'" "\\`out\\'" "\\.log\\'" "^/[^/]*:" "\\.el\\.gz\\'" "\\.gz\\'"))
+  (recentf-max-saved-items 2000)
+  (recentf-save-file (user-data "recentf"))
+  :preface
+  :config
+  (recentf-mode 1))
+#+end_src
+
+** rg
+
+#+begin_src emacs-lisp
+  (use-package rg
+    :ensure t
+    :custom ((rg-group-result t)
+             (rg-show-columns t)
+             (rg-align-line-number-field-length 3)
+             (rg-align-column-number-field-length 3)
+             (rg-align-line-column-separator "#")
+             (rg-align-position-content-separator "|")
+             (rg-hide-command nil)
+             (rg-align-position-numbers t)
+             (rg-command-line-flags '("--follow"))))
+#+end_src
+
+** savehist
+
+#+begin_src emacs-lisp
+(use-package savehist
+  :unless noninteractive
+  :custom
+  (savehist-additional-variables
+   '(file-name-history
+     kmacro-ring
+     compile-history
+     compile-command))
+  (savehist-autosave-interval 60)
+  (savehist-file (user-data "history"))
+  (savehist-ignored-variables
+   '(load-history
+     flyspell-auto-correct-ring
+     org-roam-node-history
+     magit-revision-history
+     org-read-date-history
+     query-replace-history
+     yes-or-no-p-history
+     kill-ring))
+  (savehist-mode t)
+  :config
+  (savehist-mode 1))
+#+end_src
+
+** saveplace
+
+#+begin_src emacs-lisp
+(use-package saveplace
+  :unless noninteractive
+  :custom
+  (save-place-file (user-data "places"))
+  :config
+  (save-place-mode 1))
+#+end_src
+
+** theme
+
+*** modus-themes
+
+This theme is clean and readable. The [[https://protesilaos.com/emacs/modus-themes][online documentation]] is pretty detailed too.
+
+#+begin_src emacs-lisp
+(use-package emacs
+  :custom
+  ;; Syntax Highlighting
+  ;; Increase the number of bolded syntax elements
+  (modus-themes-bold-constructs t)
+  ;; Increase the number of italicized syntax elements
+  (modus-themes-italic-constructs t)
+
+  ;; Org Mode
+  ;; Make headings in org files more distinct
+  (modus-themes-headings '((t . (background bold rainbow 1))))
+  ;; Tint the background of code blocks in org files
+  (modus-themes-org-blocks 'tinted-background)
+  ;; Make tags less colorful and tables look the same as
+  ;; the default foreground.
+  (prose-done cyan-cooler)
+  (prose-tag fg-dim)
+  (prose-table fg-main)
+
+  ;; Other
+  ;; Make the fringe more intense
+  (modus-themes-common-palette-overrides '((fringe bg-active)))
+  ;; Enhance minibuffer completions
+  (modus-themes-completions 'minimal)
+  ;; Make the current line of `hl-line-mode' a fine shade of gray
+  (bg-hl-line bg-dim)
+  ;; Make matching parentheses a shade of magenta
+  (bg-paren-match bg-magenta-intense)
+  (bg-mode-line-inactive bg-dim)
+
+  :config
+  (load-theme 'modus-operandi t))
+#+end_src
+
+*** COMMENT standard-themes
+
+I like the default theme, but there's not enough contrast. The package =standard-themes= fix this problem. The full documentation can be [[https://protesilaos.com/emacs/standard-themes][read online]].
+
+#+begin_src emacs-lisp
+(use-package standard-themes
+  :ensure t
+  :init
+  (setq standard-themes-bold-constructs t
+	standard-themes-italic-constructs t
+	standard-themes-mixed-fonts t
+	standard-themes-variable-pitch-ui nil
+	standard-themes-mode-line-accented t
+	;; Accepts a symbol value:
+	standard-themes-fringes 'intense
+	;; The following accept lists of properties
+	standard-themes-links '(italic neutral-underline)
+	standard-themes-region '(no-extend neutral intense)
+	standard-themes-prompts '(bold italic)
+        standard-themes-headings (quote ((1 . (bold 1.2))
+                                         (2 . (regular 1.1))
+                                         (agenda-date (1.1))
+                                         (agenda-structure (regular 1.1)))))
+  (load-theme 'standard-light :no-confirm))
+#+end_src
+
+** time
+
+#+begin_src emacs-lisp
+(use-package time
+  :custom
+  (display-time-interval 60)
+  (display-time-mode t)
+  (display-time-24hr-format t)
+  (display-time-day-and-date t)
+  (display-time-default-load-average nil)
+  (world-clock-list t)
+  (world-clock-timer-enable t)
+  (world-clock-timer-second 60)
+  ;; UTC      => 02:42 +0000  Wednesday 20 April
+  ;; Berkeley => 19:42 -0700  Tuesday 19 April
+  (world-clock-time-format "%R %z  %A %d %B")
+  (zoneinfo-style-world-list '(("UTC" "UTC")
+                               ("America/Los_Angeles" "Berkeley")
+                               ("America/Denver" "Mountain Time")
+                               ("America/Chicago" "Central Time")
+                               ("America/New_York" "New York")
+                               ("Europe/London" "London")
+                               ("Europe/Paris" "Paris")))
+  :init
+  (add-to-list 'display-buffer-alist '("\\*wclock\\*"
+                                       (display-buffer-in-side-window)
+                                       (side . left)
+                                       (slot . 0)
+                                       (window-width . 0.35))))
+#+end_src
+
+** tramp
+
+#+begin_src emacs-lisp
+  (use-package tramp
+    :defer t
+    :custom
+    (tramp-default-method "ssh")
+    (tramp-auto-save-directory "~/.cache/emacs/backups")
+    (tramp-ssh-controlmaster-options "-o ControlMaster=auto -o ControlPath='tramp.%%C'")
+    :config
+    ;; Setting this with `:custom' does not take effect.
+    (setq tramp-persistency-file-name (user-data "tramp")))
+#+end_src
+
+** transient
+
+#+begin_src emacs-lisp
+(use-package transient
+  :defer t
+  :custom
+  (transient-history-file (user-data "transient/history.el"))
+  (transient-values-file (user-data "transient/values.el")))
+#+end_src
+
+** vc
+
+#+begin_src emacs-lisp
+(use-package vc
+  :defer t
+  :custom
+  (vc-command-messages t)
+  (vc-follow-symlinks t))
+#+end_src
+
+** which-key
+
+#+begin_src emacs-lisp
+(use-package which-key
+  :demand t
+  :diminish
+  :ensure t
+  :config
+  (which-key-mode))
+#+end_src
+
+** whitespace
+
+#+begin_src emacs-lisp
+(use-package whitespace
+  :diminish (global-whitespace-mode
+             whitespace-mode
+             whitespace-newline-mode)
+  :commands (whitespace-buffer
+             whitespace-cleanup
+             whitespace-mode
+             whitespace-turn-off)
+  :init
+  (dolist (hook '(prog-mode-hook text-mode-hook))
+    (add-hook hook #'whitespace-mode))
+  :custom
+  (whitespace-auto-cleanup t t)
+  (whitespace-rescan-timer-time nil t)
+  (whitespace-silent t t)
+  (whitespace-style '(face trailing space-before-tab))
+  :defines
+  (whitespace-auto-cleanup
+   whitespace-rescan-timer-time
+   whitespace-silent))
+#+end_src
+
+* Finalization
+#+begin_src emacs-lisp
+(report-time-since-load)
+
+;; Local Variables:
+;; byte-compile-warnings: (not docstrings lexical noruntime)
+;; End:
+#+end_src
diff --git a/emacs/elisp/my-cheeseboard.el b/lisp/my-cheeseboard.el
index 9713e14..9713e14 100644
--- a/emacs/elisp/my-cheeseboard.el
+++ b/lisp/my-cheeseboard.el
diff --git a/emacs/elisp/my-uptime.el b/lisp/my-uptime.el
index 77c9957..77c9957 100644
--- a/emacs/elisp/my-uptime.el
+++ b/lisp/my-uptime.el
diff --git a/emacs/etc/snippets/emacs-lisp-mode/defun b/snippets/emacs-lisp-mode/defun
index 1c1282b..1c1282b 100644
--- a/emacs/etc/snippets/emacs-lisp-mode/defun
+++ b/snippets/emacs-lisp-mode/defun
diff --git a/emacs/etc/snippets/emacs-lisp-mode/format b/snippets/emacs-lisp-mode/format
index 2bd648f..2bd648f 100644
--- a/emacs/etc/snippets/emacs-lisp-mode/format
+++ b/snippets/emacs-lisp-mode/format
diff --git a/emacs/etc/snippets/emacs-lisp-mode/header b/snippets/emacs-lisp-mode/header
index b868f51..b868f51 100644
--- a/emacs/etc/snippets/emacs-lisp-mode/header
+++ b/snippets/emacs-lisp-mode/header
diff --git a/emacs/etc/snippets/go-mode/method b/snippets/go-mode/method
index 78e61fc..78e61fc 100644
--- a/emacs/etc/snippets/go-mode/method
+++ b/snippets/go-mode/method
diff --git a/emacs/etc/snippets/go-mode/test b/snippets/go-mode/test
index 3140ec2..3140ec2 100644
--- a/emacs/etc/snippets/go-mode/test
+++ b/snippets/go-mode/test
diff --git a/emacs/etc/snippets/go-mode/type b/snippets/go-mode/type
index d8b2004..d8b2004 100644
--- a/emacs/etc/snippets/go-mode/type
+++ b/snippets/go-mode/type
diff --git a/emacs/etc/snippets/markdown-mode/new-blog-entry b/snippets/markdown-mode/new-blog-entry
index ad6a53f..ad6a53f 100644
--- a/emacs/etc/snippets/markdown-mode/new-blog-entry
+++ b/snippets/markdown-mode/new-blog-entry
diff --git a/emacs/etc/snippets/org-mode/begin b/snippets/org-mode/begin
index 15d66d8..15d66d8 100644
--- a/emacs/etc/snippets/org-mode/begin
+++ b/snippets/org-mode/begin
diff --git a/emacs/etc/snippets/org-mode/srcsh b/snippets/org-mode/srcsh
index 0ced1f6..0ced1f6 100644
--- a/emacs/etc/snippets/org-mode/srcsh
+++ b/snippets/org-mode/srcsh
diff --git a/snippets/python-mode/cli b/snippets/python-mode/cli
new file mode 100644
index 0000000..f5e9503
--- /dev/null
+++ b/snippets/python-mode/cli
@@ -0,0 +1,15 @@
+# -*- mode: snippet -*-
+# name: cli
+# key: cli
+# --
+import click
+
+
+@click.command()
+@click.version_option()
+def cli():
+    pass
+
+
+if __name__ == "__main__":
+    cli()
\ No newline at end of file
diff --git a/emacs/etc/snippets/python-mode/function b/snippets/python-mode/function
index ffde801..ffde801 100644
--- a/emacs/etc/snippets/python-mode/function
+++ b/snippets/python-mode/function
diff --git a/emacs/etc/snippets/python-mode/main b/snippets/python-mode/main
index b1564a8..b1564a8 100644
--- a/emacs/etc/snippets/python-mode/main
+++ b/snippets/python-mode/main