--- /dev/null
+#+TITLE: Emacs literate config
+#+PROPERTY: header-args emacs-lisp :tangle config.el
+
+* Header
+#+BEGIN_SRC emacs-lisp
+;;; config.el --- Emacs Configuration -*- lexical-binding: t; -*-
+
+;; This file is not part of GNU emacs
+
+;;; Code:
+
+#+END_SRC
+* Initial
+#+BEGIN_SRC emacs-lisp
+ (dolist (path '("sedit-mouse/" "themes/" "re/"))
+ (add-to-list 'load-path (concat user-emacs-directory path)))
+
+ (dolist (file '(re-packages re-pass-alike eng-paper-theme sedit-mouse))
+ (require file))
+
+ (setq w32-recognize-altgr 'nil)
+
+ (unless (equal system-type 'windows-nt)
+ (require 're-mu4e)
+ (setq trash-directory "~/Trash/")
+ (defun doas ()
+ "Use TRAMP to reopen the current buffer as root using doas."
+ (interactive)
+ (when buffer-file-name
+ (find-alternate-file (concat "/doas:root@localhost:" buffer-file-name))))
+ (defun sudo ()
+ "Use TRAMP to reopen the current buffer as root using sudo."
+ (interactive)
+ (when buffer-file-name
+ (find-alternate-file (concat "/sudo:root@localhost:" buffer-file-name)))))
+
+#+END_SRC
+* Editing
+#+BEGIN_SRC emacs-lisp
+;; Editing
+(defun re/open-line-below (n)
+ "Creates a new empty line below the current line and moves to it."
+ (interactive "*p")
+ (end-of-line)
+ (open-line n)
+ (next-line 1)
+ (indent-for-tab-command))
+
+(keymap-global-set "C-o" #'re/open-line-below)
+
+(defun re/open-line-above (n)
+ "Creates a new empty line above the current line."
+ (interactive "*p")
+ (beginning-of-line)
+ (open-line n)
+ (indent-for-tab-command))
+
+(keymap-global-set "M-o" #'re/open-line-above)
+
+(defun re/flush-extra-lines ()
+ "Change all groups of blank lines to 1 blank line."
+ (interactive)
+ (save-excursion (mark-whole-buffer)
+ (replace-regexp "^\n+"
+ "\n"
+ nil
+ (region-beginning)
+ (region-end))))
+
+(defun re/comment-dwim (&optional arg)
+ "Comment region if active, otherwise comment line.
+Stolen from https://depp.brause.cc/dotemacs"
+ (interactive "P")
+ (if (use-region-p)
+ (comment-or-uncomment-region (region-beginning) (region-end))
+ (comment-line arg)))
+
+(keymap-global-set "M-;" #'re/comment-dwim)
+
+(defun re/comment-defun (&optional arg)
+ "Mark a defun and comment it out.
+Return to initial position after. Arg works on `mark-defun'."
+ (interactive "P")
+ (save-excursion (mark-defun arg)
+ (comment-region (region-beginning) (region-end))))
+
+(keymap-global-set "C-M-;" #'re/comment-defun)
+
+(defun re/kill-defun (&optional arg)
+ "Mark a defun and kill it.
+Arg works on `mark-defun'."
+ (interactive "P")
+ (mark-defun arg)
+ (kill-region (region-beginning) (region-end)))
+
+(keymap-global-set "C-M-S-K" #'re/kill-defun)
+
+(defun re/kill-bword-or-region (&optional arg)
+"Kill region if active, otherwise kill back one word."
+(interactive "p")
+(if (use-region-p)
+ (kill-region (region-beginning) (region-end))
+ (backward-kill-word arg)))
+
+(keymap-global-set "C-w" #'re/kill-bword-or-region)
+
+(keymap-global-set "<insert>" nil) ; I keep toggliŋ overwrite-mode haply
+(keymap-global-set "C-\\" #'undo-redo) ; issues with C-? sometimes
+(keymap-global-set "C-S-K" #'kill-whole-line)
+(keymap-global-set "C-u" (lambda () (interactive) (kill-line 0))) ; kill-line backwards
+(keymap-global-set "C-S-U" #'universal-argument) ; C-u used above
+(keymap-set key-translation-map "C-h" "<DEL>") ; Rather F1 for help, also C-S-H works
+(keymap-global-set "C-S-d" #'delete-pair)
+(keymap-global-set "M-j" (lambda () (interactive) (join-line 0))) ; join-line other way
+(keymap-global-set "C-z" #'zap-up-to-char)
+(keymap-global-set "C-c s" #'sort-lines)
+(keymap-global-set "<remap> <capitalize-word>" #'capitalize-dwim) ; M-c
+(keymap-global-set "<remap> <downcase-word>" #'downcase-dwim) ; M-l
+(keymap-global-set "<remap> <upcase-word>" #'upcase-dwim) ; M-u
+#+END_SRC
+* Tabs
+#+BEGIN_SRC emacs-lisp
+;; Tabs
+(setq-default indent-tabs-mode t
+ tab-width 8
+ backward-delete-char-untabify-method nil)
+
+(advice-add 'indent-to :around
+ (lambda (orig-fun column &rest args)
+ (when indent-tabs-mode
+ (setq column (* tab-width (round column tab-width))))
+ (apply orig-fun column args)))
+
+(dolist (indent-level '(c-basic-offset cperl-indent-level LaTeX-indent-level))
+ (defvaralias indent-level 'tab-width))
+
+(defun Tab (width)
+ "Give me a function analagous to the Acme `Tab' command"
+ (interactive)
+ (setq-local tab-width width))
+
+(keymap-global-set "<tab>" (lambda () (interactive) (insert "\t")))
+#+END_SRC
+* Buffer dealiŋ
+#+BEGIN_SRC emacs-lisp
+;; Buffer dealiŋ
+(setq-default indicate-empty-lines t
+ truncate-lines t
+ fill-column 78)
+
+(dolist (hook '(text-mode-hook LaTeX-mode-hook))
+ (add-hook hook #'visual-line-mode))
+
+(add-to-list 'display-buffer-alist
+ '("^\\*eldoc" display-buffer-in-direction
+ (direction . 'down)
+ (window-height . 4)))
+
+(blink-cursor-mode -1)
+(delete-selection-mode t)
+
+(setq delete-by-moving-to-trash t
+ delete-pair-blink-delay 0
+ use-short-answers t
+ use-file-dialog nil
+ echo-keystrokes 0.1
+ eldoc-idle-delay 0
+ read-buffer-completion-ignore-case t
+ history-delete-duplicates t
+ disabled-command-function nil
+ save-interprogram-paste-before-kill t
+ confirm-kill-processes nil
+ recenter-positions '(2 middle -3))
+
+(defun re/recenter-advice (&rest _)
+ "Recenter to page start."
+ (when (called-interactively-p 'any) (recenter 2)))
+
+(dolist (binding '(backward-page forward-page))
+ (advice-add binding :after #'re/recenter-advice))
+
+(keymap-global-set "C-x C-n" #'forward-page)
+(keymap-global-set "C-x C-p" #'backward-page)
+(keymap-global-set "<next>" #'forward-page)
+(keymap-global-set "<prior>" #'backward-page)
+
+(defmacro re/open-with-new-frame (frname function)
+ "Run the function in its own named frame."
+ `(progn
+ (select-frame (make-frame '((name . ,(eval frname)))))
+ (call-interactively ,function)))
+
+(keymap-global-set "C-x M-f" #'find-file-at-point)
+(keymap-global-set "C-x C-b" #'buffer-menu)
+(keymap-global-set "C-x M-b" #'buffer-menu-other-window)
+(keymap-global-set "C-x k" #'kill-current-buffer)
+(keymap-global-set "C-x K" #'kill-buffer)
+(keymap-global-set "C-c d" #'eldoc) ; force eldoc to show in minibuffer
+(keymap-global-set "C-c D" #'eldoc-doc-buffer) ; open eldoc buffer when it's getting spammed
+#+END_SRC
+* Motion
+#+BEGIN_SRC emacs-lisp
+;; Motion
+(defun re/scratch-only ()
+ "Bring up the scratch buffer as the only visible buffer."
+ (interactive)
+ (scratch-buffer)
+ (delete-other-windows))
+
+(keymap-global-set "<f5>" #'scratch-buffer)
+(keymap-global-set "S-<f5>" #'re/scratch-only)
+
+(defun re/other-window-or-split-window (&optional window)
+ "Go to other window or split sensibly."
+ (interactive)
+ (if (= (count-windows) 1)
+ (funcall split-window-preferred-function window)
+ (other-window 1)))
+
+(keymap-global-set "C-M-o" #'re/other-window-or-split-window)
+
+(defun re/smart-beginning-of-line ()
+ "Move point to first non-whitespace character or `beginning-of-visual-line'.
+If point was already at that position, call `back-to-indentation'.
+Called a third time, move point back to `beginning-of-line'.
+If in org-mode, call `org-beginning-of-line' first."
+ (interactive "^")
+ (let ((oldpos (point)))
+ (if (equal major-mode 'org-mode)
+ (org-beginning-of-line)
+ (progn
+ (when visual-line-mode (beginning-of-visual-line 1))
+ (skip-syntax-forward " " (line-end-position))
+ (backward-prefix-chars)))
+ (and (= oldpos (point))
+ (let ((newpos (point)))
+ (back-to-indentation)
+ (and (= newpos (point)) (beginning-of-line))))))
+
+(keymap-global-set "<remap> <move-beginning-of-line>" #'re/smart-beginning-of-line)
+(keymap-set visual-line-mode-map "C-a" #'re/smart-beginning-of-line)
+
+(defun re/smart-end-of-line ()
+ "Move point to the end of the visual line.
+ If point was already at that position, call `move-end-of-line'.
+If in org-mode, call `org-end-of-line' first."
+ (interactive "^")
+ (let ((oldpos (point)))
+ (if (equal major-mode 'org-mode)
+ (org-end-of-line)
+ (when visual-line-mode
+ (end-of-visual-line 1)))
+ (and (= oldpos (point)) (move-end-of-line nil))))
+
+(keymap-global-set "<remap> <move-end-of-line>" #'re/smart-end-of-line)
+(keymap-set visual-line-mode-map "C-e" #'re/smart-end-of-line)
+
+(defun re/goto-line ()
+ "Show line numbers before going to line, then hide them again."
+ (interactive)
+ (display-line-numbers-mode 1)
+ (call-interactively 'goto-line)
+ (display-line-numbers-mode -1))
+
+(keymap-global-set "<remap> <goto-line>" #'re/goto-line)
+(keymap-global-set "<home>" #'beginning-of-buffer)
+(keymap-global-set "<end>" #'end-of-buffer)
+(keymap-global-set "C-." #'next-buffer)
+(keymap-global-set "C-," #'previous-buffer)
+(keymap-global-set "C-<tab>" (lambda () (interactive) (switch-to-buffer nil))) ; toggle last two buffers
+(keymap-global-set "<mouse-4>" #'previous-buffer) ; Back button
+(keymap-global-unset "M-<down-mouse-1>")
+(keymap-global-unset "M-<drag-mouse-1>")
+(keymap-global-unset "M-<mouse-1>")
+(keymap-global-unset "M-<mouse-2>")
+(keymap-global-unset "M-<mouse-3>")
+#+END_SRC
+* Search
+#+BEGIN_SRC emacs-lisp
+;; Search
+(defun re/isearch-forward-use-region ()
+ "Search text in region if active, otherwise normal forward search."
+ (interactive)
+ (when (use-region-p)
+ (add-to-history 'search-ring
+ (buffer-substring (region-beginning) (region-end)))
+ (deactivate-mark))
+ (isearch-forward))
+
+(keymap-global-set "C-s" #'re/isearch-forward-use-region)
+
+(defun re/isearch-backward-use-region ()
+ "Search text in region if active, otherwise normal backward search."
+ (interactive)
+ (when (use-region-p)
+ (add-to-history 'search-ring
+ (buffer-substring (region-beginning) (region-end)))
+ (deactivate-mark))
+ (isearch-backward))
+
+(keymap-global-set "C-r" #'re/isearch-backward-use-region)
+
+(defun re/exchange-point-and-mark-maybe-activate (arg)
+ "Call `exchange-point-and-mark' but don't activate the region.
+Stolen from https://www.masteringemacs.org/article/fixing-mark-commands-transient-mark-mode"
+ (interactive "P")
+ (exchange-point-and-mark (if (and transient-mark-mode (not mark-active))
+ (not arg)
+ arg)))
+
+(keymap-global-set "<remap> <exchange-point-and-mark>" #'re/exchange-point-and-mark-maybe-activate)
+
+(keymap-global-set "M-s ." #'isearch-forward-thing-at-point)
+(keymap-global-set "M-s M-." #'isearch-forward-symbol-at-point)
+(keymap-global-set "M-%" #'replace-regexp)
+(keymap-global-set "C-%" #'replace-string)
+(keymap-global-set "C-M-S-R" #'replace-regexp-as-diff)
+(keymap-global-set "C-S-S" #'isearch-forward-regexp)
+(keymap-global-set "C-S-R" #'isearch-backward-regexp)
+#+END_SRC
+* Recent Files/Buffers
+#+BEGIN_SRC emacs-lisp
+;; Recent Files/Buffers
+(midnight-mode t)
+(setq clean-buffer-list-delay-general 1)
+(dolist (never-re '("\\` \\*tramp/.*\\'"
+ "\\` \\*eshell.*\\'"))
+ (add-to-list 'clean-buffer-list-kill-never-regexps never-re))
+(save-place-mode 1)
+(recentf-mode 1)
+#+END_SRC
+* File Handling
+#+BEGIN_SRC emacs-lisp
+;; File Handling
+(defun re/rename-current-buffer-file nil
+ "Renames the current buffer and the file it is visiting."
+ (interactive)
+ (let ((name (buffer-name))
+ (filename (buffer-file-name)))
+ (if (not (and filename (file-exists-p filename)))
+ (error "Buffer '%s' is not visiting a file!" name)
+ (let ((new-name (read-file-name "New name: " filename)))
+ (if (get-buffer new-name)
+ (error "A buffer named '%s' already exists!" new-name)
+ (rename-file filename new-name 1)
+ (rename-buffer new-name)
+ (set-visited-file-name new-name)
+ (set-buffer-modified-p nil)
+ (message "File '%s' successfully renamed to '%s'"
+ name
+ (file-name-nondirectory new-name)))))))
+
+(keymap-global-set "C-x C-r" #'re/rename-current-buffer-file)
+
+(defun re/get-line-from-file (file-path line-number)
+ "Return the specified LINE-NUMBER from FILE-PATH as a string.
+Start from bottom if given a negative line number."
+ (with-temp-buffer
+ (insert-file-contents file-path)
+ (if (< line-number 0)
+ (progn
+ (goto-char (point-max))
+ (forward-line line-number))
+ (progn
+ (goto-char (point-min))
+ (forward-line (1- line-number))))
+ (buffer-substring-no-properties (line-beginning-position) (line-end-position))))
+
+(defun re/get-file-modified-time (filepath)
+ (interactive)
+ (format-time-string "%Y-%m-%d-%H%M"
+ (file-attribute-modification-time (file-attributes filepath))))
+
+(defun re/filename-inject-mod-time (filepath)
+ (interactive)
+ (concat (file-name-sans-extension filepath)
+ "_"
+ (re/get-file-modified-time filepath)
+ (file-name-extension filepath t)))
+
+(defun re/copy-with-mod-time (&optional filepath)
+ (interactive)
+ (let ((filepath (if (eq major-mode 'dired-mode)
+ (dired-get-filename t)
+ (when (null filepath)
+ (read-file-name "File to copy with datestring: "
+ default-directory
+ nil
+ t
+ nil)))))
+ (copy-file filepath (re/filename-inject-mod-time filepath ) nil t t t)))
+#+END_SRC
+* Dired
+#+BEGIN_SRC emacs-lisp
+;; Dired
+(defun re/dired-display-direction ()
+ "In dired mode, visit the file at the cursor in the right/below/left/above window."
+ (interactive)
+ (let* ((file-or-dir (dired-get-file-for-visit)) ;; get the file at cursor
+ (buffer (find-file-noselect file-or-dir))) ;; load the file into a buffer
+ (let ((window ;; figure out the window to use
+ (cond ((get-buffer-window buffer (selected-frame)))
+ ((window-in-direction 'right)) ;; try window in each direction
+ ((window-in-direction 'below)) ;; and default to right
+ ((window-in-direction 'left)) ;; if no window found.
+ ((window-in-direction 'above))
+ (t (split-window (selected-window) nil 'right)))))
+ (window--display-buffer buffer window 'window nil)
+ window)))
+
+(defun re/dired-new-frame ()
+ "Open dired in a new frame."
+ (interactive)
+ (re/open-with-new-frame "DIRED"
+ #'(lambda () (interactive) (dired default-directory))))
+
+(keymap-global-set "<f8>" #'re/dired-new-frame)
+
+(defun re/dired-find-marked-files ()
+ "Open all marked files from `dired'."
+ (interactive)
+ (mapc #'find-file (reverse (dired-get-marked-files))))
+
+(defun re/dired-sort ()
+ "Change sort order of dired dir."
+ (interactive)
+ (let ((smenu '(("name" . "-Ahl")
+ ("mdate" . "-Ahlt")
+ ("adate" . "-Ahltu")
+ ("size" . "-AhlS")
+ ("dir" . "-Ahl --group-directories-first")))
+ ssortBy)
+ (setq ssortBy (completing-read "Sort by (default name):"
+ smenu
+ nil
+ t
+ nil
+ nil
+ (caar smenu)))
+ (dired-sort-other (cdr (assoc ssortBy smenu)))))
+
+(defun re/open-file-external (file)
+ "Open a file in an external program."
+ (interactive)
+ (let ((process-connection-type nil))
+ (cond ((eq system-type 'windows-nt)
+ (w32-shell-execute "open"
+ (replace-regexp-in-string "/" "\\\\" file t t)))
+ ((eq system-type 'gnu/linux)
+ (start-process "" nil "xdg-open" file))
+ (t (error "Unable to automatically open this file")))))
+
+(defun re/dired-open-externally ()
+ "Open the file at point in an external program."
+ (interactive)
+ (re/open-file-external (dired-get-filename)))
+
+(defun re/dired-open-marked-externally ()
+ "Open all marked files from `dired' in an external program."
+ (interactive)
+ (mapc #'re/open-file-external (reverse (dired-get-marked-files))))
+
+(setq dired-listing-switches "-Ahl"
+ dired-vc-rename-file t
+ dired-auto-revert-buffer t
+ dired-hide-details-hide-symlink-targets nil
+ dired-kill-when-opening-new-dired-buffer t)
+
+(add-hook 'dired-mode-hook
+ (lambda ()
+ (progn
+ (keymap-set dired-mode-map
+ "o"
+ #'re/dired-display-direction)
+ ;; Rename r,R+M(mv), chmod M>c, compress-to c>z
+ (keymap-set dired-mode-map
+ "z"
+ #'dired-do-compress-to)
+ (keymap-set dired-mode-map
+ "c"
+ #'dired-do-chmod)
+ (keymap-set dired-mode-map
+ "r"
+ #'dired-do-rename)
+ (keymap-set dired-mode-map
+ "M"
+ #'dired-do-rename)
+ ;; My add-on defuns
+ (keymap-set dired-mode-map
+ "s"
+ #'re/dired-sort)
+ (keymap-set dired-mode-map
+ "F"
+ #'re/dired-find-marked-files)
+ (keymap-set dired-mode-map
+ "M-C"
+ #'re/copy-with-mod-time)
+ (keymap-set dired-mode-map
+ "b"
+ #'re/dired-open-externally)
+ (keymap-set dired-mode-map
+ "B"
+ #'re/dired-open-marked-externally)
+ (dired-hide-details-mode t)
+ (hl-line-mode))))
+#+END_SRC
+* Bookmarks
+#+BEGIN_SRC emacs-lisp
+;; Bookmarks
+(setq bookmark-save-flag 1)
+(keymap-global-set "<f7>" #'recentf-open-files)
+(keymap-global-set "C-x r B" #'bookmark-jump-other-window)
+#+END_SRC
+* GUI
+#+BEGIN_SRC emacs-lisp
+;; GUI Settings
+(load-theme 'eng-paper t)
+(menu-bar-mode -1)
+(tool-bar-mode -1)
+(set-scroll-bar-mode (if (eq system-type 'windows-nt) nil 'left))
+
+(setq frame-title-format "%b"
+ mouse-prefer-closest-glyph t
+ mouse-1-click-follows-link nil
+ focus-follows-mouse t
+ mouse-autoselect-window -0.25)
+
+(setq-default cursor-type 'hbar
+ cursor-in-non-selected-windows nil
+ mode-line-format
+ '("%e"
+ (:eval (propertize " "
+ 'face
+ (when (buffer-modified-p)
+ 'mode-line-highlight)))
+ " "
+ (:propertize (buffer-file-name "%f" "%b")
+ face
+ mode-line)
+ (vc-mode vc-mode)
+ mode-line-format-right-align
+ (:eval (number-to-string (line-number-at-pos (point-max))))
+ "L @ %I%n %l,%C "))
+
+(setq prettify-symbols-alist '(("lambda" . 955)
+ ("delta" . 120517)
+ ("epsilon" . 120518)
+ ("->" . 8594)
+ ("<=" . 8804)
+ (">=" . 8805)))
+
+(global-prettify-symbols-mode t)
+#+END_SRC
+* Parens
+#+BEGIN_SRC emacs-lisp
+;; Parens (must be after loading the theme)
+(setq show-paren-delay 0
+ show-paren-style 'expression)
+
+(setq electric-pair-pairs '((?\" . ?\")
+ (?\‘ . ?\’)
+ (?\“ . ?\”)
+ (?\{ . ?\})
+ (?\< . ?\>)))
+#+END_SRC
+* Help
+#+BEGIN_SRC emacs-lisp
+;; Help
+(setq apropos-do-all t)
+#+END_SRC
+* UTF-8
+#+BEGIN_SRC emacs-lisp
+;; UTF-8
+(set-charset-priority 'unicode)
+(prefer-coding-system 'utf-8-unix)
+(set-language-environment 'utf-8)
+(set-default-coding-systems 'utf-8)
+(set-keyboard-coding-system 'utf-8-unix)
+(set-terminal-coding-system 'utf-8-unix)
+#+END_SRC
+* Cleanup on write
+#+BEGIN_SRC emacs-lisp
+;; Cleanup on write
+(setq require-final-newline t)
+(add-hook 'before-save-hook #'re/flush-extra-lines)
+(add-hook 'before-save-hook #'whitespace-cleanup)
+(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)
+#+END_SRC
+* Control
+#+BEGIN_SRC emacs-lisp
+;; Control
+(defun re/kill-emacs ()
+ "Save all open files and kill emacs."
+ (interactive)
+ (save-some-buffers t)
+ (kill-emacs))
+
+(keymap-global-set "C-x M-c" #'re/kill-emacs)
+
+(defun re/restart-emacs ()
+ "Save all open files and restart emacs."
+ (interactive)
+ (save-some-buffers t)
+ (kill-emacs nil t))
+
+(keymap-global-set "C-x M-r" #'re/restart-emacs)
+
+(defun re/keyboard-quit ()
+ "Smarter version of `keyboard-quit'.
+Close the minibuffer if not focused when hit.
+Stolen from emacsredux.com."
+ (interactive)
+ (if (active-minibuffer-window)
+ (if (minibufferp)
+ (minibuffer-keyboard-quit)
+ (abort-recursive-edit))
+ (keyboard-quit)))
+
+(keymap-global-set "<remap> <keyboard-quit>" #'re/keyboard-quit) ; Make C-g better
+(keymap-global-set "C-x S" (lambda () (interactive) (save-some-buffers t))) ; don't ask
+(keymap-global-set "C-x c" #'delete-frame) ; delete a frame without asking about saving files
+#+END_SRC
+* Versioning and Backups
+#+BEGIN_SRC emacs-lisp
+;; Versioning and Backups
+(defun re/vc-clone ()
+ "Interactively clone with vc-mode.
+Prompt for url and local dir."
+ (interactive)
+ (let* ((url (read-string "Repository URL: "))
+ (dir (read-string "Local Dir: " (file-name-base url))))
+ (vc-git-clone url dir nil)))
+
+(defun re/vc-show-branches (&optional arg)
+ "Display all Git branches in a separate buffer.
+Remotes as well when arg."
+ (interactive "P")
+ (let ((default-directory (if (boundp 'vc-dir-directory)
+ vc-dir-directory
+ default-directory)))
+ (vc-git-command "*git-branches*"
+ nil
+ nil
+ "branch"
+ "--verbose"
+ (when arg "--remotes"))
+ (pop-to-buffer "*git-branches*")
+ (goto-char (point-min))
+ (special-mode)))
+
+(defun re/vc-fetch (&optional arg)
+ "Interactively fetch with vc-mode.
+Allows separate fetch in addition to pull. Only care about git.
+With arg, ask for remote, otherwise fetch all."
+ (interactive "P")
+ (let* ((default-directory (if (boundp 'vc-dir-directory)
+ vc-dir-directory
+ default-directory)))
+ (vc-git-command "*vc-fetch*"
+ nil
+ nil
+ "fetch"
+ (if arg
+ (read-string "Fetch From: " "origin")
+ "--all")
+ "--verbose")
+ (pop-to-buffer "*vc-fetch*")
+ (goto-char (point-min))
+ (special-mode)))
+
+(setq vc-make-backup-files nil
+ vc-handled-backends '(Git)
+ vc-git-diff-switches '("--patch-with-stat" "--histogram")
+ vc-git-log-switches '("--oneline" "--all" "--graph")
+ vc-git-log-edit-summary-target-len 50
+ vc-git-log-edit-summary-max-len 70
+ vc-find-revision-no-save t)
+
+(setq vc-git-root-log-format
+ `("%d %h %ai %an: %s"
+ ;; The first shy group matches the characters drawn by --graph.
+ ;; We use numbered groups because `log-view-message-re' wants the
+ ;; revision number to be group 1.
+ ,(concat "^\\(?:[*/\\|]+\\)\\(?:[*/\\| ]+\\)?"
+ "\\(?2: ([^)]+) \\)?\\(?1:[0-9a-z]+\\) "
+ "\\(?4:[0-9]\\{4\\}-[0-9-]\\{4\\}[0-9\s+:-]\\{16\\}\\) "
+ "\\(?3:.*?\\):")
+ ((1 'log-view-message)
+ (2 'change-log-list nil lax)
+ (3 'change-log-name)
+ (4 'change-log-date))))
+
+(setq backup-directory-alist `((".*" . "~/emacs-backups/"))
+ backup-by-copying t
+ delete-old-versions t
+ kept-new-versions 5
+ kept-old-versions 5)
+
+(keymap-global-set "C-x v C" #'re/vc-clone)
+(keymap-global-set "C-x v b b" #'re/vc-show-branches)
+(keymap-global-set "C-x v f" #'re/vc-fetch)
+
+(add-hook 'vc-dir-mode-hook
+ (lambda ()
+ (keymap-set vc-dir-mode-map "b b" #'re/vc-show-branches)
+ (keymap-set vc-dir-mode-map "f" #'re/vc-fetch)))
+#+END_SRC
+* Any Lisp Repl
+#+BEGIN_SRC emacs-lisp
+;; Any Lisp Repl
+(defmacro re/send-on-close-paren (executor)
+ "Generalizes sending an execute on close paren.
+ Interactively call `executor'. For `executor', use whatever
+ function is called by `<RET>' in the applicable REPL. For a
+ non-repl, use `newline' or similar."
+ `(lambda (&optional arg)
+ (interactive "p")
+ (insert-char 41 arg)
+ (call-interactively ,executor)))
+
+(defun re/sexp-drop-paren-p ()
+ "Returns t if sexp needs fewer parens to balance."
+ (< (car (syntax-ppss)) 0))
+
+(defun re/sexp-need-paren-p ()
+ "Returns t if sexp needs more parens to balance."
+ (> (car (syntax-ppss)) 0))
+
+(defun re/sexp-unbalanced-count ()
+ "Returns distance from balanced sexp."
+ (abs (car (syntax-ppss))))
+
+(defun re/balance-sexp ()
+ "Balance the sexp before point.
+Either delete, move forward, or add as many ')' as needed."
+ (let ((distance (re/sexp-unbalanced-count)))
+ (cond ((re/sexp-need-paren-p)
+ (if (looking-at ")")
+ (progn
+ (forward-char)
+ (re/balance-sexp))
+ (insert-char 41 distance)))
+ ((re/sexp-drop-paren-p)
+ (backward-delete-char distance)))))
+
+(defmacro re/balance-and-eval-sexp (executor)
+ "Balance the sexp before point, then call `executor'.
+Call `re/balance-sexp', then interactively call `executor'. Bind
+this to ']' for the interlisp experience. For `executor', use
+whatever function is called by `<RET>' in the applicable REPL.
+For a non-repl, use `newline' or similar."
+ `(lambda () (interactive) (re/balance-sexp) (call-interactively ,executor)))
+
+(defvar *re/lisp-mode-hooks*
+ '(emacs-lisp-mode-hook
+ lisp-mode-hook
+ sly-mode-hook
+ scheme-mode-hook
+ geiser-mode-hook
+ lisp-interaction-mode-hook))
+
+(dolist (hook *re/lisp-mode-hooks*)
+ (add-hook hook
+ (lambda ()
+ (when (bound-and-true-p acme-mouse-mode) (acme-mouse-mode -1))
+ (sedit-mouse-mode 1)
+ (keymap-set lisp-mode-shared-map "C-M-z" #'eval-region)
+ (keymap-set lisp-mode-shared-map
+ "C-M-S-q"
+ #'sedit-auto-prettify-sexp)
+ (keymap-set lisp-mode-shared-map
+ "]"
+ (re/balance-and-eval-sexp #'sedit-auto-prettify-sexp))
+ (keymap-set lisp-interaction-mode-map
+ "]"
+ (re/balance-and-eval-sexp #'eval-print-last-sexp)))))
+#+END_SRC
+* IELM
+#+BEGIN_SRC emacs-lisp
+;; IELM
+(add-hook 'ielm-mode-hook
+ (lambda ()
+ (keymap-set inferior-emacs-lisp-mode-map
+ "C-l"
+ #'comint-clear-buffer)
+ (let ((eval-function #'ielm-send-input))
+ (keymap-set inferior-emacs-lisp-mode-map
+ ")"
+ (re/send-on-close-paren eval-function))
+ (keymap-set inferior-emacs-lisp-mode-map
+ "]"
+ (re/balance-and-eval-sexp eval-function)))))
+#+END_SRC
+* Eshell
+#+BEGIN_SRC emacs-lisp
+;; Eshell
+(keymap-global-set "C-c e" #'eshell)
+
+(add-hook 'eshell-mode-hook
+ (lambda ()
+ (keymap-set eshell-mode-map "C-d" #'eshell-quit-or-delete-char)
+ (let ((eval-function #'eshell-send-input))
+ (keymap-set eshell-mode-map
+ ")"
+ (re/send-on-close-paren eval-function))
+ (keymap-set eshell-mode-map
+ "]"
+ (re/balance-and-eval-sexp eval-function)))))
+
+(defun eshell-quit-or-delete-char (arg)
+ "Delete char if at one, quit eshell if on empty prompt.
+Stolen from https://depp.brause.cc/dotemacs"
+ (interactive "p")
+ (if (and (eolp) (looking-back eshell-prompt-regexp 0 t))
+ (eshell-life-is-too-much)
+ (delete-char arg)))
+#+END_SRC
+* SLY REPL
+#+BEGIN_SRC emacs-lisp
+;; SLY REPL
+(add-hook 'sly-mrepl-mode-hook
+ (lambda ()
+ (keymap-set sly-mrepl-mode-map
+ ")"
+ (re/send-on-close-paren #'sly-mrepl-return))
+ (keymap-set sly-mrepl-mode-map
+ "]"
+ (re/balance-and-eval-sexp #'sly-mrepl-return))
+ (keymap-set sly-mrepl-mode-map
+ "C-c q"
+ #'re/sly-quit-current-lisp)))
+
+(defun re/sly-repl-new-frame (&optional arg)
+ "Start a SLY repl in a new frame."
+ (interactive "P")
+ (re/open-with-new-frame "SLY" #'sly))
+
+(defun re/sly-quit-current-lisp ()
+ "Quit the current lisp repl connection without prompting."
+ (interactive)
+ (sly-quit-lisp nil nil))
+
+(defun re/sly-connect-stump (&optional arg)
+ "Connect to my typical stumpwm instance."
+ (interactive "P")
+ (sly-connect "localhost" 4004))
+#+END_SRC
+* GEISER REPL
+#+BEGIN_SRC emacs-lisp
+;; GEISER REPL
+(add-hook 'geiser-repl-mode-hook
+ (lambda ()
+ (keymap-set geiser-repl-mode-map
+ ")"
+ (re/send-on-close-paren #'geiser-repl-maybe-send))
+ (keymap-set geiser-repl-mode-map
+ "]"
+ (re/balance-and-eval-sexp #'geiser-repl-maybe-send))))
+#+END_SRC
+* C-mode
+#+BEGIN_SRC emacs-lisp
+;;; C-mode
+(dolist (mode-maps '(("\\.keymap\\'" . c-mode) ("\\.dtsi\\'" . c-mode)))
+ (add-to-list 'auto-mode-alist mode-maps t))
+
+(defun re/c-lineup-arglist-tabs-only (ignored)
+ "Line up argument lists by tabs, not spaces.
+ Stolen from https://kernel.org/doc/html/v4.10/process/coding-style.html"
+ (let* ((anchor (c-langelem-pos c-syntactic-element))
+ (column (c-langelem-2nd-pos c-syntactic-element))
+ (offset (- (1+ column) anchor))
+ (steps (floor offset c-basic-offset)))
+ (* (max steps 1) c-basic-offset)))
+
+(add-hook 'c-mode-common-hook
+ (lambda ()
+ (c-add-style "linux-tabs-only"
+ '("linux" (c-offsets-alist
+ (arglist-cont-nonempty
+ c-lineup-gcc-asm-reg
+ re/c-lineup-arglist-tabs-only))))))
+
+(add-hook 'c-mode-hook
+ (lambda ()
+ (setq c-backspace-function 'backward-delete-char)
+ (c-set-style "linux-tabs-only")))
+#+END_SRC
+* Auto-Revert
+#+BEGIN_SRC emacs-lisp
+;; Auto-Revert
+(global-auto-revert-mode t)
+(setq global-auto-revert-non-file-buffers t
+ global-auto-revert-ignore-modes '(Buffer-menu-mode))
+#+END_SRC
+* Crash Handliŋ
+#+BEGIN_SRC emacs-lisp
+;; Crash handliŋ
+(setq attempt-stack-overflow-recovery nil
+ attempt-orderly-shutdown-on-fatal-signal nil)
+#+END_SRC
+* Abbrev-mode and skeletons
+#+BEGIN_SRC emacs-lisp
+;; Abbrev-mode and Skeletons
+(define-skeleton workorder-link
+ "part of a link to a workorder, just enter the number."
+ ""
+ "https://eservice.r717.net/index.php/PLC_workorders/store/"
+ _ -)
+
+(define-skeleton skel-org-block
+ "Add an elisp source block to an org file."
+ ""
+ "#+BEGIN_SRC"
+ \n
+ _ -
+ \n
+ "#+END_SRC")
+
+(define-skeleton skel-org-block-elisp
+ "Add an elisp source block to an org file."
+ ""
+ "#+BEGIN_SRC emacs-lisp"
+ \n
+ _ -
+ \n
+ "#+END_SRC")
+
+(setq abbrev-file-name (expand-file-name "abbrev_defs" user-emacs-directory)
+ save-abbrevs 'silently)
+
+(dolist (hook '(org-mode-hook howm-mode-hook))
+ (add-hook hook #'abbrev-mode))
+#+END_SRC
+* Customization Framework
+#+BEGIN_SRC emacs-lisp
+;; Customization framework
+;; Disable by making a temp file (stolen from prot)
+(setq custom-file (make-temp-file "emacs-custom-"))
+
+;;; config.el ends here
+#+END_SRC
;;; Code:
-(dolist (path '("sedit-mouse/" "themes/" "re/"))
- (add-to-list 'load-path (concat user-emacs-directory path)))
-
-(dolist (file '(re-packages re-pass-alike eng-paper-theme sedit-mouse))
- (require file))
-
-(setq w32-recognize-altgr 'nil)
-
-(unless (equal system-type 'windows-nt)
- (require 're-mu4e)
- (setq trash-directory "~/Trash/")
- (defun doas ()
- "Use TRAMP to reopen the current buffer as root using doas."
- (interactive)
- (when buffer-file-name
- (find-alternate-file (concat "/doas:root@localhost:"
- buffer-file-name))))
- (defun sudo ()
- "Use TRAMP to reopen the current buffer as root using sudo."
- (interactive)
- (when buffer-file-name
- (find-alternate-file (concat "/sudo:root@localhost:"
- buffer-file-name)))))
-\f
-;; Editing
-(defun re/open-line-below (n)
- "Creates a new empty line below the current line and moves to it."
- (interactive "*p")
- (end-of-line)
- (open-line n)
- (next-line 1)
- (indent-for-tab-command))
-
-(keymap-global-set "C-o" #'re/open-line-below)
-
-(defun re/open-line-above (n)
- "Creates a new empty line above the current line."
- (interactive "*p")
- (beginning-of-line)
- (open-line n)
- (indent-for-tab-command))
-
-(keymap-global-set "M-o" #'re/open-line-above)
-
-(defun re/flush-extra-lines ()
- "Change all groups of blank lines to 1 blank line."
- (interactive)
- (save-excursion (mark-whole-buffer)
- (replace-regexp "^\n+"
- "\n"
- nil
- (region-beginning)
- (region-end))))
-
-(defun re/comment-dwim (&optional arg)
- "Comment region if active, otherwise comment line.
-Stolen from https://depp.brause.cc/dotemacs"
- (interactive "P")
- (if (use-region-p)
- (comment-or-uncomment-region (region-beginning) (region-end))
- (comment-line arg)))
-
-(keymap-global-set "M-;" #'re/comment-dwim)
-
-(defun re/comment-defun (&optional arg)
- "Mark a defun and comment it out.
-Return to initial position after. Arg works on `mark-defun'."
- (interactive "P")
- (save-excursion (mark-defun arg)
- (comment-region (region-beginning) (region-end))))
-
-(keymap-global-set "C-M-;" #'re/comment-defun)
-
-(defun re/kill-defun (&optional arg)
- "Mark a defun and kill it.
-Arg works on `mark-defun'."
- (interactive "P")
- (mark-defun arg)
- (kill-region (region-beginning) (region-end)))
-
-(keymap-global-set "C-M-S-K" #'re/kill-defun)
-
-(defun re/kill-bword-or-region (&optional arg)
-"Kill region if active, otherwise kill back one word."
-(interactive "p")
-(if (use-region-p)
- (kill-region (region-beginning) (region-end))
- (backward-kill-word arg)))
-
-(keymap-global-set "C-w" #'re/kill-bword-or-region)
-
-(keymap-global-set "<insert>" nil) ; I keep toggliŋ overwrite-mode haply
-(keymap-global-set "C-\\" #'undo-redo) ; issues with C-? sometimes
-(keymap-global-set "C-S-K" #'kill-whole-line)
-(keymap-global-set "C-u" (lambda () (interactive) (kill-line 0))) ; kill-line backwards
-(keymap-global-set "C-S-U" #'universal-argument) ; C-u used above
-(keymap-set key-translation-map "C-h" "<DEL>") ; Rather F1 for help, also C-S-H works
-(keymap-global-set "C-S-d" #'delete-pair)
-(keymap-global-set "M-j" (lambda () (interactive) (join-line 0))) ; join-line other way
-(keymap-global-set "C-z" #'zap-up-to-char)
-(keymap-global-set "C-c s" #'sort-lines)
-(keymap-global-set "<remap> <capitalize-word>" #'capitalize-dwim) ; M-c
-(keymap-global-set "<remap> <downcase-word>" #'downcase-dwim) ; M-l
-(keymap-global-set "<remap> <upcase-word>" #'upcase-dwim) ; M-u
-\f
-;; Tabs
-(setq-default indent-tabs-mode t
- tab-width 8
- backward-delete-char-untabify-method nil)
-
-(advice-add 'indent-to :around
- (lambda (orig-fun column &rest args)
- (when indent-tabs-mode
- (setq column (* tab-width (round column tab-width))))
- (apply orig-fun column args)))
-
-(dolist (indent-level '(c-basic-offset cperl-indent-level LaTeX-indent-level))
- (defvaralias indent-level 'tab-width))
-
-(defun Tab (width)
- "Give me a function analagous to the Acme `Tab' command"
- (interactive)
- (setq-local tab-width width))
-
-(keymap-global-set "<tab>" (lambda () (interactive) (insert "\t")))
-\f
-;; Buffer dealiŋ
-(setq-default indicate-empty-lines t
- truncate-lines t
- fill-column 78)
-
-(dolist (hook '(text-mode-hook LaTeX-mode-hook))
- (add-hook hook #'visual-line-mode))
-
-(add-to-list 'display-buffer-alist
- '("^\\*eldoc" display-buffer-in-direction
- (direction . 'down)
- (window-height . 4)))
-
-(blink-cursor-mode -1)
-(delete-selection-mode t)
-
-(setq delete-by-moving-to-trash t
- delete-pair-blink-delay 0
- use-short-answers t
- use-file-dialog nil
- echo-keystrokes 0.1
- eldoc-idle-delay 0
- read-buffer-completion-ignore-case t
- history-delete-duplicates t
- disabled-command-function nil
- save-interprogram-paste-before-kill t
- confirm-kill-processes nil
- recenter-positions '(2 middle -3))
-
-(defun re/recenter-advice (&rest _)
- "Recenter to page start."
- (when (called-interactively-p 'any) (recenter 2)))
-
-(dolist (binding '(backward-page forward-page))
- (advice-add binding :after #'re/recenter-advice))
-
-(keymap-global-set "C-x C-n" #'forward-page)
-(keymap-global-set "C-x C-p" #'backward-page)
-(keymap-global-set "<next>" #'forward-page)
-(keymap-global-set "<prior>" #'backward-page)
-
-(defmacro re/open-with-new-frame (frname function)
- "Run the function in its own named frame."
- `(progn
- (select-frame (make-frame '((name . ,(eval frname)))))
- (call-interactively ,function)))
-
-(keymap-global-set "C-x M-f" #'find-file-at-point)
-(keymap-global-set "C-x C-b" #'buffer-menu)
-(keymap-global-set "C-x M-b" #'buffer-menu-other-window)
-(keymap-global-set "C-x k" #'kill-current-buffer)
-(keymap-global-set "C-x K" #'kill-buffer)
-(keymap-global-set "C-c d" #'eldoc) ; force eldoc to show in minibuffer
-(keymap-global-set "C-c D" #'eldoc-doc-buffer) ; open eldoc buffer when it's getting spammed
-\f
-;; Motion
-(defun re/scratch-only ()
- "Bring up the scratch buffer as the only visible buffer."
- (interactive)
- (scratch-buffer)
- (delete-other-windows))
-
-(keymap-global-set "<f5>" #'scratch-buffer)
-(keymap-global-set "S-<f5>" #'re/scratch-only)
-
-(defun re/other-window-or-split-window (&optional window)
- "Go to other window or split sensibly."
- (interactive)
- (if (= (count-windows) 1)
- (funcall split-window-preferred-function window)
- (other-window 1)))
-
-(keymap-global-set "C-M-o" #'re/other-window-or-split-window)
-
-(defun re/smart-beginning-of-line ()
- "Move point to first non-whitespace character or `beginning-of-visual-line'.
-If point was already at that position, call `back-to-indentation'.
-Called a third time, move point back to `beginning-of-line'.
-If in org-mode, call `org-beginning-of-line' first."
- (interactive "^")
- (let ((oldpos (point)))
- (if (equal major-mode 'org-mode)
- (org-beginning-of-line)
- (progn
- (when visual-line-mode (beginning-of-visual-line 1))
- (skip-syntax-forward " " (line-end-position))
- (backward-prefix-chars)))
- (and (= oldpos (point))
- (let ((newpos (point)))
- (back-to-indentation)
- (and (= newpos (point)) (beginning-of-line))))))
-
-(keymap-global-set "<remap> <move-beginning-of-line>" #'re/smart-beginning-of-line)
-(keymap-set visual-line-mode-map "C-a" #'re/smart-beginning-of-line)
-
-(defun re/smart-end-of-line ()
- "Move point to the end of the visual line.
- If point was already at that position, call `move-end-of-line'.
-If in org-mode, call `org-end-of-line' first."
- (interactive "^")
- (let ((oldpos (point)))
- (if (equal major-mode 'org-mode)
- (org-end-of-line)
- (when visual-line-mode
- (end-of-visual-line 1)))
- (and (= oldpos (point)) (move-end-of-line nil))))
-
-(keymap-global-set "<remap> <move-end-of-line>" #'re/smart-end-of-line)
-(keymap-set visual-line-mode-map "C-e" #'re/smart-end-of-line)
-
-(defun re/goto-line ()
- "Show line numbers before going to line, then hide them again."
- (interactive)
- (display-line-numbers-mode 1)
- (call-interactively 'goto-line)
- (display-line-numbers-mode -1))
-
-(keymap-global-set "<remap> <goto-line>" #'re/goto-line)
-(keymap-global-set "<home>" #'beginning-of-buffer)
-(keymap-global-set "<end>" #'end-of-buffer)
-(keymap-global-set "C-." #'next-buffer)
-(keymap-global-set "C-," #'previous-buffer)
-(keymap-global-set "C-<tab>" (lambda () (interactive) (switch-to-buffer nil))) ; toggle last two buffers
-(keymap-global-set "<mouse-4>" #'previous-buffer) ; Back button
-(keymap-global-unset "M-<down-mouse-1>")
-(keymap-global-unset "M-<drag-mouse-1>")
-(keymap-global-unset "M-<mouse-1>")
-(keymap-global-unset "M-<mouse-2>")
-(keymap-global-unset "M-<mouse-3>")
-\f
-;; Search
-(defun re/isearch-forward-use-region ()
- "Search text in region if active, otherwise normal forward search."
- (interactive)
- (when (use-region-p)
- (add-to-history 'search-ring
- (buffer-substring (region-beginning) (region-end)))
- (deactivate-mark))
- (isearch-forward))
-
-(keymap-global-set "C-s" #'re/isearch-forward-use-region)
-
-(defun re/isearch-backward-use-region ()
- "Search text in region if active, otherwise normal backward search."
- (interactive)
- (when (use-region-p)
- (add-to-history 'search-ring
- (buffer-substring (region-beginning) (region-end)))
- (deactivate-mark))
- (isearch-backward))
-
-(keymap-global-set "C-r" #'re/isearch-backward-use-region)
-
-(defun re/exchange-point-and-mark-maybe-activate (arg)
- "Call `exchange-point-and-mark' but don't activate the region.
-Stolen from https://www.masteringemacs.org/article/fixing-mark-commands-transient-mark-mode"
- (interactive "P")
- (exchange-point-and-mark (if (and transient-mark-mode (not mark-active))
- (not arg)
- arg)))
-
-(keymap-global-set "<remap> <exchange-point-and-mark>" #'re/exchange-point-and-mark-maybe-activate)
-
-(keymap-global-set "M-s ." #'isearch-forward-thing-at-point)
-(keymap-global-set "M-s M-." #'isearch-forward-symbol-at-point)
-(keymap-global-set "M-%" #'replace-regexp)
-(keymap-global-set "C-%" #'replace-string)
-(keymap-global-set "C-M-S-R" #'replace-regexp-as-diff)
-(keymap-global-set "C-S-S" #'isearch-forward-regexp)
-(keymap-global-set "C-S-R" #'isearch-backward-regexp)
-\f
-;; Recent Files/Buffers
-(midnight-mode t)
-(setq clean-buffer-list-delay-general 1)
-(dolist (never-re '("\\` \\*tramp/.*\\'"
- "\\` \\*eshell.*\\'"))
- (add-to-list 'clean-buffer-list-kill-never-regexps never-re))
-(save-place-mode 1)
-(recentf-mode 1)
-\f
-;; File Handling
-(defun re/rename-current-buffer-file nil
- "Renames the current buffer and the file it is visiting."
- (interactive)
- (let ((name (buffer-name))
- (filename (buffer-file-name)))
- (if (not (and filename (file-exists-p filename)))
- (error "Buffer '%s' is not visiting a file!" name)
- (let ((new-name (read-file-name "New name: " filename)))
- (if (get-buffer new-name)
- (error "A buffer named '%s' already exists!" new-name)
- (rename-file filename new-name 1)
- (rename-buffer new-name)
- (set-visited-file-name new-name)
- (set-buffer-modified-p nil)
- (message "File '%s' successfully renamed to '%s'"
- name
- (file-name-nondirectory new-name)))))))
-
-(keymap-global-set "C-x C-r" #'re/rename-current-buffer-file)
-
-(defun re/get-line-from-file (file-path line-number)
- "Return the specified LINE-NUMBER from FILE-PATH as a string.
-Start from bottom if given a negative line number."
- (with-temp-buffer
- (insert-file-contents file-path)
- (if (< line-number 0)
- (progn
- (goto-char (point-max))
- (forward-line line-number))
- (progn
- (goto-char (point-min))
- (forward-line (1- line-number))))
- (buffer-substring-no-properties (line-beginning-position) (line-end-position))))
-
-(defun re/get-file-modified-time (filepath)
- (interactive)
- (format-time-string "%Y-%m-%d-%H%M"
- (file-attribute-modification-time (file-attributes filepath))))
-
-(defun re/filename-inject-mod-time (filepath)
- (interactive)
- (concat (file-name-sans-extension filepath)
- "_"
- (re/get-file-modified-time filepath)
- (file-name-extension filepath t)))
-
-(defun re/copy-with-mod-time (&optional filepath)
- (interactive)
- (let ((filepath (if (eq major-mode 'dired-mode)
- (dired-get-filename t)
- (when (null filepath)
- (read-file-name "File to copy with datestring: "
- default-directory
- nil
- t
- nil)))))
- (copy-file filepath (re/filename-inject-mod-time filepath ) nil t t t)))
-\f
-;; Dired
-(defun re/dired-display-direction ()
- "In dired mode, visit the file at the cursor in the right/below/left/above window."
- (interactive)
- (let* ((file-or-dir (dired-get-file-for-visit)) ;; get the file at cursor
- (buffer (find-file-noselect file-or-dir))) ;; load the file into a buffer
- (let ((window ;; figure out the window to use
- (cond ((get-buffer-window buffer (selected-frame)))
- ((window-in-direction 'right)) ;; try window in each direction
- ((window-in-direction 'below)) ;; and default to right
- ((window-in-direction 'left)) ;; if no window found.
- ((window-in-direction 'above))
- (t (split-window (selected-window) nil 'right)))))
- (window--display-buffer buffer window 'window nil)
- window)))
-
-(defun re/dired-new-frame ()
- "Open dired in a new frame."
- (interactive)
- (re/open-with-new-frame "DIRED"
- #'(lambda () (interactive) (dired default-directory))))
-
-(keymap-global-set "<f8>" #'re/dired-new-frame)
-
-(defun re/dired-find-marked-files ()
- "Open all marked files from `dired'."
- (interactive)
- (mapc #'find-file (reverse (dired-get-marked-files))))
-
-(defun re/dired-sort ()
- "Change sort order of dired dir."
- (interactive)
- (let ((smenu '(("name" . "-Ahl")
- ("mdate" . "-Ahlt")
- ("adate" . "-Ahltu")
- ("size" . "-AhlS")
- ("dir" . "-Ahl --group-directories-first")))
- ssortBy)
- (setq ssortBy (completing-read "Sort by (default name):"
- smenu
- nil
- t
- nil
- nil
- (caar smenu)))
- (dired-sort-other (cdr (assoc ssortBy smenu)))))
-
-(defun re/open-file-external (file)
- "Open a file in an external program."
- (interactive)
- (let ((process-connection-type nil))
- (cond ((eq system-type 'windows-nt)
- (w32-shell-execute "open"
- (replace-regexp-in-string "/" "\\\\" file t t)))
- ((eq system-type 'gnu/linux)
- (start-process "" nil "xdg-open" file))
- (t (error "Unable to automatically open this file")))))
-
-(defun re/dired-open-externally ()
- "Open the file at point in an external program."
- (interactive)
- (re/open-file-external (dired-get-filename)))
-
-(defun re/dired-open-marked-externally ()
- "Open all marked files from `dired' in an external program."
- (interactive)
- (mapc #'re/open-file-external (reverse (dired-get-marked-files))))
-
-(setq dired-listing-switches "-Ahl"
- dired-vc-rename-file t
- dired-auto-revert-buffer t
- dired-hide-details-hide-symlink-targets nil
- dired-kill-when-opening-new-dired-buffer t)
-
-(add-hook 'dired-mode-hook
- (lambda ()
- (progn
- (keymap-set dired-mode-map
- "o"
- #'re/dired-display-direction)
- ;; Rename r,R+M(mv), chmod M>c, compress-to c>z
- (keymap-set dired-mode-map
- "z"
- #'dired-do-compress-to)
- (keymap-set dired-mode-map
- "c"
- #'dired-do-chmod)
- (keymap-set dired-mode-map
- "r"
- #'dired-do-rename)
- (keymap-set dired-mode-map
- "M"
- #'dired-do-rename)
- ;; My add-on defuns
- (keymap-set dired-mode-map
- "s"
- #'re/dired-sort)
- (keymap-set dired-mode-map
- "F"
- #'re/dired-find-marked-files)
- (keymap-set dired-mode-map
- "M-C"
- #'re/copy-with-mod-time)
- (keymap-set dired-mode-map
- "b"
- #'re/dired-open-externally)
- (keymap-set dired-mode-map
- "B"
- #'re/dired-open-marked-externally)
- (dired-hide-details-mode t)
- (hl-line-mode))))
-\f
-;; Bookmarks
-(setq bookmark-save-flag 1)
-(keymap-global-set "<f7>" #'recentf-open-files)
-(keymap-global-set "C-x r B" #'bookmark-jump-other-window)
-\f
-;; GUI Settings
-(load-theme 'eng-paper t)
-(menu-bar-mode -1)
-(tool-bar-mode -1)
-(set-scroll-bar-mode (if (eq system-type 'windows-nt) nil 'left))
-
-(setq frame-title-format "%b"
- mouse-prefer-closest-glyph t
- mouse-1-click-follows-link nil
- focus-follows-mouse t
- mouse-autoselect-window -0.25)
-
-(setq-default cursor-type 'hbar
- cursor-in-non-selected-windows nil
- mode-line-format
- '("%e"
- (:eval (propertize " "
- 'face
- (when (buffer-modified-p)
- 'mode-line-highlight)))
- " "
- (:propertize (buffer-file-name "%f" "%b")
- face
- mode-line)
- (vc-mode vc-mode)
- mode-line-format-right-align
- (:eval (number-to-string (line-number-at-pos (point-max))))
- "L @ %I%n %l,%C "))
-
-(setq prettify-symbols-alist '(("lambda" . 955)
- ("delta" . 120517)
- ("epsilon" . 120518)
- ("->" . 8594)
- ("<=" . 8804)
- (">=" . 8805)))
-
-(global-prettify-symbols-mode t)
-\f
-;; Parens (must be after loading the theme)
-(setq show-paren-delay 0
- show-paren-style 'expression)
-
-(setq electric-pair-pairs '((?\" . ?\")
- (?\‘ . ?\’)
- (?\“ . ?\”)
- (?\{ . ?\})
- (?\< . ?\>)))
-\f
-;; Help
-(setq apropos-do-all t)
-\f
-;; UTF-8
-(set-charset-priority 'unicode)
-(prefer-coding-system 'utf-8-unix)
-(set-language-environment 'utf-8)
-(set-default-coding-systems 'utf-8)
-(set-keyboard-coding-system 'utf-8-unix)
-(set-terminal-coding-system 'utf-8-unix)
-\f
-;; Cleanup on write
-(setq require-final-newline t)
-(add-hook 'before-save-hook #'re/flush-extra-lines)
-(add-hook 'before-save-hook #'whitespace-cleanup)
-(add-hook 'after-save-hook #'executable-make-buffer-file-executable-if-script-p)
-\f
-;; Control
-(defun re/kill-emacs ()
- "Save all open files and kill emacs."
- (interactive)
- (save-some-buffers t)
- (kill-emacs))
-
-(keymap-global-set "C-x M-c" #'re/kill-emacs)
-
-(defun re/restart-emacs ()
- "Save all open files and restart emacs."
- (interactive)
- (save-some-buffers t)
- (kill-emacs nil t))
-
-(keymap-global-set "C-x M-r" #'re/restart-emacs)
-
-(defun re/keyboard-quit ()
- "Smarter version of `keyboard-quit'.
-Close the minibuffer if not focused when hit.
-Stolen from emacsredux.com."
- (interactive)
- (if (active-minibuffer-window)
- (if (minibufferp)
- (minibuffer-keyboard-quit)
- (abort-recursive-edit))
- (keyboard-quit)))
-
-(keymap-global-set "<remap> <keyboard-quit>" #'re/keyboard-quit) ; Make C-g better
-(keymap-global-set "C-x S" (lambda () (interactive) (save-some-buffers t))) ; don't ask
-(keymap-global-set "C-x c" #'delete-frame) ; delete a frame without asking about saving files
-\f
-;; Versioning and Backups
-(defun re/vc-clone ()
- "Interactively clone with vc-mode.
-Prompt for url and local dir."
- (interactive)
- (let* ((url (read-string "Repository URL: "))
- (dir (read-string "Local Dir: " (file-name-base url))))
- (vc-git-clone url dir nil)))
-
-(defun re/vc-show-branches (&optional arg)
- "Display all Git branches in a separate buffer.
-Remotes as well when arg."
- (interactive "P")
- (let ((default-directory (if (boundp 'vc-dir-directory)
- vc-dir-directory
- default-directory)))
- (vc-git-command "*git-branches*"
- nil
- nil
- "branch"
- "--verbose"
- (when arg "--remotes"))
- (pop-to-buffer "*git-branches*")
- (goto-char (point-min))
- (special-mode)))
-
-(defun re/vc-fetch (&optional arg)
- "Interactively fetch with vc-mode.
-Allows separate fetch in addition to pull. Only care about git.
-With arg, ask for remote, otherwise fetch all."
- (interactive "P")
- (let* ((default-directory (if (boundp 'vc-dir-directory)
- vc-dir-directory
- default-directory)))
- (vc-git-command "*vc-fetch*"
- nil
- nil
- "fetch"
- (if arg
- (read-string "Fetch From: " "origin")
- "--all")
- "--verbose")
- (pop-to-buffer "*vc-fetch*")
- (goto-char (point-min))
- (special-mode)))
-
-(setq vc-make-backup-files nil
- vc-handled-backends '(Git)
- vc-git-diff-switches '("--patch-with-stat" "--histogram")
- vc-git-log-switches '("--oneline" "--all" "--graph")
- vc-git-log-edit-summary-target-len 50
- vc-git-log-edit-summary-max-len 70
- vc-find-revision-no-save t)
-
-(setq vc-git-root-log-format
- `("%d %h %ai %an: %s"
- ;; The first shy group matches the characters drawn by --graph.
- ;; We use numbered groups because `log-view-message-re' wants the
- ;; revision number to be group 1.
- ,(concat "^\\(?:[*/\\|]+\\)\\(?:[*/\\| ]+\\)?"
- "\\(?2: ([^)]+) \\)?\\(?1:[0-9a-z]+\\) "
- "\\(?4:[0-9]\\{4\\}-[0-9-]\\{4\\}[0-9\s+:-]\\{16\\}\\) "
- "\\(?3:.*?\\):")
- ((1 'log-view-message)
- (2 'change-log-list nil lax)
- (3 'change-log-name)
- (4 'change-log-date))))
-
-(setq backup-directory-alist `((".*" . "~/emacs-backups/"))
- backup-by-copying t
- delete-old-versions t
- kept-new-versions 5
- kept-old-versions 5)
-
-(keymap-global-set "C-x v C" #'re/vc-clone)
-(keymap-global-set "C-x v b b" #'re/vc-show-branches)
-(keymap-global-set "C-x v f" #'re/vc-fetch)
-
-(add-hook 'vc-dir-mode-hook
- (lambda ()
- (keymap-set vc-dir-mode-map "b b" #'re/vc-show-branches)
- (keymap-set vc-dir-mode-map "f" #'re/vc-fetch)))
-
-\f
-;; Any Lisp Repl
-(defmacro re/send-on-close-paren (executor)
- "Generalizes sending an execute on close paren.
- Interactively call `executor'. For `executor', use whatever
- function is called by `<RET>' in the applicable REPL. For a
- non-repl, use `newline' or similar."
- `(lambda (&optional arg)
- (interactive "p")
- (insert-char 41 arg)
- (call-interactively ,executor)))
-
-(defun re/sexp-drop-paren-p ()
- "Returns t if sexp needs fewer parens to balance."
- (< (car (syntax-ppss)) 0))
-
-(defun re/sexp-need-paren-p ()
- "Returns t if sexp needs more parens to balance."
- (> (car (syntax-ppss)) 0))
-
-(defun re/sexp-unbalanced-count ()
- "Returns distance from balanced sexp."
- (abs (car (syntax-ppss))))
-
-(defun re/balance-sexp ()
- "Balance the sexp before point.
-Either delete, move forward, or add as many ')' as needed."
- (let ((distance (re/sexp-unbalanced-count)))
- (cond ((re/sexp-need-paren-p)
- (if (looking-at ")")
- (progn
- (forward-char)
- (re/balance-sexp))
- (insert-char 41 distance)))
- ((re/sexp-drop-paren-p)
- (backward-delete-char distance)))))
-
-(defmacro re/balance-and-eval-sexp (executor)
- "Balance the sexp before point, then call `executor'.
-Call `re/balance-sexp', then interactively call `executor'. Bind
-this to ']' for the interlisp experience. For `executor', use
-whatever function is called by `<RET>' in the applicable REPL.
-For a non-repl, use `newline' or similar."
- `(lambda () (interactive) (re/balance-sexp) (call-interactively ,executor)))
-
-(defvar *re/lisp-mode-hooks*
- '(emacs-lisp-mode-hook
- lisp-mode-hook
- sly-mode-hook
- scheme-mode-hook
- geiser-mode-hook
- lisp-interaction-mode-hook))
-
-(dolist (hook *re/lisp-mode-hooks*)
- (add-hook hook
- (lambda ()
- (when (bound-and-true-p acme-mouse-mode) (acme-mouse-mode -1))
- (sedit-mouse-mode 1)
- (keymap-set lisp-mode-shared-map "C-M-z" #'eval-region)
- (keymap-set lisp-mode-shared-map
- "C-M-S-q"
- #'sedit-auto-prettify-sexp)
- (keymap-set lisp-mode-shared-map
- "]"
- (re/balance-and-eval-sexp #'sedit-auto-prettify-sexp))
- (keymap-set lisp-interaction-mode-map
- "]"
- (re/balance-and-eval-sexp #'eval-print-last-sexp)))))
-
-\f
-;; IELM
-
-(add-hook 'ielm-mode-hook
- (lambda ()
- (keymap-set inferior-emacs-lisp-mode-map
- "C-l"
- #'comint-clear-buffer)
- (let ((eval-function #'ielm-send-input))
- (keymap-set inferior-emacs-lisp-mode-map
- ")"
- (re/send-on-close-paren eval-function))
- (keymap-set inferior-emacs-lisp-mode-map
- "]"
- (re/balance-and-eval-sexp eval-function)))))
-\f
-;; Eshell
-(keymap-global-set "C-c e" #'eshell)
-
-(add-hook 'eshell-mode-hook
- (lambda ()
- (keymap-set eshell-mode-map "C-d" #'eshell-quit-or-delete-char)
- (let ((eval-function #'eshell-send-input))
- (keymap-set eshell-mode-map
- ")"
- (re/send-on-close-paren eval-function))
- (keymap-set eshell-mode-map
- "]"
- (re/balance-and-eval-sexp eval-function)))))
-
-(defun eshell-quit-or-delete-char (arg)
- "Delete char if at one, quit eshell if on empty prompt.
-Stolen from https://depp.brause.cc/dotemacs"
- (interactive "p")
- (if (and (eolp) (looking-back eshell-prompt-regexp 0 t))
- (eshell-life-is-too-much)
- (delete-char arg)))
-\f
-;; SLY REPL
-(add-hook 'sly-mrepl-mode-hook
- (lambda ()
- (keymap-set sly-mrepl-mode-map
- ")"
- (re/send-on-close-paren #'sly-mrepl-return))
- (keymap-set sly-mrepl-mode-map
- "]"
- (re/balance-and-eval-sexp #'sly-mrepl-return))
- (keymap-set sly-mrepl-mode-map
- "C-c q"
- #'re/sly-quit-current-lisp)))
-
-(defun re/sly-repl-new-frame (&optional arg)
- "Start a SLY repl in a new frame."
- (interactive "P")
- (re/open-with-new-frame "SLY" #'sly))
-
-(defun re/sly-quit-current-lisp ()
- "Quit the current lisp repl connection without prompting."
- (interactive)
- (sly-quit-lisp nil nil))
-
-(defun re/sly-connect-stump (&optional arg)
- "Connect to my typical stumpwm instance."
- (interactive "P")
- (sly-connect "localhost" 4004))
-\f
-;; GEISER REPL
-(add-hook 'geiser-repl-mode-hook
- (lambda ()
- (keymap-set geiser-repl-mode-map
- ")"
- (re/send-on-close-paren #'geiser-repl-maybe-send))
- (keymap-set geiser-repl-mode-map
- "]"
- (re/balance-and-eval-sexp #'geiser-repl-maybe-send))))
-\f
-;;; C-mode
-(dolist (mode-maps '(("\\.keymap\\'" . c-mode) ("\\.dtsi\\'" . c-mode)))
- (add-to-list 'auto-mode-alist mode-maps t))
-
-(defun re/c-lineup-arglist-tabs-only (ignored)
- "Line up argument lists by tabs, not spaces.
- Stolen from https://kernel.org/doc/html/v4.10/process/coding-style.html"
- (let* ((anchor (c-langelem-pos c-syntactic-element))
- (column (c-langelem-2nd-pos c-syntactic-element))
- (offset (- (1+ column) anchor))
- (steps (floor offset c-basic-offset)))
- (* (max steps 1) c-basic-offset)))
-
-(add-hook 'c-mode-common-hook
- (lambda ()
- (c-add-style "linux-tabs-only"
- '("linux" (c-offsets-alist
- (arglist-cont-nonempty
- c-lineup-gcc-asm-reg
- re/c-lineup-arglist-tabs-only))))))
-
-(add-hook 'c-mode-hook
- (lambda ()
- (setq c-backspace-function 'backward-delete-char)
- (c-set-style "linux-tabs-only")))
-\f
-;; Auto-Revert
-(global-auto-revert-mode t)
-(setq global-auto-revert-non-file-buffers t
- global-auto-revert-ignore-modes '(Buffer-menu-mode))
-\f
-;; Crash handliŋ
-(setq attempt-stack-overflow-recovery nil
- attempt-orderly-shutdown-on-fatal-signal nil)
-\f
-;; Abbrev-mode and Skeletons
-(define-skeleton workorder-link
- "part of a link to a workorder, just enter the number."
- ""
- "https://eservice.r717.net/index.php/PLC_workorders/store/"
- _ -)
-
-(setq abbrev-file-name (expand-file-name "abbrev_defs" user-emacs-directory)
- save-abbrevs 'silently)
-
-(dolist (hook '(org-mode-hook howm-mode-hook))
- (add-hook hook #'abbrev-mode))
-\f
-;; Customization framework
-;; Disable by making a temp file (stolen from prot)
-(setq custom-file (make-temp-file "emacs-custom-"))
+(let ((org-file "~/.emacs.d/README.org")
+ (el-file "~/.emacs.d/config.el"))
+ (when (file-newer-than-file-p org-file el-file)
+ (require 'ob-tangle)
+ (org-babel-tangle-file org-file el-file))
+ (load-file el-file))
;;; init.el ends here