;;; 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/>.
+;; Author: Eshel Yaron <me@eshelyaron.com>
;;; Commentary:
;;; Code:
+
+;;;; temporarly increase GC threshold to expedite Emacs startup
(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))))
+ (init-gc-cons-threshold (* 1024 1024 1024))
+ (normal-mode-line-format mode-line-format))
+ (setq gc-cons-threshold init-gc-cons-threshold
+ mode-line-format nil)
+ (add-hook 'after-init-hook
+ (lambda () (setq gc-cons-threshold normal-gc-cons-threshold
+ mode-line-format normal-mode-line-format))))
-(require 'comp)
(setq
+ ;; my name
+ user-full-name "Eshel Yaron"
+ ;; my email address
+ user-mail-address "me@eshelyaron.com"
+ ;; direct Custom definitions to some file and forget about it
+ custom-file (expand-file-name "custom.el" user-emacs-directory)
;; 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)
-
-(require 'package)
-(setq
+ warning-minimum-level :error
+ ;; don't use stale .elc files
+ load-prefer-newer t
+ ;; maximize Emacs on startup
+ initial-frame-alist '((fullscreen . fullboth))
+ ;; disable popup dialogs
+ use-dialog-box nil
+ ;; disable splash screen
+ inhibit-startup-screen t
+ ;; make the scratch message more concise
+ initial-scratch-message ";; Go.\n"
+ ;; don't ring the bell
+ ring-bell-function #'ignore
+ ;; make C-x b obey display-buffer-alist
+ switch-to-buffer-obey-display-actions t
+ ;; disable new mail mode line indication
+ display-time-mail-function #'ignore
+ ;; enable recursive minibuffers
+ enable-recursive-minibuffers t
+ ;; save bookmarks immediately
+ bookmark-save-flag 1
;; 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
+ 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
+ devdocs
+ diff-hl
+ elfeed
+ embark-consult
+ emms
+ gnu-elpa-keyring-update
+ gnuplot
+ graphql-mode
+ graphviz-dot-mode
+ haskell-mode
+ htmlize
+ ialign
+ keycast
+ kubernetes
+ lin
+ magit
+ marginalia
+ markdown-mode
+ mastodon
+ ob-prolog
+ orderless
+ org-modern
+ package-lint
+ paredit
+ pdf-tools
+ rainbow-delimiters
+ rainbow-mode
+ request
+ rg
+ smtpmail-multi
+ sqlformat
+ sweeprolog
+ terraform-mode
+ typit
+ vterm
+ vundo
+ whitespace-cleanup-mode
+ with-editor
+ )
+ ;; configure Org capture templates
+ org-capture-templates '(("t" "Todo [inbox]" entry
+ (file+headline "~/org/inbox.org" "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:
+ :prepend t
+ :empty-lines 1
+ :immediate-finish t)
+ ("w" "Work [inbox]" entry
+ (file+headline "~/org/inbox.org" "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
+ :prepend t
+ :empty-lines 1
+ :immediate-finish t)
+ ("c" "New Calendar Event" entry
+ (file+headline "~/org/inbox.org" "Calendar")
+ "** %^{Title} %^g
:PROPERTIES:
:CreatedAt: %u
:CapturedAt: %a
: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"
+ :prepend t
+ :empty-lines 1
+ :immediate-finish t))
+ ;; point Org to file agenda file
+ org-agenda-files '("~/org/inbox.org")
+ org-default-notes-file "~/org/inbox.org"
+ ;; weeks start on Sunday
+ org-agenda-start-on-weekday 0
+ ;; use a nice unicode ellipsis
+ org-ellipsis "…"
+ ;; open everything withing Emacs
+ org-file-apps '((t . emacs))
+ ;; enable Org speed commands
+ org-use-speed-commands t
+ ;; task states
+ org-todo-keywords '((sequence
+ "TODO(t)"
+ "BLOCKED(b@/!)"
+ "INPROGRESS(i!)"
+ "|"
+ "DONE(d!)"
+ "CANCELED(c@)"))
+ ;; set a task to INPROGRESS when I clock into it
+ org-clock-in-switch-to-state "INPROGRESS"
+ ;; log the finish time of tasks in Org
+ org-log-done 'time
+ org-log-into-drawer t
+ ;; minimal prompt for task states
+ org-use-fast-todo-selection 'expert
+ ;; set up a group of mutual exclusive tags
+ org-tag-alist '((:startgroup)
+ ("work" . ?w)
+ ("studies" . ?s)
+ ("esols" . ?e)
+ ("personal" . ?p)
+ (:endgroup))
+ ;; minimal prompt for tags
+ org-fast-tag-selection-single-key 'expert
+ ;; allow evaluating some languages with Org Babel
+ org-babel-load-languages '((emacs-lisp . t)
+ (shell . t)
+ (sql . t)
+ (prolog . t))
+ ;; do not ask for confirmation when evaluating Org source blocks
+ org-confirm-babel-evaluate nil
+ ;; extra modules to load along with Org
+ org-modules '(ol-bbdb
+ ol-bibtex
+ ol-docview
+ ol-gnus
+ ol-info
+ ol-irc
+ ol-mhe
+ ol-rmail
+ ol-eww
+ ob-sql
+ org-tempo)
+ ;; refile Org entries to my agenda file(s)
+ org-refile-targets '((org-agenda-files . (:maxlevel . 5))
+ (nil . (:maxlevel . 3)))
+ ;; use full outline path when prompting for refile target
+ org-refile-use-outline-path t
+ ;; archive for Org entries
+ org-archive-location "~/org/journal.org::datetree/* Finished Tasks :ARCHIVE:"
+ ;; enable italic text in code
+ modus-themes-italic-constructs t
+ ;; enable bold text in code
+ modus-themes-bold-constructs t
+ ;; use fixed-pitch text where appropriate
+ modus-themes-mixed-fonts t
+ ;; make prompts bold
+ modus-themes-prompts '(bold)
+ ;; give source blocks a distinct background shade
+ modus-themes-org-blocks 'gray-background
+ ;; use variable-pitch text here are there
+ modus-themes-variable-pitch-ui t
+ ;; fine-tune some theme settings
+ modus-themes-common-palette-overrides '((border-mode-line-active unspecified)
+ (border-mode-line-inactive unspecified)
+ (bg-mode-line-active bg-blue-intense)
+ (fg-mode-line-active fg-main)
+ (fringe unspecified)
+ (underline-link border)
+ (underline-link-visited border)
+ (underline-link-symbolic border)
+ (fg-region unspecified))
+ ;; follow links to version-controlled files without confirming
+ vc-follow-symlinks t
+ ;; jump from .c to .h files with find-sibling-file
+ find-sibling-rules '(("\\([^/]+\\)\\.c\\'" "\\1.h"))
+ ;; configure multiple SMTP accounts
+ smtpmail-multi-accounts '((esy . ("eshelshay.yaron@gmail.com"
+ "smtp.gmail.com" 587
+ "eshelshay.yaron@gmail.com"
+ starttls nil nil nil))
+ (swp . ("eshel@swi-prolog.org"
+ "mail.swi-prolog.com" 587
+ "eshel@swi-prolog.org"
+ starttls nil nil nil))
+ (me . ("me@eshelyaron.com"
+ "mail.eshelyaron.com"
+ 587
+ "me@eshelyaron.com"
+ starttls nil nil nil)))
+ ;; associate email addresses with SMTP accounts
+ smtpmail-multi-associations '(("[^z-a]*eshelshay\\.yaron@gmail\\.com[^z-a]*" esy)
+ ("[^z-a]*eshel@swi-prolog\\.org[^z-a]*" swp)
+ ("[^z-a]*me@eshelyaron\\.com[^z-a]*" me))
+ ;; set function for sending email
+ send-mail-function #'smtpmail-multi-send-it
+ message-send-mail-function #'smtpmail-multi-send-it
+ ;; set email user agent
+ mail-user-agent 'gnus-user-agent
+ ;; make Gnus not prompt as much
+ gnus-expert-user t
+ ;; make Gnus read the dribble file on startup without prompting
+ gnus-always-read-dribble-file t
+ ;; don't break pages in incoming email
+ gnus-break-pages nil
+ ;; don't show the Gnus startup screen
+ gnus-inhibit-startup-message t
+ ;; set Gnus backends
+ gnus-select-method '(nntp "news.gmane.io")
+ gnus-secondary-select-methods '((nnimap "gmail"
+ (nnimap-address "imap.gmail.com")
+ (nnimap-server-port "imaps")
+ (nnimap-stream ssl))
+ (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)
+ (nnimap-stream ssl))
+ (nnimap "swi"
+ (nnimap-address "mail.swi-prolog.com")
+ (nnimap-server-port "imaps")
+ (nnimap-stream ssl)))
+ ;; simpler message
+ gnus-no-groups-message "No new articles"
+ ;; don't close other windows when opening Gnus
+ gnus-use-full-window nil
+ ;; make Gnus handle this content types
+ gnus-article-treat-types '("text/plain"
+ "text/x-verbatim"
+ "text/x-patch"
+ "text/html"
+ "text/calendar")
+ ;; capture calendar events from Gnus to my Org inbox file
+ gnus-icalendar-org-capture-file "~/org/inbox.org"
+ ;; put calendar events under the Calendar heading
+ gnus-icalendar-org-capture-headline '("Calendar")
+ ;; use ISO format for calendar dates
+ calendar-date-style 'iso
+ ;; maintain legibility of rendered text in HTML mails
+ shr-color-visible-luminance-min 75
+ ;; my Mastodon settings
+ mastodon-instance-url "https://emacs.ch"
+ mastodon-active-user "eshel"
+ ;; direct Magit to my Git checkouts directory
+ magit-repository-directories '(("~/checkouts/" . 1))
+ ;; have Dired operations target another visible Dired buffer
+ dired-dwim-target t
+ ;; use zsh in vterm by default
+ vterm-shell "/bin/zsh"
+ vterm-max-scrollback 2048
+ vterm-kill-buffer-on-exit nil
+ vterm-use-vterm-prompt-detection-method t
+ ;; use MPV with EMMS
+ emms-player-list '(emms-player-mpv)
+ bbdb-phone-style nil
+ eww-auto-rename-buffer 'title
+ browse-url-browser-function #'eww-browse-url
+ browse-url-generic-program "open"
+ ;; set up some feeds for Elfeed
+ elfeed-feeds '(
+ "https://ajroach42.com/feed.xml"
+ "https://alexschroeder.ch/wiki/feed/full/"
+ "https://amodernist.com/all.atom"
+ "https://archive.casouri.cc/note/atom.xml"
+ "https://arcology.garden/updates.xml"
+ "https://atthis.link/rss.xml"
+ "https://gwern.substack.com/feed"
+ "https://baty.net/feed"
+ "https://betterappsec.com/feed"
+ "https://bitspook.in/blog/feed.xml"
+ "https://blog.acthompson.net/feeds/posts/default"
+ "https://bruda.ca/feed.php"
+ "https://cce.whatthefuck.computer/updates.xml"
+ "https://cdn.jwz.org/blog/feed/"
+ "https://cestlaz.github.io/rss.xml"
+ "https://changelog.complete.org/feed"
+ "https://drewdevault.com/blog/index.xml"
+ "https://emacs.dyerdwelling.family/index.xml"
+ "https://erikmcclure.com/blog/index.xml"
+ "https://evanhahn.com/blog/index.xml"
+ "https://fasterthanli.me/index.xml"
+ "https://feeds.buzzsprout.com/2134279.rss"
+ "https://flower.codes/feed.xml"
+ "https://garymarcus.substack.com/feed"
+ "https://herman.bearblog.dev/feed/"
+ "https://jcm.libsyn.com/rss/"
+ "https://kitchen-sink.kwakk.info/feed"
+ "https://lars.ingebrigtsen.no/feed"
+ "https://lwn.net/headlines/rss"
+ "https://maggieappleton.com/rss.xml"
+ "https://matklad.github.io/feed.xml"
+ "https://matt-rickard.com/rss"
+ "https://njoseph.me/shaarli/feed/atom?"
+ "https://node2.feed43.com/7487052648530856.xml"
+ "https://nullprogram.com/feed/"
+ "https://olddeuteronomy.github.io/index.xml"
+ "https://parasurv.neocities.org/rss.xml"
+ "https://phaazon.net/blog/feed"
+ "https://planet.emacslife.com/atom.xml"
+ "https://ploum.net/atom_en.xml"
+ "https://pouria.dev/rss.xml"
+ "https://project-mage.org/rss.xml"
+ "https://reddit.com/r/prolog/.rss"
+ "https://sachachua.com/blog/feed/"
+ "https://stephanango.com/feed.xml"
+ "https://stppodcast.libsyn.com/rss"
+ "https://takeonrules.com/index.atom"
+ "https://two-wrongs.com/feed"
+ "https://usesthis.com/feed.atom"
+ "https://writer13.neocities.org/rss.xml"
+ "https://www.cs.uni.edu/~wallingf/blog/atom.xml"
+ "https://www.draketo.de/rss-feed.xml"
+ "https://www.evalapply.org/index.xml"
+ "https://www.fsf.org/static/fsforg/rss/news.xml"
+ "https://www.haskellforall.com/feeds/posts/default"
+ "https://www.murilopereira.com/index.xml"
+ "https://www.stilldrinking.org/rss/feed.xml"
+ "https://www.typetheoryforall.com/episodes.mp3.rss"
+ "https://xeiaso.net/blog.rss"
+ "https://xkcd.com/rss.xml"
+ )
+ 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
+ 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
+ corfu-cycle t
+ corfu-margin-formatters '(esy/margin-formatter)
+ corfu-indexed-start 1
+ shell-kill-buffer-on-exit t
+ ;; allow disabling confirming before compilation via local variables
+ safe-local-variable-values '((compilation-read-command . nil))
+ TeX-view-program-selection '((output-pdf "PDF Tools"))
+ TeX-source-correlate-start-server t
+ xref-show-definitions-function #'consult-xref
+ xref-show-xrefs-function #'consult-xref
+ xref-search-program 'ripgrep
+ sqlformat-command 'pgformatter
+ sql-input-ring-file-name (expand-file-name ".sqli-history" user-emacs-directory)
+ ;; use relative line numbers
+ display-line-numbers-type 'relative
+ )
+
+;;;; load the modus-vivendi theme
+(require-theme 'modus-themes)
+(load-theme 'modus-vivendi)
+
+;;;; set up the Iosevka font family
+(set-face-attribute 'default nil :family "Iosevka" :height 130)
+(set-face-attribute 'fixed-pitch nil :family "Iosevka")
+(set-face-attribute 'variable-pitch nil :family "Iosevka Etoile")
+
+(add-to-list 'load-path (expand-file-name "lisp/" user-emacs-directory))
- (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))
+(setq-default indent-tabs-mode nil)
-(defun esy/find-init-file (init)
- (interactive (list user-init-file))
- (find-file init))
+(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)
+
+;;;; utility commands
(defun esy/kill-dwim ()
"When region is active, kill region, otherwise kill last word."
(interactive)
(interactive)
(pulse-momentary-highlight-one-line))
+(defun esy/seconds-to-date-string (seconds)
+ "Decode and display the date corresponding to 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))))
+
+(defun esy/find-init-file (init)
+ "Find the Emacs INIT file."
+ (interactive (list user-init-file))
+ (find-file init))
+
+(defun esy/eww (target)
+ "Browse or search for TARGET."
+ (interactive (list (if (use-region-p)
+ (let ((target (buffer-substring-no-properties (use-region-beginning)
+ (use-region-end))))
+ (add-to-history 'eww-prompt-history target)
+ target)
+ (completing-read "Browse or search: "
+ eww-prompt-history nil nil nil
+ 'eww-prompt-history
+ (eww-suggested-uris)))))
+ (eww target))
+
+(with-eval-after-load 'shell
+ (keymap-set shell-mode-map "SPC" #'comint-magic-space))
+
+(defvar-local esy/log-buffer-filename nil
+ "File in which the current buffer is logged.")
+
+(defun esy/log-buffer ()
+ "Save the current buffer under the ~/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")
+ "~/logs")))))
+ (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))
+
+;;;; override the default startup message
+(define-advice startup-echo-area-message (:override () report-init-time)
+ (format "%s started in %s. Hack away."
+ (propertize "Emacs" 'face 'success)
+ (propertize (emacs-init-time) 'face 'error )))
+
+;;;; set up external packages
+(require 'package)
+
+;;;; configure non-default package archive
+(add-to-list 'package-archives
+ '("melpa" . "http://melpa.org/packages/"))
+(add-to-list 'package-archives
+ '("elpa-devel" . "https://elpa.gnu.org/devel/"))
+
+;;;; install packages
+(package-install-selected-packages)
+
+;;;; enable some built-in tree-sitter modes
+(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))
+
+;;;; enable spell checking in text buffers
+(add-hook 'text-mode-hook #'flyspell-mode)
+
+(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 #'flyspell-prog-mode)
+(add-hook 'prog-mode-hook #'flymake-mode)
+
+;;;; bind some keys
(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 "C-c SPC" #'consult-mark)
(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-set ctl-x-map "b" #'consult-buffer)
(keymap-set ctl-x-4-map "b" #'consult-buffer-other-window)
+(keymap-set ctl-x-5-map "b" #'consult-buffer-other-frame)
+(keymap-set ctl-x-map "r b" #'consult-bookmark)
(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)
+;;;; unbind some keys
+(dolist (key '("s-a" "s-d" "s-e" "s-f" "s-g" "s-h" "s-j" "s-k" "s-l"
+ "s-m" "s-o" "s-q" "s-s" "s-t" "s-u" "s-w" "s-x" "s-y"
+ "s-z"))
+ (keymap-global-unset key))
+
+;;;; enable some commands
(dolist (command '(set-goal-column
narrow-to-region
narrow-to-page))
(put command 'disabled nil))
+;;;; disable some commands
(put 'suspend-frame 'disabled t)
-(with-eval-after-load 'magit
- (setq magit-repository-directories '(("~/checkouts/" . 1))))
+(with-eval-after-load 'project
+ (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)))
+ (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)))
-(with-eval-after-load 'mastodon
- (setq mastodon-instance-url "https://emacs.ch"
- mastodon-active-user "eshel"))
+;;;; SQL servers
+(with-eval-after-load 'sql
+ (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-key sql-mode-map (kbd "C-c C-f") #'sqlformat)
+ (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))))
-(with-eval-after-load 'tramp
- (tramp-set-completion-function "ssh" '((tramp-parse-netrc "~/.authinfo.gpg"))))
+;;;; Org settings
+(with-eval-after-load 'org
+ (keymap-unset org-mode-map "C-," t))
-(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)))
+(with-eval-after-load 'org-agenda
+ (add-to-list 'org-agenda-custom-commands
+ '("w" "Work TODOs" tags-todo "+work")))
-(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))))
+;;;; mail settings
+(with-eval-after-load 'gnus
+ (require 'gnus-icalendar)
+ (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/local-all-the-icons-dired-mode ()
(unless (file-remote-p default-directory)
(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 'tramp
+ (tramp-set-completion-function "ssh" '((tramp-parse-netrc "~/.authinfo.gpg"))))
-(with-eval-after-load 'browse-url
- (setq browse-url-browser-function #'eww-browse-url))
+(with-eval-after-load 'proced
+ (add-hook 'proced-mode-hook #'proced-toggle-auto-update))
-(add-hook 'proced-mode-hook #'proced-toggle-auto-update)
+(with-eval-after-load 'time
+ (add-to-list 'zoneinfo-style-world-list '("Europe/Amsterdam" "Amsterdam")))
-(with-eval-after-load 'bbdb
- (setq bbdb-phone-style nil))
+(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))
-(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))
+(add-to-list 'display-buffer-alist
+ '("\\*Completions\\*"
+ (display-buffer-reuse-window display-buffer-at-bottom)
+ (window-parameters . ((mode-line-format . none)))))
-(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))))))
+(add-hook 'completion-list-mode-hook
+ (lambda ()
+ (setq-local cursor-in-non-selected-windows nil)))
+
+(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))))
+
+(define-key minibuffer-local-completion-map
+ [remap previous-line] #'minibuffer-previous-completion)
+(define-key minibuffer-local-completion-map
+ [remap next-line] #'minibuffer-next-completion)
(defun esy/dabbrev-capf ()
"Workaround for issue with `dabbrev-capf'."
(add-to-list 'completion-at-point-functions #'esy/file-capf)
+(require 'use-package)
+
+;;;; highlight the current line in line-oriented buffers
+(use-package lin
+ :config
+ (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))
+
+(use-package all-the-icons
+ :config
+ (add-to-list 'all-the-icons-extension-icon-alist
+ '("pl" all-the-icons-alltheicon "prolog"
+ :height 1.1 :face all-the-icons-lmaroon)))
+
(defun esy/margin-formatter (metadata)
"Format METADATA for `corfu-margin-formatters'."
(pcase (cdr (assoc 'category metadata))
" ")))
('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)
+(use-package marginalia
+ :config
+ (add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup))
+
+;; enable some global minor modes
+(dolist-with-progress-reporter (mode '(
+ column-number-mode
+ context-menu-mode
+ corfu-indexed-mode
+ display-time-mode
+ display-time-mode
+ global-auto-revert-mode
+ global-corfu-mode
+ global-diff-hl-mode
+ global-whitespace-cleanup-mode
+ lin-global-mode
+ marginalia-mode
+ minibuffer-depth-indicate-mode
+ mouse-avoidance-mode
+ pixel-scroll-precision-mode
+ recentf-mode
+ repeat-mode
+ save-place-mode
+ savehist-mode
+ show-paren-mode
+ transient-mark-mode
+ ))
+ "Enabling minor modes"
+ (funcall 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))
+(emms-minimalistic)
+;;;; PDF settings
(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)
+(with-eval-after-load 'tex
+ (add-hook 'TeX-after-compilation-finished-functions
+ #'TeX-revert-document-buffer))
-(add-hook 'lisp-data-mode-hook #'enable-paredit-mode)
+(use-package vterm
+ :config
+ (add-to-list 'vterm-tramp-shells '("kubernetes" "/bin/bash")))
-(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)
+(use-package paredit
+ :hook lisp-data-mode
+ :config
+ (keymap-unset paredit-mode-map "M-s" t)
+ (keymap-unset paredit-mode-map "M-?" t))
-(require 'use-package)
+(use-package haskell-mode
+ :hook ((haskell-mode . interactive-haskell-mode)
+ (haskell-mode . haskell-decl-scan-mode)
+ (haskell-mode . haskell-doc-mode)))
(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))
+ (add-hook 'sweeprolog-top-level-mode-hook #'compilation-shell-minor-mode)
+ (with-eval-after-load 'org
+ (add-to-list 'org-src-lang-modes '("prolog" . sweeprolog))))
-(with-eval-after-load 'rg
+(use-package rg
+ :config
(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 "^"))))))))
+;;;; compile this file (if changed) when Emacs is killed
+(defun esy/compile-config ()
+ (when (file-newer-than-file-p user-init-file
+ (byte-compile-dest-file user-init-file))
+ (byte-compile-file user-init-file)))
- (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))))
+(add-hook 'kill-emacs-hook #'esy/compile-config 10)
(provide 'init)
;;; init.el ends here