;; Initialization of my Emacs sessions, part two │ -*- lexical-binding: t; no-byte-compile: t; -*- ;; ;; This file is loaded by part one of the initialization, q.v. at `http://reluk.ca/.config/emacs/init.el`. ;; ;; PUBLIC at `http://reluk.ca/.config/emacs/` because public files refer to it there, including: ;; http://reluk.ca/project/Breccia/Emacs/brec-mode.el ;; http://reluk.ca/project/Java/Emacs/jmt-mode.el ;; http://reluk.ca/project/wayic/Waybrec/Emacs/waybrec-mode.el (eval-when-compile (require 'cl-lib)); For macro `cl-assert`. (defun init/part-two () "Finish the initialization." ;; Package management ;; ────────────────── (require 'package); If only for sake of `package-generate-autoloads` in `~/.config/emacs/init.el`. (defvar package-archives); [FV] (add-to-list 'package-archives '("melpa" . "https://melpa.org/packages/") t) ;;; https://melpa.org/ ;;; https://github.com/melpa/melpa ;;; https://github.com/melpa/melpa/blob/master/CONTRIBUTING.org ;; (package-initialize); Early that I might override packages’ initial settings ;; ;;; with my own in the code below, rather than have mine overridden by theirs. ;;;;; But it delays start up. Disabled pending need. ;; To uninstall packages: https://www.gnu.org/software/emacs/manual/html_node/emacs/Package-Menu.html ;; ;; • Run command `list-packages` ;; • Press `/s` to filter by status, for which give `installed` ;; • Press `d` to mark a package for deletion ;; • Press `x` to execute all marks ;; • Run command `package-autoremove`, as prompted ;; ;; Custom variable `package-selected-packages` may still list the uninstalled packages. Not sure why. ;; The last time this occured (2023-2), I cleared the list using command `customize-variable`. ;; ───── (init/general) (when (string= window-system "x") (init/x) (init/fonts)) ; Under X alone, else “error: Fontset `fontset-standard' does not exist”. (init/keys) (init/modes)) ;; ══════════════════════════════════════════════════════════════════════════════════════════════════════ ;; D e c l a r a t i o n s i n l e x i c o g r a p h i c o r d e r ;; ══════════════════════════════════════════════════════════════════════════════════════════════════════ (defconst init/autoload_docstring "[Description not available until function definition is loaded.]" "\ A placeholder description for ‘autoload’ functions.") ;;; After the pattern of the placeholder Emacs itself generates for the `arglist`. (defun init/breccia-automatically (); Mimicing what a package-manager installation would do. (load "brec-mode-autoloads" nil t); Q.v. at `http://reluk.ca/sys/computer/workstation/etc/emacs/`. (init/breccia)) (defun init/breccia-manually (); As instructed at `http://reluk.ca/project/Breccia/Emacs/brec-mode.el`. (autoload 'brec-mode "brec-mode" nil t) (set 'auto-mode-alist (cons (cons "\\.brec\\'" 'brec-mode) auto-mode-alist)) (register-definition-prefixes "brec-mode" '("brec-")) (init/breccia)) (defun init/breccia () "Configure Brec Mode and other Breccian particulars." (add-hook 'brec-mode-hook (lambda () ;; Key bindings for convenience ;; ──────────── (let ((m (make-sparse-keymap))); In order to customize them for the present buffer (below), ;;; make the key bindings of `isearch-mode-map` effectively buffer-local: (set-keymap-parent m isearch-mode-map) (setq-local isearch-mode-map m)) (local-set-key [f11] [insert ?\\ insert left down]); To overwrite a comment-block delimiter ‘\’, ;;; then move point directly beneath it. (was `toggle-frame-fullscreen`) (local-set-key [?\C-c ?`]; To wrap a template pattern-matcher around the region if present, else around point. (lambda () (interactive) (if (use-region-p) (let ((start (region-beginning))) (goto-char (region-end)) (insert "$`i") (goto-char start) (insert "`^^")) (insert "`^^${same}$`i") (backward-char 10)))) (local-set-key [?\C-c ?b] (lambda () (interactive) (init/delimit-by-chars brec-math-block-delimiter-char))) (local-set-key [?\C-c ?i] (lambda () (interactive) (init/delimit-by-chars brec-math-inline-delimiter-char))) (let ((sm isearch-mode-map)) (local-set-key [?\M-m ?b] (lambda () (interactive) (insert-char brec-math-block-delimiter-char))) (define-key sm [?\M-m ?b] (lambda () (interactive) (isearch-yank-string (char-to-string brec-math-block-delimiter-char)))) (local-set-key [?\M-m ?i] (lambda () (interactive) (insert-char brec-math-inline-delimiter-char))) (define-key sm [?\M-m ?i] (lambda () (interactive) (isearch-yank-string (char-to-string brec-math-inline-delimiter-char))))))) ;; Math Preview integration ;; ──────────────────────── (add-hook 'brec-original-math-functions (lambda (beg -end -exp-beg -exp-end) (save-excursion (goto-char beg) (math-preview-at-point))))) (defun init/buffer-names-sorted (&optional to-include-specials) "Give a list of buffer names in lexicographic order. Exclude buffers with names starting or ending ‘*’ if TO-INCLUDE-SPECIALS is nil." (let (names) (dolist (buffer (buffer-list)) (let ((name (buffer-name buffer))) (unless (and (not to-include-specials) (or (string-prefix-p "*" name) (string-suffix-p "*" name))) (setq names (cons name names))))) (sort names 'init/string-lessp-i))) (defun init/conf-mode () "Configure `conf-mode`." (defvar conf-mode-map); [FV] (add-hook 'conf-mode-hook (lambda () ;; Defeat of unwanted key bindings that would override my `init/keys` ;; ─────────────────────────────── ;; TODO more reliably: https://emacs.stackexchange.com/questions/352/how-to-override-major-mode-bindings (local-set-key [?\C-c ?8] #'init/delimit-asterisk-quotes) (local-set-key [?\C-c ?\"] #'init/delimit-double-quotes) (local-set-key [?\C-c ?'] #'init/delimit-single-quotes)))) (defun init/cperl-mode_hook (); Underived major mode, *-mode-map are defined only in here. (defvar cperl-mode-map); [FV] (define-key cperl-mode-map [?\C-c ?p] #'init/pl-println) (define-key cperl-mode-map [f11] #'init/pl-comment-down) ;; Undo stuff in `cperl-mode.el`. (define-key cperl-mode-map [?{] #'self-insert-command); Was `cperl-electric-lbrace`. (define-key cperl-mode-map [?}] #'self-insert-command); Was `cperl-electric-brace`. (define-key cperl-mode-map [tab] #'tab-to-tab-stop) ;;; Was `cperl-indent-command`, which still is bound to `C-i`. (font-lock-add-keywords nil '( ;; Subdue punctuation ("[,;:]" . font-lock-comment-face) ("['\"]" 0 font-lock-comment-face t) ;;;("[{}$@%*]" . 'init/subdued) ;;;;;; But $@ (and presumeably %*) somehow defeat fontification of variable names ("[{}]" . 'init/subdued))) (setq indent-line-function #'init/indent-relative-plain)) (defun init/css-mode () "Configure CSS mode." (defvar css-fontify-colors); [FV] (defvar css-mode-map) (add-hook 'css-mode-hook (lambda () (let ((m css-mode-map)) (define-key m [tab] #'tab-to-tab-stop)) ;;; Was `indent-for-tab-command`, which still is bound to `C-i`. (setq indent-line-function #'init/indent-relative-plain css-fontify-colors nil); Fontification of colour literals. (font-lock-add-keywords nil '( ;; Defeat of unwanted facing ;; ───────────────────────── ("^\\([[:alpha:]_*.[].*?\\)\\(?:/\\*.*\\)?$"; Buggy, inconsistent selector facing. ;; ────────S───────── ───C── ;; S selector commencing with character [:alpha:]_ OR * OR . OR [ ;; C trailing comment 1 'default t) ; ("color: *\\(hsla?(.*)\\)" 1 'default t); Colour literal ;;; It seems undefeatable. https://emacs.stackexchange.com/questions/46629 ;; Namespace prefix ;; ──────────────── ("\\(\\*\\|[[:alpha:]_][[:alnum:]_]*\\)?\\(|\\)[[:alpha:]_*]" (1 'init/subdued t t) (2 font-lock-comment-face t)) ;; Punctuation ;; ─────────── ("[;:]" . font-lock-comment-face) ("['\"]" 0 font-lock-comment-face t) ("[{},]" . 'init/subdued))))) (autoload 'css-mode "css-mode" init/autoload_docstring t)) (defun init/delimit-asterisk-quotes () ;; FIX so callers instead use `init/delimit-by-chars`, or the like. (interactive) (if (use-region-p) (let* ((start (region-beginning)) (length (- (region-end) start))) (goto-char start) (insert-char ?*) (forward-char length) (insert-char ?*)) (insert "**") (backward-char))) (defun init/delimit-by-chars (c) "Delimit using character C the present region if any, otherwise point." (if (use-region-p) (let* ((start (region-beginning)) (length (- (region-end) start))) (goto-char start) (insert-char c) (forward-char length) (insert-char c)) (insert c c) (backward-char))) (defun init/delimit-double-quotes () ;; FIX so callers instead use `init/delimit-by-chars`, or the like. (interactive) (if (use-region-p) (let* ((start (region-beginning)) (length (- (region-end) start))) (goto-char start) (insert-char ?\“) (forward-char length) (insert-char ?\”)) (insert "“”") (backward-char))) (defun init/delimit-sgml-tag () (interactive) (set-mark (point)) (left-word) (kill-region (point) (mark)) (insert-char ?<) (yank) (insert-char ?>)) (fset 'init/delimit-sgml-tag-end "\C-r<\C-m") (defun init/delimit-single-quotes () ;; FIX so callers instead use `init/delimit-by-chars`, or the like. (interactive) (if (use-region-p) (let* ((start (region-beginning)) (length (- (region-end) start))) (goto-char start) (insert-char ?\‘) (forward-char length) (insert-char ?\’)) (insert "‘’") (backward-char))) (defun init/do-nothing () nil) (defun init/ebuild-mode () "Define a major mode for Gentoo ebuilds." (define-derived-mode ebuild-mode shell-script-mode "ebuild" "Gentoo `ebuild` files." ;; Per `http://www.gentoo.org/doc/en/gentoo-howto.xml`: (setq indent-tabs-mode 1)) (add-to-list 'auto-mode-alist '("[^/]\\.ebuild$" . ebuild-mode)) (add-to-list 'auto-mode-alist '("^/home/mike/project/.+/ebuild$" . ebuild-mode)) (add-to-list 'auto-mode-alist '("[^/]\\.eclass$" . ebuild-mode))) (defun init/emacs-lisp-mode () "Configure Emacs Lisp mode." (add-hook 'emacs-lisp-mode-hook (lambda () (local-set-key [f11] [insert ?\; ?\; ?\; insert left left left down]) ;;; To overwrite a ‘;;;’, then move point directly beneath it. (was `toggle-frame-fullscreen`) (local-set-key [?\C-c ?p]; Insert ‘(message " ——— =%S" ); TEST’, and move point before the ‘=’. [?\( ?m ?e ?s ?s ?a ?g ?e ? ?\" ? ?— ?— ?— ? ?= ?% ?S ?\" ? ?\) ?\; ? ?T ?E ?S ?T left left left left left left left left left left left left])))) (defun init/fonts (); To control fallback font substitution. ;; Modified from `https://emacs.stackexchange.com/a/5714/21090`. ;; See also `~/_/zz.brec` § Fonts. (let ((font-sets '("fontset-default" "fontset-standard" "fontset-startup")) ;; Re Misc Fixed, see `~/_/zz.brec` § Fonts § Misc Fixed, ;; also `https://www.cl.cam.ac.uk/~mgk25/ucs-fonts.html`. ;;; (my-font "-Misc-Fixed-*-R-Normal--13-120-75-75-C-70-ISO10646-1")) ;;;;;; It insists on the wider 8×13 font for bold, rather than the bold variant of these fonts. ;;;;;; Appending the bold variant to each fontset does not help: ;;;;;; `(set-fontset-font font-set '(#x000000 . #x3FFFFF) my-font-bold nil 'append)`. ;;; (my-font "Fairfax SM-14")) ;;; (my-font "Fairfax SM HD-16")) (my-font "-Misc-Fixed-*-R-Normal--13-120-75-75-C-80-ISO10646-1")) ;;; Changing the font? Sync ↔ `~/.Xresources`, and there read further instructions. ;;; Spec`Emacs.font` in `~/.Xresources` must specify the same font. ;;; else duplicate windows (`make-frame` via `C-x 5 2`) use the wrong font. (mapcar (lambda (font-set) (set-fontset-font font-set (cons 0 (max-char)) my-font) ;; for all characters without font specification ;; in another words it is a setting for lack of fallback font ;; if e.g. ℕ called DOUBLE-STRUCK CAPITAL N is not covered by our font ;; it will be displayed as placeholder-box, ;; because fallback for our font is now... our font :) ;;; (set-fontset-font font-set nil my-font)) ;;; Yet it works reliably only for the originally launched window. Buffer views in duplicate ;;; windows opened `make-frame` (`C-x 5 2`) revert to the original fallback behaviour ;;; for some Misc-Fixed characters such as miniscule subscript `ₜ`, ;;; though not for others such as extended IPA `ɠ`. ;;; (set-fontset-font font-set nil "Fairfax SM HD")) ;;;;;;; But Emacs uses too small a size in this case. The following looks better: (set-fontset-font font-set nil "Fairfax SM HD-12")) ;;; Here I fallback to Fairfax HD instead, which is my font for Breccian Web images. ;;; This way I get both the beauty of Misc Fixed, and the wider coverage of Fairfax HD. ;;; Moreover I learn directly whether a typed character will go unrendered in Web images. ;;; And this (unlike the alternative above) appears to work reliably in all windows, ;;; both original and duplicates. font-sets))) (defun init/general () "General initialization." (delete-selection-mode t) (menu-bar-mode 0); Early, else the menu bar briefly flashes on screen. (show-paren-mode); Indicate opposing brackets. To move between the two, use C-M-left and right. ;;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Matching.html (setq auto-save-default nil column-number-mode t ;;;column-number-indicator-zero-based nil ;;;;;; Then Breccian perfect indentation would appear at stops 5, 9 and so forth, which is misleading. ;;;font-lock-maximum-decoration 2; TEST ;;;font-lock-maximum-decoration '((java-deprecated-mode . 1)(t . t)) ;;;font-lock-maximum-decoration '((jmt-mode . nil)(t . t)) ;;; css : It fontifies property names as keywords, making the text unreadable. ;;; Unfortunately setting a minimal decoration has no effect. ;;; java-deprecated : Minimal, as per `/usr/local/share/emacs/site-lisp/java-deprecated-mode.el`. ;;; default (t) : Maximal (t). Without this, Emacs Lisp mode (at least) fails to fontify ;;; its regular expressions. ;;;custom-unlispify-remove-prefixes t; TEST frame-title-format (format "%%b %%f") inhibit-startup-message t isearch-lax-whitespace nil kill-whole-line t make-backup-files nil query-replace-highlight t read-quoted-char-radix 16 search-highlight t ;;;track-eol t ;;;;;; Too surprising when I do not want it. ;;;vc-cvs-stay-local nil ;;;;;; But now disabling CVS along with all other version control modes: vc-handled-backends nil ;;; Disable all version control modes. The Git one is forcing Emacs to visit symlink ;;; targets ("Followed link to") instead of source. visual-line-fringe-indicators t); For `visual-line-mode`. (setq-default ;;;case-fold-search nil; Making searches case sensitive. fill-column 105; (default 70) indent-tabs-mode nil major-mode #'text-mode; By default, as opposed to `fundamental`. recenter-positions '(top middle bottom); As opposed to `middle top bottom`. scroll-conservatively 1; With 101, query lines for `query-replace` end up at screen bottom. ;;; I would add `scroll-margin 3`, but then `recenter-top-bottom` no longer positions at top. ;;; https://www.gnu.org/software/emacs/manual/html_node/emacs/Auto-Scrolling.html show-trailing-whitespace t tab-width 4 truncate-lines t) ;;;(put 'narrow-to-region 'disabled nil); Enables the command `narrow-to-region`. ;;;;;; Emacs probably put it here; I cannot remember ever having a use for it, neat as it is. (setq require-final-newline t); (setq-default require-final-newline t) ;;; But don't know how to mask it or unset it locally in major modes where it is unwanted. ;;; So instead I could explicitly set it (locally). Cf. `mode-require-final-newline`. ;; Bell ;; ──── ;;;(setq bell-volume 0); Enforce silence ;;;;;; Does not work, but this does: (setq ring-bell-function #'init/do-nothing) ;; Buffer initializations according to source file ;; ─────────────────────────────────────────────── (add-hook 'find-file-hook (lambda () (let ((bfn (file-truename buffer-file-name))) ;; Rather than simply using `buffer-file-truename`, which abbreviates e.g. "/home/mike" to "~" ;; built files ;; ┈┈┈┈┈┈┈┈┈┈┈ (when (eq (string-match "/home/mike/var/deploy/" bfn) 0) (message-box "Warning: this might be a built file."); In case I edit the wrong copy. (auto-revert-mode 1)) ;; source repositories ;; ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ ;;; (when (eq (string-match; GWT ;;; "/home/mike/code/gwt/limb/[^/]+/repo/" bfn) 0) ;;; (message "Set fill column for GWT source code.") ;;; (setq fill-column 80) ;;; ) (when (eq (string-match; SMBProvider Android app. "/home/mike/code/smbprovider/repo/[^/]*/" bfn) 0) (message "Set tabbing for SMBProvider source code.") (setq indent-tabs-mode 1)) ;;; (when (eq ;;; (string-match; Textbook Valet.. ;;; "/home/mike/client/valet/code/limb/[^/]+/repo/" bfn) ;;; 0) ;;; (message "Defeat require-final-newline for Textbook Valet source code.") ;;; (setq require-final-newline nil)) ;;; ;; remote files served across an SSH file system ;;; ;; ┈┈┈┈┈┈┈┈┈┈┈┈ ;;; (when (eq (string-match "/home/mike/code/uhm/mnt/" bfn) 0) ;;; (message "Enabling auto-revert-mode for this remote file.") ;;; (auto-revert-mode 1)); To avoid spurious editing guards: "file changed on disk". ;; current projects ;; ┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈┈ ;; For sake of properly ordering their files (by title) on opening them together, ;; e.g. by way of `~/sys/bin/lay-editable-tools`. (when (eq (string-match "/home/mike/code/100-0/repo/poll/\\([0-9a-zA-Z]+\\)/" bfn) 0) (rename-buffer (concat (match-string-no-properties 1 bfn) "/…") t)) (when (eq (string-match "/home/mike/project/proto-waycast/\\(?:README\\|_/[a-z_]+\\.task$\\)" bfn) 0) (rename-buffer (concat "proto-waycast (" (file-name-nondirectory bfn) ")") t)) (when (eq (string-match "/home/mike/work/_/proto-wayic/\\(?:README\\|_/manual\\.task$\\)" bfn) ;;; Omitting any `wayic.task`, which would rename the buffer 'proto-wayic wayic'. 0) (rename-buffer (concat "proto-wayic (" (file-name-nondirectory bfn) ")") t)) (when (eq (string-match "/home/mike/work/_/proto-wayic/\\([a-z][a-z_]*\\)/\\(?:_/\\)?\\(?:README\\|[a-z_]+\\.task$\\)" ;; └──────────────┘ ;; project name bfn) 0) (rename-buffer (concat "proto-wayic." (match-string-no-properties 1 bfn) " (" (file-name-nondirectory bfn) ")") t)) (when (eq (string-match "/home/mike/work/\\([A-Za-z].*?\\)/\\(?:README\\.[^/]+\\|[^/]*\\.\\(?:brec\\|task\\)\\)\\'" ;; └─────────────┘ ;; project name bfn) 0) (rename-buffer (concat (match-string-no-properties 1 bfn) " (" (file-name-nondirectory bfn) ")") t))))) ;; Customizer, `customize` that is. Apparently the package manager depends on it. ;; ────────── (setq custom-file "/home/mike/.config/emacs/customizer-store.el") (load custom-file nil t) ;; Line spacing ;; ──────────── ;;;(setq-default line-spacing 1) ;;;;;; Done rather in `~/.Xresources`; but it remains to stop the resulting mystery echo: (add-hook 'minibuffer-setup-hook (lambda () (init/set-for-buffer 'line-spacing 0))) ;;; Stopping the ‘[Saved text until: …]’ that attends any use of `kill-ring-save` in the echo area, ;;; whenever a positive `line-spacing` is in effect. https://emacs.stackexchange.com/q/71797/21090 ;; Tabbing and indentation ;; ─────────────────────── (setq tab-stop-list '(4 8 12 16 20 24 28 32 36 40 44 48 52 56 60)) (electric-indent-mode -1)); A minor mode enabled in 24.4. It messes up `return` key binding. ;; Yank ;; ──── ;;; (setq yank-handled-properties (assq-delete-all 'face yank-handled-properties)) ;;; (setq yank-handled-properties (assq-delete-all 'font-lock-face yank-handled-properties)) ;;; (add-to-list 'yank-excluded-properties 'face) ;;; (add-to-list 'yank-excluded-properties 'font-lock-face) ;;;;;; Still I see misfaced text after yanking, at least in Java buffers. ;;; (setq yank-handled-properties (cons (cons 'face 'yank-handle-font-lock-face-property) yank-handled-properties)) ;;;;;; Nor does that help. (fset 'init/html-a-href [?\C-w ?< ?a ? ?h ?r ?e ?f ?= ?' ?' ?> ?\C-v ?< ?/ ?a ?> ?\C-r ?< ?a right right right right right right right right right]) (defun init/html-mode () "Configure HTML mode." (add-to-list 'auto-mode-alist '("\\.html\\'" . html-mode)); As opposed to `mhtml-mode`, e.g. `XHTML+`. (add-to-list 'auto-mode-alist '("[^/]\\.xht$" . html-mode)) (add-to-list 'auto-mode-alist '("^/home/mike/work/_/proto-wayic/\\(?:.+/\\)?[^./]+$" . html-mode)) ;;; Wayic files named without an extension are HTML term files. (add-hook 'html-mode-hook (lambda () (local-set-key [?\C-c ?, ?a ?h] #'init/html-a-href)))) (defun init/indent-relative-plain () (indent-relative t)) (defun init/Java-automatically (); Mimicing what a package-manager installation would do. (load "jmt-mode-autoloads" nil t); Q.v. at `http://reluk.ca/sys/computer/workstation/etc/emacs/`. (init/Java)) (defun init/Java-manually (); As instructed at `http://reluk.ca/project/Java/Emacs/jmt-mode.el`. (autoload 'jmt-mode "jmt-mode" nil t) (set 'auto-mode-alist (cons (cons "\\.java\\'" 'jmt-mode) auto-mode-alist)) (set 'interpreter-mode-alist; For Java source-launch files encoded with a shebang. [SLS] (cons (cons "\\(?:--split-string=\\|-S\\)?java" 'jmt-mode) interpreter-mode-alist)) (register-definition-prefixes "jmt-mode" '("jmt-")) (init/Java)) (defun init/Java () "Configure JMT Mode and other Java particulars." (add-hook 'jmt-mode-hook (lambda () ;; Key bindings ;; ──────────── (local-set-key [f11] #'init/Java-comment-down); A keyboard macro; was `toggle-frame-fullscreen`. (local-set-key [tab] #'tab-to-tab-stop); Was `c-indent-line-or-region`. (local-set-key [?\M-\;] #'init/Javadoc-open-comment); A keyboard macro; was `comment-dwim`. ;;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Comment-Commands.html (local-set-key [?\C-c ?, ?a ?h] #'init/html-a-href) (local-set-key [?\C-c ?, ?l] #'init/Javadoc-linkplain) (local-set-key [?\C-c ?p] #'init/Java-println) (local-set-key [?\C-\M-,] #'init/delimit-sgml-tag); To `<` unshifted, that is; a keyboard macro. (local-set-key [?\C-\M-.] #'init/delimit-sgml-tag-end); One for its opposite, too. ;; Unwanted features of the underlying Java Mode ;; ───────────────── ;; ‘By default… electric mode and syntactic-indentation mode are enabled’ ;; and (in support of the former) abbrev mode is ‘turned on by default’. ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Minor-Modes.html ;; https://www.gnu.org/software/emacs/manual/html_node/ccmode/Electric-Keys.html (init/set-for-buffer 'abbrev-mode nil) ;;; (init/set-for-buffer 'c-electric-flag nil) ;;;;;; already disabled through my setting (elsewhere) of `electric-indent-mode` (init/set-for-buffer 'c-syntactic-indentation nil))) ;; Further fontification ;; ───────────────────── (font-lock-add-keywords #'jmt-mode (list (cons; Subdue any `assert` statements. (let (match-beg match-end) (lambda (limit) (setq match-beg (point)); Presumptively. (catch 'to-reface (while (< match-beg limit) (setq match-end (next-single-property-change match-beg 'face (current-buffer) limit)) (when (and (eq 'jmt-principal-keyword (get-text-property match-beg 'face)) (string= "assert" (buffer-substring-no-properties match-beg match-end))) (goto-char match-end) (when (search-forward ";" (min (line-end-position) limit) t) ;;; May rarely match a ‘;’ in a string or comment [BUG]. Repair by extending ;;; the search in a `while` loop till face property `jmt-separator` is found. (setq match-end (point)) (set-match-data (list match-beg match-end (current-buffer))) (throw 'to-reface t))) (setq match-beg match-end)) nil))) '(0 'init/subdued t))) t)); To append. ;; A keyboard macro that overwrites a ‘//’, then moves point directly beneath it. (fset 'init/Java-comment-down [insert ?/ ?/ insert left left down]) (defun init/Java-common-mode (mode-map) "Initialization common to Java and JavaScript modes." (define-key mode-map [?\C-c ?* ?l] #'init/Javadoc-linkplain) (define-key mode-map [?\C-c ?* ?*] #'init/Javadoc-open-comment); A keyboard macro; was `comment-dwim`. (define-key mode-map [?\C-c ?/] [?/ ?* ?* ?/ left left]) (define-key mode-map [f11] #'init/Java-comment-down); A keyboard macro; was `toggle-frame-fullscreen`. (define-key mode-map [tab] #'tab-to-tab-stop) ;;; Was `indent-for-tab-command`, which still is bound to `C-i`. (setq indent-line-function #'init/indent-relative-plain)) (defun init/java-deprecated-mode () "Configure `java-deprecated-mode`." (defvar java-deprecated-mode-map); [FV] (add-hook 'java-deprecated-mode-hook (lambda () (let ((m java-deprecated-mode-map)) (define-key m [?\C-c ?p] #'init/Java-println) ;; Undo troublesome key assignments in cc-mode.el ;;; (define-key m "#" #'self-insert-command) ;;; (define-key m "{" #'self-insert-command) ;;; (define-key m "}" #'self-insert-command) ;;; (define-key m "/" #'self-insert-command) ;;; (define-key m "*" #'self-insert-command) ;;; (define-key m ";" #'self-insert-command) ;;; (define-key m "," #'self-insert-command) ;;; (define-key m ":" #'self-insert-command); Otherwise inserts a space. ;;; (define-key m "(" #'self-insert-command) ;;; (define-key m ")" #'self-insert-command) ;;; (init/sgml-common-mode m)) (init/Java-common-mode m)) (setq abbrev-mode nil))) ;;; Otherwise enabled for some reason. Not wanted. Also I want to avoid an ;;; infinite loop that I once saw involving `c-electric-continued-statement`, ;;; which occurred after typing "else" and other words in the abbreviation table. (autoload 'java-deprecated-mode "java-deprecated-mode" init/autoload_docstring t); ↑ Q.v. at `http://reluk.ca/sys/computer/workstation/etc/emacs/`. (setq auto-mode-alist (cons (cons "\\.java\\'" 'java-deprecated-mode) auto-mode-alist))) ;; A keyboard macro that inserts an `@linkplain` Javadoc tag. Uses the selected text as the tag body. ;; Saves it to the kill ring, forms the tag around it and places point in readiness to enter (or yank) ;; the tag reference. (fset 'init/Javadoc-linkplain [?\C-w ?{ ?@ ?l ?i ?n ?k ?p ?l ?a ?i ?n ? ?\C-v ?} ?\C-r ?{ ?@ ?l ?i ?n ?k C-right ? ?#]) ;; A keyboard macro that inserts an empty API description before the present line, ;; and places point in readiness to enter its text. (fset 'init/Javadoc-open-comment [kp-prior ?/ ?* ?* return ? ? ?* ?/ up ? ?. left]) ;; A keyboard macro that inserts “System.err.println( \" ——— =\" + )” and moves point before the ‘=’. (fset 'init/Java-println [?S ?y ?s ?t ?e ?m ?. ?e ?r ?r ?. ?p ?r ?i ?n ?t ?l ?n ?\( ? ?\" ? ?— ?— ?— ? ?= ?\" ? ?+ ? ? ?\) ?\; ? ?/ ?/ ? ?T ?E ?S ?T left left left left left left left left left left left left left left left left]) (defun init/js-deprecated-mode () "Configure `js-deprecated-mode`." (defvar js-deprecated-mode-map); [FV] (add-hook 'js-deprecated-mode-hook (lambda () (let ((m js-deprecated-mode-map)) ;;; (define-key m [?\C-c ?p] [ ?j ?a ?v ?a ?. ?l ?a ?n ?g ?. ?S ?y ?s ?t ?e ?m ?. ?e ?r ?r ?. ?p ?r ?i ?n ?t ?l ?n ?\( ? ?' ? ?— ?— ?— ? ?= ?' ? ?+ ? ? ?\) ?\; ? ?/ ?/ ? ?T ?E ?S ?T left left left left left left left left left left left left left left left left]) ;;;;;; I guess I need this form when running under a JDK (e.g. as Nashorn). ;;;;;; I can sometimes distinguish that using `interpreter-mode-alist` (as below). ;;;;;; But this works only for a shebanged executable (headed by the likes of `#!/opt/jdk/bin/jjs`), ;;;;;; not for any library it loads, or any script executed by other means. So just: (define-key m [?\C-c ?p] [ ?c ?o ?n ?s ?o ?l ?e ?. ?l ?o ?g ?\( ? ?' ? ?— ?— ?— ? ?= ?' ? ?+ ? ? ?\) ?\; ? ?/ ?/ ? ?T ?E ?S ?T left left left left left left left left left left left left left left left left]) (init/Java-common-mode m)))) (autoload 'js-deprecated-mode "js-deprecated-mode" init/autoload_docstring t); ↑ Q.v. at `http://reluk.ca/sys/computer/workstation/etc/emacs/`. (set 'auto-mode-alist (cons (cons "\\.fab\\'" 'js-deprecated-mode) auto-mode-alist)) (set 'auto-mode-alist (cons (cons "\\.js\\'" 'js-deprecated-mode) auto-mode-alist)) (set 'auto-mode-alist (cons (cons "\\.jsm\\'" 'js-deprecated-mode) auto-mode-alist)) ;;; Waymaker file-associated build scripts (.fab), JavaScript (.js) ;;; and Votorola JavaScript modules (.jsm). (set 'interpreter-mode-alist (cons (cons "jjs" 'js-deprecated-mode) interpreter-mode-alist)) (set 'interpreter-mode-alist (cons (cons "jrunscript" 'js-deprecated-mode) interpreter-mode-alist))) ;;; JDK Nashorn JavaScript executable (jjs) and JDK JavaScript executable (jrunscript). (defun init/keys () "Initialize key bindings." ;; ═════════════ ;; Single-stroke ;; ═════════════ (global-unset-key [f10]); Was `tmm-menubar`. (global-unset-key [menu]); Was `execute-extended-command`. (global-set-key [?\r] #'newline-and-indent); Was `newline`, q.v. herein. (global-set-key [kp-end] #'init/newline-after) (global-set-key [kp-home] #'init/newline-before) (global-set-key [kp-left] (lambda () (interactive) (indent-rigidly (region-beginning)(region-end) -1))) (global-set-key [kp-next] #'init/open-line-after) (global-set-key [kp-prior] #'init/open-line-before) (global-set-key [kp-right] (lambda () (interactive) (indent-rigidly (region-beginning)(region-end) 1))) (let ((sm isearch-mode-map)) ;; `C`-qualified by `Ctrl` key ;; ───────────── (global-set-key [?\C-'] [?\u0301]); Accute accent ◌́ combining. (global-set-key [?\C-`] [?\u0300]); Grave accent ◌̀ combining. (global-unset-key [?\C-a]); Was `beginning-of-line`, but for that I use `Home`. ;;;(global-set-key [?\C-c] #'copy-region-as-kill-nomark) ;;;;;; Bad idea because it is a standard prefix; modes will clobber it. ;;;(global-unset-key [?\C-d]); Was `delete-char`, but for that I use `Del`. ;;;;;; Causes `Del` to fail; apparently it is remapped to `C-d` at a low level. (global-unset-key [?\C-o]) ;;; Was `open-line`, but for that I use my `init/open-line-before` and `init/open-line-after`. (global-set-key [?\C-p] #'math-preview-at-point); Was `previous-line`. (global-set-key [?\C-v] #'yank); Was `scroll-up`. (define-key sm [?\C-v] #'isearch-yank-kill); During incremental search, that is. (global-unset-key [?\C-z]); Was `iconify-or-deiconify-frame`. ;;; (global-set-key [C-end] #'end-of-buffer); Was `end-of-buffer-nomark`. ;;; (global-set-key [C-home] #'beginning-of-buffer); Was `beginning-of-buffer-nomark`. (global-set-key [C-next] #'init/switch-to-next-buffer) ; Was bound to `scroll-left`. (global-set-key [C-prior] #'init/switch-to-previous-buffer); Was bound to `scroll-right`. ;; `C-M`-qualified by `Ctrl-Alt` keys ;; ─────────────── (global-set-key [?\C-\M-'] [?′]) (define-key sm [?\C-\M-'] (lambda () (interactive) (isearch-yank-string "′"))) (global-set-key [?\C-\M-\"] [?″]) (define-key sm [?\C-\M-\"] (lambda () (interactive) (isearch-yank-string "″"))) ;; `M`-qualified by `Alt` key ;; ───────────── (global-set-key [?\M-\r] #'newline); Cf. `newline-and-indent` herein. (global-set-key [?\M- ] [? ]); Was `just-one-space`. (define-key sm [?\M- ] (lambda () (interactive) (isearch-yank-string " "))) (global-set-key [?\M-$] [?§]); Was `ispell-word`. (define-key sm [?\M-$] (lambda () (interactive) (isearch-yank-string "§"))) (global-set-key [?\M-'] [?\’]); Was `abbrev-prefix-mark`. (define-key sm [?\M-'] (lambda () (interactive) (isearch-yank-string "’"))) (global-set-key [?\M-*] [?•]) (define-key sm [?\M-*] (lambda () (interactive) (isearch-yank-string "•"))) (global-set-key [?\M--] [?—]); Was `negative-argument`. (define-key sm [?\M--] (lambda () (interactive) (isearch-yank-string "—"))) (global-set-key [?\M-.] [?…]); Was `xref-find-definitions`. (define-key sm [?\M-.] (lambda () (interactive) (isearch-yank-string "…"))) (global-set-key [?\M-~] [?∼]); Was `not-modified`. (define-key sm [?\M-~] (lambda () (interactive) (isearch-yank-string "∼"))) (global-set-key [?\M-b] [?∵]) (define-key sm [?\M-b] (lambda () (interactive) (isearch-yank-string "∵"))) (global-set-key [?\M-k] #'init/kill-ring-save-line); A keyboard macro; was `kill-sentence`. (global-set-key [?\M-t] [?∴]); Was `transpose-words`. (define-key sm [?\M-t] (lambda () (interactive) (isearch-yank-string "∴"))) (global-set-key [?\M-v] #'yank-pop); Was `scroll-down`. (define-key sm [?\M-v] #'isearch-yank-pop) (global-set-key [M-down] (lambda () (interactive) (scroll-up-line))); Was `backward-line-nomark`. (global-set-key [M-up] (lambda () (interactive) (scroll-down-line))); Was `forward-line-nomark`. (global-set-key [M-left] (lambda () (interactive) (scroll-right 1))); Was `left-word`. (global-set-key [M-right] (lambda () (interactive) (scroll-left 1))); Was `right-word`. (global-set-key [M-kp-left] #'init/null-command); Was unbound and translating to `M-left`. [TOP] (global-set-key [M-kp-right] #'init/null-command); Was unbound and translating to `M-right`. [TOP] (global-set-key [M-S-kp-4] #'init/null-command); Was unbound and translating to `M-4`. [TOP] (global-set-key [M-S-kp-6] #'init/null-command); Was unbound and translating to `M-6`. [TOP] ;; `S-C`-qualified by `Shift-Ctrl` keys ;; ─────────────── (global-set-key [S-C-next] (lambda () (interactive) (init/switch-to-next-buffer t))) (global-set-key [S-C-prior] (lambda () (interactive) (init/switch-to-previous-buffer t))) ;;; `S-C-next` and `S-C-prior` fail outside of X Windows. There `C-prior` (`Page Up`) ;;; and `C-next` (`Page Down`) are somehow equivalent to unqualified `prior` and `next`. ;; ════════════ ;; Multi-stroke ;; ════════════ ;; `C-c` based ;; ─────────── (global-set-key [?\C-c ?8] #'init/delimit-asterisk-quotes) (global-set-key [?\C-c ?'] #'init/delimit-single-quotes) (global-set-key [?\C-c ?\"] #'init/delimit-double-quotes) (global-set-key [?\C-c ?h] "http://reluk.ca/project/") ;; `C-h` based ;; ─────────── (global-set-key [?\C-h ?c] #'describe-char); Was `describe-key-briefly`. ;; `C-x` based ;; ─────────── (global-set-key [?\C-x ?r ?v] #'yank-rectangle) (global-unset-key [?\C-x ?r ?y]); Was `yank-rectangle`. (global-set-key [?\C-x ?s] #'init/save-all-buffers) ;;; Was `save-some-buffers` which prompts, whereas this one is silent. (global-unset-key [?\C-x ?u]); Was `advertised-undo`, but for that I use `S-C--`. (global-unset-key [?\C-x ?\C-z]); Was `iconify-or-deiconify-frame`, ;;; but I never do that because it makes the window disappear as though it were killed. ;; `M-m` based ;; ─────────── (define-prefix-command 'prefix-map-M-m) (global-set-key [?\M-m] #'prefix-map-M-m); Was `back-to-indentation`. (global-set-key [?\M-m ?m] [?×]) (define-key sm [?\M-m ?m] (lambda () (interactive) (isearch-yank-string "×"))))) (fset 'init/kill-ring-save-line "\C-k\C-_") (defun init/markdown (); http://jblevins.org/projects/markdown-mode/ "Configure Markdown particulars." (defvar markdown-command); [FV] (setq markdown-command "markdown2") ;;; The default is `markdown`, but it seems a Gentoo package has installed `markdown2` instead. (autoload 'markdown-mode "markdown-mode" init/autoload_docstring t) (autoload 'gfm-mode "markdown-mode" init/autoload_docstring t); GitHub Flavoured Markdown (GFM). ;;; Likely it cannot do previews without additional work. See ‘GFM’ in the manual. (add-to-list 'auto-mode-alist '("\\.markdown\\'" . markdown-mode)) (add-to-list 'auto-mode-alist '("\\.md\\'" . markdown-mode)) (add-to-list 'auto-mode-alist '("README\\.md\\'" . gfm-mode)) (add-hook 'markdown-mode-hook (lambda (); Overriding the present mode’s override of my `init/keys`: ;; Defeat of unwanted key bindings that would override my `init/keys` ;; ─────────────────────────────── ;; TODO more reliably: https://emacs.stackexchange.com/questions/352/how-to-override-major-mode-bindings (local-set-key [?\C-c ?8] #'init/delimit-asterisk-quotes) (local-set-key [?\C-c ?\"] #'init/delimit-double-quotes) (local-set-key [?\C-c ?'] #'init/delimit-single-quotes)))) (defun init/math-preview () "Initialize `math-preview`." ;; https://gitlab.com/matsievskiysv/math-preview ;; https://gitlab.com/matsievskiysv/math-preview/-/issues ;; ;; Requires compiling Emacs with the `svg` use flag, else it fails silently. ;; ;; Configure it using Customize (`M-x RET customize-group RET math-preview`) as per instructions at ;; the URL above. For the present Customize configuration, see `~/.config/emacs/customizer-store.el`. ;; Or set the custom variables directly herein. ;; ;; Note that custom variables `math-preview-mathjax-em`, `-mathjax-ex` and `-mathjax-svg-ex-factor` ;; have no effect on the resulting images, nor anything that I can tell. ;; ;; Debugging note: opening an image with Emacs (under Image Mode), one can query its properties. ;; To query its size, for instance, evaluate `(image-size (image-get-display-property) :pixels)`. ;; In this way, I learned that Emacs sizes the ex unit at ½ the nominal height of the default font. ;; So 1 ex = ½ em, for already it is documented: ‘One em is equivalent to the height of the font’. ;; [https://www.gnu.org/software/emacs/manual/html_node/elisp/Image-Descriptors.html] ;;;(setq math-preview-raise 0); Effective default: zero in my patched version, 0.4 in the original. ;;;(setq math-preview--debug-json t); TEST ;;;(setq math-preview-scale 2); TEST ;;;(setq math-preview-raise 0.4); TEST ;;;(setq math-preview-mathjax-svg-ex-factor 0.7); TEST, never makes a difference ;; Colour the math images, each to match the face colour of its LaTeX/TeX source ;; ────────────────────── (let (beg; The position of the start delimiter of each mathematic expression being imaged. s; Source text of the math to be previewed. c; Its face colour. end) (advice-add; Ensure `beg` is set for each expression being imaged, then nilled afterward. #'math-preview--submit-region :around (lambda (f-name &rest args) (setq beg (car (car args))) (prog1 (apply f-name args) (setq beg nil))) '((name . "init/advice/math-preview--submit-region"))) (require 'color) (add-hook; Colour each image as Math Preview generates it. 'math-preview-tex-preprocess-functions (lambda (preview) (when (and beg (string= "tex" (gethash 'type preview))); LaTeX/TeX only, not MathML or AsciiMath. (catch 'abort (setq s (gethash 'string preview) c (save-excursion; Its face colour. (setq beg (+ beg (length (gethash 'prefix preview))); Start of source text. end (+ beg (length s))); End of source text. (goto-char beg) ;;; (skip-syntax-forward "(" end); Through any characters of opening-parenthesis syntax. ;;; ;;; This is a workaround to avoid highlighting applied by `show-paren-mode`. ;;; (when (= end (point)); Then somehow all characters have that syntax. ;;; (throw 'abort nil)); Let the default colour apply. ;;; (foreground-color-at-point)) ;;;;;; Yet search highlighting too is a problem. Therefore exclude such highlighting ;;;;;; by looking (in effect) at the text that lies beneath all overlays. (init/text-foreground-color-at-point)); Excludes overlay facing. c (color-name-to-rgb c); From whatever form `c` is in, to floating RGB, c (color-rgb-to-hex (pop c) (pop c) (pop c) 2); thence to hex `#rrggbb`. s (concat "\\color{" c "} " s)); Prepending a colour directive to match the source. (puthash 'string s preview))))))) (defun init/modes () "Define and/or customize the various major and minor modes." (init/breccia-automatically) ;;;(init/breccia-manually); TEST (init/conf-mode) (init/css-mode) (init/ebuild-mode) (init/emacs-lisp-mode) (init/html-mode) (init/Java-automatically) ;;;(init/Java-manually); TEST ;;;(init/java-deprecated-mode); TEST (init/js-deprecated-mode) (init/mutt-mode) (init/perl-mode) (init/sh-mode) (init/sgml-mode) (init/task-sheet-mode) ;;;(init/test-mode); TEST ;;;(init/test2-mode); TEST (init/text-mode) (init/waybrec) (init/wayscript-mode) (when (string= (system-name) "primeval"); Which alone has the necessary packages installed, (when (string=(user-login-name) "mike" ); and only for user `mike`, to run the following. (init/math-preview) ;;; (init/prettify-math); Uncommenting this for TEST purposes? Then consider commenting out initial ;;; calls (elsewhere) to the image-generation functions of alternative package `math-preview`. (init/markdown)))) (defun init/mutt-mode () "Define Mutt-Mail mode." (define-derived-mode mutt-mail-mode text-mode "Mutt-Mail" "For composing mail in a buffer invoked by Mutt." (setq show-trailing-whitespace nil ;;; indent-line-function #'indent-relative) fill-column 70); Though usually you must set this in a mode hook. (defvar mutt-mail-font-lock-keywords (list '("^\\(?:From: \\|Cc: \\|Bcc: \\|Message-ID: \\|Reply-To: \\|In-Reply-To: \\).*$" . font-lock-comment-face) '("^\\(?:To: \\).*$" . font-lock-string-face) '("^\\(?:Subject: \\).*$" . font-lock-type-face) '("^\\(?: *> *>\\)+ *\\(?:[^ >\xA].*\\)?$"; Quote me (even). . font-lock-comment-face) '("^ *>.*$" ; Quote other (odd). . font-lock-string-face) '("^-- $" ; Signature delimiter. . font-lock-comment-face) '("^\\(?:Mike\\|Michael Allan\\)$" ; Signature. . font-lock-comment-face)) "For mutt-mail-mode.") ;;; (make-local-variable 'font-lock-defaults) ;;; (setq font-lock-defaults '(mutt-mail-font-lock-keywords t)) (init/set-for-buffer 'font-lock-defaults '(mutt-mail-font-lock-keywords t))) (add-to-list 'auto-mode-alist '("[mM]utt\\(?:-.*\\)?-[0-9]+-[0-9]+\\'" . mutt-mail-mode)) (add-hook 'mutt-mail-mode-hook (lambda () ;;; (make-local-variable 'require-final-newline) ;;; (setq require-final-newline nil) ;;;;;; No effect; rather than unsetting it like this, explicitly, I would have to set it explicitly ;;;;;; everywhere else [just don't like how Mutt's viewer shows the final newline] but it's not worth ;;;;;; it [and mail handlers append newlines etc. anyway, it seems] (re-search-forward "^$"); Move down to 1st blank line, past the headers. (forward-line)))); And one more, to beginning of message body. (fset 'init/newline-after [end M-return]) (fset 'init/newline-before [home M-return up]) (defun init/null-command (); Does nothing. (interactive)) (fset 'init/open-line-after [end return]) (fset 'init/open-line-before [end return ?\C-x ?\C-t up up end]) (defun init/perl-mode () "Configure Perl mode." (add-hook 'perl-mode-hook #'init/perl-mode_hook) (add-hook 'cperl-mode-hook #'init/cperl-mode_hook)) ;; Add the following if you want `cperl-mode` instead of `perl-mode`. ;; Note that opening an editor window via `lay-editable-tools` (which includes Perl buffers), ;; then switching back and forth among the buffers (Ctrl Page Up, Ctrl Page Down) results (2023-2) ;; in copies of the following in the message buffer. ;; ;; Error during redisplay: (jit-lock-function 1) signaled (error "No match 4 in highlight (4 font-lock-variable-name-face)") ;; Error during redisplay: (jit-lock-function 2) signaled (error "No match 4 in highlight (4 font-lock-variable-name-face)") ;; ;; Meanwhile it turns out (2023-2) the JIT Lock debugger is now useless: ;; enabling `jit-lock-debug-mode` causes all modes to fail silently. ;; ;; However, `cperl-mode.el` has but one line that contains `4 font-lock-variable-name-face`. ;;;(add-to-list 'auto-mode-alist '("\\.\\([pP][Llm]\\|al\\)\\'" . cperl-mode)) ;;;(add-to-list 'interpreter-mode-alist '("perl" . cperl-mode)) ;;;(add-to-list 'interpreter-mode-alist '("perl5" . cperl-mode)) ;;;(add-to-list 'interpreter-mode-alist '("miniperl" . cperl-mode))) (defun init/perl-mode_hook (); Underived major mode, *-mode-map are defined only in here. (defvar perl-mode-map); [FV] (define-key perl-mode-map [?\C-c ?p] #'init/pl-println) (define-key perl-mode-map [f11] #'init/pl-comment-down) ;; Undo stuff in perl-mode.el (define-key perl-mode-map [?{] #'self-insert-command); Auto-indent too often wrong. (define-key perl-mode-map [?}] #'self-insert-command) (define-key perl-mode-map [?\;] #'self-insert-command) (define-key perl-mode-map [?:] #'self-insert-command) (define-key perl-mode-map [tab] #'tab-to-tab-stop); Can still use C-i for indent. (font-lock-add-keywords nil '( ;; Subdue punctuation ("[,;:]" . font-lock-comment-face) ("['\"]" 0 font-lock-comment-face t); t override existing fontification. ("[{}$@%*]" . 'init/subdued))); Unless already fontified. (setq indent-line-function #'init/indent-relative-plain)) (fset 'init/pl-comment-down [insert ?# insert left down]) (fset 'init/pl-println [?p ?r ?i ?n ?t ?\( ? ?\" ? ?— ?— ?— ? ?\\ ?= ?\" ? ?. ? ? ?. ? ?\" ?\\ ?n ?\" ? ?\) ?\; left left left left left left left left left left left left left left left]) (defun init/prettify-math (); https://github.com/shaqtsui/prettify-math "Initialize `prettify-math`." ;; Requires compiling Emacs with the `svg` use flag, else it issues a warning. ;; On first running, it prompts to install MathJAX, then stores it ;; at `/home/mike/.config/emacs/elpa/prettify-math-VERSION/node_modules\`. ;; ;; The colour of its images does not match the surrounding text. The in-line images align with ;; each other at their bottoms, not their text baselines, making them inconsistent both mutually ;; and with the surrounding text. Nor does it recognize in-line math that breaks across lines. (require 'brec-mode) (setq prettify-math-default-scale 1) (setq prettify-math-delimiters-alist; This cannot be made buffer-local. It seems `prettify-math` ;;; reads it once only on loading. I guess that’s why the maintainer warns to set it ;;; ‘before this module loaded’. `https://github.com/shaqtsui/prettify-math` (list (list (char-to-string brec-math-inline-delimiter-char) 'tex) (list (char-to-string brec-math-block-delimiter-char) 'tex 'block))) (require 'prettify-math)); Last, to be affected by the settings above. (defun init/save-all-buffers () (interactive) (save-some-buffers t)) (defun init/sgml-common-mode (mode-map) "SGML related init, common to various modes." ;;; [unsure if this is still true:] ;;; Many keys cannot be bound here, because bindings are clobbered in sgml-mode.el. ;;; Test first with describe-key-briefly. ;;; ;;; Changing? Change also in zz-swatch.txt. (define-key mode-map [?/] #'self-insert-command) ;;; Was `sgml-slash`, which blocks overwriting of the present selection when I type ‘/’. (define-key mode-map [?\C-\M-,] #'init/delimit-sgml-tag); To `<` unshifted, that is; a keyboard macro. (define-key mode-map [?\C-\M-.] #'init/delimit-sgml-tag-end)); One for its opposite, too. (defun init/sgml-mode () "Configure SGML mode." (defvar sgml-mode-map); [FV] (add-to-list 'auto-mode-alist '("[^/]\\.xml$" . sgml-mode)) ;;; Somehow puts the buffer into XML mode specifically, which is derived from SGML mode; ;;; this as opposed to the default nXML mode which is *not* so derived. ;;;(add-to-list 'auto-mode-alist '("[./]tld$" . sgml-mode)) ;;;(add-to-list 'auto-mode-alist '("[^/]\\.ent$" . sgml-mode)) ;;;(add-to-list 'auto-mode-alist '("[^/]\\.mod$" . sgml-mode)) ;;;(add-to-list 'auto-mode-alist '("[^/]\\.rdf$" . sgml-mode)) ;;;(add-to-list 'auto-mode-alist '("[^/]\\.xsd$" . sgml-mode)) (add-to-list 'auto-mode-alist '("[^/]\\.xslt$" . sgml-mode)) (add-hook 'sgml-mode-hook (lambda () ;;; (define-key sgml-mode-map [tab] #'tab-to-tab-stop); Can still use C-i for indent. ;;; (define-key sgml-mode-map "/" #'self-insert-command) ;;; ;;; Undo from sgml-mode.el; refuses to obey insert/overwrite mode. ;;; (make-local-variable 'require-final-newline) ;;; (setq require-final-newline t) (setq indent-line-function #'init/indent-relative-plain) ;; As this is un-derived major mode, *-mode-map are defined only in here (init/sgml-common-mode sgml-mode-map) (font-lock-add-keywords nil; 'nil' so it affects derived modes such as HTML, too. '( ;; See also my modified older version of sgml-mode.el, from which many of these rules ;; were originally taken: /usr/local/share/emacs/site-lisp/._ ;; Attribute assignment ;; ──────────────────── (" \\([_[:alpha:]][-._[:alnum:]]*:\\)?\\([_[:alpha:]][-._[:alnum:]]*\\) *\\(=\\) *\\(['\"]\\)\\(.*?\\)\\(\\4\\)" (1 font-lock-comment-face nil t) (2 font-lock-builtin-face) (3 font-lock-comment-face) (4 'init/subdued t) (5 font-lock-comment-face t) (6 'init/subdued t)) ;;; (" id *= *\\(['\"]\\)\\(.+?\\)\\1" 2 font-lock-string-face t); HTML allows any non-empty value ;;;;;; Defeated only because my attempt to override it fails in init/wayscript-mode, q.v. (" xmlns:\\([_[:alpha:]][-._[:alnum:]]*\\) *= *['\"]" 1 font-lock-type-face t) ;; DTD declaration ;; ──────────────- ("\\(" . font-lock-comment-face); In lieu of a multiline pattern. ;; Element end ;; ──────────- ("\\(" 1 font-lock-comment-face) ;; Processing instruction ;; ────────────────────── ("\\(<\\?\\(?:[_[:alpha:]][-._[:alnum:]]*:\\)?\\)\\([_[:alpha:]][-._[:alnum:]]*\\)" (1 font-lock-comment-face) (2 font-lock-constant-face)) ("\\(\\?\\)>" 1 font-lock-comment-face)))))); In lieu of a multiline pattern (defun init/sh-mode () "Configure the shell-script mode, `sh-mode`." (defvar sh-mode-map); [FV] (add-hook 'sh-mode-hook (lambda (); Underived major mode, *-mode-map are defined only in here. (define-key sh-mode-map [tab] #'tab-to-tab-stop)))); Can still use C-i for indent. (defun init/string-lessp-i (string1 string2) "Like ‘string-lessp’ but ignores case." (setq string1(downcase string1)) (setq string2(downcase string2)) (string-lessp string1 string2)) (defface init/subdued `((t . (:inherit shadow))) "\ A face for noisy symbolic clutter that needs subduing." :group 'faces) (defun init/switch-to-next-buffer (&optional to-include-specials) "Page to the next buffer in lexicographic order. Exclude buffers with names starting or ending ‘*’ if TO-INCLUDE-SPECIALS is nil." (interactive) (delete-other-windows); In case visiting multiple initial files, when Emacs shows a split frame ;;; with a buffer list in the second window: this deletes that second window. Not sure how else to ;;; do this, or where better to place this call — both `after-init-hook` and `-funcall` operate too ;;; early, prior to load. Besides, it is not bad to see the buffer list as long as it goes away ;;; without effort, and this does the trick. (let ((bb (init/buffer-names-sorted to-include-specials)) (name (buffer-name))) (while bb (if (equal name (car bb)) (progn ;; Switch to next list entry, or first if current is last. (switch-to-buffer (or (car(cdr bb)) (car(init/buffer-names-sorted to-include-specials)))) (setq bb nil)) (setq bb (cdr bb)))))) (defun init/switch-to-previous-buffer (&optional to-include-specials) "Page to the previous buffer in lexicographic order. Exclude buffers with names starting or ending ‘*’ if TO-INCLUDE-SPECIALS is nil." (interactive) (delete-other-windows); Concordant with init/switch-to-next-buffer. (let ((bb (reverse (init/buffer-names-sorted to-include-specials))) (name (buffer-name))) (while bb (if (equal name (car bb)) (progn ;; Switch to previous list entry, or last if current is first. (switch-to-buffer (or (cadr bb) (car (last (init/buffer-names-sorted to-include-specials))))) (setq bb nil))) (setq bb (cdr bb))))) (defun init/task-sheet-mode () "Configure Task Sheet mode." (defvar task-sheet-mode-map); [FV] (add-hook 'task-sheet-mode-hook (lambda () (let ((m task-sheet-mode-map)) ;;; (init/sgml-common-mode m)) (define-key m [f11] [insert ?/ insert left down]) ;;; To overwrite a ‘/’, then move point directly beneath it. (was `toggle-frame-fullscreen`) (define-key m [?\t] #'tab-to-tab-stop)) ;;; (make-local-variable 'require-final-newline) ;;; (setq require-final-newline t) (setq indent-line-function #'init/indent-relative-plain))) (autoload 'task-sheet-mode "task-sheet-mode" init/autoload_docstring t); ↑ Q.v. at `http://reluk.ca/sys/computer/workstation/etc/emacs/`. (add-to-list 'auto-mode-alist '("[./]task$" . task-sheet-mode))) (defun init/set-for-buffer (variable value) "Set buffer-local VARIABLE (a symbol) to VALUE. Signal an error if the binding is not actually buffer-local. This might happen, for example, if an externally defined VARIABLE that was documented as being buffer-local no longer is." (set variable value) (cl-assert (local-variable-p variable))) (defvar init/task-sheet-toggle-mode-was); Used by `task-sheet-toggle-mode`, q.v. further below. (fset 'init/task-sheet-toggle-mode-was 'text-mode) ;;;(fset 'init/test "\223[^[:ascii:]]") ;;;(fset 'init/test [?\S-\C-\M-s ?\\ ?. ?h ?t ?m ?l ?\[ ?^ ?\" ?# ?< ?\]]) (defun init/test-mode () "Configure Test mode." (define-derived-mode test-mode text-mode "Test" "A major mode for testing purposes." (init/set-for-buffer 'truncate-lines t) (defconst test-line-spacing-original 4); Assumed for test purposes. (init/set-for-buffer 'line-spacing 0); One can selectively enlarge the spacing only, not zero it. ;;; Therefore zero it generally, then restore the original spacing on all but starred lines. (setq-local font-lock-extra-managed-props '(line-spacing)) (init/set-for-buffer 'font-lock-defaults '(test-fontifiers)) (defconst test-fontifiers (list (cons; A fontifier to restore the original, non-zero line spacing on all but starred `*` lines. (lambda (limit) (let ((p (point)) c found starred) (while (and (not found) (< p limit)) (setq c (char-after p)) (cond ((= c ?*) (setq starred t)) ((= c ?\n); A terminal newline. (if starred; Then keep going, seeking one that is unstarred. (setq starred nil) (setq found t)))); Else (being unstarred) restore the original line spacing. (setq p (1+ p))) (when found; The newline to propertize is just before `p`. (set-match-data (list (1- p) (goto-char p) (current-buffer))) t))); Returning t to Font Lock if `found`, else nil. '(0 (list 'face nil 'line-spacing test-line-spacing-original)))))); [NF] (set 'auto-mode-alist (cons (cons "\\.test\\'" 'test-mode) auto-mode-alist))) (defun init/test2-mode () "Configure Test2 mode." (define-derived-mode test2-mode text-mode "Test2" "Another major mode for testing purposes." (init/set-for-buffer 'truncate-lines t) ;;; (init/set-for-buffer 'line-spacing 4) (setq-local font-lock-extra-managed-props '(line-height)) (init/set-for-buffer 'font-lock-defaults '(test2-fontifiers)) (defconst test2-fontifiers (list (cons (lambda (limit) (let ((p (point)) c found starred) (while (and (not found) (< p limit)) (setq c (char-after p)) (cond ((= c ?*) (setq starred t)) ((= c ?\n) (when starred (setq found t)))) (setq p (1+ p))) (when found (set-match-data (list (1- p) (goto-char p) (current-buffer))) t))) '(0 (list 'face nil 'line-height 0)))))); [NF] (set 'auto-mode-alist (cons (cons "\\.test2\\'" 'test2-mode) auto-mode-alist))) (defun init/text-face-attribute-at-point (attribute &optional attribute-unnamed); Excludes overlay faces. ;;; Modified from `faces--attribute-at-point` of Emacs `faces.el` in order to exclude overlay faces ;;; by replacing all `get-char-property` with `get-text-property`. Licence GPL. (let ((faces (or (get-text-property (point) 'read-face-name) (and font-lock-mode (get-text-property (point) 'font-lock-face)) (get-text-property (point) 'face))) (found nil)) (dolist (face (if (face-list-p faces) faces (list faces))) (cond (found) ((and face (symbolp face)) (let ((value (face-attribute-specified-or (face-attribute face attribute nil t) nil))) (unless (member value '(nil "unspecified-fg" "unspecified-bg")) (setq found value)))) ((consp face) (setq found (cond ((and attribute-unnamed (memq attribute-unnamed face)) (cdr (memq attribute-unnamed face))) ((memq attribute face) (cadr (memq attribute face)))))))) (or found (face-attribute 'default attribute)))) (defun init/text-foreground-color-at-point (); Excludes overlay facing. Modified from `foreground- ;;; -color-at-point` of Emacs `faces.el` in order to exclude overlay faces. Licence GPL. (init/text-face-attribute-at-point :foreground 'foreground-color)) (defun init/text-mode () "Configure text mode." (let ((m text-mode-map)) (define-key m [?\t] #'tab-to-tab-stop)) (add-to-list 'auto-mode-alist '("/ChangeLog$" . text-mode))); Was Change Log, which is not Gentoo format. (defun init/waybrec () "Configure Waybrec Mode and other Waybreccian particulars." (load "waybrec-mode-autoloads" nil t); Q.v. at `http://reluk.ca/sys/computer/workstation/etc/emacs/`. (set 'auto-mode-alist (cons (cons "/way/.*\\.brec\\'" 'waybrec-mode) auto-mode-alist))) (defun init/wayscript-mode () "Configure `Wayscript mode`." ;;;(add-hook 'wayscript-mode-hook ;;; (lambda () ;;; (font-lock-add-keywords nil; 'nil' so it affects any derived modes, too. ;;; ;; ID assignment ;;; ;; ────────────- ;;; '((" id *= *\\(['\"]\\)\\(.+?\\)\\1" 2 font-lock-warning-face t))))) ;;; ;;; Override `init/sgml-mode`, toning down the colour soup. ;;;;;; Fails. (Is it how I defined Wayscript Mode? Or fontified it?). ;;;;;; Instead defeating in `init/sgml-mode`. (autoload 'wayscript-mode "wayscript-mode" init/autoload_docstring t); ↑ Q.v. at `http://reluk.ca/sys/computer/workstation/etc/emacs/`. (add-to-list 'auto-mode-alist '("^/home/mike/project/proto-waycast/.+\\.xht$" . wayscript-mode))) (defun init/x () "Configure Emacs for the X Window System." (global-set-key [S-down-mouse-1] #'mouse-save-then-kill); Was `mouse-set-font`. (global-set-key [mouse-3] #'mouse-set-font); The popup button, was mouse-save-then-kill. ;;; What was the purpose of this button swap? What button is `S-down-mouse-1`? ;;; (global-set-key [C-mouse-4] #'init/switch-to-previous-buffer) ;;; (global-set-key [C-mouse-5] #'init/switch-to-next-buffer) ;;; (global-unset-key [S-mouse-4]); Was `mwheel-scroll`, but (below) I bind that to `M-mouse-4`. ;;; (global-unset-key [S-mouse-5]) ;;;;;; I no longer have side buttons. (global-unset-key (kbd "")); Was `mouse-drag-secondary`. ; https://www.reddit.com/r/emacs/comments/3c61zl/abolish_the_secondary_selection_quick_and_easy/csszyto (global-unset-key (kbd "")); Was `mouse-set-secondary`. ; https://www.reddit.com/r/emacs/comments/3c61zl/abolish_the_secondary_selection_quick_and_easy/csszyto (global-unset-key (kbd "")); Was `mouse-start-secondary`. (global-unset-key (kbd "")); Was `mouse-yank-secondary`. (global-unset-key (kbd "")); Was `mouse-secondary-save-then-kill`. ;;; (global-set-key [M-mouse-4] #'mwheel-scroll) ;;; (global-set-key [M-mouse-5] #'mwheel-scroll) ;;;;;; I no longer have side buttons. (setq mouse-wheel-scroll-amount '(5 ((meta) . 1) )); 5 lines normally, but 1 when M modified. (setq select-enable-clipboard t); So the latest kill-ring entry is visible to other programs. (add-to-list 'default-frame-alist '(unsplittable . t)) ;; Cursor ;; ────── (blink-cursor-mode 0) ;;; (mouse-avoidance-mode 'cat-and-mouse) ;;;;;; But raises window whenever it scurries (defun adjust-cursor-type (&optional frame) "Set cursor style according to overwrite mode." (modify-frame-parameters (or frame (selected-frame)) (list (cons 'cursor-type (if overwrite-mode 'box 'bar))))) ;;; (defadvice overwrite-mode (after adjusted-cursor activate) (adjust-cursor-type)) ;;; (defadvice binary-overwrite-mode (after adjusted-cursor activate) (adjust-cursor-type)) ;;; (add-hook 'after-make-frame-functions #'adjust-cursor-type) ;;; (defadvice other-window (after adjusted-cursor activate) (adjust-cursor-type)) ;;; (defadvice switch-to-buffer (after adjusted-cursor activate) (adjust-cursor-type)) ;;;;;; Incomplete. Overwrite mode is per buffer, but cursor type is per frame. ;;;;;; Need more hooks to tie them together. Easier to use brute force: (add-hook 'post-command-hook #'adjust-cursor-type); OPT, it slows all commands. ;;;;;; But Emacs Lisp manual says the "buffer-local variable cursor-type overrides ;;;;;; the value of the cursor-type frame parameter", so maybe try that? (setq-default cursor-in-non-selected-windows 'hollow)) ;;; Else bar becomes (hardly distinguishable) thin bar. (defun task-sheet-toggle-mode () "Toggles between major modes ‘task-sheet-mode’ and the current mode." (interactive) (cond ((string= major-mode "task-sheet-mode") (init/task-sheet-toggle-mode-was)) (t (fset 'init/task-sheet-toggle-mode-was major-mode) (task-sheet-mode)))) (provide 'user-initialization) ;; NOTES ;; ───── ;; BUG This code is incorrect. ;; ;; FV · Suppressing sporadic compiler warnings ‘reference to free variable’ ;; or ‘assignment to free variable’. ;; ;; NF · In a search-based fontifier, a nil value for the `face` property of a list-form *facespec* ;; has the (undocumented) effect of leaving the face property untouched at its present value. ;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Search_002dbased-Fontification.html ;; ;; SLS Q.v. at `http://reluk.ca/project/Java/Emacs/jmt-mode.el`. ;; ;; TOP Too often pressed accidently. ;;; Licence GPL — q.v. above for source acknowledgements.