--- /dev/null
+#+TITLE: GNU Emacs configuration file
+#+AUTHOR: Eshel Yaron
+#+EMAIL: eshelshay.yaron@gmail.com
+#+OPTIONS: toc:nil ^:{}
+#+STARTUP: overview indent
+
+* Emacs configuration
+** Elisp Header
+
+#+begin_src emacs-lisp
+ ;;; esy.el --- GNU Emacs configuration -*- lexical-binding: t -*-
+ ;;; Package-Requires: ((emacs "29"))
+ ;;; Commentary: Tangled version of esy.org
+ ;;; Code:
+#+end_src
+** Set a higher GC threshold during initializion
+#+begin_src emacs-lisp
+ (let ((normal-gc-cons-threshold (* 20 1024 1024))
+ (init-gc-cons-threshold (* 128 1024 1024)))
+ (setq gc-cons-threshold init-gc-cons-threshold)
+ (add-hook 'emacs-startup-hook
+ (lambda () (setq gc-cons-threshold normal-gc-cons-threshold))))
+#+end_src
+** Package archives
+
+#+begin_src emacs-lisp
+ (require 'package)
+
+ (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
+
+ (package-initialize)
+#+end_src
+
+#+RESULTS:
+
+** Suppressing native compilation warnings
+
+#+begin_src emacs-lisp
+ (setq native-comp-async-report-warnings-errors 'silent)
+#+end_src
+
+** Loading the =modus-vivendi= theme
+
+#+begin_src emacs-lisp
+ (load-theme 'modus-vivendi)
+ (modus-themes-load-vivendi)
+#+end_src
+
+** No littering!
+
+#+begin_src emacs-lisp
+ (require 'no-littering)
+
+ (setq auto-save-file-name-transforms
+ `((".*" ,(no-littering-expand-var-file-name "auto-save/") t)))
+
+ (setq custom-file (no-littering-expand-etc-file-name "custom.el"))
+ (load custom-file 'noerror 'nomessage)
+
+ (when (fboundp 'startup-redirect-eln-cache)
+ (startup-redirect-eln-cache
+ (convert-standard-filename
+ (expand-file-name "var/eln-cache/" user-emacs-directory))))
+#+end_src
+
+** History
+#+begin_src emacs-lisp
+ (defun esy/setup-history ()
+ "Setup `recentf-mode', `savehist-mode' and more history-related settings."
+ (require 'bookmark)
+ (require 'recentf)
+ (require 'savehist)
+ (require 'saveplace)
+ (recentf-mode 1)
+ (savehist-mode 1)
+ (save-place-mode 1)
+ (setq bookmark-save-flag 1))
+
+ (esy/setup-history)
+#+end_src
+
+** Display settings
+
+*** Must have display settings
+#+begin_src emacs-lisp
+ (setq use-file-dialog nil
+ use-dialog-box nil
+ ns-use-native-fullscreen t
+ inhibit-startup-screen t
+ ring-bell-function 'ignore)
+
+ (setq-default indent-tabs-mode nil)
+
+ (menu-bar-mode -1)
+ (tool-bar-mode -1)
+ (set-scroll-bar-mode nil)
+ (pixel-scroll-precision-mode)
+ (put 'narrow-to-region 'disabled nil)
+ (put 'suspend-frame 'disabled t)
+#+end_src
+
+*** More display settings
+
+#+begin_src emacs-lisp
+ (defun esy/setup-display ()
+ "Setup display-related customizations."
+ (require 'diff-hl)
+ (require 'beacon)
+ (require 'paren)
+ (require 'lin)
+ (require 'which-key)
+ (require 'whitespace-cleanup-mode)
+ (require 'beacon)
+ (setq beacon-color "magenta"
+ show-paren-context-when-offscreen t)
+ (add-to-list 'lin-mode-hooks 'package-menu-mode-hook)
+ (global-diff-hl-mode)
+ (lin-global-mode 1)
+ (beacon-mode 1)
+ (transient-mark-mode)
+ (show-paren-mode))
+
+ (add-hook 'after-init-hook #'esy/setup-display)
+#+end_src
+** Org-mode settings :org:
+
+*** Literate config bootstrap
+
+#+begin_src emacs-lisp
+ (defun esy/tangle-and-compile-config ()
+ "Tangle literate configuration file."
+ (require 'org)
+ (require 'ob)
+ (let ((source (locate-user-emacs-file "esy.org"))
+ (target (locate-user-emacs-file "esy.el")))
+ (org-babel-tangle-file source target (rx string-start
+ (or "emacs-lisp" "elisp")
+ string-end))
+ (byte-compile-file target)))
+
+ (add-hook 'kill-emacs-hook #'esy/tangle-and-compile-config)
+#+end_src
+
+*** Org-mode basic settings
+
+#+begin_src emacs-lisp
+ (defconst esy/inbox-path "~/inbox.org"
+ "Path to my Org mode inbox file.")
+
+ (defun esy/setup-initial-org-config ()
+ "Setup initial `org-mode' configuration."
+ (require 'org)
+ (require 'org-habit)
+ (setq org-agenda-files `(,esy/inbox-path)
+ org-default-notes-file esy/inbox-path
+ org-agenda-start-on-weekday 0
+ org-ellipsis "…"))
+
+ (esy/setup-initial-org-config)
+
+ (defun esy/setup-org-config ()
+ "Configure `org-mode' specific customizations."
+ (require 'ob)
+ (require 'ob-prolog)
+ (setq org-todo-keywords '((sequence
+ "TODO(t)"
+ "BLOCKED(b@/!)"
+ "INPROGRESS(i!)"
+ "|"
+ "DONE(d!)"
+ "CANCELED(c@)"))
+ org-babel-load-languages '((emacs-lisp . t)
+ (shell . t)
+ (bnf . t)
+ (prolog . t))
+ org-confirm-babel-evaluate nil
+ org-log-done 'time
+ org-log-into-drawer t
+ org-use-fast-todo-selection 'expert
+ org-clock-in-switch-to-state "INPROGRESS"))
+
+ (add-hook 'after-init-hook #'esy/setup-org-config)
+
+ (require 'org-superstar)
+ (add-hook 'org-mode-hook #'org-superstar-mode)
+
+#+end_src
+
+*** Export and publish
+
+#+begin_src emacs-lisp
+ (require 'f)
+
+ (defconst esy/website-source-root "~/checkouts/eshelyaron.com"
+ "Local path of my website sources")
+
+ (defconst esy/website-target-html "/ssh:root@direct.eshelyaron.com:/var/www/html"
+ "Remote path of my website pages")
+
+ (defconst esy/publish-project-index-template
+ `( :base-extension "org"
+ :base-directory ,(expand-file-name "org" esy/website-source-root)
+ :exclude ".*"
+ :include ("index.org")
+ :publishing-function org-html-publish-to-html
+ :html-head "<link rel=\"stylesheet\" href=\"/style.css\" type=\"text/css\"/>"
+ :html-postamble ,(f-read-text "~/checkouts/eshelyaron.com/org/html_postamble.html"))
+ "Template for the index page of my website")
+
+ (defconst esy/publish-project-static-template
+ `( :base-directory ,(expand-file-name "org" esy/website-source-root)
+ :base-extension "ico\\|css\\|jpg\\|gif\\|png\\|txt\\|pdf"
+ :recursive t
+ :publishing-function org-publish-attachment)
+ "Template for the static assets of my website")
+
+ (defun esy/setup-publish ()
+ "Configure `org-mode'-based publishing."
+ (require 'ox-publish)
+ (require 'ox-html)
+ (require 'htmlize)
+ (setq org-export-with-section-numbers nil
+ org-export-with-toc nil
+ org-html-html5-fancy t
+ org-html-doctype "html5"
+ org-html-head-include-default-style nil
+ org-html-head-include-scripts nil
+ org-html-htmlize-output-type 'css
+ org-publish-project-alist
+ `(("index"
+ :publishing-directory ,esy/website-target-html
+ .
+ ,esy/publish-project-index-template)
+ ("static"
+ :publishing-directory ,esy/website-target-html
+ .
+ ,esy/publish-project-static-template)
+ ("eshelyaron.com" :components ("index" "static"))
+ ("index.local"
+ :publishing-directory ,(expand-file-name "html" esy/website-source-root)
+ .
+ ,esy/publish-project-index-template)
+ ("static.local"
+ :publishing-directory ,(expand-file-name "html" esy/website-source-root)
+ .
+ ,esy/publish-project-static-template)
+ ("eshelyaron.local" :components ("index.local" "static.local" "config.local")))))
+
+ (add-hook 'after-init-hook #'esy/setup-publish)
+#+end_src
+
+*** Org-mode capture templates
+
+#+begin_src emacs-lisp
+
+ (defvar esy/org-capture-to-project-heading-history-list nil
+ "History list for 'esy/org-capture-to-project-heading'.")
+
+ (require 'savehist)
+ (setq savehist-additional-variables '(esy/org-capture-to-project-heading-history-list))
+
+ (defun esy/org-capture-to-project-heading ()
+ "Prompt for a projects and capture a related task."
+ (require 'project)
+ (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 'esy/org-capture-to-project-heading-history-list))
+ (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."
+ (require 'project)
+ (let* ((projects
+ (org-map-entries `(lambda () (nth 4 (org-heading-components)))
+ (concat "+project+LEVEL=2+SCM=\"file:"
+ (project-root (with-current-buffer
+ (org-capture-get :original-buffer)
+ (project-current)))
+ "\"")
+ (list esy/inbox-path)))
+ (choice (car projects))
+ (m (org-find-olp (cons (org-capture-expand-file esy/inbox-path) (list "Projects" choice)))))
+ (set-buffer (marker-buffer m))
+ (org-capture-put-target-region-and-position)
+ (widen)
+ (goto-char m)
+ (set-marker m nil)))
+
+ (setq org-capture-templates '(("t" "Todo [inbox]" entry
+ (file+headline esy/inbox-path "Tasks")
+ "** TODO %^{Task} %^g
+ :PROPERTIES:
+ :CreatedAt: %t
+ :CapturedAt: %a
+ :CapturedAs: Inbox Task
+ :END:
+ "
+ :prepend t
+ :empty-lines 1
+ :immediate-finish t)
+ ("n" "New Project" entry
+ (file+headline esy/inbox-path "Projects")
+ "** %^{Name} %^g
+ :PROPERTIES:
+ :CreatedAt: %t
+ :CapturedAt: %a
+ :CapturedAs: New Project
+ :SCM: file:%(project-prompt-project-dir)
+ :END:
+ "
+ :prepend t
+ :empty-lines 1
+ :immediate-finish t)
+ ("c" "New Calendar Event" entry
+ (file+headline esy/inbox-path "Calendar")
+ "** %^{Title} %^g
+ :PROPERTIES:
+ :CreatedAt: %t
+ :CapturedAt: %a
+ :CapturedAs: Calendar Event
+ :END:
+ %(format-time-string \"<%Y-%m-%d %H:%M\" (org-read-date t t))-%(format-time-string \"%H:%M>\" (org-read-date t t))
+ %i
+ "
+ :prepend t
+ :empty-lines 1
+ :immediate-finish t)
+ ("p" "New Project Task" entry
+ (file+function esy/inbox-path esy/org-capture-to-project-heading)
+ "*** TODO %?
+ :PROPERTIES:
+ :CreatedAt: %t
+ :CapturedAt: %a
+ :CapturedAs: Project Task
+ :END:
+ %i
+ "
+ :prepend t
+ :empty-lines 1)
+ ("Q" "Quick Project Task" entry
+ (file+function esy/inbox-path esy/org-capture-to-project-heading)
+ "*** TODO %^{Task}
+ :PROPERTIES:
+ :CreatedAt: %t
+ :CapturedAt: %a
+ :CaptuerdAs: Quick Project Task
+ :END:
+ %i
+ "
+ :prepend t
+ :empty-lines 1
+ :immediate-finish t)
+ ("P" "Current Project Task" entry
+ (file+function esy/inbox-path esy/org-capture-to-current-project)
+ "*** TODO %^{Task}
+ :PROPERTIES:
+ :CreatedAt: %t
+ :CapturedAt: %a
+ :CaptuerdAs: Current Project Task
+ :END:
+ %i
+ "
+ :prepend t
+ :empty-lines 1
+ :immediate-finish t)))
+
+(setq org-capture-templates-contexts
+ '(("P" (list project-current))))
+#+end_src
+
+*** Unset =org-mode= binding of =C-,= to =org-cycle-agenda-files= :kbd:
+
+#+begin_src emacs-lisp
+ (keymap-unset org-mode-map "C-," t)
+#+end_src
+
+** Email settings :mail:
+
+*** My accounts
+
+#+begin_src emacs-lisp
+ (setq user-full-name "Eshel Yaron")
+
+ (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.")
+#+end_src
+
+*** Sending mail from mutiple SMTP accounts
+
+#+begin_src emacs-lisp
+ (defun esy/smtpmail-multi-make-accout (address server)
+ "Return an SMTP account definition for ADDRESS in SERVER."
+ `(,address ,server 587 ,address starttls nil nil nil))
+
+ (defun esy/smtpmail-multi-make-rx (address)
+ "Return a regexp that matches ADDRESS wrapped with anything."
+ (rx (* anything) (literal address) (* anything)))
+
+ (defun esy/customize-message-mode ()
+ "Configure `message-mode' specific customizations."
+ (require 'smtpmail-multi)
+ (setq smtpmail-multi-accounts
+ `((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"))))
+ (setq 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)))
+ (setq send-mail-function #'smtpmail-multi-send-it)
+ (setq message-send-mail-function #'smtpmail-multi-send-it))
+
+ (add-hook 'message-mode-hook #'esy/customize-message-mode)
+ (add-hook 'mail-mode-hook #'esy/customize-message-mode)
+#+end_src
+
+*** Reading mail with Gnus
+
+#+begin_src emacs-lisp
+ (setq mail-user-agent 'gnus-user-agent
+ gnus-always-read-dribble-file t
+ gnus-expert-user t
+ gnus-inhibit-startup-message t
+ gnus-select-method '(nnimap "gmail"
+ (nnimap-address "imap.gmail.com")
+ (nnimap-server-port "imaps")
+ (nnimap-stream ssl)))
+
+ (defun esy/customize-gnus-mode ()
+ "Configure Gnus specific customizations."
+ (require 'gnus)
+ (require 'gnus-icalendar)
+ (require 'shr)
+ (require 'ace-link)
+ (setq
+ gnus-article-treat-types '("text/plain"
+ "text/x-verbatim"
+ "text/x-patch"
+ "text/html"
+ "text/calendar")
+ gnus-posting-styles `((".*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")
+ shr-use-colors nil
+ calendar-date-style 'iso)
+ (gnus-icalendar-setup)
+ (gnus-icalendar-org-setup)
+ (define-key gnus-summary-mode-map (kbd "M-o") 'ace-link-gnus)
+ (define-key gnus-article-mode-map (kbd "M-o") 'ace-link-gnus)
+ (add-hook 'gnus-group-mode-hook #'gnus-topic-mode))
+
+ (add-hook 'gnus-mode-hook #'esy/customize-gnus-mode)
+#+end_src
+
+** Global keybindings :kbd:
+
+*** Misc. keybindings
+
+#+begin_src emacs-lisp
+ (defun esy/kill-dwim ()
+ "When region is active, kill region, otherwise kill last word.
+ Arguments BEG and END are the borders of the region."
+ (interactive)
+ (if (region-active-p)
+ (let ((beg (region-beginning))
+ (end (region-end)))
+ (kill-region beg end))
+ (let ((end (point)))
+ (backward-word)
+ (kill-region (point) end))))
+
+ (defun esy/customize-global-keymap ()
+ "Configure the global keymap."
+ (require 'consult)
+ (require 'consult-imenu)
+ (require 'avy)
+ (require 'dtache)
+ (require 'move-dup)
+ (require 'embark)
+ (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-m")
+ (keymap-global-unset "s-o")
+ (keymap-global-unset "s-q")
+ (keymap-global-unset "s-s")
+ (keymap-global-unset "s-u")
+ (keymap-global-unset "s-w")
+ (global-set-key [remap kill-region] #'esy/kill-dwim)
+ (global-set-key [remap goto-line] #'consult-goto-line)
+ (global-set-key [remap suspend-frame] #'zap-up-to-char)
+ (global-set-key [remap async-shell-command] #'dtache-shell-command)
+ (global-set-key [remap imenu] #'consult-imenu)
+ (global-set-key [remap make-frame] #'move-dup-duplicate-down)
+ (global-set-key [remap ns-print-buffer] #'move-dup-duplicate-up)
+ (global-set-key (kbd "M-p") #'move-dup-move-lines-up)
+ (global-set-key (kbd "M-n") #'move-dup-move-lines-down)
+ (global-set-key (kbd "C-,") #'backward-delete-char)
+ (global-set-key (kbd "C-.") #'embark-act)
+ (global-set-key (kbd "C-;") #'avy-goto-char-timer)
+ (global-set-key (kbd "C-s-f") #'toggle-frame-fullscreen)
+ (global-set-key [remap just-one-space] 'cycle-spacing))
+
+ (add-hook 'after-init-hook #'esy/customize-global-keymap)
+#+end_src
+
+*** =C-x= keybindings
+
+#+begin_src emacs-lisp
+ (defun esy/customize-ctl-x-map ()
+ "Configure the `C-x' keymap."
+ (require 'ialign)
+ ; (require 'magit)
+ (require 'consult)
+ (require 'ace-window)
+ (require 'flymake)
+ (require 'eww)
+ (require 'wgrep)
+ (require 'transient)
+ (require 'rg)
+ (keymap-set ctl-x-map "b" #'consult-buffer)
+ (keymap-set ctl-x-4-map "b" #'consult-buffer-other-window)
+ (keymap-set ctl-x-map "!" #'consult-flymake)
+ (keymap-set ctl-x-map "l" #'ialign)
+ (keymap-set ctl-x-map "g" #'magit-status)
+ (keymap-set ctl-x-map "s" rg-global-map)
+ (keymap-set ctl-x-map "c" #'org-capture)
+ (keymap-set ctl-x-map "o" #'ace-window)
+ (keymap-set ctl-x-map "w" #'browse-web)
+ (keymap-set ctl-x-map "j" #'org-agenda))
+
+ (add-hook 'after-init-hook #'esy/customize-ctl-x-map)
+#+end_src
+
+*** =C-h= keybindings
+
+#+begin_src emacs-lisp
+ (defun esy/customize-help-map ()
+ "Configure the `help-map' keymap."
+ (require 'helpful)
+ (keymap-set help-map "f" #'helpful-callable)
+ (keymap-set help-map "v" #'helpful-variable)
+ (keymap-set help-map "k" #'helpful-key)
+ (keymap-set help-map "o" #'helpful-symbol)
+ (keymap-set help-map "x" #'helpful-command))
+
+ (add-hook 'after-init-hook #'esy/customize-help-map)
+#+end_src
+
+*** =ace-window= homerow keys
+
+#+begin_src emacs-lisp
+ (with-eval-after-load 'ace-window
+ (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
+#+end_src
+
+*** =ace-link= setup
+
+#+begin_src emacs-lisp
+ (add-hook 'after-init-hook #'ace-link-setup-default)
+#+end_src
+
+** Display weekly agenda on startup
+#+begin_src emacs-lisp :tangle no
+ (defun esy/display-weekly-agenda ()
+ "Display the weekly agenda."
+ (org-agenda-list 1)
+ (delete-other-windows)
+ (toggle-frame-fullscreen))
+
+ (add-hook 'after-init-hook #'esy/display-weekly-agenda)
+#+end_src
+
+** Minibuffer and completions
+
+*** Enable and indicate recursive minibuffers
+
+#+begin_src emacs-lisp
+ (defun esy/setup-recursive-minibuffers ()
+ "Setup recursive minibuffers."
+ (require 'mb-depth)
+ (setq enable-recursive-minibuffers t)
+ (minibuffer-depth-indicate-mode))
+
+ (add-hook 'after-init-hook #'esy/setup-recursive-minibuffers)
+#+end_src
+
+*** Completions
+
+#+begin_src emacs-lisp
+ (defun esy/setup-completions ()
+ "Setup completions related-package."
+ (require 'corfu)
+ (require 'dabbrev)
+ (require 'cape)
+ (require 'marginalia)
+ (require 'orderless)
+ (require 'all-the-icons)
+ (require 'all-the-icons-completion)
+ (require 'hide-mode-line)
+ (setq corfu-cycle t
+ corfu-auto t
+ read-extended-command-predicate #'command-completion-default-include-p
+ completions-format 'one-column
+ completion-auto-select t
+ completion-styles '(basic orderless)
+ completion-show-help nil
+ completion-wrap-movement t)
+ (corfu-global-mode)
+ (marginalia-mode)
+ (add-to-list 'completion-at-point-functions #'cape-file)
+ (add-to-list 'completion-at-point-functions #'cape-dabbrev)
+ (add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup)
+ (add-hook 'completion-list-mode-hook #'hide-mode-line-mode))
+
+ (add-hook 'after-init-hook #'esy/setup-completions)
+
+#+end_src
+
+** Elfeed
+
+#+begin_src emacs-lisp
+ (defun esy/setup-elfeed ()
+ "Setup `elfeed'."
+ (require 'elfeed)
+ (setq elfeed-feeds
+ '("https://lwn.net/headlines/rss"
+ "https://reddit.com/r/prolog/.rss"
+ "https://www.haskellforall.com/feeds/posts/default"
+ "https://cestlaz.github.io/rss.xml"
+ "https://xkcd.com/rss.xml"
+ "https://hnrss.org/newest?points=50"
+ "https://planet.emacslife.com/atom.xml")))
+
+ (add-hook 'after-init-hook #'esy/setup-elfeed)
+#+end_src
+
+** eww
+
+#+begin_src emacs-lisp
+ (with-eval-after-load 'eww
+ (setq eww-auto-rename-buffer 'title
+ browse-url-browser-function #'eww-browse-url))
+#+end_src
+
+** Async shell commands with =dtache=
+
+#+begin_src emacs-lisp
+ (defun esy/setup-dtache ()
+ "Setup `dtache'."
+ (require 'dtache)
+ (setq dtache-notification-function #'dtache-state-transitionion-echo-message)
+ (dtache-setup))
+
+ (add-hook 'after-init-hook #'esy/setup-dtache)
+#+end_src
+
+** Mode-line customizations
+
+#+begin_src emacs-lisp
+ (defvar esy/ping-target "1.1.1.1"
+ "Target host to ping with `esy/ping'.")
+
+ (defvar esy/ping-buffer "*ping*"
+ "Output buffer used by `esy/ping'.")
+
+ (defvar esy/ping-count 1
+ "Number of pings to emit in `esy/ping'.")
+
+ (defvar esy/ping-wait-duration 1
+ "Number of seconds to wait for each ping in `esy/ping'.")
+
+ (defvar esy/ping-timeout-duration 1
+ "Number of seconds to be used as a timeout in `esy/ping'.")
+
+ (defvar esy/ping-program-options
+ `("-n" "-q"
+ "-c" ,(number-to-string esy/ping-count)
+ "-i" ,(number-to-string esy/ping-wait-duration)
+ "-t" ,(number-to-string esy/ping-timeout-duration))
+ "Command line options used in `esy/ping'.")
+
+ (defvar esy/ping-program "ping"
+ "Command used in `esy/ping'.")
+
+ (defvar esy/ping-rtt 0
+ "Last ping RTT.")
+
+ (defvar esy/ping-start-time 0
+ "Last ping RTT.")
+
+ (defvar esy/ping-interval 60
+ "Interval in seconds to wait between `esy/ping' runs.")
+
+ (defun esy/ping-update (proc rtt)
+ "Update results of ping process PROC yielding RTT."
+ (save-excursion
+ (with-current-buffer (process-buffer proc)
+ (goto-char (point-max))
+ (if rtt
+ (insert (format "%d %d" (- (float-time) esy/ping-start-time) rtt))
+ (insert (format "%d %d" (- (float-time) esy/ping-start-time) (* 1000 esy/ping-timeout-duration))))
+ (newline)))
+ (setq esy/ping-rtt rtt)
+ (force-mode-line-update t))
+
+ (defun esy/ping (&optional report)
+ "Ping `esy/ping-target'.
+ If REPORT in non-nil, print a message in the echo area with the
+ resulting ping RTT."
+ (interactive "p")
+ (make-process
+ :name "Ping"
+ :noquery t
+ :connection-type 'pipe
+ :command `(,esy/ping-program ,esy/ping-target . ,esy/ping-program-options)
+ :buffer esy/ping-buffer
+ :filter (lambda (proc output)
+ (when (string-match "/\\([0-9]+\.[0-9]*\\)/" output)
+ (let ((rtt (string-to-number (match-string 1 output))))
+ (when report
+ (message (format "Ping RTT: %d." rtt)))
+ (esy/ping-update proc rtt))))
+ :sentinel (lambda (proc event)
+ (when (not (string= event "finished\n"))
+ (esy/ping-update proc nil)
+ (message "Ping failed.")))))
+
+
+ (defun esy/ping-plot ()
+ "Plot ping RTT history with gnuplot."
+ (interactive)
+ (require 'gnuplot)
+ (gnuplot-send-string-to-gnuplot "set term dumb\n" 'line)
+ (let ((temp (expand-file-name (format "ping_%d" (float-time)) temporary-file-directory))
+ (buff (generate-new-buffer esy/ping-buffer)))
+ (with-current-buffer esy/ping-buffer
+ (copy-to-buffer buff (point-min) (point-max)))
+ (with-current-buffer buff
+ (write-file temp))
+ (gnuplot-send-string-to-gnuplot (format "plot \"%s\"\n" temp) 'line)
+ (delete-file temp)))
+
+ (defvar esy/ping-mode-line-string-format "RTT: %d"
+ "Format string for the modeline to be interpolated the last RTT.")
+
+ (defvar esy/ping-timeout-mode-line-string "Ping failed!"
+ "String shown in the modeline whenever ping fails.")
+
+ (defconst esy/ping-mode-line-local-map
+ (make-mode-line-mouse-map 'mouse-1 'esy/ping-plot)
+ "Keymap for modeline integration.")
+
+ (define-minor-mode esy/ping-mode
+ "Toggle background ping checks."
+ :global t :group 'mode-line
+ (setq esy/ping-start-time (float-time))
+ (run-with-timer 0 esy/ping-interval #'esy/ping)
+ (add-to-list 'global-mode-string '((:eval (propertize
+ (if esy/ping-rtt
+ (format esy/ping-mode-line-string-format esy/ping-rtt)
+ esy/ping-timeout-mode-line-string)
+ 'mouse-face
+ 'mode-line-highlight
+ 'local-map esy/ping-mode-line-local-map))
+ " ")))
+ (setq display-time-mail-function
+ (lambda () nil))
+
+ (display-time-mode)
+ (column-number-mode)
+
+ (add-hook 'after-init-hook #'esy/ping-mode)
+#+end_src
+
+** Setup PATH from shell environment
+#+begin_src emacs-lisp
+ (require 'exec-path-from-shell)
+ (add-hook 'after-init-hook #'exec-path-from-shell-initialize)
+#+end_src
+
+** Programming
+*** General =prog-mode= settings
+#+begin_src emacs-lisp
+ (defun esy/setup-programming ()
+ "Setup `prog-mode' and more programming-related settings."
+ (require 'rainbow-delimiters)
+ (require 'flymake)
+ (rainbow-delimiters-mode)
+ (display-line-numbers-mode)
+ (display-fill-column-indicator-mode)
+ (flymake-mode))
+
+ (add-hook 'prog-mode-hook #'esy/setup-programming)
+#+end_src
+*** Prolog specific settings
+#+begin_src emacs-lisp
+ (add-to-list 'auto-mode-alist '("\\.pl\\'" . prolog-mode))
+ (add-to-list 'auto-mode-alist '("\\.plt\\'" . prolog-mode))
+
+ (defun esy/setup-prolog ()
+ "Setup `prolog-mode' and more Prolog-related settings."
+ (require 'flymake-swi-prolog)
+ (flymake-swi-prolog-setup-backend))
+
+ (add-hook 'prolog-mode-hook #'esy/setup-prolog)
+#+end_src
+
+** LaTeX and PDF settings
+#+begin_src emacs-lisp
+ (defun esy/pdf-tools-install ()
+ "Install PDF-Tools on demand."
+ (interactive)
+ (require 'tex)
+ (require 'pdf-tools)
+ (require 'pdf-view)
+ (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-hook 'TeX-after-compilation-finished-functions
+ #'TeX-revert-document-buffer))
+#+end_src
+
+** Misc. settings
+
+#+begin_src emacs-lisp
+ (defun esy/setup-misc ()
+ "Catch-all for miscellaneous settings that can wait for `after-init-hook'."
+ (require 'autorevert)
+ (require 'which-key)
+ (require 'whitespace-cleanup-mode)
+ (setq global-auto-revert-non-file-buffers t
+ auto-revert-verbose nil)
+ (global-auto-revert-mode)
+ (which-key-mode)
+ (global-whitespace-cleanup-mode))
+
+ (add-hook 'after-init-hook #'esy/setup-misc)
+#+end_src
+** Elisp Footer
+
+#+begin_src emacs-lisp
+ (provide 'esy)
+ ;;; esy.el ends here
+#+end_src
;;; Code:
-;; Produce backtraces when errors occur: can be helpful to diagnose startup issues
-;; (setq debug-on-error t)
+;; (require 'benchmark-init)
+;; (add-hook 'after-init-hook 'benchmark-init/deactivate)
-(let ((normal-gc-cons-threshold (* 20 1024 1024))
- (init-gc-cons-threshold (* 128 1024 1024)))
- (setq gc-cons-threshold init-gc-cons-threshold)
- (add-hook 'emacs-startup-hook
- (lambda () (setq gc-cons-threshold normal-gc-cons-threshold))))
-
-(require 'package)
-
-(add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/"))
-
-(package-initialize)
-
-(unless (package-installed-p 'use-package)
- ((package-refresh-contents)
- (package-install 'use-package)))
-
-(global-set-key (kbd "C-s-f") 'toggle-frame-fullscreen)
-
-(require 'use-package)
-
-(setq native-comp-async-report-warnings-errors 'silent)
-
-(setq use-package-always-ensure t)
-
-(setq-default indent-tabs-mode nil)
-
-(load-theme 'modus-vivendi)
-(modus-themes-load-vivendi)
-
-(use-package auto-package-update
- :custom
- (auto-package-update-interval 7)
- (auto-package-update-prompt-before-update t)
- (auto-package-update-hide-results t)
- :config
- (auto-package-update-maybe)
- (auto-package-update-at-time "09:00"))
-
-(use-package 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))
-
-(recentf-mode 1)
-
-(setq history-length 25)
-(savehist-mode 1)
-
-(save-place-mode 1)
-
-(add-hook 'after-init-hook 'exec-path-from-shell-initialize)
-
-(setq use-file-dialog nil)
-(setq use-dialog-box nil)
-(setq inhibit-startup-screen t)
-
-
-(menu-bar-mode -1)
-(tool-bar-mode -1)
-(set-scroll-bar-mode nil)
-(setq ns-use-native-fullscreen t)
-
-
-(require 'wgrep)
-(require 'transient)
-(require 'rg)
-(rg-enable-default-bindings)
-
-
-(add-hook 'after-init-hook 'global-auto-revert-mode)
-(setq global-auto-revert-non-file-buffers t
- auto-revert-verbose nil)
-
-(add-hook 'after-init-hook 'transient-mark-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 'after-init-hook 'show-paren-mode)
-
-(require 'symbol-overlay)
-(global-set-key (kbd "M-i") 'symbol-overlay-put)
-
-
-(use-package move-dup
- :bind (("M-p" . move-dup-move-lines-up)
- ("M-n" . move-dup-move-lines-down)
- ("s-p" . move-dup-duplicate-up)
- ("s-n" . move-dup-duplicate-down)))
-
-(require 'which-key)
-(add-hook 'after-init-hook 'which-key-mode)
-
-(require 'whitespace-cleanup-mode)
-(add-hook 'after-init-hook 'global-whitespace-cleanup-mode)
-
-(global-set-key [remap just-one-space] 'cycle-spacing)
-
-(require 'diff-hl)
-(add-hook 'after-init-hook 'global-diff-hl-mode)
-
-(use-package magit
- :bind (("C-x g" . magit-status))
- :init
- (add-hook 'magit-post-refresh-hook #'diff-hl-magit-post-refresh))
-
-
-(require 'forge)
-
-(require 'pdf-tools)
-(require 'pdf-view)
-
-(defun esy/pdf-tools-install ()
- "Install PDF-Tools without prompting."
- (pdf-tools-install t))
-
-(esy/pdf-tools-install)
-
-(add-hook 'pdf-view-mode-hook #'pdf-view-midnight-minor-mode)
-
-(require 'ialign)
-
-(global-set-key (kbd "C-x l") #'ialign)
-
-(global-set-key (kbd "C-x m") #'execute-extended-command) ; bound to #'compose-mail by default
-(global-set-key (kbd "C-x M") #'execute-extended-command-for-buffer)
-
-(require 'keycast)
-
-(require 'publish)
-
-
-(use-package dtache
- :custom (dtache-notification-function #'dtache-state-transitionion-echo-message)
- :init (dtache-setup)
- :bind (([remap async-shell-command] . dtache-shell-command)))
-
-(add-to-list 'auto-mode-alist '("\\.pl\\'" . prolog-mode))
-(add-to-list 'auto-mode-alist '("\\.plt\\'" . prolog-mode))
-
-(require 'ob-prolog)
-
-(define-derived-mode dapscript-mode
- prolog-mode "DAP script"
- "Major mode for dapscript source files."
- (flymake-mode))
-
-(add-to-list 'auto-mode-alist '("\\.dapscript\\'" . dapscript-mode))
-
-(use-package vterm)
-(use-package lsp-mode)
-(use-package lsp-ui)
-(use-package dap-mode)
-
-(global-set-key (kbd "C-c d") 'dap-hydra)
-
-(require 'dap-ui)
-(require 'dap-swi-prolog)
-
-(require 'helpful)
-(global-set-key (kbd "C-h f") #'helpful-callable)
-(global-set-key (kbd "C-h v") #'helpful-variable)
-(global-set-key (kbd "C-h k") #'helpful-key)
-
-
-(use-package corfu
- :custom
- (corfu-cycle t)
- (corfu-auto t)
- :init
- (corfu-global-mode))
-
-(use-package dabbrev
- :bind (("M-/" . dabbrev-completion)
- ("C-M-/" . dabbrev-expand)))
-
-(use-package cape
- :init
- (add-to-list 'completion-at-point-functions #'cape-file)
- (add-to-list 'completion-at-point-functions #'cape-dabbrev))
-
-(use-package reformatter)
-
-(setq read-extended-command-predicate 'command-completion-default-include-p)
-(use-package mct)
-(add-hook 'after-init-hook 'mct-minibuffer-mode)
-
-(defun esy/choose-completion-no-exit ()
- "Hack to circumvent 'mct-choose-completion-no-exit' leaving the minibuffer."
- (interactive)
- (mct-choose-completion-no-exit)
- (mct-focus-minibuffer))
-
-(defun esy/edit-completion ()
- "Hack to circumvent 'mct-edit-completion' leaving the minibuffer."
- (interactive)
- (mct-edit-completion)
- (mct-focus-minibuffer))
-
-(define-key mct-minibuffer-completion-list-map [remap mct-choose-completion-no-exit] #'esy/choose-completion-no-exit)
-(define-key mct-minibuffer-completion-list-map [remap mct-edit-completion] #'esy/edit-completion)
-
-(use-package marginalia
- :init
- (marginalia-mode))
-
-(use-package orderless
- :custom (completion-styles '(orderless)))
-
-(use-package all-the-icons
- :if (display-graphic-p))
-
-(use-package all-the-icons-completion
- :config (all-the-icons-completion-mode))
-
-(add-hook 'marginalia-mode-hook #'all-the-icons-completion-marginalia-setup)
-
-(add-hook 'prog-mode-hook 'flymake-mode)
-
-(require 'consult)
-(require 'consult-imenu)
-
-(global-set-key [remap switch-to-buffer] 'consult-buffer)
-(global-set-key [remap switch-to-buffer-other-window] 'consult-buffer-other-window)
-(global-set-key [remap switch-to-buffer-other-frame] 'consult-buffer-other-frame)
-(global-set-key [remap goto-line] 'consult-goto-line)
-
-(global-set-key (kbd "C-c !") 'consult-flymake)
-
-(defvar esy/inbox-path "~/inbox.org"
- "Path to my Org mode inbox file.")
-
-(defvar esy/projects-root-path "~/checkouts/"
- "Path to the Projects Root directory.")
-
-(defun esy/read-project-directory ()
- "Prompt for a project directory.
-Project directories are direct subdirectories of the Projects
-Root Directory defined by 'esy/projects-root-path'."
- (read-directory-name "Project: " esy/projects-root-path))
-
-(defvar esy/org-capture-to-project-heading-history-list nil
- "History list for 'esy/org-capture-to-project-heading'.")
-
-(setq savehist-additional-variables (list 'esy/org-capture-to-project-heading-history-list))
-
-(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" (list esy/inbox-path)))
- (choice (completing-read "Project: " projects nil t nil 'esy/org-capture-to-project-heading-history-list))
- (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)))
-
-(require 'project)
-
-(defun esy/org-capture-to-current-project ()
- "Prompt for a projects and capture a related task."
- (let* ((projects
- (org-map-entries `(lambda () (nth 4 (org-heading-components)))
- (concat "+project+LEVEL=2+SCM=\"file:"
- (project-root (with-current-buffer
- (org-capture-get :original-buffer)
- (project-current)))
- "\"")
- (list esy/inbox-path)))
- (choice (car projects))
- (m (org-find-olp (cons (org-capture-expand-file esy/inbox-path) (list "Projects" choice)))))
- (set-buffer (marker-buffer m))
- (org-capture-put-target-region-and-position)
- (widen)
- (goto-char m)
- (set-marker m nil)))
-
-
-(setq org-capture-templates '(("t" "Todo [inbox]" entry
- (file+headline esy/inbox-path "Tasks")
- "** TODO %^{Task} %^g
-:PROPERTIES:
-:CreatedAt: %t
-:CapturedAt: %a
-:CapturedAs: Inbox Task
-:END:
-"
- :prepend t
- :empty-lines 1
- :immediate-finish t)
- ("n" "New Project" entry
- (file+headline esy/inbox-path "Projects")
- "** %^{Name} %^g
-:PROPERTIES:
-:CreatedAt: %t
-:CapturedAt: %a
-:CapturedAs: New Project
-:SCM: file:%(esy/read-project-directory)
-:END:
-"
- :prepend t
- :empty-lines 1
- :immediate-finish t)
- ("c" "New Calendar Event" entry
- (file+headline esy/inbox-path "Calendar")
- "** %^{Title} %^g
-:PROPERTIES:
-:CreatedAt: %t
-:CapturedAt: %a
-:CapturedAs: Calendar Event
-:END:
-%(format-time-string \"<%Y-%m-%d %H:%M\" (org-read-date t t))-%(format-time-string \"%H:%M>\" (org-read-date t t))
-%i
-"
- :prepend t
- :empty-lines 1
- :immediate-finish t)
- ("p" "New Project Task" entry
- (file+function esy/inbox-path esy/org-capture-to-project-heading)
- "*** TODO %?
-:PROPERTIES:
-:CreatedAt: %t
-:CapturedAt: %a
-:CapturedAs: Project Task
-:END:
-%i
-"
- :prepend t
- :empty-lines 1)
- ("Q" "Quick Project Task" entry
- (file+function esy/inbox-path esy/org-capture-to-project-heading)
- "*** TODO %^{Task}
-:PROPERTIES:
-:CreatedAt: %t
-:CapturedAt: %a
-:CaptuerdAs: Quick Project Task
-:END:
-%i
-"
- :prepend t
- :empty-lines 1
- :immediate-finish t)
- ("P" "Current Project Task" entry
- (file+function esy/inbox-path esy/org-capture-to-current-project)
- "*** TODO %^{Task}
-:PROPERTIES:
-:CreatedAt: %t
-:CapturedAt: %a
-:CaptuerdAs: Current Project Task
-:END:
-%i
-"
- :prepend t
- :empty-lines 1
- :immediate-finish t)))
-
-(setq org-capture-templates-contexts
- '(("P" (list project-current))))
-
-(setq org-log-into-drawer t)
-(setq org-log-done 'time)
-
-(setq org-todo-keywords
- '((sequence "TODO(t)" "BLOCKED(b@/!)" "INPROGRESS(i!)" "|" "DONE(d!)" "CANCELED(c@)")))
-
-(setq org-use-fast-todo-selection 'expert)
-
-(setq org-clock-in-switch-to-state "INPROGRESS")
-
-(setq org-babel-load-languages
- '((emacs-lisp . t)
- (shell . t)
- (bnf . t)
- (prolog . t)))
-
-(setq org-confirm-babel-evaluate nil)
-
-(global-set-key (kbd "C-c c") 'org-capture)
-(global-set-key (kbd "C-c a") 'org-agenda)
-
-(require 'calendar)
-(setq calendar-date-style 'iso)
-
-(require 'icalendar)
-
-(require 'ox-icalendar)
-(setq org-icalendar-combined-agenda-file (locate-user-emacs-file "var/icalendar.ics"))
-
-(add-to-list 'Info-default-directory-list (locate-user-emacs-file "info/"))
-;; (defun esy/diary-icalendar-sync ()
-;; "Sync the Emacs Diary with the Org exported ICalendar."
-;; (interactive)
-;; (org-icalendar-combine-agenda-files t)
-;; (delete-file diary-file)
-;; (with-current-buffer (find-file org-icalendar-combined-agenda-file)
-;; (icalendar-import-buffer diary-file t)
-;; (kill-buffer)))
-
-(use-package org-superstar)
-(add-hook 'org-mode-hook #'org-superstar-mode)
-
-(setq org-ellipsis "…")
-
-(use-package embark
- :bind
- (("C-." . embark-act))
- :config
- ;; Hide the mode line of the Embark live/completions buffers
- (add-to-list 'display-buffer-alist
- '("\\`\\*Embark Collect \\(Live\\|Completions\\)\\*"
- nil
- (window-parameters (mode-line-format . none)))))
-
-;; Consult users will also want the embark-consult package.
-(use-package embark-consult
- :ensure t
- :after (embark consult)
- :demand t ; only necessary if you have the hook below
- :hook
- (embark-collect-mode . consult-preview-at-point-mode))
-
-(require 'windmove)
-(windmove-default-keybindings 'meta)
-
-(use-package ace-window
- :bind
- (("C-x o" . ace-window))
- :config
- (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)))
-
-(require 'beacon)
-(beacon-mode 1)
-(setq beacon-color "magenta")
-
-(setq ring-bell-function 'ignore)
-
-(defun esy/pin-buffer ()
- "Pin buffer to current window."
- (interactive)
- (message
- (if (let (window (get-buffer-window (current-buffer)))
- (set-window-dedicated-p window (not (window-dedicated-p window))))
- "pinned buffer" "un-pinned buffer")
- ))
-
-(require 'company)
-
-(add-to-list 'load-path "~/.emacs.d/checkouts/flymake-swi-prolog")
-
-(require 'flymake-swi-prolog)
-
-(add-hook 'prolog-mode-hook #'flymake-swi-prolog-setup-backend)
-
-(add-to-list 'auto-mode-alist '("\\.json\\'" . json-mode))
-(defun esy/kill-dwim ()
- "When region is active, kill region, otherwise kill last word.
-Arguments BEG and END are the borders of the region."
- (interactive)
- (if (region-active-p)
- (let ((beg (region-beginning))
- (end (region-end)))
- (kill-region beg end))
- (let ((end (point)))
- (backward-word)
- (kill-region (point) end))))
-
-
-(global-set-key [remap kill-region] #'esy/kill-dwim)
-
-(minibuffer-depth-indicate-mode)
-
-(setq display-time-mail-function
- (lambda ()
- nil))
-
-(display-time-mode)
-
-
-;; (require 'typing)
-
-(require 'eww)
-
-(setq eww-auto-rename-buffer 'title)
-
-(setq browse-url-browser-function #'eww-browse-url)
-
-(require 'shr)
-(setq shr-use-colors nil)
-
-(pixel-scroll-precision-mode)
-
-(require 'avy)
-
-(global-set-key (kbd "C-:") 'avy-goto-char)
-(global-set-key (kbd "C-'") 'avy-goto-char-timer)
-
-(require 'osm)
-(require 'osm-ol)
-
-(require 'bookmark)
-(setq bookmark-save-flag 1)
-;; (require 'cov)
-
-;; (defun cov--swiplcov-parse (&optional buffer)
-;; "Foo BUFFER."
-;; (with-current-buffer (or buffer (current-buffer))
-;; (save-excursion
-;; (save-match-data
-;; (save-restriction
-;; (goto-char (point-min))
-;; ...)))))
-
-
-;; (setq cov-coverage-file-paths
-;; (list #'(lambda (file-dir file-name)
-;; (let ((path (concat file-dir
-;; "/"
-;; file-name
-;; ".cov")))
-;; (and (file-exists-p try)
-;; (cons (file-truename try) 'swiplcov))))))
-
-(setq gnus-inhibit-startup-message t)
-
-(add-hook 'after-init-hook
- (lambda ()
- (org-agenda-list 1)
- (delete-other-windows)
- (toggle-frame-fullscreen)))
-
-(require 'page-break-lines)
-(global-page-break-lines-mode)
-
-(require 'olivetti)
-(require 'logos)
-
-(setq-default logos-hide-mode-line t
- logos-scroll-lock t
- logos-variable-pitch t
- logos-indicate-buffer-boundaries t
- logos-buffer-read-only t
- logos-olivetti t)
-
-
-(let ((map global-map))
- (define-key map [remap narrow-to-region] #'logos-narrow-dwim)
- (define-key map [remap forward-page] #'logos-forward-page-dwim)
- (define-key map [remap backward-page] #'logos-backward-page-dwim))
-
-(define-key narrow-map (kbd "f") #'logos-focus-mode)
-
-(put 'narrow-to-region 'disabled nil)
-(put 'suspend-frame 'disabled t)
-
-(define-key global-map [remap suspend-frame] #'zap-up-to-char)
-
-(use-package bnf-mode)
+(load-file (locate-user-emacs-file "esy.el"))
(provide 'init)
;;; init.el ends here
+
+