summaryrefslogtreecommitdiff
path: root/.emacs.d
diff options
context:
space:
mode:
Diffstat (limited to '.emacs.d')
-rw-r--r--.emacs.d/eshell/alias4
-rw-r--r--.emacs.d/init.el664
2 files changed, 167 insertions, 501 deletions
diff --git a/.emacs.d/eshell/alias b/.emacs.d/eshell/alias
index 3016144c..29a43d2d 100644
--- a/.emacs.d/eshell/alias
+++ b/.emacs.d/eshell/alias
@@ -1,8 +1,8 @@
alias grep-queued { cd /ssh:ssh.upload.debian.org: && *grep $* /srv/upload.debian.org/queued/run/log }
alias grep-dak { cd /ssh:ftp-master.debian.org: && *grep $* /srv/ftp-master.debian.org/log/current }
alias push-develacc-dotfiles-branch git push -f origin develacc/develacc-"${hostname}":develacc-"${hostname}"
-alias sbuild-prerelease sbuild --dpkg-source-opts='-Zgzip -z1 --format=1.0 -sn' $* --no-run-lintian
-alias sbuild-lts quilt pop -a; git is-clean ':!debian/patches/' && sbuild --no-clean-source --no-run-lintian $*
+alias sbuild-prerelease sbuild --dpkg-source-opts='-Zgzip -z1 --format=1.0 -sn' $*
+alias sbuild-lts quilt pop -a; git is-clean ':!debian/patches/' && sbuild --no-clean-source $*
alias dpkg-bp-lts quilt pop -a; git is-clean && dpkg-buildpackage -S -nc --force-sign $*
alias dpkg-buildpackage-lts dpkg-bp-lts $*
alias d dired $1
diff --git a/.emacs.d/init.el b/.emacs.d/init.el
index 9105beb2..cdf702fa 100644
--- a/.emacs.d/init.el
+++ b/.emacs.d/init.el
@@ -104,18 +104,16 @@
;; The colour is from the Lucid build of Emacs.
'(region ((t (:extend t :background "#EECD82")))))
-;; Set background colour but don't touch text terminals.
-(dolist (ws '(x pgtk w32 ns))
- (add-to-list
- 'window-system-default-frame-alist
- ;; If we were not started with --daemon or by 'emacsclient -a ""', then
- ;; we're probably a shortlived instance of Emacs just to test something.
- ;; Set a different background colour to more easily distinguish frames
- ;; belonging to shortlived instances from those belonging to main instance.
- `(,ws
- . ((background-color
- . ,(pcase (daemonp)
- ('nil "#F0FFF0") ("gdbmacs" "#F5F5DC") (_ "#FFFFF6")))))))
+;; Set background colours for graphical frames; leave TUI frames alone.
+;; If we were not started with --daemon or by 'emacsclient -a ""', then
+;; we're probably a shortlived instance of Emacs just to test something.
+;; Set a different background colour to more easily distinguish frames
+;; belonging to shortlived instances from those belonging to main instance.
+(let ((colour (pcase (daemonp)
+ ('nil "#F0FFF0") ("gdbmacs" "#F5F5DC") (_ "#FFFFF6"))))
+ (dolist (ws '(x pgtk w32 ns))
+ (add-to-list 'window-system-default-frame-alist
+ `(,ws . ((background-color . ,colour))))))
(defun spw/maybe-scale-basic-faces (frame)
"Entry for `window-size-change-functions' to increase font sizes,
@@ -178,11 +176,16 @@ two 80-column windows side-by-side in the frame."
'(Man-notify-method 'aggressive)
'(after-save-hook '(executable-make-buffer-file-executable-if-script-p))
'(async-shell-command-buffer 'rename-buffer)
+
+ ;; Always update buffers when files change on disk -- if we want to go back
+ ;; to the version of the file we had in Emacs, we can just hit C-/.
+ '(auto-revert-use-notify nil)
+ '(global-auto-revert-mode 1)
+
'(auth-source-save-behavior nil)
'(auto-save-file-name-transforms '((".*" "~/.emacs.d/auto-saves/" t)))
'(backup-by-copying-when-linked t)
'(backup-directory-alist '(("." . "~/.emacs.d/backups/")))
- '(c-default-style "linux")
'(calc-kill-line-numbering nil)
'(column-number-mode t)
'(comint-prompt-read-only t)
@@ -214,6 +217,7 @@ two 80-column windows side-by-side in the frame."
'(gdb-show-main t)
'(global-so-long-mode t)
+ '(help-display-function-type nil)
'(help-window-keep-selected t)
'(imenu-auto-rescan t)
'(inferior-lisp-program "sbcl")
@@ -538,7 +542,7 @@ that's something we can determine.")
;; Switch such that right after startup 'q' takes us to *scratch*, as usual.
(switch-to-buffer (remember-notes)))
-(unless (stringp (daemonp))
+(when (eq (daemonp) t)
(add-hook 'after-init-hook #'spw/hijack-scratch)
(advice-add 'get-scratch-buffer-create :override #'remember-notes))
@@ -860,11 +864,6 @@ To be used only when it seems to be necessary."
;; calling emacsclient(1), this is like '<ESC>ZZ' in vi.
(global-set-key "\C-cz" "\C-x\C-s\C-x#")
-;; always update buffers when files change on disk -- if we want to go back to
-;; the version of the file we had in Emacs, we can just hit undo
-(setq auto-revert-use-notify nil)
-(global-auto-revert-mode 1)
-
;; C-x x g should not ask for confirmation.
(global-set-key "\C-xxg" (lambda ()
(interactive)
@@ -912,10 +911,30 @@ To be used only when it seems to be necessary."
(add-hook 'text-mode-hook #'goto-address-mode)
(add-hook 'prog-mode-hook #'goto-address-prog-mode)
+;; message-mode is sensitive to trailing whitespace in sig dashes and empty
+;; headers. markdown-mode is sensitive in empty headers (e.g. "# " which I
+;; use in writing essays) and newlines that indicate paragraph flow (obscure
+;; Markdown feature)
+;;
+;; The message-mode case is handled by `spw/normalise-message', which is
+;; better than setting `ws-butler-trim-predicate' to a complicated function
+;; because the code in `spw/normalise-message' gets called less often. Could
+;; try setting `ws-butler-trim-predicate' to handle the markdown-mode case,
+;; but chances are someday I'll want to use that obscure markdown-mode feature
+(define-globalized-minor-mode spw/ws-butler-global-mode ws-butler-mode
+ (lambda () (when (buffer-file-name) (ws-butler-mode 1)))
+ :predicate '((not markdown-mode
+ message-mode
+ lisp-interaction-mode)
+ prog-mode text-mode))
+(spw/ws-butler-global-mode 1)
+
+(spw/feature-add-hook rainbow-mode (sgml-mode html-mode-hook) css-mode)
+
(global-set-key "\C-cih" #'add-file-local-variable-prop-line)
;; don't do anything with abbrevs if ~/doc is not checked out
-(defvar spw/doc-abbrevs-file (expand-file-name "~/doc/emacs-abbrevs"))
+(defvar spw/doc-abbrevs-file (expand-file-name "~/doc/abbrevs"))
(when (file-exists-p spw/doc-abbrevs-file)
(setq abbrev-file-name spw/doc-abbrevs-file)
(quietly-read-abbrev-file)
@@ -926,7 +945,7 @@ To be used only when it seems to be necessary."
(setf (cadr (assq 'abbrev-mode minor-mode-alist)) nil))
;; similar
-(defvar spw/doc-bookmarks-file (expand-file-name "~/doc/emacs-bookmarks"))
+(defvar spw/doc-bookmarks-file (expand-file-name "~/doc/bookmarks"))
(when (file-exists-p spw/doc-bookmarks-file)
(setq bookmark-default-file spw/doc-bookmarks-file
bookmark-save-flag 1))
@@ -1158,45 +1177,6 @@ To be used only when it seems to be necessary."
;;;; Buffers and windows
-(defvar spw/arrow-keys-mode-map
- (let ((map (make-sparse-keymap)))
- (dolist (key '(up down left right
- S-up S-down S-left S-right
- M-up M-down M-left M-right))
- (define-key map (vector ?\C-z key) #'spw/arrow-keys-mode-passthru))
- map)
- "Keymap for `spw/arrow-keys-mode'.")
-
-(define-minor-mode spw/arrow-keys-mode
- "Apply the bindings in `spw/arrow-keys-mode-map', but
-additionally bind the sequences of C-z followed by each of the
-four arrow keys to activate a transient map in which the four
-arrow keys have the bindings they would have absent this mode.
-
-Permits globally re-binding the four arrow keys without rendering
-it impossible to access mode-specific bindings for those four
-keys (e.g. the use of the left and right arrow keys in
-`fido-mode' minibuffers)."
- ;; :init-value t
- :lighter nil :keymap spw/arrow-keys-mode-map :global t)
-
-(defun spw/arrow-keys-mode-passthru ()
- (interactive)
- ;; Possibly we could cache the map in a buffer-local variable. It'd get
- ;; cleared if the major mode changes, but we'd also need to figure out
- ;; clearing it (but not recomputing it until and unless this function is
- ;; called) if the minor modes change.
- (let ((map (make-sparse-keymap))
- (cell (cl-find 'spw/arrow-keys-mode minor-mode-map-alist :key #'car)))
- (cl-letf (((car cell) nil))
- (dolist (key '([up] [down] [left] [right]
- [S-up] [S-down] [S-left] [S-right]
- [M-up] [M-down] [M-left] [M-right]))
- (define-key map key (key-binding key))))
- (let ((key (vector last-command-event)))
- (call-interactively (lookup-key map key) t key))
- (set-transient-map map t)))
-
(defun spw/get-mru-window (&optional exclude)
"Like `get-mru-window' but also consider the minibuffer, and
don't consider windows satisfying the predicate EXCLUDE."
@@ -1240,8 +1220,8 @@ don't consider windows satisfying the predicate EXCLUDE."
;;; <left>/<right>. We could still put something on unmodified <down>/<up>,
;;; which I used to use for `tab-bar-history-mode' forward & back commands.
;;; (`spw/arrow-keys-mode' made it feasible to bind things to unmodified arrow
-;;; keys in the global map. That's disabled at present, as the unmodified
-;;; arrow keys are not in use.)
+;;; keys in the global map. That's archived to git history at present, as the
+;;; unmodified arrow keys are not in use.)
;;;
;;; We might put one of the other sets of windmove commands, such as
;;; windmove-swap-states-* commands, on C-z M-7/8/9/0, or possibly
@@ -1418,9 +1398,8 @@ state, attempt to produce some useful side window(s)."
(let ((default-directory (expand-file-name "~/")))
(slime))))
(t (error "No side windows state & no heuristic")))))))
-;; Possibly this command should go on M-5 or M-6.
-(global-set-key [remap window-toggle-side-windows]
- #'spw/window-toggle-side-windows)
+(define-key spw/personal-bindings-mode-map "\M-6"
+ #'spw/window-toggle-side-windows)
(defun spw/delete-other-windows--toggle-side-windows
(&optional window &rest _ignore)
@@ -1447,54 +1426,20 @@ the non-side windows deleted by `delete-other-windows' will also reappear."
(define-key ctl-x-5-map "\C-j" "\C-x55\C-x\C-j")
(define-key tab-prefix-map "\C-j" "\C-xtt\C-x\C-j")
-;;; For when the buffer's name isn't much help for switching to it, as is
-;;; often the case with `notmuch-show' buffers. We select the most recent
-;;; buffer but then transient cycling can take us to other buffers of the same
-;;; major mode.
-
-(defun spw/read-major-mode-recent-buffer ()
- (let ((buffers (make-hash-table)))
- (dolist (buffer (buffer-list))
- (with-current-buffer buffer
- (unless (gethash major-mode buffers)
- (puthash major-mode buffer buffers))))
- (list
- (gethash
- (intern
- (completing-read
- "Most recent buffer of major mode: " (hash-table-keys buffers) nil t))
- buffers))))
-
-(spw/transient-cycles-define-buffer-switch
- ((("\C-zb" . spw/switch-to-recent-major-mode-buffer) (buffer)
- (interactive (spw/read-major-mode-recent-buffer))
- (switch-to-buffer buffer t))
-
- (("\C-z4b" . spw/switch-to-recent-major-mode-buffer-other-window) (buffer)
- (interactive (spw/read-major-mode-recent-buffer))
- (switch-to-buffer-other-window buffer t))
-
- (("\C-z5b" . spw/switch-to-recent-major-mode-buffer-other-frame) (buffer)
- (interactive (spw/read-major-mode-recent-buffer))
- (switch-to-buffer-other-frame buffer t))
-
- (("\C-z4\C-o" . spw/display-recent-major-mode-buffer) (buffer)
- (interactive (spw/read-major-mode-recent-buffer))
- (display-buffer buffer))))
+(autoload 'redtick "redtick")
+(global-set-key "\C-cP" #'redtick)
+(autoload 'redtick-mode "redtick")
+(global-set-key "\C-cgP" #'redtick-mode)
;;;; TRAMP
-(with-eval-after-load 'tramp
- (add-to-list 'tramp-connection-properties
- ;; Activate direct-async-process for all non-multihop SSH
- ;; connections.
- '("/ssh:" "direct-async-process" t)
- ;; session-timeout is about dropping a connection for security
- ;; reasons alone: never do that.
- '(nil "session-timeout" nil))
-
- (add-to-list 'tramp-remote-path 'tramp-own-remote-path))
+(spw/feature-add-to-list tramp-connection-properties tramp
+ ;; Activate `direct-async-process' for all non-multihop SSH connections.
+ '("/ssh:" "direct-async-process" t)
+ ;; Don't drop connections for security reasons alone.
+ '(nil "session-timeout" nil))
+(spw/feature-add-to-list tramp-remote-path tramp 'tramp-own-remote-path)
(unless (string-match ; Emacs 28: unquote and `string-search'
(regexp-quote tramp-file-name-regexp) vc-ignore-dir-regexp)
@@ -1554,14 +1499,6 @@ the non-side windows deleted by `delete-other-windows' will also reappear."
;; history of recent dirs is effectively buffer-local.
(setq eshell-last-dir-ring-file-name nil)
-(defun spw/eshell-cd-project-root ()
- (interactive)
- (if-let ((project (project-current)))
- (spw/eshell-cd (project-root project))
- (user-error "No current project")))
-(with-eval-after-load 'esh-mode
- (define-key eshell-mode-map "\C-zp" #'spw/eshell-cd-project-root))
-
(spw/define-skeleton spw/eshell-libexec
(eshell-mode :abbrev "le" :file "esh-mode")
"" "" "~/" '(eshell-electric-forward-slash) "src/dotfiles/scripts/")
@@ -1758,7 +1695,11 @@ Some ideas behind these behaviours are as follows.
(spw/transient-cycles-define-buffer-switch
((("e" . spw/project-eshell) ()
(interactive)
- (spw/eshell-jump 'project 'interactive)))
+ (prog1 (spw/eshell-jump 'project 'interactive)
+ ;; Make it possible to use M-& to repeat C-x p e.
+ (let ((map (make-sparse-keymap)))
+ (define-key map "\M-&" #'transient-cycles-cmd-spw/project-eshell)
+ (set-transient-map map)))))
;; Bind into project-prefix-map, rather than adding a remap, so that we
;; have it under C-x 4 p, C-x 5 p etc. too.
:keymap project-prefix-map)))
@@ -1766,8 +1707,6 @@ Some ideas behind these behaviours are as follows.
;;;; Miscellaneous functions & commands
-;;;; This is meant to be like ~/src/dotfiles/bin & ~/src/dotfiles/scripts, not
-;;;; so much about Emacs startup, except that we do want them always loaded.
;; This is an alternative way to activate the mark temporarily when
;; `transient-mark-mode' is off, and whether it's on or off, makes it
@@ -1811,15 +1750,6 @@ Some ideas behind these behaviours are as follows.
(add-hook 'isearch-mode-end-hook hook nil t)))
(define-key spw/ctl-z-map "\s" #'spw/ensure-whole-lines-mode)
-;; If know the name of group might try `gnus-read-ephemeral-gmane-group' (and
-;; if that works well, might want to make this function prompt for a group to
-;; pass to that function, and if blank, do what function does now).
-(defun spw/browse-gmane ()
- (interactive)
- (gnus-no-server)
- (gnus-group-browse-foreign-server '(nntp "news.gmane.io")))
-(global-set-key "\C-cgG" #'spw/browse-gmane)
-
(defun spw/org-reformat-subtree ()
(interactive)
;; we have to set the mark, rather than just narrowing to the subtree, or
@@ -1896,14 +1826,6 @@ Some ideas behind these behaviours are as follows.
(global-set-key "\C-cD" #'spw/delete-visited-file)
(global-set-key "\C-cvD" #'spw/vc-delete-visited-file)
-(defun spw/link-stat-block (start end)
- (interactive "r")
- (when-let ((region-text (buffer-substring start end)))
- (org-insert-link
- nil
- (concat "file:~/annex/gaming/5eblocks/" region-text ".png")
- region-text)))
-
;; Possibly this should be replaced with something like `project-find-regexp'
;;
;; Input e.g.: lisp "Emacs configuration"
@@ -1917,21 +1839,6 @@ Some ideas behind these behaviours are as follows.
nil (expand-file-name "~/doc")))
(global-set-key "\C-cog" #'spw/git-grep-docs)
-;; this is called by .dir-locals.el in ~/doc/{pres,papers}
-(defun spw/set-pandoc-compile-command (&rest exts)
- (setq-local compile-command
- (concat "make "
- (mapconcat
- (lambda (ext)
- (file-name-nondirectory
- (concat (file-name-sans-extension
- (buffer-file-name))
- "."
- ext)))
- (or exts '("pdf"))
- " ")))
- (local-set-key "\C-z\C-c" #'compile))
-
(defun spw/all-programming-projects ()
(call-process "src-register-all")
(let ((default-directory (expand-file-name "~/src")))
@@ -2007,36 +1914,6 @@ Some ideas behind these behaviours are as follows.
(display-buffer buffer))))
(global-set-key "\C-cvc" #'spw/clone-repo)
-;; author unknown
-(defun spw/toggle-frame-split ()
- "Toggle the orientation of a two-window split.
-
-Useful after resizing the frame."
- (interactive)
- (when (= (count-windows) 2)
- (let* ((this-win-buffer (window-buffer))
- (next-win-buffer (window-buffer (next-window)))
- (this-win-edges (window-edges (selected-window)))
- (next-win-edges (window-edges (next-window)))
- (this-win-2nd (not (and (<= (car this-win-edges)
- (car next-win-edges))
- (<= (cadr this-win-edges)
- (cadr next-win-edges)))))
- (splitter
- (if (= (car this-win-edges)
- (car (window-edges (next-window))))
- 'split-window-horizontally
- 'split-window-vertically)))
- (delete-other-windows)
- (let ((first-win (selected-window)))
- (funcall splitter)
- (when this-win-2nd (other-window 1))
- (set-window-buffer (selected-window) this-win-buffer)
- (set-window-buffer (next-window) next-win-buffer)
- (select-window first-win)
- (when this-win-2nd (other-window 1))))))
-(define-key spw/personal-bindings-mode-map "\M-5" #'spw/toggle-frame-split)
-
(defun spw/maybe-toggle-split-after-resize (frame)
(when (and (framep frame)
(frame-size-changed-p frame)
@@ -2124,78 +2001,6 @@ Useful after resizing the frame."
(interactive)
(spw/myrepos-global-action "sync")))
-;; There are many variations on this online. This one by Robert Bost, based
-;; on work by Steve Yegge, Colin Doering and others
-(defun spw/rotate-windows (arg)
- "Rotate your windows, reversing direction if ARG."
- (interactive "P")
- (if (not (> (count-windows) 1))
- (message "You can't rotate a single window!")
- (let* ((rotate-times (prefix-numeric-value arg))
- (direction (if (or (< rotate-times 0) (equal arg '(4)))
- 'reverse 'identity)))
- (dotimes (_ (abs rotate-times))
- (dotimes (i (- (count-windows) 1))
- (let* ((w1 (elt (funcall direction (window-list)) i))
- (w2 (elt (funcall direction (window-list)) (+ i 1)))
- (b1 (window-buffer w1))
- (b2 (window-buffer w2))
- (s1 (window-start w1))
- (s2 (window-start w2))
- (p1 (window-point w1))
- (p2 (window-point w2)))
- (set-window-buffer-start-and-point w1 b2 s2 p2)
- (set-window-buffer-start-and-point w2 b1 s1 p1)))))))
-;; This gets this key because we're likely to want to invoke it repeatedly.
-(define-key spw/personal-bindings-mode-map "\M-6" #'spw/rotate-windows)
-
-;; some influence here from Michael Stapelberg's config -- we both had a
-;; function to do this, I discovered
-(defun spw/recipient-first-name ()
- "Attempt to extract the first name of the recipient of a `message-mode' message.
-
-Used in my `message-mode' yasnippets."
- (if-let ((to (save-excursion
- (save-restriction
- (message-narrow-to-headers-or-head)
- (message-fetch-field "To")))))
- (let ((full-name (car (mail-extract-address-components to))))
- (if (string-match "\\([^ ]+\\)" full-name)
- (let ((first-name (match-string 0 full-name)))
- (cond
- ;; some names which may be in a longer form in the From header
- ;; but which I would never type out in full in a salutation
- ((string= first-name "Nathaniel") "Nathan")
- ((string= first-name "Thomas") "Tom")
- (t first-name)))
- ;; no spaces -- assume whole thing is an alias and use it
- full-name))
- ""))
-
-(spw/define-skeleton spw/message-dear
- (message-mode :abbrev "dear" :file "message")
- ""
- (completing-read "Dear " (ignore-errors (list (spw/recipient-first-name))))
- '(when (setq v1 (looking-at ">")) (forward-line -2))
- "Dear " str "," \n \n
- '(when v1 (forward-line 2)))
-
-(spw/define-skeleton spw/message-hello
- (message-mode :abbrev "hl" :file "message")
- ""
- (completing-read "Hello " (ignore-errors (list (spw/recipient-first-name))))
- '(when (setq v1 (looking-at ">")) (forward-line -2))
- "Hello " str '(when (zerop (length str)) (delete-backward-char 1)) "," \n \n
- '(when v1 (forward-line 2)))
-
-(spw/define-skeleton spw/message-thanks
- (message-mode :abbrev "ty" :file "message")
- ""
- (completing-read "Dear " (ignore-errors (list (spw/recipient-first-name))))
- '(when (setq v1 (looking-at ">")) (forward-line -2))
- "Dear " str "," \n \n "Thank you for your e-mail." \n \n
- '(when v1 (forward-line 2)))
-
(defun spw/copy-to-annotated ()
(interactive)
(let* ((source (expand-file-name (dired-file-name-at-point)))
@@ -2445,56 +2250,6 @@ Called by '~/src/dotfiles/bin/emacsclient --spw/update-environment'."
(not (string= (daemonp) "gdbmacs"))
(eq (server-running-p "gdbmacs") t)))
-;; open a frame on a new workspace with only the relevant dired buffer open,
-;; eval this form: (global-set-key "\C-cG" #'spw/grading-advance)
-;; and then use C-c G to open the first item (will need C-c f t after just
-;; this first one, and also maybe C-i =)
-(defun spw/grading-advance ()
- (interactive)
- (unless (eq major-mode 'dired-mode)
- (when (eq major-mode 'org-mode)
- (ignore-errors (org-ctrl-c-ctrl-c)))
- (save-buffer)
- (other-window 1))
- (dired-display-file)
- (dired-next-line 1)
- (let ((pdf (dired-get-filename)))
- (dired-next-line 1)
- (other-window 1)
- (goto-char (point-min))
-
- ;; assignment-specific
- (search-forward "Grammar")
- (org-cycle)
- (set-goal-column nil)
- ;; (overwrite-mode 1)
-
- (start-process "pdf" "pdf" "xdg-open" pdf)
- (sleep-for 1)
- (call-process-shell-command
- (concat (if (executable-find "i3-msg") "i3-msg" "swaymsg")
- " move right"))
- (let ((pdf-words (substring (with-temp-buffer
- (call-process-shell-command
- (concat "pdftotext "
- (shell-quote-argument pdf)
- " - | wc -w")
- nil
- (current-buffer))
- (buffer-string))
- 0
- -1)))
- (message (concat pdf-words " words")))))
-
-(defun spw/untabify-project ()
- (interactive)
- (save-window-excursion
- (dolist (file (project-files
- (project-current nil (project-prompt-project-dir))))
-
- (find-file file)
- (untabify (point-min) (point-max)))))
-
(defun spw/go-to-consfig ()
(interactive)
;; (let ((repo (expand-file-name "~/src/cl/consfig")))
@@ -2580,32 +2335,6 @@ Called by '~/src/dotfiles/bin/emacsclient --spw/update-environment'."
(string-join (cons "rm -f config.cache; ./configure -C" (cdr conf)) " ")
nil :system t)))
-(defun spw/read-athenet-lxc ()
- (let (lxcs
- (file (expand-file-name "~/src/cl/consfig/hosts.lisp")))
- (unless (file-exists-p file)
- (user-error "Looks like consfig not checked out"))
- (with-current-buffer (find-file-noselect file)
- (save-excursion
- (save-restriction
- (widen)
- (goto-char (point-min))
- (while (re-search-forward
- "(define-athenet-container \\([a-z0-9-.]+\\)
-\\s-*\"\\([a-z0-9-.]+\\)"
- nil t)
- (push (list (substring-no-properties (match-string 1))
- (substring-no-properties (match-string 2)))
- lxcs)))))
- (assoc (completing-read "LXC: " lxcs nil t) lxcs #'string=)))
-
-(defun spw/ssh-and-lxc-attach-term (container host)
- (interactive (spw/read-athenet-lxc))
- (start-process "ssh-and-tmux" nil "foot" "ssh-and-tmux" host
- (format "--container-name=%s" container)
-"--container-cmd=lxc-unpriv-attach -n %s --keep-var TERM --clear-env -vHOME=/root"))
-(global-set-key "\C-cgL" #'spw/ssh-and-lxc-attach-term)
-
(defun spw/proced-root ()
(interactive)
(require 'proced)
@@ -2699,7 +2428,7 @@ Called by '~/src/dotfiles/bin/emacsclient --spw/update-environment'."
(interactive)
(let ((string (ignore-errors (cdr (bounds-of-thing-at-point 'string)))))
(fill-region-as-paragraph
- (car (bounds-of-thing-at-point 'sentence))
+ (point)
(cond (string (min string (cdr (bounds-of-thing-at-point 'paragraph))))
((cl-fifth (syntax-ppss))
(min (cdr (bounds-of-thing-at-point 'paragraph))
@@ -2722,6 +2451,25 @@ Called by '~/src/dotfiles/bin/emacsclient --spw/update-environment'."
(global-set-key "\C-ce" #'spw/fill-rest-of-paragraph)
(global-set-key "\C-cj" "\M-j\C-ce")
+(defun spw/backward-upcase-sexp (arg &optional interactive)
+ (interactive "p\nd")
+ (upcase-region (save-excursion (backward-sexp arg interactive)
+ (point))
+ (point)))
+(define-key spw/ctl-z-map "\C-u" #'spw/backward-upcase-sexp)
+
+(defun spw/qrencode-region (beg end)
+ (interactive "r")
+ (let ((buf (get-buffer-create "*qrencode*")))
+ (with-current-buffer buf
+ (let ((inhibit-read-only t))
+ (erase-buffer)))
+ (call-process-region beg end "qrencode" nil buf nil "-s10" "-o-")
+ (with-current-buffer buf
+ (image-mode))
+ (display-buffer buf)))
+
+;;;; "Miscellaneous functions & commands" page ends here
;;;; Terminal emulation
@@ -2975,6 +2723,9 @@ mutt's review view, after exiting EDITOR."
(require 'notmuch-address) (notmuch-address-setup))
(add-hook 'message-mode-hook #'footnote-mode)
+ (spw/when-library-available orgalist
+ (add-hook 'message-mode-hook #'orgalist-mode))
+ (add-hook 'message-mode-hook #'orgtbl-mode)
(define-key message-mode-map
[remap message-newline-and-reformat] #'spw/message-newline-and-reformat)
@@ -2992,7 +2743,6 @@ mutt's review view, after exiting EDITOR."
'(dired-clean-up-buffers-too nil)
'(dired-dwim-target t)
'(dired-free-space 'separate)
- '(dired-isearch-filenames t)
'(dired-listing-switches "--group-directories-first -alh")
'(dired-omit-files "\\`[.]?#\\|\\`[.][.]?\\'\\|\\`\\.git\\'")
'(dired-recursive-copies 'always))
@@ -3073,7 +2823,7 @@ mutt's review view, after exiting EDITOR."
"&" #'spw/dired-copy-filename-as-kill)
-;;;; EWW
+;;;; EWW / shr
;; this should ensure that M-a and M-e work for most webpages
(add-hook 'eww-mode-hook (lambda ()
@@ -3103,6 +2853,10 @@ mutt's review view, after exiting EDITOR."
(setq-local bookmark-make-record-function
#'spw/bookmark-eww-bookmark-make-record)))
+(customize-set-variable 'nov-text-width 78)
+(spw/when-library-available nov
+ (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)))
+
;;;; Gnus
@@ -3864,7 +3618,8 @@ unread."
;; `gnus-summary-save-parts' has some alternative ways to get the handles
;; if `gnus-article-mime-handles' is nil.
(let ((handles gnus-article-mime-handles))
- (when (stringp (car handles)) (pop handles))
+ (when (stringp (car handles))
+ (setq handles (cdr handles)))
(mapc #'mm-save-part (cl-remove-if-not #'mm-handle-filename handles)))))
(with-eval-after-load 'gnus-sum
@@ -4002,12 +3757,17 @@ unread."
;; We might also consider -B.
'(vc-git-diff-switches '("--patch-with-stat" "-M" "-C"))
- '(vc-git-print-log-follow t))
+ ;; Drop the name & date to make more of the commit message visible.
+ '(vc-git-root-log-format
+ '("%d%h..: %s"
+ "^\\(?:[*/\\| ]+ \\)?\\(?2: ([^)]+)\\)?\\(?1:[0-9a-z]+\\)\\.\\.: "
+ ((1 'log-view-message) (2 'change-log-list nil lax)))))
;; Avoid `log-edit-show-files' window becoming most recently used for C-x o.
(with-eval-after-load 'log-edit
(customize-set-variable 'log-edit-hook
- (delete 'log-edit-show-files log-edit-hook)))
+ (cons 'spw/log-edit-show-diff
+ (delete 'log-edit-show-files log-edit-hook))))
(require 'git-commit nil t)
@@ -4274,71 +4034,7 @@ unread."
(global-set-key "\C-cvf" 'spw/vc-next-action-for-git-fixup)
-;;;; Assorted packages
-
-;; message-mode is sensitive to trailing whitespace in sig dashes and empty
-;; headers. markdown-mode is sensitive in empty headers (e.g. "# " which I
-;; use in writing essays) and newlines that indicate paragraph flow (obscure
-;; Markdown feature)
-;;
-;; The message-mode case is handled by `spw/normalise-message', which is
-;; better than setting `ws-butler-trim-predicate' to a complicated function
-;; because the code in `spw/normalise-message' gets called less often. Could
-;; try setting `ws-butler-trim-predicate' to handle the markdown-mode case,
-;; but chances are someday I'll want to use that obscure markdown-mode feature
-(define-globalized-minor-mode spw/ws-butler-global-mode ws-butler-mode
- (lambda () (when (buffer-file-name) (ws-butler-mode 1)))
- :predicate '((not markdown-mode
- message-mode
- lisp-interaction-mode)
- prog-mode text-mode))
-(spw/ws-butler-global-mode 1)
-
-(autoload 'redtick "redtick")
-(global-set-key "\C-cP" #'redtick)
-(autoload 'redtick-mode "redtick")
-(global-set-key "\C-cgP" #'redtick-mode)
-
-(with-eval-after-load 'org-d20
- (setq org-d20-dice-sound
- "~/annex/media/sounds/147531__ziembee__diceland.wav"
- org-d20-display-rolls-buffer t
- ;; the roll20 tokens I'm using for NPCs are lettered
- org-d20-letter-monsters t
- ;; ... and they come in only two colours, so let's just have
- ;; one monster per letter
- org-d20-continue-monster-numbering t)
-
- (define-key org-d20-mode-map [f5] #'org-d20-initiative-dwim)
- (define-key org-d20-mode-map [f6] #'org-d20-damage)
-
- (define-key org-d20-mode-map [f7] (lambda (arg)
- (interactive "P")
- (call-interactively
- (if arg
- #'org-d20-roll-last
- #'org-d20-roll))))
- (define-key org-d20-mode-map [f8] #'org-d20-roll-at-point)
- (define-key org-d20-mode-map [f9] (lambda (arg)
- (interactive "P")
- (call-interactively
- (if arg
- #'org-d20-d%
- #'org-d20-d20)))))
-
-(customize-set-variable 'nov-text-width 78)
-(spw/when-library-available nov
- (add-to-list 'auto-mode-alist '("\\.epub\\'" . nov-mode)))
-
-(setq ggtags-mode-line-project-name nil)
-
-(spw/when-library-available ggtags
- (dolist (hook '(cperl-mode-hook c-mode-hook))
- (add-hook hook #'ggtags-mode)))
-
-(spw/when-library-available rainbow-mode
- (dolist (hook '(html-mode-hook css-mode-hook))
- (add-hook hook 'rainbow-mode)))
+;;;; Haskell
(custom-theme-set-variables
'user
@@ -4360,10 +4056,8 @@ unread."
nil t))
haskell-mode))
-(spw/when-library-available orgalist
- (spw/feature-add-hook orgalist-mode message))
-
-(spw/feature-add-hook orgtbl-mode message)
+
+;;;; Bongo
(custom-theme-set-variables
'user
@@ -4407,14 +4101,6 @@ unread."
;; 'v' again to exit
(global-set-key "\C-cgv" #'volume)
-(with-eval-after-load 'elpher
- ;; standard Emacs conventions
- (define-key elpher-mode-map "l" #'elpher-back)
- (define-key elpher-mode-map "d" #'elpher-back-to-start)
- (define-key elpher-mode-map "<" #'elpher-root-dir)
-
- (add-hook 'elpher-mode-hook (lambda () (variable-pitch-mode 1))))
-
;;;; Lisp
@@ -4547,22 +4233,6 @@ that the user is expecting that it might pop up."
(defslime-repl-shortcut nil ("clear-source-registry")
(:handler #'spw/slime-clear-source-registry)))
-(defun spw/comment-form (n)
- "Replacement for \\[comment-line] in Lisp modes which is more
-likely to keep parentheses balanced."
- (interactive "p")
- (if (use-region-p)
- (comment-line n)
- (let ((begin (point))
- (end (line-end-position)))
- (skip-chars-forward "; \t" end)
- (forward-sexp)
- (unless (> (point) (line-end-position))
- (comment-or-uncomment-region begin (point))))))
-(define-key lisp-mode-shared-map [?\C-x ?\C-\;] #'spw/comment-form)
-(when (boundp 'lisp-data-mode-map) ; Emacs 27
- (define-key lisp-data-mode-map [?\C-x ?\C-\;] #'spw/comment-form))
-
;; Loading `slime' puts `slime-macrostep' on `load-path'.
;; `slime-macrostep' knows how to load an embedded copy of `macrostep'.
(with-eval-after-load 'slime (require 'slime-macrostep))
@@ -4809,7 +4479,7 @@ before uploading to NEW again." \n \n
'(org-adapt-indentation t nil)
'(org-agenda-entry-text-maxlines 3)
- '(org-agenda-files "~/doc/emacs-org-agenda-files")
+ '(org-agenda-files "~/doc/org-agenda-files")
'(org-agenda-persistent-filter t)
'(org-agenda-remove-times-when-in-prefix 'beg)
@@ -4942,17 +4612,17 @@ before uploading to NEW again." \n \n
("m" ((in-mode . "gnus-summary-mode"))))
org-capture-templates
'(("t" "Task to be refiled" entry (file org-default-notes-file)
- "* TODO %^{Title}\n%?")
+ "* TODO %^{Title}\n%?"
+ :empty-lines 1)
("T" "Task to be refiled" entry (file org-default-notes-file)
- "* TODO %^{Title}\n%?")
+ "* TODO %^{Title}\n%?"
+ :empty-lines 1)
("n" "Information to be refiled" entry (file org-default-notes-file)
- "* %^{Title}\n%?")
+ "* %^{Title}\n%?"
+ :empty-lines 1)
("m" "Task from mail to be refiled" entry (file org-default-notes-file)
- ;; Lisp is to filter square brackets out of the subject as these mean that
- ;; the Org-mode link does not properly form. In Org 9.3, the escaping
- ;; syntax for links has changed, so might be able to do something smarter
- ;; than this
- "* TODO [[gnus:%:group#%:message-id][%^{Title|\"%(replace-regexp-in-string \"\\\\\\[\\\\\\|\\\\\\]\" \"\" \"%:subject\")\" from %:fromname}]]\n%?")
+ "* TODO [[gnus:%:group#%:message-id][%^{Title|%:fromname ⁘ %:subject}]]\n%?"
+ :empty-lines 1)
;; ("a" "Appointment" entry (file+datetree "~/doc/howm/diary.org")
;; "* %^{Time} %^{Title & location}
@@ -4962,11 +4632,13 @@ before uploading to NEW again." \n \n
;; %^t" :immediate-finish t)
("s" "Task for the future to be refiled" entry (file org-default-notes-file)
- "* SOMEDAY %^{Title}\n%?")
- ("d" "Diary entry" entry (file+datetree "~/.labbook.gpg")
- "* %^{Title}\n%U\n\n%?")
+ "* SOMEDAY %^{Title}\n%?"
+ :empty-lines 1)
+ ("d" "Diary entry" entry (file+olp+datetree "~/.labbook.gpg") "* %U\n\n%?"
+ :jump-to-captured t :empty-lines 1 :tree-type month)
("u" "URI on clipboard" entry (file org-default-notes-file)
- "* SOMEDAY [[%^{URI|%x}][%^{Title}]]" :immediate-finish t)))
+ "* SOMEDAY [[%^{URI|%x}][%^{Title}]]"
+ :immediate-finish t :empty-lines 1)))
;; `org-forward-paragraph', `org-backward-paragraph' and `org-mark-element' do
;; not leave point where someone who uses `forward-paragraph',
@@ -5099,6 +4771,29 @@ Called by doccheckin script."
(org-odt-convert org-input "docx")))
(advice-add 'org-odt-export-to-odt :after #'spw/org-odt-export-docx)
+(custom-theme-set-variables
+ 'user
+ '(org-d20-dice-sound "~/annex/media/sounds/147531__ziembee__diceland.wav")
+ '(org-d20-display-rolls-buffer t)
+ ;; The Roll20 tokens I'm using for NPCs are lettered, and they come in only
+ ;; two colours, so one monster per letter.
+ '(org-d20-letter-monsters t)
+ '(org-d20-continue-monster-numbering t))
+(spw/feature-define-keys org-d20
+ [f5] org-d20-initiative-dwim
+ [f6] org-d20-damage
+ [f7] (lambda (arg)
+ (interactive "P")
+ (call-interactively (if arg
+ #'org-d20-roll-last
+ #'org-d20-roll)))
+ [f8] org-d20-roll-at-point
+ [f9] (lambda (arg)
+ (interactive "P")
+ (call-interactively (if arg
+ #'org-d20-d%
+ #'org-d20-d20))))
+
;;;; Org-mode agenda
@@ -5438,7 +5133,7 @@ different occasions."
(string-to-number day) dayname)))
'(calendar-date-style 'iso)
'(calendar-week-start-day 1)
- '(diary-file "~/doc/emacs-diary")
+ '(diary-file "~/doc/diary")
'(diary-list-entries-hook
'(diary-include-other-diary-files diary-sort-entries))
'(diary-mark-entries-hook '(diary-mark-included-diary-files))
@@ -5450,13 +5145,13 @@ different occasions."
;; bindings, and for editing purposes just C-x b suffices.
(global-set-key "\C-cC" #'calendar)
-(when (file-readable-p "~/doc/emacs-diary")
+(when (file-readable-p "~/doc/diary")
(require 'org-agenda) ; for `org-class'
(unless
(bound-and-true-p appt-timer) ; avoid msgs when `eval-buffer' init.el
(appt-activate 1))
(add-to-list 'auto-mode-alist
- `(,(format "\\`%s\\'" (expand-file-name "~/doc/emacs-diary"))
+ `(,(format "\\`%s\\'" (expand-file-name "~/doc/diary"))
. diary-mode)))
(defun spw/diary-archive-entry (year)
@@ -5467,7 +5162,7 @@ different occasions."
(let ((start (point)))
(forward-line 1)
(while (looking-at "[[:blank:]]+") (forward-line 1))
- (append-to-file start (point) (format "~/doc/archive/emacs-diary-%d" year))
+ (append-to-file start (point) (format "~/doc/archive/diary-%d" year))
(delete-region start (point))
(when (and (bolp) (eolp)) (delete-blank-lines))))
(with-eval-after-load 'diary-lib
@@ -5615,32 +5310,26 @@ We don't use the FILES parameter in the entry for \"d\" in
(when (file-directory-p "~/doc/howm/") (require 'howm nil t))
-;;;; C and friends
-
-;; following setting also part of Linux kernel style, but it's from
-;; newcomment.el, not cc-mode, so must be set in addition to
-;; `c-default-style' -- and it's my preference in general
-(setq comment-style 'extra-line)
+;;;; CC mode
-(with-eval-after-load 'cc-mode
- ;; Use the mode-specific paren binding. Default M-( binding will insert
- ;; spaces before the paren which is not called for by all C styles
- (define-key c-mode-base-map "\M-(" #'c-electric-paren)
-
- ;; I've seen this interact badly with electric-indent-mode (which is now on
- ;; globally by default, and has been on locally in c-mode for longer I
- ;; believe) outside of comments, but I cannot currently reproduce the
- ;; problem. Can always just use C-M-j and M-q within comments
- (define-key c-mode-base-map (kbd "RET") #'c-context-line-break)
+(custom-theme-set-variables
+ 'user
+ '(c-default-style "linux")
+ '(comment-style 'extra-line))
- ;; would be nice to have a global version of this
- (define-key c-mode-base-map "\C-o" #'c-context-open-line))
+(spw/feature-define-keys ((cc-mode c-mode-base-map))
+ " " c-context-line-break
+ "\C-o" c-context-open-line)
-;; M-; is adequate for GNU-style comments. This is for other styles.
+;; M-; is enough for GNU-style comments. This is for other styles.
(spw/define-skeleton spw/cc-com (c-mode :abbrev "comm" :file 'cc-mode)
"" nil "/*" \n
" * " '(c-indent-line-or-region) - \n "*/" '(c-indent-line-or-region))
+(setq ggtags-mode-line-project-name nil)
+(spw/when-library-available ggtags
+ (spw/feature-add-hook ggtags-mode (cc-mode c-mode-hook) cperl-mode))
+
;;;; Perl
@@ -5656,30 +5345,17 @@ We don't use the FILES parameter in the entry for \"d\" in
'(cperl-lineup-step 1))
-(defun spw/perl-add-use (module)
- (interactive "suse ")
- (let ((line (concat "use " module
- (and (not (string-match ";$" module)) ";"))))
- (save-excursion
- (goto-char (point-min))
- (while (re-search-forward "^use " nil t))
- (forward-line 1)
- (open-line 1)
- (insert line)
- (message (concat "Inserted: " line)))))
-
(defun spw/perltidy-region (begin end)
(interactive "r")
- (let ((perltidy-env (getenv "PERLTIDY")))
- (setenv "PERLTIDY"
- (or (concat (expand-file-name
- (locate-dominating-file
- (buffer-file-name)
- ".perltidyrc")) ".perltidyrc")
- perltidy-env))
- (shell-command-on-region begin end "perltidy -q" nil t)
- (font-lock-ensure)
- (setenv "PERLTIDY" perltidy-env)))
+ (let* ((dominating (locate-dominating-file default-directory ".perltidyrc"))
+ (process-environment
+ (if dominating
+ (cons (format "PERLTIDY=%s"
+ (expand-file-name ".perltidyrc" dominating))
+ process-environment)
+ process-environment)))
+ (shell-command-on-region begin end "perltidy -q" nil t))
+ (font-lock-ensure))
;; an older version of this would use the region if it's active, but that
;; rarely produces good results -- perltidy would get the indentation wrong
@@ -5712,11 +5388,9 @@ We don't use the FILES parameter in the entry for \"d\" in
(forward-sexp)
(forward-line)
(spw/perltidy-region begin (point))))))))
+(spw/feature-define-keys cperl-mode "\C-z\C-c" spw/perltidy-block-or-buffer)
-(spw/feature-define-keys cperl-mode
- "\C-ciu" spw/perl-add-use "\C-z\C-c" spw/perltidy-block-or-buffer)
-
-;; TODO Take "head" as input too so that we can do =method and =func too.
+;; Might adapt this so that it can do =func and =method too.
(spw/define-skeleton spw/cperl-headsub (cperl-mode :abbrev "headsub")
""
"Name and arguments: "
@@ -5727,14 +5401,6 @@ We don't use the FILES parameter in the entry for \"d\" in
> _ \n
"}")
-(spw/define-skeleton spw/cperl-trytiny (cperl-mode :abbrev "try")
- ""
- nil
- "#<<<" \n
- "try {" \n _ ?\n
- "} catch {" '(cperl-indent-line) \n _ \n "};" '(cperl-indent-line)
- \n "#>>>")
-
;; This is for turning one-liners into small scripts.
(spw/define-skeleton spw/cperl-shebang (cperl-mode :abbrev "shebang")
"" (read-string "Command line options: " "-w") ; e.g. -wln