diff options
Diffstat (limited to 'users/wpcarro/emacs/.emacs.d/wpc')
39 files changed, 3342 insertions, 0 deletions
diff --git a/users/wpcarro/emacs/.emacs.d/wpc/>.el b/users/wpcarro/emacs/.emacs.d/wpc/>.el new file mode 100644 index 000000000000..6d5f86f8b4e6 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/>.el @@ -0,0 +1,28 @@ +;;; >.el --- Small utility functions -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/buffer.el b/users/wpcarro/emacs/.emacs.d/wpc/buffer.el new file mode 100644 index 000000000000..0f86f7f811e6 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/buffer.el @@ -0,0 +1,174 @@ +;;; buffer.el --- Working with buffers -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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) +(require 'list) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Library +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(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-ivy-source-code-whitelist '("*scratch*" "*Messages*") + "A whitelist of buffers to include when 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: " + (-concat buffer-ivy-source-code-whitelist + (-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))) + +(provide 'buffer) +;;; buffer.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/clipboard.el b/users/wpcarro/emacs/.emacs.d/wpc/clipboard.el new file mode 100644 index 000000000000..ec2a46f5404f --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/clipboard.el @@ -0,0 +1,40 @@ +;;; clipboard.el --- Working with X11's pasteboard -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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. + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/constants.el b/users/wpcarro/emacs/.emacs.d/wpc/constants.el new file mode 100644 index 000000000000..48bcd9042f78 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/constants.el @@ -0,0 +1,29 @@ +;;; constants.el --- Constants for organizing my Elisp -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24")) + +;;; Commentary: +;; This file contains constants that are shared across my configuration. + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dependencies +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'maybe) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Configuration +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defconst constants-ci? (maybe-some? (getenv "CI")) + "Defined as t when Emacs is running in CI.") + +(defconst constants-osx? (eq system-type 'darwin) + "Defined as t when OSX is running.") + +(provide 'constants) +;;; constants.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/display.el b/users/wpcarro/emacs/.emacs.d/wpc/display.el new file mode 100644 index 000000000000..69dae6939e40 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/display.el @@ -0,0 +1,103 @@ +;;; display.el --- Working with single or multiple displays -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 " ")))))) + +(provide 'display) +;;; display.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/email.el b/users/wpcarro/emacs/.emacs.d/wpc/email.el new file mode 100644 index 000000000000..a83ca25e6c17 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/email.el @@ -0,0 +1,76 @@ +;;; email.el --- My email settings -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/fonts.el b/users/wpcarro/emacs/.emacs.d/wpc/fonts.el new file mode 100644 index 000000000000..0f70f69c2b8d --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/fonts.el @@ -0,0 +1,99 @@ +;;; fonts.el --- Font preferences -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24.3")) + +;;; Commentary: +;; Control my font preferences with ELisp. + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dependencies +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'maybe) +(require 'cl-lib) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Constants +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defgroup fonts nil + "Customize group for fonts configuration.") + +(defcustom fonts-size "10" + "My preferred default font-size." + :group 'fonts) + +(defcustom fonts-size-step 10 + "The amount (%) by which to increase or decrease a font." + :group 'fonts) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(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-current () + "Return the currently enabled font." + (symbol-name (font-get (face-attribute 'default :font) :family))) + +(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-set (fonts-current) fonts-size)) + +(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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/ivy-helpers.el b/users/wpcarro/emacs/.emacs.d/wpc/ivy-helpers.el new file mode 100644 index 000000000000..3303237d52af --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/ivy-helpers.el @@ -0,0 +1,67 @@ +;;; ivy-helpers.el --- More interfaces to ivy -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/kbd.el b/users/wpcarro/emacs/.emacs.d/wpc/kbd.el new file mode 100644 index 000000000000..7defc3d08f3b --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/kbd.el @@ -0,0 +1,85 @@ +;;; kbd.el --- Elisp keybinding -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/keybindings.el b/users/wpcarro/emacs/.emacs.d/wpc/keybindings.el new file mode 100644 index 000000000000..a55bf2733011 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/keybindings.el @@ -0,0 +1,495 @@ +;;; keybindings.el --- Centralizing my keybindings -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 'screen-brightness) +(require 'pulse-audio) +(require 'scrot) +(require 'ivy) +(require 'ivy-clipmenu) +(require 'ivy-helpers) +(require 'general) +(require 'exwm) +(require 'vterm-mgt) +(require 'buffer) +(require 'fonts) +(require 'bookmark) +(require 'tvl) +(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-commentary) +(require 'evil-surround) +(require 'key-chord) +(require 'edebug) +(require 'avy) +(require 'passage) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Helper Functions +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun keybindings--window-vsplit-right () + "Split the window vertically and focus the right half." + (interactive) + (evil-window-vsplit) + (windmove-right)) + +(defun keybindings--window-split-down () + "Split the window horizontal and focus the bottom half." + (interactive) + (evil-window-split) + (windmove-down)) + +(defun keybindings--create-snippet () + "Create a window split and then opens the Yasnippet editor." + (interactive) + (evil-window-vsplit) + (call-interactively #'yas-new-snippet)) + +(defun keybindings--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 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)) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; General Keybindings +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; 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" #'keybindings--window-vsplit-right + "sh" #'evil-window-vsplit + "sk" #'evil-window-split + "sj" #'keybindings--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") + +(customize-set-variable '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))))) + +(general-define-key + :keymaps '(isearch-mode-map) + "C-p" #'isearch-ring-retreat + "C-n" #'isearch-ring-advance + "<up>" #'isearch-ring-retreat + "<down>" #'isearch-ring-advance) + +(general-define-key + :keymaps '(minibuffer-local-isearch-map) + "C-p" #'previous-line-or-history-element + "C-n" #'next-line-or-history-element + "<up>" #'previous-line-or-history-element + "<down>" #'next-line-or-history-element) + +(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-S-f" #'window-manager-toggle-previous) +(keybindings-exwm "C-M-\\" #'passage-select) + +(defun keybindings-copy-emoji () + "Select an emoji from the completing-read menu." + (interactive) + (clipboard-copy (emojify-completing-read "Copy: "))) + +(keybindings-exwm "s-e" #'keybindings-copy-emoji) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Workspaces +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +(keybindings-exwm (kbd-raw 'workspace "l") + (lambda () + (interactive) + (shell-command window-manager-screenlocker))) + +(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 + "gsd" #'tvl-depot-status + "E" #'refine + "es" #'keybindings--create-snippet + "l" #'linum-mode + "B" #'magit-blame + "w" #'save-buffer + "r" #'keybindings--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) + ;; For some reason vterm captures this KBD instead of EXWM + "C-S-f" nil + "s-x" #'vterm-mgt-select + "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 + ;; Without this, typing "+" is effectively no-op. Try for yourself: + ;; (vterm-send-key "<kp-add>") + "<kp-add>" "+" + "M--" #'evil-window-split + "M-\\" #'evil-window-vsplit) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 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) + +(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) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; buffers +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(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) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; edebug +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(general-define-key + :states '(normal) + :keymaps '(edebug-mode-map) + ;; this restores my ability to move-left while debugging + "h" nil) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; deadgrep +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(general-define-key + :states '(normal) + :keymaps '(deadgrep-mode-map) + "<tab>" #'deadgrep-forward + "<backtab>" #'deadgrep-backward) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; bookmarks +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(bookmark-install-kbd + (make-bookmark :label "wpcarro" + :path (f-join tvl-depot-path "users/wpcarro") + :kbd "w")) + +(bookmark-install-kbd + (make-bookmark :label "depot" + :path tvl-depot-path + :kbd "d")) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; refine +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(general-define-key + :keymaps '(refine-mode-map) + :states '(normal) + "K" #'refine-delete + "q" #'kill-this-buffer) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; avy +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(global-set-key (kbd "C-;") #'avy-goto-char) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; ivy +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +;; restore the ability to paste in ivy +(general-define-key + :keymaps '(ivy-minibuffer-map) + "C-k" #'kill-line + "C-u" (lambda () (interactive) (kill-line 0)) + "C-v" #'clipboard-yank + "C-S-v" #'clipboard-yank) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Rust +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(general-define-key + :keymaps '(rust-mode-map) + :states '(normal) + "gd" #'lsp-find-definition + "gr" #'lsp-find-references) + +(general-define-key + :keymaps '(rust-mode-map) + "TAB" #'company-indent-or-complete-common) + +(provide 'keybindings) +;;; keybindings.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/keyboard.el b/users/wpcarro/emacs/.emacs.d/wpc/keyboard.el new file mode 100644 index 000000000000..0ee00e1b84e7 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/keyboard.el @@ -0,0 +1,138 @@ +;;; keyboard.el --- Managing keyboard preferences with Elisp -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 'cl-lib) +(require 'prelude) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 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 (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 (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 (1+ keyboard-repeat-rate)) + (keyboard-set-key-repeat :rate keyboard-repeat-rate) + (keyboard-message + (format "Rate: %s" keyboard-repeat-rate))) + +(defun keyboard-dec-repeat-rate () + "Decrement `keyboard-repeat-rate'." + (interactive) + (setq keyboard-repeat-rate (1- keyboard-repeat-rate)) + (keyboard-set-key-repeat :rate keyboard-repeat-rate) + (keyboard-message + (format "Rate: %s" keyboard-repeat-rate))) + +(defun keyboard-inc-repeat-delay () + "Increment `keyboard-repeat-delay'." + (interactive) + (setq keyboard-repeat-delay (1+ keyboard-repeat-delay)) + (keyboard-set-key-repeat :delay keyboard-repeat-delay) + (keyboard-message + (format "Delay: %s" keyboard-repeat-delay))) + +(defun keyboard-dec-repeat-delay () + "Decrement `keyboard-repeat-delay'." + (interactive) + (setq keyboard-repeat-delay (1- keyboard-repeat-delay)) + (keyboard-set-key-repeat :delay keyboard-repeat-delay) + (keyboard-message + (format "Delay: %s" keyboard-repeat-delay))) + +(defun keyboard-print-key-repeat () + "Print the currently set values for key repeat." + (interactive) + (keyboard-message + (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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/modeline.el b/users/wpcarro/emacs/.emacs.d/wpc/modeline.el new file mode 100644 index 000000000000..df1cddec9d92 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/modeline.el @@ -0,0 +1,68 @@ +;;; modeline.el --- Customize my mode-line -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "25.1")) + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/prelude.el b/users/wpcarro/emacs/.emacs.d/wpc/prelude.el new file mode 100644 index 000000000000..4a332cb8ca0e --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/prelude.el @@ -0,0 +1,144 @@ +;;; 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")) + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/pulse-audio.el b/users/wpcarro/emacs/.emacs.d/wpc/pulse-audio.el new file mode 100644 index 000000000000..eaa610659073 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/pulse-audio.el @@ -0,0 +1,69 @@ +;;; pulse-audio.el --- Control audio with Elisp -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24")) + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/region.el b/users/wpcarro/emacs/.emacs.d/wpc/region.el new file mode 100644 index 000000000000..0b692981f899 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/region.el @@ -0,0 +1,23 @@ +;;; region.el --- Functions for working with regions -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/screen-brightness.el b/users/wpcarro/emacs/.emacs.d/wpc/screen-brightness.el new file mode 100644 index 000000000000..851be9f99f80 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/screen-brightness.el @@ -0,0 +1,57 @@ +;;; screen-brightness.el --- Control laptop screen brightness -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24")) + +;;; Commentary: +;; Control your laptop's screen brightness. + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dependencies +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'prelude) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Constants +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defgroup screen-brightness nil "Configuration for screen-brightness.") + +(defcustom screen-brightness-increase-cmd + "light -A 3" + "The shell command to run to increase screen brightness." + :group 'screen-brightness + :type 'string) + +(defcustom screen-brightness-decrease-cmd + "light -U 3" + "The shell command to run to decrease screen brightness." + :group 'screen-brightness + :type 'string) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Library +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun screen-brightness-increase () + "Increase the screen brightness." + (interactive) + (prelude-start-process + :name "screen-brightness-increase" + :command screen-brightness-increase-cmd) + (message "[screen-brightness.el] Increased screen brightness.")) + +(defun screen-brightness-decrease () + "Decrease the screen brightness." + (interactive) + (prelude-start-process + :name "screen-brightness-decrease" + :command screen-brightness-decrease-cmd) + (message "[screen-brightness.el] Decreased screen brightness.")) + +(provide 'screen-brightness) +;;; screen-brightness.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/scrot.el b/users/wpcarro/emacs/.emacs.d/wpc/scrot.el new file mode 100644 index 000000000000..08994fea5fda --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/scrot.el @@ -0,0 +1,54 @@ +;;; scrot.el --- Screenshot functions -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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-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" "--select" ,screenshot-path) + :sentinel (lambda (proc _err) + (when (= 0 (process-exit-status proc)) + (scrot--copy-image screenshot-path)))))) + +(provide 'scrot) +;;; scrot.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/ssh.el b/users/wpcarro/emacs/.emacs.d/wpc/ssh.el new file mode 100644 index 000000000000..1179e9036334 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/ssh.el @@ -0,0 +1,67 @@ +;;; ssh.el --- When working remotely -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 '("wpcarro@wpcarro.dev" + "foundation" + "edge") + "List of hosts to which I commonly connect.") + +(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) + (pcase (s-split ":" buffer-file-name) + (`(,one ,two ,three) (find-file (format "/ssh:%s|sudo:%s:%s" two two three)))) + (find-file + (s-join ":" (-insert-at 2 "|sudo" (s-split ":" buffer-file-name)))) + (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:%s:~" machine)))) + +(provide 'ssh) +;;; ssh.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/window-manager.el b/users/wpcarro/emacs/.emacs.d/wpc/window-manager.el new file mode 100644 index 000000000000..94fb99d4271b --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/window-manager.el @@ -0,0 +1,228 @@ +;;; window-manager.el --- Functions augmenting my usage of EXWM -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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. + +;; Wist List: +;; - TODO: Consider supporting MRU cache of worksapces. + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dependencies +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'alert) +(require 'cycle) +(require 'dash) +(require 'kbd) +(require 's) +(require 'exwm) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Variables +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defgroup window-manager nil + "Customization options for `window-manager'.") + +(cl-defstruct window-manager-named-workspace + label kbd display) + +(defcustom window-manager-named-workspaces nil + "List of `window-manager-named-workspace' structs." + :group 'window-manager + :type (list 'window-manager-named-workspace)) + +(defcustom window-manager-screenlocker "xsecurelock" + "Reference to a screen-locking executable." + :group 'window-manager + :type 'string) + +(defvar window-manager--workspaces nil + "Cycle of the my EXWM workspaces.") + +(defconst window-manager--modes + (cycle-from-list (list #'window-manager--char-mode + #'window-manager--line-mode)) + "Functions to switch exwm modes.") + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Library +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(defun window-manager--alert (x) + "Message X with a structured format." + (alert (s-concat "[exwm] " x))) + +(cl-defun window-manager-init (&key init-hook) + "Call `exwm-enable' alongside other bootstrapping functions." + (require 'exwm-config) + (require 'exwm-randr) + (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 (length window-manager-named-workspaces)) + (setq exwm-input-simulation-keys + '(([?\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]) + ([?\C-c] . [C-c]))) + ;; Install workspace KBDs + (progn + (->> window-manager-named-workspaces + (list-map #'window-manager--register-kbd)) + (window-manager--alert "Registered workspace KBDs!")) + ;; Ensure exwm apps open in char-mode. + (add-hook 'exwm-manage-finish-hook #'window-manager--char-mode) + (add-hook 'exwm-init-hook init-hook) + (setq window-manager--workspaces + (cycle-from-list window-manager-named-workspaces)) + (exwm-randr-enable) + (exwm-enable)) + +(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))) + +;; 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")) + +(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))))) + +(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 + (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))) + +(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)))) + +(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-workspace-move () + "Prompt the user to move the current workspace to another." + (interactive) + (exwm-workspace-move + exwm-workspace--current + (window-manager--label->index + (completing-read "Move current workspace to: " + (->> window-manager-named-workspaces + (-map #'window-manager-named-workspace-label)) + nil + t) + window-manager-named-workspaces))) + +(defun window-manager-move-window () + "Prompt the user to move the current window to another workspace." + (interactive) + (let ((window (get-buffer-window)) + (dest (completing-read "Move current window to: " + (->> window-manager-named-workspaces + (-map #'window-manager-named-workspace-label)) + nil + t))) + (exwm-workspace-move-window + (exwm-workspace--workspace-from-frame-or-index + (window-manager--label->index dest window-manager-named-workspaces)) + (exwm--buffer->id window)) + (window-manager--switch dest))) + +(provide 'window-manager) +;;; window-manager.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-clojure.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-clojure.el new file mode 100644 index 000000000000..5582641b3f35 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-clojure.el @@ -0,0 +1,71 @@ +;;; wpc-clojure.el --- My Clojure preferences -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-company.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-company.el new file mode 100644 index 000000000000..89fde4b6a177 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-company.el @@ -0,0 +1,41 @@ +;;; wpc-company.el --- Autocompletion package, company, preferences -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-dired.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-dired.el new file mode 100644 index 000000000000..7c22a4657fc0 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-dired.el @@ -0,0 +1,51 @@ +;;; wpc-dired.el --- My dired preferences -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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) + (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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-dotnet.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-dotnet.el new file mode 100644 index 000000000000..03fc430e4846 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-dotnet.el @@ -0,0 +1,16 @@ +;;; wpc-dotnet.el --- C# and company -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> + +;;; Commentary: +;; Windows things v0v. + +;;; Code: + +(require 'macros) + +(use-package csharp-mode) +(macros-support-file-extension "csproj" xml-mode) + +(provide 'wpc-dotnet) +;;; wpc-dotnet.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-elixir.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-elixir.el new file mode 100644 index 000000000000..69259274c86d --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-elixir.el @@ -0,0 +1,27 @@ +;;; wpc-elixir.el --- Elixir / Erland configuration -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-flycheck.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-flycheck.el new file mode 100644 index 000000000000..c32c5daeff13 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-flycheck.el @@ -0,0 +1,17 @@ +;;; wpc-flycheck.el --- My flycheck configuration -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-golang.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-golang.el new file mode 100644 index 000000000000..47198c8e02a1 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-golang.el @@ -0,0 +1,42 @@ +;;; wpc-golang.el --- Tooling preferences for Go -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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. + +(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 () + (setq-local tab-width 2) + (setq-local compile-command "go build -v"))) + (macros-add-hook-before-save 'go-mode-hook #'gofmt-before-save)) + +(provide 'wpc-golang) +;;; wpc-golang.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-haskell.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-haskell.el new file mode 100644 index 000000000000..536790e36d61 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-haskell.el @@ -0,0 +1,53 @@ +;;; wpc-haskell.el --- My Haskell preferences -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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)) + +;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-javascript.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-javascript.el new file mode 100644 index 000000000000..9e137ad8803e --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-javascript.el @@ -0,0 +1,93 @@ +;;; wpc-javascript.el --- My Javascript preferences -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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) + +(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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-language-support.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-language-support.el new file mode 100644 index 000000000000..8363e3c08ea0 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-language-support.el @@ -0,0 +1,36 @@ +;;; wpc-language-support.el --- Support for miscellaneous programming languages -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "25.1")) + +;;; Commentary: +;; I defined this module to declutter my init.el. +;; +;; When a particular programming-language's configuration gets too complicated, +;; I break it out into a dedicated module. Everything else gets dumped in +;; "Miscellaneous Configuration". + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dedicated Modules +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'wpc-lisp) +(require 'wpc-haskell) +(require 'wpc-elixir) +(require 'wpc-nix) +(require 'wpc-rust) +(require 'wpc-clojure) +(require 'wpc-prolog) +(require 'wpc-dotnet) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Miscellaneous Configuration +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(use-package terraform-mode) + +(provide 'wpc-language-support) +;;; wpc-language-support.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-lisp.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-lisp.el new file mode 100644 index 000000000000..599d42620419 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-lisp.el @@ -0,0 +1,123 @@ +;;; wpc-lisp.el --- Generic LISP preferences -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; 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)) + +(defun wpc-lisp-copy-elisp-eval-output () + "Copy the output of the elisp evaluation" + (interactive) + (call-interactively 'eval-last-sexp) + (clipboard-copy (current-message) + :message (format "%s - copied!" (current-message)))) + +(general-define-key + :keymaps 'emacs-lisp-mode-map + :prefix "<SPC>" + :states 'normal + "c" #'wpc-lisp-copy-elisp-eval-output + "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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-misc.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-misc.el new file mode 100644 index 000000000000..36fbf8b12ce6 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-misc.el @@ -0,0 +1,330 @@ +;;; wpc-misc.el --- Hosting miscellaneous configuration -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "25.1")) + +;;; Commentary: +;; This is the home of any configuration that couldn't find a better home. + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dependencies +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'project) +(require 'f) +(require 'dash) +(require 'tvl) +(require 'region) +(require 'general) +(require 'constants) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 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 +(customize-set-variable 'select-enable-primary t) +(customize-set-variable 'select-enable-clipboard t) +(customize-set-variable 'evil-visual-update-x-selection-p nil) +(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) + +(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 mode-specific syntax highlighting for code blocks. + (setq markdown-fontify-code-blocks-natively t) + ;; Prevent Emacs from adding a space after the leading 3x-backticks. + (setq markdown-spaces-after-code-fence 0)) + +(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-same-window-except-diff-v1)) + +(use-package magit-popup) + +;; http +(use-package request) + +;; TVL depot stuff +(use-package tvl) + +;; 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) + +;; 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 80) + +;; render tabs 2x-chars wide +(setq tab-width 2) + +(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 tvl-depot-path + "users" + "wpcarro" + "secrets.json")) + (shell-command "git secret hide")))) + +;; use tabs instead of spaces +(setq-default indent-tabs-mode nil) + +;; prefer shorter tab-widths (e.g. writing Go code) +(setq-default tab-width 2) + +;; automatically follow symlinks +(setq vc-follow-symlinks t) + +;; fullscreen settings +(setq ns-use-native-fullscreen nil) + +(use-package yasnippet + :config + (unless constants-ci? + (setq yas-snippet-dirs (list (f-join user-emacs-directory "snippets"))) + (yas-global-mode 1))) + +(use-package projectile + :config + (projectile-mode t)) + +;; TODO(wpcarro): Consider replacing this with a TVL version if it exists. +(defun wpc-misc--depot-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? tvl-depot-path dir) + (cons 'vc dir) + (when (f-ancestor-of? tvl-depot-path dir) + (if (f-exists? (f-join dir "default.nix")) + (cons 'transient dir) + (wpc-misc--depot-find (f-parent dir)))))) + +(add-to-list 'project-find-functions #'wpc-misc--depot-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--arguments + :filter-return + (lambda (args) + (push "--hidden" args) + (push "--follow" args)))) + +;; 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)) + +;; 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)) + +;; render emojis in Emacs 🕺 +(use-package emojify + :config + (add-hook 'after-init-hook #'global-emojify-mode) + ;; Disable the default styles of: + ;; - ascii :P (When this is enabled, the vim command, :x, renders as 😶) + ;; - github :smile: + (setq emojify-emoji-styles '(unicode))) + +;; Always auto-close parantheses and other pairs +(electric-pair-mode) + +;; Start the Emacs server +(when (not (server-running-p)) + (server-start)) + +(provide 'wpc-misc) +;;; wpc-misc.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-nix.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-nix.el new file mode 100644 index 000000000000..e9dc203691c2 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-nix.el @@ -0,0 +1,37 @@ +;;; wpc-nix.el --- Nix support -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "25.1")) + +;;; Commentary: +;; Configuration to support working with Nix. + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dependencies +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'tvl) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Library +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(use-package nix-mode + :mode "\\.nix\\'") + +(defun wpc-nix-rebuild-emacs () + "Use nix-env to rebuild wpcarros-emacs." + (interactive) + (let* ((pname (format "nix-env -iA users.wpcarro.emacs.nixos")) + (bname (format "*%s*" pname))) + (start-process pname bname + "nix-env" + "-f" tvl-depot-path + "-iA" "users.wpcarro.emacs.nixos") + (display-buffer bname))) + +(provide 'wpc-nix) +;;; wpc-nix.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-org.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-org.el new file mode 100644 index 000000000000..229177220b1e --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-org.el @@ -0,0 +1,39 @@ +;;; wpc-org.el --- My org preferences -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24.1")) + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-package.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-package.el new file mode 100644 index 000000000000..9c57bb427076 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-package.el @@ -0,0 +1,32 @@ +;;; wpc-package.el --- My package configuration -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24.1")) + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-prolog.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-prolog.el new file mode 100644 index 000000000000..6779431c1215 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-prolog.el @@ -0,0 +1,19 @@ +;;; wpc-prolog.el --- For Prologging things -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24")) + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-python.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-python.el new file mode 100644 index 000000000000..9ffb7c4c8a2b --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-python.el @@ -0,0 +1,24 @@ +;;; wpc-python.el --- Python configuration -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24")) + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-rust.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-rust.el new file mode 100644 index 000000000000..b609efb431fd --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-rust.el @@ -0,0 +1,30 @@ +;;; wpc-rust.el --- Support Rust language -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24")) + +;;; Commentary: +;; Supports my Rust work. + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dependencies +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require 'lsp) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Configuration +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(use-package rust-mode + :config + (setq lsp-rust-server #'rust-analyzer) + (setq rust-format-show-buffer nil) + (setq rust-format-on-save t) + (add-hook 'rust-mode-hook #'lsp)) + +(provide 'wpc-rust) +;;; wpc-rust.el ends here diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-shell.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-shell.el new file mode 100644 index 000000000000..f4229ed328e7 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-shell.el @@ -0,0 +1,31 @@ +;;; wpc-shell.el --- POSIX Shell scripting support -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24")) + +;;; 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 diff --git a/users/wpcarro/emacs/.emacs.d/wpc/wpc-ui.el b/users/wpcarro/emacs/.emacs.d/wpc/wpc-ui.el new file mode 100644 index 000000000000..a2f533cec095 --- /dev/null +++ b/users/wpcarro/emacs/.emacs.d/wpc/wpc-ui.el @@ -0,0 +1,186 @@ +;;; wpc-ui.el --- Any related to the UI/UX goes here -*- lexical-binding: t -*- + +;; Author: William Carroll <wpcarro@gmail.com> +;; Version: 0.0.1 +;; Package-Requires: ((emacs "24")) + +;;; Commentary: +;; Hosts font settings, scrolling, color schemes. + +;;; Code: + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; Dependencies +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; + +(require '>) +(require 'al) +(require 'constants) +(require 'dash) +(require 'fonts) +(require 'general) +(require 'modeline) +(require 'prelude) +(require 'theme) + +;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; +;; 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) + +;; 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) + (unless constants-ci? + (prescient-persist-mode 1))) + +;; all-the-icons +(use-package all-the-icons + :config + (unless (or constants-ci? + (f-exists? "~/.local/share/fonts/all-the-icons.ttf") + (f-exists? "~/Library/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 80 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 80) + (setq whitespace-style '(face lines-tail tabs)) + (global-whitespace-mode t)) + +;; 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)) + +(display-battery-mode 1) + +(setq theme-whitelist + (->> (custom-available-themes) + (list-map #'symbol-name) + (list-filter (>-> (s-starts-with? "doom-"))) + (list-map #'intern) + cycle-from-list)) +(setq theme-linum-color-override "da5478") +(add-hook 'theme-after-change + (lambda () (prelude-set-line-number-color "#da5478"))) +(theme-whitelist-set 'doom-flatwhite) + +(when window-system + ;; On OSX, JetBrainsMono is installed as "JetBrains Mono", and I'm + ;; not sure how to change that. + (let ((font (if constants-osx? "JetBrains Mono" "JetBrainsMono"))) + (fonts-set font) + ;; Some themes (e.g. doom-acario-*) change the font for comments. This + ;; should prevent that. + (set-face-attribute font-lock-comment-face nil + :family font + :slant 'normal))) + +(modeline-setup) + +(provide 'wpc-ui) +;;; wpc-ui.el ends here |