From cc6e35f6f43786dc75a7670a69939c3dcdbe4b7c Mon Sep 17 00:00:00 2001 From: Camden Dixie O'Brien Date: Fri, 1 Jan 2021 00:00:37 +0000 Subject: [PATCH] Implement case flipping thing Wasn't really sure where to put this in the current structure so made a new section called 'Custom Stuff' lol --- config.org | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 93 insertions(+) diff --git a/config.org b/config.org index b8ded2e..9668aeb 100644 --- a/config.org +++ b/config.org @@ -1102,3 +1102,96 @@ (add-to-list 'tramp-default-proxies-alist '((regexp-quote (system-name)) nil nil)) #+end_src + +* Custom Stuff +** Case-flipping + Want to be able to toggle the 'shiftedness' of a selected region, + that is, map uppercase to lowercase and vice versa, but also map + things like '1' to '!' and '[' to '{'. + + I doubt there's anything in Emacs already that has that mapping for + non-alphabetic characters, so first thing to do is define that: + + #+begin_src emacs-lisp + (defvar non-letter-case-mapping + '((?1 . ?!) (?2 . ?\") (?3 . ?£) (?4 . ?$) (?5 . ?%) + (?6 . ?^) (?7 . ?&) (?8 . ?*) (?9 . ?\() (?0 . ?\)) + (?- . ?_) (?= . ?+) (?\` . ?¬) (?\\ . ?\|) (?\[ . ?{) + (?\] . ?}) (?\; . ?:) (?\' . ?@) (?\# . ?~) (?\, . ?<) + (?\. . ?>) (?/ . ??))) + #+end_src + + And then, a function to toggle a non-letter character, using that + mapping, defaulting to the identity if there's no entry. + + #+begin_src emacs-lisp + (defun flip-non-letter-case (c) + (let (value) + (dolist (case-pair non-letter-case-mapping value) + (cond ((eq (car case-pair) c) + (setq value (cdr case-pair))) + ((eq (cdr case-pair) c) + (setq value (car case-pair))))) + (when (eq value nil) + (setq value c)) + value)) + #+end_src + + A similar function for letters can be easily defined using [[help:upcase][upcase]] + and [[help:downcase][downcase]]: + + #+begin_src emacs-lisp + (defun upper-case-p (c) + (eq (upcase c) c)) + + (defun flip-letter-case (c) + (if (upper-case-p c) + (downcase c) + (upcase c))) + #+end_src + + These can then be combined into a case-flipping function that will + work for both letters and non-letters: + + #+begin_src emacs-lisp + (defun letter-p (c) + (and (characterp c) + (let ((uc (upcase c))) + (and (>= uc ?A) (<= uc ?Z))))) + + (defun flip-char-case (c) + (if (letter-p c) + (flip-letter-case c) + (flip-non-letter-case c))) + #+end_src + + ~flip-char-case~ can then applied over a whole string: + + #+begin_src emacs-lisp + (defun flip-string-case (s) + (let ((len (length s)) + (i 0)) + (while (< i len) + (aset s i (flip-char-case (aref s i))) + (setq i (1+ i))) + s)) + #+end_src + + Finally, this can then be applied to the region, if it's active: + + #+begin_src emacs-lisp + (defun flip-case-region () + (interactive) + (when (region-active-p) + (let* ((start (region-beginning)) + (end (region-end)) + (text (buffer-substring-no-properties start end))) + (delete-region start end) + (insert (flip-string-case text))))) + #+end_src + + And of course, I need a keybinding for that: + + #+begin_src emacs-lisp + (global-set-key (kbd "C-~") 'flip-case-region) + #+end_src