]> git.eshelyaron.com Git - dotfiles.git/commitdiff
Remove esy.org - use init.el instead
authorEshel Yaron <me@eshelyaron.com>
Wed, 15 Mar 2023 19:35:56 +0000 (21:35 +0200)
committerEshel Yaron <me@eshelyaron.com>
Wed, 15 Mar 2023 19:35:56 +0000 (21:35 +0200)
.emacs.d/esy.org [deleted file]
.emacs.d/init.el
.zshenv

diff --git a/.emacs.d/esy.org b/.emacs.d/esy.org
deleted file mode 100644 (file)
index 9c0dbb3..0000000
+++ /dev/null
@@ -1,1845 +0,0 @@
-#+TITLE: GNU Emacs literate configuration
-#+AUTHOR: Eshel Yaron
-#+EMAIL: eshelshay.yaron@gmail.com
-#+DESCRIPTION: Personal GNU Emacs configuration of Eshel Yaron
-#+KEYWORDS: eshel emacs configuration literate babel org elisp
-#+OPTIONS: ^:{}
-#+STARTUP: overview indent
-
-* Introduction
-:PROPERTIES:
-:CUSTOM_ID: introduction
-:END:
-
-This document holds my customizations for GNU Emacs.  Its source
-version is written in [[https://orgmode.org/][Org mode]], utilizing [[https://orgmode.org/worg/org-contrib/babel/][Babel]] to realize [[https://en.wikipedia.org/wiki/Literate_programming][literate
-programming]].  The Elisp code blocks scattered throughout this
-document are bundled together to create an Elisp library called
-=esy.el=, which Emacs executes on startup.
-
-The source of this document is managed with Git in [[https://git.sr.ht/~eshel/dotfiles][my dotfiles
-repository hosted on SourceHut]]. An [[https://eshelyaron.com/esy.html][online HTML version of this Emacs
-configuration]] is also published on my website.
-
-** Last modification time
-:PROPERTIES:
-:CUSTOM_ID: last-modification-time
-:END:
-
-This file was last updated at:
-
-#+begin_src emacs-lisp :tangle no :exports results
-  (format-time-string
-   "%d-%m-%Y"
-   (file-attribute-modification-time
-    (file-attributes
-     esy/source-path)))
-#+end_src
-
-** Current source control revision
-:PROPERTIES:
-:CUSTOM_ID: current-git-revision
-:END:
-
-Git revision of this file:
-
-#+begin_src emacs-lisp :tangle no :exports results
-  (vc-git-working-revision esy/source-path)
-#+end_src
-
-* Fresh installation
-:PROPERTIES:
-:CUSTOM_ID: install
-:END:
-
-To bootstrap this configuration, fetch a local clone of the repository from
-[[https://git.sr.ht/~eshel/dotfiles][SourceHut]] and create a symlink from the =.emacs.d= subdirectory into your home
-directory, possibly using [[https://www.gnu.org/software/stow/][GNU Stow]].
-
-#+begin_src shell
-  $ git clone https://git.sr.ht/~eshel/dotfiles
-  $ stow -t ~ dotfiles/.emacs.d
-  $ emacs
-#+end_src
-
-After the first run of the provided =init.el=, modifications to
-=esy.org= will be made available automatically whenever Emacs
-restarts. See also [[#bootstrap][Literate config bootstrap]].
-
-* Elisp Header
-:PROPERTIES:
-:CUSTOM_ID: header
-:END:
-
-For further information about Elisp headers, see [[info:elisp#Library
- Headers][elisp#Library Headers]].
-
-#+begin_src emacs-lisp
-  ;;; esy.el --- GNU Emacs configuration -*- lexical-binding: t -*-
-
-  ;; Copyright (C) 2021-2023 Eshel Yaron
-
-  ;; Author: Eshel Yaron <eshelshay.yaron@gmail.com>
-  ;; URL: https://eshelyaron.com/esy.html
-
-  ;; This file is free software: you can redistribute it and/or modify it
-  ;; under the terms of the GNU General Public License as published by the
-  ;; Free Software Foundation, either version 3 of the License, or (at
-  ;; your option) any later version.
-
-  ;; This file is distributed in the hope that it will be useful, but
-  ;; WITHOUT ANY WARRANTY; without even the implied warranty of
-  ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
-  ;; General Public License for more details.
-
-  ;; You should have received a copy of the GNU General Public License
-  ;; along with this file.  If not, see <http://www.gnu.org/licenses/>.
-
-  ;;; Package-Requires: ((emacs "30"))
-  ;;; Commentary:
-  ;;  Tangled version of esy.org
-  ;;; Code:
-#+end_src
-
-* Allow for more memory usage during initialization
-:PROPERTIES:
-:CUSTOM_ID: garbage-collection-tweeks
-:END:
-
-#+begin_src emacs-lisp
-  (let ((normal-gc-cons-threshold (* 20 1024 1024))
-        (init-gc-cons-threshold (* 1024 1024 1024)))
-    (setq gc-cons-threshold init-gc-cons-threshold)
-    (add-hook 'emacs-startup-hook
-              (lambda () (setq gc-cons-threshold normal-gc-cons-threshold))))
-#+end_src
-
-* Suppressing compilation warnings
-:PROPERTIES:
-:CUSTOM_ID: compilation-warning
-:END:
-
-#+begin_src emacs-lisp
-  (setq native-comp-async-report-warnings-errors 'silent)
-  (setq warning-minimum-level :error)
-#+end_src
-
-* Package archives
-:PROPERTIES:
-:CUSTOM_ID: package-archives
-:END:
-
-#+begin_src emacs-lisp
-  (require 'package)
-
-  (add-to-list 'package-archives
-               '("melpa" . "http://melpa.org/packages/"))
-  (add-to-list 'package-archives
-               '("elpa-devel" . "https://elpa.gnu.org/devel/"))
-
-  (setq package-archive-column-width 12
-        package-version-column-width 28)
-#+end_src
-
-* Selected packages
-:PROPERTIES:
-:CUSTOM_ID: selected-packages
-:END:
-
-These are external Emacs packages that I want to install:
-
-#+begin_src emacs-lisp
-  (setq package-selected-packages
-        '(
-          all-the-icons
-          all-the-icons-completion
-          all-the-icons-dired
-          all-the-icons-gnus
-          auctex
-          auctex-latexmk
-          avy
-          bbdb
-          corfu
-          define-word
-          denote
-          devdocs
-          diff-hl
-          ef-themes
-          elfeed
-          embark-consult
-          emms
-          gnu-elpa-keyring-update
-          gnuplot
-          graphviz-dot-mode
-          graphql-mode
-          haskell-mode
-          htmlize
-          ialign
-          jenkinsfile-mode
-          keycast
-          kubernetes
-          lin
-          magit
-          marginalia
-          markdown-mode
-          mastodon
-          no-littering
-          ob-prolog
-          orderless
-          org-modern
-          package-lint
-          paredit
-          pdf-tools
-          rainbow-delimiters
-          rainbow-mode
-          request
-          rg
-          slack
-          smtpmail-multi
-          sqlformat
-          typit
-          terraform-mode
-          vterm
-          vundo
-          whitespace-cleanup-mode
-          with-editor
-          ))
-#+end_src
-
-Ensure they're all installed:
-
-#+begin_src emacs-lisp
-  (package-install-selected-packages)
-#+end_src
-
-* No littering!
-:PROPERTIES:
-:CUSTOM_ID: no-littering
-:END:
-
-#+begin_src emacs-lisp
-  (require 'no-littering)
-
-  (setq auto-save-file-name-transforms
-        `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))
-
-  (setq custom-file (no-littering-expand-etc-file-name "custom.el"))
-  (load custom-file 'noerror 'nomessage)
-
-  (when (fboundp 'startup-redirect-eln-cache)
-    (startup-redirect-eln-cache
-     (convert-standard-filename
-      (expand-file-name  "var/eln-cache/" user-emacs-directory))))
-#+end_src
-
-* Add local Elisp directory to load-path
-:PROPERTIES:
-:CUSTOM_ID: add-to-load-path
-:END:
-
-#+begin_src emacs-lisp
-  (add-to-list 'load-path (expand-file-name  "lisp/" user-emacs-directory))
-#+end_src
-
-* Display settings
-:PROPERTIES:
-:CUSTOM_ID: display
-:END:
-
-#+begin_src emacs-lisp
-  (add-to-list 'initial-frame-alist '(fullscreen . fullboth))
-
-  (set-face-attribute 'default nil
-                      :height 130
-                      :family "Iosevka")
-
-  (set-face-attribute 'fixed-pitch nil
-                      :family "Iosevka")
-
-  (set-face-attribute 'variable-pitch nil
-                      :family "Iosevka Etoile")
-
-  (setq ef-themes-mixed-fonts       t
-        ef-themes-variable-pitch-ui t
-        ef-themes-to-toggle         '(ef-bio ef-day))
-  (mapc #'disable-theme custom-enabled-themes)
-  (load-theme 'ef-bio :no-confirm)
-
-  (tool-bar-mode -1)
-  (set-scroll-bar-mode nil)
-
-  (setq use-dialog-box nil)
-
-  (setq inhibit-startup-screen t)
-  (setq initial-scratch-message ";; Go.\n")
-
-  (setq ring-bell-function 'ignore)
-
-  (setq switch-to-buffer-obey-display-actions t)
-
-  (setq-default indent-tabs-mode nil)
-
-  (context-menu-mode)
-
-  (pixel-scroll-precision-mode)
-
-  (global-diff-hl-mode)
-
-  (transient-mark-mode)
-
-  (mouse-avoidance-mode 'banish)
-
-  (show-paren-mode)
-
-  (require 'lin)
-  (add-to-list 'lin-mode-hooks 'gnus-summary-mode-hook)
-  (add-to-list 'lin-mode-hooks 'gnus-group-mode-hook)
-  (add-to-list 'lin-mode-hooks 'gnus-server-mode-hook)
-  (lin-global-mode 1)
-
-  (add-hook 'completion-list-mode-hook
-              (lambda ()
-                (setq-local cursor-in-non-selected-windows nil)))
-#+end_src
-
-* History
-:PROPERTIES:
-:CUSTOM_ID: history
-:END:
-
-#+begin_src emacs-lisp
-  (recentf-mode 1)
-
-  (save-place-mode 1)
-
-  (setq bookmark-save-flag 1)
-
-  (savehist-mode 1)
-  (with-eval-after-load 'log-edit
-      (add-to-list 'savehist-additional-variables
-                  'log-edit-comment-ring))
-#+end_src
-
-* Org-mode settings
-:PROPERTIES:
-:CUSTOM_ID: org
-:END:
-
-** Literate config bootstrap
-:PROPERTIES:
-:CUSTOM_ID: bootstrap
-:END:
-
-#+begin_src emacs-lisp
-  (defconst esy/source-path (locate-user-emacs-file "esy.org")
-    "Path to the Org version of this file.")
-
-  (defconst esy/target-path (locate-user-emacs-file "esy.el")
-    "Path to the Elisp version of this file.")
-
-  (defun esy/tangle-and-compile-config ()
-    "Tangle literate configuration file."
-    (interactive)
-    (when (file-newer-than-file-p esy/source-path esy/target-path)
-      (require 'org)
-      (require 'ob)
-      (org-babel-tangle-file esy/source-path
-                             esy/target-path
-                             (rx string-start
-                                 (or "emacs-lisp" "elisp")
-                                 string-end))
-      (byte-compile-file esy/target-path)))
-
-  (add-hook 'kill-emacs-hook #'esy/tangle-and-compile-config)
-
-  (defun esy/find-esy-org ()
-    "Open my Emacs configuration."
-    (interactive)
-    (find-file esy/source-path))
-#+end_src
-
-** Org-mode basic settings
-:PROPERTIES:
-:CUSTOM_ID: org-must-haves
-:END:
-
-#+begin_src emacs-lisp
-  (defconst esy/inbox-path (expand-file-name "inbox.org" "~/org")
-    "Path to my Org mode inbox file.")
-
-  (defconst esy/journal-path (expand-file-name "journal.org" "~/org")
-    "Path to my Org mode journal file.")
-
-  (with-eval-after-load 'org
-    (require 'ob)
-    (require 'ob-prolog)
-    (require 'ob-sql)
-    (require 'org-tempo)
-    (setq org-agenda-files `(,esy/inbox-path ,esy/journal-path)
-          org-default-notes-file esy/inbox-path
-          org-agenda-start-on-weekday 0
-          org-ellipsis "…"
-          org-use-speed-commands t
-          org-todo-keywords '((sequence
-                               "TODO(t)"
-                               "BLOCKED(b@/!)"
-                               "INPROGRESS(i!)"
-                               "|"
-                               "DONE(d!)"
-                               "CANCELED(c@)"))
-          org-tag-alist '((:startgroup)
-                          ("work"     . ?w)
-                          ("studies"  . ?s)
-                          ("esols"    . ?e)
-                          ("personal" . ?p)
-                          (:endgroup))
-          org-babel-load-languages '((emacs-lisp . t)
-                                     (shell      . t)
-                                     (sql        . t)
-                                     (bnf        . t)
-                                     (prolog     . t))
-          org-confirm-babel-evaluate nil
-          org-log-done 'time
-          org-log-into-drawer t
-          org-fast-tag-selection-single-key 'expert
-          org-use-fast-todo-selection 'expert
-          org-clock-in-switch-to-state "INPROGRESS")
-    (add-to-list 'org-src-lang-modes '("prolog" . sweeprolog))
-    (keymap-unset org-mode-map "C-," t))
-
-  (with-eval-after-load 'org-agenda
-    (add-to-list 'org-agenda-custom-commands
-                 '("w" "Work TODOs" tags-todo "+work")))
-#+end_src
-
-*** Always open files with =C-c C-o= inside Emacs
-:PROPERTIES:
-:CUSTOM_ID: org-file-apps-t-emacs
-:CreatedAt: <2022-06-10 Fri>
-:CapturedAt:
-:CapturedAs: Emacs configuration fragment
-:END:
-
-#+begin_src emacs-lisp
-  (setq org-file-apps '((t . emacs)))
-#+end_src
-
-** Refile targets
-:PROPERTIES:
-:CUSTOM_ID: org-refile-targets
-:END:
-
-By default, =org-refile= considers only top level heading to be
-candidates for refiling into, we set =org-refile-targets= to allow
-refiling directly into deeper headings as well.
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'org-refile
-    (setq org-refile-targets '((org-agenda-files . (:maxlevel . 5))
-                               (nil . (:maxlevel . 3)))
-          org-archive-location "~/org/journal.org::datetree/* Finished Tasks                                              :ARCHIVE"
-          org-refile-use-outline-path t))
-#+end_src
-
-** Interactively fill missing CUSTOM_ID properties                     :cmd:
-:PROPERTIES:
-:CUSTOM_ID: orgs-custom-ids
-:END:
-
-#+begin_src emacs-lisp
-  (defun esy/org-fill-custom-id (point value)
-    "Set CUSTOM_ID to VALUE interactively for the entry at POINT."
-    (interactive "d\nMCUSTOM_ID: ")
-    (org-entry-put point "CUSTOM_ID" value))
-
-  (defun esy/org-fill-description (point value)
-    "Set DESCRIPTION to VALUE interactively for the entry at POINT."
-    (interactive "d\nMDESCRIPTION: ")
-    (org-entry-put point "DESCRIPTION" value))
-
-  (defun esy/org-maybe-prompt-custom-id ()
-    "Prompt for CUSTOM_ID if not set for the entry at POINT."
-    (let ((res 0))
-      (unless (and (org-entry-get (point) "DESCRIPTION")
-                   (org-entry-get (point) "CUSTOM_ID"))
-        (pulse-momentary-highlight-one-line)
-        (org-cycle)
-        (unless (org-entry-get (point) "CUSTOM_ID")
-          (call-interactively #'esy/org-fill-custom-id)
-          (setq res (1+ res)))
-        (unless (org-entry-get (point) "DESCRIPTION")
-          (call-interactively #'esy/org-fill-description)
-          (setq res (1+ res)))
-        (org-global-cycle 1))
-      res))
-
-  (defun esy/org-fill-custom-ids-in-buffer ()
-    "Visit headers in the current buffer and set CUSTOM_ID for each."
-    (interactive)
-    (org-global-cycle 1)
-    (message "Filled %d properties."
-             (apply #'+ (remove nil
-                             (org-map-entries
-                              #'esy/org-maybe-prompt-custom-id)))))
-#+end_src
-
-** Org-mode capture templates
-:PROPERTIES:
-:CUSTOM_ID: org-capture-templates
-:END:
-
-#+begin_src emacs-lisp
-  (defun esy/org-capture-to-project-heading ()
-    "Prompt for a projects and capture a related task."
-    (let* ((projects
-            (org-map-entries `(lambda () (nth 4 (org-heading-components)))
-                             "+project+LEVEL=2" `(,esy/inbox-path)))
-           (choice (completing-read "Project: " projects nil t nil))
-           (m (org-find-olp (cons
-                             (org-capture-expand-file esy/inbox-path)
-                             (list "Projects" choice)))))
-      (set-buffer (marker-buffer m))
-      (org-capture-put-target-region-and-position)
-      (widen)
-      (goto-char m)
-      (set-marker m nil)))
-
-  (defun esy/org-capture-to-current-project ()
-    "Prompt for a projects and capture a related task."
-    (let* ((projects
-            (org-map-entries (lambda () (nth 4 (org-heading-components)))
-                             (concat "+project+LEVEL=2+SCM=\"file:"
-                                     (project-root (with-current-buffer
-                                                       (org-capture-get :original-buffer)
-                                                     (project-current)))
-                                     "\"")
-                             (list esy/inbox-path)))
-           (choice (car projects))
-           (m (org-find-olp (cons
-                             (org-capture-expand-file esy/inbox-path)
-                             (list "Projects" choice)))))
-      (set-buffer (marker-buffer m))
-      (org-capture-put-target-region-and-position)
-      (widen)
-      (goto-char m)
-      (set-marker m nil)))
-
-  (setq org-capture-templates '(("t" "Todo [inbox]" entry
-                                 (file+headline esy/inbox-path "Tasks")
-                                 "** TODO %^{Task}    %^g
-  :PROPERTIES:
-  :CreatedAt: %u
-  :CapturedAt: %a
-  :CapturedAs: Inbox Task
-  :END:"
-                                 :prepend t
-                                 :empty-lines 1
-                                 :immediate-finish t)
-                                ("w" "Work [inbox]" entry
-                                 (file+headline esy/inbox-path "Tasks")
-                                 "** TODO %^{Task}    :work:
-  :PROPERTIES:
-  :CreatedAt: %u
-  :CapturedAt: %a
-  :CapturedAs: Work Task
-  :END:"
-                                 :prepend t
-                                 :empty-lines 1
-                                 :immediate-finish t)
-                                ("e" "Emacs configuration fragment" entry
-                                 (file+headline esy/source-path
-                                                "Misc. settings")
-                                 "** %^{Fragment}    %^g
-  :PROPERTIES:
-  :CUSTOM_ID: %^{CUSTOM_ID}
-  :CreatedAt: %u
-  :CapturedAt: %a
-  :CapturedAs: Emacs configuration fragment
-  :END:\n\n#+begin_src emacs-lisp\n  %i\n#+end_src"
-                                 :empty-lines 1)
-                                ("c" "New Calendar Event" entry
-                                 (file+headline esy/inbox-path "Calendar")
-                                 "** %^{Title}    %^g
-  :PROPERTIES:
-  :CreatedAt: %u
-  :CapturedAt: %a
-  :CapturedAs: Calendar Event
-  :END:
-  %(format-time-string \"<%Y-%m-%d %H:%M\" (org-read-date t t))-%(format-time-string \"%H:%M>\" (org-read-date t t))
-  %i"
-                                 :prepend t
-                                 :empty-lines 1
-                                 :immediate-finish t)
-                                ("j" "Journal" entry
-                                 (file+datetree esy/journal-path)
-                                 "* %?
-  :PROPERTIES:
-  :CreatedAt: %u
-  :CapturedAt: %a
-  :CaptuerdAs: Journal entry
-  :END:
-  %i"
-                                 :empty-lines 1)))
-
-  (setq org-capture-templates-contexts
-        '(("P" (list project-current))))
-#+end_src
-
-** Open files (with =C-c C-o=) in Emacs
-  :PROPERTIES:
-  :CUSTOM_ID: org-file-apps-t-emacs
-  :CreatedAt: <2022-06-10 Fri>
-  :CapturedAt:
-  :CapturedAs: Emacs configuration fragment
-  :END:
-
-#+begin_src emacs-lisp
-  (setq org-file-apps '((t . emacs)))
-#+end_src
-
-* Email settings
-:PROPERTIES:
-:CUSTOM_ID: email
-:END:
-
-** My accounts
-:PROPERTIES:
-:CUSTOM_ID: accounts
-:END:
-
-#+begin_src emacs-lisp
-  (setq user-full-name "Eshel Yaron")
-  (setq user-mail-address "me@eshelyaron.com")
-
-  (defconst esy/user-mail-address-gmail "eshelshay.yaron@gmail.com"
-    "My personal Gmail address.")
-
-  (defconst esy/user-mail-address-swipl "eshel@swi-prolog.org"
-    "My SWI-Prolog email address.")
-
-  (defconst esy/user-mail-address-dazz "eshel@dazz.io"
-    "My Dazz email address.")
-
-  (defconst esy/user-mail-address-me "me@eshelyaron.com"
-    "My persomal email address.")
-#+end_src
-
-** Sending mail from multiple SMTP accounts
-:PROPERTIES:
-:CUSTOM_ID: multiple-smtp-accounts
-:END:
-
-#+begin_src emacs-lisp
-  (defun esy/smtpmail-multi-make-accout (address server)
-    "Return an SMTP account definition for ADDRESS in SERVER."
-    `(,address ,server 587 ,address starttls nil nil nil))
-
-  (defun esy/smtpmail-multi-make-rx (address)
-    "Return a regexp that matches ADDRESS wrapped with anything."
-    (rx (* anything) (literal address) (* anything)))
-
-  (defun esy/customize-message-mode ()
-    "Configure `message-mode' specific customizations."
-    (require 'smtpmail-multi)
-    (setq smtpmail-multi-accounts
-          `((daz . ,(esy/smtpmail-multi-make-accout
-                     esy/user-mail-address-dazz
-                     "smtp.gmail.com"))
-            (esy . ,(esy/smtpmail-multi-make-accout
-                     esy/user-mail-address-gmail
-                     "smtp.gmail.com"))
-            (swp . ,(esy/smtpmail-multi-make-accout
-                     esy/user-mail-address-swipl
-                     "mail.swi-prolog.com"))
-            (me  . ,(esy/smtpmail-multi-make-accout
-                     esy/user-mail-address-me
-                     "mail.eshelyaron.com"))))
-    (setq smtpmail-multi-associations
-          `((,(esy/smtpmail-multi-make-rx esy/user-mail-address-dazz)  daz)
-            (,(esy/smtpmail-multi-make-rx esy/user-mail-address-gmail) esy)
-            (,(esy/smtpmail-multi-make-rx esy/user-mail-address-swipl) swp)
-            (,(esy/smtpmail-multi-make-rx esy/user-mail-address-me) me)))
-    (setq send-mail-function #'smtpmail-multi-send-it)
-    (setq message-send-mail-function #'smtpmail-multi-send-it))
-
-  (add-hook 'message-mode-hook #'esy/customize-message-mode)
-  (add-hook 'mail-mode-hook #'esy/customize-message-mode)
-#+end_src
-
-** Reading mail with Gnus
-:PROPERTIES:
-:CUSTOM_ID: gnus
-:END:
-
-#+begin_src emacs-lisp
-  (setq mail-user-agent 'gnus-user-agent
-        gnus-always-read-dribble-file t
-        gnus-expert-user t
-        gnus-break-pages nil
-        gnus-inhibit-startup-message t
-        gnus-select-method '(nnimap "gmail"
-                                    (nnimap-address "imap.gmail.com")
-                                    (nnimap-server-port "imaps")
-                                    (nnimap-stream ssl))
-        gnus-secondary-servers '((nnimap "me"
-                                         (nnimap-address "mail.eshelyaron.com")
-                                         (nnimap-server-port "imaps")
-                                         (nnimap-stream ssl)
-                                         (nnimap-authinfo-file "~/.authinfo")))
-        gnus-no-groups-message "No new articles")
-
-  (defun esy/customize-gnus-mode ()
-    "Configure Gnus specific customizations."
-    (require 'gnus)
-    (require 'gnus-icalendar)
-    (setq
-     gnus-use-full-window nil
-     gnus-article-treat-types '("text/plain"
-                                "text/x-verbatim"
-                                "text/x-patch"
-                                "text/html"
-                                "text/calendar")
-     gnus-posting-styles `((".*eshelyaron.com.*"
-                            (address ,esy/user-mail-address-me))
-                           (".*mail.swi-prolog.com.*"
-                            (address ,esy/user-mail-address-swipl))
-                           (".*"
-                            (address ,esy/user-mail-address-gmail)))
-     gnus-icalendar-org-capture-file esy/inbox-path
-     gnus-icalendar-org-capture-headline '("Calendar")
-     calendar-date-style 'iso)
-    (gnus-icalendar-setup)
-    (gnus-icalendar-org-setup)
-    (add-hook 'gnus-group-mode-hook #'gnus-topic-mode))
-
-  (add-hook 'gnus-mode-hook #'esy/customize-gnus-mode)
-
-  (with-eval-after-load 'gnus
-    (require 'all-the-icons-gnus)
-    (all-the-icons-gnus-setup))
-#+end_src
-
-* Global keybindings                                                    :kbd:
-:PROPERTIES:
-:CUSTOM_ID: global-keybindings
-:END:
-
-** =C-c= keybindings
-:PROPERTIES:
-:CUSTOM_ID: ctrl-c-bindings
-:END:
-
-#+begin_src emacs-lisp
-  (keymap-global-set "C-c w" #'esy/eww)
-  (keymap-global-set "C-c c" #'org-capture)
-  (keymap-global-set "C-c l" #'org-store-link)
-  (keymap-global-set "C-c a" #'org-agenda)
-  (keymap-global-set "C-c !" #'consult-flymake)
-  (keymap-global-set "C-c C" #'openai-chat)
-  (keymap-global-set "C-c D" #'denote)
-  (keymap-global-set "C-c E" #'elfeed)
-  (keymap-global-set "C-c G" #'gnus)
-  (keymap-global-set "C-c M" #'mastodon)
-  (keymap-global-set "C-c S" #'esy/vterm-at)
-  (keymap-global-set "C-c V" #'vertalen-at-point)
-  (keymap-global-set "C-c F" #'esy/find-esy-org)
-
-#+end_src
-
-** Custom kill command                                                 :cmd:
-:PROPERTIES:
-:CUSTOM_ID: kill-dwim-command
-:END:
-
-#+begin_src emacs-lisp
-  (defun esy/kill-dwim ()
-    "When region is active, kill region, otherwise kill last word."
-    (interactive)
-    (if (region-active-p)
-        (let ((beg (region-beginning))
-              (end (region-end)))
-          (kill-region beg end))
-      (let ((end (point)))
-        (backward-word)
-        (kill-region (point) end))))
-#+end_src
-
-** Pulse current line                                                  :cmd:
-:PROPERTIES:
-:CUSTOM_ID: pulse-line
-:END:
-
-#+begin_src emacs-lisp
-  (defun esy/pulse-line (&optional _)
-    "Pulse current line."
-    (interactive)
-    (pulse-momentary-highlight-one-line))
-#+end_src
-
-** Misc. keybindings
-:PROPERTIES:
-:CUSTOM_ID: misc-keybindings
-:END:
-
-#+begin_src emacs-lisp
-  (keymap-global-unset "s-a")
-  (keymap-global-unset "s-d")
-  (keymap-global-unset "s-e")
-  (keymap-global-unset "s-f")
-  (keymap-global-unset "s-g")
-  (keymap-global-unset "s-h")
-  (keymap-global-unset "s-j")
-  (keymap-global-unset "s-k")
-  (keymap-global-unset "s-l")
-  (keymap-global-unset "s-m")
-  (keymap-global-unset "s-o")
-  (keymap-global-unset "s-q")
-  (keymap-global-unset "s-s")
-  (keymap-global-unset "s-t")
-  (keymap-global-unset "s-u")
-  (keymap-global-unset "s-w")
-  (keymap-global-unset "s-x")
-  (keymap-global-unset "s-y")
-  (keymap-global-unset "s-z")
-  (global-set-key [remap kill-region] #'esy/kill-dwim)
-  (global-set-key [remap goto-line] #'consult-goto-line)
-  (global-set-key [remap suspend-frame] #'zap-up-to-char)
-  (global-set-key [remap imenu] #'consult-imenu)
-  (global-set-key [remap make-frame] #'move-dup-duplicate-down)
-  (global-set-key [remap ns-print-buffer] #'move-dup-duplicate-up)
-  (global-set-key (kbd "M-#") #'define-word-at-point)
-  (global-set-key (kbd "M-o") #'previous-buffer)
-  (global-set-key (kbd "M-O") #'next-buffer)
-  (global-set-key (kbd "C-,") #'backward-delete-char)
-  (global-set-key (kbd "C-.") #'embark-act)
-  (global-set-key (kbd "C-;") #'avy-goto-char-timer)
-  (global-set-key (kbd "C-s-f") #'toggle-frame-fullscreen)
-  (global-set-key (kbd "C-s-l") #'esy/pulse-line)
-#+end_src
-
-** =C-x= keybindings
-:PROPERTIES:
-:CUSTOM_ID: c-x-keybindings
-:END:
-
-#+begin_src emacs-lisp
-  (keymap-set ctl-x-map "b" #'consult-buffer)
-  (keymap-set ctl-x-4-map "b" #'consult-buffer-other-window)
-  (keymap-set ctl-x-map "C-b" #'ibuffer)
-
-  (put 'set-goal-column 'disabled nil)
-  (put 'narrow-to-region 'disabled nil)
-  (put 'narrow-to-page 'disabled nil)
-  (put 'suspend-frame 'disabled t)
-#+end_src
-
-** =M-s= keybindings
-:PROPERTIES:
-:CUSTOM_ID: search-map-keybindings
-:END:
-
-#+begin_src emacs-lisp
-  (keymap-set search-map "r" #'rg)
-  (keymap-set search-map "l" #'rg-literal)
-  (keymap-set search-map "b" #'some-button)
-#+end_src
-
-* Applications
-:PROPERTIES:
-:CUSTOM_ID: applications
-:END:
-
-** Magit
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'magit
-    (setq magit-repository-directories '(("~/checkouts/" . 1))))
-#+end_src
-
-** Mastodon
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'mastodon
-    (setq mastodon-instance-url "https://emacs.ch"
-          mastodon-active-user "eshel"))
-#+end_src
-
-** tramp
-:PROPERTIES:
-:CUSTOM_ID: tramp-optimization
-:END:
-#+begin_src emacs-lisp
-  (with-eval-after-load 'tramp
-    (tramp-set-completion-function "ssh" '((tramp-parse-netrc "~/.authinfo"))))
-
-  (define-advice project--find-in-directory (:override (dir) no-remote-projects)
-    (unless (file-remote-p dir)
-      (run-hook-with-args-until-success 'project-find-functions dir)))
-
-  (define-advice completion-file-name-table (:filter-args (args) no-remote-file-name-completion)
-    (let ((string (car args))
-          (pred (cadr args))
-          (action (caddr args)))
-      (if (and (file-remote-p string) (eq pred #'file-exists-p))
-          (list string nil action)
-        (list string pred action))))
-#+end_src
-
-** Dired
-:PROPERTIES:
-:CUSTOM_ID: dired
-:END:
-
-#+begin_src emacs-lisp
-  (defun esy/local-all-the-icons-dired-mode ()
-    (unless (file-remote-p default-directory)
-      (all-the-icons-dired-mode)))
-
-  (with-eval-after-load 'dired
-    (put 'dired-find-alternate-file 'disabled nil)
-    (setq dired-dwim-target t)
-    (add-hook 'dired-mode-hook #'esy/local-all-the-icons-dired-mode))
-#+end_src
-
-** vterm                                                               :cmd:
-:PROPERTIES:
-:CUSTOM_ID: remote-vtrem
-:END:
-Start =vterm= in a given directory and with a given shell, possibly
-over ssh for remote connections.
-
-#+begin_src emacs-lisp
-  (defun esy/vterm-mode-hook-function ()
-    (setq-local term-prompt-regexp "^[^#$%>\n]*[#$%>] *"))
-
-  (defun esy/vterm-with (arg shell)
-    (interactive
-     (list current-prefix-arg
-           (completing-read
-            "Start vterm with shell: "
-            '("bash" "zsh" "sh")
-            nil t nil nil "bash")))
-    (require 'vterm)
-    (let ((vterm-shell (concat "/bin/" shell)))
-      (vterm arg)))
-
-  (defun esy/vterm-at (arg dir)
-    (interactive
-     (list current-prefix-arg
-           (read-directory-name "Start vterm in directory: " )))
-    (let ((default-directory dir))
-      (vterm arg)))
-
-  (with-eval-after-load 'vterm
-    (setq vterm-shell "/bin/zsh"
-          vterm-max-scrollback 2048
-          vterm-kill-buffer-on-exit nil
-          vterm-use-vterm-prompt-detection-method t)
-    (add-to-list 'vterm-tramp-shells '("kubernetes" "/bin/bash"))
-    (add-hook 'vterm-mode-hook #'esy/vterm-mode-hook-function))
-#+end_src
-
-** Elfeed
-:PROPERTIES:
-:CUSTOM_ID: elfeed
-:END:
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'elfeed
-    (setq elfeed-feeds
-          '(
-            "https://ajroach42.com/feed.xml"
-            "https://cdn.jwz.org/blog/feed/"
-            "https://jcm.libsyn.com/rss/"
-            "https://betterappsec.com/feed"
-            "https://emacs.dyerdwelling.family/index.xml"
-            "https://www.typetheoryforall.com/episodes.mp3.rss"
-            "https://www.fsf.org/static/fsforg/rss/news.xml"
-            "https://amodernist.com/all.atom"
-            "https://arcology.garden/updates.xml"
-            "https://takeonrules.com/index.atom"
-            "https://atthis.link/rss.xml"
-            "https://archive.casouri.cc/note/atom.xml"
-            "https://cestlaz.github.io/rss.xml"
-            "https://drewdevault.com/blog/index.xml"
-            "https://evanhahn.com/blog/index.xml"
-            "https://alexschroeder.ch/wiki/feed/full/"
-            "https://usesthis.com/feed.atom"
-            "https://xeiaso.net/blog.rss"
-            "https://changelog.complete.org/feed"
-            "https://herman.bearblog.dev/feed/"
-            "https://lwn.net/headlines/rss"
-            "https://maggieappleton.com/rss.xml"
-            "https://matt-rickard.com/rss"
-            "https://node2.feed43.com/7487052648530856.xml"
-            "https://njoseph.me/shaarli/feed/atom?"
-            "https://nullprogram.com/feed/"
-            "https://olddeuteronomy.github.io/index.xml"
-            "https://parasurv.neocities.org/rss.xml"
-            "https://phaazon.net/blog/feed"
-            "https://bruda.ca/feed.php"
-            "https://erikmcclure.com/blog/index.xml"
-            "https://blog.acthompson.net/feeds/posts/default"
-            "https://planet.emacslife.com/atom.xml"
-            "https://pouria.dev/rss.xml"
-            "https://project-mage.org/rss.xml"
-            "https://reddit.com/r/prolog/.rss"
-            "https://sachachua.com/blog/feed/"
-            "https://feeds.buzzsprout.com/2134279.rss"
-            "https://stephanango.com/feed.xml"
-            "https://stppodcast.libsyn.com/rss"
-            "https://writer13.neocities.org/rss.xml"
-            "https://www.draketo.de/rss-feed.xml"
-            "https://www.haskellforall.com/feeds/posts/default"
-            "https://cce.whatthefuck.computer/updates.xml"
-            "https://xkcd.com/rss.xml"
-            "https://bitspook.in/blog/feed.xml"
-            "https://flower.codes/feed.xml"
-            "https://www.cs.uni.edu/~wallingf/blog/atom.xml"
-            "https://matklad.github.io/feed.xml"
-            "https://www.evalapply.org/index.xml"
-            "https://www.stilldrinking.org/rss/feed.xml"
-            "https://fasterthanli.me/index.xml"
-            "https://kitchen-sink.kwakk.info/feed"
-            "https://lars.ingebrigtsen.no/feed"
-            )))
-#+end_src
-
-** denote
-
-#+begin_src emacs-lisp
-  (setq denote-directory "~/Notes")
-#+end_src
-** eww                                                                 :www:
-:PROPERTIES:
-:CUSTOM_ID: eww
-:END:
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'eww
-    (setq eww-auto-rename-buffer 'title)
-    (with-eval-after-load 'browse-url
-      (setq browse-url-browser-function #'eww-browse-url
-            browse-url-generic-program "open")))
-
-  ;; (with-eval-after-load 'shr
-  ;;   (setq shr-use-colors nil))
-#+end_src
-
-*** Prompt for URL with history-based completion
-:PROPERTIES:
-:CUSTOM_ID: eww-completing-read-url
-:CreatedAt: <2022-05-08 Sun>
-:CapturedAt: [[file:~/checkouts/protfiles/emacs/.emacs.d/prot-lisp/prot-eww.el::defun prot-eww-browse-dwim]]
-:CapturedAs: Emacs configuration fragment
-:END:
-
-The =eww= command in the heart of =eww.el= prompts the user for a URL,
-and browses it (see [[info:eww#Basics][eww#Basics]] for more details). One shortcoming of
-the built-in =eww= command is that it uses the =read-string= function
-to read the requested URL, which does not facilitate completions.
-
-The following fragment, inspired by [[https://protesilaos.com/emacs/dotemacs#h:524bc702-ff55-4ed9-9a38-26d30d64591d][Protesilaos Stavrou's prot-eww.el]],
-provides a simple wrapper for =eww= that uses =completing-read=
-instead of =read-string=, allowing for quick input completion based on
-the prior submitted URLs and web search keywords.
-
-#+begin_src emacs-lisp
-  (defun esy/eww ()
-    "Prompt for a URL or keywords to search the web for."
-    (interactive)
-    (require 'eww)
-    (eww (mapconcat #'identity
-                    (completing-read-multiple "Browse or search: "
-                                              eww-prompt-history
-                                              nil nil nil
-                                              'eww-prompt-history
-                                              (car (eww-suggested-uris)))
-                    " ")))
-#+end_src
-
-*** Use =eww= as the default web browser
-:PROPERTIES:
-:CUSTOM_ID: eww-browse-url-browser-function
-:CreatedAt: <2022-05-09 Mon>
-:CapturedAt: [[file:~/checkouts/emacs/nextstep/Emacs.app/Contents/Resources/lisp/net/browse-url.el.gz::setq browse-url-browser-function 'browse-url-w3]]
-:CapturedAs: Emacs configuration fragment
-:END:
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'browse-url
-    (setq browse-url-browser-function #'eww-browse-url))
-#+end_src
-
-** Proced
-:PROPERTIES:
-:CUSTOM_ID: proced-auto-update
-:CreatedAt: <2022-05-07 Sat>
-:CapturedAt: [[file:~/checkouts/protfiles/emacs/.emacs.d/prot-emacs.org::#h:6b56ce11-c84c-4b6d-98c7-bc3eefbe9325][file:~/checkouts/protfiles/emacs/.emacs.d/prot-emacs.org::#h:6b56ce11-c84c-4b6d-98c7-bc3eefbe9325]]
-:CapturedAs: Emacs configuration fragment
-:END:
-
-=proced.el= is an Elisp library built into Emacs that provides a
-listing of the currently running system processes.  The following code
-fragment hooks =proced= to set =proced-auto-update-flag= variable to
-=t= on startup, making =M-x proced= behave similarly to how =top(1)=
-does in the shell.
-
-#+begin_src emacs-lisp
-  (defun esy/setup-proced ()
-    "Setup `proced-mode' specific settings."
-    (setq proced-auto-update-flag t))
-
-  (add-hook 'proced-mode-hook #'esy/setup-proced)
-#+end_src
-
-** BBDB
-:PROPERTIES:
-:CUSTOM_ID: bbdb-phone-style-nil
-:END:
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'bbdb
-    (setq bbdb-phone-style nil))
-
-  (with-eval-after-load 'gnus
-    (bbdb-initialize 'gnus 'mail 'message))
-#+end_src
-
-** Slack
-:PROPERTIES:
-:CUSTOM_ID: slack
-:END:
-#+begin_src emacs-lisp
-  (defun esy/slack-start ()
-    (interactive)
-    (require 'slack)
-    (require 'auth-source)
-    (slack-register-team :name "Dazz"
-                         :default t
-                         :token (auth-source-pick-first-password
-                                 :host "dazz-io.slack.com"
-                                 :user "eshel")
-                         :cookie (auth-source-pick-first-password
-                                  :host "dazz-io.slack.com"
-                                  :user "eshel^cookie"))
-    (setq slack-prefer-current-team t
-          slack-buffer-emojify t)
-    (slack-start))
-#+end_src
-
-** EMMS
-:PROPERTIES:
-:CUSTOM_ID: emms
-:END:
-
-#+begin_src emacs-lisp
-  (emms-minimalistic)
-  (setq emms-player-list '(emms-player-mpv))
-#+end_src
-
-* Dutch to English translation with =define-word= and [[https://www.vertalen.nu/][vertalen.nu]]
-:PROPERTIES:
-:CUSTOM_ID: vertalen
-:END:
-
-#+begin_src emacs-lisp
-  (defun vertalen--on-success (&rest args)
-    "Process ARGS and display translation in a dedicated buffer."
-    (with-current-buffer-window "*vertalen*"
-        (with-selected-window (selected-window)
-          (unless (eq major-mode 'vertalen-mode)
-            `(nil . ((inhibit-same-window . t)))))
-        #'fit-window-to-buffer
-      (setq tabulated-list-entries (plist-get args :data))
-      (vertalen-mode)
-      (+ 2 (length tabulated-list-entries))))
-
-  (defun vertalen--parse ()
-    (require 'dom)
-    "Parse buffer and return a list of translations."
-    (let* ((dom (libxml-parse-html-region (point-min) (point-max)))
-           (res (dom-by-class dom ".*result-item-translations.*"))
-           (ret nil))
-      (dolist (elem res)
-        (setq ret
-              `((nil ,(vector
-                       (apply #'concat
-                              (dom-strings
-                               (car (dom-by-class
-                                     elem
-                                     ".*result-item-source.*"))))
-                       (mapconcat #'identity
-                                  (dom-strings
-                                   (car (dom-by-class
-                                         elem
-                                         ".*result-item-target.*")))
-                                  ", ")))
-                . ,ret)))
-      (reverse ret)))
-
-  (setq vertalen--source nil)
-  (setq vertalen-history nil)
-
-  (with-eval-after-load 'savehist
-    (add-to-list 'savehist-additional-variables
-                 'vertalen-history))
-
-  (defun vertalen (word)
-    "Translate WORD."
-    (interactive (list (read-string "Translate: " nil 'vertalen-history (thing-at-point 'word))))
-    (require 'request)
-    (setq vertalen--source word)
-    (request "https://www.vertalen.nu/vertaal"
-      :params `(("van" . "nl")
-                ("naar" . "en")
-                ("vertaal" . ,word))
-      :parser  #'vertalen--parse
-      :success #'vertalen--on-success))
-
-  (defun vertalen-at-point ()
-    "Translate word at point."
-    (interactive nil vertalen-mode)
-    (vertalen (thing-at-point 'word t)))
-
-  (defvar-keymap vertalen-mode-map
-    :doc "Keymap for `vertalen-mode' buffers."
-    "RET" #'vertalen-at-point)
-
-  (define-derived-mode vertalen-mode tabulated-list-mode "Vertalen"
-    "Major mode for listing Dutch to English translations."
-    (setq tabulated-list-format [("Source Language" 64 t)
-                                 ("Target Language" 32 t)])
-    (tabulated-list-init-header)
-    (tabulated-list-print)
-    (save-excursion
-      (goto-char (point-min))
-      (let ((inhibit-read-only t)
-            (word (search-forward vertalen--source nil t)))
-        (while word
-          (add-face-text-property (match-beginning 0) (match-end 0) 'success)
-          (setq word (search-forward vertalen--source nil t))))))
-#+end_src
-
-* Minibuffer and completions
-:PROPERTIES:
-:CUSTOM_ID: minibuffer-and-completions
-:END:
-
-** Enable and indicate recursive minibuffers
-:PROPERTIES:
-:CUSTOM_ID: recursive-minibuffers
-:END:
-
-#+begin_src emacs-lisp
-  (setq enable-recursive-minibuffers t)
-  (minibuffer-depth-indicate-mode)
-#+end_src
-
-** Completions
-:PROPERTIES:
-:CUSTOM_ID: completions
-:END:
-
-*** Completion at point
-:PROPERTIES:
-:CUSTOM_ID: completion-at-point
-:END:
-
-#+begin_src emacs-lisp
-  (defun esy/dabbrev-capf ()
-    "Workaround for issue with `dabbrev-capf'."
-    (require 'dabbrev)
-    (dabbrev--reset-global-variables)
-    (setq dabbrev-case-fold-search nil)
-    (dabbrev-capf))
-
-  (defun esy/file-capf ()
-    "File completion at point function."
-    (let ((bs (bounds-of-thing-at-point 'filename)))
-      (when bs
-        (let* ((start (car bs))
-               (end   (cdr bs)))
-          `(,start ,end completion--file-name-table . (:exclusive no))))))
-
-  (defun esy/margin-formatter (metadata)
-    "Margin formatter for `corfu-margin-formatters'."
-    (pcase (cdr (assoc 'category metadata))
-      ('file (lambda (string)
-               (concat (if (string-suffix-p "/" string)
-                           (all-the-icons-icon-for-dir string)
-                         (all-the-icons-icon-for-file string))
-                       " ")))
-      ('dabbrev (lambda (_) "… "))))
-
-  (setq corfu-cycle t
-        corfu-margin-formatters '(esy/margin-formatter)
-        corfu-indexed-start     1)
-  (global-corfu-mode)
-  (corfu-indexed-mode 1)
-  (add-to-list 'completion-at-point-functions #'esy/dabbrev-capf)
-  (add-to-list 'completion-at-point-functions #'esy/file-capf)
-#+end_src
-
-*** Minibuffer-based completions
-:PROPERTIES:
-:CUSTOM_ID: minibuffer-completion
-:END:
-
-#+begin_src emacs-lisp
-  (setq read-extended-command-predicate #'command-completion-default-include-p
-        completions-format 'one-column
-        completion-auto-select nil
-        completions-detailed nil
-        completion-styles '(orderless partial-completion basic)
-        completion-show-help nil
-        completions-header-format (propertize "%s candidates:\n"
-                                              'face 'shadow)
-        completion-auto-help 'visual
-        completions-max-height 16
-        completion-auto-wrap t)
-  (define-key minibuffer-local-completion-map
-              [remap previous-line]
-              #'minibuffer-previous-completion)
-  (define-key minibuffer-local-completion-map
-              [remap next-line]
-              #'minibuffer-next-completion)
-  (add-hook 'marginalia-mode-hook
-            #'all-the-icons-completion-marginalia-setup)
-  (marginalia-mode)
-  (add-to-list 'display-buffer-alist
-               '("\\*Completions\\*"
-                 (display-buffer-reuse-window display-buffer-at-bottom)
-                 (window-parameters . ((mode-line-format . none)))))
-  (add-to-list 'all-the-icons-extension-icon-alist
-               '("pl" all-the-icons-alltheicon "prolog"
-                 :height 1.1 :face all-the-icons-lmaroon))
-#+end_src
-
-* Mode-line customizations
-:PROPERTIES:
-:CUSTOM_ID: modeline
-:END:
-
-#+begin_src emacs-lisp
-  (setq display-time-mail-function (lambda () nil))
-  (display-time-mode)
-  (column-number-mode)
-  (display-battery-mode)
-  #+end_src
-
-* Text mode and derivatives
-:PROPERTIES:
-:CUSTOM_ID: text-mode
-:END:
-#+begin_src emacs-lisp
-  (add-hook 'text-mode-hook #'flyspell-mode)
-
-  (with-eval-after-load 'flyspell
-    (keymap-unset flyspell-mode-map "C-," t)
-    (keymap-unset flyspell-mode-map "C-." t)
-    (keymap-unset flyspell-mode-map "C-;" t))
-#+end_src
-
-* LaTeX and PDF settings
-:PROPERTIES:
-:CUSTOM_ID: latex-and-pdf
-:END:
-
-#+begin_src emacs-lisp
-  (pdf-tools-install t)
-  (add-hook 'pdf-view-mode-hook #'pdf-view-midnight-minor-mode)
-  (setq TeX-view-program-selection '((output-pdf "PDF Tools"))
-        TeX-source-correlate-start-server t)
-  (add-to-list 'revert-without-query "\\.pdf\\'")
-  (add-hook 'TeX-after-compilation-finished-functions
-            #'TeX-revert-document-buffer)
-  (add-to-list 'auto-mode-alist '("\\.pdf\\'" . pdf-view-mode))
-#+end_src
-
-* Programming
-:PROPERTIES:
-:CUSTOM_ID: programming
-:END:
-
-** Compilation
-:PROPERTIES:
-:CUSTOM_ID: compilation
-:END:
-
-#+begin_src emacs-lisp
-  (setq safe-local-variable-values
-        '((compilation-read-command . nil)))
-#+end_src
-
-** General =prog-mode= settings
-:PROPERTIES:
-:CUSTOM_ID: prog-mode
-:END:
-
-#+begin_src emacs-lisp
-  (defun esy/setup-programming ()
-    "Setup `prog-mode' and more programming-related settings."
-    (require 'rainbow-delimiters)
-    (require 'flymake)
-    (rainbow-delimiters-mode)
-    (display-line-numbers-mode)
-    (display-fill-column-indicator-mode)
-    (flymake-mode))
-
-  (add-hook 'prog-mode-hook #'esy/setup-programming)
-#+end_src
-
-** Lisp specific settings
-:PROPERTIES:
-:CUSTOM_ID: lisp
-:END:
-
-*** Paredit
-:PROPERTIES:
-:CUSTOM_ID: paredit
-:END:
-
-Enable =paredit-mode= in =lisp-data-mode= and its derivatites, which
-include =emacs-lisp-mode= and =lisp-interaction-mode=.
-
-#+begin_src emacs-lisp
-  (defun esy/setup-lisp ()
-    "Setup Lisp specific settings."
-    (require 'paredit)
-    (enable-paredit-mode))
-
-  (add-hook 'lisp-data-mode-hook #'esy/setup-lisp)
-#+end_src
-
-** Haskell specific settings
-:PROPERTIES:
-:CUSTOM_ID: haskell
-:END:
-
-#+begin_src emacs-lisp
-  (add-hook 'haskell-mode-hook #'interactive-haskell-mode)
-  (add-hook 'haskell-mode-hook #'haskell-decl-scan-mode)
-  (add-hook 'haskell-mode-hook #'haskell-doc-mode)
-#+end_src
-
-** Prolog specific settings
-:PROPERTIES:
-:CUSTOM_ID: prolog
-:END:
-
-*** Setup =sweep=
-:PROPERTIES:
-:CUSTOM_ID: setup-sweep
-:END:
-
-#+begin_src emacs-lisp
-  (require 'use-package)
-
-  (use-package sweeprolog
-    :mode ("\\.plt?\\'" . sweeprolog-mode)
-    :bind-keymap ("C-c p" . sweeprolog-prefix-map)
-    :config
-    (add-hook 'sweeprolog-mode-hook #'sweeprolog-electric-layout-mode)
-    (add-hook 'sweeprolog-top-level-mode-hook
-              #'compilation-shell-minor-mode))
-#+end_src
-
-*** Make =rg= regard =.pl= files as Prolog rather than Perl
-:PROPERTIES:
-:CUSTOM_ID: rg-pl-is-prolog-not-perl
-:END:
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'rg
-    (add-to-list 'rg-custom-type-aliases '("Prolog" . "*.pl *.plt *.pro *.prolog")))
-#+end_src
-
-** Dockerfile
-:PROPERTIES:
-:CUSTOM_ID: dockerfile
-:END:
-
-#+begin_src emacs-lisp
-  (add-to-list 'auto-mode-alist '("Dockerfile" . dockerfile-ts-mode))
-#+end_src
-
-** YAML
-:PROPERTIES:
-:CUSTOM_ID: yaml
-:END:
-
-#+begin_src emacs-lisp
-  (add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode))
-#+end_src
-
-** JSON
-:PROPERTIES:
-:CUSTOM_ID: json
-:END:
-
-#+begin_src emacs-lisp
-  (add-to-list 'auto-mode-alist '("\\.json\\'" . json-ts-mode))
-#+end_src
-
-** Rust
-:PROPERTIES:
-:CUSTOM_ID: rust
-:END:
-
-#+begin_src emacs-lisp
-  (add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
-#+end_src
-
-** Go
-:PROPERTIES:
-:CUSTOM_ID: go
-:END:
-
-#+begin_src emacs-lisp
-  (add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
-#+end_src
-
-** Terraform
-:PROPERTIES:
-:CUSTOM_ID: terraform
-:END:
-
-#+begin_src emacs-lisp
-  (use-package terraform-mode
-    :config
-    (setq terraform--resource-name-face font-lock-function-name-face
-          terraform--resource-type-face font-lock-type-face))
-#+end_src
-
-* =vc= customizations
-:PROPERTIES:
-:CUSTOM_ID: vc-follow-symlinks-t
-:END:
-
-By default, Emacs asks for confirmation when visiting a path that
-points to symlink to a file committed to version control. I often
-visit this file with =C-x C-f ~/.emacs.d/esy.org=, which is a symlink
-to the actual source of this file which is managed by git and Stow, so
-in this cases I prefer Emacs to trust me that I know what I'm doing
-without asking each time.
-
-#+begin_src emacs-lisp
-  (setq vc-follow-symlinks t)
-#+end_src
-
-* Project management
-:PROPERTIES:
-:CUSTOM_ID: project-management
-:END:
-** Populate project list from my projects directory
-:PROPERTIES:
-:CUSTOM_ID: remember-projects-under-directory
-:END:
-
-#+begin_src emacs-lisp
-  (defconst esy/projects-directory "~/checkouts/"
-    "Path of the projects directory.")
-
-  (add-hook 'kill-emacs-hook
-            (lambda ()
-              (require 'project)
-              (mapcar #'project-remember-projects-under
-                      (directory-files
-                       esy/projects-directory))))
-#+end_src
-
-** Project switch commands
-:PROPERTIES:
-:CUSTOM_ID: project-switch-commands
-:END:
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'project
-    (add-to-list 'project-switch-commands '(project-compile "Compile"))
-    (add-to-list 'project-switch-commands '(rg-project "rg"))
-    (add-to-list 'project-switch-commands '(magit-project-status "Magit"))
-    (add-to-list 'project-switch-commands '(project-shell "Shell"))
-    (when (boundp 'project-prefix-map)
-      (define-key project-prefix-map "R" #'rg-project)
-      (define-key project-prefix-map "m" #'magit-project-status)))
-#+end_src
-
-* =shell= customizations
-:PROPERTIES:
-:CUSTOM_ID: shell
-:END:
-
-** Kill =shell= buffers on exit
-:PROPERTIES:
-:CUSTOM_ID: shell-kill-on-exit
-:END:
-Kill =M-x shell= buffers automatically when the shell process
-terminates, e.g. when pressing =C-d=.
-
-#+begin_src emacs-lisp
-  (setq shell-kill-buffer-on-exit t)
-#+end_src
-
-** Restart async shell process                                     :cmd:kbd:
-:PROPERTIES:
-:CUSTOM_ID: shell-restart-process
-:CreatedAt: <2022-07-01 Fri>
-:CapturedAt:
-:CapturedAs: Emacs configuration fragment
-:END:
-
-#+begin_src emacs-lisp
-  (defun shell-restart-process ()
-    "Restart process of `shell-mode' buffer."
-    (interactive)
-    (let* ((proc (get-buffer-process (current-buffer)))
-           (pid  (process-id proc))
-           (cmd  (caddr (process-command proc))))
-      (message "%s" cmd)
-      (delete-process proc)
-      (async-shell-command cmd)))
-
-  (with-eval-after-load 'shell
-    (keymap-set shell-mode-map "C-c C-k" #'shell-restart-process)
-    (keymap-set shell-mode-map "SPC" #'comint-magic-space))
-#+end_src
-
-** Save logs of =comint= buffers                                   :cmd:kbd:
-:PROPERTIES:
-:CUSTOM_ID: comint-log-buffer
-:CreatedAt: <2022-07-13 Wed>
-:CapturedAt:
-:CapturedAs: Emacs configuration fragment
-:END:
-
-#+begin_src emacs-lisp
-  (defvar esy/logs-directory "~/logs"
-    "Directory where some log files will be saved.")
-
-  (defvar-local esy/log-buffer-filename nil
-    "File in which the current buffer is logged.")
-
-  (defun esy/log-buffer ()
-    "Save the current buffer under `esy/logs-directory'."
-    (interactive)
-    (let ((filename (or esy/log-buffer-filename
-                        (setq esy/log-buffer-filename
-                              (expand-file-name
-                               (concat mode-name
-                                       "_"
-                                       (format-time-string
-                                        "%Y%m%d%H%M%S"
-                                        (current-time))
-                                       ".log")
-                               esy/logs-directory)))))
-      (save-restriction
-        (widen)
-        (write-region (point-min)
-                      (point-max)
-                      filename))))
-
-  (with-eval-after-load 'comint
-    (keymap-set comint-mode-map "C-c C-q" #'esy/log-buffer))
-#+end_src
-
-* Misc. settings
-:PROPERTIES:
-:CUSTOM_ID: misc
-:END:
-
-#+begin_src emacs-lisp
-  (setq global-auto-revert-non-file-buffers t
-        auto-revert-verbose nil
-        query-about-changed-file t
-        kill-do-not-save-duplicates t
-        show-trailing-whitespace t)
-  (global-auto-revert-mode)
-  (global-whitespace-cleanup-mode 1)
-#+end_src
-
-** Enable ~embark-consult~
-
-This is a little companion library for ~embark~ that makes ~embark-export~
-and friends work correctly with ~consult~ enabled completions.
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'consult
-    (with-eval-after-load 'embark
-      (require 'embark-consult)))
-#+end_src
-
-** Add a repeat-map to =tranpose-lines=
-:PROPERTIES:
-:CUSTOM_ID: repeat-transpose-lines
-:END:
-
-#+begin_src emacs-lisp
-  (defvar-keymap transpose-lines-repeat-map
-    :doc "Repeat map for \\[transpose-lines]"
-    "C-t" #'transpose-lines)
-
-  (put 'transpose-lines 'repeat-map 'transpose-lines-repeat-map)
-#+end_src
-
-** Use =consult= to show =xref= results
-:PROPERTIES:
-:CUSTOM_ID: consult-xref
-:END:
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'xref
-    (setq xref-show-definitions-function #'consult-xref
-          xref-show-xrefs-function       #'consult-xref
-          xref-search-program             'ripgrep))
-#+end_src
-
-** Show the time in Amsterdam in =world-clock=
-:PROPERTIES:
-:CUSTOM_ID: world-clock-amsterdam
-:CreatedAt: <2022-05-12 Thu>
-:CapturedAt: [[file:~/checkouts/dotfiles/.emacs.d/esy.org::#footer][file:~/checkouts/dotfiles/.emacs.d/esy.org::#footer]]
-:CapturedAs: Emacs configuration fragment
-:END:
-
-Add the timezones of places of interest to the list of clocks shown by
-=M-x world-clock=. The list of named timezones is maintained by [[https://www.iana.org/time-zones][IANA]].
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'time
-    (add-to-list 'zoneinfo-style-world-list '("Europe/Amsterdam" "Amsterdam")))
-#+end_src
-
-** Restart async shell process in =process-menu-mode=    :cmd:kbd:
-:PROPERTIES:
-:CUSTOM_ID: process-menu-restart-process
-:CreatedAt: <2022-07-01 Fri>
-:CapturedAt:
-:CapturedAs: Emacs configuration fragment
-:END:
-
-#+begin_src emacs-lisp
-  (defun process-menu-restart-process ()
-    "Restart process at point in a `list-processes' buffer."
-    (interactive)
-    (let* ((pos (point))
-           (pid (tabulated-list-get-id))
-           (ent (tabulated-list-get-entry))
-           (cmd (combine-and-quote-strings
-                 (seq-drop (split-string-shell-command (seq-elt ent 6))
-                           2))))
-      (delete-process pid)
-      (async-shell-command cmd)
-      (revert-buffer)))
-
-  (with-eval-after-load 'simple
-    (keymap-set process-menu-mode-map
-                "r"
-                #'process-menu-restart-process))
-#+end_src
-
-** Enable =repeat-mode=
-:PROPERTIES:
-:CUSTOM_ID: repeat-mode
-:END:
-
-#+begin_src emacs-lisp
-  (repeat-mode)
-#+end_src
-
-** Sibling files
-:PROPERTIES:
-:CUSTOM_ID: find-sibling
-:END:
-#+begin_src emacs-lisp
-  (setq find-sibling-rules '(("\\([^/]+\\)\\.c\\'" "\\1.h")))
-#+end_src
-
-** Small command for converting Unix timestamps to date strings
-
-#+begin_src emacs-lisp
-  (defun esy/seconds-to-date-string (seconds)
-    (interactive (list (if (use-region-p)
-                           (string-to-number (buffer-substring (region-beginning)
-                                                               (region-end)))
-                         (read-number "Unix timestamp: " (round (float-time))))))
-    (message (format-time-string "%FT%T%z" (seconds-to-time seconds))))
-#+end_src
-
-
-** Predefined SQL connections
-:PROPERTIES:
-:CUSTOM_ID: predefined-sql-connections
-:CreatedAt: <2022-08-11 Thu>
-:CapturedAt: [[file:~/tmp/foo.el]]
-:CapturedAs: Emacs configuration fragment
-:END:
-
-#+begin_src emacs-lisp
-  (with-eval-after-load 'sql
-    (setq sqlformat-command 'pgformatter)
-    (define-key sql-mode-map (kbd "C-c C-f") 'sqlformat)
-    (setq sql-input-ring-file-name (expand-file-name ".sqli-history"
-                                                     no-littering-var-directory))
-    (setq sql-connection-alist
-          (let* ((a (auth-source-search :port 5432
-                                        :max  5
-                                        :require '(:user :port :secret :host)))
-                 (d (nth 0 a))
-                 (p (nth 1 a))
-                 (c (nth 2 a))
-                 (e (nth 3 a))
-                 (f (nth 4 a)))
-            `((dev
-               (sql-product 'postgres)
-               (sql-user ,(plist-get d :user))
-               (sql-port 5432)
-               (sql-password ,(funcall (plist-get d :secret)))
-               (sql-server ,(plist-get d :host))
-               (sql-database "alerts"))
-              (prod
-               (sql-product 'postgres)
-               (sql-user ,(plist-get p :user))
-               (sql-port 5432)
-               (sql-password ,(funcall (plist-get p :secret)))
-               (sql-server ,(plist-get p :host))
-               (sql-database "alerts"))
-              (cgs
-               (sql-product 'postgres)
-               (sql-user ,(plist-get c :user))
-               (sql-port 5432)
-               (sql-password ,(funcall (plist-get c :secret)))
-               (sql-server ,(plist-get c :host))
-               (sql-database "container_graph"))
-              (ten
-               (sql-product 'postgres)
-               (sql-user ,(plist-get e :user))
-               (sql-port 5432)
-               (sql-password ,(funcall (plist-get e :secret)))
-               (sql-server ,(cadr (split-string (plist-get e :host)  (rx "^"))))
-               (sql-database ,(car (split-string (plist-get e :host) (rx "^")))))
-              (ac
-               (sql-product 'postgres)
-               (sql-user ,(plist-get f :user))
-               (sql-port 5432)
-               (sql-password ,(funcall (plist-get f :secret)))
-               (sql-server ,(cadr (split-string (plist-get f :host)  (rx "^"))))
-               (sql-database ,(car (split-string (plist-get f :host) (rx "^"))))))))
-
-    (define-advice sql-comint-postgres (:around (fun &rest args) use-sql-password)
-      (let ((process-environment
-             (nconc
-              (list (format "PGPASSWORD=%s" sql-password))
-              process-environment)))
-        (apply fun args))))
-#+end_src
-
-* Elisp Footer
-:PROPERTIES:
-:CUSTOM_ID: footer
-:END:
-
-#+begin_src emacs-lisp
-  (provide 'esy)
-  ;;; esy.el ends here
-#+end_src
index e30eabf54f1cd834c91ef769d2c96bfc3d812587..960a665f021b2f6e7326de0b7a14ed2830617f2d 100644 (file)
-;;; init.el --- Load the full configuration -*- lexical-binding: t -*-
+;;; init.el --- Personal Emacs configuration -*- lexical-binding: t -*-
+;; Copyright (C) 2021-2023 Eshel Yaron
+
+;; Author: Eshel Yaron <eshelshay.yaron@gmail.com>
+;; URL: https://eshelyaron.com/esy.html
+
+;; This file is free software: you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published by the
+;; Free Software Foundation, either version 3 of the License, or (at
+;; your option) any later version.
+
+;; This file is distributed in the hope that it will be useful, but
+;; WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+;; General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with this file.  If not, see <http://www.gnu.org/licenses/>.
+
 ;;; Commentary:
 
+;; My personal Emacs configuration
+
 ;;; Code:
 
-;; (require 'benchmark-init)
-;; (add-hook 'after-init-hook 'benchmark-init/deactivate)
+(let ((normal-gc-cons-threshold (* 20 1024 1024))
+      (init-gc-cons-threshold (* 1024 1024 1024)))
+  (setq gc-cons-threshold init-gc-cons-threshold)
+  (add-hook 'emacs-startup-hook
+            (lambda () (setq gc-cons-threshold normal-gc-cons-threshold))))
 
-(let ((esy (expand-file-name (locate-user-emacs-file "esy"))))
-  (or (load esy t t nil t)
-      (progn
-        (require 'org)
-        (org-babel-load-file (concat esy ".org") t))))
+(require 'comp)
+(setq
+ ;; silence native compilation warnings
+ native-comp-async-report-warnings-errors 'silent
+ ;; only display the warning buffer if something's really broken
+ warning-minimum-level :error)
 
-(provide 'init)
-;;; init.el ends here
+(require 'package)
+(setq
+ ;; make some space in the Packages menu
+ package-archive-column-width 12
+ package-version-column-width 28
+ ;; select some packages to install
+ package-selected-packages
+ '(
+   all-the-icons
+   all-the-icons-completion
+   all-the-icons-dired
+   all-the-icons-gnus
+   auctex
+   auctex-latexmk
+   avy
+   bbdb
+   corfu
+   define-word
+   denote
+   devdocs
+   diff-hl
+   ef-themes
+   elfeed
+   embark-consult
+   emms
+   gnu-elpa-keyring-update
+   gnuplot
+   graphviz-dot-mode
+   graphql-mode
+   haskell-mode
+   htmlize
+   ialign
+   jenkinsfile-mode
+   keycast
+   kubernetes
+   lin
+   magit
+   marginalia
+   markdown-mode
+   mastodon
+   no-littering
+   ob-prolog
+   orderless
+   org-modern
+   package-lint
+   paredit
+   pdf-tools
+   rainbow-delimiters
+   rainbow-mode
+   request
+   rg
+   slack
+   smtpmail-multi
+   sqlformat
+   typit
+   terraform-mode
+   vterm
+   vundo
+   whitespace-cleanup-mode
+   with-editor
+   ))
+
+(add-to-list 'package-archives
+             '("melpa" . "http://melpa.org/packages/"))
+(add-to-list 'package-archives
+             '("elpa-devel" . "https://elpa.gnu.org/devel/"))
+
+(package-install-selected-packages)
+
+(require 'no-littering)
+
+(setq auto-save-file-name-transforms
+      `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))
+
+(setq custom-file (no-littering-expand-etc-file-name "custom.el"))
+(load custom-file 'noerror 'nomessage)
+
+(when (fboundp 'startup-redirect-eln-cache)
+  (startup-redirect-eln-cache
+   (convert-standard-filename
+    (expand-file-name  "var/eln-cache/" user-emacs-directory))))
+
+(add-to-list 'load-path (expand-file-name  "lisp/" user-emacs-directory))
+
+(add-to-list 'initial-frame-alist '(fullscreen . fullboth))
+
+(set-face-attribute 'default nil
+                    :height 130
+                    :family "Iosevka")
+
+(set-face-attribute 'fixed-pitch nil
+                    :family "Iosevka")
+
+(set-face-attribute 'variable-pitch nil
+                    :family "Iosevka Etoile")
+
+(setq ef-themes-mixed-fonts       t
+      ef-themes-variable-pitch-ui t
+      ef-themes-to-toggle         '(ef-bio ef-day))
+(mapc #'disable-theme custom-enabled-themes)
+(load-theme 'ef-bio :no-confirm)
+
+(tool-bar-mode -1)
+(set-scroll-bar-mode nil)
+
+(setq use-dialog-box nil
+      inhibit-startup-screen t
+      initial-scratch-message ";; Go.\n"
+      ring-bell-function 'ignore
+      switch-to-buffer-obey-display-actions t)
+
+(setq-default indent-tabs-mode nil)
+
+(context-menu-mode)
+
+(pixel-scroll-precision-mode)
+
+(global-diff-hl-mode)
+
+(transient-mark-mode)
+
+(mouse-avoidance-mode 'banish)
+
+(show-paren-mode)
+
+(setq display-time-mail-function (lambda () nil))
+
+(display-time-mode)
+
+(column-number-mode)
+
+(display-battery-mode)
+
+(setq enable-recursive-minibuffers t)
+(minibuffer-depth-indicate-mode)
+
+(require 'lin)
+(add-to-list 'lin-mode-hooks 'gnus-summary-mode-hook)
+(add-to-list 'lin-mode-hooks 'gnus-group-mode-hook)
+(add-to-list 'lin-mode-hooks 'gnus-server-mode-hook)
+(lin-global-mode 1)
+
+(add-hook 'completion-list-mode-hook
+            (lambda ()
+              (setq-local cursor-in-non-selected-windows nil)))
+
+(recentf-mode 1)
+
+(save-place-mode 1)
+
+(setq bookmark-save-flag 1)
+
+(require 'savehist)
+(add-to-list 'savehist-additional-variables
+             'log-edit-comment-ring)
+(savehist-mode 1)
+
+(defconst esy/inbox-path (expand-file-name "inbox.org" "~/org")
+  "Path to my Org mode inbox file.")
+
+(defconst esy/journal-path (expand-file-name "journal.org" "~/org")
+  "Path to my Org mode journal file.")
+
+(with-eval-after-load 'org
+  (require 'ob)
+  (require 'ob-prolog)
+  (require 'ob-sql)
+  (require 'org-tempo)
+  (setq org-agenda-files `(,esy/inbox-path ,esy/journal-path)
+        org-default-notes-file esy/inbox-path
+        org-agenda-start-on-weekday 0
+        org-ellipsis "…"
+        org-use-speed-commands t
+        org-todo-keywords '((sequence
+                             "TODO(t)"
+                             "BLOCKED(b@/!)"
+                             "INPROGRESS(i!)"
+                             "|"
+                             "DONE(d!)"
+                             "CANCELED(c@)"))
+        org-tag-alist '((:startgroup)
+                        ("work"     . ?w)
+                        ("studies"  . ?s)
+                        ("esols"    . ?e)
+                        ("personal" . ?p)
+                        (:endgroup))
+        org-babel-load-languages '((emacs-lisp . t)
+                                   (shell      . t)
+                                   (sql        . t)
+                                   (bnf        . t)
+                                   (prolog     . t))
+        org-confirm-babel-evaluate nil
+        org-log-done 'time
+        org-log-into-drawer t
+        org-fast-tag-selection-single-key 'expert
+        org-use-fast-todo-selection 'expert
+        org-clock-in-switch-to-state "INPROGRESS")
+  (add-to-list 'org-src-lang-modes '("prolog" . sweeprolog))
+  (keymap-unset org-mode-map "C-," t))
+
+(with-eval-after-load 'org-agenda
+  (add-to-list 'org-agenda-custom-commands
+               '("w" "Work TODOs" tags-todo "+work")))
+
+(setq org-file-apps '((t . emacs)))
+
+(with-eval-after-load 'org-refile
+  (setq org-refile-targets '((org-agenda-files . (:maxlevel . 5))
+                             (nil . (:maxlevel . 3)))
+        org-archive-location "~/org/journal.org::datetree/* Finished Tasks                                              :ARCHIVE"
+        org-refile-use-outline-path t))
+
+(defun esy/org-fill-custom-id (point value)
+  "Set CUSTOM_ID to VALUE interactively for the entry at POINT."
+  (interactive "d\nMCUSTOM_ID: ")
+  (org-entry-put point "CUSTOM_ID" value))
+
+(defun esy/org-fill-description (point value)
+  "Set DESCRIPTION to VALUE interactively for the entry at POINT."
+  (interactive "d\nMDESCRIPTION: ")
+  (org-entry-put point "DESCRIPTION" value))
+
+(defun esy/org-maybe-prompt-custom-id ()
+  "Prompt for CUSTOM_ID if not set for the entry at POINT."
+  (let ((res 0))
+    (unless (and (org-entry-get (point) "DESCRIPTION")
+                 (org-entry-get (point) "CUSTOM_ID"))
+      (pulse-momentary-highlight-one-line)
+      (org-cycle)
+      (unless (org-entry-get (point) "CUSTOM_ID")
+        (call-interactively #'esy/org-fill-custom-id)
+        (setq res (1+ res)))
+      (unless (org-entry-get (point) "DESCRIPTION")
+        (call-interactively #'esy/org-fill-description)
+        (setq res (1+ res)))
+      (org-global-cycle 1))
+    res))
+
+(defun esy/org-fill-custom-ids-in-buffer ()
+  "Visit headers in the current buffer and set CUSTOM_ID for each."
+  (interactive)
+  (org-global-cycle 1)
+  (message "Filled %d properties."
+           (apply #'+ (remove nil
+                           (org-map-entries
+                            #'esy/org-maybe-prompt-custom-id)))))
+
+(defun esy/org-capture-to-project-heading ()
+  "Prompt for a projects and capture a related task."
+  (let* ((projects
+          (org-map-entries `(lambda () (nth 4 (org-heading-components)))
+                           "+project+LEVEL=2" `(,esy/inbox-path)))
+         (choice (completing-read "Project: " projects nil t nil))
+         (m (org-find-olp (cons
+                           (org-capture-expand-file esy/inbox-path)
+                           (list "Projects" choice)))))
+    (set-buffer (marker-buffer m))
+    (org-capture-put-target-region-and-position)
+    (widen)
+    (goto-char m)
+    (set-marker m nil)))
+
+(defun esy/org-capture-to-current-project ()
+  "Prompt for a projects and capture a related task."
+  (let* ((projects
+          (org-map-entries (lambda () (nth 4 (org-heading-components)))
+                           (concat "+project+LEVEL=2+SCM=\"file:"
+                                   (project-root (with-current-buffer
+                                                     (org-capture-get :original-buffer)
+                                                   (project-current)))
+                                   "\"")
+                           (list esy/inbox-path)))
+         (choice (car projects))
+         (m (org-find-olp (cons
+                           (org-capture-expand-file esy/inbox-path)
+                           (list "Projects" choice)))))
+    (set-buffer (marker-buffer m))
+    (org-capture-put-target-region-and-position)
+    (widen)
+    (goto-char m)
+    (set-marker m nil)))
+
+(setq org-capture-templates '(("t" "Todo [inbox]" entry
+                               (file+headline esy/inbox-path "Tasks")
+                               "** TODO %^{Task}    %^g
+:PROPERTIES:
+:CreatedAt: %u
+:CapturedAt: %a
+:CapturedAs: Inbox Task
+:END:"
+                               :prepend t
+                               :empty-lines 1
+                               :immediate-finish t)
+                              ("w" "Work [inbox]" entry
+                               (file+headline esy/inbox-path "Tasks")
+                               "** TODO %^{Task}    :work:
+:PROPERTIES:
+:CreatedAt: %u
+:CapturedAt: %a
+:CapturedAs: Work Task
+:END:"
+                               :prepend t
+                               :empty-lines 1
+                               :immediate-finish t)
+                              ("c" "New Calendar Event" entry
+                               (file+headline esy/inbox-path "Calendar")
+                               "** %^{Title}    %^g
+:PROPERTIES:
+:CreatedAt: %u
+:CapturedAt: %a
+:CapturedAs: Calendar Event
+:END:
+%(format-time-string \"<%Y-%m-%d %H:%M\" (org-read-date t t))-%(format-time-string \"%H:%M>\" (org-read-date t t))
+%i"
+                               :prepend t
+                               :empty-lines 1
+                               :immediate-finish t)
+                              ("j" "Journal" entry
+                               (file+datetree esy/journal-path)
+                               "* %?
+:PROPERTIES:
+:CreatedAt: %u
+:CapturedAt: %a
+:CaptuerdAs: Journal entry
+:END:
+%i"
+                               :empty-lines 1)))
+
+(setq org-capture-templates-contexts
+      '(("P" (list project-current))))
+
+(setq user-full-name "Eshel Yaron")
+(setq user-mail-address "me@eshelyaron.com")
+
+(defconst esy/user-mail-address-gmail "eshelshay.yaron@gmail.com"
+  "My personal Gmail address.")
+
+(defconst esy/user-mail-address-swipl "eshel@swi-prolog.org"
+  "My SWI-Prolog email address.")
+
+(defconst esy/user-mail-address-me "me@eshelyaron.com"
+  "My persomal email address.")
+
+(defun esy/smtpmail-multi-make-accout (address server)
+  "Return an SMTP account definition for ADDRESS in SERVER."
+  `(,address ,server 587 ,address starttls nil nil nil))
+
+(defun esy/smtpmail-multi-make-rx (address)
+  "Return a regexp that matches ADDRESS wrapped with anything."
+  (rx (* anything) (literal address) (* anything)))
+
+(with-eval-after-load 'gnus
+  (require 'smtpmail-multi)
+  (require 'gnus-icalendar)
+  (require 'all-the-icons-gnus)
+
+  (setq smtpmail-multi-accounts
+        `((esy . ,(esy/smtpmail-multi-make-accout
+                   esy/user-mail-address-gmail
+                   "smtp.gmail.com"))
+          (swp . ,(esy/smtpmail-multi-make-accout
+                   esy/user-mail-address-swipl
+                   "mail.swi-prolog.com"))
+          (me  . ,(esy/smtpmail-multi-make-accout
+                   esy/user-mail-address-me
+                   "mail.eshelyaron.com")))
+        smtpmail-multi-associations
+        `((,(esy/smtpmail-multi-make-rx esy/user-mail-address-gmail) esy)
+          (,(esy/smtpmail-multi-make-rx esy/user-mail-address-swipl) swp)
+          (,(esy/smtpmail-multi-make-rx esy/user-mail-address-me) me))
+        send-mail-function #'smtpmail-multi-send-it
+        message-send-mail-function #'smtpmail-multi-send-it
+        mail-user-agent 'gnus-user-agent
+        gnus-always-read-dribble-file t
+        gnus-expert-user t
+        gnus-break-pages nil
+        gnus-inhibit-startup-message t
+        gnus-select-method '(nnimap "gmail"
+                                    (nnimap-address "imap.gmail.com")
+                                    (nnimap-server-port "imaps")
+                                    (nnimap-stream ssl))
+        gnus-secondary-servers '((nnimap "me"
+                                         (nnimap-address "mail.eshelyaron.com")
+                                         (nnimap-server-port "imaps")
+                                         (nnimap-stream ssl)
+                                         (nnimap-authinfo-file "~/.authinfo")))
+        gnus-no-groups-message "No new articles"
+        gnus-use-full-window nil
+        gnus-article-treat-types '("text/plain"
+                                   "text/x-verbatim"
+                                   "text/x-patch"
+                                   "text/html"
+                                   "text/calendar")
+        gnus-posting-styles `((".*eshelyaron.com.*"
+                               (address ,esy/user-mail-address-me))
+                              (".*mail.swi-prolog.com.*"
+                               (address ,esy/user-mail-address-swipl))
+                              (".*"
+                               (address ,esy/user-mail-address-gmail)))
+        gnus-icalendar-org-capture-file esy/inbox-path
+        gnus-icalendar-org-capture-headline '("Calendar")
+        calendar-date-style 'iso)
+
+  (add-hook 'gnus-group-mode-hook #'gnus-topic-mode)
+  (gnus-icalendar-setup)
+  (gnus-icalendar-org-setup)
+  (all-the-icons-gnus-setup)
+  (bbdb-initialize 'gnus 'mail 'message))
+
+(defun esy/find-init-file (init)
+  (interactive (list user-init-file))
+  (find-file init))
+
+(defun esy/kill-dwim ()
+  "When region is active, kill region, otherwise kill last word."
+  (interactive)
+  (if (region-active-p)
+      (let ((beg (region-beginning))
+            (end (region-end)))
+        (kill-region beg end))
+    (let ((end (point)))
+      (backward-word)
+      (kill-region (point) end))))
+
+(defun esy/pulse-line (&optional _)
+  "Pulse current line."
+  (interactive)
+  (pulse-momentary-highlight-one-line))
+
+(keymap-global-set "C-c w" #'esy/eww)
+(keymap-global-set "C-c c" #'org-capture)
+(keymap-global-set "C-c l" #'org-store-link)
+(keymap-global-set "C-c a" #'org-agenda)
+(keymap-global-set "C-c !" #'consult-flymake)
+(keymap-global-set "C-c C" #'openai-chat)
+(keymap-global-set "C-c D" #'denote)
+(keymap-global-set "C-c E" #'elfeed)
+(keymap-global-set "C-c G" #'gnus)
+(keymap-global-set "C-c M" #'mastodon)
+(keymap-global-set "C-c V" #'vertalen-at-point)
+(keymap-global-set "C-c F" #'esy/find-init-file)
+(keymap-global-unset "s-a")
+(keymap-global-unset "s-d")
+(keymap-global-unset "s-e")
+(keymap-global-unset "s-f")
+(keymap-global-unset "s-g")
+(keymap-global-unset "s-h")
+(keymap-global-unset "s-j")
+(keymap-global-unset "s-k")
+(keymap-global-unset "s-l")
+(keymap-global-unset "s-m")
+(keymap-global-unset "s-o")
+(keymap-global-unset "s-q")
+(keymap-global-unset "s-s")
+(keymap-global-unset "s-t")
+(keymap-global-unset "s-u")
+(keymap-global-unset "s-w")
+(keymap-global-unset "s-x")
+(keymap-global-unset "s-y")
+(keymap-global-unset "s-z")
+(keymap-global-set "<remap> <kill-region>" #'esy/kill-dwim)
+(keymap-global-set "<remap> <goto-line>" #'consult-goto-line)
+(keymap-global-set "<remap> <suspend-frame>" #'zap-up-to-char)
+(keymap-global-set "<remap> <imenu>" #'consult-imenu)
+(keymap-global-set "<remap> <make-frame>" #'duplicate-line)
+(keymap-global-set "M-#" #'define-word-at-point)
+(keymap-global-set "M-o" #'previous-buffer)
+(keymap-global-set "M-O" #'next-buffer)
+(keymap-global-set "C-," #'backward-delete-char)
+(keymap-global-set "C-." #'embark-act)
+(keymap-global-set "C-;" #'avy-goto-char-timer)
+(keymap-global-set "C-s-f" #'toggle-frame-fullscreen)
+(keymap-global-set "C-s-l" #'esy/pulse-line)
+
+(keymap-set ctl-x-map "b" #'consult-buffer)
+(keymap-set ctl-x-4-map "b" #'consult-buffer-other-window)
+(keymap-set ctl-x-map "C-b" #'ibuffer)
+
+(keymap-set search-map "r" #'rg)
+(keymap-set search-map "l" #'rg-literal)
+(keymap-set search-map "b" #'some-button)
+
+(dolist (command '(set-goal-column
+                   narrow-to-region
+                   narrow-to-page))
+  (put command 'disabled nil))
+
+(put 'suspend-frame 'disabled t)
+
+(with-eval-after-load 'magit
+  (setq magit-repository-directories '(("~/checkouts/" . 1))))
+
+(with-eval-after-load 'mastodon
+  (setq mastodon-instance-url "https://emacs.ch"
+        mastodon-active-user "eshel"))
+
+(with-eval-after-load 'tramp
+  (tramp-set-completion-function "ssh" '((tramp-parse-netrc "~/.authinfo.gpg"))))
+
+(define-advice project--find-in-directory (:override (dir) no-remote-projects)
+  (unless (file-remote-p dir)
+    (run-hook-with-args-until-success 'project-find-functions dir)))
+
+(define-advice completion-file-name-table (:filter-args (args) no-remote-file-name-completion)
+  (let ((string (car args))
+        (pred (cadr args))
+        (action (caddr args)))
+    (if (and (file-remote-p string) (eq pred #'file-exists-p))
+        (list string nil action)
+      (list string pred action))))
+
+(defun esy/local-all-the-icons-dired-mode ()
+  (unless (file-remote-p default-directory)
+    (all-the-icons-dired-mode)))
 
+(with-eval-after-load 'dired
+  (put 'dired-find-alternate-file 'disabled nil)
+  (setq dired-dwim-target t)
+  (add-hook 'dired-mode-hook #'esy/local-all-the-icons-dired-mode))
 
+(defun esy/vterm-mode-hook-function ()
+  (setq-local term-prompt-regexp "^[^#$%>\n]*[#$%>] *"))
+
+(with-eval-after-load 'vterm
+  (setq vterm-shell "/bin/zsh"
+        vterm-max-scrollback 2048
+        vterm-kill-buffer-on-exit nil
+        vterm-use-vterm-prompt-detection-method t)
+  (add-to-list 'vterm-tramp-shells '("kubernetes" "/bin/bash"))
+  (add-hook 'vterm-mode-hook #'esy/vterm-mode-hook-function))
+
+(with-eval-after-load 'elfeed
+  (setq elfeed-feeds
+        '(
+          "https://ajroach42.com/feed.xml"
+          "https://cdn.jwz.org/blog/feed/"
+          "https://jcm.libsyn.com/rss/"
+          "https://betterappsec.com/feed"
+          "https://emacs.dyerdwelling.family/index.xml"
+          "https://www.typetheoryforall.com/episodes.mp3.rss"
+          "https://www.fsf.org/static/fsforg/rss/news.xml"
+          "https://amodernist.com/all.atom"
+          "https://arcology.garden/updates.xml"
+          "https://takeonrules.com/index.atom"
+          "https://atthis.link/rss.xml"
+          "https://archive.casouri.cc/note/atom.xml"
+          "https://cestlaz.github.io/rss.xml"
+          "https://drewdevault.com/blog/index.xml"
+          "https://evanhahn.com/blog/index.xml"
+          "https://alexschroeder.ch/wiki/feed/full/"
+          "https://usesthis.com/feed.atom"
+          "https://xeiaso.net/blog.rss"
+          "https://changelog.complete.org/feed"
+          "https://herman.bearblog.dev/feed/"
+          "https://lwn.net/headlines/rss"
+          "https://maggieappleton.com/rss.xml"
+          "https://matt-rickard.com/rss"
+          "https://node2.feed43.com/7487052648530856.xml"
+          "https://njoseph.me/shaarli/feed/atom?"
+          "https://nullprogram.com/feed/"
+          "https://olddeuteronomy.github.io/index.xml"
+          "https://parasurv.neocities.org/rss.xml"
+          "https://phaazon.net/blog/feed"
+          "https://bruda.ca/feed.php"
+          "https://erikmcclure.com/blog/index.xml"
+          "https://blog.acthompson.net/feeds/posts/default"
+          "https://planet.emacslife.com/atom.xml"
+          "https://pouria.dev/rss.xml"
+          "https://project-mage.org/rss.xml"
+          "https://reddit.com/r/prolog/.rss"
+          "https://sachachua.com/blog/feed/"
+          "https://feeds.buzzsprout.com/2134279.rss"
+          "https://stephanango.com/feed.xml"
+          "https://stppodcast.libsyn.com/rss"
+          "https://writer13.neocities.org/rss.xml"
+          "https://www.draketo.de/rss-feed.xml"
+          "https://www.haskellforall.com/feeds/posts/default"
+          "https://cce.whatthefuck.computer/updates.xml"
+          "https://xkcd.com/rss.xml"
+          "https://bitspook.in/blog/feed.xml"
+          "https://flower.codes/feed.xml"
+          "https://www.cs.uni.edu/~wallingf/blog/atom.xml"
+          "https://matklad.github.io/feed.xml"
+          "https://www.evalapply.org/index.xml"
+          "https://www.stilldrinking.org/rss/feed.xml"
+          "https://fasterthanli.me/index.xml"
+          "https://kitchen-sink.kwakk.info/feed"
+          "https://lars.ingebrigtsen.no/feed"
+          )))
+
+(with-eval-after-load 'denote
+  (setq denote-directory "~/Notes"))
+
+(with-eval-after-load 'eww
+  (setq eww-auto-rename-buffer 'title)
+  (with-eval-after-load 'browse-url
+    (setq browse-url-browser-function #'eww-browse-url
+          browse-url-generic-program "open")))
+
+(defun esy/eww ()
+  "Prompt for a URL or keywords to search the web for."
+  (interactive)
+  (eww (mapconcat #'identity
+                  (completing-read-multiple "Browse or search: "
+                                            eww-prompt-history
+                                            nil nil nil
+                                            'eww-prompt-history
+                                            (car (eww-suggested-uris)))
+                  " ")))
+
+(with-eval-after-load 'browse-url
+  (setq browse-url-browser-function #'eww-browse-url))
+
+(add-hook 'proced-mode-hook #'proced-toggle-auto-update)
+
+(with-eval-after-load 'bbdb
+  (setq bbdb-phone-style nil))
+
+(defun esy/slack-start ()
+  (interactive)
+  (require 'slack)
+  (require 'auth-source)
+  (slack-register-team :name "Dazz"
+                       :default t
+                       :token (auth-source-pick-first-password
+                               :host "dazz-io.slack.com"
+                               :user "eshel")
+                       :cookie (auth-source-pick-first-password
+                                :host "dazz-io.slack.com"
+                                :user "eshel^cookie"))
+  (setq slack-prefer-current-team t
+        slack-buffer-emojify t)
+  (slack-start))
+
+(emms-minimalistic)
+(setq emms-player-list '(emms-player-mpv))
+
+(defun vertalen--on-success (&rest args)
+  "Process ARGS and display translation in a dedicated buffer."
+  (with-current-buffer-window "*vertalen*"
+      (with-selected-window (selected-window)
+        (unless (eq major-mode 'vertalen-mode)
+          `(nil . ((inhibit-same-window . t)))))
+      #'fit-window-to-buffer
+    (setq tabulated-list-entries (plist-get args :data))
+    (vertalen-mode)
+    (+ 2 (length tabulated-list-entries))))
+
+(defun vertalen--parse ()
+  (require 'dom)
+  "Parse buffer and return a list of translations."
+  (let* ((dom (libxml-parse-html-region (point-min) (point-max)))
+         (res (dom-by-class dom ".*result-item-translations.*"))
+         (ret nil))
+    (dolist (elem res)
+      (setq ret
+            `((nil ,(vector
+                     (apply #'concat
+                            (dom-strings
+                             (car (dom-by-class
+                                   elem
+                                   ".*result-item-source.*"))))
+                     (mapconcat #'identity
+                                (dom-strings
+                                 (car (dom-by-class
+                                       elem
+                                       ".*result-item-target.*")))
+                                ", ")))
+              . ,ret)))
+    (reverse ret)))
+
+(setq vertalen--source nil)
+(setq vertalen-history nil)
+
+(with-eval-after-load 'savehist
+  (add-to-list 'savehist-additional-variables
+               'vertalen-history))
+
+(defun vertalen (word)
+  "Translate WORD."
+  (interactive (list (read-string "Translate: " nil 'vertalen-history (thing-at-point 'word))))
+  (require 'request)
+  (setq vertalen--source word)
+  (request "https://www.vertalen.nu/vertaal"
+    :params `(("van" . "nl")
+              ("naar" . "en")
+              ("vertaal" . ,word))
+    :parser  #'vertalen--parse
+    :success #'vertalen--on-success))
+
+(defun vertalen-at-point ()
+  "Translate word at point."
+  (interactive nil vertalen-mode)
+  (vertalen (thing-at-point 'word t)))
+
+(defvar-keymap vertalen-mode-map
+  :doc "Keymap for `vertalen-mode' buffers."
+  "RET" #'vertalen-at-point)
+
+(define-derived-mode vertalen-mode tabulated-list-mode "Vertalen"
+  "Major mode for listing Dutch to English translations."
+  (setq tabulated-list-format [("Source Language" 64 t)
+                               ("Target Language" 32 t)])
+  (tabulated-list-init-header)
+  (tabulated-list-print)
+  (save-excursion
+    (goto-char (point-min))
+    (let ((inhibit-read-only t)
+          (word (search-forward vertalen--source nil t)))
+      (while word
+        (add-face-text-property (match-beginning 0) (match-end 0) 'success)
+        (setq word (search-forward vertalen--source nil t))))))
+
+(defun esy/dabbrev-capf ()
+  "Workaround for issue with `dabbrev-capf'."
+  (require 'dabbrev)
+  (dabbrev--reset-global-variables)
+  (setq dabbrev-case-fold-search nil)
+  (dabbrev-capf))
+
+(add-to-list 'completion-at-point-functions #'esy/dabbrev-capf)
+
+(defun esy/file-capf ()
+  "File completion at point function."
+  (let ((bs (bounds-of-thing-at-point 'filename)))
+    (when bs
+      (let* ((start (car bs))
+             (end   (cdr bs)))
+        `(,start ,end completion--file-name-table . (:exclusive no))))))
+
+(add-to-list 'completion-at-point-functions #'esy/file-capf)
+
+(defun esy/margin-formatter (metadata)
+  "Format METADATA for `corfu-margin-formatters'."
+  (pcase (cdr (assoc 'category metadata))
+    ('file (lambda (string)
+             (concat (if (string-suffix-p "/" string)
+                         (all-the-icons-icon-for-dir string)
+                       (all-the-icons-icon-for-file string))
+                     " ")))
+    ('dabbrev (lambda (_) "… "))))
+
+(setq corfu-cycle t
+      corfu-margin-formatters '(esy/margin-formatter)
+      corfu-indexed-start     1)
+(global-corfu-mode)
+(corfu-indexed-mode 1)
+
+(setq read-extended-command-predicate #'command-completion-default-include-p
+      completions-format 'one-column
+      completion-auto-select nil
+      completions-detailed nil
+      completion-styles '(orderless partial-completion basic)
+      completion-show-help nil
+      completions-header-format (propertize "%s candidates:\n"
+                                            'face 'shadow)
+      completion-auto-help 'visual
+      completions-max-height 16
+      completion-auto-wrap t)
+
+(define-key minibuffer-local-completion-map
+            [remap previous-line]
+            #'minibuffer-previous-completion)
+
+(define-key minibuffer-local-completion-map
+            [remap next-line]
+            #'minibuffer-next-completion)
+
+(add-hook 'marginalia-mode-hook
+          #'all-the-icons-completion-marginalia-setup)
+
+(marginalia-mode)
+
+(add-to-list 'display-buffer-alist
+             '("\\*Completions\\*"
+               (display-buffer-reuse-window display-buffer-at-bottom)
+               (window-parameters . ((mode-line-format . none)))))
+(add-to-list 'all-the-icons-extension-icon-alist
+             '("pl" all-the-icons-alltheicon "prolog"
+               :height 1.1 :face all-the-icons-lmaroon))
+
+(add-hook 'text-mode-hook #'flyspell-mode)
+
+(with-eval-after-load 'flyspell
+  (keymap-unset flyspell-mode-map "C-," t)
+  (keymap-unset flyspell-mode-map "C-." t)
+  (keymap-unset flyspell-mode-map "C-;" t))
+
+(pdf-tools-install t)
+
+(add-hook 'pdf-view-mode-hook #'pdf-view-midnight-minor-mode)
+
+(setq TeX-view-program-selection '((output-pdf "PDF Tools"))
+      TeX-source-correlate-start-server t)
+
+(add-to-list 'revert-without-query "\\.pdf\\'")
+
+(add-hook 'TeX-after-compilation-finished-functions
+          #'TeX-revert-document-buffer)
+
+(add-to-list 'auto-mode-alist '("\\.pdf\\'" . pdf-view-mode))
+
+(setq safe-local-variable-values
+      '((compilation-read-command . nil)))
+
+(add-hook 'prog-mode-hook #'rainbow-delimiters-mode)
+(add-hook 'prog-mode-hook #'display-line-numbers-mode)
+(add-hook 'prog-mode-hook #'display-fill-column-indicator-mode)
+(add-hook 'prog-mode-hook #'flymake-mode)
+
+(add-hook 'lisp-data-mode-hook #'enable-paredit-mode)
+
+(add-hook 'haskell-mode-hook #'interactive-haskell-mode)
+(add-hook 'haskell-mode-hook #'haskell-decl-scan-mode)
+(add-hook 'haskell-mode-hook #'haskell-doc-mode)
+
+(require 'use-package)
+
+(use-package sweeprolog
+  :mode ("\\.plt?\\'" . sweeprolog-mode)
+  :bind-keymap ("C-c p" . sweeprolog-prefix-map)
+  :config
+  (add-hook 'sweeprolog-mode-hook #'sweeprolog-electric-layout-mode)
+  (add-hook 'sweeprolog-top-level-mode-hook
+            #'compilation-shell-minor-mode))
+
+(with-eval-after-load 'rg
+  (add-to-list 'rg-custom-type-aliases '("Prolog" . "*.pl *.plt *.pro *.prolog")))
+
+(add-to-list 'auto-mode-alist '("Dockerfile" . dockerfile-ts-mode))
+
+(add-to-list 'auto-mode-alist '("\\.ya?ml\\'" . yaml-ts-mode))
+
+(add-to-list 'auto-mode-alist '("\\.json\\'" . json-ts-mode))
+
+(add-to-list 'auto-mode-alist '("\\.rs\\'" . rust-ts-mode))
+
+(add-to-list 'auto-mode-alist '("\\.go\\'" . go-ts-mode))
+
+(use-package terraform-mode
+  :config
+  (setq terraform--resource-name-face font-lock-function-name-face
+        terraform--resource-type-face font-lock-type-face))
+
+(setq vc-follow-symlinks t)
+
+(with-eval-after-load 'project
+  (add-to-list 'project-switch-commands '(project-compile "Compile"))
+  (add-to-list 'project-switch-commands '(rg-project "rg"))
+  (add-to-list 'project-switch-commands '(magit-project-status "Magit"))
+  (add-to-list 'project-switch-commands '(project-shell "Shell"))
+  (when (boundp 'project-prefix-map)
+    (define-key project-prefix-map "R" #'rg-project)
+    (define-key project-prefix-map "m" #'magit-project-status)))
+
+(setq shell-kill-buffer-on-exit t)
+
+(defun shell-restart-process ()
+  "Restart process of `shell-mode' buffer."
+  (interactive)
+  (let* ((proc (get-buffer-process (current-buffer)))
+         (pid  (process-id proc))
+         (cmd  (caddr (process-command proc))))
+    (message "%s" cmd)
+    (delete-process proc)
+    (async-shell-command cmd)))
+
+(with-eval-after-load 'shell
+  (keymap-set shell-mode-map "C-c C-k" #'shell-restart-process)
+  (keymap-set shell-mode-map "SPC" #'comint-magic-space))
+
+(defvar esy/logs-directory "~/logs"
+  "Directory where some log files will be saved.")
+
+(defvar-local esy/log-buffer-filename nil
+  "File in which the current buffer is logged.")
+
+(defun esy/log-buffer ()
+  "Save the current buffer under `esy/logs-directory'."
+  (interactive)
+  (let ((filename (or esy/log-buffer-filename
+                      (setq esy/log-buffer-filename
+                            (expand-file-name
+                             (concat mode-name
+                                     "_"
+                                     (format-time-string
+                                      "%Y%m%d%H%M%S"
+                                      (current-time))
+                                     ".log")
+                             esy/logs-directory)))))
+    (save-restriction
+      (widen)
+      (write-region (point-min)
+                    (point-max)
+                    filename))))
+
+(with-eval-after-load 'comint
+  (keymap-set comint-mode-map "C-c C-q" #'esy/log-buffer))
+
+(setq global-auto-revert-non-file-buffers t
+      auto-revert-verbose nil
+      query-about-changed-file t
+      kill-do-not-save-duplicates t
+      show-trailing-whitespace t)
+(global-auto-revert-mode)
+(global-whitespace-cleanup-mode 1)
+
+(with-eval-after-load 'consult
+  (with-eval-after-load 'embark
+    (require 'embark-consult)))
+
+(defvar-keymap transpose-lines-repeat-map
+  :doc "Repeat map for \\[transpose-lines]"
+  "C-t" #'transpose-lines)
+
+(put 'transpose-lines 'repeat-map 'transpose-lines-repeat-map)
+
+(with-eval-after-load 'xref
+  (setq xref-show-definitions-function #'consult-xref
+        xref-show-xrefs-function       #'consult-xref
+        xref-search-program             'ripgrep))
+
+(with-eval-after-load 'time
+  (add-to-list 'zoneinfo-style-world-list '("Europe/Amsterdam" "Amsterdam")))
+
+(defun process-menu-restart-process ()
+  "Restart process at point in a `list-processes' buffer."
+  (interactive)
+  (let* ((pos (point))
+         (pid (tabulated-list-get-id))
+         (ent (tabulated-list-get-entry))
+         (cmd (combine-and-quote-strings
+               (seq-drop (split-string-shell-command (seq-elt ent 6))
+                         2))))
+    (delete-process pid)
+    (async-shell-command cmd)
+    (revert-buffer)))
+
+(with-eval-after-load 'simple
+  (keymap-set process-menu-mode-map
+              "r"
+              #'process-menu-restart-process))
+
+(repeat-mode)
+
+(setq find-sibling-rules '(("\\([^/]+\\)\\.c\\'" "\\1.h")))
+
+(defun esy/seconds-to-date-string (seconds)
+  (interactive (list (if (use-region-p)
+                         (string-to-number (buffer-substring (region-beginning)
+                                                             (region-end)))
+                       (read-number "Unix timestamp: " (round (float-time))))))
+  (message (format-time-string "%FT%T%z" (seconds-to-time seconds))))
+
+(with-eval-after-load 'sql
+  (setq sqlformat-command 'pgformatter)
+  (define-key sql-mode-map (kbd "C-c C-f") 'sqlformat)
+  (setq sql-input-ring-file-name (expand-file-name ".sqli-history"
+                                                   no-littering-var-directory))
+  (setq sql-connection-alist
+        (let* ((a (auth-source-search :port 5432
+                                      :max  5
+                                      :require '(:user :port :secret :host)))
+               (d (nth 0 a))
+               (p (nth 1 a))
+               (c (nth 2 a))
+               (e (nth 3 a))
+               (f (nth 4 a)))
+          `((dev
+             (sql-product 'postgres)
+             (sql-user ,(plist-get d :user))
+             (sql-port 5432)
+             (sql-password ,(funcall (plist-get d :secret)))
+             (sql-server ,(plist-get d :host))
+             (sql-database "alerts"))
+            (prod
+             (sql-product 'postgres)
+             (sql-user ,(plist-get p :user))
+             (sql-port 5432)
+             (sql-password ,(funcall (plist-get p :secret)))
+             (sql-server ,(plist-get p :host))
+             (sql-database "alerts"))
+            (cgs
+             (sql-product 'postgres)
+             (sql-user ,(plist-get c :user))
+             (sql-port 5432)
+             (sql-password ,(funcall (plist-get c :secret)))
+             (sql-server ,(plist-get c :host))
+             (sql-database "container_graph"))
+            (ten
+             (sql-product 'postgres)
+             (sql-user ,(plist-get e :user))
+             (sql-port 5432)
+             (sql-password ,(funcall (plist-get e :secret)))
+             (sql-server ,(cadr (split-string (plist-get e :host)  (rx "^"))))
+             (sql-database ,(car (split-string (plist-get e :host) (rx "^")))))
+            (ac
+             (sql-product 'postgres)
+             (sql-user ,(plist-get f :user))
+             (sql-port 5432)
+             (sql-password ,(funcall (plist-get f :secret)))
+             (sql-server ,(cadr (split-string (plist-get f :host)  (rx "^"))))
+             (sql-database ,(car (split-string (plist-get f :host) (rx "^"))))))))
+
+  (define-advice sql-comint-postgres (:around (fun &rest args) use-sql-password)
+    (let ((process-environment
+           (nconc
+            (list (format "PGPASSWORD=%s" sql-password))
+            process-environment)))
+      (apply fun args))))
+
+(provide 'init)
+;;; init.el ends here
diff --git a/.zshenv b/.zshenv
index 4c0038fa6f169731f9696f53178cc340f9cd463f..8d40f90c572f37509e1bfe27134612c99ba51f17 100644 (file)
--- a/.zshenv
+++ b/.zshenv
@@ -1 +1 @@
-export PATH=/Users/eshelyaron/checkouts/emacs/nextstep/Emacs.app/Contents/MacOS:/Users/eshelyaron/.cargo/bin:/Users/eshelyaron/go/bin:$PATH
+export PATH="/Users/eshelyaron/.local/bin:/Users/eshelyaron/checkouts/emacs/nextstep/Emacs.app/Contents/MacOS:/Users/eshelyaron/.cargo/bin:/Users/eshelyaron/go/bin:$PATH"