From 2c72fd14cd1bdab0cd5bead7aad6b87e6f721dcd Mon Sep 17 00:00:00 2001 From: Case Duckworth Date: Mon, 8 Mar 2021 16:58:18 -0600 Subject: Add functions --- init.el | 80 ++++++++++++++++++++++++++++++++++++++--- lisp/acdw.el | 116 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 190 insertions(+), 6 deletions(-) diff --git a/init.el b/init.el index 7f6da30..4998f47 100644 --- a/init.el +++ b/init.el @@ -19,9 +19,81 @@ ;;; Code: ;; Add `acdw.el' -(add-to-list 'load-path (expand-file-name "lisp/" - user-emacs-directory)) +(push (expand-file-name "lisp/" + user-emacs-directory) + load-path) + (require 'acdw) -(autoload 'ehelp-command "ehelp") -(define-key acdw/map (kbd "C-h") #'ehelp-command) +;;; Good defaults + +;; Lines +(acdw/set '((fill-column 80))) +(global-display-fill-column-indicator-mode +1) +(add-hook 'text-mode-hook #'turn-on-auto-fill) +(add-hook 'prog-mode-hook #'turn-on-auto-fill) +(global-so-long-mode +1) +;; Whitespace +(acdw/set `((whitespace-style + (empty indentation space-before-tab space-after-tab)) + (indent-tabs-mode t) + (tab-width 8))) +(add-hook 'before-save-hook #'whitespace-cleanup) + +;; Pairs +(add-hook 'prog-mode-hook #'electric-pair-local-mode) +(acdw/set '((show-paren-delay 0) + (show-paren-style mixed) + (show-paren-when-point-inside-paren t) + (show-paren-when-point-in-periphery t))) +(show-paren-mode +1) + +;; Killing & Yanking +(delete-selection-mode +1) +(acdw/set `((save-interprogram-paste-before-kill t) + (yank-pop-change-selection t) + (x-select-enable-clipboard t) + (x-select-enable-primary t) + (mouse-drag-copy-region t) + (kill-do-not-save-duplicates t))) + +;; Encoding +(set-charset-priority 'unicode) +(set-language-environment "UTF-8") +(prefer-coding-system 'utf-8-unix) +(set-default-coding-systems 'utf-8-unix) +(set-terminal-coding-system 'utf-8-unix) +(set-keyboard-coding-system 'utf-8-unix) +(set-selection-coding-system 'utf-8-unix) +(acdw/set '((locale-coding-system utf-8-unix) + (coding-system-for-read utf-8-unix) + (coding-system-for-write utf-8-unix) + (buffer-file-coding-system utf-8-unix) + (org-export-coding-system utf-8-unix) + (org-html-coding-system utf-8-unix) + (default-process-coding-system (utf-8-unix . utf-8-unix)) + (x-select-request-type (UTF8_STRING COMPOUND_TEXT TEXT STRING)))) + +;; Backups +(acdw/set `((backup-by-copying t) + (delete-old-versions -1) + (version-control t) + (vc-make-backup-files t) + (backup-directory-alist ((".*" . ,(acdw/in-dir "backup/" t)))))) +;; Autosaves +(acdw/set `((auto-save-file-name-transforms + ((".*" ,(acdw/in-dir "auto-save/" t) t))) + (auto-save-list-file-prefix + ,(acdw/in-dir "auto-save-list/.saves-" t)))) +(auto-save-visited-mode +1) + +;; Cursor +(acdw/set '((cursor-type bar) + (cursor-in-non-selected-windows 'box))) + +(defun hook--overwrite-mode-change-cursor () + (setq cursor-type (if overwrite-mode t 'bar))) +(add-hook 'overwrite-mode-hook #'hook--overwrite-mode-change-cursor) + +;; Bindings +(acdw/bind "C-h" 'ehelp-command :autoload ("ehelp" nil nil 'keymap)) diff --git a/lisp/acdw.el b/lisp/acdw.el index 03e4a62..7f0145c 100644 --- a/lisp/acdw.el +++ b/lisp/acdw.el @@ -35,7 +35,7 @@ directory." (let ((f (expand-file-name (convert-standard-filename file) acdw/dir))) (when make-directory - (make-directory (file-name-directory) 'parents)) + (make-directory (file-name-directory file) 'parents)) f)) ;;; Settings @@ -45,7 +45,7 @@ directory." ASSIGNMENTS is a list where each element is of the form (VARIABLE VALUE [COMMENT])." - (dolist (assn assignments) + (dolist (assignment assignments) (customize-set-variable (car assignment) (cadr assignment) (if (and (caddr assignment) @@ -53,6 +53,118 @@ ASSIGNMENTS is a list where each element is of the form (caddr assignment) "Customized by `acdw/set'.")))) +;;; Faces + +(defun acdw/set-face (face spec) + "Customize FACE according to SPEC, and register it with `customize'. +SPEC is as for `defface'." + (put face 'customized-face spec) + (face-spec-set face spec)) + +(defmacro acdw/set-faces (face-specs) + "Run `acdw/set-face' over each face in FACE-SPECS." + (let (face-list) + (dolist (face face-specs) + (push `(acdw/set-face ',(car face) ',(cdr face)) face-list)) + `(progn + ,@face-list))) + +;;; Hooks + +;; XXX NOT WORKING +(defmacro acdw/defun-hook (hook docstring &optional depth local &rest forms) + "Add FORMS to a function described by DOCSTRING, then add that + function to HOOK. DOCSTRING is converted to a function name by + calling `docstring-to-symbol', if it's a string, or used as-is + otherwise. The optional DEPTH and LOCAL are passed to + `add-hook', if they're present (i.e., not a list). + +This macro aims to split the difference between the syntax of +lambdas in hooks and the ability to easily disable hooks." + (declare (indent 2)) + (let ((name (if (stringp docstring) + (docstring-to-symbol docstring "hook-") + docstring))) + (when (listp local) (push local forms) (setq local nil)) + (when (listp depth) (push depth forms) (setq depth 0)) + `(progn + (defun ,name () ,@forms) + (add-hook ,hook #',name ,depth ,local)))) + +(defmacro acdw/hooks (hooks funcs &optional depth local) + "Add FUNCS to HOOKS. + +Either HOOKS or FUNCS can be a list, in which case they're mapped +over to add all FUNCS to all HOOKS. They can also be singletons, +in which case `acdw/hooks' acts pretty much like `add-hook'. + +DEPTH and LOCAL apply to all HOOKS defined here. If you need +more fine-grained control, just use `add-hook'." + (let ((hooks (if (listp hooks) hooks (list hooks))) + (funcs (if (listp funcs) funcs (list funcs))) + (depth (if depth depth 0)) + (hook-list)) + (dolist (hook hooks) + (dolist (func funcs) + (push `(add-hook ',hook #',func ,depth ,local) hook-list))) + `(progn + ,@hook-list))) + +;; Utilities +(defun docstring-to-symbol (docstring &optional prefix) + "Convert a DOCSTRING to a symbol by lowercasing the string, +converting non-symbol-safe characters to '-', and calling + `intern'. Returns the created symbol." + (let ((str (split-string (downcase docstring) "[ \f\t\n\r\v'\"`,]+" + :omit-nulls))) + (when prefix (push prefix str)) + (intern (mapconcat #'identity str "-")))) + +;;; Keybindings + +(defvar acdw/bind-default-map 'acdw/map + "The default keymap to use with `acdw/bind'.") + +(defmacro acdw/bind (key command &rest args) + "A simple key-binding macro to take care of the repetitive stuff +automatically. + +If KEY is a vector, it's passed directly to `define-key', +otherwise it's wrapped in `read-kbd-macro'. + +The following keywords are recognized: + +:autoload ARGS .. call `autoload' on COMMAND using ARGS before + binding the key. ARGS can be just the filename to load; in + that case it's wrapped in a list. +:map KEYMAP .. define KEY in KEYMAP instead of the + default `acdw/bind-default-map'." + (let ((autoload (when-let (sym (plist-get args :autoload)) + (if (not (listp sym)) + (list sym) + sym))) + (keymap (or (plist-get args :map) acdw/bind-default-map)) + (keycode (if (vectorp key) key (kbd key))) + (command-list)) + (push `(define-key ,keymap ,keycode ,command) command-list) + (when autoload + (push `(autoload ,command ,@autoload) command-list)) + `(progn + ,@command-list))) + +;; convenience +(defmacro acdw/bind-after-map (file keymap &rest bindings) + "Wrap multiple calls of `acdw/bind' after FILE and with KEYMAP. +KEYMAP can be nil." + (declare (indent 2)) + (let (bind-list) + (dolist (binding bindings) + (if keymap + (push `(acdw/bind ,@binding :after ,file :map ,keymap) bind-list) + (push `(acdw/bind ,@binding :after ,file) bind-list))) + `(progn + ,@bind-list))) + ;;; Keymap & Mode (defvar acdw/map (make-sparse-keymap) -- cgit 1.4.1-21-gabe81