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