From: Eshel Yaron Date: Thu, 16 Mar 2023 21:07:08 +0000 (+0200) Subject: update init.el X-Git-Url: http://git.eshelyaron.com/gitweb/?a=commitdiff_plain;h=b0dc29c10f209a51f3f8a99d62c3f930b21e803c;p=dotfiles.git update init.el --- diff --git a/.emacs.d/init.el b/.emacs.d/init.el index 960a665..d55693f 100644 --- a/.emacs.d/init.el +++ b/.emacs.d/init.el @@ -1,21 +1,7 @@ ;;; init.el --- Personal Emacs configuration -*- lexical-binding: t -*- ;; Copyright (C) 2021-2023 Eshel Yaron -;; Author: Eshel Yaron -;; 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 . +;; Author: Eshel Yaron ;;; Commentary: @@ -23,326 +9,128 @@ ;;; 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 @@ -350,105 +138,292 @@ :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) @@ -465,37 +440,107 @@ (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 " " #'esy/kill-dwim) (keymap-global-set " " #'consult-goto-line) (keymap-global-set " " #'zap-up-to-char) @@ -512,40 +557,110 @@ (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) @@ -553,201 +668,43 @@ (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'." @@ -768,6 +725,21 @@ (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)) @@ -778,274 +750,95 @@ " "))) ('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