.emacs.d/init.el

3090 lines
119 KiB
EmacsLisp
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

;;; Init.el --- Daniel's Emacs Configuration -*- lexical-binding: t -*-
;;; Commentary:
;; This is the main entry point for Emacs to load this configuration. The
;; structure is roughly as follows:
;; * first comes some preliminary setup, mostly setting up `package;
;; * the main activation of the configuration is done in the function
;; `db/run-init, which is installed in `after-init-hook; it is thus run
;; after init.el has been read
;; * then comes setting up all the packages that can be used by this
;; configuration; most of these packages are not loaded however, and only
;; configuration hooks are installed (using `use-package); this way a user
;; can choose in `db/run-init which configuration to activate without
;; changing much of the rest of the file.
;; * this file also introduces a new customization group `personal-settings
;; containing variables (mostly file paths) that must be set to enable some
;; of the provided functionality.
;;; Code:
;; * Preliminaries (constants and path settings)
(defconst emacs-d (file-name-directory
(file-chase-links load-file-name))
"The giant turtle on which the world rests.")
(defconst on-windows (memq system-type '(windows-nt cygwin))
"Non-nil if and only if this instance of Emacs runs on Windows.")
(setq custom-file (expand-file-name "private/custom.el" emacs-d)
custom-theme-directory (expand-file-name "themes/" emacs-d))
(add-to-list 'load-path (expand-file-name "site-lisp" emacs-d))
;; Ensure that ~/.emacs.d/private exists, because we want to store data there
(let ((private-data-dir (expand-file-name "private/" emacs-d)))
(unless (file-directory-p private-data-dir)
(make-directory private-data-dir)))
;; * Packages
(setq package-archives
'(("melpa" . "https://melpa.org/packages/")
("gnu" . "https://elpa.gnu.org/packages/")
("melpa-stable" . "https://stable.melpa.org/packages/")
("org" . "https://orgmode.org/elpa/")))
(when (< emacs-major-version 27)
;; Before Emacs 27.1, we had to do package initialization ourselves. In Emacs
;; 27.1 and later, it's done directly after loading early-init.el. See
;; https://www.gnu.org/software/emacs/news/NEWS.27.1
(load-file (expand-file-name "early-init.el" emacs-d))
(package-initialize))
(eval-when-compile
(setq use-package-enable-imenu-support t
use-package-always-defer t
use-package-verbose t
use-package-minimum-reported-time 0.01)
(dolist (package '(bind-key use-package))
(unless (package-installed-p package)
(package-install package))
(require package)))
(add-to-list 'package-pinned-packages '(use-package . "melpa-stable"))
(add-to-list 'package-pinned-packages '(bind-key . "melpa-stable"))
(put 'use-package 'lisp-indent-function 1)
;; * Mode activation
(defun db/run-init ()
"Run main initialization after everything is set up."
(message "Running main initialization ...")
;; Activate modes (builtin)
(show-paren-mode 1)
(transient-mark-mode 1)
(global-font-lock-mode 1)
(column-number-mode 1)
;; (display-time)
(delete-selection-mode 1)
(dolist (mode '(tool-bar-mode
scroll-bar-mode
menu-bar-mode
blink-cursor-mode
tooltip-mode))
(when (fboundp mode)
(funcall mode 0)))
(when (<= 24 emacs-major-version)
(electric-indent-mode -1))
(appt-activate +1)
(savehist-mode 1)
(size-indication-mode 1)
(display-battery-mode -1)
(electric-pair-mode +1)
(recentf-mode t)
(winner-mode 1)
(global-auto-revert-mode -1)
(which-function-mode +1)
(global-eldoc-mode +1)
;; Activate modes (packages)
(dolist (mode '(global-undo-tree-mode
ace-window-display-mode
key-chord-mode
ivy-mode
minions-mode
which-key-mode
eyebrowse-mode
projectile-mode
yas-global-mode
semantic-mode
global-git-commit-mode))
(with-demoted-errors "Cannot activate mode: %s"
(funcall mode +1)))
(unless on-windows
(with-demoted-errors "Cannot load `pdf-tools: %s"
(pdf-tools-install)))
(with-demoted-errors "Cannot activate moody: %s"
(moody-replace-mode-line-buffer-identification)
(moody-replace-vc-mode))
(with-demoted-errors "Cannot activate `vlf': %s"
(require 'vlf-setup))
;; Explicitly require helm, because autoloading is difficult with helm's
;; separate `helm-command-prefix-key' mechanism.
(require 'helm)
(when (package-installed-p 'org-roam)
(if (executable-find "sqlite3")
(org-roam-mode +1)
(warn "Cannot activate org-roam: sqlite3 not found.")))
;; Global Hooks
(add-hook 'minibuffer-setup-hook 'conditionally-enable-lispy)
(add-hook 'minibuffer-setup-hook 'cursor-intangible-mode)
(add-hook 'after-save-hook 'executable-make-buffer-file-executable-if-script-p)
(add-hook 'prog-mode-hook 'page-break-lines-mode)
(add-hook 'prog-mode-hook 'subword-mode)
(add-hook 'lisp-mode-hook 'turn-on-lispy-when-available)
(when (<= 24 emacs-major-version)
(add-hook 'prog-mode-hook 'electric-indent-local-mode))
(add-hook 'text-mode-hook 'turn-on-auto-fill)
(add-hook 'text-mode-hook 'abbrev-mode)
;; Auto-Modes
(dolist (mode-spec '(("\\.clj\\'" . clojure-mode)
("\\.cl\\'" . lisp-mode)
("\\.lisp\\'" . lisp-mode)
("\\.plx\\" . cperl-mode)
("\\.hs\\'" . haskell-mode)
("\\.lhs\\'" . haskell-mode)
("\\.md\\'" . markdown-mode)
("\\.html\\'" . nxml-mode)
("\\.xml\\'" . nxml-mode)))
(add-to-list 'auto-mode-alist mode-spec))
;; Top-Level Keybindings
(bind-key "<XF86Back>" #'winner-undo)
(bind-key "<XF86Forward>" #'winner-redo)
(bind-key "<Scroll_Lock>" 'scroll-lock-mode)
(bind-key "<f10>" #'magit-status)
(bind-key "<f1>" #'db/run-or-hide-eshell)
(bind-key "<f2>" #'hydra-feature-shortcuts/body)
(bind-key "<f5>" (if (executable-find "ag") #'counsel-ag #'rgrep))
(bind-key "<f6>" #'hydra-zoom/body)
(bind-key "<f7>" #'dictcc)
(bind-key "<f8>" #'bm-toggle)
(bind-key "<f9>" #'hydra-org-linking/body)
(bind-key "<C-f8>" #'bm-next)
(bind-key "<C-S-f8>" #'bm-previous)
(bind-key "C-," #'mc/skip-to-previous-like-this)
(bind-key "C-." #'mc/skip-to-next-like-this)
(bind-key "C-;" #'iedit-mode)
(bind-key "C-<" #'mc/mark-previous-like-this)
(bind-key "C->" #'mc/mark-next-like-this)
(bind-key "C-@" #'er/expand-region)
(bind-key "C-M-\\" #'crux-cleanup-buffer-or-region)
(bind-key "C-S-c C-S-c" #'mc/edit-lines)
(bind-key "C-Z" #'undo-tree-redo)
(bind-key "C-c C-<" #'mc/mark-all-like-this)
(bind-key "C-c C-r" #'ivy-resume)
(bind-key "C-c D" #'define-word)
(bind-key "C-c J" #'avy-goto-word-or-subword-1)
(bind-key "C-c P" #'ivy-pages)
(bind-key "C-c a" #'org-agenda)
(bind-key "C-c c" #'org-capture)
(bind-key "C-c d" #'define-word-at-point)
(bind-key "C-c e" #'crux-eval-and-replace)
(bind-key "C-c i" #'ispell-change-dictionary)
(bind-key "C-c j" #'avy-goto-char-timer)
(bind-key "C-c l" #'org-store-link)
(bind-key "C-c m" #'music-control/body)
(bind-key "C-c n I" #'org-roam-insert-immediate)
(bind-key "C-c n i" #'org-roam-insert)
(bind-key "C-c o" #'hydra-org-clock/body)
(bind-key "C-c s" #'synonyms)
(bind-key "C-c t" #'hydra-toggle/body)
(bind-key "C-h C-f" #'find-function)
(bind-key "C-h C-k" #'find-function-on-key)
(bind-key "C-h C-v" #'find-variable)
(bind-key "C-x 4 C-j" #'dired-jump-other-window)
(bind-key "C-x C-b" #'ibuffer)
(bind-key "C-x C-d" #'dired)
(bind-key "C-x C-j" #'dired-jump)
(bind-key "C-x C-r" #'revert-buffer)
(bind-key "C-x SPC" #'hydra-rectangle/body)
(bind-key "C-x g" #'db/helm-shortcuts)
(bind-key "C-x r E" #'db/bookmark-add-external)
(bind-key "C-x r M" #'db/bookmark-add-url)
(bind-key "C-x r v" #'list-registers)
(bind-key "C-z" #'goto-last-change)
(bind-key "M-/" #'hippie-expand)
(bind-key "M-:" #'pp-eval-expression)
(bind-key "M-=" #'count-words)
(bind-key "M-SPC" #'cycle-spacing)
(bind-key "M-Z" #'zap-to-char)
(bind-key "M-i" #'swiper-from-isearch isearch-mode-map)
(bind-key "M-j" #'(lambda () (interactive) (join-line -1)))
(bind-key "M-z" #'zap-up-to-char)
(bind-key [remap fill-paragraph] #'endless/fill-or-unfill)
(bind-key [remap keyboard-quit] #'keyboard-quit-context+)
(unbind-key "<insert>" global-map)
(unbind-key "<kp-insert>" global-map)
(unbind-key "C-x C-c" global-map)
(unbind-key "M-o" global-map)
;; Overwrite certain keybindings only if packages are avilable
(when (package-installed-p 'counsel)
(bind-key "M-x" #'counsel-M-x) ; gets nicer sorting with smex installed
(bind-key "C-c r" #'counsel-recentf)
(bind-key "C-x C-f" #'counsel-find-file)
(bind-key "C-h f" #'counsel-describe-function)
(bind-key "C-h v" #'counsel-describe-variable)
(bind-key "C-h b" #'counsel-descbinds)
(bind-key "C-S-s" #'counsel-grep-or-swiper))
(when (package-installed-p 'helm)
(bind-key "M-y" #'helm-show-kill-ring))
(when (package-installed-p 'crux)
(bind-key [remap kill-whole-line] #'crux-kill-whole-line)
(bind-key [remap open-line] #'crux-smart-open-line-above))
(when (package-installed-p 'ace-window)
(bind-key "C-x o" #'ace-window))
(when (package-installed-p 'avy)
(bind-key "M-g M-g" #'avy-goto-line)
(bind-key "M-g g" #'avy-goto-line))
;; Environment Variables
(unless on-windows
(with-demoted-errors "Cannot import environment variables: %s"
(exec-path-from-shell-copy-envs '("SSH_AUTH_SOCK"
"SSH_AGENT_PID"
"PATH"
"TEXMFHOME"
"PERL5LIB"
"PERL_LOCAL_LIB_ROOT"
"PERL_MB_OPT"
"PERL_MM_OPT"))))
;; Start Server when not running already
;; The following condition should actually always be false, since we have
;; neither loaded the server package yet nor have explicitly started the
;; server process. Also the --daemon command line switches will start the
;; server only later, after initialization (and they do so unconditionally,
;; thus restarting the server we have started here). However, for robustness,
;; we keep the condition nevertheless, since when a server process is already
;; present, we really don't have to do anything. Furthermore, calling
;; `db/run-init' again in a running Emacs will not restart the server (but
;; then, why whould one want to do this?).
(if (and (boundp 'server-process) server-process)
(message "Server already running, not restarting.")
(require 'server)
(let ((server-file (expand-file-name server-name
(if server-use-tcp server-auth-dir server-socket-dir))))
(if (file-exists-p server-file)
(warn "Server file already exists, but no server process is running. Check %s and restart server manually."
server-file)
(server-start)
(cl-ecase (server-running-p)
((t) t) ; server is running
(nil (warn "Server not running, check logs and restart manually."))
(t (warn "`server-running-p' returned neither nil nor t. Check and restart server manually if required."))))))
;; Load custom code
(dolist (file db/after-init-load-files)
(message "Loading %s" file)
(with-demoted-errors "Error loading file: %s"
(load-file file)))
;; Finish
(message "Running main initialization ... done")
t)
(add-hook 'after-init-hook #'db/run-init)
;; * Personal customization
(use-package db-customize
:demand t
:defines (db/jabber-id
db/important-documents-path
db/path-to-onenote
db/path-to-outlook
db/cert-file-directory
org-working-task-id
org-break-task-id
org-home-task-id
db/org-clock-current-task-file
db/org-default-org-file
db/org-default-work-file
db/org-default-home-file
db/org-default-notes-file
db/org-default-refile-file
db/after-init-load-files))
;; * General configuration
(use-package cl-lib
:demand t)
(use-package subr-x
:demand t)
(set-default-coding-systems 'utf-8)
(prefer-coding-system 'utf-8)
(set-terminal-coding-system 'utf-8)
(set-keyboard-coding-system 'utf-8)
(setq buffer-file-coding-system 'utf-8)
(setq x-select-request-type '(UTF8_STRING COMPOUND_TEXT TEXT STRING))
(setq inhibit-startup-message t
inhibit-default-init t
frame-inhibit-implied-resize t
initial-scratch-message nil
initial-major-mode 'fundamental-mode
ring-bell-function #'ignore
garbage-collection-messages nil
load-prefer-newer nil ; t breaks `org-reload'
auth-sources '("~/.authinfo.gpg")
auth-source-save-behavior nil)
(fset 'yes-or-no-p 'y-or-n-p)
(setq-default fill-column 80)
(setq-default indent-tabs-mode nil)
(setq frame-title-format "emacs")
(setq select-enable-clipboard t
select-enable-primary t
save-interprogram-paste-before-kill t
mouse-yank-at-point t
require-final-newline nil
sentence-end-double-space t
recenter-positions '(top middle bottom)
scroll-conservatively 10
message-log-max t
inhibit-eol-conversion nil
tab-always-indent 'complete
completion-cycle-threshold 10
enable-recursive-minibuffers t
set-mark-command-repeat-pop t
large-file-warning-threshold 10000000
echo-keystrokes 0.1
delete-by-moving-to-trash t
delete-trailing-lines nil
x-underline-at-descent-line t
search-whitespace-regexp "[ \t\r\n]+"
visual-line-fringe-indicators '(left-curly-arrow right-curly-arrow)
history-delete-duplicates t
track-eol t
gc-cons-threshold (* 100 1024 1024) ; 100mb
read-process-output-max (* 1024 1024)) ; 1mb
(when (memq system-type '(gnu gnu/linux gnu/kfreebsd))
(setq x-wait-for-event-timeout nil))
(when on-windows
;; treat memory for display time ... but hey, this is Windows, memory doesnt
;; matter!
(setq inhibit-compacting-font-caches t))
;; don't let the cursor go into minibuffer prompt
(setq minibuffer-prompt-properties '(read-only t
face minibuffer-prompt
cursor-intangible t))
;; Make M-v undo C-v
(setq scroll-preserve-screen-position 'always)
;; Backups and Autosave
(defvar backup-dir (expand-file-name "ebackup/" emacs-d))
(defvar autosave-dir (expand-file-name "eautosave/" emacs-d))
(setq make-backup-files t
backup-directory-alist (list (cons ".*" backup-dir))
auto-save-list-file-prefix autosave-dir
auto-save-file-name-transforms `((".*" ,autosave-dir t))
version-control t
kept-old-versions 2
kept-new-versions 4
delete-old-versions t
vc-make-backup-files t)
(setq undo-limit 80000000)
(setq-default async-shell-command-buffer 'new-buffer)
(add-to-list 'display-buffer-alist
'("^\\*Async Shell Command*" . (display-buffer-no-window)))
(put 'set-goal-column 'disabled nil)
(put 'upcase-region 'disabled nil)
(put 'downcase-region 'disabled nil)
(put 'narrow-to-region 'disabled nil)
(setq-default savehist-file (expand-file-name "savehist" emacs-d))
(setq default-input-method "TeX")
;; * Fixes
(with-eval-after-load 'enriched
(defun enriched-decode-display-prop (start end &optional params)
(ignore params)
(list start end)))
;; Disable gconf settings, as it might interfere with ours. Cf.
;; https://debbugs.gnu.org/cgi/bugreport.cgi?bug=25228 and
;; https://emacs.stackexchange.com/questions/32641/something-changes-the-default-face-in-my-emacs.
(define-key special-event-map [config-changed-event] 'ignore)
;; * Builtin Packages
(use-package misc
:commands (zap-up-to-char zap-to-char))
(use-package grep
:commands (rgrep zrgrep)
:bind (:map grep-mode-map
("C-x C-q" . wgrep-change-to-wgrep-mode)
("C-c C-c" . wgrep-finish-edit)))
(use-package winner
:commands (winner-mode winner-undo winner-redo))
(use-package abbrev
:init (setq save-abbrevs 'silently
abbrev-file-name (expand-file-name "private/abbrev_defs"))
:diminish abbrev-mode)
(use-package appt
:commands (appt-activate)
:init (setq appt-display-mode-line nil))
(use-package ispell
:commands (ispell-change-directory))
(use-package mailcap
:config (progn
;; Remove doc-view so pdf will open with default viewer
(setcdr
(assoc "application" mailcap-mime-data)
(remove '("pdf"
(viewer . doc-view-mode)
(type . "application/pdf")
(test eq window-system 'x))
(cdr (assoc "application" mailcap-mime-data))))))
(use-package quail
:config (add-hook 'input-method-activate-hook
#'db/add-symbols-to-TeX-input-method))
(use-package isearch
:init (setq isearch-allow-scroll t))
(use-package server
:commands (server-running-p server-start)
:init (setq server-log t))
(use-package bookmark
:init (setq bookmark-default-file (expand-file-name "private/bookmarks"
emacs-d)))
(use-package warnings
:config (cl-pushnew '(undo discard-info) warning-suppress-types
:test #'equal))
(use-package calender
:init (setq calendar-date-style 'iso
calendar-week-start-day 1 ; Monday
calendar-bahai-all-holidays-flag nil
calendar-chinese-all-holidays-flag nil
calendar-christian-all-holidays-flag t
calendar-islamic-all-holidays-flag nil
calendar-hebrew-all-holidays-flag nil
holiday-general-holidays '((holiday-fixed 1 1 "New Year's Day")
(holiday-fixed 2 14 "Valentine's Day")
(holiday-fixed 4 1 "April Fools' Day")
(holiday-fixed 5 1 "Labour Day")
(holiday-fixed 10 3 "German Unity Day")
(holiday-fixed 10 31 "Reformation Day")
(holiday-float 11 3 -1 "Day of Repentance and Prayer" 22)
(holiday-float 11 4 4 "Thanksgiving"))
holiday-other-holidays '((holiday-fixed 2 13 "Jahrestag Zerstörung Dresden 1945")
(holiday-fixed 5 25 "Towel Day")
(holiday-fixed 6 4 "Tiananmen Massacre 1989")
(holiday-fixed 6 5 "Snowden-Veröffentlichungen 2013")
(holiday-fixed 6 6 "D-Day 1944")
(holiday-fixed 6 8 "Yoneda Appreciation Day")
(holiday-fixed 6 10 "Jahrestag Zerstörung von Oradour-sur-Glane 1944")
(holiday-fixed 6 10 "Jahrestag Massaker von Distomo 1944")
(holiday-fixed 6 16 "Bloomsday")
(holiday-fixed 7 20 "Jahrestag Attentat auf Hitler 1944")
(holiday-fixed 7 21 "Jahrestag der 1. Mondlandung 1969")
(holiday-fixed 7 21 "Jahrestag Massaker von Vassieux-en-Vercors 1944")
(holiday-fixed 7 28 "Start WWI 1914")
(holiday-fixed 11 11 "End WWI 1918"))
diary-show-holidays-flag t
calendar-view-holidays-initially-flag nil))
(use-package re-builder
:commands (re-builder)
:init (setq reb-re-syntax 'string))
(use-package browser-url
:init (setq browse-url-browser-function 'browse-url-generic
browse-url-generic-program "firefox"))
(use-package tramp
:init (setq tramp-default-method (if on-windows "plink" "sshx")))
(use-package calc
;; https://florian.adamsky.it/2016/03/31/emacs-calc-for-programmers-and-cs.html
:defines (math-additional-units
math-units-table)
:init (setq math-additional-units
'((bit nil "Bit")
(byte "8 * bit" "Byte")
(bps "bit / s" "Bit per second"))
math-units-table nil))
(use-package tab-bar
:init (setq tab-bar-show nil)
:config (progn
(tab-bar-history-mode +1)))
;; * Essential external packages
(use-package dash)
(use-package hydra
:pin "melpa-stable")
;; `lv' is a dependency of `hydra'
(add-to-list 'package-pinned-packages '(lv . "melpa-stable"))
(use-package db-utils
:commands (endless/fill-or-unfill
db/delete-trailing-whitespace-maybe
db/run-or-hide-shell
db/gnus
db/org-agenda
db/scratch
db/find-user-init-file
db/run-or-hide-ansi-term
db/hex-to-ascii
db/text-to-hex
conditionally-enable-lispy
turn-on-lispy-when-available
turn-on-flycheck-when-file
db/sort-nsm-permanent-settings
endless/colorize-compilation
db/turn-off-local-electric-pair-mode
db/add-symbols-to-TeX-input-method
db/two-monitors-xrandr
db/one-monitor-xrandr
db/pretty-print-xml
db/bookmark-add-external
db/bookmark-add-url
db/lookup-smime-key
db/dired-from-shell-command
db/system-open
db/switch-to-dark-theme
db/switch-to-light-theme
keyboard-quit-context+
db/convert-lf-to-crlf-in-buffer
db/convert-crlf-to-lf-in-buffer
db/sync-magit-repos-from-projectile))
(use-package db-hydras
:commands (hydra-toggle/body
hydra-zoom/body
hydra-rectangle/body
db/define-feature-shortcuts-hydra
hydra-feature-shortcuts/body))
(use-package exec-path-from-shell
:pin "melpa-stable"
:commands (exec-path-from-shell-copy-envs))
(use-package crux
:ensure t
:commands (crux-eval-and-replace
crux-smart-open-line-above
crux-kill-whole-line
crux-cleanup-buffer-or-region
crux-delete-buffer-and-file))
;; * Text editing
(use-package electric
:commands (electric-quote-mode))
(use-package elec-pair
:commands (electric-pair-mode)
:config (progn
(add-to-list 'electric-pair-pairs '(?“ . ?”))
(add-to-list 'electric-pair-text-pairs '(?“ . ?”))
(add-to-list 'electric-pair-pairs '(?„ . ?“))
(add-to-list 'electric-pair-text-pairs '(?„ . ?“))))
(use-package flyspell
:commands (flyspell-mode turn-on-flyspell)
:config (progn
(unbind-key "C-M-i" flyspell-mode-map)
(unbind-key "C-c $" flyspell-mode-map)))
(use-package key-chord
:ensure t
:commands (key-chord-mode)
:config (progn
(key-chord-define-global "``" "")
(key-chord-define-global "''" "")
(key-chord-define-global ",," "")))
(use-package multiple-cursors
:pin "melpa-stable"
:ensure t
:commands (mc/edit-lines
mc/mark-next-like-this
mc/mark-previous-like-this
mc/mark-all-like-this))
(use-package synonyms
:commands (synonyms))
(use-package undo-tree
:ensure t
:commands (global-undo-tree-mode
undo
undo-tree-redo)
:init (setq undo-tree-visualizer-timestamps t
undo-tree-visualizer-diff t)
:diminish undo-tree-mode)
(use-package wgrep
:ensure t
:commands (wgrep-finish-edit
wgrep-change-to-wgrep-mode))
(use-package yasnippet
:commands (yas-minor-mode-on
yas-minor-mode
yas-global-mode
yas-reload-all)
:ensure t
:diminish yas-minor-mode
:config (yas-reload-all))
;; * Org
(use-package db-org
:commands (db/check-special-org-files-in-agenda
db/verify-refile-target
org-reset-checkbox-state-maybe
db/find-parent-task
db/ensure-running-clock
db/save-current-org-task-to-file
db/org-update-frame-title-with-current-clock
db/org-clock-out
db/org-clock-in-break-task
db/org-clock-in-home-task
db/org-clock-in-work-task
db/show-current-org-task
endless/org-ispell
db/org-agenda-list-deadlines
db/org-agenda-skip-tag
hydra-org-agenda-view/body
db/org-agenda-insert-efforts
org-babel-execute:hy
db/org-timestamp-difference
db/org-capture-code-snippet
hydra-org-clock/body
db/make-org-capture-frame
db/org-onenote-open
db/org-outlook-open
db/org-rfc-open
db/org-cleanup-continuous-clocks
db/find-csv-in-org
db/org-mark-current-default-task
db/export-diary
db/org-copy-template-for-periodic-task
db/org-find-links-to-current-item
db/org-add-link-to-other-item
db/org-add-link-to-current-clock
hydra-org-linking/body))
(use-package org
:pin "gnu"
:bind (:map org-mode-map
([remap org-return] . org-return-indent))
:init (progn
(setq org-deadline-warning-days 14
org-read-date-popup-calendar t
org-insert-heading-respect-content t
org-adapt-indentation nil
org-edit-timestamp-down-means-later t
org-archive-location "%s_archive.gpg::"
org-image-actual-width nil
org-imenu-depth 10
org-footnote-section nil
org-log-into-drawer "LOGBOOK"
org-log-reschedule 'note
org-log-redeadline 'note
org-log-note-clock-out nil
org-log-done 'note
org-clone-delete-id t
org-catch-invisible-edits 'error
org-M-RET-may-split-line '((default . nil))
org-highlight-latex-and-related '(latex)
org-use-sub-superscripts '{}
org-src-fontify-natively t
org-src-preserve-indentation t
org-src-tab-acts-natively nil
org-ellipsis ""
org-fontify-done-headline nil
org-cycle-separator-lines 0
org-duration-format '(("y") ("w") ("d") (special . h:mm))
org-treat-S-cursor-todo-selection-as-state-change nil
org-global-properties
'(("Effort_ALL" . "0:00 0:05 0:10 0:15 0:30 0:45 1:00 2:00 3:00 4:00 6:00 8:00"))
org-columns-default-format
"%80ITEM(Task) %10Effort(Effort) %10CLOCKSUM")
;; Keywords and Tags
(setq org-todo-keywords
'((sequence "TODO(t)" "CONT(n!)" "|" "DONE(d@)")
(sequence "GOTO(g)" "ATTN(a)" "|" "DONE(d@)")
(sequence "READ(r)" "CONT(n!)" "|" "DONE(d@)")
(sequence "DELG(e@/!)" "WAIT(w@/!)" "HOLD(h@/!)"
"|" "CANC(c@/!)" "PHONE" "MEETING"))
org-todo-state-tags-triggers
'(("WAIT" ("HOLD") ("WAIT" . t))
("DELG" ("HOLD") ("WAIT" . t))
("HOLD" ("HOLD" . t) ("WAIT"))
(done ("HOLD") ("WAIT"))
("TODO" ("HOLD") ("WAIT") ("DATE") ("READ"))
("READ" ("READ" . t) ("DATE") ("HOLD") ("WAIT"))
("GOTO" ("DATE" . t) ("READ") ("HOLD") ("WAIT"))
("CONT" ("DATE") ("HOLD") ("WAIT"))
("ATTN" ("DATE" . t) ("READ") ("HOLD") ("WAIT"))
("" ("HOLD") ("WAIT") ("DATE") ("READ")))
org-tag-alist
'((:startgroup . nil)
("WORK" . ?w)
("HOME" . ?h)
("FUN" . ?f)
("UNTAGGED" . ?u)
(:endgroup . nil)
("NOTE" . ?n)
("PERIODIC" . ?p)
("REGULAR" . ?r)
("NOP" . ?o)
("TOPIC" . ?t))
org-fast-tag-selection-single-key 'expert)
;; Faces
(setq org-todo-keyword-faces
'(("TODO" :foreground "red" :weight normal)
("GOTO" :foreground "red" :weight normal)
("READ" :foreground "red" :weight normal)
("CONT" :foreground "DeepSkyBlue" :weight normal)
("ATTN" :foreground "DeepSkyBlue" :weight normal)
("DONE" :foreground "forest green" :weight normal)
("DELG" :foreground "dark orange" :weight normal)
("WAIT" :foreground "orange" :weight normal)
("HOLD" :foreground "magenta" :weight normal)
("CANC" :foreground "lime green" :weight normal)
("MEETING" :foreground "forest green" :weight normal)
("PHONE" :foreground "forest green" :weight normal)
("REPEAT" :foreground "indian red" :weight normal))
org-priority-faces
'((?A . (:foreground "Red" :weight bold))
(?B . (:foreground "firebrick"))
(?C . (:foreground "tomato"))))
;; Refiling
(setq org-refile-targets '((org-agenda-files . (:maxlevel . 9))
(nil . (:maxlevel . 9))
(db/org-default-notes-file . (:maxlevel . 9)))
org-refile-use-outline-path 'file
org-refile-use-cache t
org-refile-allow-creating-parent-nodes 'confirm
org-indirect-buffer-display 'current-window
org-outline-path-complete-in-steps nil
org-refile-target-verify-function 'db/verify-refile-target)
;; Bable
(setq org-babel-load-languages '((shell . t)
(emacs-lisp . t))))
:config (progn
;; Allow company completion in Org Mode buffers
(add-hook 'org-mode-hook 'company-mode)
;; Reset checkboxes if the RESET_CHECK_BOXES property is set
(add-hook 'org-after-todo-state-change-hook 'org-reset-checkbox-state-maybe)
;; Statically color links sponding to whether the file exists, but
;; this turns out to be slow on Windows; we can use `org-lint' for
;; this when necessary)
(org-link-set-parameters "file" :face 'org-link)
;; File Apps
(add-to-list 'org-file-apps '(directory . emacs))
(add-to-list 'org-file-apps '("\\.docx?\\'" . default))
(add-to-list 'org-file-apps '("\\.pptx?\\'" . default))
(add-to-list 'org-file-apps '("\\.xlsx?\\'" . default))
(when (eq system-type 'cygwin)
(add-to-list 'org-file-apps '(t . "cygstart %s") t))
;; Custom link types for Windows
(when (eq system-type 'windows-nt)
(org-link-set-parameters "onenote" :follow #'db/org-onenote-open)
(org-link-set-parameters "outlook" :follow #'db/org-outlook-open))
;; Skip some org mode regions to be skipped by ispell
(add-hook 'org-mode-hook #'endless/org-ispell)
;; Link type for RFCs
(org-link-set-parameters "rfc" :follow #'db/org-rfc-open)
;; Some timers
(unless (memq #'org-clock-save
(mapcar #'timer--function timer-list))
(run-with-timer 0 3600 #'org-clock-save))
(unless (memq #'db/export-diary
(mapcar #'timer--function timer-idle-list))
(run-with-idle-timer 200 t #'db/export-diary))
;; Hack: The default implementation is too slow, because it is
;; parsing all properties of an entry by default. Lets simplify
;; this to only parse what we are looking for. This makes tag
;; search *much* faster!
(with-eval-after-load 'org
(defun org-cached-entry-get (pom property)
(if (or (eq t org-use-property-inheritance)
(and (stringp org-use-property-inheritance)
(let ((case-fold-search t))
(string-match-p org-use-property-inheritance property)))
(and (listp org-use-property-inheritance)
(member-ignore-case property org-use-property-inheritance)))
;; Caching is not possible, check it directly.
(org-entry-get pom property 'inherit)
;; This is different in the original implementation
(org-entry-get pom property))))))
;; Drag-and-Drop images into org-mode buffer
(use-package org-download
:commands (org-download-yank
org-download-screenshot
org-download-clipboard)
:init (setq org-download-method 'attach))
(use-package ol
:init (setq org-link-keep-stored-after-insertion t)
:commands (org-store-link))
(use-package org-id
:init (setq org-id-link-to-org-use-id t))
(use-package org-clock
:commands (org-clock-save)
:init (progn
(setq org-clock-history-length 23
org-clock-in-resume t
org-clock-into-drawer t
org-clock-idle-time nil
org-clock-out-remove-zero-time-clocks t
org-clock-out-when-done '("DONE" "CANC" "WAIT" "HOLD")
org-clock-auto-clock-resolution 'when-no-clock-is-running
org-clock-mode-line-total 'auto
org-clock-report-include-clocking-task t
org-clock-in-switch-to-state (lambda (_)
(when (not
(and (boundp 'org-capture-mode)
org-capture-mode))
(cond
((member (org-get-todo-state)
(list "TODO" "READ"))
"CONT")
((member (org-get-todo-state)
(list "GOTO"))
"ATTN"))))
org-clock-persist t
org-clock-persist-query-resume nil
org-time-stamp-rounding-minutes '(1 1))
;; On Windows, we don't have dbus to show notifications; default to
;; `message' instead
(when on-windows
(setq org-show-notification-handler #'message)))
:config (progn
(org-clock-persistence-insinuate)
(add-hook 'org-clock-in-hook #'db/org-mark-current-default-task)
(add-hook 'org-clock-in-hook #'db/org-update-frame-title-with-current-clock)
;; Clock in default task if no other task is given
(add-hook 'org-clock-out-hook #'db/ensure-running-clock 'append)
;; Communicate the currently clocked in task to the outside world
(add-hook 'org-clock-in-hook #'db/save-current-org-task-to-file)))
;; Agenda
(use-package org-agenda
:commands (org-agenda)
:bind (:map org-agenda-mode-map
("i" . org-agenda-clock-in)
("v" . hydra-org-agenda-view/body))
:init (setq org-agenda-include-diary t
org-agenda-span 1
org-agenda-insert-diary-strategy 'top-level
org-catch-invisible-edits 'show
org-agenda-sorting-strategy '((agenda time-up habit-up priority-down)
(todo category-keep)
(tags category-keep)
(search category-keep))
org-agenda-window-setup 'current-window
org-agenda-restore-windows-after-quit t
org-agenda-compact-blocks nil
org-agenda-todo-ignore-with-date nil
org-agenda-todo-ignore-deadlines nil
org-agenda-todo-ignore-scheduled nil
org-agenda-todo-ignore-timestamp nil
org-agenda-skip-deadline-if-done t
org-agenda-skip-scheduled-if-done t
org-agenda-skip-timestamp-if-done t
org-agenda-skip-scheduled-if-deadline-is-shown 'not-today
org-agenda-tags-todo-honor-ignore-options t
org-agenda-start-with-log-mode nil
org-agenda-log-mode-items '(closed)
org-agenda-remove-tags t
org-agenda-sticky nil
org-agenda-inhibit-startup nil
org-agenda-tags-todo-honor-ignore-options t
org-agenda-dim-blocked-tasks nil
org-enforce-todo-checkbox-dependencies t
org-enforce-todo-dependencies t
org-agenda-use-time-grid t
org-agenda-persistent-filter t
org-agenda-search-headline-for-time nil
org-agenda-search-view-always-boolean t
;; Show daily efforts directly in the agenda
org-agenda-finalize-hook '(db/org-agenda-insert-efforts)
org-agenda-clock-consistency-checks
'(:max-duration 9999999
:min-duration 0
:max-gap 0
:gap-ok-around nil
:default-face ((:background "DarkRed") (:foreground "white"))
:overlap-face nil :gap-face nil :no-end-time-face nil
:long-face nil :short-face nil)
org-agenda-clockreport-parameter-plist
'(:link t :maxlevel 4 :compact t :narrow 60 :fileskip0 t)
org-stuck-projects
'("+TODO=\"\"-DATE-REGULAR-HOLD-NOTE-TAGS={NOP\\|TOPIC\\|SOMEWHEN}"
("CONT" "TODO" "READ" "WAIT" "GOTO" "DELG" "ATTN")
()
"")
org-agenda-prefix-format
'((agenda . "%11s%?-12t%-4e ")
(todo . "%-8c%-4e ")
(tags . "%-8c%-4e ")
(search . "%-8c%-4e "))
org-agenda-custom-commands
`(("A" "Main Agenda"
((agenda
""
((org-agenda-entry-types '(:timestamp :sexp :scheduled))
(org-deadline-warning-days 0)))
(db/org-agenda-list-deadlines
""
((org-agenda-overriding-header "Deadlines")
(org-agenda-sorting-strategy '(deadline-up priority-down))
(org-deadline-warning-days 30)))
(tags "REFILE"
((org-agenda-files (list db/org-default-refile-file))
(org-agenda-overriding-header "Things to refile (make it empty!)")))
(tags-todo "-HOLD-SOMEWHEN-DATE-WAIT-READ/-DONE"
((org-agenda-overriding-header "Next Actions List (unscheduled actions)")
(org-tags-match-list-sublevels t)
(org-agenda-todo-ignore-scheduled t)
(org-agenda-sorting-strategy '(priority-down category-up))))
(tags-todo "READ-SOMEWHEN/-DONE"
((org-agenda-overriding-header "Reading List")
(org-agenda-todo-ignore-scheduled t)
(org-agenda-sorting-strategy
'(priority-down time-up category-keep))))))
("O" "Open, non-periodic TODOs"
((tags-todo "-PERIODIC-SOMEWHEN-REGULAR-HOLD"
((org-agenda-overriding-header "List of open, non-periodic TODO items")
(org-use-tag-inheritance t)
(org-agenda-sorting-strategy '(deadline-down priority-down))
(org-agenda-prefix-format '((tags . "%-12c %-4e ")))))))
("U" "Unsupervised (Waiting, Missed Appointments, Hold)"
((tags-todo "WAIT"
((org-agenda-overriding-header "Waiting For List")
(org-agenda-todo-ignore-scheduled t)
(org-agenda-sorting-strategy '(priority-down category-up))))
(tags-todo "DATE"
((org-agenda-overriding-header "Missed appointments (DATEs with timestamp in the past)")
(org-agenda-todo-ignore-timestamp 0)))
(tags-todo "HOLD"
((org-agenda-overriding-header "Tasks on Hold")))))
("S" "Somewhen (Do if nothing else to do, i.e., personal backlog)"
((tags-todo "SOMEWHEN/-CANC-DONE"
((org-agenda-overriding-header "Things to do or read somewhen")
(org-agenda-todo-ignore-with-date t)
(org-tags-match-list-sublevels nil)))))
("P" "Current Projects"
((stuck ""
((org-agenda-overriding-header "Stuck Projects")))
(tags "TODO=\"\"-TAGS={NOP\\|TOPIC}-PERIODIC-NOTE-DATE"
((org-agenda-overriding-header "Open Projects (no TODO keyword, no PERIODIC, no NOTE, no DATE)")))
(tags "TAGS={PERIODIC}"
((org-agenda-overriding-header "Periodic Projects (PERIODIC)")))))
("W" "Weekly Review"
((agenda ""
((org-agenda-span 7)
(org-agenda-dim-blocked-tasks nil)
(org-agenda-skip-deadline-prewarning-if-scheduled t)))))))
:config (progn
;; avoid important buffers to end up in `org-agenda-new-buffers by
;; opening them manually
(mapc #'find-file-noselect org-agenda-files)
(add-hook 'org-agenda-mode-hook #'hl-line-mode 'append)
(advice-add 'org-agenda
:before #'db/check-special-org-files-in-agenda)))
;; Capturing
(use-package org-capture
:commands (org-capture)
:init (setq org-capture-use-agenda-date nil
org-capture-templates
`(("t" "Simple Task"
entry
(file db/org-default-refile-file)
,(concat "* TODO [#B] %^{What}\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"%a\n"
"%?"))
("T" "Complex Tasks")
("TC" "Record new complex task with first item"
entry
(file db/org-default-refile-file)
,(concat "* %^{Task Description}\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n** TODO [#B] %^{First Thing to Do}\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n%?"))
("TT" "Record new ticket with first item"
entry
(file db/org-default-refile-file)
,(concat "* Ticket #%^{Ticket Number}: %^{Ticket Description}\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\nReference: %^{Reference}\n"
"\n** TODO [#B] %^{First Task}\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n%?"))
("n" "Note"
entry
(file db/org-default-refile-file)
"* %^{About} :NOTE:\n:PROPERTIES:\n:CREATED: %U\n:END:\n\n%?")
("d" "Date"
entry
(file db/org-default-refile-file)
"* GOTO [#B] %^{What} :DATE:\n%^{When}t\n%a%?")
("i" "Interruptions"
entry
(file db/org-default-refile-file)
,(concat "* DONE [#B] %^{What}\nCLOSED: %U\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n%?")
:clock-in t :clock-resume t)
("r" "respond"
entry
(file db/org-default-refile-file)
,(concat "* TODO [#B] Reply: %:subject (%:from) :EMAIL:\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n%a\n%?"))
("R" "read"
entry
(file db/org-default-refile-file)
,(concat "* READ [#B] %^{Topic} :READ:\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n%a\n%?"))
("U" "Read current content of clipboard"
entry
(file db/org-default-refile-file)
,(concat "* READ [#B] %^{Description} :READ:\n"
":PROPERTIES:\n:CREATED: %U\n:END:\n"
"\n%(current-kill 0)"))
("w" "Weekly Summary"
entry
(file+olp+datetree db/org-default-pensieve-file "Reviews")
"* Weekly Review\n\n%?")
("s" "Code Snippet"
entry
(file db/org-default-refile-file)
"* %?\n%(db/org-capture-code-snippet \"%F\")")
;; http://www.howardism.org/Technical/Emacs/capturing-content.html
("c" "Note for currently clocked in task"
item
(clock)
"%i%?"
:empty-lines 1)
("K" "Kill-ring to currently clocked in task"
plain
(clock)
"%c"
:immediate-finish t :empty-lines 1)))
:config (progn
;; disable usage of helm for `org-capture'
(with-eval-after-load 'helm-mode
(defvar helm-completing-read-handlers-alist) ; for the byte compiler
(add-to-list 'helm-completing-read-handlers-alist
'(org-capture . nil)))))
;; Babel
(use-package ob-core
:init (setq org-export-use-babel nil)
:config (setf (alist-get :results org-babel-default-header-args)
"output code replace"))
(use-package ob-sql
:config (progn
(defun db/ob-sql-oracle-ask-for-password (orig-fun
host port user password database)
"Ask for PASSWORD if not given, and call ORIG-FUN with arguments afterwards."
(cond
((not (or (and user database host port)
(and user database)))
(user-error "Insufficient login credentials given, aborting"))
(password
(funcall orig-fun host port user password database))
(t
(funcall orig-fun
host port user
(password-read (format "Password for %s@%s: " user database))
database))))
(advice-add #'org-babel-sql-dbstring-oracle
:around #'db/ob-sql-oracle-ask-for-password)))
;; Exporting
(use-package ox-icalendar
:commands (org-icalendar-combine-agenda-files)
:init (setq org-icalendar-include-body nil
org-icalendar-store-UID t
org-icalendar-use-deadline nil
org-icalendar-use-scheduled nil
org-icalendar-include-todo nil
org-icalendar-exclude-tags '("NO_EXPORT")))
(use-package ox
:init (setq org-export-with-broken-links 'mark
org-export-with-sub-superscripts '{}
org-export-with-author nil
org-export-with-date nil
org-export-with-toc nil
org-export-with-archived-trees nil
org-export-with-tags t
org-export-with-priority nil
org-export-with-creator nil
org-export-with-entities t
org-export-with-special-strings t
org-export-with-todo-keywords nil
org-export-exclude-tags '("NO_EXPORT"))
:config (with-demoted-errors "Cannot load package: %s"
(require 'ox-md)
(require 'ox-pandoc)))
(use-package ox-latex
:init (setq org-latex-default-class "scrartcl"
org-latex-listings t
org-latex-compiler "lualatex")
:config (progn
(add-to-list 'org-latex-classes
`("scrartcl"
,(concat "\\documentclass[parskip=half,colorlinks]{scrartcl}\n"
"[DEFAULT-PACKAGES]"
"[PACKAGES]"
"
\\lstset{
basewidth=0.5em,
keywordstyle=\\textcolor{blue!80!white},
basicstyle=\\ttfamily,
commentstyle={\\itshape},
frame=tb,
showspaces=false,
showtabs=false,
showstringspaces=false,
}
"
"[EXTRA]\n")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")
("\\paragraph{%s}" . "\\paragraph*{%s}")
("\\subparagraph{%s}" . "\\subparagraph*{%s}")))
(add-to-list 'org-latex-classes
`("beamer"
,(concat "\\documentclass[presentation]{beamer}\n"
"[DEFAULT-PACKAGES]"
"[PACKAGES]"
"
\\lstset{
basewidth=0.5em,
keywordstyle=\\textcolor{blue!80!white},
basicstyle=\\ttfamily,
commentstyle={\\itshape},
frame=tb,
showspaces=false,
showtabs=false,
showstringspaces=false,
}
"
"[EXTRA]\n")
("\\section{%s}" . "\\section*{%s}")
("\\subsection{%s}" . "\\subsection*{%s}")
("\\subsubsection{%s}" . "\\subsubsection*{%s}")))
(add-to-list 'org-latex-packages-alist
'("" "listings"))
(add-to-list 'org-latex-packages-alist
'("" "xcolor"))))
(use-package ox-html
:init (setq org-html-postamble nil))
(use-package ox-pandoc
:init (setq org-pandoc-options-for-docx '((standalone . t))))
(use-package org-tree-slide
:commands (org-tree-slide-mode)
;; Configuration from https://protesilaos.com/dotemacs/
:init (setq org-tree-slide-breadcrumbs ""
org-tree-slide-header t
org-tree-slide-slide-in-effect nil
org-tree-slide-heading-emphasis nil
org-tree-slide-cursor-init t
org-tree-slide-modeline-display nil
org-tree-slide-skip-done nil
org-tree-slide-skip-comments t
org-tree-slide-fold-subtrees-skipped t
org-tree-slide-skip-outline-level 8
org-tree-slide-never-touch-face t
org-tree-slide-activate-message (propertize "Presentation mode ON" 'face 'success)
org-tree-slide-deactivate-message (propertize "Presentation mode OFF" 'face 'error))
:bind (:map org-tree-slide-mode-map
("<C-down>" . org-tree-slide-display-header-toggle)
("<C-right>" . org-tree-slide-move-next-tree)
("<C-left>" . org-tree-slide-move-previous-tree)))
(use-package org-roam
:commands (org-roam-find-file)
:custom ((org-roam-directory "~/Documents/zettelkasten/")
(org-roam-db-location "~/Documents/zettelkasten/org-roam.db")
(org-roam-completion-everywhere t))
:bind (:map org-roam-mode-map
(("C-c n l" . org-roam)
("C-c n f" . org-roam-find-file)
("C-c n g" . org-roam-graph)))
:config (progn
;; There seems to be a problem when capturing notes with the capture
;; template. More precisely, `org-roam-current-title' does not get
;; set correctly (is it my setup or a general bug?) This causes
;; `org-roam--update-file-name-on-title-change' to get a nil
;; argument, on which it barfs. Let's intercept this case and don't
;; do anything. This effectively disables the auto-rename
;; functionality when using org-capture to add notes.
(defun db/org-roam--no-titlechange-if-title-is-nil (orig-fun &rest args)
(unless (cl-some #'null args)
(apply orig-fun args)))
(advice-add 'org-roam--update-file-name-on-title-change
:around #'db/org-roam--no-titlechange-if-title-is-nil)
;; `org-roam--id-link-face' apparently changes the matching data,
;; resulting in `org-finalize-agenda' to fail while applying text
;; properties to ID links; let's warp `save-match-data' around calls
;; to it.
(defun db/save-match-data (orig-fun &rest args)
(save-match-data
(apply orig-fun args)))
(advice-add 'org-roam--id-link-face
:around #'db/save-match-data)))
(use-package org-ref
:config (progn
(require 'org-ref-pdf)
(require 'org-ref-url-utils)))
;; * General Programming
(use-package ediff
:init (setq ediff-diff-options "-w"
ediff-window-setup-function 'ediff-setup-windows-plain
ediff-split-window-function 'split-window-horizontally
ediff-show-clashes-only t)
:config (progn
(add-hook 'ediff-keymap-setup-hook
'(lambda ()
(bind-key "j" #'ediff-next-difference ediff-mode-map)
(bind-key "k" #'ediff-previous-difference ediff-mode-map)))
(add-hook 'ediff-after-quit-hook-internal 'winner-undo)))
(use-package git-commit
:commands (global-git-commit-mode)
:ensure t
:init (setq git-commit-style-convention-checks '(non-empty-second-line
overlong-summary-line)
git-commit-known-pseudo-headers '("Signed-off-by"
"Acked-by"
"Modified-by"
"Cc"
"Suggested-by"
"Reported-by"
"Tested-by"
"Reviewed-by")))
(use-package magit
:ensure t
:commands (magit-status)
:init (setq magit-diff-refine-hunk nil
magit-commit-show-diff nil)
:config (progn
(when (fboundp 'global-magit-file-mode)
(global-magit-file-mode -1))
(global-git-commit-mode +1)
(db/sync-magit-repos-from-projectile)))
(use-package magit-repos
:commands (magit-list-repositories))
(use-package projectile
:ensure t
:commands (projectile-mode)
:defines (projectile-known-projects)
:bind (:map projectile-mode-map ("C-c p" . projectile-command-map))
:init (setq projectile-switch-project-action 'projectile-dired
projectile-completion-system 'helm
projectile-ignored-project-function #'file-remote-p
projectile-create-missing-test-files t
projectile-known-projects-file (expand-file-name "private/projectile-bookmarks.eld"
emacs-d))
:diminish projectile-mode)
(use-package counsel-projectile
:commands counsel-projectile)
(use-package highlight-indentation
:commands highlight-indentation-mode)
(use-package iedit
:ensure t
:commands (iedit-mode))
(use-package page-break-lines
:pin "melpa-stable"
:commands (page-break-lines-mode)
:diminish page-break-lines-mode)
(use-package semantic
:commands (semantic-mode)
:init (setq semantic-default-submodes
'(global-semantic-idle-scheduler-mode
global-semanticdb-minor-mode))
:config (progn
(require 'semantic/ia)
(require 'semantic/bovine/el)
;; recognize `use-package' as include statement; the function seems
;; to have to be a byte-compiled function, for otherwise it just
;; wont work … ?
(eval `(semantic-elisp-setup-form-parser
,(lambda (form start end)
(ignore start end)
(semantic-tag-new-include (symbol-name (nth 1 form))
nil))
use-package))))
(use-package flycheck
:ensure t
:commands (global-flycheck-mode flycheck-mode)
:init (setq flycheck-emacs-lisp-load-path 'inherit))
(use-package lsp-mode
:ensure t
:init (setq lsp-keymap-prefix "C-c C-l")
:commands (lsp lsp-deferred))
(use-package lsp-ui
:ensure t
:commands (lsp-ui-mode))
;; * Mail
(use-package db-mail
:commands (db/smtpmail-send-it
db/public-key
db/encryption-possible-p
db/message-recipients
db/signencrypt-message-when-possible
db/gnus-save-newsrc-with-whitespace-1
db/gnus-summary-open-Link
db/gnus-html-mime-part-to-org
db/gnus-demon-scan-news-on-level-2))
(use-package bbdb
:ensure t
:commands (bbdb-search-name
bbdb-initialize
bbdb-mua-auto-update-init
bbdb-save)
:init (setq bbdb-completion-display-record nil
bbdb-complete-mail-allow-cycling t
bbdb-mua-auto-update-p 'query
bbdb-default-country "Germany")
:config (progn
(add-hook 'message-setup-hook 'bbdb-mail-aliases)
(add-hook 'mail-setup-hook 'bbdb-mail-aliases)
(run-with-timer 0 3600 #'bbdb-save)))
;; General Gnus configuration
(setq gnus-init-file (expand-file-name "gnus.el" emacs-d)
gnus-home-directory (expand-file-name "private/news/" emacs-d)
gnus-directory (expand-file-name "private/news/" emacs-d)
gnus-kill-files-directory gnus-directory
gnus-startup-file (expand-file-name "private/gnus-newsrc" emacs-d)
gnus-cache-directory (expand-file-name "cache/" gnus-directory)
gnus-verbose 10
message-directory (expand-file-name "mail/" gnus-directory)
nnmail-message-id-cache-file (expand-file-name ".nnmail-cache" gnus-directory)
nnml-directory message-directory
mail-sources '((file))
mail-source-delete-incoming t
nntp-nov-is-evil t
nntp-connection-timeout nil
gnus-asynchronous t
gnus-save-killed-list nil
gnus-save-newsrc-file nil
gnus-read-newsrc-file nil
gnus-check-new-newsgroups nil
gnus-use-cache 'passive
gnus-read-active-file 'some
gnus-build-sparse-threads 'some
gnus-subscribe-newsgroup-method 'gnus-subscribe-killed
gnus-group-list-inactive-groups t
gnus-suppress-duplicates nil
gnus-large-newsgroup 200
nnmail-expiry-wait 7
nnmail-cache-accepted-message-ids t
gnus-summary-next-group-on-exit nil
gnus-use-full-window nil
gnus-always-force-window-configuration t
gnus-fetch-old-headers nil
gnus-select-method '(nnnil "")
gnus-refer-article-method 'current
gnus-visible-headers (regexp-opt '("From:"
"Newsgroups:"
"Subject:"
"Date:"
"Followup-To:"
"Reply-To:"
"Organization:"
"Summary:"
"Keywords:"
"Mail-Copies-To:"
"To:"
"Cc:"
"BCC:"
"X-Newsreader:"
"X-Mailer:"
"X-Sent:"
"Posted-To:"
"Mail-Copies-To:"
"Apparently-To:"
"Gnus-Warning:"
"Resent-From:"
"gpg-key-ID:"
"fingerprint:"
"X-Jabber-ID:"
"User-Agent:"))
message-citation-line-function
(lambda ()
(when message-reply-headers
(insert "ghItlhpu' "
(mail-header-from message-reply-headers)
":")
(newline))))
;; Gnus Appearence
(setq gnus-group-line-format "%S%p%P%5y(%2i):%B%(%s:%G%)\n"
gnus-auto-select-first nil
gnus-auto-select-next nil
gnus-summary-line-format "%U%O%R%6k %(%&user-date; %-13,13f %B%s%)\n"
gnus-thread-sort-functions '(gnus-thread-sort-by-most-recent-date)
gnus-subthread-sort-functions '(gnus-thread-sort-by-date)
gnus-thread-hide-subtree t
gnus-user-date-format-alist '((t . "%Y-%m-%d %H:%M"))
gnus-sum-thread-tree-indent " "
gnus-sum-thread-tree-root ""
gnus-sum-thread-tree-false-root ""
gnus-sum-thread-tree-single-indent ""
gnus-sum-thread-tree-single-leaf "╰► "
gnus-sum-thread-tree-leaf-with-other "├► "
gnus-sum-thread-tree-vertical ""
gnus-summary-thread-gathering-function 'gnus-gather-threads-by-references
;; New mark symbols (seen here:
;; `https://github.com/cofi/dotfiles/blob/master/gnus.el')
gnus-ancient-mark ?✓
;; gnus-cached-mark ?☍
gnus-canceled-mark ?↗
gnus-del-mark ?✗
;; gnus-dormant-mark ?⚐
gnus-expirable-mark ?♻
gnus-forwarded-mark ?↪
;; gnus-killed-mark ?☠
;; gnus-process-mark ?⚙
gnus-read-mark ?✓
gnus-recent-mark ?✩
gnus-replied-mark ?↺
gnus-unread-mark ?✉
;; gnus-unseen-mark ?★
;; gnus-ticked-mark ?⚑
gnus-treat-hide-boring-headers 'head
gnus-treat-strip-multiple-blank-lines nil
gnus-treat-display-smileys t
gnus-treat-emphasize 'head
gnus-treat-unsplit-urls t)
(use-package gnus-art
:init (setq gnus-ignored-mime-types '("text/x-vcard")
gnus-inhibit-mime-unbuttonizing nil
gnus-buttonized-mime-types '("multipart/signed" "multipart/encrypted")
gnus-inhibit-images t
gnus-blocked-images ".*"))
;; Adaptive Scoring
(setq gnus-use-scoring t
gnus-use-adaptive-scoring '(word line)
gnus-summary-mark-below nil
gnus-adaptive-word-length-limit 5
gnus-adaptive-word-no-group-words t
gnus-default-adaptive-score-alist
'((gnus-unread-mark)
(gnus-ticked-mark (from 4))
(gnus-dormant-mark (from 5))
(gnus-del-mark (from -4) (subject -1))
(gnus-read-mark (from 4) (subject 2))
(gnus-expirable-mark (from -1) (subject -1))
(gnus-killed-mark (from -1) (subject -3))
(gnus-kill-file-mark)
(gnus-ancient-mark)
(gnus-low-score-mark)
(gnus-catchup-mark (from -1) (subject -1)))
gnus-summary-mark-below nil)
;; Gnus Registry
(use-package gnus-registry
:commands (gnus-registry-split-fancy-with-parent
gnus-registry-initialize)
:init (setq gnus-registry-split-strategy 'majority
gnus-registry-ignored-groups '(("^nntp" t)
("^nnfolder" t)
("^nnir" t)
("^nnmaildir" t)
("INBOX$" t))
gnus-registry-max-entries 40000
gnus-registry-track-extra '(sender subject recipient)
gnus-registry-cache-file (expand-file-name "gnus.registry.eioioi"
emacs-d)))
;; MIME decoding
(use-package mm-decode
:init (setq mm-text-html-renderer 'shr
mm-discouraged-alternatives '("text/richtext")
mm-decrypt-option 'known
mm-verify-option 'known)
:config (progn
(setq mm-automatic-display (-difference mm-automatic-display
'("text/enriched"
"text/richtext")))
;; Automatically show PGP data inline
(add-to-list 'mm-inlined-types "application/pgp$")
(add-to-list 'mm-inline-media-tests
'("application/pgp$" mm-inline-text identity))
(add-to-list 'mm-automatic-display "application/pgp$")
;; When copying MIME buffers, we are looking for the start of the
;; header by searching ^\n; however, if we received mail from
;; Outlook, there's an ^\r\n seperating header and body, which is
;; not found by `mm-copy-to-buffer', leaving the target buffer empty
;; and the mail as well. Redefining `mm-copy-to-buffer' to also
;; search for ^\r\n might help.
(defun mm-copy-to-buffer ()
"Copy the contents of the current buffer to a fresh buffer."
(let ((obuf (current-buffer))
(mb enable-multibyte-characters)
beg)
(goto-char (point-min))
;; The following regex has been extended by \r? .
(search-forward-regexp "^\r?\n" nil 'move) ;; There might be no body.
(setq beg (point))
(with-current-buffer
(generate-new-buffer " *mm*")
;; Preserve the data's unibyteness (for url-insert-file-contents).
(set-buffer-multibyte mb)
(insert-buffer-substring obuf beg)
(current-buffer))))))
(setq message-forward-as-mime nil)
;; MIME creation; signing, and encryption
(use-package mml
:config (progn
;; Move to end of message buffer before attaching a file
;; http://mbork.pl/2015-11-28_Fixing_mml-attach-file_using_advice
(defun db/mml-attach-file--go-to-eob (orig-fun &rest args)
"Go to the end of buffer before attaching files."
(save-excursion
(save-restriction
(widen)
(goto-char (point-max))
(apply orig-fun args))))
(advice-add 'mml-attach-file
:around #'db/mml-attach-file--go-to-eob)))
(use-package mm-encode
:init (setq mm-encrypt-option nil
mm-sign-option nil))
(setq mml-secure-openpgp-encrypt-to-self t
mml-secure-smime-encrypt-to-self t
mml2015-display-key-image nil
gnus-message-replysign t
gnus-message-replyencrypt t
gnus-message-replysignencrypted t
mml-secure-cache-passphrase nil
mml-secure-openpgp-sign-with-sender t
mml-secure-smime-sign-with-sender t)
(use-package mml-smime
:init (setq mml-smime-use 'epg)
:config (progn
;; Outlook seems to expect \r\n in PKCS#7 encrypted containers, but
;; Gnus is only sending \n; so let's artificially replace \n by \r\n
;; after, well, signing? But only if we are encrypting with S/MIME,
;; as otherwise the search for \n\n in `message-encode-message-body'
;; will break. However, I think this is not the right way to do it
;; … isn't there some way to specify the encoding of the the
;; relevant MML buffers to be some nasty cp1252 or something?
;; A previous version of this worked, but the following has not been
;; tested with Outlook proper.
(defun db/smime-add-crlf-when-pkcs7 (cont)
"If CONT signifies encryption with smime, replace all \n with \r\n."
(when (and (eq (car cont) 'part)
(string= "smime" (or (cdr (assq 'encrypt cont)) "")))
(db/convert-lf-to-crlf-in-buffer)))
(advice-add 'mml-smime-epg-sign
:after #'db/smime-add-crlf-when-pkcs7)))
;; Archiving
;; We store messages in the current group, so there is
;; no need to use Gnus archiving method
(setq gnus-message-archive-method nil
gnus-update-message-archive-method t
gnus-message-archive-group nil
gnus-gcc-mark-as-read t)
;; Searching
(setq nnir-method-default-engines '((nnimap . imap)
(nnmaildir . notmuch)
(nntp . gmane)))
;; Agents
(use-package gnus-agent
:init (setq gnus-agent-mark-unread-after-downloaded nil
gnus-agent-synchronize-flags t
gnus-agent-go-online t))
;; Package configuration
(use-package gnus
:commands (gnus)
:config (progn
(require 'db-mail)
(with-demoted-errors "Setting up BBDB failed: %s"
(bbdb-initialize 'gnus 'message)
(bbdb-mua-auto-update-init 'message))
;; Ensure that whenever we compose new mail, it will use the correct
;; posting style. This is ensured by setting ARG of
;; `gnus-group-mail to 1 to let it query the user for a group.
(defadvice gnus-group-mail (before inhibit-no-argument activate)
(unless (ad-get-arg 0)
(ad-set-arg 0 1)))
(remove-hook 'gnus-mark-article-hook
'gnus-summary-mark-read-and-unread-as-read)
(add-hook 'gnus-mark-article-hook 'gnus-summary-mark-unread-as-read)
;; Quit Gnus gracefully when exiting Emacs
(add-hook 'kill-emacs-hook #'(lambda ()
(interactive)
(when (get-buffer "*Group*")
(gnus-group-exit))))
;; Dont quit summary buffer when pressing `q
(bind-key "q" #'gnus-summary-expand-window gnus-article-mode-map)
;; Show topics in group buffer
(add-hook 'gnus-group-mode-hook 'gnus-topic-mode)
;; We need to do some magic as otherwise the agent does not delete
;; articles from its .overview when we move them around. Thus we
;; mark articles as expireable when they have been moved to another
;; group.
(defadvice gnus-summary-move-article (around
no-cancel-mark
(&optional n to-newsgroup
select-method action)
activate)
(let ((articles (gnus-summary-work-articles n))
(return ad-do-it))
(when (or (null action)
(eq action 'move))
(dolist (article articles)
(gnus-summary-mark-article article gnus-expirable-mark)))
return))
;; Increase score of group after reading it
(add-hook 'gnus-summary-exit-hook
'gnus-summary-bubble-group)
;; Use Gnus registry; doing this too early conflicts with `gnus'
;; calling `gnus-shutdown', which in turn calls
;; `gnus-registry-clear', leaving us with an empty registry upon
;; startup. So let's call this initialization right after startup,
;; that should be fine.
(add-hook 'gnus-started-hook
#'gnus-registry-initialize)
;; Automatic encryption if all necessary keys are present
(add-hook 'gnus-message-setup-hook
#'db/signencrypt-message-when-possible)
;; Do some pretty printing before saving the newsrc file
(add-hook 'gnus-save-quick-newsrc-hook
#'db/gnus-save-newsrc-with-whitespace-1)
;; Automatically scan for new news
(gnus-demon-add-handler 'db/gnus-demon-scan-news-on-level-2 5 5)
(add-hook 'gnus-started-hook #'gnus-demon-init)
;; Visit group under point and immediately close it; this updates
;; gnus registry as a side-effect
(bind-key "v u"
'(lambda ()
(interactive)
(save-mark-and-excursion
(when (gnus-topic-select-group)
(gnus-summary-exit))))
gnus-group-mode-map)
;; Toggle visibility of News group
(bind-key "v c"
(lambda ()
(interactive)
(save-mark-and-excursion
(gnus-topic-jump-to-topic "News")
(gnus-topic-read-group)))
gnus-group-mode-map)
(bind-key "C-<return>" #'db/gnus-summary-open-Link gnus-summary-mode-map)
(bind-key "C-<return>" #'db/gnus-summary-open-Link gnus-article-mode-map)))
;; Sending mail
(setq message-send-mail-function #'db/smtpmail-send-it
send-mail-function #'db/smtpmail-send-it
mail-user-agent 'gnus-user-agent)
(use-package smtpmail
:init (setq smtpmail-stream-type 'starttls
smtpmail-smtp-service 587
smtpmail-debug-info t))
;; * Crypto
(use-package nsm
:init (setq network-security-level 'high
nsm-save-host-names t
nsm-settings-file (expand-file-name
"~/.emacs.d/private/network-security.data"))
:config (advice-add 'nsm-write-settings
:before #'db/sort-nsm-permanent-settings))
(use-package gnutls
:init (setq gnutls-log-level 0 ; too noisy otherwise
gnutls-min-prime-bits 1024
gnutls-verify-error t))
(use-package epg
:init (setq epg-debug t
epg-gpg-program "gpg"))
;; * Appearance
(setq-default cursor-type 'bar
cursor-in-non-selected-windows nil
font-lock-maximum-decoration '((t . t)))
(setq mode-line-format '((ace-window-display-mode
(:eval
(window-parameter
(selected-window)
'ace-window-path)))
"%e"
mode-line-front-space
mode-line-position
mode-line-mule-info
mode-line-client
mode-line-modified
mode-line-remote
mode-line-buffer-identification
mode-line-modes
(vc-mode vc-mode)
mode-line-misc-info
mode-line-end-spaces))
(use-package solarized-theme
:ensure t
:init (setq solarized-use-less-bold t
solarized-emphasize-indicators t
solarized-use-variable-pitch nil))
(use-package smart-mode-line
:ensure t
:init (setq sml/mode-width 'full
sml/name-width 30)
:commands (sml/setup))
(use-package minions
:ensure t
:commands (minions-mode)
:init (setq minions-mode-line-lighter ""))
(use-package moody
:ensure t
:commands (moody-replace-mode-line-buffer-identification
moody-replace-vc-mode))
;; * Dired
(use-package dired
:bind (:map dired-mode-map
("e" . ora-ediff-files)
("z" . dired-get-size)
([remap beginning-of-buffer] . dired-back-to-top)
([remap end-of-buffer] . dired-jump-to-bottom)
("<f1>" . nil)
("<tab>" . dired-subtree-toggle)
("<C-tab>" . dired-subtree-cycle))
:init (progn
(setq dired-dwim-target t
dired-listing-switches (if on-windows "-aGFhlv" "-aGFhlv --group-directories-first --time-style=long-iso")
dired-hide-details-hide-information-lines t
dired-hide-details-hide-symlink-targets t
dired-recursive-copies 'top
dired-recursive-deletes 'top
dired-create-destination-dirs 'ask
dired-vc-rename-file t
;; Dont use obsolete diredx local variables
dired-enable-local-variables nil
dired-local-variables-file nil
dired-omit-files "^\\.?#\\|^\\.$\\|^\\.\\.$\\|^\\..*$"
diredp-hide-details-initially-flag t
wdired-create-parent-directories t
wdired-allow-to-change-permissions t
dired-isearch-filenames 'dwim
dired-auto-revert-buffer t)
(setq dired-guess-shell-alist-user
'(("\\.pdf\\'" "evince")
("\\.ps\\'" "evince")
("\\.\\(?:djvu\\|eps\\)\\'" "evince")
("\\.\\(?:jpg\\|jpeg\\|png\\|gif\\|xpm\\)\\'" "eog")
("\\.\\(?:xcf\\)\\'" "gimp")
("\\.\\(?:mp4\\|mkv\\|avi\\|flv\\|ogv\\|webm\\)\\(?:\\.part\\)?\\'"
"vlc")
("\\.\\(?:mp3\\|flac\\|ogg\\)\\'" "mplayer")
("\\.docx?\\'" "loffice")))
(when on-windows
(setq directory-free-space-program nil)))
:config (progn
(put 'dired-find-alternate-file 'disabled nil)
(require 'dired-x)
(with-demoted-errors "Non-Fatal Errors (dired-open): %s"
(require 'dired-open))
(if (eq system-type 'windows-nt)
(with-demoted-errors "Non-Fatal Error (w32-browser): %s"
(require 'w32-browser)
(bind-key "M-RET" #'dired-w32-browser dired-mode-map)
(bind-key "<C-return>" #'dired-w32explore dired-mode-map))
(bind-key "M-RET" #'dired-open-xdg dired-mode-map))
(with-demoted-errors "Non-Fatal Errors (dired-recent): %s"
(dired-recent-mode +1))
;; Gnus support in dired
(add-hook 'dired-mode-hook 'turn-on-gnus-dired-mode)
;; Highlight current line more prominently
(add-hook 'dired-mode-hook 'hl-line-mode)
;; omitting files
(add-hook 'dired-mode-hook 'dired-omit-mode)
(add-hook 'dired-mode-hook 'dired-hide-details-mode)
(dolist (extension '(".out" ".synctex.gz" ".thm"))
(add-to-list 'dired-latex-unclean-extensions extension))
(defun ora-ediff-files ()
"Compare marked files in dired with ediff."
;; from: https://oremacs.com/2017/03/18/dired-ediff/
(interactive)
(lexical-let ((files (dired-get-marked-files))
(wnd (current-window-configuration)))
(if (<= (length files) 2)
(lexical-let ((file1 (car files))
(file2 (if (cdr files)
(cadr files)
(read-file-name
"file: "
(dired-dwim-target-directory)))))
(if (file-newer-than-file-p file1 file2)
(ediff-files file2 file1)
(ediff-files file1 file2))
(add-hook 'ediff-after-quit-hook-internal
(lambda ()
(setq ediff-after-quit-hook-internal nil)
(set-window-configuration wnd))))
(error "No more than 2 files should be marked"))))
(defun dired-back-to-top ()
"Jump to first non-trivial line in dired."
(interactive)
(goto-char (point-min))
(dired-next-line 1))
(defun dired-jump-to-bottom ()
"Jump to last non-trivial line in dired."
(interactive)
(goto-char (point-max))
(dired-next-line -1))
(defun dired-get-size () ; from emacswiki, via oremacs
"Print size of all files marked in the current dired buffer."
(interactive)
(let ((files (dired-get-marked-files)))
(with-temp-buffer
(apply 'call-process "/usr/bin/du" nil t nil "-sch" files)
(message
"size of all marked files: %s"
(progn
(re-search-backward "\\(^[0-9.,]+[a-za-z]+\\).*total$")
(match-string 1))))))))
(use-package dired-x
:commands (dired-jump dired-jump-other-window)
:init (setq dired-clean-confirm-killing-deleted-buffers t
dired-x-hands-off-my-keys t
dired-bind-man nil
dired-bind-info nil
dired-clean-up-buffers-too t))
(use-package dired-subtree
:commands (dired-subtree-toggle))
(use-package find-dired
:commands (find-dired)
:init (setq find-ls-option '("-print0 | xargs -0 ls -ld" . "-ld")))
(use-package dired-open
:ensure t
:init (progn
(unless (eq system-type 'gnu/linux)
(setq dired-open-use-nohup nil))
(setq dired-open-extensions-elisp '(("html" . eww-open-file))))
:config (progn
(add-to-list 'dired-open-functions
#'dired-open-guess-shell-alist)
(add-to-list 'dired-open-functions
#'dired-open-call-function-by-extension)))
(use-package dired-recent
:ensure t
:init (setq dired-recent-max-directories nil)
:commands (dired-recent-mode
dired-recent-open))
(use-package gnus-dired
:commands (turn-on-gnus-dired-mode))
(use-package trashed
;; A simple dired-like interface to the system trash bin
;; Configuration taken from https://protesilaos.com/dotemacs
:init (setq trashed-action-confirmer 'y-or-n-p
trashed-use-header-line t
trashed-sort-key '("Date deleted" . t)
trashed-date-format "%Y-%m-%d %H:%M:%S"))
;; * Completion
(use-package hippie-exp
:commands (hippie-expand))
(use-package helm
:ensure t
:diminish helm-mode
:init (setq helm-command-prefix-key "C-c h"
helm-input-idle-delay 0.0
helm-buffers-fuzzy-matching t
helm-mode-fuzzy-match t
helm-autoresize-min-height 20
helm-ff-auto-update-initial-value t
helm-ff-file-name-history-use-recentf t
helm-ff-search-library-in-sexp t
helm-ff-skip-boring-files nil
helm-split-window-inside-p t
helm-move-to-line-cycle-in-source nil
helm-scroll-amount nil
helm-locate-command nil
helm-candidate-number-limit 100
helm-follow-mode-persistent t
helm-buffer-details-flag t
helm-buffer-skip-remote-checking t
helm-mode-no-completion-in-region-in-modes '(eshell-mode))
:config (progn
(require 'helm-config)
(require 'helm-mode)
(require 'helm-buffers)
(require 'helm-ring)
(if (require 'helm-global-bindings nil :no-error)
(progn
(bind-key "#" #'helm-emms helm-command-map)
(bind-key "P" #'helm-pages helm-command-map))
(warn (concat
"Cannot load `helm-global-bindings', please check your helm installation for completeness. "
"(Have you installed it from melpa?)")))
(bind-key "<tab>" #'helm-execute-persistent-action helm-map)
(bind-key "C-i" #'helm-execute-persistent-action helm-map)
(bind-key "C-z" #'helm-select-action helm-map)))
(use-package helm-ring
:commands (helm-show-kill-ring))
(use-package ivy
:ensure t
:commands (ivy-mode
ivy-resume)
:diminish ivy-mode
:init (setq ivy-use-virtual-buffers t
ivy-magic-tilde nil
ivy-count-format "(%d/%d) "
ivy-initial-inputs-alist '((counsel-describe-function . "^")
(counsel-describe-variable . "^")
(man . "^")
(woman . "^"))
ivy-use-selectable-prompt t
ivy-do-completion-in-region t
ivy-re-builders-alist '((t . ivy--regex-ignore-order)))
:config (progn
;; Since we are using `ivy--regex-ignore-order' for completion
;; anyway, providing the an individual restriction in the ivy buffer
;; is not necessary anymore. Since I often mistype S-SPC for SPC,
;; loosing the current candidate and annoying myself, removing this
;; shortcut is both helpful and not removing necessary
;; functionality.
(define-key ivy-minibuffer-map (kbd "S-SPC") nil)))
(use-package ivy-hydra)
(use-package counsel
:ensure t
:commands (counsel-org-goto-all
counsel-ag
counsel-M-x
counsel-find-file
counsel-info-lookup-symbol
counsel-unicode-char
counsel-descbinds
counsel-describe-variable
counsel-describe-function
counsel-recentf
counsel-shell-history))
(use-package swiper
:ensure t
:commands (swiper
swiper-from-isearch))
(use-package recentf
:commands (recentf-mode recentf-save-list)
:init (setq recentf-max-saved-items 1000)
:config (run-with-timer 0 3600 #'recentf-save-list))
(use-package company
:commands (company-mode global-company-mode)
:init (setq company-show-numbers t))
;; * Navigation
(defun db/helm-shortcuts (arg)
"Open helm completion on common locations.
With given ARG, display files in `db/important-document-path."
(interactive "p")
(require 'helm-bookmark)
(require 'helm-for-files) ; for helm-source-recentf
(helm :sources (list
(helm-make-source "Frequently Used" 'helm-source-sync
:candidates (mapcar #'(lambda (entry)
(cons (car entry)
(caddr entry)))
db/frequently-used-features)
:action '(("Open" . call-interactively))
:filtered-candidate-transformer #'helm-adaptive-sort)
;; taken from `helm-buffers-list'
(helm-make-source "Buffers" 'helm-source-buffers)
helm-source-recentf
;; if prefix arg is given, extract files from
;; `db/important-documents-path and list them as well
(when (and (= arg 4)
(file-directory-p db/important-documents-path))
(let ((search-path (expand-file-name db/important-documents-path)))
(helm-make-source "Important files" 'helm-source-sync
:candidates (mapcar #'(lambda (file)
;; display only relative path,
;; but keep absolute path for
;; actions
(cons (string-remove-prefix search-path file)
file))
(directory-files-recursively search-path ""))
:action '(("Open externally" . db/system-open)
("Find file" . find-file)))))
helm-source-bookmarks
helm-source-buffer-not-found
helm-source-bookmark-set)))
(use-package ace-window
:ensure t
:commands (ace-window ace-window-display-mode)
:init (setq aw-keys '(?a ?s ?d ?f ?g ?h ?j ?k ?l)
aw-background t
aw-leading-char-style 'char
aw-scope 'frame))
(use-package avy
:ensure t
:commands (avy-goto-char-timer
avy-goto-word-or-subword-1
avy-goto-line))
(use-package bm
;; Taken from https://protesilaos.com/dotemacs/ and slightly adapted
:ensure t
:commands (bm-toggle bm-next bm-previous bm-toggle-buffer-persistence)
:init (setq bm-restore-repository-on-load t
bm-annotate-on-create nil
bm-buffer-persistence t
bm-cycle-all-buffers t
bm-goto-position nil
bm-highlight-style 'bm-highlight-line-and-fringe
bm-marker 'bm-marker-right
bm-in-lifo-order nil
bm-recenter t
bm-repository-file "~/.emacs.d/bm-bookmarks"
bm-repository-size 100
bm-show-annotations t
bm-wrap-immediately t
bm-wrap-search t))
(use-package dumb-jump
:commands (dumb-jump-xref-activate)
:init (progn
(setq dumb-jump-selector 'helm)
(add-hook 'xref-backend-functions #'dumb-jump-xref-activate)))
(use-package helm-pages
:ensure t
:commands (helm-pages))
(use-package imenu
:init (setq imenu-use-markers t
imenu-auto-rescan t
imenu-auto-rescan-maxout 600000
imenu-max-item-length 100
imenu-use-popup-menu nil
imenu-eager-completion-buffer t))
(use-package eyebrowse
:ensure t
:commands (eyebrowse-mode)
:init (setq eyebrowse-keymap-prefix (kbd "C-c w")))
(use-package goto-last-change
:commands goto-last-change)
;; * Media
(use-package emms
:pin "melpa-stable"
:commands (emms
emms-pause
emms-stop
emms-next
emms-previous)
:bind (:map emms-playlist-mode-map
("S s" . emms-shuffle))
:init (setq emms-source-file-default-directory "~/Documents/media/audio/"
emms-player-list '(emms-player-mplayer emms-player-mplayer-playlist)
emms-show-format "NP: %s"
emms-stream-default-action "play"
emms-track-description-function 'db/emms-track-description
emms-playlist-default-major-mode 'emms-playlist-mode
emms-cache-file (expand-file-name "private/emms/cache" emacs-d)
emms-history-file (expand-file-name "private/emms/history" emacs-d)
emms-score-file (expand-file-name "private/emms/scores" emacs-d)
emms-stream-bookmarks-file (expand-file-name "private/emms/streams" emacs-d))
:config (progn
;; Initialization copied and adapted from `emms-setup
(require 'emms-source-file)
(require 'emms-source-playlist)
(require 'emms-player-simple)
(require 'emms-player-mplayer)
(require 'emms-playlist-mode)
(require 'emms-info)
(require 'emms-info-mp3info)
(require 'emms-info-ogginfo)
(require 'emms-info-opusinfo)
(require 'emms-cache)
(require 'emms-mode-line)
(require 'emms-mark)
(require 'emms-tag-editor)
(require 'emms-show-all)
(require 'emms-streams)
(require 'emms-playing-time)
(require 'emms-player-mpd)
(require 'emms-playlist-sort)
(require 'emms-browser)
(require 'emms-mode-line-icon)
(require 'emms-cue)
(require 'emms-bookmarks)
(require 'emms-last-played)
(require 'emms-metaplaylist-mode)
(require 'emms-stream-info)
(require 'emms-score)
(require 'emms-history)
(require 'emms-i18n)
(require 'emms-volume)
(require 'emms-playlist-limit)
(add-to-list 'emms-track-initialize-functions
'emms-info-initialize-track)
(if (require 'emms-info-mediainfo nil 'no-error)
(setq emms-info-functions '(emms-info-mediainfo))
(when (executable-find emms-info-mp3info-program-name)
(add-to-list 'emms-info-functions 'emms-info-mp3info))
(when (executable-find emms-info-ogginfo-program-name)
(add-to-list 'emms-info-functions 'emms-info-ogginfo))
(when (executable-find emms-info-opusinfo-program-name)
(add-to-list 'emms-info-functions 'emms-info-opusinfo))
(add-to-list 'emms-info-functions 'emms-info-cueinfo))
(when (fboundp 'emms-cache) ; work around compiler warning
(emms-cache 1))
(emms-mode-line -1)
(emms-playing-time 1)
(emms-score 1)
(add-hook 'emms-player-started-hook 'emms-last-played-update-current)
(add-hook 'emms-player-started-hook 'emms-show)
(advice-add 'emms-tag-editor-submit
:after (lambda (&rest r)
(ignore r)
(delete-window)))
(unless (eq system-type 'windows-nt)
(setq emms-source-file-directory-tree-function
#'db/emms-source-file-directory-tree-find))
;; `emms-playlist-mode sets `emms-playlist-insert-track-function,
;; no matter what previous values or customization may say otherwise
;; … so we need to employ a hook to change its value
(add-hook 'emms-playlist-mode-hook
(lambda ()
(setq emms-playlist-insert-track-function
#'db/emms-playlist-mode-insert-track)))
(run-with-timer 0 3600 #'emms-cache-save)))
;; Make sure emms is up and running when we call functions such as
;; `emms-play-dired etc.
(use-package emms-source-file
:config (require 'emms))
(use-package db-emms
:commands (db/emms-source-file-directory-tree-find
db/emms-track-description
db/emms-playlist-mode-insert-track))
(use-package helm-emms
:commands (helm-emms)
:init (setq helm-emms-use-track-description-function t
helm-emms-default-sources '(helm-source-emms-streams
helm-source-emms-dired
helm-source-emms-files))
:config (progn
(require 'emms)
(require 'helm-adaptive)))
(use-package db-music
:init (setq db/auto-playlist-file-function
#'(lambda ()
(db/playlist-files-from-git-annex-find
"--metadata db-playlist=include")))
:commands (db/play-auto-playlist
db/playlist-files-from-git-annex-find
db/play-auto-playlist-from-git-annex-find
music-control/body
db/play-radio-stations
db/update-playlist-files))
;; * Shells and such
(use-package comint
:init (setq comint-scroll-to-bottom-on-input t
comint-scroll-to-bottom-on-output nil
comint-scroll-show-maximum-output t
comint-completion-addsuffix t
comint-buffer-maximum-size 100000
comint-input-ring-size 5000)
:config (progn
;; Never let bash know that we are inside Emacs;
;; cf. https://coredumped.dev/2020/01/04/native-shell-completion-in-emacs/
(advice-add 'comint-term-environment
:filter-return #'(lambda (env) (cons "INSIDE_EMACS" env)))))
(use-package term
:commands (term-send-string)
:init (setq explicit-shell-file-name "/bin/bash")
:config (progn
(add-hook 'term-exec-hook ; oremacs.com
(lambda ()
(let* ((buff (current-buffer))
(proc (get-buffer-process buff)))
(set-process-sentinel
proc
`(lambda (process event)
(if (string= event "finished\n")
(kill-buffer ,buff)))))))