subtree(users/wpcarro): docking briefcase at '24f5a642'
				
					
				
			git-subtree-dir: users/wpcarro git-subtree-mainline:464bbcb15cgit-subtree-split:24f5a642afChange-Id: I6105b3762b79126b3488359c95978cadb3efa789
This commit is contained in:
		
						commit
						019f8fd211
					
				
					 766 changed files with 175420 additions and 0 deletions
				
			
		
							
								
								
									
										29
									
								
								users/wpcarro/emacs/.emacs.d/wpc/>.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								users/wpcarro/emacs/.emacs.d/wpc/>.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| ;;; >.el --- Small utility functions -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Originally I stored the `>>` macro in macros.el, but after setting up linting | ||||
| ;; for my Elisp in CI, `>>` failed because it didn't have the `macros-` | ||||
| ;; namespace.  I created this module to establish a `>-` namespace under which I | ||||
| ;; can store some utilities that would be best kept without a cumbersome | ||||
| ;; namespace. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defmacro >-> (&rest forms) | ||||
|   "Compose a new, point-free function by composing FORMS together." | ||||
|   (let ((sym (gensym))) | ||||
|     `(lambda (,sym) | ||||
|        (->> ,sym ,@forms)))) | ||||
| 
 | ||||
| 
 | ||||
| (provide '>) | ||||
| ;;; >.el ends here | ||||
							
								
								
									
										255
									
								
								users/wpcarro/emacs/.emacs.d/wpc/al.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										255
									
								
								users/wpcarro/emacs/.emacs.d/wpc/al.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,255 @@ | |||
| ;;; al.el --- Interface for working with associative lists -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Firstly, a rant: | ||||
| ;; In most cases, I find Elisp's APIs to be confusing.  There's a mixture of | ||||
| ;; overloaded functions that leak the implementation details (TODO: provide an | ||||
| ;; example of this.) of the abstract data type, which I find privileges those | ||||
| ;; "insiders" who spend disproportionately large amounts of time in Elisp land, | ||||
| ;; and other functions with little-to-no pattern about the order in which | ||||
| ;; arguments should be applied.  In theory, however, most of these APIs could | ||||
| ;; and should be much simpler.  This module represents a step in that direction. | ||||
| ;; | ||||
| ;; I'm modelling these APIs after Elixir's APIs. | ||||
| ;; | ||||
| ;; On my wishlist is to create protocols that will allow generic interfaces like | ||||
| ;; Enum protocols, etc.  Would be nice to abstract over... | ||||
| ;; - associative lists (i.e. alists) | ||||
| ;; - property lists (i.e. plists) | ||||
| ;; - hash tables | ||||
| ;; ...with some dictionary or map-like interface.  This will probably end up | ||||
| ;; being quite similar to the kv.el project but with differences at the API | ||||
| ;; layer. | ||||
| ;; | ||||
| ;; Similar libraries: | ||||
| ;; - map.el: Comes bundled with recent versions of Emacs. | ||||
| ;; - asoc.el: Helpers for working with alists.  asoc.el is similar to alist.el | ||||
| ;;   because it uses the "!" convention for signalling that a function mutates | ||||
| ;;   the underlying data structure. | ||||
| ;; - ht.el: Hash table library. | ||||
| ;; - kv.el: Library for dealing with key-value collections.  Note that map.el | ||||
| ;;   has a similar typeclass because it works with lists, hash-tables, or | ||||
| ;;   arrays. | ||||
| ;; - a.el: Clojure-inspired way of working with key-value data structures in | ||||
| ;; Elisp.  Works with alists, hash-tables, and sometimes vectors. | ||||
| ;; | ||||
| ;; Some API design principles: | ||||
| ;; - The "noun" (i.e. alist) of the "verb" (i.e. function) comes last to improve | ||||
| ;; composability with the threading macro (i.e. `->>') and to improve consumers' | ||||
| ;; intuition with the APIs.  Learn this once, know it always. | ||||
| ;; | ||||
| ;; - Every function avoids mutating the alist unless it ends with !. | ||||
| ;; | ||||
| ;; - CRUD operations will be named according to the following table: | ||||
| ;;   - "create" *and* "set" | ||||
| ;;   - "read"   *and* "get" | ||||
| ;;   - "update" | ||||
| ;;   - "delete" *and* "remove" | ||||
| ;; | ||||
| ;; For better or worse, all of this code expects alists in the form of: | ||||
| ;; ((first-name . "William") (last-name . "Carroll")) | ||||
| ;; | ||||
| ;; Special thanks to github.com/alphapapa/emacs-package-dev-handbook for some of | ||||
| ;; the idiomatic ways to update alists. | ||||
| ;; | ||||
| ;; TODO: Include a section that compares alist.el to a.el from | ||||
| ;; github.com/plexus/a.el. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies: | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'macros) | ||||
| (require 'dash) | ||||
| (require 'tuple) | ||||
| (require 'maybe) | ||||
| 
 | ||||
| ;; TODO: Support function aliases for: | ||||
| ;; - create/set | ||||
| ;; - read/get | ||||
| ;; - update | ||||
| ;; - delete/remove | ||||
| 
 | ||||
| ;; Support mutative variants of functions with an ! appendage to their name. | ||||
| 
 | ||||
| ;; Ensure that the same message about only updating the first occurrence of a | ||||
| ;; key is consistent throughout documentation using string interpolation or some | ||||
| ;; other mechanism. | ||||
| 
 | ||||
| ;; TODO: Consider wrapping all of this with `(cl-defstruct alist xs)'. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst al-enable-tests? t | ||||
|   "When t, run the test suite.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Support a variadic version of this to easily construct alists. | ||||
| (defun al-new () | ||||
|   "Return a new, empty alist." | ||||
|   '()) | ||||
| 
 | ||||
| ;; Create | ||||
| ;; TODO: See if this mutates. | ||||
| (defun al-set (k v xs) | ||||
|   "Set K to V in XS." | ||||
|   (if (al-has-key? k xs) | ||||
|       (progn | ||||
|         ;; Note: this is intentional `alist-get' and not `al-get'. | ||||
|         (setf (alist-get k xs) v) | ||||
|         xs) | ||||
|     (list-cons `(,k . ,v) xs))) | ||||
| 
 | ||||
| (defun al-set! (k v xs) | ||||
|   "Set K to V in XS mutatively. | ||||
| Note that this doesn't append to the alist in the way that most alists handle | ||||
|   writing.  If the k already exists in XS, it is overwritten." | ||||
|   (map-delete xs k) | ||||
|   (map-put! xs k v)) | ||||
| 
 | ||||
| ;; Read | ||||
| (defun al-get (k xs) | ||||
|   "Return the value at K in XS; otherwise, return nil. | ||||
| Returns the first occurrence of K in XS since alists support multiple entries." | ||||
|   (cdr (assoc k xs))) | ||||
| 
 | ||||
| (defun al-get-entry (k xs) | ||||
|   "Return the first key-value pair at K in XS." | ||||
|   (assoc k xs)) | ||||
| 
 | ||||
| ;; Update | ||||
| ;; TODO: Add warning about only the first occurrence being updated in the | ||||
| ;; documentation. | ||||
| (defun al-update (k f xs) | ||||
|   "Apply F to the value stored at K in XS. | ||||
| If `K' is not in `XS', this function errors.  Use `al-upsert' if you're | ||||
| interested in inserting a value when a key doesn't already exist." | ||||
|   (if (not (al-has-key? k xs)) | ||||
|       (error "Refusing to update: key does not exist in alist") | ||||
|     (al-set k (funcall f (al-get k xs)) xs))) | ||||
| 
 | ||||
| (defun al-update! (k f xs) | ||||
|   "Call F on the entry at K in XS. | ||||
| Mutative variant of `al-update'." | ||||
|   (al-set! k (funcall f (al-get k xs))xs)) | ||||
| 
 | ||||
| ;; TODO: Support this. | ||||
| (defun al-upsert (k v f xs) | ||||
|   "If K exists in `XS' call `F' on the value otherwise insert `V'." | ||||
|   (if (al-has-key? k xs) | ||||
|       (al-update k f xs) | ||||
|     (al-set k v xs))) | ||||
| 
 | ||||
| ;; Delete | ||||
| ;; TODO: Make sure `delete' and `remove' behave as advertised in the Elisp docs. | ||||
| (defun al-delete (k xs) | ||||
|   "Deletes the entry of K from XS. | ||||
| This only removes the first occurrence of K, since alists support multiple | ||||
|   key-value entries.  See `al-delete-all' and `al-dedupe'." | ||||
|   (remove (assoc k xs) xs)) | ||||
| 
 | ||||
| (defun al-delete! (k xs) | ||||
|   "Delete the entry of K from XS. | ||||
| Mutative variant of `al-delete'." | ||||
|   (delete (assoc k xs) xs)) | ||||
| 
 | ||||
| ;; Additions to the CRUD API | ||||
| ;; TODO: Implement this function. | ||||
| (defun al-dedupe-keys (xs) | ||||
|   "Remove the entries in XS where the keys are `equal'.") | ||||
| 
 | ||||
| (defun al-dedupe-entries (xs) | ||||
|   "Remove the entries in XS where the key-value pair are `equal'." | ||||
|   (delete-dups xs)) | ||||
| 
 | ||||
| (defun al-keys (xs) | ||||
|   "Return a list of the keys in XS." | ||||
|   (mapcar 'car xs)) | ||||
| 
 | ||||
| (defun al-values (xs) | ||||
|   "Return a list of the values in XS." | ||||
|   (mapcar 'cdr xs)) | ||||
| 
 | ||||
| (defun al-has-key? (k xs) | ||||
|   "Return t if XS has a key `equal' to K." | ||||
|   (maybe-some? (assoc k xs))) | ||||
| 
 | ||||
| (defun al-has-value? (v xs) | ||||
|   "Return t if XS has a value of V." | ||||
|   (maybe-some? (rassoc v xs))) | ||||
| 
 | ||||
| (defun al-count (xs) | ||||
|   "Return the number of entries in XS." | ||||
|   (length xs)) | ||||
| 
 | ||||
| ;; TODO: Should I support `al-find-key' and `al-find-value' variants? | ||||
| (defun al-find (p xs) | ||||
|   "Find an element in XS. | ||||
| 
 | ||||
| Apply a predicate fn, P, to each key and value in XS and return the key of the | ||||
| first element that returns t." | ||||
|   (let ((result (list-find (lambda (x) (funcall p (car x) (cdr x))) xs))) | ||||
|     (if result | ||||
|         (car result) | ||||
|       nil))) | ||||
| 
 | ||||
| (defun al-map-keys (f xs) | ||||
|   "Call F on the values in XS, returning a new alist." | ||||
|   (list-map (lambda (x) | ||||
|               `(,(funcall f (car x)) . ,(cdr x))) | ||||
|             xs)) | ||||
| 
 | ||||
| (defun al-map-values (f xs) | ||||
|   "Call F on the values in XS, returning a new alist." | ||||
|   (list-map (lambda (x) | ||||
|               `(,(car x) . ,(funcall f (cdr x)))) | ||||
|             xs)) | ||||
| 
 | ||||
| (defun al-reduce (acc f xs) | ||||
|   "Return a new alist by calling F on k v and ACC from XS. | ||||
| F should return a tuple.  See tuple.el for more information." | ||||
|   (->> (al-keys xs) | ||||
|        (list-reduce acc | ||||
|                     (lambda (k acc) | ||||
|                       (funcall f k (al-get k xs) acc))))) | ||||
| 
 | ||||
| (defun al-merge (a b) | ||||
|   "Return a new alist with a merge of alists, A and B. | ||||
| In this case, the last writer wins, which is B." | ||||
|   (al-reduce a #'al-set b)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (when al-enable-tests? | ||||
|   (prelude-assert | ||||
|    (equal '((2 . one) | ||||
|             (3 . two)) | ||||
|           (al-map-keys #'1+ | ||||
|                           '((1 . one) | ||||
|                             (2 . two))))) | ||||
|   (prelude-assert | ||||
|    (equal '((one . 2) | ||||
|             (two . 3)) | ||||
|           (al-map-values #'1+ | ||||
|                             '((one . 1) | ||||
|                               (two . 2)))))) | ||||
| 
 | ||||
| 
 | ||||
| ;; TODO: Support test cases for the entire API. | ||||
| 
 | ||||
| (provide 'al) | ||||
| ;;; al.el ends here | ||||
							
								
								
									
										71
									
								
								users/wpcarro/emacs/.emacs.d/wpc/bag.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								users/wpcarro/emacs/.emacs.d/wpc/bag.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,71 @@ | |||
| ;;; bag.el --- Working with bags (aka multi-sets) -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; What is a bag?  A bag should be thought of as a frequency table.  It's a way | ||||
| ;; to convert a list of something into a set that allows duplicates.  Isn't | ||||
| ;; allowing duplicates the whole thing with Sets?  Kind of.  But the interface | ||||
| ;; of Sets is something that bags resemble, so multi-set isn't as bag of a name | ||||
| ;; as it may first seem. | ||||
| ;; | ||||
| ;; If you've used Python's collections.Counter, the concept of a bag should be | ||||
| ;; familiar already. | ||||
| ;; | ||||
| ;; Interface: | ||||
| ;; - add        :: x -> Bag(x) -> Bag(x) | ||||
| ;; - remove     :: x -> Bag(x) -> Bag(x) | ||||
| ;; - union      :: Bag(x) -> Bag(x) -> Bag(x) | ||||
| ;; - difference :: Bag(x) -> Bag(x) -> Bag(x) | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'al) | ||||
| (require 'number) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defstruct bag xs) | ||||
| 
 | ||||
| (defun bag-update (f xs) | ||||
|   "Call F on alist in XS." | ||||
|   (let ((ys (bag-xs xs))) | ||||
|     (setf (bag-xs xs) (funcall f ys)))) | ||||
| 
 | ||||
| (defun bag-new () | ||||
|   "Create an empty bag." | ||||
|   (make-bag :xs (al-new))) | ||||
| 
 | ||||
| (defun bag-contains? (x xs) | ||||
|   "Return t if XS has X." | ||||
|   (al-has-key? x (bag-xs xs))) | ||||
| 
 | ||||
| ;; TODO: Tabling this for now since working with structs seems to be | ||||
| ;; disappointingly difficult.  Where is `struct-update'? | ||||
| ;; (defun bag-add (x xs) | ||||
| ;;   "Add X to XS.") | ||||
| 
 | ||||
| ;; TODO: What do we name delete vs. remove? | ||||
| ;; (defun bag-remove (x xs) | ||||
| ;;   "Remove X from XS. | ||||
| ;; This is a no-op is X doesn't exist in XS.") | ||||
| 
 | ||||
| (defun bag-from-list (xs) | ||||
|   "Map a list of `XS' into a bag." | ||||
|   (->> xs | ||||
|        (list-reduce | ||||
|         (bag-new) | ||||
|         (lambda (x acc) | ||||
|           (bag-add x 1 #'number-inc acc))))) | ||||
| 
 | ||||
| (provide 'bag) | ||||
| ;;; bag.el ends here | ||||
							
								
								
									
										100
									
								
								users/wpcarro/emacs/.emacs.d/wpc/bookmark.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								users/wpcarro/emacs/.emacs.d/wpc/bookmark.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,100 @@ | |||
| ;;; bookmark.el --- Saved files and directories on my filesystem -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; After enjoying and relying on Emacs's builtin `jump-to-register' command, I'd | ||||
| ;; like to recreate this functionality with a few extensions. | ||||
| ;; | ||||
| ;; Everything herein will mimmick my previous KBDs for `jump-to-register', which | ||||
| ;; were <leader>-j-<register-kbd>.  If the `bookmark-path' is a file, Emacs will | ||||
| ;; open a buffer with that file.  If the `bookmark-path' is a directory, Emacs | ||||
| ;; will open an ivy window searching that directory. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'f) | ||||
| (require 'buffer) | ||||
| (require 'list) | ||||
| (require 'string) | ||||
| (require 'set) | ||||
| (require 'constants) | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defstruct bookmark label path kbd) | ||||
| 
 | ||||
| ;; TODO: Consider hosting this function somewhere other than here, since it | ||||
| ;; feels useful above of the context of bookmarks. | ||||
| ;; TODO: Assess whether it'd be better to use the existing function: | ||||
| ;; `counsel-projectile-switch-project-action'.  See the noise I made on GH for | ||||
| ;; more context: https://github.com/ericdanan/counsel-projectile/issues/137 | ||||
| 
 | ||||
| (defun bookmark-handle-directory-dwim (path) | ||||
|   "Open PATH as either a project directory or a regular directory. | ||||
| If PATH is `projectile-project-p', open with `counsel-projectile-find-file'. | ||||
| Otherwise, open with `counsel-find-file'." | ||||
|   (if (projectile-project-p path) | ||||
|       (with-temp-buffer | ||||
|         (cd (projectile-project-p path)) | ||||
|         (call-interactively #'counsel-projectile-find-file)) | ||||
|     (let ((ivy-extra-directories nil)) | ||||
|       (counsel-find-file path)))) | ||||
| 
 | ||||
| (defconst bookmark-handle-directory #'bookmark-handle-directory-dwim | ||||
|   "Function to call when a bookmark points to a directory.") | ||||
| 
 | ||||
| (defconst bookmark-handle-file #'counsel-find-file-action | ||||
|   "Function to call when a bookmark points to a file.") | ||||
| 
 | ||||
| (defconst bookmark-whitelist | ||||
|   (list | ||||
|    (make-bookmark :label "briefcase" | ||||
|                   :path constants-briefcase | ||||
|                   :kbd "b") | ||||
|    (make-bookmark :label "current project" | ||||
|                   :path constants-current-project | ||||
|                   :kbd "p")) | ||||
|   "List of registered bookmarks.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; API | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun bookmark-open (b) | ||||
|   "Open bookmark, B, in a new buffer or an ivy minibuffer." | ||||
|   (let ((path (bookmark-path b))) | ||||
|     (cond | ||||
|      ((f-directory? path) | ||||
|       (funcall bookmark-handle-directory path)) | ||||
|      ((f-file? path) | ||||
|       (funcall bookmark-handle-file path))))) | ||||
| 
 | ||||
| 
 | ||||
| (defun bookmark-install-kbds () | ||||
|   "Install the keybindings defined herein." | ||||
|   (->> bookmark-whitelist | ||||
|        (list-map | ||||
|         (lambda (b) | ||||
|           (general-define-key | ||||
|            :prefix "<SPC>" | ||||
|            :states '(normal) | ||||
|            (format "J%s" (bookmark-kbd b)) | ||||
|            (lambda () (interactive) (find-file (bookmark-path b))) | ||||
|            (format "j%s" (bookmark-kbd b)) | ||||
|            ;; TODO: Consider `cl-labels' so `which-key' minibuffer is more | ||||
|            ;; helpful. | ||||
|            (lambda () (interactive) (bookmark-open b))))))) | ||||
| 
 | ||||
| (provide 'bookmark) | ||||
| ;;; bookmark.el ends here | ||||
							
								
								
									
										206
									
								
								users/wpcarro/emacs/.emacs.d/wpc/buffer.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										206
									
								
								users/wpcarro/emacs/.emacs.d/wpc/buffer.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,206 @@ | |||
| ;;; buffer.el --- Working with buffers -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Utilities for CRUDing buffers in Emacs. | ||||
| ;; | ||||
| ;; Many of these functions may seem unnecessary especially when you consider | ||||
| ;; there implementations.  In general I believe that Elisp suffers from a | ||||
| ;; library disorganization problem.  Providing simple wrapper functions that | ||||
| ;; rename functions or reorder parameters is worth the effort in my opinion if | ||||
| ;; it improves discoverability (via intuition) and improve composability. | ||||
| ;; | ||||
| ;; I support three ways for switching between what I'm calling "source code | ||||
| ;; buffers": | ||||
| ;; 1. Toggling previous: <SPC><SPC> | ||||
| ;; 2. Using `ivy-read': <SPC>b | ||||
| ;; TODO: These obscure evil KBDs.  Maybe a hydra definition would be best? | ||||
| ;; 3. Cycling (forwards/backwards): C-f, C-b | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'maybe) | ||||
| (require 'set) | ||||
| (require 'cycle) | ||||
| (require 'struct) | ||||
| (require 'ts) | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst buffer-enable-tests? t | ||||
|   "When t, run the test suite.") | ||||
| 
 | ||||
| (defconst buffer-install-kbds? t | ||||
|   "When t, install the keybindings defined herein.") | ||||
| 
 | ||||
| (defconst buffer-source-code-blacklist | ||||
|   (set-new 'dired-mode | ||||
|            'erc-mode | ||||
|            'vterm-mode | ||||
|            'magit-status-mode | ||||
|            'magit-process-mode | ||||
|            'magit-log-mode | ||||
|            'magit-diff-mode | ||||
|            'org-mode | ||||
|            'fundamental-mode) | ||||
|   "A blacklist of major-modes to ignore for listing source code buffers.") | ||||
| 
 | ||||
| (defconst buffer-source-code-timeout 2 | ||||
|   "Number of seconds to wait before invalidating the cycle.") | ||||
| 
 | ||||
| (cl-defstruct source-code-cycle cycle last-called) | ||||
| 
 | ||||
| (defun buffer-emacs-generated? (name) | ||||
|   "Return t if buffer, NAME, is an Emacs-generated buffer. | ||||
| Some buffers are Emacs-generated but are surrounded by whitespace." | ||||
|   (let ((trimmed (s-trim name))) | ||||
|     (and (s-starts-with? "*" trimmed)))) | ||||
| 
 | ||||
| (defun buffer-find (buffer-or-name) | ||||
|   "Find a buffer by its BUFFER-OR-NAME." | ||||
|   (get-buffer buffer-or-name)) | ||||
| 
 | ||||
| (defun buffer-major-mode (name) | ||||
|   "Return the active `major-mode' in buffer, NAME." | ||||
|   (with-current-buffer (buffer-find name) | ||||
|     major-mode)) | ||||
| 
 | ||||
| (defun buffer-source-code-buffers () | ||||
|   "Return a list of source code buffers. | ||||
| This will ignore Emacs-generated buffers, like *Messages*.  It will also ignore | ||||
|   any buffer whose major mode is defined in `buffer-source-code-blacklist'." | ||||
|   (->> (buffer-list) | ||||
|        (list-map #'buffer-name) | ||||
|        (list-reject #'buffer-emacs-generated?) | ||||
|        (list-reject (lambda (name) | ||||
|                       (set-contains? (buffer-major-mode name) | ||||
|                                      buffer-source-code-blacklist))))) | ||||
| 
 | ||||
| (defvar buffer-source-code-cycle-state | ||||
|   (make-source-code-cycle | ||||
|    :cycle (cycle-from-list (buffer-source-code-buffers)) | ||||
|    :last-called (ts-now)) | ||||
|   "State used to manage cycling between source code buffers.") | ||||
| 
 | ||||
| (defun buffer-exists? (name) | ||||
|   "Return t if buffer, NAME, exists." | ||||
|   (maybe-some? (buffer-find name))) | ||||
| 
 | ||||
| (defun buffer-new (name) | ||||
|   "Return a newly created buffer NAME." | ||||
|   (generate-new-buffer name)) | ||||
| 
 | ||||
| (defun buffer-find-or-create (name) | ||||
|   "Find or create buffer, NAME. | ||||
| Return a reference to that buffer." | ||||
|   (let ((x (buffer-find name))) | ||||
|     (if (maybe-some? x) | ||||
|         x | ||||
|       (buffer-new name)))) | ||||
| 
 | ||||
| ;; TODO: Should this consume: `display-buffer' or `switch-to-buffer'? | ||||
| (defun buffer-show (buffer-or-name) | ||||
|   "Display the BUFFER-OR-NAME, which is either a buffer reference or its name." | ||||
|   (display-buffer buffer-or-name)) | ||||
| 
 | ||||
| ;; TODO: Move this and `buffer-cycle-prev' into a separate module that | ||||
| ;; encapsulates all of this behavior. | ||||
| 
 | ||||
| (defun buffer-cycle (cycle-fn) | ||||
|   "Using CYCLE-FN, move through `buffer-source-code-buffers'." | ||||
|   (let ((last-called (source-code-cycle-last-called | ||||
|                       buffer-source-code-cycle-state)) | ||||
|         (cycle (source-code-cycle-cycle | ||||
|                 buffer-source-code-cycle-state))) | ||||
|     (if (> (ts-diff (ts-now) last-called) | ||||
|            buffer-source-code-timeout) | ||||
|         (progn | ||||
|           (struct-set! source-code-cycle | ||||
|                        cycle | ||||
|                        (cycle-from-list (buffer-source-code-buffers)) | ||||
|                        buffer-source-code-cycle-state) | ||||
|           (let ((cycle (source-code-cycle-cycle | ||||
|                         buffer-source-code-cycle-state))) | ||||
|             (funcall cycle-fn cycle) | ||||
|             (switch-to-buffer (cycle-current cycle))) | ||||
|           (struct-set! source-code-cycle | ||||
|                        last-called | ||||
|                        (ts-now) | ||||
|                        buffer-source-code-cycle-state)) | ||||
|       (progn | ||||
|         (funcall cycle-fn cycle) | ||||
|         (switch-to-buffer (cycle-current cycle)))))) | ||||
| 
 | ||||
| (defun buffer-cycle-next () | ||||
|   "Cycle forward through the `buffer-source-code-buffers'." | ||||
|   (interactive) | ||||
|   (buffer-cycle #'cycle-next)) | ||||
| 
 | ||||
| (defun buffer-cycle-prev () | ||||
|   "Cycle backward through the `buffer-source-code-buffers'." | ||||
|   (interactive) | ||||
|   (buffer-cycle #'cycle-prev)) | ||||
| 
 | ||||
| (defun buffer-ivy-source-code () | ||||
|   "Use `ivy-read' to choose among all open source code buffers." | ||||
|   (interactive) | ||||
|   (ivy-read "Source code buffer: " | ||||
|             (-drop 1 (buffer-source-code-buffers)) | ||||
|             :sort nil | ||||
|             :action #'switch-to-buffer)) | ||||
| 
 | ||||
| (defun buffer-show-previous () | ||||
|   "Call `switch-to-buffer' on the previously visited buffer. | ||||
| This function ignores Emacs-generated buffers, i.e. the ones that look like | ||||
|   this: *Buffer*.  It also ignores buffers that are `dired-mode' or `erc-mode'. | ||||
|   This blacklist can easily be changed." | ||||
|   (interactive) | ||||
|   (let* ((xs (buffer-source-code-buffers)) | ||||
|          (candidate (list-get 1 xs))) | ||||
|     (prelude-assert (maybe-some? candidate)) | ||||
|     (switch-to-buffer candidate))) | ||||
| 
 | ||||
| (when buffer-install-kbds? | ||||
|   (general-define-key | ||||
|    :states '(normal) | ||||
|    "C-f" #'buffer-cycle-next | ||||
|    "C-b" #'buffer-cycle-prev) | ||||
|   (general-define-key | ||||
|    :prefix "<SPC>" | ||||
|    :states '(normal) | ||||
|    "b" #'buffer-ivy-source-code | ||||
|    "<SPC>" #'buffer-show-previous | ||||
|    "k" #'kill-buffer)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (when buffer-enable-tests? | ||||
|   (prelude-assert | ||||
|    (list-all? #'buffer-emacs-generated? | ||||
|               '("*scratch*" | ||||
|                 "*Messages*" | ||||
|                 "*shell*" | ||||
|                 "*Shell Command Output*" | ||||
|                 "*Occur*" | ||||
|                 "*Warnings*" | ||||
|                 "*Help*" | ||||
|                 "*Completions*" | ||||
|                 "*Apropos*" | ||||
|                 "*info*")))) | ||||
| 
 | ||||
| (provide 'buffer) | ||||
| ;;; buffer.el ends here | ||||
							
								
								
									
										113
									
								
								users/wpcarro/emacs/.emacs.d/wpc/bytes.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								users/wpcarro/emacs/.emacs.d/wpc/bytes.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,113 @@ | |||
| ;;; bytes.el --- Working with byte values -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Functions to help with human-readable representations of byte values. | ||||
| ;; | ||||
| ;; Usage: | ||||
| ;; See the test cases for example usage.  Or better yet, I should use a type of | ||||
| ;; structured documentation that would allow me to expose a view into the test | ||||
| ;; suite here.  Is this currently possible in Elisp? | ||||
| ;; | ||||
| ;; API: | ||||
| ;; - serialize :: Integer -> String | ||||
| ;; | ||||
| ;; Wish list: | ||||
| ;; - Rounding: e.g. (bytes (* 1024 1.7)) => "2KB" | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;; TODO: Support -ibabyte variants like Gibibyte (GiB). | ||||
| 
 | ||||
| ;; Ranges: | ||||
| ;;  B: [   0,  1e3) | ||||
| ;; KB: [ 1e3,  1e6) | ||||
| ;; MB: [ 1e6,  1e6) | ||||
| ;; GB: [ 1e9, 1e12) | ||||
| ;; TB: [1e12, 1e15) | ||||
| ;; PB: [1e15, 1e18) | ||||
| ;; | ||||
| ;; Note: I'm currently not support exabytes because that causes the integer to | ||||
| ;;  overflow.  I imagine a larger integer type may exist, but for now, I'll | ||||
| ;;  treat this as a YAGNI. | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'tuple) | ||||
| (require 'math) | ||||
| (require 'number) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst bytes-kb (math-exp 2 10) | ||||
|   "Number of bytes in a kilobyte.") | ||||
| 
 | ||||
| (defconst bytes-mb (math-exp 2 20) | ||||
|   "Number of bytes in a megabytes.") | ||||
| 
 | ||||
| (defconst bytes-gb (math-exp 2 30) | ||||
|   "Number of bytes in a gigabyte.") | ||||
| 
 | ||||
| (defconst bytes-tb (math-exp 2 40) | ||||
|   "Number of bytes in a terabyte.") | ||||
| 
 | ||||
| (defconst bytes-pb (math-exp 2 50) | ||||
|   "Number of bytes in a petabyte.") | ||||
| 
 | ||||
| (defconst bytes-eb (math-exp 2 60) | ||||
|   "Number of bytes in an exabyte.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Functions | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun bytes-classify (x) | ||||
|   "Return unit that closest fits byte count, X." | ||||
|   (prelude-assert (number-whole? x)) | ||||
|   (cond | ||||
|    ((and (>= x 0)        (< x bytes-kb))     'byte) | ||||
|    ((and (>= x bytes-kb) (< x bytes-mb)) 'kilobyte) | ||||
|    ((and (>= x bytes-mb) (< x bytes-gb)) 'megabyte) | ||||
|    ((and (>= x bytes-gb) (< x bytes-tb)) 'gigabyte) | ||||
|    ((and (>= x bytes-tb) (< x bytes-pb)) 'terabyte) | ||||
|    ((and (>= x bytes-pb) (< x bytes-eb)) 'petabyte))) | ||||
| 
 | ||||
| (defun bytes-to-string (x) | ||||
|   "Convert integer X into a human-readable string." | ||||
|   (let ((base-and-unit | ||||
|          (pcase (bytes-classify x) | ||||
|            ('byte     (tuple/from        1 "B")) | ||||
|            ('kilobyte (tuple/from bytes-kb "KB")) | ||||
|            ('megabyte (tuple/from bytes-mb "MB")) | ||||
|            ('gigabyte (tuple/from bytes-gb "GB")) | ||||
|            ('terabyte (tuple/from bytes-tb "TB")) | ||||
|            ('petabyte (tuple/from bytes-pb "PB"))))) | ||||
|     (string-format "%d%s" | ||||
|                    (round x (tuple/first base-and-unit)) | ||||
|                    (tuple/second base-and-unit)))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (progn | ||||
|   (prelude-assert | ||||
|    (equal "1000B" (bytes-to-string 1000))) | ||||
|   (prelude-assert | ||||
|    (equal "2KB" (bytes-to-string (* 2 bytes-kb)))) | ||||
|   (prelude-assert | ||||
|    (equal "17MB" (bytes-to-string (* 17 bytes-mb)))) | ||||
|   (prelude-assert | ||||
|    (equal "419GB" (bytes-to-string (* 419 bytes-gb)))) | ||||
|   (prelude-assert | ||||
|    (equal "999TB" (bytes-to-string (* 999 bytes-tb)))) | ||||
|   (prelude-assert | ||||
|    (equal "2PB" (bytes-to-string (* 2 bytes-pb))))) | ||||
| 
 | ||||
| (provide 'bytes) | ||||
| ;;; bytes.el ends here | ||||
							
								
								
									
										89
									
								
								users/wpcarro/emacs/.emacs.d/wpc/cache.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								users/wpcarro/emacs/.emacs.d/wpc/cache.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,89 @@ | |||
| ;;; cache.el --- Caching things -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; An immutable cache data structure. | ||||
| ;; | ||||
| ;; This is like a sideways stack, that you can pull values out from and re-push | ||||
| ;; to the top.  It'd be like a stack supporting push, pop, pull. | ||||
| ;; | ||||
| ;; This isn't a key-value data-structure like you might expect from a | ||||
| ;; traditional cache.  The name is subject to change, but the underlying idea of | ||||
| ;; a cache remains the same. | ||||
| ;; | ||||
| ;; Think about prescient.el, which uses essentially an LRU cache integrated into | ||||
| ;; counsel to help create a "clairovoyant", self-organizing list. | ||||
| ;; | ||||
| ;; Use-cases: | ||||
| ;; - Keeps an cache of workspaces sorted as MRU with an LRU eviction strategy. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'struct) | ||||
| (require '>) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defstruct cache xs) | ||||
| 
 | ||||
| ;; TODO: Prefer another KBD for yasnippet form completion than company-mode's | ||||
| ;; current KBD. | ||||
| 
 | ||||
| (defun cache-from-list (xs) | ||||
|   "Turn list, XS, into a cache." | ||||
|   (make-cache :xs xs)) | ||||
| 
 | ||||
| (defun cache-contains? (x xs) | ||||
|   "Return t if X in XS." | ||||
|   (->> xs | ||||
|        cache-xs | ||||
|        (list-contains? x))) | ||||
| 
 | ||||
| (defun cache-touch (x xs) | ||||
|   "Ensure value X in cache, XS, is front of the list. | ||||
| If X isn't in XS (using `equal'), insert it at the front." | ||||
|   (struct-update | ||||
|    cache | ||||
|    xs | ||||
|    (>-> (list-reject (lambda (y) (equal x y))) | ||||
|        (list-cons x)) | ||||
|    xs)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (progn | ||||
|   (let ((cache (cache-from-list '("chicken" "nugget")))) | ||||
|     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|     ;; contains?/2 | ||||
|     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|     (prelude-refute | ||||
|      (cache-contains? "turkey" cache)) | ||||
|     (prelude-assert | ||||
|      (cache-contains? "chicken" cache)) | ||||
|     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|     ;; touch/2 | ||||
|     ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|     (prelude-assert | ||||
|      (equal | ||||
|       (cache-touch "nugget" cache) | ||||
|       (cache-from-list '("nugget" "chicken")))) | ||||
|     (prelude-assert | ||||
|      (equal | ||||
|       (cache-touch "spicy" cache) | ||||
|       (cache-from-list '("spicy" "chicken" "nugget")))))) | ||||
| 
 | ||||
| (provide 'cache) | ||||
| ;;; cache.el ends here | ||||
							
								
								
									
										44
									
								
								users/wpcarro/emacs/.emacs.d/wpc/clipboard.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								users/wpcarro/emacs/.emacs.d/wpc/clipboard.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,44 @@ | |||
| ;;; clipboard.el --- Working with X11's pasteboard -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Simple functions for copying and pasting. | ||||
| ;; | ||||
| ;; Integrate with bburns/clipmon so that System Clipboard can integrate with | ||||
| ;; Emacs's kill-ring. | ||||
| ;; | ||||
| ;; Wish list: | ||||
| ;; - Create an Emacs integration with github.com/cdown/clipmenud. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defun clipboard-copy (x &key (message "[clipboard.el] Copied!")) | ||||
|   "Copy string, X, to X11's clipboard and `message' MESSAGE." | ||||
|   (kill-new x) | ||||
|   (message message)) | ||||
| 
 | ||||
| (cl-defun clipboard-paste (&key (message "[clipboard.el] Pasted!")) | ||||
|   "Paste contents of X11 clipboard and `message' MESSAGE." | ||||
|   (yank) | ||||
|   (message message)) | ||||
| 
 | ||||
| (defun clipboard-contents () | ||||
|   "Return the contents of the clipboard as a string." | ||||
|   (substring-no-properties (current-kill 0))) | ||||
| 
 | ||||
| (provide 'clipboard) | ||||
| ;;; clipboard.el ends here | ||||
							
								
								
									
										86
									
								
								users/wpcarro/emacs/.emacs.d/wpc/colorscheme.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								users/wpcarro/emacs/.emacs.d/wpc/colorscheme.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | |||
| ;;; colorscheme.el --- Syntax highlight and friends -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; | ||||
| ;; TODO: Clarify this. | ||||
| ;; Since I have my own definition of "theme", which couples wallpaper, font, | ||||
| ;; with Emacs's traditional notion of the word "theme", I'm choosing to use | ||||
| ;; "colorscheme" to refer to *just* the notion of syntax highlight etc. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'cycle) | ||||
| (require '>) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defcustom colorscheme-whitelist | ||||
|   (cycle-from-list | ||||
|    (->> (custom-available-themes) | ||||
|         (list-map #'symbol-name) | ||||
|         (list-filter (>-> (s-starts-with? "doom-"))) | ||||
|         (list-map #'intern))) | ||||
|   "The whitelist of colorschemes through which to cycle.") | ||||
| 
 | ||||
| (defun colorscheme-current () | ||||
|   "Return the currently enabled colorscheme." | ||||
|   (cycle-current colorscheme-whitelist)) | ||||
| 
 | ||||
| (defun colorscheme-disable-all () | ||||
|   "Disable all currently enabled colorschemes." | ||||
|   (interactive) | ||||
|   (->> custom-enabled-themes | ||||
|        (list-map #'disable-theme))) | ||||
| 
 | ||||
| (defun colorscheme-set (theme) | ||||
|     "Call `load-theme' with `THEME', ensuring that the line numbers are bright. | ||||
| There is no hook that I'm aware of to handle this more elegantly." | ||||
|     (load-theme theme t) | ||||
|     (prelude-set-line-number-color "#da5468")) | ||||
| 
 | ||||
| (defun colorscheme-whitelist-set (colorscheme) | ||||
|   "Focus the COLORSCHEME in the `colorscheme-whitelist' cycle." | ||||
|   (cycle-focus (lambda (x) (equal x colorscheme)) colorscheme-whitelist) | ||||
|   (colorscheme-set (colorscheme-current))) | ||||
| 
 | ||||
| (defun colorscheme-ivy-select () | ||||
|   "Load a colorscheme using ivy." | ||||
|   (interactive) | ||||
|   (let ((theme (ivy-read "Theme: " (cycle-to-list colorscheme-whitelist)))) | ||||
|     (colorscheme-disable-all) | ||||
|     (colorscheme-set (intern theme)))) | ||||
| 
 | ||||
| (cl-defun colorscheme-cycle (&key forward?) | ||||
|   "Cycle next if `FORWARD?' is non-nil. | ||||
| Cycle prev otherwise." | ||||
|   (disable-theme (cycle-current colorscheme-whitelist)) | ||||
|   (let ((theme (if forward? | ||||
|                    (cycle-next colorscheme-whitelist) | ||||
|                  (cycle-prev colorscheme-whitelist)))) | ||||
|     (colorscheme-set theme) | ||||
|     (message (s-concat "Active theme: " (symbol-to-string theme))))) | ||||
| 
 | ||||
| (defun colorscheme-next () | ||||
|   "Disable the currently active theme and load the next theme." | ||||
|   (interactive) | ||||
|   (colorscheme-cycle :forward? t)) | ||||
| 
 | ||||
| (defun colorscheme-prev () | ||||
|   "Disable the currently active theme and load the previous theme." | ||||
|   (interactive) | ||||
|   (colorscheme-cycle :forward? nil)) | ||||
| 
 | ||||
| (provide 'colorscheme) | ||||
| ;;; colorscheme.el ends here | ||||
							
								
								
									
										55
									
								
								users/wpcarro/emacs/.emacs.d/wpc/constants.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										55
									
								
								users/wpcarro/emacs/.emacs.d/wpc/constants.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,55 @@ | |||
| ;;; constants.el --- Constants for organizing my Elisp -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; This file contains constants that are shared across my configuration. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'f) | ||||
| (require 'maybe) | ||||
| 
 | ||||
| (prelude-assert (f-exists? (getenv "BRIEFCASE"))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst constants-ci? | ||||
|   (maybe-some? (getenv "CI")) | ||||
|   "Encoded as t when Emacs is running in CI.") | ||||
| 
 | ||||
| (defconst constants-briefcase | ||||
|   (getenv "BRIEFCASE") | ||||
|   "Path to my monorepo, which various parts of my configuration rely on.") | ||||
| 
 | ||||
| ;; TODO: Consider merging `ui.el' and `misc.el' because those are the only | ||||
| ;; current consumers of these constants, and I'm unsure if the indirection that | ||||
| ;; globally defined constants introduces is worth it. | ||||
| 
 | ||||
| (defconst constants-current-project | ||||
|   constants-briefcase | ||||
|   "Variable holding the directory for my currently active project.") | ||||
| 
 | ||||
| (defconst constants-mouse-kbds | ||||
|   '([mouse-1] [down-mouse-1] [drag-mouse-1] [double-mouse-1] [triple-mouse-1] | ||||
|     [mouse-2] [down-mouse-2] [drag-mouse-2] [double-mouse-2] [triple-mouse-2] | ||||
|     [mouse-3] [down-mouse-3] [drag-mouse-3] [double-mouse-3] [triple-mouse-3] | ||||
|     [mouse-4] [down-mouse-4] [drag-mouse-4] [double-mouse-4] [triple-mouse-4] | ||||
|     [mouse-5] [down-mouse-5] [drag-mouse-5] [double-mouse-5] [triple-mouse-5]) | ||||
|   "All of the mouse-related keybindings that Emacs recognizes.") | ||||
| 
 | ||||
| (defconst constants-fill-column 80 | ||||
|   "Variable used to set the defaults for wrapping, highlighting, etc.") | ||||
| 
 | ||||
| (provide 'constants) | ||||
| ;;; constants.el ends here | ||||
							
								
								
									
										224
									
								
								users/wpcarro/emacs/.emacs.d/wpc/cycle.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										224
									
								
								users/wpcarro/emacs/.emacs.d/wpc/cycle.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,224 @@ | |||
| ;;; cycle.el --- Simple module for working with cycles -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Something like this may already exist, but I'm having trouble finding it, and | ||||
| ;; I think writing my own is a nice exercise for learning more Elisp. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'math) | ||||
| (require 'maybe) | ||||
| (require 'struct) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Wish list | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; - TODO: Provide immutable variant. | ||||
| ;; - TODO: Replace mutable consumption with immutable variant. | ||||
| ;; - TODO: Replace indexing with (math-mod current cycle). | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; `current-index' tracks the current index | ||||
| ;; `xs' is the original list | ||||
| (cl-defstruct cycle current-index previous-index xs) | ||||
| 
 | ||||
| (defconst cycle-enable-tests? t | ||||
|   "When t, run the tests defined herein.") | ||||
| 
 | ||||
| (defun cycle-from-list (xs) | ||||
|   "Create a cycle from a list of `XS'." | ||||
|   (if (= 0 (length xs)) | ||||
|       (make-cycle :current-index nil | ||||
|                   :previous-index nil | ||||
|                   :xs xs) | ||||
|     (make-cycle :current-index 0 | ||||
|                 :previous-index nil | ||||
|                 :xs xs))) | ||||
| 
 | ||||
| (defun cycle-new (&rest xs) | ||||
|   "Create a cycle with XS as the values." | ||||
|   (cycle-from-list xs)) | ||||
| 
 | ||||
| (defun cycle-to-list (xs) | ||||
|   "Return the list representation of a cycle, XS." | ||||
|   (cycle-xs xs)) | ||||
| 
 | ||||
| (defun cycle--next-index<- (lo hi x) | ||||
|   "Return the next index in a cycle when moving downwards. | ||||
| - `LO' is the lower bound. | ||||
| - `HI' is the upper bound. | ||||
| - `X' is the current index." | ||||
|   (if (< (- x 1) lo) | ||||
|       (- hi 1) | ||||
|     (- x 1))) | ||||
| 
 | ||||
| (defun cycle--next-index-> (lo hi x) | ||||
|   "Return the next index in a cycle when moving upwards. | ||||
| - `LO' is the lower bound. | ||||
| - `HI' is the upper bound. | ||||
| - `X' is the current index." | ||||
|   (if (>= (+ 1 x) hi) | ||||
|       lo | ||||
|     (+ 1 x))) | ||||
| 
 | ||||
| (defun cycle-previous-focus (cycle) | ||||
|   "Return the previously focused entry in CYCLE." | ||||
|   (let ((i (cycle-previous-index cycle))) | ||||
|     (if (maybe-some? i) | ||||
|         (nth i (cycle-xs cycle)) | ||||
|       nil))) | ||||
| 
 | ||||
| ;; TODO: Consider adding "!" to the function name herein since many of them | ||||
| ;; mutate the collection, and the APIs are beginning to confuse me. | ||||
| (defun cycle-focus-previous! (xs) | ||||
|   "Jump to the item in XS that was most recently focused; return the cycle. | ||||
| This will error when previous-index is nil.  This function mutates the | ||||
| underlying struct." | ||||
|   (let ((i (cycle-previous-index xs))) | ||||
|     (if (maybe-some? i) | ||||
|         (progn | ||||
|           (cycle-jump i xs) | ||||
|           (cycle-current xs)) | ||||
|       (error "Cannot focus the previous element since cycle-previous-index is nil")))) | ||||
| 
 | ||||
| (defun cycle-next (xs) | ||||
|   "Return the next value in `XS' and update `current-index'." | ||||
|   (let* ((current-index (cycle-current-index xs)) | ||||
|          (next-index (cycle--next-index-> 0 (cycle-count xs) current-index))) | ||||
|     (struct-set! cycle previous-index current-index xs) | ||||
|     (struct-set! cycle current-index next-index xs) | ||||
|     (nth next-index (cycle-xs xs)))) | ||||
| 
 | ||||
| (defun cycle-prev (xs) | ||||
|   "Return the previous value in `XS' and update `current-index'." | ||||
|   (let* ((current-index (cycle-current-index xs)) | ||||
|          (next-index (cycle--next-index<- 0 (cycle-count xs) current-index))) | ||||
|     (struct-set! cycle previous-index current-index xs) | ||||
|     (struct-set! cycle current-index next-index xs) | ||||
|     (nth next-index (cycle-xs xs)))) | ||||
| 
 | ||||
| (defun cycle-current (cycle) | ||||
|   "Return the current value in `CYCLE'." | ||||
|   (nth (cycle-current-index cycle) (cycle-xs cycle))) | ||||
| 
 | ||||
| (defun cycle-count (cycle) | ||||
|   "Return the length of `xs' in `CYCLE'." | ||||
|   (length (cycle-xs cycle))) | ||||
| 
 | ||||
| (defun cycle-jump (i xs) | ||||
|   "Jump to the I index of XS." | ||||
|   (let ((current-index (cycle-current-index xs)) | ||||
|         (next-index (math-mod i (cycle-count xs)))) | ||||
|     (struct-set! cycle previous-index current-index xs) | ||||
|     (struct-set! cycle current-index next-index xs)) | ||||
|   xs) | ||||
| 
 | ||||
| (defun cycle-focus (p cycle) | ||||
|   "Focus the element in CYCLE for which predicate, P, is t." | ||||
|   (let ((i (->> cycle | ||||
|                 cycle-xs | ||||
|                 (-find-index p)))) | ||||
|     (if i | ||||
|         (cycle-jump i cycle) | ||||
|       (error "No element in cycle matches predicate")))) | ||||
| 
 | ||||
| (defun cycle-focus-item (x xs) | ||||
|   "Focus item, X, in cycle XS. | ||||
| ITEM is the first item in XS that t for `equal'." | ||||
|   (cycle-focus (lambda (y) (equal x y)) xs)) | ||||
| 
 | ||||
| (defun cycle-contains? (x xs) | ||||
|   "Return t if cycle, XS, has member X." | ||||
|   (->> xs | ||||
|        cycle-xs | ||||
|        (list-contains? x))) | ||||
| 
 | ||||
| (defun cycle-empty? (xs) | ||||
|   "Return t if cycle XS has no elements." | ||||
|   (= 0 (length (cycle-xs xs)))) | ||||
| 
 | ||||
| (defun cycle-focused? (xs) | ||||
|   "Return t if cycle XS has a non-nil value for current-index." | ||||
|   (maybe-some? (cycle-current-index xs))) | ||||
| 
 | ||||
| (defun cycle-append (x xs) | ||||
|   "Add X to the left of the focused element in XS. | ||||
| If there is no currently focused item, add X to the beginning of XS." | ||||
|   (if (cycle-empty? xs) | ||||
|       (progn | ||||
|         (struct-set! cycle xs (list x) xs) | ||||
|         (struct-set! cycle current-index 0 xs) | ||||
|         (struct-set! cycle previous-index nil xs)) | ||||
|     (let ((curr-i (cycle-current-index xs)) | ||||
|           (prev-i (cycle-previous-index xs))) | ||||
|       (if curr-i | ||||
|           (progn | ||||
|             (struct-set! cycle xs (-insert-at curr-i x (cycle-xs xs)) xs) | ||||
|             (when (>= prev-i curr-i) (struct-set! cycle previous-index (1+ prev-i) xs)) | ||||
|             (when curr-i (struct-set! cycle current-index (1+ curr-i) xs))) | ||||
|         (progn | ||||
|           (struct-set! cycle xs (cons x (cycle-xs xs)) xs) | ||||
|           (when prev-i (struct-set! cycle previous-index (1+ prev-i) xs)))) | ||||
|       xs))) | ||||
| 
 | ||||
| (defun cycle-remove (x xs) | ||||
|   "Attempt to remove X from XS. | ||||
| 
 | ||||
| X is found using `equal'. | ||||
| 
 | ||||
| If X is the currently focused value, after it's deleted, current-index will be | ||||
|   nil.  If X is the previously value, after it's deleted, previous-index will be | ||||
|   nil." | ||||
|   (let ((curr-i (cycle-current-index xs)) | ||||
|         (prev-i (cycle-previous-index xs)) | ||||
|         (rm-i (-elem-index x (cycle-xs xs)))) | ||||
|     (struct-set! cycle xs (-remove-at rm-i (cycle-xs xs)) xs) | ||||
|     (when prev-i | ||||
|       (when (> prev-i rm-i) (struct-set! cycle previous-index (1- prev-i) xs)) | ||||
|       (when (= prev-i rm-i) (struct-set! cycle previous-index nil xs))) | ||||
|     (when curr-i | ||||
|       (when (> curr-i rm-i) (struct-set! cycle current-index (1- curr-i) xs)) | ||||
|       (when (= curr-i rm-i) (struct-set! cycle current-index nil xs))) | ||||
|     xs)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (when cycle-enable-tests? | ||||
|   (let ((xs (cycle-new 1 2 3))) | ||||
|     (prelude-assert (maybe-nil? (cycle-previous-focus xs))) | ||||
|     (prelude-assert (= 1 (cycle-current xs))) | ||||
|     (prelude-assert (= 2 (cycle-next xs))) | ||||
|     (prelude-assert (= 1 (cycle-previous-focus xs))) | ||||
|     (prelude-assert (= 1 (->> xs (cycle-jump 0) cycle-current))) | ||||
|     (prelude-assert (= 2 (->> xs (cycle-jump 1) cycle-current))) | ||||
|     (prelude-assert (= 3 (->> xs (cycle-jump 2) cycle-current))) | ||||
|     (prelude-assert (= 2 (cycle-previous-focus xs))) | ||||
|     (prelude-assert (= 2 (cycle-focus-previous! xs))) | ||||
|     (prelude-assert (equal '(1 4 2 3) (cycle-xs (cycle-append 4 xs)))) | ||||
|     (prelude-assert (equal '(1 2 3) (cycle-xs (cycle-remove 4 xs)))) | ||||
|     (progn | ||||
|       (cycle-focus-item 3 xs) | ||||
|       (cycle-focus-item 2 xs) | ||||
|       (cycle-remove 1 xs) | ||||
|       (prelude-assert (= 2 (cycle-current xs))) | ||||
|       (prelude-assert (= 3 (cycle-previous-focus xs)))))) | ||||
| 
 | ||||
| (provide 'cycle) | ||||
| ;;; cycle.el ends here | ||||
							
								
								
									
										50
									
								
								users/wpcarro/emacs/.emacs.d/wpc/device.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										50
									
								
								users/wpcarro/emacs/.emacs.d/wpc/device.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,50 @@ | |||
| ;;; device.el --- Physical device information -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Functions for querying device information. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'dash) | ||||
| (require 'al) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst device-hostname->device | ||||
|   '(("zeno.lon.corp.google.com" . work-desktop) | ||||
|     ("seneca" . work-laptop)) | ||||
|   "Mapping hostname to a device symbol.") | ||||
| 
 | ||||
| ;; TODO: Should I generate these predicates? | ||||
| 
 | ||||
| (defun device-classify () | ||||
|   "Return the device symbol for the current host or nil if not supported." | ||||
|   (al-get system-name device-hostname->device)) | ||||
| 
 | ||||
| (defun device-work-laptop? () | ||||
|   "Return t if current device is work laptop." | ||||
|   (equal 'work-laptop | ||||
|          (device-classify))) | ||||
| 
 | ||||
| (defun device-work-desktop? () | ||||
|   "Return t if current device is work desktop." | ||||
|   (equal 'work-desktop | ||||
|          (device-classify))) | ||||
| 
 | ||||
| (defun device-corporate? () | ||||
|   "Return t if the current device is owned by my company." | ||||
|   (or (device-work-laptop?) (device-work-desktop?))) | ||||
| 
 | ||||
| (provide 'device) | ||||
| ;;; device.el ends here | ||||
							
								
								
									
										138
									
								
								users/wpcarro/emacs/.emacs.d/wpc/display.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								users/wpcarro/emacs/.emacs.d/wpc/display.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,138 @@ | |||
| ;;; display.el --- Working with single or multiple displays -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Mostly wrappers around xrandr. | ||||
| ;; | ||||
| ;; Troubleshooting: | ||||
| ;; The following commands help me when I (infrequently) interact with xrandr. | ||||
| ;; - xrandr --listmonitors | ||||
| ;; - xrandr --query | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'dash) | ||||
| (require 's) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defmacro display-register (name &key | ||||
|                                     output | ||||
|                                     primary | ||||
|                                     coords | ||||
|                                     size | ||||
|                                     rate | ||||
|                                     dpi | ||||
|                                     rotate) | ||||
|   "Macro to define constants and two functions for {en,dis}abling a display. | ||||
| 
 | ||||
| NAME    - the human-readable identifier for the display | ||||
| OUTPUT  - the xrandr identifier for the display | ||||
| PRIMARY - if true, send --primary flag to xrandr | ||||
| COORDS  - X and Y offsets | ||||
| SIZE    - the pixel resolution of the display (width height) | ||||
| RATE    - the refresh rate | ||||
| DPI     - the pixel density in dots per square inch | ||||
| rotate  - one of {normal,left,right,inverted} | ||||
| 
 | ||||
| See the man-page for xrandr for more details." | ||||
|   `(progn | ||||
|      (defconst ,(intern (format "display-%s" name)) ,output | ||||
|        ,(format "The xrandr identifier for %s" name)) | ||||
|      (defconst ,(intern (format "display-%s-args" name)) | ||||
|        ,(replace-regexp-in-string | ||||
|          "\s+" " " | ||||
|          (s-format "--output ${output} ${primary-flag} --auto \ | ||||
|                     --size ${size-x}x${size-y} --rate ${rate} --dpi ${dpi} \ | ||||
|                     --rotate ${rotate} ${pos-flag}" | ||||
|                    #'aget | ||||
|                    `(("output" . ,output) | ||||
|                      ("primary-flag" . ,(if primary "--primary" "--noprimary")) | ||||
|                      ("pos-flag" . ,(if coords | ||||
|                                         (format "--pos %dx%d" | ||||
|                                                 (car coords) | ||||
|                                                 (cadr coords)) | ||||
|                                       "")) | ||||
|                      ("size-x" . ,(car size)) | ||||
|                      ("size-y" . ,(cadr size)) | ||||
|                      ("rate" . ,rate) | ||||
|                      ("dpi" . ,dpi) | ||||
|                      ("rotate" . ,rotate)))) | ||||
|        ,(format "The arguments we pass to xrandr for display-%s." name)) | ||||
|      (defconst ,(intern (format "display-%s-command" name)) | ||||
|        (format "xrandr %s" ,(intern (format "display-%s-args" name))) | ||||
|        ,(format "The command we run to configure %s" name)) | ||||
|      (defun ,(intern (format "display-enable-%s" name)) () | ||||
|        ,(format "Attempt to enable my %s monitor" name) | ||||
|        (interactive) | ||||
|        (prelude-start-process | ||||
|         :name ,(format "display-enable-%s" name) | ||||
|         :command ,(intern (format "display-%s-command" name)))) | ||||
|      (defun ,(intern (format "display-disable-%s" name)) () | ||||
|        ,(format "Attempt to disable my %s monitor." name) | ||||
|        (interactive) | ||||
|        (prelude-start-process | ||||
|         :name ,(format "display-disable-%s" name) | ||||
|         :command ,(format | ||||
|                    "xrandr --output %s --off" | ||||
|                    output))))) | ||||
| 
 | ||||
| (defmacro display-arrangement (name &key displays) | ||||
|   "Create a function, display-arrange-<NAME>, to enable all your DISPLAYS." | ||||
|   `(defun ,(intern (format "display-arrange-%s" name)) () | ||||
|      (interactive) | ||||
|      (prelude-start-process | ||||
|       :name ,(format "display-configure-%s" name) | ||||
|       :command ,(format "xrandr %s" | ||||
|                         (->> displays | ||||
|                              (-map (lambda (x) | ||||
|                                      (eval (intern (format "display-%s-args" x))))) | ||||
|                              (s-join " ")))))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (display-register laptop | ||||
|                   :output "eDP1" | ||||
|                   :primary nil | ||||
|                   :coords (2560 1440) | ||||
|                   :size (1920 1080) | ||||
|                   :rate 30.0 | ||||
|                   :dpi 144 | ||||
|                   :rotate normal) | ||||
| 
 | ||||
| (display-register 4k-horizontal | ||||
|                   :output "DP2" | ||||
|                   :primary t | ||||
|                   :coords (0 0) | ||||
|                   :size (2560 1440) | ||||
|                   :rate 30.0 | ||||
|                   :dpi 144 | ||||
|                   :rotate normal) | ||||
| 
 | ||||
| (display-register 4k-vertical | ||||
|                   :output "HDMI1" | ||||
|                   :primary nil | ||||
|                   :coords (-1440 -560) | ||||
|                   :size (2560 1440) | ||||
|                   :rate 30.0 | ||||
|                   :dpi 144 | ||||
|                   :rotate left) | ||||
| 
 | ||||
| (display-arrangement primary | ||||
|                      :displays (laptop 4k-horizontal 4k-vertical)) | ||||
| 
 | ||||
| (provide 'display) | ||||
| ;;; display.el ends here | ||||
							
								
								
									
										58
									
								
								users/wpcarro/emacs/.emacs.d/wpc/dotted.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								users/wpcarro/emacs/.emacs.d/wpc/dotted.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| ;;; dotted.el --- Working with dotted pairs in Elisp -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Part of my primitives library extensions in Elisp.  Contrast my primitives | ||||
| ;; with the wrapper extensions that I provide, which expose immutable variants | ||||
| ;; of data structures like an list, alist, tuple, as well as quasi-typeclasses | ||||
| ;; like sequence, etc. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'macros) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defun dotted-new (&optional a b) | ||||
|   "Create a new dotted pair of A and B." | ||||
|   (cons a b)) | ||||
| 
 | ||||
| (defun dotted-instance? (x) | ||||
|   "Return t if X is a dotted pair." | ||||
|   (let ((b (cdr x))) | ||||
|     (and b (atom b)))) | ||||
| 
 | ||||
| (defun dotted-first (x) | ||||
|   "Return the first element of X." | ||||
|   (car x)) | ||||
| 
 | ||||
| (defun dotted-second (x) | ||||
|   "Return the second element of X." | ||||
|   (cdr x)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (progn | ||||
|   (prelude-assert | ||||
|    (equal '(fname . "Bob") (dotted-new 'fname "Bob"))) | ||||
|   (prelude-assert | ||||
|    (dotted-instance? '(one . two))) | ||||
|   (prelude-refute | ||||
|    (dotted-instance? '(1 2 3)))) | ||||
| 
 | ||||
| (provide 'dotted) | ||||
| ;;; dotted.el ends here | ||||
							
								
								
									
										77
									
								
								users/wpcarro/emacs/.emacs.d/wpc/email.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								users/wpcarro/emacs/.emacs.d/wpc/email.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,77 @@ | |||
| ;;; email.el --- My email settings -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Attempting to configure to `notmuch' for my personal use. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'notmuch) | ||||
| (require 'list) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (setq notmuch-saved-searches | ||||
|       '((:name "inbox" :query "tag:inbox" :key "i") | ||||
|         (:name "direct" | ||||
|          :query "tag:direct and tag:unread and not tag:sent" | ||||
|          :key "d") | ||||
|         (:name "action" :query "tag:action" :key "a") | ||||
|         (:name "review" :query "tag:review" :key "r") | ||||
|         (:name "waiting" :query "tag:waiting" :key "w") | ||||
|         (:name "broadcast" :query "tag:/broadcast\/.+/ and tag:unread" :key "b") | ||||
|         (:name "systems" :query "tag:/systems\/.+/ and tag:unread" :key "s") | ||||
|         (:name "sent" :query "tag:sent" :key "t") | ||||
|         (:name "drafts" :query "tag:draft" :key "D"))) | ||||
| 
 | ||||
| ;; Sort results from newest-to-oldest. | ||||
| (setq notmuch-search-oldest-first nil) | ||||
| 
 | ||||
| ;; Discard noisy email signatures. | ||||
| (setq notmuch-mua-cite-function #'message-cite-original-without-signature) | ||||
| 
 | ||||
| ;; By default, this is just '("-inbox") | ||||
| (setq notmuch-archive-tags '("-inbox" "-unread" "+archive")) | ||||
| 
 | ||||
| ;; Show saved searches even when they're empty. | ||||
| (setq notmuch-show-empty-saved-searches t) | ||||
| 
 | ||||
| ;; Currently the sendmail executable on my system is symlinked to msmtp. | ||||
| (setq send-mail-function #'sendmail-send-it) | ||||
| 
 | ||||
| ;; I'm not sure if I need this or not. Copying it from tazjin@'s monorepo. | ||||
| (setq notmuch-always-prompt-for-sender nil) | ||||
| 
 | ||||
| ;; Add the "User-Agent" header to my emails and ensure that it includes Emacs | ||||
| ;; and notmuch information. | ||||
| (setq notmuch-mua-user-agent-function | ||||
|       (lambda () | ||||
|         (format "Emacs %s; notmuch.el %s" emacs-version notmuch-emacs-version))) | ||||
| 
 | ||||
| ;; I was informed that Gmail does this server-side | ||||
| (setq notmuch-fcc-dirs nil) | ||||
| 
 | ||||
| ;; Ensure buffers are closed after sending mail. | ||||
| (setq message-kill-buffer-on-exit t) | ||||
| 
 | ||||
| ;; Ensure sender is correctly passed to msmtp. | ||||
| (setq mail-specify-envelope-from t | ||||
|       message-sendmail-envelope-from 'header | ||||
|       mail-envelope-from 'header) | ||||
| 
 | ||||
| ;; Assert that no two saved searches share share a KBD | ||||
| (prelude-assert | ||||
|  (list-xs-distinct-by? (lambda (x) (plist-get x :key)) notmuch-saved-searches)) | ||||
| 
 | ||||
| (provide 'email) | ||||
| ;;; email.el ends here | ||||
							
								
								
									
										172
									
								
								users/wpcarro/emacs/.emacs.d/wpc/fonts.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										172
									
								
								users/wpcarro/emacs/.emacs.d/wpc/fonts.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,172 @@ | |||
| ;;; fonts.el --- Font preferences -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Control my font preferences with ELisp. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;; TODO: `defcustom' font-size. | ||||
| ;; TODO: `defcustom' fonts. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'cycle) | ||||
| (require 'device) | ||||
| (require 'maybe) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Troubleshoot why "8" appears so large on my desktop. | ||||
| 
 | ||||
| ;; TODO: Consider having a different font size when I'm using my 4K monitor. | ||||
| 
 | ||||
| (defconst fonts-size | ||||
|   (pcase (device-classify) | ||||
|     ('work-laptop "10") | ||||
|     ('work-desktop "10")) | ||||
|   "My preferred default font-size, which is device specific.") | ||||
| 
 | ||||
| (defconst fonts-size-step 10 | ||||
|   "The amount (%) by which to increase or decrease a font.") | ||||
| 
 | ||||
| (defconst fonts-hacker-news-recommendations | ||||
|   '("APL385 Unicode" | ||||
|     "Go Mono" | ||||
|     "Sudo" | ||||
|     "Monoid" | ||||
|     "Input Mono Medium" ;; NOTE: Also "Input Mono Thin" is nice. | ||||
|     ) | ||||
|   "List of fonts optimized for programming I found in a HN article.") | ||||
| 
 | ||||
| (defconst fonts-whitelist | ||||
|   (cycle-from-list | ||||
|    (list-concat | ||||
|     fonts-hacker-news-recommendations | ||||
|     '("JetBrainsMono" | ||||
|       "Mononoki Medium" | ||||
|       "Monospace" | ||||
|       "Operator Mono Light" | ||||
|       "Courier" | ||||
|       "Andale Mono" | ||||
|       "Source Code Pro" | ||||
|       "Terminus"))) | ||||
|   "This is a list of my preferred fonts.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Functions | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: fonts and fonts-whitelist make it difficult to name functions like | ||||
| ;; fonts-set as a generic Emacs function vs choosing a font from the whitelist. | ||||
| 
 | ||||
| (cl-defun fonts-cycle (&key forward?) | ||||
|   "Cycle forwards when `FORWARD?' non-nil." | ||||
|   (let ((font (if forward? | ||||
|                   (cycle-next fonts-whitelist) | ||||
|                 (cycle-prev fonts-whitelist)))) | ||||
|     (message (s-concat "Active font: " font)) | ||||
|     (fonts-set font))) | ||||
| 
 | ||||
| (defun fonts-next () | ||||
|   "Quickly cycle through preferred fonts." | ||||
|   (interactive) | ||||
|   (fonts-cycle :forward? t)) | ||||
| 
 | ||||
| (defun fonts-prev () | ||||
|   "Quickly cycle through preferred fonts." | ||||
|   (interactive) | ||||
|   (fonts-cycle :forward? nil)) | ||||
| 
 | ||||
| (defun fonts-set (font &optional size) | ||||
|   "Change the font to `FONT' with option integer, SIZE, in pixels." | ||||
|   (if (maybe-some? size) | ||||
|       (set-frame-font (string-format "%s %s" font size) nil t) | ||||
|     (set-frame-font font nil t))) | ||||
| 
 | ||||
| (defun fonts-whitelist-set (font) | ||||
|   "Focuses the FONT in the `fonts-whitelist' cycle. | ||||
| The size of the font is determined by `fonts-size'." | ||||
|   (prelude-assert (cycle-contains? font fonts-whitelist)) | ||||
|   (cycle-focus (lambda (x) (equal x font)) fonts-whitelist) | ||||
|   (fonts-set (fonts-current) fonts-size)) | ||||
| 
 | ||||
| (defun fonts-ivy-select () | ||||
|   "Select a font from an ivy prompt." | ||||
|   (interactive) | ||||
|   (fonts-whitelist-set | ||||
|    (ivy-read "Font: " (cycle-to-list fonts-whitelist)))) | ||||
| 
 | ||||
| (defun fonts-print-current () | ||||
|   "Message the currently enabled font." | ||||
|   (interactive) | ||||
|   (message | ||||
|    (string-format "[fonts] Current font: \"%s\"" | ||||
|                   (fonts-current)))) | ||||
| 
 | ||||
| (defun fonts-current () | ||||
|   "Return the currently enabled font." | ||||
|   (cycle-current fonts-whitelist)) | ||||
| 
 | ||||
| (defun fonts-increase-size () | ||||
|   "Increase font size." | ||||
|   (interactive) | ||||
|   (->> (face-attribute 'default :height) | ||||
|        (+ fonts-size-step) | ||||
|        (set-face-attribute 'default (selected-frame) :height))) | ||||
| 
 | ||||
| (defun fonts-decrease-size () | ||||
|   "Decrease font size." | ||||
|   (interactive) | ||||
|   (->> (face-attribute 'default :height) | ||||
|        (+ (- fonts-size-step)) | ||||
|        (set-face-attribute 'default (selected-frame) :height))) | ||||
| 
 | ||||
| (defun fonts-reset-size () | ||||
|   "Restore font size to its default value." | ||||
|   (interactive) | ||||
|   (fonts-whitelist-set (fonts-current))) | ||||
| 
 | ||||
| (defun fonts-enable-ligatures () | ||||
|   "Call this function to enable ligatures." | ||||
|   (interactive) | ||||
|   (let ((alist '((33 . ".\\(?:\\(?:==\\|!!\\)\\|[!=]\\)") | ||||
|                  (35 . ".\\(?:###\\|##\\|_(\\|[#(?[_{]\\)") ;; | ||||
|                  (36 . ".\\(?:>\\)") | ||||
|                  (37 . ".\\(?:\\(?:%%\\)\\|%\\)") | ||||
|                  (38 . ".\\(?:\\(?:&&\\)\\|&\\)") | ||||
|                  (42 . ".\\(?:\\(?:\\*\\*/\\)\\|\\(?:\\*[*/]\\)\\|[*/>]\\)") ;; | ||||
|                  (43 . ".\\(?:\\(?:\\+\\+\\)\\|[+>]\\)") | ||||
|                  (45 . ".\\(?:\\(?:-[>-]\\|<<\\|>>\\)\\|[<>}~-]\\)") | ||||
|                  (46 . ".\\(?:\\(?:\\.[.<]\\)\\|[.=-]\\)") ;; | ||||
|                  (47 . ".\\(?:\\(?:\\*\\*\\|//\\|==\\)\\|[*/=>]\\)") | ||||
|                  (48 . ".\\(?:x[a-zA-Z]\\)") | ||||
|                  (58 . ".\\(?:::\\|[:=]\\)") | ||||
|                  (59 . ".\\(?:;;\\|;\\)") | ||||
|                  (60 . ".\\(?:\\(?:!--\\)\\|\\(?:~~\\|->\\|\\$>\\|\\*>\\|\\+>\\|--\\|<[<=-]\\|=[<=>]\\||>\\)\\|[*$+~/<=>|-]\\)") | ||||
|                  (61 . ".\\(?:\\(?:/=\\|:=\\|<<\\|=[=>]\\|>>\\)\\|[<=>~]\\)") | ||||
|                  (62 . ".\\(?:\\(?:=>\\|>[=>-]\\)\\|[=>-]\\)") | ||||
|                  (63 . ".\\(?:\\(\\?\\?\\)\\|[:=?]\\)") | ||||
|                  (91 . ".\\(?:]\\)") | ||||
|                  (92 . ".\\(?:\\(?:\\\\\\\\\\)\\|\\\\\\)") | ||||
|                  (94 . ".\\(?:=\\)") | ||||
|                  (119 . ".\\(?:ww\\)") | ||||
|                  (123 . ".\\(?:-\\)") | ||||
|                  (124 . ".\\(?:\\(?:|[=|]\\)\\|[=>|]\\)") | ||||
|                  (126 . ".\\(?:~>\\|~~\\|[>=@~-]\\)")))) | ||||
|     (dolist (char-regexp alist) | ||||
|       (set-char-table-range composition-function-table (car char-regexp) | ||||
|                             `([,(cdr char-regexp) 0 font-shape-gstring]))))) | ||||
| 
 | ||||
| (provide 'fonts) | ||||
| ;;; fonts.el ends here | ||||
							
								
								
									
										70
									
								
								users/wpcarro/emacs/.emacs.d/wpc/fs.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								users/wpcarro/emacs/.emacs.d/wpc/fs.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| ;;; fs.el --- Make working with the filesystem easier -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Ergonomic alternatives for working with the filesystem. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'dash) | ||||
| (require 'f) | ||||
| (require 's) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun fs-ensure-file (path) | ||||
|   "Ensure that a file and its directories in `PATH' exist. | ||||
| Will error for inputs with a trailing slash." | ||||
|   (when (s-ends-with? "/" path) | ||||
|     (error (format "Input path has trailing slash: %s" path))) | ||||
|   (->> path | ||||
|        f-dirname | ||||
|        fs-ensure-dir) | ||||
|   (f-touch path)) | ||||
| 
 | ||||
| (f-dirname "/tmp/a/b/file.txt") | ||||
| 
 | ||||
| (defun fs-ensure-dir (path) | ||||
|   "Ensure that a directory and its ancestor directories in `PATH' exist." | ||||
|   (->> path | ||||
|        f-split | ||||
|        (apply #'f-mkdir))) | ||||
| 
 | ||||
| (defun fs-ls (dir &optional full-path?) | ||||
|   "List the files in `DIR' one-level deep. | ||||
| Should behave similarly in spirit to the Unix command, ls. | ||||
| If `FULL-PATH?' is set, return the full-path of the files." | ||||
|   (-drop 2 (directory-files dir full-path?))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (ert-deftest fs-test-ensure-file () | ||||
|   (let ((file "/tmp/file/a/b/c/file.txt")) | ||||
|     ;; Ensure this file doesn't exist first to prevent false-positives. | ||||
|     (f-delete file t) | ||||
|     (fs-ensure-file file) | ||||
|     (should (and (f-exists? file) | ||||
|                  (f-file? file))))) | ||||
| 
 | ||||
| (ert-deftest fs-test-ensure-dir () | ||||
|   (let ((dir "/tmp/dir/a/b/c")) | ||||
|     ;; Ensure the directory doesn't exist. | ||||
|     (f-delete dir t) | ||||
|     (fs-ensure-dir dir) | ||||
|     (should (and (f-exists? dir) | ||||
|                  (f-dir? dir))))) | ||||
| 
 | ||||
| (provide 'fs) | ||||
| ;;; fs.el ends here | ||||
							
								
								
									
										47
									
								
								users/wpcarro/emacs/.emacs.d/wpc/functions.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								users/wpcarro/emacs/.emacs.d/wpc/functions.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,47 @@ | |||
| ;;; functions.el --- Helper functions -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; This file hopefully contains friendly APIs that making ELisp development more | ||||
| ;; enjoyable. | ||||
| 
 | ||||
| ;; TODO: Break these out into separate modules. | ||||
| 
 | ||||
| ;;; Code: | ||||
| (defun functions-evil-window-vsplit-right () | ||||
|   "Split the window vertically and focus the right half." | ||||
|   (interactive) | ||||
|   (evil-window-vsplit) | ||||
|   (windmove-right)) | ||||
| 
 | ||||
| (defun functions-evil-window-split-down () | ||||
|   "Split the window horizontal and focus the bottom half." | ||||
|   (interactive) | ||||
|   (evil-window-split) | ||||
|   (windmove-down)) | ||||
| 
 | ||||
| (defun functions-create-snippet () | ||||
|   "Create a window split and then opens the Yasnippet editor." | ||||
|   (interactive) | ||||
|   (evil-window-vsplit) | ||||
|   (call-interactively #'yas-new-snippet)) | ||||
| 
 | ||||
| (defun functions-evil-replace-under-point () | ||||
|   "Faster than typing %s//thing/g." | ||||
|   (interactive) | ||||
|   (let ((term (s-replace "/" "\\/" (symbol-to-string (symbol-at-point))))) | ||||
|     (save-excursion | ||||
|       (evil-ex (concat "%s/\\b" term "\\b/"))))) | ||||
| 
 | ||||
| (defun functions-buffer-dirname () | ||||
|   "Return the directory name of the current buffer as a string." | ||||
|   (->> buffer-file-name | ||||
|        f-dirname | ||||
|        f-filename)) | ||||
| 
 | ||||
| (provide 'functions) | ||||
| ;;; functions.el ends here | ||||
							
								
								
									
										95
									
								
								users/wpcarro/emacs/.emacs.d/wpc/graph.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										95
									
								
								users/wpcarro/emacs/.emacs.d/wpc/graph.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,95 @@ | |||
| ;;; graph.el --- Working with in-memory graphs -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; | ||||
| ;; Remember that there are optimal three ways to model a graph: | ||||
| ;; 1. Edge List | ||||
| ;; 2. Vertex Table (a.k.a. Neighbors Table) | ||||
| ;; 3. Adjacency Matrix | ||||
| ;; | ||||
| ;; I may call these "Edges", "Neighbors", "Adjacencies" to avoid verbose naming. | ||||
| ;; For now, I'm avoiding dealing with Adjacency Matrices as I don't have an | ||||
| ;; immediate use-case for them.  This is subject to change. | ||||
| ;; | ||||
| ;; There are also hybrid representations of graphs that combine the three | ||||
| ;; aforementioned models.  I believe Erlang's digraph module models graphs in | ||||
| ;; Erlang Term Storage (i.e. ETS) this way. | ||||
| ;; TODO: Verify this claim. | ||||
| ;; | ||||
| ;; Graphs can be weighted or unweighted.  They can also be directed or | ||||
| ;; undirected. | ||||
| ;; TODO: Create a table explaining all graph variants. | ||||
| ;; | ||||
| ;; TODO: Figure out the relationship of this module and tree.el, which should in | ||||
| ;; principle overlap. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; For now, I'll support storing *either* neighbors or edges in the graph struct | ||||
| ;; as long as both aren't set, since that introduces consistency issues.  I may | ||||
| ;; want to handle that use-case in the future, but not now. | ||||
| (cl-defstruct graph neighbors edges) | ||||
| 
 | ||||
| ;; TODO: How do you find the starting point for a topo sort? | ||||
| (defun graph-sort (xs) | ||||
|   "Return a topological sort of XS.") | ||||
| 
 | ||||
| (defun graph-from-edges (xs) | ||||
|   "Create a graph struct from the Edge List, XS. | ||||
| The user must pass in a valid Edge List since asserting on the shape of XS might | ||||
|   be expensive." | ||||
|   (make-graph :edges xs)) | ||||
| 
 | ||||
| (defun graph-from-neighbors (xs) | ||||
|   "Create a graph struct from a Neighbors Table, XS. | ||||
| The user must pass in a valid Neighbors Table since asserting on the shape of | ||||
|   XS might be expensive." | ||||
|   (make-graph :neighbors xs)) | ||||
| 
 | ||||
| (defun graph-instance? (xs) | ||||
|   "Return t if XS is a graph struct." | ||||
|   (graph-p xs)) | ||||
| 
 | ||||
| ;; TODO: Model each of the mapping functions into an isomorphism. | ||||
| (defun graph-edges->neighbors (xs) | ||||
|   "Map Edge List, XS, into a Neighbors Table." | ||||
|   (prelude-assert (graph-instance? xs))) | ||||
| 
 | ||||
| (defun graph-neighbors->edges (xs) | ||||
|   "Map Neighbors Table, XS, into an Edge List." | ||||
|   (prelude-assert (graph-instance? xs))) | ||||
| 
 | ||||
| ;; Below are three different models of the same unweighted, directed graph. | ||||
| 
 | ||||
| (defvar graph-edges | ||||
|   '((a . b) (a . c) (a . e) | ||||
|     (b . c) (b . d) | ||||
|     (c . e) | ||||
|     (d . f) | ||||
|     (e . d) (e . f))) | ||||
| 
 | ||||
| (defvar graph-neighbors | ||||
|   ((a b c e) | ||||
|    (b c d) | ||||
|    (c e) | ||||
|    (d f) | ||||
|    (e d g) | ||||
|    (f))) | ||||
| 
 | ||||
| (provide 'graph) | ||||
| ;;; graph.el ends here | ||||
							
								
								
									
										171
									
								
								users/wpcarro/emacs/.emacs.d/wpc/irc.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										171
									
								
								users/wpcarro/emacs/.emacs.d/wpc/irc.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,171 @@ | |||
| ;;; irc.el --- Configuration for IRC chat -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Need to decide which client I will use for IRC. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'erc) | ||||
| (require 'cycle) | ||||
| (require 'string) | ||||
| (require 'prelude) | ||||
| (require 'al) | ||||
| (require 'set) | ||||
| (require 'maybe) | ||||
| (require 'macros) | ||||
| (require '>) | ||||
| (require 'password-store) | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defcustom irc-install-kbds? t | ||||
|   "When t, install the keybindings defined herein.") | ||||
| 
 | ||||
| (setq erc-rename-buffers t) | ||||
| 
 | ||||
| ;; Setting `erc-join-buffer' to 'bury prevents erc from stealing focus of the | ||||
| ;; current buffer when it connects to IRC servers. | ||||
| (setq erc-join-buffer 'bury) | ||||
| 
 | ||||
| ;; TODO: Find a way to avoid putting "freenode" and "#freenode" as channels | ||||
| ;; here.  I'm doing it because when erc first connects, it's `(buffer-name)' is | ||||
| ;; "freenode", so when `irc-next-channel' is called, it 404s on the | ||||
| ;; `cycle-contains?' call in `irc-channel->cycle" unless "freenode" is there. To | ||||
| ;; make matters even uglier, when `erc-join-channel' is called with "freenode" | ||||
| ;; as the value, it connects to the "#freenode" channel, so unless "#freenode" | ||||
| ;; exists in this cycle also, `irc-next-channel' breaks again. | ||||
| (defconst irc-server->channels | ||||
|   `(("irc.freenode.net"    . ,(cycle-new "freenode" "#freenode" "#nixos" "#emacs" "#pass")) | ||||
|     ("irc.corp.google.com" . ,(cycle-new "#drive-prod"))) | ||||
|   "Mapping of IRC servers to a cycle of my preferred channels.") | ||||
| 
 | ||||
| ;; TODO: Here is another horrible hack that should be revisted. | ||||
| (setq erc-autojoin-channels-alist | ||||
|       (->> irc-server->channels | ||||
|            (al-map-values #'cycle-to-list) | ||||
|            (al-map-keys (>-> (s-chop-prefix "irc.") | ||||
|                              (s-chop-suffix ".net"))))) | ||||
| 
 | ||||
| ;; TODO: Assert that no two servers have a channel with the same name. We need | ||||
| ;; this because that's the assumption that underpins the `irc-channel->server' | ||||
| ;; function. This will probably be an O(n^2) operation. | ||||
| (prelude-assert | ||||
|  (set-distinct? (set-from-list | ||||
|                  (cycle-to-list | ||||
|                   (al-get "irc.freenode.net" | ||||
|                           irc-server->channels))) | ||||
|                 (set-from-list | ||||
|                  (cycle-to-list | ||||
|                   (al-get "irc.corp.google.com" | ||||
|                           irc-server->channels))))) | ||||
| 
 | ||||
| (defun irc-channel->server (server->channels channel) | ||||
|   "Using SERVER->CHANNELS, resolve an IRC server from a given CHANNEL." | ||||
|   (let ((result (al-find (lambda (k v) (cycle-contains? channel v)) | ||||
|                          server->channels))) | ||||
|     (prelude-assert (maybe-some? result)) | ||||
|     result)) | ||||
| 
 | ||||
| (defun irc-channel->cycle (server->channels channel) | ||||
|   "Using SERVER->CHANNELS, resolve an IRC's channels cycle from CHANNEL." | ||||
|   (al-get (irc-channel->server server->channels channel) | ||||
|           server->channels)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun irc-message (x) | ||||
|   "Print message X in a structured way." | ||||
|   (message (string-format "[irc.el] %s" x))) | ||||
| 
 | ||||
| ;; TODO: Integrate Google setup with Freenode setup. | ||||
| 
 | ||||
| ;; TODO: Support function or KBD for switching to an ERC buffer. | ||||
| 
 | ||||
| (defun irc-kill-all-erc-processes () | ||||
|   "Kill all ERC buffers and processes." | ||||
|   (interactive) | ||||
|   (->> (erc-buffer-list) | ||||
|        (-map #'kill-buffer))) | ||||
| 
 | ||||
| (defun irc-switch-to-erc-buffer () | ||||
|   "Switch to an ERC buffer." | ||||
|   (interactive) | ||||
|   (let ((buffers (erc-buffer-list))) | ||||
|     (if (list-empty? buffers) | ||||
|         (error "[irc.el] No ERC buffers available") | ||||
|       (switch-to-buffer (list-head (erc-buffer-list)))))) | ||||
| 
 | ||||
| (defun irc-connect-to-freenode () | ||||
|   "Connect to Freenode IRC." | ||||
|   (interactive) | ||||
|   (erc-ssl :server "irc.freenode.net" | ||||
|            :port 6697 | ||||
|            :nick "wpcarro" | ||||
|            :password (password-store-get "programming/irc/freenode") | ||||
|            :full-name "William Carroll")) | ||||
| 
 | ||||
| ;; TODO: Handle failed connections. | ||||
| (defun irc-connect-to-google () | ||||
|   "Connect to Google's Corp IRC using ERC." | ||||
|   (interactive) | ||||
|   (erc-ssl :server "irc.corp.google.com" | ||||
|            :port 6697 | ||||
|            :nick "wpcarro" | ||||
|            :full-name "William Carroll")) | ||||
| 
 | ||||
| ;; TODO: Prefer defining these with a less homespun solution. There is a | ||||
| ;; function call `erc-buffer-filter' that would be more appropriate for the | ||||
| ;; implementation of `irc-next-channel' and `irc-prev-channel'. | ||||
| (defun irc-next-channel () | ||||
|   "Join the next channel for the active server." | ||||
|   (interactive) | ||||
|   (with-current-buffer (current-buffer) | ||||
|     (let ((cycle (irc-channel->cycle irc-server->channels (buffer-name)))) | ||||
|       (erc-join-channel | ||||
|        (cycle-next cycle)) | ||||
|       (irc-message | ||||
|        (string-format "Current IRC channel: %s" (cycle-current cycle)))))) | ||||
| 
 | ||||
| (defun irc-prev-channel () | ||||
|   "Join the previous channel for the active server." | ||||
|   (interactive) | ||||
|   (with-current-buffer (current-buffer) | ||||
|     (let ((cycle (irc-channel->cycle irc-server->channels (buffer-name)))) | ||||
|       (erc-join-channel | ||||
|        (cycle-prev cycle)) | ||||
|       (irc-message | ||||
|        (string-format "Current IRC channel: %s" (cycle-current cycle)))))) | ||||
| 
 | ||||
| (add-hook 'erc-mode-hook (macros-disable auto-fill-mode)) | ||||
| (add-hook 'erc-mode-hook (macros-disable company-mode)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Keybindings | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (when irc-install-kbds? | ||||
|   (general-define-key | ||||
|    :keymaps 'erc-mode-map | ||||
|    "<C-tab>" #'irc-next-channel | ||||
|    "<C-S-iso-lefttab>" #'irc-prev-channel)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (provide 'irc) | ||||
| ;;; irc.el ends here | ||||
							
								
								
									
										138
									
								
								users/wpcarro/emacs/.emacs.d/wpc/ivy-clipmenu.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										138
									
								
								users/wpcarro/emacs/.emacs.d/wpc/ivy-clipmenu.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,138 @@ | |||
| ;;; ivy-clipmenu.el --- Emacs client for clipmenu -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Ivy integration with the clipboard manager, clipmenu.  Essentially, clipmenu | ||||
| ;; turns your system clipboard into a list. | ||||
| ;; | ||||
| ;; To use this module, you must first install clipmenu and ensure that the | ||||
| ;; clipmenud daemon is running.  Refer to the installation instructions at | ||||
| ;; github.com/cdown/clipmenu for those details. | ||||
| ;; | ||||
| ;; This module intentionally does not define any keybindings since I'd prefer | ||||
| ;; not to presume my users' preferences.  Personally, I use EXWM as my window | ||||
| ;; manager, so I call `exwm-input-set-key' and map it to `ivy-clipmenu-copy'. | ||||
| ;; | ||||
| ;; Usually clipmenu integrates with rofi or dmenu.  This Emacs module integrates | ||||
| ;; with ivy.  Launch this when you want to select a clip. | ||||
| ;; | ||||
| ;; Clipmenu itself supports a variety of environment variables that allow you to | ||||
| ;; customize its behavior.  These variables are respected herein.  If you'd | ||||
| ;; prefer to customize clipmenu's behavior from within Emacs, refer to the | ||||
| ;; variables defined in this module. | ||||
| ;; | ||||
| ;; For more information: | ||||
| ;; - See `clipmenu --help`. | ||||
| ;; - Visit github.com/cdown/clipmenu. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'f) | ||||
| (require 's) | ||||
| (require 'dash) | ||||
| (require 'ivy) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Variables | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defgroup ivy-clipmenu nil | ||||
|   "Ivy integration for clipmenu." | ||||
|   :group 'ivy) | ||||
| 
 | ||||
| (defcustom ivy-clipmenu-directory | ||||
|   (or (getenv "XDG_RUNTIME_DIR") | ||||
|       (getenv "TMPDIR") | ||||
|       "/tmp") | ||||
|   "Base directory for clipmenu's data." | ||||
|   :type 'string | ||||
|   :group 'ivy-clipmenu) | ||||
| 
 | ||||
| (defconst ivy-clipmenu-executable-version 5 | ||||
|    "The major version number for the clipmenu executable.") | ||||
| 
 | ||||
| (defconst ivy-clipmenu-cache-directory | ||||
|   (f-join ivy-clipmenu-directory | ||||
|           (format "clipmenu.%s.%s" | ||||
|                   ivy-clipmenu-executable-version | ||||
|                   (getenv "USER"))) | ||||
|   "Directory where the clips are stored.") | ||||
| 
 | ||||
| (defconst ivy-clipmenu-cache-file-pattern | ||||
|   (f-join ivy-clipmenu-cache-directory "line_cache_*") | ||||
|   "Glob pattern matching the locations on disk for clipmenu's labels.") | ||||
| 
 | ||||
| (defcustom ivy-clipmenu-history-length | ||||
|   (or (getenv "CM_HISTLENGTH") 25) | ||||
|   "Limit the number of clips in the history. | ||||
| This value defaults to 25.") | ||||
| 
 | ||||
| (defvar ivy-clipmenu-history nil | ||||
|   "History for `ivy-clipmenu-copy'.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Functions | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun ivy-clipmenu-parse-content (x) | ||||
|   "Parse the label from the entry, X, in clipmenu's line-cache." | ||||
|   (->> (s-split " " x) | ||||
|        (-drop 1) | ||||
|        (s-join " "))) | ||||
| 
 | ||||
| (defun ivy-clipmenu-list-clips () | ||||
|   "Return a list of the content of all of the clips." | ||||
|   (->> ivy-clipmenu-cache-file-pattern | ||||
|        f-glob | ||||
|        (-map (lambda (path) | ||||
|                (s-split "\n" (f-read path) t))) | ||||
|        -flatten | ||||
|        (-reject #'s-blank?) | ||||
|        (-sort #'string>) | ||||
|        (-map #'ivy-clipmenu-parse-content) | ||||
|        delete-dups | ||||
|        (-take ivy-clipmenu-history-length))) | ||||
| 
 | ||||
| (defun ivy-clipmenu-checksum (content) | ||||
|   "Return the CRC checksum of CONTENT." | ||||
|   (s-trim-right | ||||
|    (with-temp-buffer | ||||
|      (call-process "/bin/bash" nil (current-buffer) nil "-c" | ||||
|                    (format "cksum <<<'%s'" content)) | ||||
|      (buffer-string)))) | ||||
| 
 | ||||
| (defun ivy-clipmenu-line-to-content (line) | ||||
|   "Map the chosen LINE from the line cache its content from disk." | ||||
|   (->> line | ||||
|        ivy-clipmenu-checksum | ||||
|        (f-join ivy-clipmenu-cache-directory) | ||||
|        f-read)) | ||||
| 
 | ||||
| (defun ivy-clipmenu-do-copy (x) | ||||
|   "Copy string, X, to the system clipboard." | ||||
|   (kill-new x) | ||||
|   (message "[ivy-clipmenu.el] Copied!")) | ||||
| 
 | ||||
| (defun ivy-clipmenu-copy () | ||||
|   "Use `ivy-read' to select and copy a clip. | ||||
| It's recommended to bind this function to a globally available keymap." | ||||
|   (interactive) | ||||
|   (let ((ivy-sort-functions-alist nil)) | ||||
|     (ivy-read "Clipmenu: " | ||||
|               (ivy-clipmenu-list-clips) | ||||
|               :history 'ivy-clipmenu-history | ||||
|               :action (lambda (line) | ||||
|                         (->> line | ||||
|                              ivy-clipmenu-line-to-content | ||||
|                              ivy-clipmenu-do-copy))))) | ||||
| 
 | ||||
| (provide 'ivy-clipmenu) | ||||
| ;;; ivy-clipmenu.el ends here | ||||
							
								
								
									
										68
									
								
								users/wpcarro/emacs/.emacs.d/wpc/ivy-helpers.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								users/wpcarro/emacs/.emacs.d/wpc/ivy-helpers.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,68 @@ | |||
| ;;; ivy-helpers.el --- More interfaces to ivy -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Hopefully to improve my workflows. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'tuple) | ||||
| (require 'string) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defun ivy-helpers-kv (prompt kv f) | ||||
|   "PROMPT users with the keys in KV and return its corresponding value. | ||||
| 
 | ||||
| Apply key and value from KV to F." | ||||
|   (ivy-read | ||||
|    prompt | ||||
|    kv | ||||
|    :require-match t | ||||
|    :action (lambda (entry) | ||||
|              (funcall f (car entry) (cdr entry))))) | ||||
| 
 | ||||
| (defun ivy-helpers-do-run-external-command (cmd) | ||||
|   "Execute the specified CMD and notify the user when it finishes." | ||||
|   (message "Starting %s..." cmd) | ||||
|   (set-process-sentinel | ||||
|    (start-process-shell-command cmd nil cmd) | ||||
|    (lambda (process event) | ||||
|      (when (string= event "finished\n") | ||||
|        (message "%s process finished." process))))) | ||||
| 
 | ||||
| (defun ivy-helpers-list-external-commands () | ||||
|   "Create a list of all external commands available on $PATH." | ||||
|   (cl-loop | ||||
|    for dir in (split-string (getenv "PATH") path-separator) | ||||
|    when (and (file-exists-p dir) (file-accessible-directory-p dir)) | ||||
|    for lsdir = (cl-loop for i in (directory-files dir t) | ||||
|                         for bn = (file-name-nondirectory i) | ||||
|                         when (and (not (s-contains? "-wrapped" i)) | ||||
|                                   (not (member bn completions)) | ||||
|                                   (not (file-directory-p i)) | ||||
|                                   (file-executable-p i)) | ||||
|                         collect bn) | ||||
|    append lsdir into completions | ||||
|    finally return (sort completions 'string-lessp))) | ||||
| 
 | ||||
| (defun ivy-helpers-run-external-command () | ||||
|   "Prompts the user with a list of all installed applications to launch." | ||||
|   (interactive) | ||||
|   (let ((external-commands-list (ivy-helpers-list-external-commands))) | ||||
|     (ivy-read "Command:" external-commands-list | ||||
|               :require-match t | ||||
|               :action #'ivy-helpers-do-run-external-command))) | ||||
| 
 | ||||
| ;;; Code: | ||||
| (provide 'ivy-helpers) | ||||
| ;;; ivy-helpers.el ends here | ||||
							
								
								
									
										86
									
								
								users/wpcarro/emacs/.emacs.d/wpc/kbd.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								users/wpcarro/emacs/.emacs.d/wpc/kbd.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | |||
| ;;; kbd.el --- Elisp keybinding -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; In order to stay organized, I'm attempting to dedicate KBD prefixes to | ||||
| ;; specific functions.  I'm hoping I can be more deliberate with my keybinding | ||||
| ;; choices this way. | ||||
| ;; | ||||
| ;; Terminology: | ||||
| ;; For a more thorough overview of the terminology refer to `keybindings.md' | ||||
| ;; file.  Here's a brief overview: | ||||
| ;; - workspace: Anything concerning EXWM workspaces. | ||||
| ;; - x11: Anything concerning X11 applications. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'al) | ||||
| (require 'set) | ||||
| (require 'string) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst kbd-prefixes | ||||
|   '((workspace . "s") | ||||
|     (x11 . "C-s")) | ||||
|   "Mapping of functions to designated keybinding prefixes to stay organized.") | ||||
| 
 | ||||
| ;; Assert that no keybindings are colliding. | ||||
| (prelude-assert | ||||
|  (= (al-count kbd-prefixes) | ||||
|     (->> kbd-prefixes | ||||
|          al-values | ||||
|          set-from-list | ||||
|          set-count))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun kbd-raw (f x) | ||||
|   "Return the string keybinding for function F and appendage X. | ||||
| Values for F include: | ||||
| - workspace | ||||
| - x11" | ||||
|   (prelude-assert (al-has-key? f kbd-prefixes)) | ||||
|   (string-format | ||||
|    "%s-%s" | ||||
|    (al-get f kbd-prefixes) | ||||
|    x)) | ||||
| 
 | ||||
| (defun kbd-for (f x) | ||||
|   "Return the `kbd' for function F and appendage X. | ||||
| Values for F include: | ||||
| - workspace | ||||
| - x11" | ||||
|   (kbd (kbd-raw f x))) | ||||
| 
 | ||||
| ;; TODO: Prefer copying human-readable versions to the clipboard.  Right now | ||||
| ;; this isn't too useful. | ||||
| (defun kbd-copy-keycode () | ||||
|   "Copy the pressed key to the system clipboard." | ||||
|   (interactive) | ||||
|   (message "[kbd] Awaiting keypress...") | ||||
|   (let ((key (read-key))) | ||||
|     (clipboard-copy (string-format "%s" key)) | ||||
|     (message (string-format "[kbd] \"%s\" copied!" key)))) | ||||
| 
 | ||||
| (defun kbd-print-keycode () | ||||
|   "Prints the pressed keybinding." | ||||
|   (interactive) | ||||
|   (message "[kbd] Awaiting keypress...") | ||||
|   (message (string-format "[kbd] keycode: %s" (read-key)))) | ||||
| 
 | ||||
| (provide 'kbd) | ||||
| ;;; kbd.el ends here | ||||
							
								
								
									
										367
									
								
								users/wpcarro/emacs/.emacs.d/wpc/keybindings.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										367
									
								
								users/wpcarro/emacs/.emacs.d/wpc/keybindings.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,367 @@ | |||
| ;;; keybindings.el --- Centralizing my keybindings -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Attempting to centralize my keybindings to simplify my configuration. | ||||
| ;; | ||||
| ;; I have some expectations about my keybindings.  Here are some of those | ||||
| ;; defined: | ||||
| ;; - In insert mode: | ||||
| ;;   - C-a: beginning-of-line | ||||
| ;;   - C-e: end-of-line | ||||
| ;;   - C-b: backwards-char | ||||
| ;;   - C-f: forwards-char | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'functions) | ||||
| (require 'clipboard) | ||||
| (require 'screen-brightness) | ||||
| (require 'pulse-audio) | ||||
| (require 'scrot) | ||||
| (require 'ivy-clipmenu) | ||||
| (require 'general) | ||||
| (require 'exwm) | ||||
| (require 'vterm-mgt) | ||||
| (require 'buffer) | ||||
| (require 'display) | ||||
| (require 'device) | ||||
| (require 'fonts) | ||||
| (require 'bookmark) | ||||
| (require 'constants) | ||||
| (require 'window-manager) | ||||
| 
 | ||||
| ;; Note: The following lines must be sorted this way. | ||||
| (setq evil-want-integration t) | ||||
| (setq evil-want-keybinding nil) | ||||
| (general-evil-setup) | ||||
| (require 'evil) | ||||
| (require 'evil-collection) | ||||
| (require 'evil-magit) | ||||
| (require 'evil-commentary) | ||||
| (require 'evil-surround) | ||||
| (require 'key-chord) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; General Keybindings | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; Install KBDs like <SPC>jb to search through my monorepo. | ||||
| (bookmark-install-kbds) | ||||
| 
 | ||||
| ;; Ensure that evil's command mode behaves with readline bindings. | ||||
| (general-define-key | ||||
|  :keymaps 'evil-ex-completion-map | ||||
|  "C-a" #'move-beginning-of-line | ||||
|  "C-e" #'move-end-of-line | ||||
|  "C-k" #'kill-line | ||||
|  "C-u" #'evil-delete-whole-line | ||||
|  "C-v" #'evil-paste-after | ||||
|  "C-d" #'delete-char | ||||
|  "C-f" #'forward-char | ||||
|  "M-b" #'backward-word | ||||
|  "M-f" #'forward-word | ||||
|  "M-d" #'kill-word | ||||
|  "M-DEL" #'backward-kill-word | ||||
|  "C-b" #'backward-char) | ||||
| 
 | ||||
| (general-mmap | ||||
|   :keymaps 'override | ||||
|   "RET" #'evil-goto-line | ||||
|   "H"   #'evil-first-non-blank | ||||
|   "L"   #'evil-end-of-line | ||||
|   "_"   #'ranger | ||||
|   "-"   #'dired-jump | ||||
|   "sl"  #'functions-evil-window-vsplit-right | ||||
|   "sh"  #'evil-window-vsplit | ||||
|   "sk"  #'evil-window-split | ||||
|   "sj"  #'functions-evil-window-split-down) | ||||
| 
 | ||||
| (general-nmap | ||||
|   :keymaps 'override | ||||
|   "gu" #'browse-url-at-point | ||||
|   "gd" #'xref-find-definitions | ||||
|   ;; Wrapping `xref-find-references' in the `let' binding to prevent xref from | ||||
|   ;; prompting.  There are other ways to handle this variable, such as setting | ||||
|   ;; it globally with `setq' or buffer-locally with `setq-local'.  For now, I | ||||
|   ;; prefer setting it with `let', which should bind it in the dynamic scope | ||||
|   ;; for the duration of the `xref-find-references' function call. | ||||
|   "gx" (lambda () | ||||
|          (interactive) | ||||
|          (let ((xref-prompt-for-identifier nil)) | ||||
|            (call-interactively #'xref-find-references)))) | ||||
| 
 | ||||
| (general-unbind 'motion "M-." "C-p" "<SPC>") | ||||
| (general-unbind 'normal "s"   "M-." "C-p" "C-n") | ||||
| (general-unbind 'insert "C-v" "C-d" "C-a" "C-e" "C-n" "C-p" "C-k") | ||||
| 
 | ||||
| (setq evil-symbol-word-search t) | ||||
| (evil-mode 1) | ||||
| (evil-collection-init) | ||||
| (evil-commentary-mode) | ||||
| (global-evil-surround-mode 1) | ||||
| 
 | ||||
| ;; Ensure the Evil search results get centered vertically. | ||||
| ;; When Emacs is run from a terminal, this forces Emacs to redraw itself, which | ||||
| ;; is visually disruptive. | ||||
| (when window-system | ||||
|   (progn | ||||
|     (defadvice isearch-update | ||||
|         (before advice-for-isearch-update activate) | ||||
|       (evil-scroll-line-to-center (line-number-at-pos))) | ||||
|     (defadvice evil-search-next | ||||
|         (after advice-for-evil-search-next activate) | ||||
|       (evil-scroll-line-to-center (line-number-at-pos))) | ||||
|     (defadvice evil-search-previous | ||||
|         (after advice-for-evil-search-previous activate) | ||||
|       (evil-scroll-line-to-center (line-number-at-pos))))) | ||||
| 
 | ||||
| (key-chord-mode 1) | ||||
| (key-chord-define evil-insert-state-map "jk" 'evil-normal-state) | ||||
| 
 | ||||
| ;; This may be contraversial, but I never use the prefix key, and I'd prefer to | ||||
| ;; have to bound to the readline function that deletes the entire line. | ||||
| (general-unbind "C-u") | ||||
| 
 | ||||
| (defmacro keybindings-exwm (c fn) | ||||
|   "Bind C to FN using `exwm-input-set-key' with `kbd' applied to C." | ||||
|   `(exwm-input-set-key (kbd ,c) ,fn)) | ||||
| 
 | ||||
| (keybindings-exwm "C-M-v" #'ivy-clipmenu-copy) | ||||
| (keybindings-exwm "<XF86MonBrightnessUp>" #'screen-brightness-increase) | ||||
| (keybindings-exwm "<XF86MonBrightnessDown>" #'screen-brightness-decrease) | ||||
| (keybindings-exwm "<XF86AudioMute>" #'pulse-audio-toggle-mute) | ||||
| (keybindings-exwm "<XF86AudioLowerVolume>" #'pulse-audio-decrease-volume) | ||||
| (keybindings-exwm "<XF86AudioRaiseVolume>" #'pulse-audio-increase-volume) | ||||
| (keybindings-exwm "<XF86AudioMicMute>" #'pulse-audio-toggle-microphone) | ||||
| (keybindings-exwm (kbd-raw 'x11 "s") #'scrot-select) | ||||
| (keybindings-exwm "<C-M-tab>" #'window-manager-switch-to-exwm-buffer) | ||||
| (keybindings-exwm (kbd-raw 'workspace "k") #'fonts-increase-size) | ||||
| (keybindings-exwm (kbd-raw 'workspace "j") #'fonts-decrease-size) | ||||
| (keybindings-exwm (kbd-raw 'workspace "0") #'fonts-reset-size) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Window sizing | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| (keybindings-exwm "C-M-=" #'balance-windows) | ||||
| (keybindings-exwm "C-M-j" #'shrink-window) | ||||
| (keybindings-exwm "C-M-k" #'enlarge-window) | ||||
| (keybindings-exwm "C-M-h" #'shrink-window-horizontally) | ||||
| (keybindings-exwm "C-M-l" #'enlarge-window-horizontally) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Window Management | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| (keybindings-exwm "M-h" #'windmove-left) | ||||
| (keybindings-exwm "M-j" #'windmove-down) | ||||
| (keybindings-exwm "M-k" #'windmove-up) | ||||
| (keybindings-exwm "M-l" #'windmove-right) | ||||
| (keybindings-exwm "M-\\" #'evil-window-vsplit) | ||||
| (keybindings-exwm "M--" #'evil-window-split) | ||||
| (keybindings-exwm "M-q" #'delete-window) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Miscellaneous | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| (keybindings-exwm "M-:" #'eval-expression) | ||||
| (keybindings-exwm "M-SPC" #'ivy-helpers-run-external-command) | ||||
| (keybindings-exwm "M-x" #'counsel-M-x) | ||||
| (keybindings-exwm "<M-tab>" #'window-manager-next-workspace) | ||||
| (keybindings-exwm "<M-S-iso-lefttab>" #'window-manager-prev-workspace) | ||||
| (keybindings-exwm "C-M-\\" #'ivy-pass) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Workspaces | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| (keybindings-exwm (kbd-raw 'workspace "l") #'window-manager-logout) | ||||
| 
 | ||||
| (general-define-key | ||||
|  :keymaps 'override | ||||
|  "M-q" #'delete-window | ||||
|  "<s-return>" #'toggle-frame-fullscreen | ||||
|  "M-h" #'windmove-left | ||||
|  "M-l" #'windmove-right | ||||
|  "M-k" #'windmove-up | ||||
|  "M-j" #'windmove-down | ||||
|  "M-q" #'delete-window) | ||||
| 
 | ||||
| ;; Support pasting in M-:. | ||||
| (general-define-key | ||||
|  :keymaps 'read-expression-map | ||||
|  "C-v"   #'clipboard-yank | ||||
|  "C-S-v" #'clipboard-yank) | ||||
| 
 | ||||
| (general-define-key | ||||
|  :prefix "<SPC>" | ||||
|  :states '(normal) | ||||
|  "." #'ffap | ||||
|  "gn" #'notmuch | ||||
|  "i" #'counsel-semantic-or-imenu | ||||
|  "I" #'ibuffer | ||||
|  "hk" #'helpful-callable | ||||
|  "hf" #'helpful-function | ||||
|  "hm" #'helpful-macro | ||||
|  "hc" #'helpful-command | ||||
|  "hk" #'helpful-key | ||||
|  "hv" #'helpful-variable | ||||
|  "hp" #'helpful-at-point | ||||
|  "hi" #'info-apropos | ||||
|  "s" #'flyspell-mode | ||||
|  "S" #'sort-lines | ||||
|  "=" #'align | ||||
|  "p" #'flycheck-previous-error | ||||
|  "f" #'project-find-file | ||||
|  "n" #'flycheck-next-error | ||||
|  "N" #'smerge-next | ||||
|  "W" #'balance-windows | ||||
|  "gss" #'magit-status | ||||
|  "gsb" (lambda () | ||||
|          (interactive) | ||||
|          (magit-status constants-briefcase)) | ||||
|  "E" #'refine | ||||
|  "es" #'functions-create-snippet | ||||
|  "l" #'linum-mode | ||||
|  "B" #'magit-blame | ||||
|  "w" #'save-buffer | ||||
|  "r" #'functions-evil-replace-under-point | ||||
|  "R" #'deadgrep) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Vterm | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; Show or hide a vterm buffer.  I'm intentionally not defining this in | ||||
| ;; vterm-mgt.el because it consumes `buffer-show-previous', and I'd like to | ||||
| ;; avoid bloating vterm-mgt.el with dependencies that others may not want. | ||||
| (general-define-key (kbd-raw 'x11 "t") | ||||
|                     (lambda () | ||||
|                       (interactive) | ||||
|                       (if (vterm-mgt--instance? (current-buffer)) | ||||
|                           (switch-to-buffer (first (buffer-source-code-buffers))) | ||||
|                         (call-interactively #'vterm-mgt-find-or-create)))) | ||||
| 
 | ||||
| (general-define-key | ||||
|  :keymaps '(vterm-mode-map) | ||||
|  "C-S-n" #'vterm-mgt-instantiate | ||||
|  "C-S-w" #'vterm-mgt-kill | ||||
|  "<C-tab>" #'vterm-mgt-next | ||||
|  "<C-S-iso-lefttab>" #'vterm-mgt-prev | ||||
|  "<s-backspace>" #'vterm-mgt-rename-buffer) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Displays | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (when (device-work-laptop?) | ||||
|   (general-define-key | ||||
|    :prefix "<SPC>" | ||||
|    :states '(normal) | ||||
|    "d0" #'display-enable-laptop | ||||
|    "D0" #'display-disable-laptop | ||||
|    "d1" #'display-enable-4k-horizontal | ||||
|    "D1" #'display-disable-4k-horizontal)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; notmuch | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; evil-collection adds many KBDs to notmuch modes. Some of these I find | ||||
| ;; disruptive. | ||||
| (general-define-key | ||||
|  :states '(normal) | ||||
|  :keymaps '(notmuch-show-mode-map) | ||||
|  "M-j" nil | ||||
|  "M-k" nil | ||||
|  "<C-S-iso-lefttab>" #'notmuch-show-previous-thread-show | ||||
|  "<C-tab>" #'notmuch-show-next-thread-show | ||||
|  "e" #'notmuch-show-archive-message-then-next-or-next-thread) | ||||
| 
 | ||||
| ;; TODO(wpcarro): Consider moving this to a separate module | ||||
| (defun keybindings--evil-ex-define-cmd-local (cmd f) | ||||
|   "Define CMD to F locally to a buffer." | ||||
|   (unless (local-variable-p 'evil-ex-commands) | ||||
|     (setq-local evil-ex-commands (copy-alist evil-ex-commands))) | ||||
|   (evil-ex-define-cmd cmd f)) | ||||
| 
 | ||||
| ;; TODO(wpcarro): Support a macro that can easily define evil-ex commands for a | ||||
| ;; particular mode. | ||||
| ;; Consumption: | ||||
| ;; (evil-ex-for-mode 'notmuch-message-mode | ||||
| ;;                   "x" #'notmuch-mua-send-and-exit) | ||||
| 
 | ||||
| (add-hook 'notmuch-message-mode-hook | ||||
|           (lambda () | ||||
|             (keybindings--evil-ex-define-cmd-local "x" #'notmuch-mua-send-and-exit))) | ||||
| 
 | ||||
| ;; For now, I'm mimmicking Gmail KBDs that I have memorized and enjoy | ||||
| (general-define-key | ||||
|  :states '(normal visual) | ||||
|  :keymaps '(notmuch-search-mode-map) | ||||
|  "M"  (lambda () | ||||
|         (interactive) | ||||
|         (notmuch-search-tag '("-inbox" "+muted"))) | ||||
|  "mi" (lambda () | ||||
|         (interactive) | ||||
|         (notmuch-search-tag '("+inbox" "-action" "-review" "-waiting" "-muted"))) | ||||
|  "ma" (lambda () | ||||
|         (interactive) | ||||
|         (notmuch-search-tag '("-inbox" "+action" "-review" "-waiting"))) | ||||
|  "mr" (lambda () | ||||
|         (interactive) | ||||
|         (notmuch-search-tag '("-inbox" "-action" "+review" "-waiting"))) | ||||
|  "mw" (lambda () | ||||
|         (interactive) | ||||
|         (notmuch-search-tag '("-inbox" "-action" "-review" "+waiting"))) | ||||
|  "e" #'notmuch-search-archive-thread) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; magit | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (general-define-key | ||||
|  :states '(normal) | ||||
|  :keymaps '(magit-status-mode-map | ||||
|             magit-log-mode-map | ||||
|             magit-revision-mode-map) | ||||
|  "l" #'evil-forward-char | ||||
|  "L" #'magit-log) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Info-mode | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; NOTE: I find some of the following, existing KBDs useful: | ||||
| ;;   M-x info-apropos | ||||
| ;;   u   Info-up | ||||
| ;;   M-n clone-buffer | ||||
| (general-define-key | ||||
|  :states '(normal) | ||||
|  :keymaps '(Info-mode-map) | ||||
|  "SPC" nil | ||||
|  "g SPC" #'Info-scroll-up | ||||
|  "RET" #'Info-follow-nearest-node | ||||
|  "<C-tab>" #'Info-next | ||||
|  "<C-S-iso-lefttab>" #'Info-prev | ||||
|  "g l" #'Info-history-back | ||||
|  "g t" #'Info-toc) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; ibuffer | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (general-define-key | ||||
|  :states '(normal) | ||||
|  :keymaps '(ibuffer-mode-map) | ||||
|  "M-j" nil | ||||
|  "K" #'ibuffer-do-delete) | ||||
| 
 | ||||
| (provide 'keybindings) | ||||
| ;;; keybindings.el ends here | ||||
							
								
								
									
										140
									
								
								users/wpcarro/emacs/.emacs.d/wpc/keyboard.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										140
									
								
								users/wpcarro/emacs/.emacs.d/wpc/keyboard.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,140 @@ | |||
| ;;; keyboard.el --- Managing keyboard preferences with Elisp -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Setting key repeat and other values. | ||||
| ;; | ||||
| ;; Be wary of suspiciously round numbers.  Especially those divisible by ten! | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'string) | ||||
| (require 'number) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Support clamping functions for repeat-{rate,delay} to ensure only valid | ||||
| ;; values are sent to xset. | ||||
| (defcustom keyboard-repeat-rate 80 | ||||
|   "The number of key repeat signals sent per second.") | ||||
| 
 | ||||
| (defcustom keyboard-repeat-delay 170 | ||||
|   "The number of milliseconds before autorepeat starts.") | ||||
| 
 | ||||
| (defconst keyboard-repeat-rate-copy keyboard-repeat-rate | ||||
|   "Copy of `keyboard-repeat-rate' to support `keyboard-reset-key-repeat'.") | ||||
| 
 | ||||
| (defconst keyboard-repeat-delay-copy keyboard-repeat-delay | ||||
|   "Copy of `keyboard-repeat-delay' to support `keyboard-reset-key-repeat'.") | ||||
| 
 | ||||
| (defcustom keyboard-install-preferences? t | ||||
|   "When t, install keyboard preferences.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Functions | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun keyboard-message (x) | ||||
|   "Message X in a structured way." | ||||
|   (message (string-format "[keyboard.el] %s" x))) | ||||
| 
 | ||||
| (cl-defun keyboard-set-key-repeat (&key | ||||
|                                    (rate keyboard-repeat-rate) | ||||
|                                    (delay keyboard-repeat-delay)) | ||||
|   "Use xset to set the key-repeat RATE and DELAY." | ||||
|   (prelude-start-process | ||||
|    :name "keyboard-set-key-repeat" | ||||
|    :command (string-format "xset r rate %s %s" delay rate))) | ||||
| 
 | ||||
| ;; NOTE: Settings like this are machine-dependent. For instance I only need to | ||||
| ;; do this on my laptop and other devices where I don't have access to my split | ||||
| ;; keyboard. | ||||
| ;; NOTE: Running keysym Caps_Lock is not idempotent.  If this is called more | ||||
| ;; than once, xmodmap will start to error about non-existent Caps_Lock symbol. | ||||
| ;; For more information see here: | ||||
| ;; https://unix.stackexchange.com/questions/108207/how-to-map-caps-lock-as-the-compose-key-using-xmodmap-portably-and-idempotently | ||||
| (defun keyboard-swap-caps-lock-and-escape () | ||||
|   "Swaps the caps lock and escape keys using xmodmap." | ||||
|   (interactive) | ||||
|   ;; TODO: Ensure these work once the tokenizing in prelude-start-process works | ||||
|   ;; as expected. | ||||
|   (start-process "keyboard-swap-caps-lock-and-escape" | ||||
|                  nil "/usr/bin/xmodmap" "-e" "remove Lock = Caps_Lock") | ||||
|   (start-process "keyboard-swap-caps-lock-and-escape" | ||||
|                  nil "/usr/bin/xmodmap" "-e" "keysym Caps_Lock = Escape")) | ||||
| 
 | ||||
| (defun keyboard-inc-repeat-rate () | ||||
|   "Increment `keyboard-repeat-rate'." | ||||
|   (interactive) | ||||
|   (setq keyboard-repeat-rate (number-inc keyboard-repeat-rate)) | ||||
|   (keyboard-set-key-repeat :rate keyboard-repeat-rate) | ||||
|   (keyboard-message | ||||
|    (string-format "Rate: %s" keyboard-repeat-rate))) | ||||
| 
 | ||||
| (defun keyboard-dec-repeat-rate () | ||||
|   "Decrement `keyboard-repeat-rate'." | ||||
|   (interactive) | ||||
|   (setq keyboard-repeat-rate (number-dec keyboard-repeat-rate)) | ||||
|   (keyboard-set-key-repeat :rate keyboard-repeat-rate) | ||||
|   (keyboard-message | ||||
|    (string-format "Rate: %s" keyboard-repeat-rate))) | ||||
| 
 | ||||
| (defun keyboard-inc-repeat-delay () | ||||
|   "Increment `keyboard-repeat-delay'." | ||||
|   (interactive) | ||||
|   (setq keyboard-repeat-delay (number-inc keyboard-repeat-delay)) | ||||
|   (keyboard-set-key-repeat :delay keyboard-repeat-delay) | ||||
|   (keyboard-message | ||||
|    (string-format "Delay: %s" keyboard-repeat-delay))) | ||||
| 
 | ||||
| (defun keyboard-dec-repeat-delay () | ||||
|   "Decrement `keyboard-repeat-delay'." | ||||
|   (interactive) | ||||
|   (setq keyboard-repeat-delay (number-dec keyboard-repeat-delay)) | ||||
|   (keyboard-set-key-repeat :delay keyboard-repeat-delay) | ||||
|   (keyboard-message | ||||
|    (string-format "Delay: %s" keyboard-repeat-delay))) | ||||
| 
 | ||||
| (defun keyboard-print-key-repeat () | ||||
|   "Print the currently set values for key repeat." | ||||
|   (interactive) | ||||
|   (keyboard-message | ||||
|    (string-format "Rate: %s. Delay: %s" | ||||
|                   keyboard-repeat-rate | ||||
|                   keyboard-repeat-delay))) | ||||
| 
 | ||||
| (defun keyboard-set-preferences () | ||||
|   "Reset the keyboard preferences to their default values. | ||||
| NOTE: This function exists because occasionally I unplug and re-plug in a | ||||
|   keyboard and all of the preferences that I set using xset disappear." | ||||
|   (interactive) | ||||
|   (keyboard-swap-caps-lock-and-escape) | ||||
|   (keyboard-set-key-repeat :rate keyboard-repeat-rate | ||||
|                            :delay keyboard-repeat-delay) | ||||
|   ;; TODO: Implement this message function as a macro that pulls the current | ||||
|   ;; file name. | ||||
|   (keyboard-message "Keyboard preferences set!")) | ||||
| 
 | ||||
| (defun keyboard-reset-key-repeat () | ||||
|   "Set key repeat rate and delay to original values." | ||||
|   (interactive) | ||||
|   (keyboard-set-key-repeat :rate keyboard-repeat-rate-copy | ||||
|                            :delay keyboard-repeat-delay-copy) | ||||
|   (keyboard-message "Key repeat preferences reset.")) | ||||
| 
 | ||||
| (when keyboard-install-preferences? | ||||
|   (keyboard-set-preferences)) | ||||
| 
 | ||||
| (provide 'keyboard) | ||||
| ;;; keyboard.el ends here | ||||
							
								
								
									
										64
									
								
								users/wpcarro/emacs/.emacs.d/wpc/laptop-battery.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								users/wpcarro/emacs/.emacs.d/wpc/laptop-battery.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | |||
| ;;; laptop-battery.el --- Display laptop battery information -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Some wrappers to obtain battery information. | ||||
| ;; | ||||
| ;; To troubleshoot battery consumpton look into the CLI `powertop`. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Roadmap | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Support functions that work with reporting battery stats. | ||||
| ;; TODO: low-battery-reporting-threshold | ||||
| ;; TODO: charged-battery-reporting-threshold | ||||
| ;; TODO: Format modeline battery information. | ||||
| ;; TODO: Provide better time information in the modeline. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'battery) | ||||
| (require 'al) | ||||
| (require 'maybe) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun laptop-battery-available? () | ||||
|   "Return t if battery information is available." | ||||
|   (maybe-some? battery-status-function)) | ||||
| 
 | ||||
| (defun laptop-battery-percentage () | ||||
|   "Return the current percentage of the battery." | ||||
|   (->> battery-status-function | ||||
|        funcall | ||||
|        (al-get 112))) | ||||
| 
 | ||||
| (defun laptop-battery-print-percentage () | ||||
|   "Return the current percentage of the battery." | ||||
|   (interactive) | ||||
|   (->> (laptop-battery-percentage) | ||||
|        message)) | ||||
| 
 | ||||
| (defun laptop-battery-display () | ||||
|   "Display laptop battery percentage in the modeline." | ||||
|   (interactive) | ||||
|   (display-battery-mode 1)) | ||||
| 
 | ||||
| (defun laptop-battery-hide () | ||||
|   "Hide laptop battery percentage in the modeline." | ||||
|   (interactive) | ||||
|   (display-battery-mode -1)) | ||||
| 
 | ||||
| (provide 'laptop-battery) | ||||
| ;;; laptop-battery.el ends here | ||||
							
								
								
									
										222
									
								
								users/wpcarro/emacs/.emacs.d/wpc/list.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										222
									
								
								users/wpcarro/emacs/.emacs.d/wpc/list.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,222 @@ | |||
| ;;; list.el --- Functions for working with lists -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Since I prefer having the `list-' namespace, I wrote this module to wrap many | ||||
| ;; of the functions that are defined in the the global namespace in ELisp.  I | ||||
| ;; sometimes forget the names of these functions, so it's nice for them to be | ||||
| ;; organized like this. | ||||
| ;; | ||||
| ;; Motivation: | ||||
| ;; Here are some examples of function names that I cannot tolerate: | ||||
| ;; - `car': Return the first element (i.e. "head") of a linked list | ||||
| ;; - `cdr': Return the tail of a linked list | ||||
| 
 | ||||
| ;; As are most APIs for standard libraries that I write, this is heavily | ||||
| ;; influenced by Elixir's standard library. | ||||
| ;; | ||||
| ;; Elixir's List library: | ||||
| ;; - ++/2 | ||||
| ;; - --/2 | ||||
| ;; - hd/1 | ||||
| ;; - tl/1 | ||||
| ;; - in/2 | ||||
| ;; - length/1 | ||||
| ;; | ||||
| ;; Similar libraries: | ||||
| ;; - dash.el: Functional library that mimmicks Clojure.  It is consumed herein. | ||||
| ;; - list-utils.el: Utility library that covers things that dash.el may not | ||||
| ;;   cover. | ||||
| ;;   stream.el: Elisp implementation of streams, "implemented as delayed | ||||
| ;;   evaluation of cons cells." | ||||
| 
 | ||||
| ;; TODO: Consider naming this file linked-list.el. | ||||
| 
 | ||||
| ;; TODO: Support module-like macro that auto-namespaces functions. | ||||
| 
 | ||||
| ;; TODO: Consider wrapping most data structures like linked-lists, | ||||
| ;; associative-lists, etc in a `cl-defstruct', so that the dispatching by type | ||||
| ;; can be nominal instead of duck-typing.  I'm not sure if this is a good idea | ||||
| ;; or not.  If I do this, I should provide isomorphisms to map between idiomatic | ||||
| ;; ways of working with Elisp data structures and my wrapped variants. | ||||
| 
 | ||||
| ;; TODO: Are function aliases/synonyms even a good idea?  Or do they just | ||||
| ;; bloat the API unnecessarily? | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Move `prelude-assert' elsewhere so that I can require it without | ||||
| ;; introducing the circular dependency of list.el -> prelude.el -> list.el. | ||||
| ;;(require 'prelude) | ||||
| (require 'dash) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst list-tests? t | ||||
|   "When t, run the test suite.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun list-new () | ||||
|   "Return a new, empty list." | ||||
|   '()) | ||||
| 
 | ||||
| (defun list-concat (&rest lists) | ||||
|   "Joins `LISTS' into on list." | ||||
|   (apply #'-concat lists)) | ||||
| 
 | ||||
| (defun list-join (joint xs) | ||||
|   "Join a list of strings, XS, with JOINT." | ||||
|   (if (list-empty? xs) | ||||
|       "" | ||||
|     (list-reduce (list-first xs) | ||||
|                  (lambda (x acc) | ||||
|                    (string-concat acc joint x)) | ||||
|                  (list-tail xs)))) | ||||
| 
 | ||||
| (defun list-length (xs) | ||||
|   "Return the number of elements in `XS'." | ||||
|   (length xs)) | ||||
| 
 | ||||
| (defun list-get (i xs) | ||||
|   "Return the value in `XS' at `I', or nil." | ||||
|   (nth i xs)) | ||||
| 
 | ||||
| (defun list-head (xs) | ||||
|   "Return the head of `XS'." | ||||
|   (car xs)) | ||||
| 
 | ||||
| ;; TODO: Learn how to write proper function aliases. | ||||
| (defun list-first (xs) | ||||
|   "Alias for `list-head' for `XS'." | ||||
|   (list-head xs)) | ||||
| 
 | ||||
| (defun list-tail (xs) | ||||
|   "Return the tail of `XS'." | ||||
|   (cdr xs)) | ||||
| 
 | ||||
| (defun list-reverse (xs) | ||||
|   "Reverses `XS'." | ||||
|   (reverse xs)) | ||||
| 
 | ||||
| (defun list-cons (x xs) | ||||
|   "Add `X' to the head of `XS'." | ||||
|   (cons x xs)) | ||||
| 
 | ||||
| ;; map, filter, reduce | ||||
| 
 | ||||
| ;; TODO: Create function adapters like swap. | ||||
| ;; (defun adapter/swap (f) | ||||
| ;;   "Return a new function that wraps `F' and swaps the arguments." | ||||
| ;;   (lambda (a b) | ||||
| ;;     (funcall f b a))) | ||||
| 
 | ||||
| ;; TODO: Make this function work. | ||||
| (defun list-reduce (acc f xs) | ||||
|   "Return over `XS' calling `F' on an element in `XS'and `ACC'." | ||||
|   (-reduce-from (lambda (acc x) (funcall f x acc)) acc xs)) | ||||
| 
 | ||||
| (defun list-map (f xs) | ||||
|   "Call `F' on each element of `XS'." | ||||
|   (-map f xs)) | ||||
| 
 | ||||
| (defun list-map-indexed (f xs) | ||||
|   "Call `F' on each element of `XS' along with its index." | ||||
|   (-map-indexed (lambda (i x) (funcall f x i)) xs)) | ||||
| 
 | ||||
| (defun list-filter (p xs) | ||||
|   "Return a subset of XS where predicate P returned t." | ||||
|   (list-reverse | ||||
|    (list-reduce | ||||
|     '() | ||||
|     (lambda (x acc) | ||||
|       (if (funcall p x) | ||||
|           (list-cons x acc) | ||||
|         acc)) | ||||
|     xs))) | ||||
| 
 | ||||
| (defun list-reject (p xs) | ||||
|   "Return a subset of XS where predicate of P return nil." | ||||
|   (list-filter (lambda (x) (not (funcall p x))) xs)) | ||||
| 
 | ||||
| (defun list-find (p xs) | ||||
|   "Return the first x in XS that passes P or nil." | ||||
|   (-find p xs)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Predicates | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun list-instance? (xs) | ||||
|   "Return t if `XS' is a list. | ||||
| Be leery of using this with things like alists.  Many data structures in Elisp | ||||
|   are implemented using linked lists." | ||||
|   (listp xs)) | ||||
| 
 | ||||
| (defun list-empty? (xs) | ||||
|   "Return t if XS are empty." | ||||
|   (= 0 (list-length xs))) | ||||
| 
 | ||||
| (defun list-all? (p xs) | ||||
|   "Return t if all `XS' pass the predicate, `P'." | ||||
|   (-all? p xs)) | ||||
| 
 | ||||
| (defun list-any? (p xs) | ||||
|   "Return t if any `XS' pass the predicate, `P'." | ||||
|   (-any? p xs)) | ||||
| 
 | ||||
| (defun list-contains? (x xs) | ||||
|   "Return t if X is in XS using `equal'." | ||||
|   (-contains? xs x)) | ||||
| 
 | ||||
| (defun list-xs-distinct-by? (f xs) | ||||
|   "Return t if all elements in XS are distinct after applying F to each." | ||||
|   (= (length xs) | ||||
|      (->> xs (-map f) set-from-list set-count))) | ||||
| 
 | ||||
| ;; TODO: Support dedupe. | ||||
| ;; TODO: Should we call this unique? Or distinct? | ||||
| 
 | ||||
| ;; TODO: Add tests. | ||||
| (defun list-dedupe-adjacent (xs) | ||||
|   "Return XS without adjacent duplicates." | ||||
|   (prelude-assert (not (list-empty? xs))) | ||||
|   (list-reduce (list (list-first xs)) | ||||
|     (lambda (x acc) | ||||
|       (if (equal x (list-first acc)) | ||||
|           acc | ||||
|         (list-cons x acc))) | ||||
|     xs)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; (when list-tests? | ||||
| ;;   (prelude-assert | ||||
| ;;    (= 0 | ||||
| ;;       (list-length '()))) | ||||
| ;;   (prelude-assert | ||||
| ;;    (= 5 | ||||
| ;;       (list-length '(1 2 3 4 5)))) | ||||
| ;;   (prelude-assert | ||||
| ;;    (= 16 | ||||
| ;;       (list-reduce 1 (lambda (x acc) (+ x acc)) '(1 2 3 4 5)))) | ||||
| ;;   (prelude-assert | ||||
| ;;    (equal '(2 4 6 8 10) | ||||
| ;;           (list-map (lambda (x) (* x 2)) '(1 2 3 4 5))))) | ||||
| 
 | ||||
| (provide 'list) | ||||
| ;;; list.el ends here | ||||
							
								
								
									
										64
									
								
								users/wpcarro/emacs/.emacs.d/wpc/macros.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								users/wpcarro/emacs/.emacs.d/wpc/macros.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,64 @@ | |||
| ;;; macros.el --- Helpful variables for making my ELisp life more enjoyable -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; This file contains helpful variables that I use in my ELisp development. | ||||
| 
 | ||||
| ;; TODO: Consider a macro solution for mimmicking OCaml's auto resolution of | ||||
| ;; dependencies using `load-path' and friends. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'f) | ||||
| (require 'string) | ||||
| (require 'symbol) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defmacro macros-enable (mode) | ||||
|   "Helper for enabling `MODE'. | ||||
| Useful in `add-hook' calls.  Some modes, like `linum-mode' need to be called as | ||||
| `(linum-mode 1)', so `(add-hook mode #'linum-mode)' won't work." | ||||
|   `#'(lambda nil (,mode 1))) | ||||
| 
 | ||||
| (defmacro macros-disable (mode) | ||||
|   "Helper for disabling `MODE'. | ||||
| Useful in `add-hook' calls." | ||||
|   `#'(lambda nil (,mode -1))) | ||||
| 
 | ||||
| (defmacro macros-add-hook-before-save (mode f) | ||||
|   "Register a hook, `F', for a mode, `MODE' more conveniently. | ||||
| Usage: (macros-add-hook-before-save 'reason-mode-hook #'refmt-before-save)" | ||||
|   `(add-hook ,mode | ||||
|              (lambda () | ||||
|                (add-hook 'before-save-hook ,f)))) | ||||
| 
 | ||||
| ;; TODO: Privatize? | ||||
| (defun macros--namespace () | ||||
|   "Return the namespace for a function based on the filename." | ||||
|   (->> (buffer-file-name) | ||||
|        f-filename | ||||
|        f-base)) | ||||
| 
 | ||||
| (defmacro macros-comment (&rest _) | ||||
|   "Empty comment s-expresion where `BODY' is ignored." | ||||
|   `nil) | ||||
| 
 | ||||
| (defmacro macros-support-file-extension (ext mode) | ||||
|   "Register MODE to automatically load with files ending with EXT extension. | ||||
| Usage: (macros-support-file-extension \"pb\" protobuf-mode)" | ||||
|   (let ((extension (string-format "\\.%s\\'" ext))) | ||||
|     `(add-to-list 'auto-mode-alist '(,extension . ,mode)))) | ||||
| 
 | ||||
| (provide 'macros) | ||||
| ;;; macros.el ends here | ||||
							
								
								
									
										63
									
								
								users/wpcarro/emacs/.emacs.d/wpc/math.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										63
									
								
								users/wpcarro/emacs/.emacs.d/wpc/math.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,63 @@ | |||
| ;;; math.el --- Math stuffs -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Containing some useful mathematical functions. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'maybe) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst math-pi pi | ||||
|   "The number pi.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Functions | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Support all three arguments. | ||||
| ;; Int -> Int -> Int -> Boolean | ||||
| (cl-defun math-triangle-of-power (&key base power result) | ||||
|   (cond | ||||
|    ((maybe-somes? base power result) | ||||
|     (error "All three arguments should not be set")) | ||||
|    ((maybe-somes? power result) | ||||
|     (message "power and result")) | ||||
|    ((maybe-somes? base result) | ||||
|     (log result base)) | ||||
|    ((maybe-somes? base power) | ||||
|     (expt base power)) | ||||
|    (t | ||||
|     (error "Two of the three arguments must be set")))) | ||||
| 
 | ||||
| (defun math-mod (x y) | ||||
|   "Return X mod Y." | ||||
|   (mod x y)) | ||||
| 
 | ||||
| (defun math-exp (x y) | ||||
|   "Return X raised to the Y." | ||||
|   (expt x y)) | ||||
| 
 | ||||
| (defun math-round (x) | ||||
|   "Round X to nearest ones digit." | ||||
|   (round x)) | ||||
| 
 | ||||
| (defun math-floor (x) | ||||
|   "Floor value X." | ||||
|   (floor x)) | ||||
| 
 | ||||
| (provide 'math) | ||||
| ;;; math.el ends here | ||||
							
								
								
									
										79
									
								
								users/wpcarro/emacs/.emacs.d/wpc/maybe.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								users/wpcarro/emacs/.emacs.d/wpc/maybe.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,79 @@ | |||
| ;;; maybe.el --- Library for dealing with nil values -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Inspired by Elm's Maybe library. | ||||
| ;; | ||||
| ;; For now, a Nothing value will be defined exclusively as a nil value.  I'm | ||||
| ;; uninterested in supported falsiness in this module even at risk of going | ||||
| ;; against the LISP grain. | ||||
| ;; | ||||
| ;; I'm avoiding introducing a struct to handle the creation of Just and Nothing | ||||
| ;; variants of Maybe.  Perhaps this is a mistake in which case this file would | ||||
| ;; be more aptly named nil.el.  I may change that.  Because of this limitation, | ||||
| ;; functions in Elm's Maybe library like andThen, which is the monadic bind for | ||||
| ;; the Maybe type, doesn't have a home here since we cannot compose multiple | ||||
| ;; Nothing or Just values without a struct or some other construct. | ||||
| ;; | ||||
| ;; Possible names for the variants of a Maybe. | ||||
| ;; None    | Some | ||||
| ;; Nothing | Something | ||||
| ;; None    | Just | ||||
| ;; Nil     | Set | ||||
| ;; | ||||
| ;; NOTE: In Elisp, values like '() (i.e. the empty list) are aliases for nil. | ||||
| ;; What else in Elisp is an alias in this way? | ||||
| ;; Examples: | ||||
| ;; TODO: Provide examples of other nil types in Elisp. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'list) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defvar maybe--run-tests? t | ||||
|   "When t, run the test suite defined herein.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun maybe-nil? (x) | ||||
|   "Return t if X is nil." | ||||
|   (eq nil x)) | ||||
| 
 | ||||
| (defun maybe-some? (x) | ||||
|   "Return t when X is non-nil." | ||||
|   (not (maybe-nil? x))) | ||||
| 
 | ||||
| (defun maybe-nils? (&rest xs) | ||||
|   "Return t if all XS are nil." | ||||
|   (list-all? #'maybe-nil? xs)) | ||||
| 
 | ||||
| (defun maybe-somes? (&rest xs) | ||||
|   "Return t if all XS are non-nil." | ||||
|   (list-all? #'maybe-some? xs)) | ||||
| 
 | ||||
| (defun maybe-default (default x) | ||||
|   "Return DEFAULT when X is nil." | ||||
|   (if (maybe-nil? x) default x)) | ||||
| 
 | ||||
| (defun maybe-map (f x) | ||||
|   "Apply F to X if X is not nil." | ||||
|   (if (maybe-some? x) | ||||
|       (funcall f x) | ||||
|     x)) | ||||
| 
 | ||||
| (provide 'maybe) | ||||
| ;;; maybe.el ends here | ||||
							
								
								
									
										69
									
								
								users/wpcarro/emacs/.emacs.d/wpc/modeline.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								users/wpcarro/emacs/.emacs.d/wpc/modeline.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,69 @@ | |||
| ;;; modeline.el --- Customize my mode-line -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Because I use EXWM, I treat my Emacs mode-line like my system bar: I need to | ||||
| ;; quickly check the system time, and I expect it to be at the bottom-right of | ||||
| ;; my Emacs frame.  I used doom-modeline for awhile, which is an impressive | ||||
| ;; package, but it conditionally colorizes on the modeline for the active | ||||
| ;; buffer.  So if my bottom-right window is inactive, I cannot see the time. | ||||
| ;; | ||||
| ;; My friend, @tazjin, has a modeline setup that I think is more compatible with | ||||
| ;; EXWM, so I'm going to base my setup off of his. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| (use-package telephone-line) | ||||
| 
 | ||||
| (defun modeline-bottom-right-window? () | ||||
|   "Determines whether the last (i.e. | ||||
| bottom-right) window of the | ||||
| active frame is showing the buffer in which this function is | ||||
|   executed." | ||||
|   (let* ((frame (selected-frame)) | ||||
|          (right-windows (window-at-side-list frame 'right)) | ||||
|          (bottom-windows (window-at-side-list frame 'bottom)) | ||||
|          (last-window (car (seq-intersection right-windows bottom-windows)))) | ||||
|     (eq (current-buffer) (window-buffer last-window)))) | ||||
| 
 | ||||
| (defun modeline-maybe-render-time () | ||||
|   "Conditionally renders the `mode-line-misc-info' string. | ||||
| 
 | ||||
|   The idea is to not display information like the current time, | ||||
|   load, battery levels on all buffers." | ||||
|   (when (modeline-bottom-right-window?) | ||||
|     (telephone-line-raw mode-line-misc-info t))) | ||||
| 
 | ||||
| (defun modeline-setup () | ||||
|   "Render my custom modeline." | ||||
|   (telephone-line-defsegment telephone-line-last-window-segment () | ||||
|     (modeline-maybe-render-time)) | ||||
|   ;; Display the current EXWM workspace index in the mode-line | ||||
|   (telephone-line-defsegment telephone-line-exwm-workspace-index () | ||||
|     (when (modeline-bottom-right-window?) | ||||
|       (format "[%s]" exwm-workspace-current-index))) | ||||
|   ;; Define a highlight font for ~ important ~ information in the last | ||||
|   ;; window. | ||||
|   (defface special-highlight | ||||
|     '((t (:foreground "white" :background "#5f627f"))) "") | ||||
|   (add-to-list 'telephone-line-faces | ||||
|                '(highlight . (special-highlight . special-highlight))) | ||||
|   (setq telephone-line-lhs | ||||
|         '((nil . (telephone-line-position-segment)) | ||||
|           (accent . (telephone-line-buffer-segment)))) | ||||
|   (setq telephone-line-rhs | ||||
|         '((accent . (telephone-line-major-mode-segment)) | ||||
|           (nil . (telephone-line-last-window-segment | ||||
|                   telephone-line-exwm-workspace-index)))) | ||||
|   (setq telephone-line-primary-left-separator 'telephone-line-tan-left | ||||
|         telephone-line-primary-right-separator 'telephone-line-tan-right | ||||
|         telephone-line-secondary-left-separator 'telephone-line-tan-hollow-left | ||||
|         telephone-line-secondary-right-separator 'telephone-line-tan-hollow-right) | ||||
|   (telephone-line-mode 1)) | ||||
| 
 | ||||
| (provide 'modeline) | ||||
| ;;; modeline.el ends here | ||||
							
								
								
									
										142
									
								
								users/wpcarro/emacs/.emacs.d/wpc/number.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										142
									
								
								users/wpcarro/emacs/.emacs.d/wpc/number.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,142 @@ | |||
| ;;; number.el --- Functions for working with numbers -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; | ||||
| ;; Classifications of numbers: | ||||
| ;; - Natural: (a.k.a positive integers, counting numbers); {1, 2, 3, ... } | ||||
| ;; | ||||
| ;; - Whole: Natural Numbers, plus zero; {0, 1, 2, 3, ...} | ||||
| ;; | ||||
| ;; - Integers: Whole numbers plus all the negatives of the natural numbers; | ||||
| ;;   {... , -2, -1, 0, 1, 2, ...} | ||||
| ;; | ||||
| ;; - Rational numbers: (a.k.a. fractions) where the top and bottom numbers are | ||||
| ;;   integers; e.g., 1/2, 3/4, 7/2, ⁻4/3, 4/1.  Note: The denominator cannot be | ||||
| ;;   0, but the numerator can be. | ||||
| ;; | ||||
| ;; - Real numbers: All numbers that can be written as a decimal.  This includes | ||||
| ;;   fractions written in decimal form e.g., 0.5, 0.75 2.35, ⁻0.073, 0.3333, or | ||||
| ;;   2.142857. It also includes all the irrational numbers such as π, √2 etc. | ||||
| ;;   Every real number corresponds to a point on the number line. | ||||
| ;; | ||||
| ;; The functions defined herein attempt to capture the mathematical definitions | ||||
| ;; of numbers and their classifications as defined above. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'dash) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst number-test? t | ||||
|   "When t, run the test suite defined herein.") | ||||
| 
 | ||||
| ;; TODO: What about int.el? | ||||
| 
 | ||||
| ;; TODO: How do we handle a number typeclass? | ||||
| 
 | ||||
| (defun number-positive? (x) | ||||
|   "Return t if `X' is a positive number." | ||||
|   (> x 0)) | ||||
| 
 | ||||
| (defun number-negative? (x) | ||||
|   "Return t if `X' is a positive number." | ||||
|   (< x 0)) | ||||
| 
 | ||||
| ;; TODO: Don't rely on this. Need to have 10.0 and 10 behave similarly. | ||||
| (defun number-float? (x) | ||||
|   "Return t if `X' is a floating point number." | ||||
|   (floatp x)) | ||||
| 
 | ||||
| (defun number-natural? (x) | ||||
|   "Return t if `X' is a natural number." | ||||
|   (and (number-positive? x) | ||||
|        (not (number-float? x)))) | ||||
| 
 | ||||
| (defun number-whole? (x) | ||||
|   "Return t if `X' is a whole number." | ||||
|   (or (= 0 x) | ||||
|       (number-natural? x))) | ||||
| 
 | ||||
| (defun number-integer? (x) | ||||
|   "Return t if `X' is an integer." | ||||
|   (or (number-whole? x) | ||||
|       (number-natural? (- x)))) | ||||
| 
 | ||||
| ;; TODO: How defensive should these guards be?  Should we assert that the inputs | ||||
| ;; are integers before checking evenness or oddness? | ||||
| 
 | ||||
| ;; TODO: Look up Runar (from Unison) definition of handling zero as even or odd. | ||||
| 
 | ||||
| ;; TODO: How should rational numbers be handled? Lisp is supposedly famous for | ||||
| ;; its handling of rational numbers. | ||||
| ;; TODO: `calc-mode' supports rational numbers as "1:2" meaning "1/2" | ||||
| ;; (defun number-rational? (x)) | ||||
| 
 | ||||
| ;; TODO: Can or should I support real numbers? | ||||
| ;; (defun number-real? (x)) | ||||
| 
 | ||||
| (defun number-even? (x) | ||||
|   "Return t if `X' is an even number." | ||||
|   (or (= 0 x) | ||||
|       (= 0 (mod x 2)))) | ||||
| 
 | ||||
| (defun number-odd? (x) | ||||
|   "Return t if `X' is an odd number." | ||||
|   (not (number-even? x))) | ||||
| 
 | ||||
| (defun number-dec (x) | ||||
|   "Subtract one from `X'. | ||||
| While this function is undeniably trivial, I have unintentionally done (- 1 x) | ||||
|   when in fact I meant to do (- x 1) that I figure it's better for this function | ||||
|   to exist, and for me to train myself to reach for it and its inc counterpart." | ||||
|   (- x 1)) | ||||
| 
 | ||||
| (defun number-inc (x) | ||||
|   "Add one to `X'." | ||||
|   (+ x 1)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (when number-test? | ||||
|   (prelude-assert | ||||
|    (number-positive? 10)) | ||||
|   (prelude-assert | ||||
|    (number-natural? 10)) | ||||
|   (prelude-assert | ||||
|    (number-whole? 10)) | ||||
|   (prelude-assert | ||||
|    (number-whole? 0)) | ||||
|   (prelude-assert | ||||
|    (number-integer? 10)) | ||||
|   ;; (prelude-assert | ||||
|   ;;  (= 120 (number-factorial 5))) | ||||
|   (prelude-assert | ||||
|    (number-even? 6)) | ||||
|   (prelude-refute | ||||
|    (number-odd? 6)) | ||||
|   (prelude-refute | ||||
|    (number-positive? -10)) | ||||
|   (prelude-refute | ||||
|    (number-natural? 10.0)) | ||||
|   (prelude-refute | ||||
|    (number-natural? -10)) | ||||
|   (prelude-refute | ||||
|    (number-natural? -10.0))) | ||||
| 
 | ||||
| (provide 'number) | ||||
| ;;; number.el ends here | ||||
							
								
								
									
										145
									
								
								users/wpcarro/emacs/.emacs.d/wpc/prelude.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										145
									
								
								users/wpcarro/emacs/.emacs.d/wpc/prelude.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,145 @@ | |||
| ;;; prelude.el --- My attempt at augmenting Elisp stdlib -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Some of these ideas are scattered across other modules like `fs', | ||||
| ;; `string-functions', etc.  I'd like to keep everything modular.  I still don't | ||||
| ;; have an answer for which items belond in `misc'; I don't want that to become | ||||
| ;; a dumping grounds.  Ideally this file will `require' all other modules and | ||||
| ;; define just a handful of functions. | ||||
| 
 | ||||
| ;; TODO: Consider removing all dependencies from prelude.el. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'dash) | ||||
| (require 's) | ||||
| (require 'f) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Utilities | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun prelude-to-string (x) | ||||
|   "Convert X to a string." | ||||
|   (format "%s" x)) | ||||
| 
 | ||||
| (defun prelude-inspect (&rest args) | ||||
|   "Message ARGS where ARGS are any type." | ||||
|   (->> args | ||||
|        (-map #'prelude-to-string) | ||||
|        (apply #'s-concat) | ||||
|        message)) | ||||
| 
 | ||||
| (defmacro prelude-call-process-to-string (cmd &rest args) | ||||
|   "Return the string output of CMD called with ARGS." | ||||
|   `(with-temp-buffer | ||||
|      (call-process ,cmd nil (current-buffer) nil ,@args) | ||||
|      (buffer-string))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Assertions | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Should I `throw' instead of `error' here? | ||||
| (defmacro prelude-assert (x) | ||||
|   "Errors unless X is t. | ||||
| These are strict assertions and purposely do not rely on truthiness." | ||||
|   (let ((as-string (prelude-to-string x))) | ||||
|     `(unless (equal t ,x) | ||||
|        (error (s-concat "Assertion failed: " ,as-string))))) | ||||
| 
 | ||||
| (defmacro prelude-refute (x) | ||||
|   "Errors unless X is nil." | ||||
|   (let ((as-string (prelude-to-string x))) | ||||
|     `(unless (equal nil ,x) | ||||
|        (error (s-concat "Refutation failed: " ,as-string))))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Adapter functions | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun prelude-identity (x) | ||||
|   "Return X unchanged." | ||||
|   x) | ||||
| 
 | ||||
| (defun prelude-const (x) | ||||
|   "Return a variadic lambda that will return X." | ||||
|   (lambda (&rest _) x)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Miscellaneous | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Consider packaging these into a linum-color.el package. | ||||
| ;; TODO: Generate the color used here from the theme. | ||||
| (defvar prelude--linum-safe? nil | ||||
|   "Flag indicating whether it is safe to work with function `linum-mode'.") | ||||
| 
 | ||||
| (defvar prelude--linum-mru-color nil | ||||
|   "Stores the color most recently attempted to be applied.") | ||||
| 
 | ||||
| (add-hook 'linum-mode-hook | ||||
|           (lambda () | ||||
|             (setq prelude--linum-safe? t) | ||||
|             (when (maybe-some? prelude--linum-mru-color) | ||||
|               (set-face-foreground 'linum prelude--linum-mru-color)))) | ||||
| 
 | ||||
| (defun prelude-set-line-number-color (color) | ||||
|   "Safely set linum color to `COLOR'. | ||||
| 
 | ||||
| If this is called before Emacs initializes, the color will be stored in | ||||
| `prelude--linum-mru-color' and applied once initialization completes. | ||||
| 
 | ||||
| Why is this safe? | ||||
| If `(set-face-foreground 'linum)' is called before initialization completes, | ||||
| Emacs will silently fail.  Without this function, it is easy to introduce | ||||
| difficult to troubleshoot bugs in your init files." | ||||
|   (if prelude--linum-safe? | ||||
|       (set-face-foreground 'linum color) | ||||
|     (setq prelude--linum-mru-color color))) | ||||
| 
 | ||||
| (defun prelude-prompt (prompt) | ||||
|   "Read input from user with PROMPT." | ||||
|   (read-string prompt)) | ||||
| 
 | ||||
| (cl-defun prelude-start-process (&key name command) | ||||
|   "Pass command string, COMMAND, and the function name, NAME. | ||||
| This is a wrapper around `start-process' that has an API that resembles | ||||
| `shell-command'." | ||||
|   ;; TODO: Fix the bug with tokenizing here, since it will split any whitespace | ||||
|   ;; character, even though it shouldn't in the case of quoted string in shell. | ||||
|   ;; e.g. - "xmodmap -e 'one two three'" => '("xmodmap" "-e" "'one two three'") | ||||
|   (prelude-refute (s-contains? "'" command)) | ||||
|   (let* ((tokens (s-split " " command)) | ||||
|          (program-name (nth 0 tokens)) | ||||
|          (program-args (cdr tokens))) | ||||
|     (apply #'start-process | ||||
|            `(,(format "*%s<%s>*" program-name name) | ||||
|              ,nil | ||||
|              ,program-name | ||||
|              ,@program-args)))) | ||||
| 
 | ||||
| (defun prelude-executable-exists? (name) | ||||
|   "Return t if CLI tool NAME exists according to the variable `exec-path'." | ||||
|   (let ((file (locate-file name exec-path))) | ||||
|     (require 'maybe) | ||||
|     (if (maybe-some? file) | ||||
|         (f-exists? file) | ||||
|       nil))) | ||||
| 
 | ||||
| (defmacro prelude-time (x) | ||||
|   "Print the time it takes to evaluate X." | ||||
|   `(benchmark 1 ',x)) | ||||
| 
 | ||||
| (provide 'prelude) | ||||
| ;;; prelude.el ends here | ||||
							
								
								
									
										70
									
								
								users/wpcarro/emacs/.emacs.d/wpc/pulse-audio.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										70
									
								
								users/wpcarro/emacs/.emacs.d/wpc/pulse-audio.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,70 @@ | |||
| ;;; pulse-audio.el --- Control audio with Elisp -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Because everything in my configuration is turning into Elisp these days. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'string) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst pulse-audio--step-size 5 | ||||
|   "The size by which to increase or decrease the volume.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun pulse-audio--message (x) | ||||
|   "Output X to *Messages*." | ||||
|   (message (string-format "[pulse-audio.el] %s" x))) | ||||
| 
 | ||||
| (defun pulse-audio-toggle-mute () | ||||
|   "Mute the default sink." | ||||
|   (interactive) | ||||
|   (prelude-start-process | ||||
|    :name "pulse-audio-toggle-mute" | ||||
|    :command "pactl set-sink-mute @DEFAULT_SINK@ toggle") | ||||
|   (pulse-audio--message "Mute toggled.")) | ||||
| 
 | ||||
| (defun pulse-audio-toggle-microphone () | ||||
|   "Mute the default sink." | ||||
|   (interactive) | ||||
|   (prelude-start-process | ||||
|    :name "pulse-audio-toggle-microphone" | ||||
|    :command "pactl set-source-mute @DEFAULT_SOURCE@ toggle") | ||||
|   (pulse-audio--message "Microphone toggled.")) | ||||
| 
 | ||||
| (defun pulse-audio-decrease-volume () | ||||
|   "Low the volume output of the default sink." | ||||
|   (interactive) | ||||
|   (prelude-start-process | ||||
|    :name "pulse-audio-decrease-volume" | ||||
|    :command (string-format "pactl set-sink-volume @DEFAULT_SINK@ -%s%%" | ||||
|                            pulse-audio--step-size)) | ||||
|   (pulse-audio--message "Volume decreased.")) | ||||
| 
 | ||||
| (defun pulse-audio-increase-volume () | ||||
|   "Raise the volume output of the default sink." | ||||
|   (interactive) | ||||
|   (prelude-start-process | ||||
|    :name "pulse-audio-increase-volume" | ||||
|    :command (string-format "pactl set-sink-volume @DEFAULT_SINK@ +%s%%" | ||||
|                            pulse-audio--step-size)) | ||||
|   (pulse-audio--message "Volume increased.")) | ||||
| 
 | ||||
| (provide 'pulse-audio) | ||||
| ;;; pulse-audio.el ends here | ||||
							
								
								
									
										81
									
								
								users/wpcarro/emacs/.emacs.d/wpc/random.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										81
									
								
								users/wpcarro/emacs/.emacs.d/wpc/random.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,81 @@ | |||
| ;;; random.el --- Functions for working with randomness -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Functions for working with randomness.  Some of this code is not as | ||||
| ;; functional as I'd like from. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'number) | ||||
| (require 'math) | ||||
| (require 'series) | ||||
| (require 'list) | ||||
| (require 'set) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun random-int (x) | ||||
|   "Return a random integer from 0 to `X'." | ||||
|   (random x)) | ||||
| 
 | ||||
| ;; TODO: Make this work with sequences instead of lists. | ||||
| (defun random-choice (xs) | ||||
|   "Return a random element of `XS'." | ||||
|   (let ((ct (list-length xs))) | ||||
|     (list-get | ||||
|      (random-int ct) | ||||
|      xs))) | ||||
| 
 | ||||
| (defun random-boolean? () | ||||
|   "Randonly return t or nil." | ||||
|   (random-choice (list t nil))) | ||||
| 
 | ||||
| ;; TODO: This may not work if any of these generate numbers like 0, 1, etc. | ||||
| (defun random-uuid () | ||||
|   "Return a generated UUID string." | ||||
|   (let ((eight  (number-dec (math-triangle-of-power :base 16 :power 8))) | ||||
|         (four   (number-dec (math-triangle-of-power :base 16 :power 4))) | ||||
|         (twelve (number-dec (math-triangle-of-power :base 16 :power 12)))) | ||||
|     (format "%x-%x-%x-%x-%x" | ||||
|             (random-int eight) | ||||
|             (random-int four) | ||||
|             (random-int four) | ||||
|             (random-int four) | ||||
|             (random-int twelve)))) | ||||
| 
 | ||||
| (defun random-token (length) | ||||
|   "Return a randomly generated hexadecimal string of LENGTH." | ||||
|   (->> (series/range 0 (number-dec length)) | ||||
|        (list-map (lambda (_) (format "%x" (random-int 15)))) | ||||
|        (list-join ""))) | ||||
| 
 | ||||
| ;; TODO: Support random-sample | ||||
| ;; (defun random-sample (n xs) | ||||
| ;;   "Return a randomly sample of list XS of size N." | ||||
| ;;   (prelude-assert (and (>= n 0) (< n (list-length xs)))) | ||||
| ;;   (cl-labels ((do-sample | ||||
| ;;                (n xs y ys) | ||||
| ;;                (if (= n (set-count ys)) | ||||
| ;;                    (->> ys | ||||
| ;;                         set-to-list | ||||
| ;;                         (list-map (lambda (i) | ||||
| ;;                                     (list-get i xs)))) | ||||
| ;;                  (if (set-contains? y ys) | ||||
| ;;                      (do-sample n xs (random-int (list-length xs)) ys) | ||||
| ;;                    (do-sample n xs y (set-add y ys)))))) | ||||
| ;;     (do-sample n xs (random-int (list-length xs)) (set-new)))) | ||||
| 
 | ||||
| (provide 'random) | ||||
| ;;; random.el ends here | ||||
							
								
								
									
										24
									
								
								users/wpcarro/emacs/.emacs.d/wpc/region.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								users/wpcarro/emacs/.emacs.d/wpc/region.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,24 @@ | |||
| ;;; region.el --- Functions for working with regions -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Sometimes Emacs's function names and argument ordering is great; other times, | ||||
| ;; it isn't. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun region-to-string () | ||||
|   "Return the string in the active region." | ||||
|   (buffer-substring-no-properties (region-beginning) | ||||
|                                   (region-end))) | ||||
| 
 | ||||
| (provide 'region) | ||||
| ;;; region.el ends here | ||||
							
								
								
									
										107
									
								
								users/wpcarro/emacs/.emacs.d/wpc/scope.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										107
									
								
								users/wpcarro/emacs/.emacs.d/wpc/scope.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,107 @@ | |||
| ;;; scope.el --- Work with a scope data structure -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Exposing an API for working with a scope data structure in a non-mutative | ||||
| ;; way. | ||||
| ;; | ||||
| ;; What's a scope?  Think of a scope as a stack of key-value bindings. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'al) | ||||
| (require 'stack) | ||||
| (require 'struct) | ||||
| (require '>) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Create | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defstruct scope scopes) | ||||
| 
 | ||||
| (defun scope-new () | ||||
|   "Return an empty scope." | ||||
|   (make-scope :scopes (->> (stack-new) | ||||
|                            (stack-push (al-new))))) | ||||
| 
 | ||||
| (defun scope-flatten (xs) | ||||
|   "Return a flattened representation of the scope, XS. | ||||
| The newest bindings eclipse the oldest." | ||||
|   (->> xs | ||||
|        scope-scopes | ||||
|        stack-to-list | ||||
|        (list-reduce (al-new) | ||||
|                     (lambda (scope acc) | ||||
|                       (al-merge acc scope))))) | ||||
| 
 | ||||
| (defun scope-push-new (xs) | ||||
|   "Push a new, empty scope onto XS." | ||||
|   (struct-update scope | ||||
|                  scopes | ||||
|                  (>-> (stack-push (al-new))) | ||||
|                  xs)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Read | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun scope-get (k xs) | ||||
|   "Return K from XS if it's in scope." | ||||
|   (->> xs | ||||
|        scope-flatten | ||||
|        (al-get k))) | ||||
| 
 | ||||
| (defun scope-current (xs) | ||||
|   "Return the newest scope from XS." | ||||
|   (let ((xs-copy (copy-scope xs))) | ||||
|     (->> xs-copy | ||||
|          scope-scopes | ||||
|          stack-peek))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Update | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun scope-set (k v xs) | ||||
|   "Set value, V, at key, K, in XS for the current scope." | ||||
|   (struct-update scope | ||||
|                  scopes | ||||
|                  (>-> (stack-map-top (>-> (al-set k v)))) | ||||
|                  xs)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Delete | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun scope-pop (xs) | ||||
|   "Return a new scope without the top element from XS." | ||||
|   (->> xs | ||||
|        scope-scopes | ||||
|        stack-pop)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Predicates | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun scope-defined? (k xs) | ||||
|   "Return t if K is in scope of XS." | ||||
|   (->> xs | ||||
|        scope-flatten | ||||
|        (al-has-key? k))) | ||||
| 
 | ||||
| ;; TODO: Find a faster way to write aliases like this. | ||||
| (defun scope-instance? (xs) | ||||
|   "Return t if XS is a scope struct." | ||||
|   (scope-p xs)) | ||||
| 
 | ||||
| (provide 'scope) | ||||
| ;;; scope.el ends here | ||||
							
								
								
									
										49
									
								
								users/wpcarro/emacs/.emacs.d/wpc/screen-brightness.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								users/wpcarro/emacs/.emacs.d/wpc/screen-brightness.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| ;;; screen-brightness.el --- Control laptop screen brightness -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Mainly just Elisp wrappers around `xbacklight`. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;; TODO: Define some isomorphisms. E.g. int->string, string->int. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Constants | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst screen-brightness-step-size 15 | ||||
|   "The size of the increment or decrement step for the screen's brightness.") | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun screen-brightness-increase () | ||||
|   "Increase the screen brightness." | ||||
|   (interactive) | ||||
|   (prelude-start-process | ||||
|    :name "screen-brightness-increase" | ||||
|    :command (string-format "xbacklight -inc %s" screen-brightness-step-size)) | ||||
|   (message "[screen-brightness.el] Increased screen brightness.")) | ||||
| 
 | ||||
| (defun screen-brightness-decrease () | ||||
|   "Decrease the screen brightness." | ||||
|   (interactive) | ||||
|   (prelude-start-process | ||||
|    :name "screen-brightness-decrease" | ||||
|    :command (string-format "xbacklight -dec %s" screen-brightness-step-size)) | ||||
|   (message "[screen-brightness.el] Decreased screen brightness.")) | ||||
| 
 | ||||
| (provide 'screen-brightness) | ||||
| ;;; screen-brightness.el ends here | ||||
							
								
								
									
										58
									
								
								users/wpcarro/emacs/.emacs.d/wpc/scrot.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										58
									
								
								users/wpcarro/emacs/.emacs.d/wpc/scrot.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,58 @@ | |||
| ;;; scrot.el --- Screenshot functions -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; scrot is a Linux utility for taking screenshots. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'f) | ||||
| (require 'string) | ||||
| (require 'ts) | ||||
| (require 'clipboard) | ||||
| (require 'kbd) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst scrot-screenshot-directory "~/Downloads" | ||||
|   "The default directory for screenshot outputs.") | ||||
| 
 | ||||
| (defconst scrot-path-to-executable "/usr/bin/scrot" | ||||
|   "Path to the scrot executable.") | ||||
| 
 | ||||
| (defconst scrot-output-format "screenshot_%H:%M:%S_%Y-%m-%d.png" | ||||
|   "The format string for the output screenshot file. | ||||
| See scrot's man page for more information.") | ||||
| 
 | ||||
| (defun scrot--copy-image (path) | ||||
|   "Use xclip to copy the image at PATH to the clipboard. | ||||
| This currently only works for PNG files because that's what I'm outputting" | ||||
|   (call-process "xclip" nil nil nil | ||||
|                 "-selection" "clipboard" "-t" "image/png" path) | ||||
|   (message (string-format "[scrot.el] Image copied to clipboard!"))) | ||||
| 
 | ||||
| (defun scrot-select () | ||||
|   "Click-and-drag to screenshot a region. | ||||
| The output path is copied to the user's clipboard." | ||||
|   (interactive) | ||||
|   (let ((screenshot-path (f-join scrot-screenshot-directory | ||||
|                                  (ts-format scrot-output-format (ts-now))))) | ||||
|     (make-process | ||||
|      :name "scrot-select" | ||||
|      :command `(,scrot-path-to-executable "--select" ,screenshot-path) | ||||
|      :sentinel (lambda (proc _err) | ||||
|                  (when (= 0 (process-exit-status proc)) | ||||
|                    (scrot--copy-image screenshot-path)))))) | ||||
| 
 | ||||
| (provide 'scrot) | ||||
| ;;; scrot.el ends here | ||||
							
								
								
									
										109
									
								
								users/wpcarro/emacs/.emacs.d/wpc/sequence.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										109
									
								
								users/wpcarro/emacs/.emacs.d/wpc/sequence.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,109 @@ | |||
| ;;; sequence.el --- Working with the "sequence" types -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Elisp supports a typeclass none as "sequence" which covers the following | ||||
| ;; types: | ||||
| ;; - list: '(1 2 3 4 5) | ||||
| ;; - vector: ["John" 27 :blue] | ||||
| ;; - string: "To be or not to be..." | ||||
| 
 | ||||
| ;; TODO: Document the difference between a "reduce" and a "fold".  I.e. - reduce | ||||
| ;; has an initial value whereas fold uses the first element in the sequence as | ||||
| ;; the initial value. | ||||
| ;; | ||||
| ;; Note: This should be an approximation of Elixir's Enum protocol albeit | ||||
| ;; without streams. | ||||
| ;; | ||||
| ;; Elisp has done a lot of this work already and these are mostly wrapper | ||||
| ;; functions. | ||||
| ;; See the following list for reference: | ||||
| ;; - sequencep | ||||
| ;; - elt | ||||
| ;; - copy-sequence | ||||
| ;; - reverse | ||||
| ;; - nreverse | ||||
| ;; - sort | ||||
| ;; - seq-elt | ||||
| ;; - seq-length | ||||
| ;; - seqp | ||||
| ;; - seq-drop | ||||
| ;; - seq-take | ||||
| ;; - seq-take-while | ||||
| ;; - seq-drop-while | ||||
| ;; - seq-do | ||||
| ;; - seq-map | ||||
| ;; - seq-mapn | ||||
| ;; - seq-filter | ||||
| ;; - seq-remove | ||||
| ;; - seq-reduce | ||||
| ;; - seq-some | ||||
| ;; - seq-find | ||||
| ;; - seq-every-p | ||||
| ;; - seq-empty-p | ||||
| ;; - seq-count | ||||
| ;; - seq-sort | ||||
| ;; - seq-contains | ||||
| ;; - seq-position | ||||
| ;; - seq-uniq | ||||
| ;; - seq-subseq | ||||
| ;; - seq-concatenate | ||||
| ;; - seq-mapcat | ||||
| ;; - seq-partition | ||||
| ;; - seq-intersection | ||||
| ;; - seq-difference | ||||
| ;; - seq-group-by | ||||
| ;; - seq-into | ||||
| ;; - seq-min | ||||
| ;; - seq-max | ||||
| ;; - seq-doseq | ||||
| ;; - seq-let | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;; Perhaps we can provide default implementations for `filter' and `map' derived | ||||
| ;; from the `reduce' implementation. | ||||
| ;; (defprotocol sequence | ||||
| ;;   :functions (reduce)) | ||||
| ;; (definstance sequence list | ||||
| ;;   :reduce #'list-reduce | ||||
| ;;   :filter #'list-filter | ||||
| ;;   :map    #'list-map) | ||||
| ;; (definstance sequence vector | ||||
| ;;   :reduce #'vector/reduce) | ||||
| ;; (definstance sequence string | ||||
| ;;   :reduce #'string) | ||||
| 
 | ||||
| (defun sequence-classify (xs) | ||||
|   "Return the type of `XS'." | ||||
|   (cond | ||||
|    ((listp xs) 'list) | ||||
|    ((vectorp xs) 'vector) | ||||
|    ((stringp xs) 'string))) | ||||
| 
 | ||||
| (defun sequence-reduce (acc f xs) | ||||
|   "Reduce of `XS' calling `F' on x and `ACC'." | ||||
|   (seq-reduce | ||||
|    (lambda (acc x) | ||||
|      (funcall f x acc)) | ||||
|    xs | ||||
|    acc)) | ||||
| 
 | ||||
| ;; Elixir also turned everything into a list for efficiecy reasons. | ||||
| 
 | ||||
| (defun sequence-filter (p xs) | ||||
|   "Filter `XS' with predicate, `P'. | ||||
| Returns a list regardless of the type of `XS'." | ||||
|   (seq-filter p xs)) | ||||
| 
 | ||||
| (defun sequence-map (f xs) | ||||
|   "Maps `XS' calling `F' on each element. | ||||
| Returns a list regardless of the type of `XS'." | ||||
|   (seq-map f xs)) | ||||
| 
 | ||||
| (provide 'sequence) | ||||
| ;;; sequence.el ends here | ||||
							
								
								
									
										93
									
								
								users/wpcarro/emacs/.emacs.d/wpc/series.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										93
									
								
								users/wpcarro/emacs/.emacs.d/wpc/series.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,93 @@ | |||
| ;;; series.el --- Hosting common series of numbers -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Encoding number series as I learn about them. | ||||
| ;; | ||||
| ;; These are the following series I'm interested in supporting: | ||||
| ;; - Fibonacci | ||||
| ;; - Catalan numbers | ||||
| ;; - Figurate number series | ||||
| ;;   - Triangular | ||||
| ;;   - Square | ||||
| ;;   - Pentagonal | ||||
| ;;   - Hexagonal | ||||
| ;;   - Lazy-caterer | ||||
| ;; - Magic square | ||||
| ;; - Look-and-say | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'number) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun series-range (beg end) | ||||
|   "Create a list of numbers from `BEG' to `END'. | ||||
| This is an inclusive number range." | ||||
|   (if (< end beg) | ||||
|       (list-reverse | ||||
|        (number-sequence end beg)) | ||||
|     (number-sequence beg end))) | ||||
| 
 | ||||
| (defun series-fibonacci-number (i) | ||||
|   "Return the number in the fibonacci series at `I'." | ||||
|   (cond | ||||
|    ((= 0 i) 0) | ||||
|    ((= 1 i) 1) | ||||
|    (t (+ (series-fibonacci-number (- i 1)) | ||||
|          (series-fibonacci-number (- i 2)))))) | ||||
| 
 | ||||
| (defun series-fibonacci (n) | ||||
|   "Return the first `N' numbers of the fibonaccci series starting at zero." | ||||
|   (if (= 0 n) | ||||
|       '() | ||||
|     (list-reverse | ||||
|      (list-cons (series-fibonacci-number (number-dec n)) | ||||
|                 (list-reverse | ||||
|                  (series-fibonacci (number-dec n))))))) | ||||
| 
 | ||||
| ;; TODO: Consider memoization. | ||||
| (defun series-triangular-number (i) | ||||
|   "Return the number in the triangular series at `I'." | ||||
|   (if (= 0 i) | ||||
|       0 | ||||
|     (+ i (series-triangular-number (number-dec i))))) | ||||
| 
 | ||||
| ;; TODO: Improve performance. | ||||
| ;; TODO: Consider creating a stream protocol with `stream/next' and implement | ||||
| ;; this using that. | ||||
| (defun series-triangular (n) | ||||
|   "Return the first `N' numbers of a triangular series starting at 0." | ||||
|   (if (= 0 n) | ||||
|       '() | ||||
|     (list-reverse | ||||
|      (list-cons (series-triangular-number (number-dec n)) | ||||
|                 (list-reverse | ||||
|                  (series-triangular (number-dec n))))))) | ||||
| 
 | ||||
| (defun series-catalan-number (i) | ||||
|   "Return the catalan number in the series at `I'." | ||||
|   (if (= 0 i) | ||||
|       1 | ||||
|     (/ (number-factorial (* 2 i)) | ||||
|        (* (number-factorial (number-inc i)) | ||||
|           (number-factorial i))))) | ||||
| 
 | ||||
| (defun series-catalan (n) | ||||
|   "Return the first `N' numbers in a catalan series." | ||||
|   (->> (series-range 0 (number-dec n)) | ||||
|        (list-map #'series-catalan-number))) | ||||
| 
 | ||||
| (provide 'series) | ||||
| ;;; series.el ends here | ||||
							
								
								
									
										175
									
								
								users/wpcarro/emacs/.emacs.d/wpc/set.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										175
									
								
								users/wpcarro/emacs/.emacs.d/wpc/set.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,175 @@ | |||
| ;;; set.el --- Working with mathematical sets -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; The set data structure is a collection that deduplicates its elements. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| (require 'ht) ;; friendlier API for hash-tables | ||||
| (require 'dotted) | ||||
| (require 'struct) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Wish List | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; - TODO: Support enum protocol for set. | ||||
| ;; - TODO: Prefer a different hash-table library that doesn't rely on mutative | ||||
| ;;   code. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defstruct set xs) | ||||
| 
 | ||||
| (defconst set-enable-testing? t | ||||
|   "Run tests when t.") | ||||
| 
 | ||||
| (defun set-from-list (xs) | ||||
|   "Create a new set from the list XS." | ||||
|   (make-set :xs (->> xs | ||||
|                      (list-map #'dotted-new) | ||||
|                      ht-from-alist))) | ||||
| 
 | ||||
| (defun set-new (&rest args) | ||||
|   "Create a new set from ARGS." | ||||
|   (set-from-list args)) | ||||
| 
 | ||||
| (defun set-to-list (xs) | ||||
|   "Map set XS into a list." | ||||
|   (->> xs | ||||
|        set-xs | ||||
|        ht-keys)) | ||||
| 
 | ||||
| (defun set-add (x xs) | ||||
|   "Add X to set XS." | ||||
|   (struct-update set | ||||
|                  xs | ||||
|                  (lambda (table) | ||||
|                    (let ((table-copy (ht-copy table))) | ||||
|                      (ht-set table-copy x nil) | ||||
|                      table-copy)) | ||||
|                  xs)) | ||||
| 
 | ||||
| ;; TODO: Ensure all `*/reduce' functions share the same API. | ||||
| (defun set-reduce (acc f xs) | ||||
|   "Return a new set by calling F on each element of XS and ACC." | ||||
|   (->> xs | ||||
|        set-to-list | ||||
|        (list-reduce acc f))) | ||||
| 
 | ||||
| (defun set-intersection (a b) | ||||
|   "Return the set intersection between A and B." | ||||
|   (set-reduce (set-new) | ||||
|               (lambda (x acc) | ||||
|                 (if (set-contains? x b) | ||||
|                     (set-add x acc) | ||||
|                   acc)) | ||||
|               a)) | ||||
| 
 | ||||
| (defun set-count (xs) | ||||
|   "Return the number of elements in XS." | ||||
|   (->> xs | ||||
|        set-xs | ||||
|        ht-size)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Predicates | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun set-empty? (xs) | ||||
|   "Return t if XS has no elements in it." | ||||
|   (= 0 (set-count xs))) | ||||
| 
 | ||||
| (defun set-contains? (x xs) | ||||
|   "Return t if set XS has X." | ||||
|   (ht-contains? (set-xs xs) x)) | ||||
| 
 | ||||
| ;; TODO: Prefer using `ht.el' functions for this. | ||||
| (defun set-equal? (a b) | ||||
|   "Return t if A and B share the name members." | ||||
|   (ht-equal? (set-xs a) | ||||
|              (set-xs b))) | ||||
| 
 | ||||
| (defun set-distinct? (a b) | ||||
|   "Return t if A and B have no shared members." | ||||
|   (set-empty? (set-intersection a b))) | ||||
| 
 | ||||
| (defun set-superset? (a b) | ||||
|   "Return t if A has all of the members of B." | ||||
|   (->> b | ||||
|        set-to-list | ||||
|        (list-all? (lambda (x) (set-contains? x a))))) | ||||
| 
 | ||||
| (defun set-subset? (a b) | ||||
|   "Return t if each member of set A is present in set B." | ||||
|   (set-superset? b a)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (when set-enable-testing? | ||||
|   ;; set-distinct? | ||||
|   (prelude-assert | ||||
|    (set-distinct? (set-new 'one 'two 'three) | ||||
|                   (set-new 'a 'b 'c))) | ||||
|   (prelude-refute | ||||
|    (set-distinct? (set-new 1 2 3) | ||||
|                   (set-new 3 4 5))) | ||||
|   (prelude-refute | ||||
|    (set-distinct? (set-new 1 2 3) | ||||
|                   (set-new 1 2 3))) | ||||
|   ;; set-equal? | ||||
|   (prelude-refute | ||||
|    (set-equal? (set-new 'a 'b 'c) | ||||
|                (set-new 'x 'y 'z))) | ||||
|   (prelude-refute | ||||
|    (set-equal? (set-new 'a 'b 'c) | ||||
|                (set-new 'a 'b))) | ||||
|   (prelude-assert | ||||
|    (set-equal? (set-new 'a 'b 'c) | ||||
|                (set-new 'a 'b 'c))) | ||||
|   ;; set-intersection | ||||
|   (prelude-assert | ||||
|    (set-equal? (set-new 2 3) | ||||
|                (set-intersection (set-new 1 2 3) | ||||
|                                  (set-new 2 3 4)))) | ||||
|   ;; set-{from,to}-list | ||||
|   (prelude-assert (equal '(1 2 3) | ||||
|                          (->> '(1 1 2 2 3 3) | ||||
|                               set-from-list | ||||
|                               set-to-list))) | ||||
|   (let ((primary-colors (set-new "red" "green" "blue"))) | ||||
|     ;; set-subset? | ||||
|     (prelude-refute | ||||
|      (set-subset? (set-new "black" "grey") | ||||
|                   primary-colors)) | ||||
|     (prelude-assert | ||||
|      (set-subset? (set-new "red") | ||||
|                   primary-colors)) | ||||
|     ;; set-superset? | ||||
|     (prelude-refute | ||||
|      (set-superset? primary-colors | ||||
|                     (set-new "black" "grey"))) | ||||
|     (prelude-assert | ||||
|      (set-superset? primary-colors | ||||
|                     (set-new "red" "green" "blue"))) | ||||
|     (prelude-assert | ||||
|      (set-superset? primary-colors | ||||
|                     (set-new "red" "blue")))) | ||||
|   ;; set-empty? | ||||
|   (prelude-assert (set-empty? (set-new))) | ||||
|   (prelude-refute (set-empty? (set-new 1 2 3))) | ||||
|   ;; set-count | ||||
|   (prelude-assert (= 0 (set-count (set-new)))) | ||||
|   (prelude-assert (= 2 (set-count (set-new 1 1 2 2))))) | ||||
| 
 | ||||
| (provide 'set) | ||||
| ;;; set.el ends here | ||||
							
								
								
									
										65
									
								
								users/wpcarro/emacs/.emacs.d/wpc/ssh.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								users/wpcarro/emacs/.emacs.d/wpc/ssh.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,65 @@ | |||
| ;;; ssh.el --- When working remotely -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Configuration to make remote work easier. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'tramp) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Is "ssh" preferable to "scp"? | ||||
| (setq tramp-default-method "ssh") | ||||
| 
 | ||||
| ;; Taken from: https://superuser.com/questions/179313/tramp-waiting-for-prompts-from-remote-shell | ||||
| (setq tramp-shell-prompt-pattern "^[^$>\n]*[#$%>] *\\(\[[0-9;]*[a-zA-Z] *\\)*") | ||||
| 
 | ||||
| ;; Sets the value of the TERM variable to "dumb" when logging into the remote | ||||
| ;; host. This allows me to check for the value of "dumb" in my shell's init file | ||||
| ;; and control the startup accordingly. You can see in the (shamefully large) | ||||
| ;; commit, 0b4ef0e, that I added a check like this to my ~/.zshrc. I've since | ||||
| ;; switched from z-shell to fish. I don't currently have this check in | ||||
| ;; config.fish, but I may need to add it one day soon. | ||||
| (setq tramp-terminal-type "dumb") | ||||
| 
 | ||||
| ;; Maximizes the tramp debugging noisiness while I'm still learning about tramp. | ||||
| (setq tramp-verbose 10) | ||||
| 
 | ||||
| ;; As confusing as this may seem, this forces Tramp to use *my* .ssh/config | ||||
| ;; options, which enable ControlMaster. In other words, disabling this actually | ||||
| ;; enables ControlMaster. | ||||
| (setq tramp-use-ssh-controlmaster-options nil) | ||||
| 
 | ||||
| (defcustom ssh-hosts '("desktop" "socrates") | ||||
|   "List of hosts to which I commonly connect. | ||||
| Note: It could be interesting to read these values from ~/.ssh-config, but | ||||
|   that's more than I need at the moment.") | ||||
| 
 | ||||
| (defun ssh-sudo-buffer () | ||||
|   "Open the current buffer with sudo rights." | ||||
|   (interactive) | ||||
|   (with-current-buffer (current-buffer) | ||||
|     (if (s-starts-with? "/ssh:" buffer-file-name) | ||||
|         (message "[ssh.el] calling ssh-sudo-buffer for remote files isn't currently supported") | ||||
|       (find-file (format "/sudo::%s" buffer-file-name))))) | ||||
| 
 | ||||
| (defun ssh-cd-home () | ||||
|   "Prompt for an SSH host and open a dired buffer for wpcarro on that machine." | ||||
|   (interactive) | ||||
|   (let ((machine (completing-read "Machine: " ssh-hosts))) | ||||
|     (find-file (format "/ssh:wpcarro@%s:~" machine)))) | ||||
| 
 | ||||
| (provide 'ssh) | ||||
| ;;; ssh.el ends here | ||||
							
								
								
									
										102
									
								
								users/wpcarro/emacs/.emacs.d/wpc/stack.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								users/wpcarro/emacs/.emacs.d/wpc/stack.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,102 @@ | |||
| ;;; stack.el --- Working with stacks in Elisp -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; A stack is a LIFO queue. | ||||
| ;; The design goal here is to expose an intuitive API for working with stacks in | ||||
| ;; non-mutative way. | ||||
| ;; | ||||
| ;; TODO: Consider naming a Functor instance "Mappable." | ||||
| ;; TODO: Consider naming a Foldable instance "Reduceable." | ||||
| ;; | ||||
| ;; TODO: Consider implementing an instance for Mappable. | ||||
| ;; TODO: Consider implementing an instance for Reduceable. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'list) | ||||
| (require '>) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Create | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defstruct stack xs) | ||||
| 
 | ||||
| (defun stack-new () | ||||
|   "Create an empty stack." | ||||
|   (make-stack :xs '())) | ||||
| 
 | ||||
| (defun stack-from-list (xs) | ||||
|   "Create a new stack from the list, `XS'." | ||||
|   (list-reduce (stack-new) #'stack-push xs)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Read | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun stack-peek (xs) | ||||
|   "Look at the top element of `XS' without popping it off." | ||||
|   (->> xs | ||||
|        stack-xs | ||||
|        list-head)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Update | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun stack-push (x xs) | ||||
|   "Push `X' on `XS'." | ||||
|   (struct-update stack | ||||
|                  xs | ||||
|                  (>-> (list-cons x)) | ||||
|                  xs)) | ||||
| 
 | ||||
| ;; TODO: How to return something like {(list-head xs), (list-tail xs)} in Elixir | ||||
| ;; TODO: How to handle popping from empty stacks? | ||||
| (defun stack-pop (xs) | ||||
|   "Return the stack, `XS', without the top element. | ||||
| Since I cannot figure out a nice way of return tuples in Elisp, if you want to | ||||
| look at the first element, use `stack-peek' before running `stack-pop'." | ||||
|   (struct-update stack | ||||
|                  xs | ||||
|                  (>-> list-tail) | ||||
|                  xs)) | ||||
| 
 | ||||
| (defun stack-map-top (f xs) | ||||
|   "Apply F to the top element of XS." | ||||
|   (->> xs | ||||
|        stack-pop | ||||
|        (stack-push (funcall f (stack-peek xs))))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Miscellaneous | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun stack-to-list (xs) | ||||
|   "Return XS as a list. | ||||
| The round-trip property of `stack-from-list' and `stack-to-list' should hold." | ||||
|   (->> xs | ||||
|        stack-xs | ||||
|        list-reverse)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Predicates | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Create a macro that wraps `cl-defstruct' that automatically creates | ||||
| ;; things like `new', `instance?'. | ||||
| (defun stack-instance? (xs) | ||||
|   "Return t if XS is a stack." | ||||
|   (stack-p xs)) | ||||
| 
 | ||||
| (provide 'stack) | ||||
| ;;; stack.el ends here | ||||
							
								
								
									
										111
									
								
								users/wpcarro/emacs/.emacs.d/wpc/string.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										111
									
								
								users/wpcarro/emacs/.emacs.d/wpc/string.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,111 @@ | |||
| ;;; string.el --- Library for working with strings -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Library for working with string. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 's) | ||||
| (require 'dash) | ||||
| ;; TODO: Resolve the circular dependency that this introduces. | ||||
| ;; (require 'prelude) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun string-contains? (c x) | ||||
|   "Return t if X is in C." | ||||
|   (s-contains? c x)) | ||||
| 
 | ||||
| (defun string-hookify (x) | ||||
|   "Append \"-hook\" to X." | ||||
|   (s-append "-hook" x)) | ||||
| 
 | ||||
| (defun string-split (y x) | ||||
|   "Map string X into a list of strings that were separated by Y." | ||||
|   (s-split y x)) | ||||
| 
 | ||||
| (defun string-ensure-hookified (x) | ||||
|   "Ensure that X has \"-hook\" appended to it." | ||||
|   (if (s-ends-with? "-hook" x) | ||||
|       x | ||||
|     (string-hookify x))) | ||||
| 
 | ||||
| (defun string-format (x &rest args) | ||||
|   "Format template string X with ARGS." | ||||
|   (apply #'format (cons x args))) | ||||
| 
 | ||||
| (defun string-concat (&rest strings) | ||||
|   "Joins `STRINGS' into onto string." | ||||
|   (apply #'s-concat strings)) | ||||
| 
 | ||||
| (defun string-->symbol (string) | ||||
|   "Maps `STRING' to a symbol." | ||||
|   (intern string)) | ||||
| 
 | ||||
| (defun string-<-symbol (symbol) | ||||
|   "Maps `SYMBOL' into a string." | ||||
|   (symbol-name symbol)) | ||||
| 
 | ||||
| (defun string-prepend (prefix x) | ||||
|   "Prepend `PREFIX' onto `X'." | ||||
|   (s-concat prefix x)) | ||||
| 
 | ||||
| (defun string-append (postfix x) | ||||
|   "Appen `POSTFIX' onto `X'." | ||||
|   (s-concat x postfix)) | ||||
| 
 | ||||
| (defun string-surround (s x) | ||||
|   "Surrounds `X' one each side with `S'." | ||||
|   (->> x | ||||
|        (string-prepend s) | ||||
|        (string-append s))) | ||||
| 
 | ||||
| ;; TODO: Define a macro for defining a function and a test. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Casing | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun string-caps->kebab (x) | ||||
|   "Change the casing of `X' from CAP_CASE to kebab-case." | ||||
|   (->> x | ||||
|        s-downcase | ||||
|        (s-replace "_" "-"))) | ||||
| 
 | ||||
| (defun string-kebab->caps (x) | ||||
|   "Change the casing of X from CAP_CASE to kebab-case." | ||||
|   (->> x | ||||
|        s-upcase | ||||
|        (s-replace "-" "_"))) | ||||
| 
 | ||||
| (defun string-lower->caps (x) | ||||
|   "Change the casing of X from lowercase to CAPS_CASE." | ||||
|   (->> x | ||||
|        s-upcase | ||||
|        (s-replace " " "_"))) | ||||
| 
 | ||||
| (defun string-lower->kebab (x) | ||||
|   "Change the casing of `X' from lowercase to kebab-case." | ||||
|   (s-replace " " "-" x)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Predicates | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun string-instance? (x) | ||||
|   "Return t if X is a string." | ||||
|   (stringp x)) | ||||
| 
 | ||||
| (provide 'string) | ||||
| ;;; string.el ends here | ||||
							
								
								
									
										86
									
								
								users/wpcarro/emacs/.emacs.d/wpc/struct.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								users/wpcarro/emacs/.emacs.d/wpc/struct.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,86 @@ | |||
| ;;; struct.el --- Helpers for working with structs -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24.3")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Provides new macros for working with structs.  Also provides adapter | ||||
| ;; interfaces to existing struct macros, that should have more intuitive | ||||
| ;; interfaces. | ||||
| ;; | ||||
| ;; Sometimes `setf' just isn't enough. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'string) | ||||
| (require 'dash) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defvar struct--enable-tests? t | ||||
|   "When t, run the test suite defined herein.") | ||||
| 
 | ||||
| (defmacro struct-update (type field f xs) | ||||
|   "Apply F to FIELD in XS, which is a struct of TYPE. | ||||
| This is immutable." | ||||
|   (let ((copier (->> type | ||||
|                      symbol-name | ||||
|                      (string-prepend "copy-") | ||||
|                      intern)) | ||||
|         (accessor (->> field | ||||
|                        symbol-name | ||||
|                        (string-prepend (string-concat (symbol-name type) "-")) | ||||
|                        intern))) | ||||
|     `(let ((copy (,copier ,xs))) | ||||
|        (setf (,accessor copy) (funcall ,f (,accessor copy))) | ||||
|        copy))) | ||||
| 
 | ||||
| (defmacro struct-set (type field x xs) | ||||
|   "Immutably set FIELD in XS (struct TYPE) to X." | ||||
|   (let ((copier (->> type | ||||
|                      symbol-name | ||||
|                      (string-prepend "copy-") | ||||
|                      intern)) | ||||
|         (accessor (->> field | ||||
|                        symbol-name | ||||
|                        (string-prepend (string-concat (symbol-name type) "-")) | ||||
|                        intern))) | ||||
|     `(let ((copy (,copier ,xs))) | ||||
|        (setf (,accessor copy) ,x) | ||||
|        copy))) | ||||
| 
 | ||||
| (defmacro struct-set! (type field x xs) | ||||
|   "Set FIELD in XS (struct TYPE) to X mutably. | ||||
| This is an adapter interface to `setf'." | ||||
|   (let ((accessor (->> field | ||||
|                        symbol-name | ||||
|                        (string-prepend (string-concat (symbol-name type) "-")) | ||||
|                        intern))) | ||||
|     `(progn | ||||
|        (setf (,accessor ,xs) ,x) | ||||
|        ,xs))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (when struct--enable-tests? | ||||
|   (cl-defstruct dummy name age) | ||||
|   (defvar struct--test-dummy (make-dummy :name "Roofus" :age 19)) | ||||
|   (struct-set! dummy name "Doofus" struct--test-dummy) | ||||
|   (prelude-assert (string= "Doofus" (dummy-name struct--test-dummy))) | ||||
|   (let ((result (struct-set dummy name "Shoofus" struct--test-dummy))) | ||||
|     ;; Test the immutability of `struct-set' | ||||
|     (prelude-assert (string= "Doofus" (dummy-name struct--test-dummy))) | ||||
|     (prelude-assert (string= "Shoofus" (dummy-name result))))) | ||||
| 
 | ||||
| (provide 'struct) | ||||
| ;;; struct.el ends here | ||||
							
								
								
									
										49
									
								
								users/wpcarro/emacs/.emacs.d/wpc/symbol.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								users/wpcarro/emacs/.emacs.d/wpc/symbol.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,49 @@ | |||
| ;;; symbol.el --- Library for working with symbols -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Library for working with symbols. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'string) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; Symbols | ||||
| (defun symbol-as-string (callback x) | ||||
|   "Treat the symbol, X, as a string while applying CALLBACK to it. | ||||
| Coerce back to a symbol on the way out." | ||||
|   (->> x | ||||
|        #'symbol-name | ||||
|        callback | ||||
|        #'intern)) | ||||
| 
 | ||||
| (defun symbol-to-string (x) | ||||
|   "Map `X' into a string." | ||||
|   (string-<-symbol x)) | ||||
| 
 | ||||
| (defun symbol-hookify (x) | ||||
|   "Append \"-hook\" to X when X is a symbol." | ||||
|   (symbol-as-string #'string-hookify x)) | ||||
| 
 | ||||
| (defun symbol-ensure-hookified (x) | ||||
|   "Ensure that X has \"-hook\" appended to it when X is a symbol." | ||||
|   (symbol-as-string #'string-ensure-hookified x)) | ||||
| 
 | ||||
| (defun symbol-instance? (x) | ||||
|   "Return t if X is a symbol." | ||||
|   (symbolp x)) | ||||
| 
 | ||||
| (provide 'symbol) | ||||
| ;;; symbol.el ends here | ||||
							
								
								
									
										78
									
								
								users/wpcarro/emacs/.emacs.d/wpc/timestring.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										78
									
								
								users/wpcarro/emacs/.emacs.d/wpc/timestring.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,78 @@ | |||
| ;;; timestring.el --- Quickly access timestamps in different formats -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| 
 | ||||
| ;; I was making some API calls where a URL needed a `since` parameter that of an | ||||
| ;; RFC 3339 encoded string. | ||||
| ;; | ||||
| ;; Because I didn't know what a RFC 3339 encoded | ||||
| ;; string was at the time, and because I didn't know what its format was | ||||
| ;; according to strftime, and because I'm most likely to forget both of these | ||||
| ;; things by the next time that I need something similar, I decided to write | ||||
| ;; this package so that I can accumulate a list of common time encodings. | ||||
| ;; | ||||
| ;; Thank you, Emacs. | ||||
| ;; | ||||
| ;; p.s. - I may turn this into a proper module and publish it.  But not today. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'ts) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defgroup timestring nil | ||||
|   "Customize group for timestring configuration.") | ||||
| 
 | ||||
| (defcustom timestring-supported-encodings | ||||
|   '(("RFC 3339" . "%Y-%m-%dT%H:%M:%SZ") | ||||
|     ;; Does anyone recognize this format? | ||||
|     ("IDK" . "%Y-%m-%d %H:%M:%S %z")) | ||||
|   "Mapping of encoding names to their format strings." | ||||
|   :group 'timestring) | ||||
| 
 | ||||
| (defcustom timestring-supported-times | ||||
|   '(("yesterday" . timestring--yesterday) | ||||
|     ("now" . ts-now) | ||||
|     ("tomorrow" . timestring--tomorrow)) | ||||
|   "Mapping of a labels to the functions that create those time objects." | ||||
|   :group 'timestring) | ||||
| 
 | ||||
| (defun timestring--yesterday () | ||||
|   "Return a time object for yesterday." | ||||
|   (ts-adjust 'day -1 (ts-now))) | ||||
| 
 | ||||
| (defun timestring--tomorrow () | ||||
|   "Return a time object for yesterday." | ||||
|   (ts-adjust 'day +1 (ts-now))) | ||||
| 
 | ||||
| (defun timestring--completing-read (label xs) | ||||
|   "Call `completing-read' with LABEL over the collection XS." | ||||
|   (alist-get (completing-read label xs) xs nil nil #'equal)) | ||||
| 
 | ||||
| (defun timestring-copy-encoded-time () | ||||
|   "Select a common time and an encoding. | ||||
| 
 | ||||
| The selected time will be encoded using the selected encoding and copied onto | ||||
| your clipboard." | ||||
|   (interactive) | ||||
|   (let ((time (funcall (timestring--completing-read | ||||
|                         "Time: " timestring-supported-times))) | ||||
|         (fmt (timestring--completing-read | ||||
|               "Encoding: " timestring-supported-encodings))) | ||||
|     (kill-new (ts-format fmt time)) | ||||
|     (message "Copied!"))) | ||||
| 
 | ||||
| (provide 'timestring) | ||||
| ;;; timestring.el ends here | ||||
							
								
								
									
										200
									
								
								users/wpcarro/emacs/.emacs.d/wpc/tree.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										200
									
								
								users/wpcarro/emacs/.emacs.d/wpc/tree.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,200 @@ | |||
| ;;; tree.el --- Working with Trees -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Some friendly functions that hopefully will make working with trees cheaper | ||||
| ;; and therefore more appealing! | ||||
| ;; | ||||
| ;; Tree terminology: | ||||
| ;; - leaf: node with zero children. | ||||
| ;; - root: node with zero parents. | ||||
| ;; - depth: measures a node's distance from the root node.  This implies the | ||||
| ;;   root node has a depth of zero. | ||||
| ;; - height: measures the longest traversal from a node to a leaf.  This implies | ||||
| ;;   that a leaf node has a height of zero. | ||||
| ;; - balanced? | ||||
| ;; | ||||
| ;; Tree variants: | ||||
| ;; - binary: the maximum number of children is two. | ||||
| ;; - binary search: the maximum number of children is two and left sub-trees are | ||||
| ;;   lower in value than right sub-trees. | ||||
| ;; - rose: the number of children is variable. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'list) | ||||
| (require 'set) | ||||
| (require 'tuple) | ||||
| (require 'series) | ||||
| (require 'random) | ||||
| (require 'maybe) | ||||
| (require 'cl-lib) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defstruct tree xs) | ||||
| 
 | ||||
| (cl-defstruct node value children) | ||||
| 
 | ||||
| (cl-defun tree-node (value &optional children) | ||||
|   "Create a node struct of VALUE with CHILDREN." | ||||
|   (make-node :value value | ||||
|              :children children)) | ||||
| 
 | ||||
| (defun tree-reduce-breadth (acc f xs) | ||||
|   "Reduce over XS breadth-first applying F to each x and ACC (in that order). | ||||
| Breadth-first traversals guarantee to find the shortest path in a graph. | ||||
|   They're typically more difficult to implement than DFTs and may also incur | ||||
|   higher memory costs on average than their depth-first counterparts.") | ||||
| 
 | ||||
| ;; TODO: Support :order as 'pre | 'in | 'post. | ||||
| ;; TODO: Troubleshoot why I need defensive (nil? node) check. | ||||
| (defun tree-reduce-depth (acc f node) | ||||
|   "Reduce over NODE depth-first applying F to each NODE and ACC. | ||||
| F is called with each NODE, ACC, and the current depth. | ||||
| Depth-first traversals have the advantage of typically consuming less memory | ||||
|   than their breadth-first equivalents would have.  They're also typically | ||||
|   easier to implement using recursion.  This comes at the cost of not | ||||
|   guaranteeing to be able to find the shortest path in a graph." | ||||
|   (cl-labels ((do-reduce-depth | ||||
|                (acc f node depth) | ||||
|                (let ((acc-new (funcall f node acc depth))) | ||||
|                  (if (or (maybe-nil? node) | ||||
|                          (tree-leaf? node)) | ||||
|                      acc-new | ||||
|                    (list-reduce | ||||
|                     acc-new | ||||
|                     (lambda (node acc) | ||||
|                       (tree-do-reduce-depth | ||||
|                        acc | ||||
|                        f | ||||
|                        node | ||||
|                        (number-inc depth))) | ||||
|                     (node-children node)))))) | ||||
|     (do-reduce-depth acc f node 0))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Helpers | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun tree-height (xs) | ||||
|   "Return the height of tree XS.") | ||||
| 
 | ||||
| ;; TODO: Troubleshoot why need for (nil? node).  Similar misgiving | ||||
| ;; above. | ||||
| (defun tree-leaf-depths (xs) | ||||
|   "Return a list of all of the depths of the leaf nodes in XS." | ||||
|   (list-reverse | ||||
|    (tree-reduce-depth | ||||
|     '() | ||||
|     (lambda (node acc depth) | ||||
|       (if (or (maybe-nil? node) | ||||
|               (tree-leaf? node)) | ||||
|           (list-cons depth acc) | ||||
|         acc)) | ||||
|     xs))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Generators | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Consider parameterizing height, forced min-max branching, random | ||||
| ;; distributions, etc. | ||||
| 
 | ||||
| ;; TODO: Bail out before stack overflowing by consider branching, current-depth. | ||||
| 
 | ||||
| (cl-defun tree-random (&optional (value-fn (lambda (_) nil)) | ||||
|                                  (branching-factor 2)) | ||||
|   "Randomly generate a tree with BRANCHING-FACTOR. | ||||
| 
 | ||||
| This uses VALUE-FN to compute the node values.  VALUE-FN is called with the | ||||
| current-depth of the node.  Useful for generating test data.  Warning this | ||||
| function can overflow the stack." | ||||
|   (cl-labels ((do-random | ||||
|                (d vf bf) | ||||
|                (make-node | ||||
|                 :value (funcall vf d) | ||||
|                 :children (->> (series/range 0 (number-dec bf)) | ||||
|                                (list-map | ||||
|                                 (lambda (_) | ||||
|                                   (when (random-boolean?) | ||||
|                                     (do-random d vf bf)))))))) | ||||
|     (do-random 0 value-fn branching-factor))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Predicates | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun tree-instance? (tree) | ||||
|   "Return t if TREE is a tree struct." | ||||
|   (node-p tree)) | ||||
| 
 | ||||
| (defun tree-leaf? (node) | ||||
|   "Return t if NODE has no children." | ||||
|   (maybe-nil? (node-children node))) | ||||
| 
 | ||||
| (defun tree-balanced? (n xs) | ||||
|   "Return t if the tree, XS, is balanced. | ||||
| A tree is balanced if none of the differences between any two depths of two leaf | ||||
|   nodes in XS is greater than N." | ||||
|   (> n (->> xs | ||||
|             tree-leaf-depths | ||||
|             set-from-list | ||||
|             set-count | ||||
|             number-dec))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Tests | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst tree-enable-testing? t | ||||
|   "When t, test suite runs.") | ||||
| 
 | ||||
| ;; TODO: Create set of macros for a proper test suite including: | ||||
| ;; - describe (arbitrarily nestable) | ||||
| ;; - it (arbitrarily nestable) | ||||
| ;; - line numbers for errors | ||||
| ;; - accumulated output for synopsis | ||||
| ;; - do we want describe *and* it? Why not a generic label that works for both? | ||||
| (when tree-enable-testing? | ||||
|   (let ((tree-a (tree-node 1 | ||||
|                            (list (tree-node 2 | ||||
|                                             (list (tree-node 5) | ||||
|                                                   (tree-node 6))) | ||||
|                                  (tree-node 3 | ||||
|                                             (list (tree-node 7) | ||||
|                                                   (tree-node 8))) | ||||
|                                  (tree-node 4 | ||||
|                                             (list (tree-node 9) | ||||
|                                                   (tree-node 10)))))) | ||||
|         (tree-b (tree-node 1 | ||||
|                            (list (tree-node 2 | ||||
|                                             (list (tree-node 5) | ||||
|                                                   (tree-node 6))) | ||||
|                                  (tree-node 3) | ||||
|                                  (tree-node 4 | ||||
|                                             (list (tree-node 9) | ||||
|                                                   (tree-node 10))))))) | ||||
|     ;; instance? | ||||
|     (prelude-assert (tree-instance? tree-a)) | ||||
|     (prelude-assert (tree-instance? tree-b)) | ||||
|     (prelude-refute (tree-instance? '(1 2 3))) | ||||
|     (prelude-refute (tree-instance? "oak")) | ||||
|     ;; balanced? | ||||
|     (prelude-assert (tree-balanced? 1 tree-a)) | ||||
|     (prelude-refute (tree-balanced? 1 tree-b)) | ||||
|     (message "Tests pass!"))) | ||||
| 
 | ||||
| (provide 'tree) | ||||
| ;;; tree.el ends here | ||||
							
								
								
									
										94
									
								
								users/wpcarro/emacs/.emacs.d/wpc/tuple.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										94
									
								
								users/wpcarro/emacs/.emacs.d/wpc/tuple.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,94 @@ | |||
| ;;; tuple.el --- Tuple API for Elisp -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Work with cons cells with two elements with a familiar API for those who have | ||||
| ;; worked with tuples before. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (cl-defstruct tuple first second) | ||||
| 
 | ||||
| ;; Create | ||||
| (defun tuple-new () | ||||
|   "Return an empty tuple." | ||||
|   (make-tuple :first nil | ||||
|               :second nil)) | ||||
| 
 | ||||
| (defun tuple-from (a b) | ||||
|   "Return a new tuple from A and B." | ||||
|   (make-tuple :first a | ||||
|               :second b)) | ||||
| 
 | ||||
| (defun tuple-from-dotted (dp) | ||||
|   "Convert dotted pair, DP, into a tuple." | ||||
|   (tuple-from (car dp) (cdr dp))) | ||||
| 
 | ||||
| ;; Read | ||||
| (defun tuple-first (pair) | ||||
|   "Return the first element of PAIR." | ||||
|   (tuple-first pair)) | ||||
| 
 | ||||
| (defun tuple-second (pair) | ||||
|   "Return the second element of PAIR." | ||||
|   (tuple-second pair)) | ||||
| 
 | ||||
| ;; Update | ||||
| (defun tuple-map-each (f g pair) | ||||
|   "Apply F to first, G to second in PAIR." | ||||
|   (->> pair | ||||
|        (tuple-map-first f) | ||||
|        (tuple-map-second g))) | ||||
| 
 | ||||
| (defun tuple-map (f pair) | ||||
|   "Apply F to PAIR." | ||||
|   (let ((pair-copy (copy-tuple pair))) | ||||
|     (funcall f pair-copy))) | ||||
| 
 | ||||
| (defun tuple-map-first (f pair) | ||||
|   "Apply function F to the first element of PAIR." | ||||
|   (let ((pair-copy (copy-tuple pair))) | ||||
|     (setf (tuple-first pair-copy) (funcall f (tuple-first pair-copy))) | ||||
|     pair-copy)) | ||||
| 
 | ||||
| (defun tuple-map-second (f pair) | ||||
|   "Apply function F to the second element of PAIR." | ||||
|   (let ((pair-copy (copy-tuple pair))) | ||||
|     (setf (tuple-second pair-copy) (funcall f (tuple-second pair-copy))) | ||||
|     pair-copy)) | ||||
| 
 | ||||
| (defun tuple-set-first (a pair) | ||||
|   "Return a new tuple with the first element set as A in PAIR." | ||||
|   (tuple-map-first (lambda (_) a) pair)) | ||||
| 
 | ||||
| (defun tuple-set-second (b pair) | ||||
|   "Return a new tuple with the second element set as B in PAIR." | ||||
|   (tuple-map-second (lambda (_) b) pair)) | ||||
| 
 | ||||
| ;; Delete | ||||
| (defun tuple-delete-first (pair) | ||||
|   "Return PAIR with the first element set to nil." | ||||
|   (tuple-set-first nil pair)) | ||||
| 
 | ||||
| (defun tuple-delete-second (pair) | ||||
|   "Return PAIR with the second element set to nil." | ||||
|   (tuple-set-second nil pair)) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Predicates | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun tuple-instance? (x) | ||||
|   "Return t if X is a tuple." | ||||
|   (tuple-p x)) | ||||
| 
 | ||||
| (provide 'tuple) | ||||
| ;;; tuple.el ends here | ||||
							
								
								
									
										85
									
								
								users/wpcarro/emacs/.emacs.d/wpc/vector.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										85
									
								
								users/wpcarro/emacs/.emacs.d/wpc/vector.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,85 @@ | |||
| ;;; vector.el --- Working with Elisp's Vector data type -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; It might be best to think of Elisp vectors as tuples in languages like | ||||
| ;; Haskell or Erlang. | ||||
| ;; | ||||
| ;; Not surprisingly, this API is modelled after Elixir's Tuple API. | ||||
| ;; | ||||
| ;; Some Elisp trivia: | ||||
| ;; - "Array": Usually means vector or string. | ||||
| ;; - "Sequence": Usually means list or "array" (see above). | ||||
| ;; | ||||
| ;; It might be a good idea to think of Array and Sequence as typeclasses in | ||||
| ;; Elisp.  This is perhaps more similar to Elixir's notion of the Enum protocol. | ||||
| ;; | ||||
| ;; Intentionally not supporting a to-list function, because tuples can contain | ||||
| ;; heterogenous types whereas lists should contain homogenous types. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;; TODO: Consider supporting an alias named tuple for vector. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst vector-enable-tests? t | ||||
|   "When t, run the tests defined herein.") | ||||
| 
 | ||||
| ;; TODO: Consider labelling variadic functions like `vector-concat*' | ||||
| ;; vs. `vector-concat'. | ||||
| (defun vector-concat (&rest args) | ||||
|   "Return a new vector composed of all vectors in `ARGS'." | ||||
|   (apply #'vconcat args)) | ||||
| 
 | ||||
| ;; TODO: Here's a sketch of a protocol macro being consumed. | ||||
| ;; (definstance monoid vector | ||||
| ;;   :empty (lambda () [])) | ||||
| 
 | ||||
| (defun vector-prepend (x xs) | ||||
|   "Add `X' to the beginning of `XS'." | ||||
|   (vector-concat `[,x] xs)) | ||||
| 
 | ||||
| (defun vector-append (x xs) | ||||
|   "Add `X' to the end of `XS'." | ||||
|   (vector-concat xs `[,x])) | ||||
| 
 | ||||
| (defun vector-get (i xs) | ||||
|   "Return the value in `XS' at index, `I'." | ||||
|   (aref xs i)) | ||||
| 
 | ||||
| (defun vector-set (i v xs) | ||||
|   "Set index `I' to value `V' in `XS'. | ||||
| Returns a copy of `XS' with the updates." | ||||
|   (let ((copy (vconcat [] xs))) | ||||
|     (aset copy i v) | ||||
|     copy)) | ||||
| 
 | ||||
| (defun vector-set! (i v xs) | ||||
|   "Set index `I' to value `V' in `XS'. | ||||
| This function mutates XS." | ||||
|   (aset xs i v)) | ||||
| 
 | ||||
| (when vector-enable-tests? | ||||
|   (let ((xs [1 2 3]) | ||||
|         (ys [1 2 3])) | ||||
|     (prelude-assert (= 1 (vector-get 0 ys))) | ||||
|     (vector-set 0 4 ys) | ||||
|     (prelude-assert (= 1 (vector-get 0 ys))) | ||||
|     (prelude-assert (= 1 (vector-get 0 xs))) | ||||
|     (vector-set! 0 4 xs) | ||||
|     (prelude-assert (= 4 (vector-get 0 xs))))) | ||||
| 
 | ||||
| ;; TODO: Decide between "remove" and "delete" as the appropriate verbs. | ||||
| ;; TODO: Implement this. | ||||
| ;; (defun vector/delete (i xs) | ||||
| ;;   "Remove the element at `I' in `XS'.") | ||||
| 
 | ||||
| (provide 'vector) | ||||
| ;;; vector.el ends here | ||||
							
								
								
									
										129
									
								
								users/wpcarro/emacs/.emacs.d/wpc/vterm-mgt.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										129
									
								
								users/wpcarro/emacs/.emacs.d/wpc/vterm-mgt.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,129 @@ | |||
| ;;; vterm-mgt.el --- Help me manage my vterm instances -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Supporting functions to instantiate vterm buffers, kill existing vterm | ||||
| ;; buffers, rename vterm buffers, cycle forwards and backwards through vterm | ||||
| ;; buffers. | ||||
| ;; | ||||
| ;; Many of the functions defined herein are intended to be bound to | ||||
| ;; `vterm-mode-map'.  Some assertions are made to guard against calling | ||||
| ;; functions that are intended to be called from outside of a vterm buffer. | ||||
| ;; These assertions shouldn't error when the functions are bound to | ||||
| ;; `vterm-mode-map'.  If for some reason, you'd like to bind these functions to | ||||
| ;; a separate keymap, caveat emptor. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'dash) | ||||
| (require 'cycle) | ||||
| (require 'vterm) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defgroup vterm-mgt nil | ||||
|   "Customization options for `vterm-mgt'.") | ||||
| 
 | ||||
| (defcustom vterm-mgt-scroll-on-focus nil | ||||
|   "When t, call `end-of-buffer' after focusing a vterm instance." | ||||
|   :type '(boolean) | ||||
|   :group 'vterm-mgt) | ||||
| 
 | ||||
| (defconst vterm-mgt--instances (cycle-new) | ||||
|   "A cycle tracking all of my vterm instances.") | ||||
| 
 | ||||
| (defun vterm-mgt--instance? (b) | ||||
|   "Return t if the buffer B is a vterm instance." | ||||
|   (equal 'vterm-mode (buffer-local-value 'major-mode b))) | ||||
| 
 | ||||
| (defmacro vterm-mgt--assert-vterm-buffer () | ||||
|   "Error when the `current-buffer' is not a vterm buffer." | ||||
|   '(prelude-assert (vterm-mgt--instance? (current-buffer)))) | ||||
| 
 | ||||
| (defun vterm-mgt-next () | ||||
|   "Replace the current buffer with the next item in `vterm-mgt--instances'. | ||||
| This function should be called from a buffer running vterm." | ||||
|   (interactive) | ||||
|   (vterm-mgt--assert-vterm-buffer) | ||||
|   (cycle-focus-item (current-buffer) vterm-mgt--instances) | ||||
|   (switch-to-buffer (cycle-next vterm-mgt--instances)) | ||||
|   (when vterm-mgt-scroll-on-focus (end-of-buffer))) | ||||
| 
 | ||||
| (defun vterm-mgt-prev () | ||||
|   "Replace the current buffer with the previous item in `vterm-mgt--instances'. | ||||
| This function should be called from a buffer running vterm." | ||||
|   (interactive) | ||||
|   (vterm-mgt--assert-vterm-buffer) | ||||
|   (cycle-focus-item (current-buffer) vterm-mgt--instances) | ||||
|   (switch-to-buffer (cycle-prev vterm-mgt--instances)) | ||||
|   (when vterm-mgt-scroll-on-focus (end-of-buffer))) | ||||
| 
 | ||||
| (defun vterm-mgt-instantiate () | ||||
|   "Create a new vterm instance. | ||||
| 
 | ||||
| Prefer calling this function instead of `vterm'.  This function ensures that the | ||||
|   newly created instance is added to `vterm-mgt--instances'. | ||||
| 
 | ||||
| If however you must call `vterm', if you'd like to cycle through vterm | ||||
|   instances, make sure you call `vterm-mgt-populate-cycle' to allow vterm-mgt to | ||||
|   collect any untracked vterm instances." | ||||
|   (interactive) | ||||
|   (let ((buffer (vterm))) | ||||
|     (cycle-append buffer vterm-mgt--instances) | ||||
|     (cycle-focus-item buffer vterm-mgt--instances))) | ||||
| 
 | ||||
| (defun vterm-mgt-kill () | ||||
|   "Kill the current buffer and remove it from `vterm-mgt--instances'. | ||||
| This function should be called from a buffer running vterm." | ||||
|   (interactive) | ||||
|   (vterm-mgt--assert-vterm-buffer) | ||||
|   (let ((buffer (current-buffer))) | ||||
|     (cycle-remove buffer vterm-mgt--instances) | ||||
|     (kill-buffer buffer))) | ||||
| 
 | ||||
| (defun vterm-mgt-find-or-create () | ||||
|   "Call `switch-to-buffer' on a focused vterm instance if there is one. | ||||
| 
 | ||||
| When `cycle-focused?' returns nil, focus the first item in the cycle.  When | ||||
| there are no items in the cycle, call `vterm-mgt-instantiate' to create a vterm | ||||
| instance." | ||||
|   (interactive) | ||||
|   (if (cycle-empty? vterm-mgt--instances) | ||||
|       (vterm-mgt-instantiate) | ||||
|     (if (cycle-focused? vterm-mgt--instances) | ||||
|         (switch-to-buffer (cycle-current vterm-mgt--instances)) | ||||
|       (progn | ||||
|         (cycle-jump 0 vterm-mgt--instances) | ||||
|         (switch-to-buffer (cycle-current vterm-mgt--instances)))))) | ||||
| 
 | ||||
| (defun vterm-mgt-rename-buffer (name) | ||||
|   "Rename the current buffer ensuring that its NAME is wrapped in *vterm*<...>. | ||||
| This function should be called from a buffer running vterm." | ||||
|   (interactive "SRename vterm buffer: ") | ||||
|   (vterm-mgt--assert-vterm-buffer) | ||||
|   (rename-buffer (format "vterm<%s>" name))) | ||||
| 
 | ||||
| (defun vterm-mgt-repopulate-cycle () | ||||
|   "Fill `vterm-mgt--instances' with the existing vterm buffers. | ||||
| 
 | ||||
| If for whatever reason, the state of `vterm-mgt--instances' is corrupted and | ||||
|   misaligns with the state of vterm buffers in Emacs, use this function to | ||||
|   restore the state." | ||||
|   (interactive) | ||||
|   (setq vterm-mgt--instances | ||||
|         (->> (buffer-list) | ||||
|              (-filter #'vterm-mgt--instance?) | ||||
|              cycle-from-list))) | ||||
| 
 | ||||
| (provide 'vterm-mgt) | ||||
| ;;; vterm-mgt.el ends here | ||||
							
								
								
									
										354
									
								
								users/wpcarro/emacs/.emacs.d/wpc/window-manager.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										354
									
								
								users/wpcarro/emacs/.emacs.d/wpc/window-manager.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,354 @@ | |||
| ;;; window-manager.el --- Functions augmenting my usage of EXWM -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; I switched to EXWM from i3, and I haven't looked back.  One day I may write a | ||||
| ;; poem declaring my love for Emacs and EXWM.  For now, I haven't the time. | ||||
| 
 | ||||
| ;; Wish list: | ||||
| ;; - TODO: Support different startup commands and layouts depending on laptop or | ||||
| ;;   desktop. | ||||
| ;; - TODO: Support a Music named-workspace. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'alert) | ||||
| (require 'al) | ||||
| (require 'prelude) | ||||
| (require 'string) | ||||
| (require 'cycle) | ||||
| (require 'set) | ||||
| (require 'kbd) | ||||
| (require 'ivy-helpers) | ||||
| (require 'display) | ||||
| (require 'vterm-mgt) | ||||
| (require 'dash) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Associate `window-purpose' window-layouts with each of these named | ||||
| ;; workspaces. | ||||
| 
 | ||||
| ;; TODO: Associate KBDs for each of these named-layouts. | ||||
| 
 | ||||
| ;; TODO: Decide between window-manager, exwm, or some other namespace. | ||||
| 
 | ||||
| ;; TODO: Support (cycle-from-list '(current previous)) to toggle back and forth | ||||
| ;; between most recent workspace. | ||||
| 
 | ||||
| ;; TODO: Support ad hoc cycle for loading a few workspaces that can be cycled | ||||
| ;; between. (cycle-from-list '("Project" "Workspace")) | ||||
| 
 | ||||
| ;; TODO: Consider supporting a workspace for Racket, Clojure, Common Lisp, | ||||
| ;; Haskell, Elixir, and a few other languages. These could behave very similarly | ||||
| ;; to repl.it, which I've wanted to have locally for awhile now. | ||||
| 
 | ||||
| ;; TODO: Support MRU cache of workspaces for easily switching back-and-forth | ||||
| ;; between workspaces. | ||||
| 
 | ||||
| (cl-defstruct window-manager--named-workspace label kbd display) | ||||
| 
 | ||||
| (defconst window-manager--install-kbds? t | ||||
|   "When t, install the keybindings to switch between named-workspaces.") | ||||
| 
 | ||||
| ;; TODO: Consume `cache/touch' after changing workspaces.  Use this to enable | ||||
| ;; cycling through workspaces. | ||||
| 
 | ||||
| (defconst window-manager--named-workspaces | ||||
|   (list (make-window-manager--named-workspace | ||||
|          :label "Web Browsing" | ||||
|          :kbd "c" | ||||
|          :display display-4k-horizontal) | ||||
|         (make-window-manager--named-workspace | ||||
|          :label "Coding" | ||||
|          :kbd "d" | ||||
|          :display display-4k-horizontal) | ||||
|         (make-window-manager--named-workspace | ||||
|          :label "Vertical" | ||||
|          :kbd "h" | ||||
|          :display display-4k-vertical) | ||||
|         (make-window-manager--named-workspace | ||||
|          :label "Laptop" | ||||
|          :kbd "p" | ||||
|          :display display-laptop)) | ||||
|   "List of `window-manager--named-workspace' structs.") | ||||
| 
 | ||||
| ;; Assert that no two workspaces share KBDs. | ||||
| (prelude-assert (= (list-length window-manager--named-workspaces) | ||||
|                    (->> window-manager--named-workspaces | ||||
|                         (list-map #'window-manager--named-workspace-kbd) | ||||
|                         set-from-list | ||||
|                         set-count))) | ||||
| 
 | ||||
| (defun window-manager--alert (x) | ||||
|   "Message X with a structured format." | ||||
|   (alert (string-concat "[exwm] " x))) | ||||
| 
 | ||||
| ;; Use Emacs as my primary window manager. | ||||
| (use-package exwm | ||||
|   :config | ||||
|   (require 'exwm-config) | ||||
| 
 | ||||
|   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|   ;; Multiple Displays | ||||
|   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
|   (require 'exwm-randr) | ||||
|   (exwm-randr-enable) | ||||
|   (setq exwm-randr-workspace-monitor-plist | ||||
|         (->> window-manager--named-workspaces | ||||
|              (-map-indexed (lambda (i x) | ||||
|                              (list i (window-manager--named-workspace-display x)))) | ||||
|              -flatten)) | ||||
|   (setq exwm-workspace-number (list-length window-manager--named-workspaces)) | ||||
|   (setq exwm-input-simulation-keys | ||||
|         ;; TODO: Consider supporting M-d and other readline style KBDs. | ||||
|         '(([?\C-b] . [left]) | ||||
|           ([?\M-b] . [C-left]) | ||||
|           ([?\C-f] . [right]) | ||||
|           ([?\M-f] . [C-right]) | ||||
|           ([?\C-p] . [up]) | ||||
|           ([?\C-n] . [down]) | ||||
|           ([?\C-a] . [home]) | ||||
|           ([?\C-e] . [end]) | ||||
|           ([?\C-d] . [delete]) | ||||
|           ;; TODO: Assess whether or not this is a good idea. | ||||
|           ;; TODO: Ensure C-c copies. | ||||
|           ([?\C-c] . [C-c]))) | ||||
|   (exwm-enable)) | ||||
| 
 | ||||
| ;; Here is the code required to allow EXWM to cycle workspaces. | ||||
| (defconst window-manager--workspaces | ||||
|   (->> window-manager--named-workspaces | ||||
|        cycle-from-list) | ||||
|   "Cycle of the my EXWM workspaces.") | ||||
| 
 | ||||
| (prelude-assert | ||||
|  (= exwm-workspace-number | ||||
|     (list-length window-manager--named-workspaces))) | ||||
| 
 | ||||
| (defun window-manager-next-workspace () | ||||
|   "Cycle forwards to the next workspace." | ||||
|   (interactive) | ||||
|   (window-manager--change-workspace (cycle-next window-manager--workspaces))) | ||||
| 
 | ||||
| (defun window-manager-prev-workspace () | ||||
|   "Cycle backwards to the previous workspace." | ||||
|   (interactive) | ||||
|   (window-manager--change-workspace (cycle-prev window-manager--workspaces))) | ||||
| 
 | ||||
| ;; TODO: Create friendlier API for working with EXWM. | ||||
| 
 | ||||
| ;; Here is the code required to toggle EXWM's modes. | ||||
| (defun window-manager--line-mode () | ||||
|   "Switch exwm to line-mode." | ||||
|   (call-interactively #'exwm-input-grab-keyboard) | ||||
|   (window-manager--alert "Switched to line-mode")) | ||||
| 
 | ||||
| (defun window-manager--char-mode () | ||||
|   "Switch exwm to char-mode." | ||||
|   (call-interactively #'exwm-input-release-keyboard) | ||||
|   (window-manager--alert "Switched to char-mode")) | ||||
| 
 | ||||
| (defconst window-manager--modes | ||||
|   (cycle-from-list (list #'window-manager--char-mode | ||||
|                          #'window-manager--line-mode)) | ||||
|   "Functions to switch exwm modes.") | ||||
| 
 | ||||
| (defun window-manager-toggle-mode () | ||||
|   "Switch between line- and char- mode." | ||||
|   (interactive) | ||||
|   (with-current-buffer (window-buffer) | ||||
|     (when (eq major-mode 'exwm-mode) | ||||
|       (funcall (cycle-next window-manager--modes))))) | ||||
| 
 | ||||
| ;; Ensure exwm apps open in char-mode. | ||||
| (add-hook 'exwm-manage-finish-hook #'window-manager--char-mode) | ||||
| 
 | ||||
| ;; Interface to the Linux password manager | ||||
| ;; TODO: Consider writing a better client for this. | ||||
| (use-package ivy-pass) | ||||
| 
 | ||||
| ;; TODO: How do I handle this dependency? | ||||
| (defconst window-manager--preferred-browser "google-chrome" | ||||
|   "My preferred web browser.") | ||||
| 
 | ||||
| ;; TODO: Consider replacing the `ivy-read' call with something like `hydra' that | ||||
| ;; can provide a small mode for accepting user-input. | ||||
| ;; TODO: Put this somewhere more diliberate. | ||||
| 
 | ||||
| ;; TODO: Configure the environment variables for xsecurelock so that the font is | ||||
| ;; smaller, different, and the glinux wallpaper doesn't show. | ||||
| ;; - XSECURELOCK_FONT="InputMono-Black 10" | ||||
| ;; - XSECURE_SAVER="" | ||||
| ;; - XSECURE_LOGO_IMAGE="" | ||||
| ;; Maybe just create a ~/.xsecurelockrc | ||||
| ;; TODO: Is there a shell-command API that accepts an alist and serializes it | ||||
| ;; into variables to pass to the shell command? | ||||
| (defconst window-manager--xsecurelock | ||||
|   "/usr/share/goobuntu-desktop-files/xsecurelock.sh" | ||||
|   "Path to the proper xsecurelock executable. | ||||
| The other path to xsecurelock is /usr/bin/xsecurelock, which works fine, but it | ||||
| is not optimized for Goobuntu devices.  Goobuntu attempts to check a user's | ||||
| password using the network.  When there is no network connection available, the | ||||
| login attempts fail with an \"unknown error\", which isn't very helpful.  To | ||||
| avoid this, prefer the goobuntu wrapper around xsecurelock when on a goobuntu | ||||
| device.  This all relates to PAM (i.e. pluggable authentication modules).") | ||||
| 
 | ||||
| (defun window-manager-logout () | ||||
|   "Prompt the user for options for logging out, shutting down, etc. | ||||
| 
 | ||||
| The following options are supported: | ||||
| - Lock | ||||
| - Logout | ||||
| - Suspend | ||||
| - Hibernate | ||||
| - Reboot | ||||
| - Shutdown | ||||
| 
 | ||||
| Ivy is used to capture the user's input." | ||||
|   (interactive) | ||||
|   (let* ((name->cmd `(("Lock" . | ||||
|                        (lambda () | ||||
|                          (shell-command window-manager--xsecurelock))) | ||||
|                       ("Logout" . | ||||
|                        (lambda () | ||||
|                          (let ((default-directory "/sudo::")) | ||||
|                            (shell-command "systemctl stop lightdm")))) | ||||
|                       ("Suspend" . | ||||
|                        (lambda () | ||||
|                          (shell-command "systemctl suspend"))) | ||||
|                       ("Hibernate" . | ||||
|                        (lambda () | ||||
|                          (shell-command "systemctl hibernate"))) | ||||
|                       ("Reboot" . | ||||
|                        (lambda () | ||||
|                          (let ((default-directory "/sudo::")) | ||||
|                            (shell-command "reboot")))) | ||||
|                       ("Shutdown" . | ||||
|                        (lambda () | ||||
|                          (let ((default-directory "/sudo::")) | ||||
|                            (shell-command "shutdown now"))))))) | ||||
|     (funcall | ||||
|      (lambda () | ||||
|        (funcall (al-get (ivy-read "System: " (al-keys name->cmd)) | ||||
|                         name->cmd)))))) | ||||
| 
 | ||||
| (defun window-manager--label->index (label workspaces) | ||||
|   "Return the index of the workspace in WORKSPACES named LABEL." | ||||
|   (let ((index (-elem-index label (-map #'window-manager--named-workspace-label | ||||
|                                         workspaces)))) | ||||
|     (if index index (error (format "No workspace found for label: %s" label))))) | ||||
| 
 | ||||
| (defun window-manager--register-kbd (workspace) | ||||
|   "Registers a keybinding for WORKSPACE struct. | ||||
| Currently using super- as the prefix for switching workspaces." | ||||
|   (let ((handler (lambda () | ||||
|                    (interactive) | ||||
|                    (window-manager--switch | ||||
|                     (window-manager--named-workspace-label workspace)))) | ||||
|         (key (window-manager--named-workspace-kbd workspace))) | ||||
|     (exwm-input-set-key | ||||
|      (kbd-for 'workspace key) | ||||
|      handler))) | ||||
| 
 | ||||
| (defun window-manager--change-workspace (workspace) | ||||
|   "Switch EXWM workspaces to the WORKSPACE struct." | ||||
|   (exwm-workspace-switch | ||||
|    (window-manager--label->index | ||||
|     (window-manager--named-workspace-label workspace) | ||||
|     window-manager--named-workspaces)) | ||||
|   (window-manager--alert | ||||
|    (string-format "Switched to: %s" | ||||
|                   (window-manager--named-workspace-label workspace)))) | ||||
| 
 | ||||
| (defun window-manager--switch (label) | ||||
|   "Switch to a named workspaces using LABEL." | ||||
|   (cycle-focus (lambda (x) | ||||
|                  (equal label | ||||
|                         (window-manager--named-workspace-label x))) | ||||
|                window-manager--workspaces) | ||||
|   (window-manager--change-workspace (cycle-current window-manager--workspaces))) | ||||
| 
 | ||||
| (exwm-input-set-key (kbd "C-S-f") #'window-manager-toggle-previous) | ||||
| 
 | ||||
| (defun window-manager-toggle-previous () | ||||
|   "Focus the previously active EXWM workspace." | ||||
|   (interactive) | ||||
|   (window-manager--change-workspace | ||||
|    (cycle-focus-previous! window-manager--workspaces))) | ||||
| 
 | ||||
| (defun window-manager--exwm-buffer? (x) | ||||
|   "Return t if buffer X is an EXWM buffer." | ||||
|   (equal 'exwm-mode (buffer-local-value 'major-mode x))) | ||||
| 
 | ||||
| (defun window-manager--application-name (buffer) | ||||
|   "Return the name of the application running in the EXWM BUFFER. | ||||
| This function asssumes that BUFFER passes the `window-manager--exwm-buffer?' | ||||
| predicate." | ||||
|   (with-current-buffer buffer exwm-class-name)) | ||||
| 
 | ||||
| ;; TODO: Support disambiguating between two or more instances of the same | ||||
| ;; application. For instance if two `exwm-class-name' values are | ||||
| ;; "Google-chrome", find a encode this information in the `buffer-alist'. | ||||
| (defun window-manager-switch-to-exwm-buffer () | ||||
|   "Use `completing-read' to focus an EXWM buffer." | ||||
|   (interactive) | ||||
|   (let* ((buffer-alist (->> (buffer-list) | ||||
|                             (-filter #'window-manager--exwm-buffer?) | ||||
|                             (-map | ||||
|                              (lambda (buffer) | ||||
|                                (cons (window-manager--application-name buffer) | ||||
|                                      buffer))))) | ||||
|          (label (completing-read "Switch to EXWM buffer: " buffer-alist))) | ||||
|     (exwm-workspace-switch-to-buffer | ||||
|      (al-get label buffer-alist)))) | ||||
| 
 | ||||
| (when window-manager--install-kbds? | ||||
|   (progn | ||||
|     (->> window-manager--named-workspaces | ||||
|          (list-map #'window-manager--register-kbd)) | ||||
|     (window-manager--alert "Registered workspace KBDs!"))) | ||||
| 
 | ||||
| (defun window-manager-current-workspace () | ||||
|   "Output the label of the currently active workspace." | ||||
|   (->> window-manager--workspaces | ||||
|        cycle-current | ||||
|        window-manager--named-workspace-label)) | ||||
| 
 | ||||
| (defun window-manager-swap-workspaces () | ||||
|   "Prompt the user to switch the current workspace with another." | ||||
|   (interactive) | ||||
|   (let* ((selection (->> window-manager--named-workspaces | ||||
|                          (-map #'window-manager--named-workspace-label) | ||||
|                          (-reject | ||||
|                           (lambda (x) | ||||
|                             (s-equals? x (window-manager-current-workspace)))) | ||||
|                          (completing-read | ||||
|                           (format "Swap current workspace (i.e. \"%s\") with: " | ||||
|                                   (window-manager-current-workspace))))) | ||||
|          (i (-find-index (lambda (x) | ||||
|                            (s-equals? selection (window-manager--named-workspace-label x))) | ||||
|                                  window-manager--named-workspaces))) | ||||
|     (exwm-workspace-swap exwm-workspace--current (elt exwm-workspace--list i)))) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Startup Applications in `window-manager--named-workspaces' | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (add-hook 'exwm-init-hook | ||||
|           (lambda () | ||||
|             (display-arrange-primary) | ||||
|             (window-manager--switch "Coding"))) | ||||
| 
 | ||||
| (provide 'window-manager) | ||||
| ;;; window-manager.el ends here | ||||
							
								
								
									
										41
									
								
								users/wpcarro/emacs/.emacs.d/wpc/window.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								users/wpcarro/emacs/.emacs.d/wpc/window.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| ;;; window.el --- Working with windows -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Utilities to make CRUDing windows in Emacs easier. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'macros) | ||||
| (require 'maybe) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defun window-find (name) | ||||
|   "Find a window by the NAME of the buffer it's hosting." | ||||
|   (let ((buffer (get-buffer name))) | ||||
|     (if (maybe-some? buffer) | ||||
|         (get-buffer-window buffer) | ||||
|       nil))) | ||||
| 
 | ||||
| ;; TODO: Find a way to incorporate these into function documentation. | ||||
| (macros-comment | ||||
|  (window-find "*scratch*")) | ||||
| 
 | ||||
| (defun window-delete (window) | ||||
|   "Delete the WINDOW reference." | ||||
|   (delete-window window)) | ||||
| 
 | ||||
| (provide 'window) | ||||
| ;;; window.el ends here | ||||
							
								
								
									
										72
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-clojure.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-clojure.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| ;;; wpc-clojure.el --- My Clojure preferences -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Hosting my Clojure tooling preferences | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (use-package clojure-mode | ||||
|   :config | ||||
|   ;; from Ryan Schmukler: | ||||
|   (setq cljr-magic-require-namespaces | ||||
|         '(("io" . "clojure.java.io") | ||||
|           ("sh" . "clojure.java.shell") | ||||
|           ("jdbc" . "clojure.java.jdbc") | ||||
|           ("set" . "clojure.set") | ||||
|           ("time" . "java-time") | ||||
|           ("str" . "cuerdas.core") | ||||
|           ("path" . "pathetic.core") | ||||
|           ("walk" . "clojure.walk") | ||||
|           ("zip" . "clojure.zip") | ||||
|           ("async" . "clojure.core.async") | ||||
|           ("component" . "com.stuartsierra.component") | ||||
|           ("http" . "clj-http.client") | ||||
|           ("url" . "cemerick.url") | ||||
|           ("sql" . "honeysql.core") | ||||
|           ("csv" . "clojure.data.csv") | ||||
|           ("json" . "cheshire.core") | ||||
|           ("s" . "clojure.spec.alpha") | ||||
|           ("fs" . "me.raynes.fs") | ||||
|           ("ig" . "integrant.core") | ||||
|           ("cp" . "com.climate.claypoole") | ||||
|           ("re-frame" . "re-frame.core") | ||||
|           ("rf" . "re-frame.core") | ||||
|           ("re" . "reagent.core") | ||||
|           ("reagent" . "reagent.core") | ||||
|           ("u.core" . "utopia.core") | ||||
|           ("gen" . "clojure.spec.gen.alpha")))) | ||||
| 
 | ||||
| (use-package cider | ||||
|   :config | ||||
|   (general-define-key | ||||
|     :keymaps 'cider-repl-mode-map | ||||
|     "C-l"    #'cider-repl-clear-buffer | ||||
|     "C-u"    #'kill-whole-line | ||||
|     "<up>"   #'cider-repl-previous-input | ||||
|     "<down>" #'cider-repl-next-input) | ||||
|   (general-define-key | ||||
|    :keymaps 'clojure-mode-map | ||||
|    :states '(normal) | ||||
|    :prefix "<SPC>" | ||||
|    "x" #'cider-eval-defun-at-point | ||||
|    "X" #'cider-eval-buffer | ||||
|    "d" #'cider-symbol-at-point) | ||||
|   (setq cider-prompt-for-symbol nil)) | ||||
| 
 | ||||
| (provide 'wpc-clojure) | ||||
| ;;; wpc-clojure.el ends here | ||||
							
								
								
									
										42
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-company.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-company.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,42 @@ | |||
| ;;; wpc-company.el --- Autocompletion package, company, preferences -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Hosts my company mode preferences | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; autocompletion client | ||||
| (use-package company | ||||
|   :config | ||||
|   (general-define-key | ||||
|     :keymaps 'company-active-map | ||||
|     "C-j" #'company-select-next | ||||
|     "C-n" #'company-select-next | ||||
|     "C-k" #'company-select-previous | ||||
|     "C-p" #'company-select-previous | ||||
|     "C-d" #'company-show-doc-buffer) | ||||
|   (setq company-tooltip-align-annotations t) | ||||
|   (setq company-idle-delay 0) | ||||
|   (setq company-show-numbers t) | ||||
|   (setq company-minimum-prefix-length 2) | ||||
|   (setq company-dabbrev-downcase nil | ||||
|         company-dabbrev-ignore-case t) | ||||
|   (global-company-mode)) | ||||
| 
 | ||||
| (provide 'wpc-company) | ||||
| ;;; wpc-company.el ends here | ||||
							
								
								
									
										53
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-dired.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										53
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-dired.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,53 @@ | |||
| ;;; wpc-dired.el --- My dired preferences -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; File management in Emacs, if learned and configured properly, should be | ||||
| ;; capable to reduce my dependency on the terminal. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'macros) | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (progn | ||||
|   (require 'dired) | ||||
|   (setq dired-recursive-copies 'always | ||||
|         dired-recursive-deletes 'top | ||||
|         dired-dwim-target t) | ||||
|   (setq dired-listing-switches "-la --group-directories-first") | ||||
|   (general-define-key | ||||
|    :keymaps 'dired-mode-map | ||||
|    :states '(normal) | ||||
|    ;; Overriding some KBDs defined in the evil-collection module. | ||||
|    "o" #'dired-find-file-other-window | ||||
|    "<SPC>" nil ;; This unblocks some of my leader-prefixed KBDs. | ||||
|    "s" nil ;; This unblocks my window-splitting KBDs. | ||||
|    "c" #'find-file | ||||
|    "f" #'project-find-file | ||||
|    "-" (lambda () (interactive) (find-alternate-file ".."))) | ||||
|   (general-add-hook 'dired-mode-hook | ||||
|                     (list (macros-enable dired-hide-details-mode) | ||||
|                           #'auto-revert-mode))) | ||||
| 
 | ||||
| (progn | ||||
|   (require 'locate) | ||||
|   (general-define-key | ||||
|    :keymaps 'locate-mode-map | ||||
|    :states 'normal | ||||
|    "o" #'dired-find-file-other-window)) | ||||
| 
 | ||||
| (provide 'wpc-dired) | ||||
| ;;; wpc-dired.el ends here | ||||
							
								
								
									
										28
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-elixir.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-elixir.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,28 @@ | |||
| ;;; wpc-elixir.el --- Elixir / Erland configuration -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; My preferences for working with Elixir / Erlang projects | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'macros) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (use-package elixir-mode | ||||
|   :config | ||||
|   (macros-add-hook-before-save 'elixir-mode-hook #'elixir-format)) | ||||
| 
 | ||||
| (provide 'wpc-elixir) | ||||
| ;;; wpc-elixir.el ends here | ||||
							
								
								
									
										18
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-flycheck.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-flycheck.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,18 @@ | |||
| ;;; wpc-flycheck.el --- My flycheck configuration -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Hosts my Flycheck preferences | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| (use-package flycheck | ||||
|   :config | ||||
|   (global-flycheck-mode)) | ||||
| 
 | ||||
| (provide 'wpc-flycheck) | ||||
| ;;; wpc-flycheck.el ends here | ||||
							
								
								
									
										48
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-golang.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-golang.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| ;;; wpc-golang.el --- Tooling preferences for Go -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Tooling support for golang development. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'prelude) | ||||
| (require 'macros) | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; TODO: Support jumping to go source code for fmt.Println, etc. | ||||
| 
 | ||||
| ;; I'm unsure if this belongs in wpc-golang.el because it's a generic setting, | ||||
| ;; but because go is the first languages I've encountered that enforces tab | ||||
| ;; usage (I think) I'm configuring it. | ||||
| (setq-default tab-width 4) | ||||
| 
 | ||||
| (use-package go-mode | ||||
|   :config | ||||
|   (setq gofmt-command "goimports") | ||||
|   ;; TODO: Consider configuring `xref-find-definitions' to use `godef-jump' | ||||
|   ;; instead of shadowing the KBD here. | ||||
|   (general-define-key | ||||
|    :states '(normal) | ||||
|    :keymaps '(go-mode-map) | ||||
|    "M-." #'godef-jump) | ||||
|   ;; Support calling M-x `compile'. | ||||
|   (add-hook 'go-mode-hook (lambda () | ||||
|                             (set (make-local-variable 'compile-command) | ||||
|                                  "go build -v"))) | ||||
|   (macros-add-hook-before-save 'go-mode-hook #'gofmt-before-save)) | ||||
| 
 | ||||
| (provide 'wpc-golang) | ||||
| ;;; wpc-golang.el ends here | ||||
							
								
								
									
										62
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-haskell.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										62
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-haskell.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,62 @@ | |||
| ;;; wpc-haskell.el --- My Haskell preferences -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Hosts my Haskell development preferences | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'macros) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; font-locking, glyph support, etc | ||||
| (use-package haskell-mode | ||||
|   :config | ||||
|   (macros-add-hook-before-save 'haskell-mode #'haskell-align-imports)) | ||||
| 
 | ||||
| ;; LSP support | ||||
| (use-package lsp-haskell | ||||
|   :after (haskell-mode) | ||||
|   :config | ||||
|   (setq lsp-haskell-process-path-hie "hie-wrapper") | ||||
|   (add-hook 'haskell-mode-hook #'lsp-haskell-enable) | ||||
|   (add-hook 'haskell-mode-hook #'flycheck-mode)) | ||||
| 
 | ||||
| ;; Test toggling | ||||
| (defun wpc-haskell-module->test () | ||||
|   "Jump from a module to a test." | ||||
|   (let ((filename (->> buffer-file-name | ||||
|                        (s-replace "/src/" "/test/") | ||||
|                        (s-replace ".hs" "Test.hs") | ||||
|                        find-file))) | ||||
|     (make-directory (f-dirname filename) t) | ||||
|     (find-file filename))) | ||||
| 
 | ||||
| (defun wpc-haskell-test->module () | ||||
|   "Jump from a test to a module." | ||||
|   (let ((filename (->> buffer-file-name | ||||
|                        (s-replace "/test/" "/src/") | ||||
|                        (s-replace "Test.hs" ".hs")))) | ||||
|     (make-directory (f-dirname filename) t) | ||||
|     (find-file filename))) | ||||
| 
 | ||||
| (defun wpc-haskell-test<->module () | ||||
|   "Toggle between test and module in Haskell." | ||||
|   (interactive) | ||||
|   (if (s-contains? "/src/" buffer-file-name) | ||||
|       (wpc-haskell-module->test) | ||||
|     (wpc-haskell-test->module))) | ||||
| 
 | ||||
| (provide 'wpc-haskell) | ||||
| ;;; wpc-haskell.el ends here | ||||
							
								
								
									
										99
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-javascript.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-javascript.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,99 @@ | |||
| ;;; wpc-javascript.el --- My Javascript preferences -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; This module hosts my Javascript tooling preferences.  This also includes | ||||
| ;; tooling for TypeScript and other frontend tooling.  Perhaps this module will | ||||
| ;; change names to more accurately reflect that. | ||||
| ;; | ||||
| ;; Depends | ||||
| ;; - yarn global add prettier | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; Constants | ||||
| (defconst wpc-javascript--js-hooks | ||||
|   '(js-mode-hook | ||||
|     web-mode-hook | ||||
|     typescript-mode-hook | ||||
|     js2-mode-hook | ||||
|     rjsx-mode-hook) | ||||
|   "All of the commonly used hooks for Javascript buffers.") | ||||
| 
 | ||||
| (defconst wpc-javascript--frontend-hooks | ||||
|   (-insert-at 0 'css-mode-hook wpc-javascript--js-hooks) | ||||
|   "All of the commonly user hooks for frontend development.") | ||||
| 
 | ||||
| ;; frontend indentation settings | ||||
| (setq typescript-indent-level 2 | ||||
|       js-indent-level 2 | ||||
|       css-indent-offset 2) | ||||
| 
 | ||||
| ;; Flow for Javascript | ||||
| (use-package add-node-modules-path | ||||
|   :config | ||||
|   (general-add-hook wpc-javascript--js-hooks #'add-node-modules-path)) | ||||
| 
 | ||||
| (use-package web-mode | ||||
|   :mode "\\.html\\'" | ||||
|   :config | ||||
|   (setq web-mode-css-indent-offset 2) | ||||
|   (setq web-mode-code-indent-offset 2) | ||||
|   (setq web-mode-markup-indent-offset 2)) | ||||
| 
 | ||||
| ;; JSX highlighting | ||||
| (use-package rjsx-mode | ||||
|   :config | ||||
|   (general-unbind rjsx-mode-map "<" ">" "C-d") | ||||
|   (general-nmap | ||||
|     :keymaps 'rjsx-mode-map | ||||
|     "K" #'flow-minor-type-at-pos) | ||||
|   (setq js2-mode-show-parse-errors nil | ||||
|         js2-mode-show-strict-warnings nil)) | ||||
| 
 | ||||
| (progn | ||||
|   (defun wpc-javascript-tide-setup () | ||||
|     (interactive) | ||||
|     (tide-setup) | ||||
|     (flycheck-mode 1) | ||||
|     (setq flycheck-check-syntax-automatically '(save mode-enabled)) | ||||
|     (eldoc-mode 1) | ||||
|     (tide-hl-identifier-mode 1) | ||||
|     (company-mode 1)) | ||||
|   (use-package tide | ||||
|     :config | ||||
|     (add-hook 'typescript-mode-hook #'wpc-javascript-tide-setup)) | ||||
|   (require 'web-mode) | ||||
|   (add-to-list 'auto-mode-alist '("\\.tsx\\'" . web-mode)) | ||||
|   (add-hook 'web-mode-hook | ||||
|             (lambda () | ||||
|               (when (string-equal "tsx" (f-ext buffer-file-name)) | ||||
|                 (wpc-javascript-tide-setup)))) | ||||
|   (flycheck-add-mode 'typescript-tslint 'web-mode)) | ||||
| 
 | ||||
| ;; JS autoformatting | ||||
| (use-package prettier-js | ||||
|   :config | ||||
|   (general-add-hook wpc-javascript--frontend-hooks #'prettier-js-mode)) | ||||
| 
 | ||||
| ;; Support Elm | ||||
| (use-package elm-mode | ||||
|   :config | ||||
|   (add-hook 'elm-mode-hook #'elm-format-on-save-mode)) | ||||
| 
 | ||||
| (provide 'wpc-javascript) | ||||
| ;;; wpc-javascript.el ends here | ||||
							
								
								
									
										116
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-lisp.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-lisp.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,116 @@ | |||
| ;;; wpc-lisp.el --- Generic LISP preferences -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; parent (up) | ||||
| ;; child (down) | ||||
| ;; prev-sibling (left) | ||||
| ;; next-sibling (right) | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;; TODO: Consider having a separate module for each LISP dialect. | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (defconst wpc-lisp--hooks | ||||
|   '(lisp-mode-hook | ||||
|     emacs-lisp-mode-hook | ||||
|     clojure-mode-hook | ||||
|     clojurescript-mode-hook | ||||
|     racket-mode-hook) | ||||
|   "List of LISP modes.") | ||||
| 
 | ||||
| (use-package sly | ||||
|   :config | ||||
|   (setq inferior-lisp-program "sbcl") | ||||
|   (general-define-key | ||||
|    :keymaps 'sly-mode-map | ||||
|    :states '(normal) | ||||
|    :prefix "<SPC>" | ||||
|    "x" #'sly-eval-defun | ||||
|    "X" #'sly-eval-buffer | ||||
|    "d" #'sly-describe-symbol)) | ||||
| 
 | ||||
| (use-package rainbow-delimiters | ||||
|   :config | ||||
|   (general-add-hook wpc-lisp--hooks #'rainbow-delimiters-mode)) | ||||
| 
 | ||||
| (use-package racket-mode | ||||
|   :config | ||||
|   (general-define-key | ||||
|    :keymaps 'racket-mode-map | ||||
|    :states 'normal | ||||
|    :prefix "<SPC>" | ||||
|    "x" #'racket-send-definition | ||||
|    "X" #'racket-run | ||||
|    "d" #'racket-describe) | ||||
|   (setq racket-program "~/.nix-profile/bin/racket")) | ||||
| 
 | ||||
| (use-package lispyville | ||||
|   :init | ||||
|   (defconst wpc-lisp--lispyville-key-themes | ||||
|     '(c-w | ||||
|       operators | ||||
|       text-objects | ||||
|       prettify | ||||
|       commentary | ||||
|       slurp/barf-cp | ||||
|       wrap | ||||
|       additional | ||||
|       additional-insert | ||||
|       additional-wrap | ||||
|       escape) | ||||
|     "All available key-themes in Lispyville.") | ||||
|   :config | ||||
|   (general-add-hook wpc-lisp--hooks #'lispyville-mode) | ||||
|   (lispyville-set-key-theme wpc-lisp--lispyville-key-themes) | ||||
|   (progn | ||||
|     (general-define-key | ||||
|      :keymaps 'lispyville-mode-map | ||||
|      :states 'motion | ||||
|      ;; first unbind | ||||
|      "M-h" nil | ||||
|      "M-l" nil) | ||||
|     (general-define-key | ||||
|      :keymaps 'lispyville-mode-map | ||||
|      :states 'normal | ||||
|      ;; first unbind | ||||
|      "M-j" nil | ||||
|      "M-k" nil | ||||
|      ;; second rebind | ||||
|      "C-s-h" #'lispyville-drag-backward | ||||
|      "C-s-l" #'lispyville-drag-forward | ||||
|      "C-s-e" #'lispyville-end-of-defun | ||||
|      "C-s-a" #'lispyville-beginning-of-defun))) | ||||
| 
 | ||||
| ;; Elisp | ||||
| (use-package elisp-slime-nav | ||||
|   :config | ||||
|   (general-add-hook 'emacs-lisp-mode #'ielm-mode)) | ||||
| 
 | ||||
| (general-define-key | ||||
|  :keymaps 'emacs-lisp-mode-map | ||||
|  :prefix "<SPC>" | ||||
|  :states 'normal | ||||
|  "x" #'eval-defun | ||||
|  "X" #'eval-buffer | ||||
|  "d" (lambda () | ||||
|        (interactive) | ||||
|        (with-current-buffer (current-buffer) | ||||
|          (helpful-function (symbol-at-point))))) | ||||
| 
 | ||||
| (provide 'wpc-lisp) | ||||
| ;;; wpc-lisp.el ends here | ||||
							
								
								
									
										315
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-misc.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										315
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-misc.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,315 @@ | |||
| ;;; wpc-misc.el --- Hosting miscellaneous configuration -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; This is the home of any configuration that couldn't find a better home. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'project) | ||||
| (require 'f) | ||||
| (require 'dash) | ||||
| (require 'constants) | ||||
| (require 'region) | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (setq display-time-string-forms | ||||
|       '((format-time-string "%H:%M %a %b %d"))) | ||||
| (display-time-mode 1) | ||||
| 
 | ||||
| ;; Remove the boilerplate in the *scratch* buffer | ||||
| (setq initial-scratch-message "") | ||||
| 
 | ||||
| ;; disable custom variable entries from being written to ~/.emacs.d/init.el | ||||
| (setq custom-file (f-join user-emacs-directory "custom.el")) | ||||
| (load custom-file 'noerror) | ||||
| 
 | ||||
| ;; integrate Emacs with X11 clipboard | ||||
| (setq select-enable-primary t) | ||||
| (setq select-enable-clipboard t) | ||||
| (general-def 'insert | ||||
|   "s-v" #'clipboard-yank | ||||
|   "C-S-v" #'clipboard-yank) | ||||
| 
 | ||||
| ;; transparently edit compressed files | ||||
| (auto-compression-mode t) | ||||
| 
 | ||||
| ;; autowrap when over the fill-column | ||||
| (setq-default auto-fill-function #'do-auto-fill) | ||||
| 
 | ||||
| ;; link to Emacs source code | ||||
| ;; TODO: Update this link. | ||||
| (setq find-function-C-source-directory | ||||
|       "~/Dropbox/programming/emacs/src") | ||||
| 
 | ||||
| ;; change emacs prompts from "yes or no" -> "y or n" | ||||
| (fset 'yes-or-no-p 'y-or-n-p) | ||||
| 
 | ||||
| ;; open photos in Emacs | ||||
| (auto-image-file-mode 1) | ||||
| 
 | ||||
| ;; disable line-wrapping | ||||
| (setq-default truncate-lines 1) | ||||
| 
 | ||||
| ;; shell file indentation | ||||
| (setq sh-basic-offset 2) | ||||
| (setq sh-indentation 2) | ||||
| 
 | ||||
| ;; Emacs library that interfaces with my Linux password manager. | ||||
| (use-package password-store) | ||||
| 
 | ||||
| (use-package vterm | ||||
|   :config | ||||
|   (general-define-key | ||||
|    :keymaps '(vterm-mode-map) | ||||
|    :states '(insert) | ||||
|    "C-S-v" #'vterm-yank) | ||||
|   (general-define-key | ||||
|    :keymaps '(vterm-mode-map) | ||||
|    :states '(normal) | ||||
|    "K" #'evil-scroll-line-up | ||||
|    "J" #'evil-scroll-line-down | ||||
|    "C-b" #'evil-scroll-page-up | ||||
|    "C-f" #'evil-scroll-page-down)) | ||||
| 
 | ||||
| ;; Use en Emacs buffer as a REST client. | ||||
| ;; For more information: http://emacsrocks.com/e15.html | ||||
| (use-package restclient) | ||||
| 
 | ||||
| ;; Run `package-lint' before publishing to MELPA. | ||||
| (use-package package-lint) | ||||
| 
 | ||||
| ;; Parser combinators in Elisp. | ||||
| (use-package parsec) | ||||
| 
 | ||||
| ;; disable company mode when editing markdown | ||||
| ;; TODO: move this out of wpc-misc.el and into a later file to call | ||||
| ;; `(disable company-mode)' | ||||
| (use-package markdown-mode | ||||
|   :config | ||||
|   ;; TODO: Add assertion that pandoc is installed and it is accessible from | ||||
|   ;; Emacs. | ||||
|   (setq markdown-command "pandoc") | ||||
|   (setq markdown-split-window-direction 'right) | ||||
|   ;; (add-hook 'markdown-mode-hook #'markdown-live-preview-mode) | ||||
|   ) | ||||
| 
 | ||||
| (use-package alert) | ||||
| 
 | ||||
| (use-package refine) | ||||
| 
 | ||||
| ;; Required by some google-emacs package commands. | ||||
| (use-package deferred) | ||||
| 
 | ||||
| ;; git integration | ||||
| (use-package magit | ||||
|   :config | ||||
|   (add-hook 'git-commit-setup-hook | ||||
|             (lambda () | ||||
|               (company-mode -1) | ||||
|               (flyspell-mode 1))) | ||||
|   (setq magit-display-buffer-function | ||||
|         #'magit-display-buffer-fullframe-status-v1)) | ||||
| 
 | ||||
| (use-package magit-popup) | ||||
| 
 | ||||
| ;; http | ||||
| (use-package request) | ||||
| 
 | ||||
| ;; perl-compatible regular expressions | ||||
| (use-package pcre2el) | ||||
| 
 | ||||
| ;; alternative to help | ||||
| (use-package helpful) | ||||
| 
 | ||||
| ;; If called from an existing helpful-mode buffer, reuse that buffer; otherwise, | ||||
| ;; call `pop-to-buffer'. | ||||
| (setq helpful-switch-buffer-function | ||||
|       (lambda (buffer-or-name) | ||||
|         (if (eq major-mode 'helpful-mode) | ||||
|             (switch-to-buffer buffer-or-name) | ||||
|           (pop-to-buffer buffer-or-name)))) | ||||
| 
 | ||||
| ;; Emacs integration with direnv | ||||
| (use-package direnv | ||||
|   :config | ||||
|   (direnv-mode)) | ||||
| 
 | ||||
| ;; Superior Elisp library for working with dates and times. | ||||
| ;; TODO: Put this where my other installations for dash.el, s.el, a.el, and | ||||
| ;; other utility Elisp libraries are located. | ||||
| (use-package ts) | ||||
| 
 | ||||
| ;; persist history etc b/w Emacs sessions | ||||
| (setq desktop-save 'if-exists) | ||||
| (desktop-save-mode 1) | ||||
| (setq desktop-globals-to-save | ||||
|       (append '((extended-command-history . 30) | ||||
|                 (file-name-history        . 100) | ||||
|                 (grep-history             . 30) | ||||
|                 (compile-history          . 30) | ||||
|                 (minibuffer-history       . 50) | ||||
|                 (query-replace-history    . 60) | ||||
|                 (read-expression-history  . 60) | ||||
|                 (regexp-history           . 60) | ||||
|                 (regexp-search-ring       . 20) | ||||
|                 (search-ring              . 20) | ||||
|                 (shell-command-history    . 50) | ||||
|                 tags-file-name | ||||
|                 register-alist))) | ||||
| 
 | ||||
| ;; configure ibuffer | ||||
| (setq ibuffer-default-sorting-mode 'major-mode) | ||||
| 
 | ||||
| ;; config Emacs to use $PATH values | ||||
| (use-package exec-path-from-shell | ||||
|   :if (memq window-system '(mac ns)) | ||||
|   :config | ||||
|   (exec-path-from-shell-initialize)) | ||||
| 
 | ||||
| ;; Emacs autosave, backup, interlocking files | ||||
| (setq auto-save-default nil | ||||
|       make-backup-files nil | ||||
|       create-lockfiles nil) | ||||
| 
 | ||||
| ;; ensure code wraps at 80 characters by default | ||||
| (setq-default fill-column constants-fill-column) | ||||
| 
 | ||||
| (put 'narrow-to-region 'disabled nil) | ||||
| 
 | ||||
| ;; trim whitespace on save | ||||
| (add-hook 'before-save-hook #'delete-trailing-whitespace) | ||||
| 
 | ||||
| ;; call `git secret hide` after saving secrets.json | ||||
| (add-hook 'after-save-hook | ||||
|           (lambda () | ||||
|             (when (f-equal? (buffer-file-name) | ||||
|                             (f-join constants-briefcase "secrets.json")) | ||||
|               (shell-command "git secret hide")))) | ||||
| 
 | ||||
| ;; use tabs instead of spaces | ||||
| (setq-default indent-tabs-mode nil) | ||||
| 
 | ||||
| ;; automatically follow symlinks | ||||
| (setq vc-follow-symlinks t) | ||||
| 
 | ||||
| ;; fullscreen settings | ||||
| (setq ns-use-native-fullscreen nil) | ||||
| 
 | ||||
| (use-package yasnippet | ||||
|   :config | ||||
|   (setq yas-snippet-dirs (list (f-join user-emacs-directory "snippets"))) | ||||
|   (yas-global-mode 1)) | ||||
| 
 | ||||
| (use-package projectile | ||||
|   :config | ||||
|   (projectile-mode t)) | ||||
| 
 | ||||
| ;; TODO: Consider moving this into a briefcase.el module. | ||||
| (defun wpc-misc--briefcase-find (dir) | ||||
|   "Find the default.nix nearest to DIR." | ||||
|   ;; I use 'vc only at the root of my monorepo because 'transient doesn't use my | ||||
|   ;; .gitignore, which slows things down. Ideally, I could write a version that | ||||
|   ;; behaves like 'transient but also respects my monorepo's .gitignore and any | ||||
|   ;; ancestor .gitignore files. | ||||
|   (if (f-equal? constants-briefcase dir) | ||||
|       (cons 'vc dir) | ||||
|     (when (f-ancestor-of? constants-briefcase dir) | ||||
|       (if (f-exists? (f-join dir "default.nix")) | ||||
|           (cons 'transient dir) | ||||
|         (wpc-misc--briefcase-find (f-parent dir)))))) | ||||
| 
 | ||||
| (add-to-list 'project-find-functions #'wpc-misc--briefcase-find) | ||||
| 
 | ||||
| (defun wpc-misc-pkill (name) | ||||
|   "Call the pkill executable using NAME as its argument." | ||||
|   (interactive "sProcess name: ") | ||||
|   (call-process "pkill" nil nil nil name)) | ||||
| 
 | ||||
| (use-package deadgrep | ||||
|   :config | ||||
|   (general-define-key | ||||
|    :keymaps 'deadgrep-mode-map | ||||
|    :states 'normal | ||||
|    "o" #'deadgrep-visit-result-other-window) | ||||
|   (setq-default deadgrep--context '(0 . 3)) | ||||
|   (defun wpc-misc-deadgrep-region () | ||||
|     "Run a ripgrep search on the active region." | ||||
|     (interactive) | ||||
|     (deadgrep (region-to-string))) | ||||
|   (defun wpc-misc-deadgrep-dwim () | ||||
|     "If a region is active, use that as the search, otherwise don't." | ||||
|     (interactive) | ||||
|     (with-current-buffer (current-buffer) | ||||
|       (if (region-active-p) | ||||
|           (setq deadgrep--additional-flags '("--multiline")) | ||||
|           (wpc-misc-deadgrep-region) | ||||
|         (call-interactively #'deadgrep)))) | ||||
|   (advice-add | ||||
|    'deadgrep--format-command | ||||
|    :filter-return | ||||
|    (lambda (cmd) | ||||
|      (replace-regexp-in-string | ||||
|       "^rg " "rg --hidden " cmd)))) | ||||
| 
 | ||||
| ;; TODO: Do I need this when I have swiper? | ||||
| (use-package counsel) | ||||
| 
 | ||||
| (use-package counsel-projectile) | ||||
| 
 | ||||
| ;; search Google, Stackoverflow from within Emacs | ||||
| (use-package engine-mode | ||||
|   :config | ||||
|   (defengine google | ||||
|     "http://www.google.com/search?ie=utf-8&oe=utf-8&q=%s" | ||||
|     :keybinding "g") | ||||
|   (defengine stack-overflow | ||||
|     "https://stackoverflow.com/search?q=%s" | ||||
|     :keybinding "s")) | ||||
| 
 | ||||
| ;; EGlot (another LSP client) | ||||
| (use-package eglot) | ||||
| 
 | ||||
| ;; Microsoft's Debug Adapter Protocol (DAP) | ||||
| (use-package dap-mode | ||||
|   :after lsp-mode | ||||
|   :config | ||||
|   (dap-mode 1) | ||||
|   (dap-ui-mode 1)) | ||||
| 
 | ||||
| ;; Microsoft's Language Server Protocol (LSP) | ||||
| (use-package lsp-ui | ||||
|   :config | ||||
|   (add-hook 'lsp-mode-hook #'lsp-ui-mode)) | ||||
| 
 | ||||
| (use-package company-lsp | ||||
|   :config | ||||
|   (push 'company-lsp company-backends)) | ||||
| 
 | ||||
| ;; Wilfred/suggest.el - Tool for discovering functions basesd on declaring your | ||||
| ;; desired inputs and outputs. | ||||
| (use-package suggest) | ||||
| 
 | ||||
| ;; Malabarba/paradox - Enhances the `list-packages' view. | ||||
| (use-package paradox | ||||
|   :config | ||||
|   (paradox-enable)) | ||||
| 
 | ||||
| ;; Start the Emacs server | ||||
| (when (not (server-running-p)) | ||||
|   (server-start)) | ||||
| 
 | ||||
| (provide 'wpc-misc) | ||||
| ;;; wpc-misc.el ends here | ||||
							
								
								
									
										72
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-nix.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-nix.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,72 @@ | |||
| ;;; wpc-nix.el --- Nix support -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "25.1")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Configuration to support working with Nix. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'device) | ||||
| (require 'constants) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Library | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (use-package nix-mode | ||||
|   :mode "\\.nix\\'") | ||||
| 
 | ||||
| ;; TODO(wpcarro): Ensure the sub-process can resolve <briefcase>. | ||||
| (defun wpc-nix-rebuild-emacs () | ||||
|   "Use nix-env to rebuild wpcarros-emacs." | ||||
|   (interactive) | ||||
|   (let* ((pname (format "nix-build <briefcase/emacs.nixos>")) | ||||
|          (bname (format "*%s*" pname))) | ||||
|     (start-process pname bname | ||||
|                    "nix-env" | ||||
|                    "-I" (format "briefcase=%s" constants-briefcase) | ||||
|                    "-f" "<briefcase>" "-iA" "emacs.nixos") | ||||
|     (display-buffer bname))) | ||||
| 
 | ||||
| (defun wpc-nix-sly-from-briefcase (attr) | ||||
|   "Start a Sly REPL configured using the derivation pointed at by ATTR. | ||||
| 
 | ||||
|   The derivation invokes nix.buildLisp.sbclWith and is built asynchronously. | ||||
|   The build output is included in the error thrown on build failures." | ||||
|   (interactive "sAttribute: ") | ||||
|   (lexical-let* ((outbuf (get-buffer-create (format "*briefcase-out/%s*" attr))) | ||||
|          (errbuf (get-buffer-create (format "*briefcase-errors/%s*" attr))) | ||||
|          (expression (format "let briefcase = import <briefcase> {}; in briefcase.third_party.depot.nix.buildLisp.sbclWith [ briefcase.%s ]" attr)) | ||||
|          (command (list "nix-build" "-E" expression))) | ||||
|     (message "Acquiring Lisp for <briefcase>.%s" attr) | ||||
|     (make-process :name (format "nix-build/%s" attr) | ||||
|                   :buffer outbuf | ||||
|                   :stderr errbuf | ||||
|                   :command command | ||||
|                   :sentinel | ||||
|                   (lambda (process event) | ||||
|                     (unwind-protect | ||||
|                         (pcase event | ||||
|                           ("finished\n" | ||||
|                            (let* ((outpath (s-trim (with-current-buffer outbuf | ||||
|                                                      (buffer-string)))) | ||||
|                                   (lisp-path (s-concat outpath "/bin/sbcl"))) | ||||
|                              (message "Acquired Lisp for <briefcase>.%s at %s" | ||||
|                                       attr lisp-path) | ||||
|                              (sly lisp-path))) | ||||
|                           (_ (with-current-buffer errbuf | ||||
|                                (error "Failed to build '%s':\n%s" attr | ||||
|                                       (buffer-string))))) | ||||
|                       (kill-buffer outbuf) | ||||
|                       (kill-buffer errbuf)))))) | ||||
| 
 | ||||
| (provide 'wpc-nix) | ||||
| ;;; wpc-nix.el ends here | ||||
							
								
								
									
										40
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-org.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-org.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,40 @@ | |||
| ;;; wpc-org.el --- My org preferences -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24.1")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Hosts my org mode preferences | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'f) | ||||
| (require 'macros) | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (use-package org | ||||
|   :config | ||||
|   (evil-set-initial-state 'org-mode 'normal) | ||||
|   (general-add-hook 'org-mode-hook | ||||
|                     (list (macros-disable linum-mode) | ||||
|                           (macros-disable company-mode))) | ||||
|   (setq org-startup-folded nil) | ||||
|   (setq org-todo-keywords '((sequence "TODO" "BLOCKED" "DONE"))) | ||||
|   (general-unbind 'normal org-mode-map "M-h" "M-j" "M-k" "M-l")) | ||||
| 
 | ||||
| (use-package org-bullets | ||||
|   :config | ||||
|   (general-add-hook 'org-mode-hook (macros-enable org-bullets-mode))) | ||||
| 
 | ||||
| (provide 'wpc-org) | ||||
| ;;; wpc-org.el ends here | ||||
							
								
								
									
										33
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-package.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-package.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,33 @@ | |||
| ;;; wpc-package.el --- My package configuration -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24.1")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; This module hosts all of the settings required to work with ELPA, | ||||
| ;; MELPA, QUELPA, and co. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| (require 'package) | ||||
| 
 | ||||
| ;; Even though we're packaging our Emacs with Nix, having MELPA registered is | ||||
| ;; helpful to ad-hoc test out packages before declaratively adding them to | ||||
| ;; emacs/default.nix. | ||||
| (add-to-list 'package-archives '("melpa" . "http://melpa.org/packages/")) | ||||
| (package-initialize) | ||||
| 
 | ||||
| (unless (package-installed-p 'use-package) | ||||
|   ;; TODO: Consider removing this to improve initialization speed. | ||||
|   (package-refresh-contents) | ||||
|   (package-install 'use-package)) | ||||
| (eval-when-compile | ||||
|   (require 'use-package)) | ||||
| ;; TODO: Consider removing this, since I'm requiring general.el in individual | ||||
| ;; modules. | ||||
| (use-package general) | ||||
| 
 | ||||
| (provide 'wpc-package) | ||||
| ;;; wpc-package.el ends here | ||||
							
								
								
									
										20
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-prolog.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-prolog.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,20 @@ | |||
| ;;; wpc-prolog.el --- For Prologging things -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Code configuring my Prolog work. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| (require 'macros) | ||||
| 
 | ||||
| ;; TODO: Notice that the .pl extension conflicts with Perl files. This may | ||||
| ;; become a problem should I start working with Perl. | ||||
| (macros-support-file-extension "pl" prolog-mode) | ||||
| 
 | ||||
| (provide 'wpc-prolog) | ||||
| ;;; wpc-prolog.el ends here | ||||
							
								
								
									
										25
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-python.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-python.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,25 @@ | |||
| ;;; wpc-python.el --- Python configuration -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; My Python configuration settings | ||||
| ;; | ||||
| ;; Depends | ||||
| ;; - `apti yapf` | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (use-package py-yapf | ||||
|   :config | ||||
|   (add-hook 'python-mode-hook #'py-yapf-enable-on-save)) | ||||
| 
 | ||||
| (provide 'wpc-python) | ||||
| ;;; wpc-python.el ends here | ||||
							
								
								
									
										48
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-rust.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										48
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-rust.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,48 @@ | |||
| ;;; wpc-rust.el --- Support Rust language -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Supports my Rust work. | ||||
| ;; | ||||
| ;; Dependencies: | ||||
| ;; - `rustup` | ||||
| ;; - `rustup component add rust-src` | ||||
| ;; - `rustup toolchain add nightly && cargo +nightly install racer` | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'macros) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (use-package racer | ||||
|   :config | ||||
|   (setq rust-sysroot (->> "~/.cargo/bin/rustc --print sysroot" | ||||
|                           shell-command-to-string | ||||
|                           s-trim-right)) | ||||
|   (setq racer-rust-src-path (f-join rust-sysroot "lib/rustlib/src/rust/src")) | ||||
|   (add-hook 'racer-mode-hook #'eldoc-mode)) | ||||
| 
 | ||||
| (use-package rust-mode | ||||
|   :config | ||||
|   (add-hook 'rust-mode-hook #'racer-mode) | ||||
|   (macros-add-hook-before-save 'rust-mode-hook #'rust-format-buffer) | ||||
|   (define-key rust-mode-map | ||||
|     (kbd "TAB") | ||||
|     #'company-indent-or-complete-common) | ||||
|   (define-key rust-mode-map | ||||
|     (kbd "M-d") | ||||
|     #'racer-describe)) | ||||
| 
 | ||||
| (provide 'wpc-rust) | ||||
| ;;; wpc-rust.el ends here | ||||
							
								
								
									
										32
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-shell.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-shell.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,32 @@ | |||
| ;;; wpc-shell.el --- POSIX Shell scripting support -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| ;; Homepage: https://user.git.corp.google.com/wpcarro/briefcase | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Helpers for my shell scripting.  Includes bash, zsh, etc. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'zle) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Code | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (use-package flymake-shellcheck | ||||
|   :commands flymake-shellcheck-load | ||||
|   :init | ||||
|   (add-hook 'sh-mode-hook #'flymake-shellcheck-load) | ||||
|   (add-hook 'sh-mode-hook #'zle-minor-mode)) | ||||
| 
 | ||||
| (use-package fish-mode) | ||||
| 
 | ||||
| (provide 'wpc-shell) | ||||
| ;;; wpc-shell.el ends here | ||||
							
								
								
									
										181
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-ui.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										181
									
								
								users/wpcarro/emacs/.emacs.d/wpc/wpc-ui.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,181 @@ | |||
| ;;; wpc-ui.el --- Any related to the UI/UX goes here -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; Hosts font settings, scrolling, color schemes. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Dependencies | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| (require 'constants) | ||||
| (require 'prelude) | ||||
| (require 'al) | ||||
| (require 'fonts) | ||||
| (require 'colorscheme) | ||||
| (require 'device) | ||||
| (require 'laptop-battery) | ||||
| (require 'modeline) | ||||
| (require 'general) | ||||
| 
 | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| ;; Configuration | ||||
| ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; | ||||
| 
 | ||||
| ;; line height | ||||
| (setq-default line-spacing 0) | ||||
| 
 | ||||
| (when window-system | ||||
|   (setq frame-title-format '(buffer-file-name "%f" ("%b")))) | ||||
| 
 | ||||
| ;; Ensure that buffers update when their contents change on disk. | ||||
| (global-auto-revert-mode t) | ||||
| 
 | ||||
| ;; smooth scrolling settings | ||||
| (setq scroll-step 1 | ||||
|       scroll-conservatively 10000) | ||||
| 
 | ||||
| ;; clean up modeline | ||||
| (use-package diminish | ||||
|   :config | ||||
|   (diminish 'emacs-lisp-mode "elisp") | ||||
|   (diminish 'evil-commentary-mode) | ||||
|   (diminish 'flycheck-mode) | ||||
|   (diminish 'auto-revert-mode) | ||||
|   (diminish 'which-key-mode) | ||||
|   (diminish 'yas-minor-mode) | ||||
|   (diminish 'lispyville-mode) | ||||
|   (diminish 'undo-tree-mode) | ||||
|   (diminish 'company-mode) | ||||
|   (diminish 'projectile-mode) | ||||
|   (diminish 'eldoc-mode) | ||||
|   ;; This is how to diminish `auto-fill-mode'. | ||||
|   (diminish 'auto-fill-function) | ||||
|   (diminish 'counsel-mode) | ||||
|   (diminish 'ivy-mode)) | ||||
| 
 | ||||
| ;; TODO: Further customize `mode-line-format' variable. | ||||
| (delete 'mode-line-modes mode-line-format) | ||||
| (delete '(vc-mode vc-mode) mode-line-format) | ||||
| 
 | ||||
| ;; disable startup screen | ||||
| (setq inhibit-startup-screen t) | ||||
| 
 | ||||
| ;; disable toolbar | ||||
| (tool-bar-mode -1) | ||||
| 
 | ||||
| ;; set default buffer for Emacs | ||||
| (setq initial-buffer-choice constants-current-project) | ||||
| 
 | ||||
| ;; premium Emacs themes | ||||
| (use-package doom-themes | ||||
|   :config | ||||
|   (setq doom-themes-enable-bold t | ||||
|         doom-themes-enable-italic t) | ||||
|   (doom-themes-visual-bell-config) | ||||
|   (doom-themes-org-config)) | ||||
| 
 | ||||
| ;; kbd discovery | ||||
| (use-package which-key | ||||
|   :config | ||||
|   (setq which-key-idle-delay 0.25) | ||||
|   (which-key-mode)) | ||||
| 
 | ||||
| ;; completion framework | ||||
| (use-package ivy | ||||
|   :config | ||||
|   (counsel-mode t) | ||||
|   (ivy-mode t) | ||||
|   ;; Remove preceding "^" from ivy prompts | ||||
|   (setq ivy-initial-inputs-alist nil) | ||||
|   ;; prefer using `helpful' variants | ||||
|   (progn | ||||
|     (setq counsel-describe-function-function #'helpful-callable) | ||||
|     (setq counsel-describe-variable-function #'helpful-variable)) | ||||
|   (general-define-key | ||||
|    :keymaps '(ivy-minibuffer-map ivy-switch-buffer-map) | ||||
|    ;; prev | ||||
|    "C-k" #'ivy-previous-line | ||||
|    "<backtab>" #'ivy-previous-line | ||||
|    ;; next | ||||
|    "C-j" #'ivy-next-line | ||||
|    "<tab>" #'ivy-next-line)) | ||||
| 
 | ||||
| (use-package ivy-prescient | ||||
|   :config | ||||
|   (ivy-prescient-mode 1) | ||||
|   (prescient-persist-mode 1)) | ||||
| 
 | ||||
| ;; all-the-icons | ||||
| (use-package all-the-icons | ||||
|   :config | ||||
|   (when (not constants-ci?) | ||||
|     (unless (f-exists? "~/.local/share/fonts/all-the-icons.ttf") | ||||
|       (all-the-icons-install-fonts t)))) | ||||
| 
 | ||||
| ;; icons for Ivy | ||||
| (use-package all-the-icons-ivy | ||||
|   :after (ivy all-the-icons) | ||||
|   :config | ||||
|   (all-the-icons-ivy-setup)) | ||||
| 
 | ||||
| ;; disable menubar | ||||
| (menu-bar-mode -1) | ||||
| 
 | ||||
| ;; reduce noisiness of auto-revert-mode | ||||
| (setq auto-revert-verbose nil) | ||||
| 
 | ||||
| ;; highlight lines that are over `constants-fill-column' characters long | ||||
| (use-package whitespace | ||||
|   :config | ||||
|   ;; TODO: This should change depending on the language and project. For | ||||
|   ;; example, Google Java projects prefer 100 character width instead of 80 | ||||
|   ;; character width. | ||||
|   (setq whitespace-line-column constants-fill-column) | ||||
|   (setq whitespace-style '(face lines-tail)) | ||||
|   (add-hook 'prog-mode-hook #'whitespace-mode)) | ||||
| 
 | ||||
| ;; dirname/filename instead of filename<dirname> | ||||
| (setq uniquify-buffer-name-style 'forward) | ||||
| 
 | ||||
| ;; highlight matching parens, brackets, etc | ||||
| (show-paren-mode 1) | ||||
| 
 | ||||
| ;; hide the scroll-bars in the GUI | ||||
| (scroll-bar-mode -1) | ||||
| 
 | ||||
| ;; TODO: Learn how to properly integrate this with dunst or another system-level | ||||
| ;; notification program. | ||||
| ;; GUI alerts in emacs | ||||
| (use-package alert | ||||
|   :commands (alert) | ||||
|   :config | ||||
|   (setq alert-default-style 'notifier)) | ||||
| 
 | ||||
| ;; TODO: Should `device-work-laptop?' be a function or a constant that gets set | ||||
| ;; during initialization? | ||||
| (when (device-work-laptop?) | ||||
|   (laptop-battery-display)) | ||||
| 
 | ||||
| (if window-system | ||||
|     (progn | ||||
|       (fonts-whitelist-set "JetBrainsMono") | ||||
|       (fonts-enable-ligatures) | ||||
|       (colorscheme-whitelist-set 'doom-solarized-light) | ||||
|       ;; the doom-acario-dark theme uses "Monospace Serif" as the font for | ||||
|       ;; comments, and I'd prefer JetBrainsMono (no italics). | ||||
|       (set-face-attribute font-lock-comment-face nil | ||||
|                           :family "JetBrainsMono" | ||||
|                           :slant 'normal)) | ||||
|   (load-theme 'wombat)) | ||||
| 
 | ||||
| (modeline-setup) | ||||
| 
 | ||||
| (provide 'wpc-ui) | ||||
| ;;; wpc-ui.el ends here | ||||
							
								
								
									
										92
									
								
								users/wpcarro/emacs/.emacs.d/wpc/zle.el
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										92
									
								
								users/wpcarro/emacs/.emacs.d/wpc/zle.el
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,92 @@ | |||
| ;;; zle.el --- Functions to mimmick my ZLE KBDs -*- lexical-binding: t -*- | ||||
| 
 | ||||
| ;; Author: William Carroll <wpcarro@gmail.com> | ||||
| ;; Version: 0.0.1 | ||||
| ;; URL: https://git.wpcarro.dev/wpcarro/briefcase | ||||
| ;; Package-Requires: ((emacs "24")) | ||||
| 
 | ||||
| ;;; Commentary: | ||||
| ;; This is primarily for personal use.  The keybindings that I choose are those | ||||
| ;; that feel slightly mnemonic while also not shadowing important bindings. | ||||
| ;; It's quite possible that our tastes will differ here. | ||||
| ;; | ||||
| ;; All of these keybindings are intended to shave off milliseconds off your | ||||
| ;; typing.  I don't expect these numbers to sum up to a meaningful amount.  The | ||||
| ;; primary reason that I wrote this, is that it introduces a small amount of | ||||
| ;; structural editing to my workflow.  I've been using these exact keybindings | ||||
| ;; on the command line, and I find them subtely delightful to use.  So much so | ||||
| ;; that I decided to bring them to my Emacs configuration. | ||||
| ;; | ||||
| ;; ZLE is the Z-shell line editor.  I have some KBDs and functions that I often | ||||
| ;; want in Emacs. | ||||
| ;; | ||||
| ;; Usage: | ||||
| ;; Consider running `(zle-minor-mode)' to run this globally.  Depending on your | ||||
| ;; configuration, it could be non-disruptive, disruptive, or extremely | ||||
| ;; disruptive. | ||||
| 
 | ||||
| ;;; Code: | ||||
| 
 | ||||
| ;; subshell (C-j) | ||||
| (defun zle-subshell () | ||||
|   "Insert the characters necessary to create a subshell." | ||||
|   (interactive) | ||||
|   (insert-char ?$) | ||||
|   (insert-char ?\() | ||||
|   (save-excursion | ||||
|     (insert-char ?\)))) | ||||
| 
 | ||||
| ;; variable (C-v) | ||||
| (defun zle-variable () | ||||
|   "Insert the characters to reference a variable." | ||||
|   (interactive) | ||||
|   (insert-char ?$) | ||||
|   (insert-char ?{) | ||||
|   (save-excursion | ||||
|     (insert-char ?}))) | ||||
| 
 | ||||
| ;; 2x dash (C-M--) | ||||
| (defun zle-dash-dash () | ||||
|   "Insert the characters for flags with 2x dashes." | ||||
|   (interactive) | ||||
|   (insert-char ? ) | ||||
|   (insert-char ?-) | ||||
|   (insert-char ?-)) | ||||
| 
 | ||||
| ;; 1x quotes (M-') | ||||
| (defun zle-single-quote () | ||||
|   "Insert the characters to quickly create single quotes." | ||||
|   (interactive) | ||||
|   (insert-char ? ) | ||||
|   (insert-char ?') | ||||
|   (save-excursion | ||||
|     (insert-char ?'))) | ||||
| 
 | ||||
| ;; 2x quotes (M-") | ||||
| (defun zle-double-quote () | ||||
|   "Insert the characters to quickly create double quotes." | ||||
|   (interactive) | ||||
|   (insert-char ? ) | ||||
|   (insert-char ?\") | ||||
|   (save-excursion | ||||
|     (insert-char ?\"))) | ||||
| 
 | ||||
| (defvar zle-kbds | ||||
|   (let ((map (make-sparse-keymap))) | ||||
|     (bind-keys :map map | ||||
|                ("C-j"   . zle-subshell) | ||||
|                ("C-v"   . zle-variable) | ||||
|                ("C-M--" . zle-dash-dash) | ||||
|                ("M-'"   . zle-single-quote) | ||||
|                ("M-\""  . zle-double-quote)) | ||||
|     map) | ||||
|   "Keybindings shaving milliseconds off of typing.") | ||||
| 
 | ||||
| (define-minor-mode zle-minor-mode | ||||
|   "A minor mode mirroring my ZLE keybindings." | ||||
|   :init-value nil | ||||
|   :lighter " zle" | ||||
|   :keymap zle-kbds) | ||||
| 
 | ||||
| (provide 'zle) | ||||
| ;;; zle.el ends here | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue