diff --git a/emacs/.emacs.d/wpc/keybindings.el b/emacs/.emacs.d/wpc/keybindings.el index 190535360..2f4a703b0 100644 --- a/emacs/.emacs.d/wpc/keybindings.el +++ b/emacs/.emacs.d/wpc/keybindings.el @@ -128,7 +128,7 @@ (keybinding/exwm "" #'pulse-audio/toggle-microphone) (keybinding/exwm "C-M-c" #'chrome/browse) (keybinding/exwm (kbd/raw 'x11 "s") #'scrot/select) -(keybinding/exwm "" #'exwm/switch-to-exwm-buffer) +(keybinding/exwm "" #'window-manager-switch-to-exwm-buffer) (general-define-key :keymaps 'override diff --git a/emacs/.emacs.d/wpc/window-manager.el b/emacs/.emacs.d/wpc/window-manager.el index 25c2abe9f..ee25f9203 100644 --- a/emacs/.emacs.d/wpc/window-manager.el +++ b/emacs/.emacs.d/wpc/window-manager.el @@ -1,5 +1,9 @@ -;;; window-manager.el --- Functions augmenting my usage of EXWM. -*- lexical-binding: t -*- +;;; window-manager.el --- Functions augmenting my usage of EXWM -*- lexical-binding: t -*- + ;; Author: William Carroll +;; Version: 0.0.1 +;; URL: https://git.wpcarro.dev/wpcarro/briefcase +;; Package-Requires: ((emacs "25.1")) ;;; Commentary: ;; I switched to EXWM from i3, and I haven't looked back. One day I may write a @@ -32,12 +36,6 @@ ;; Library ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; TODO: Move this function to another module. -(defun pkill (name) - "Call the pkill executable using NAME as its argument." - (interactive "sProcess name: ") - (call-process "pkill" nil nil nil name)) - ;; TODO: Associate `window-purpose' window-layouts with each of these named ;; workspaces. @@ -58,37 +56,37 @@ ;; TODO: Support MRU cache of workspaces for easily switching back-and-forth ;; between workspaces. -(cl-defstruct exwm/named-workspace label kbd) +(cl-defstruct window-manager--named-workspace label kbd) -(defconst exwm/install-workspace-kbds? t +(defconst window-manager--install-kbds? t "When t, install the keybindings to switch between named-workspaces.") ;; TODO: Consume `cache/touch' after changing workspaces. Use this to enable ;; cycling through workspaces. -(defconst exwm/named-workspaces - (list (make-exwm/named-workspace +(defconst window-manager--named-workspaces + (list (make-window-manager--named-workspace :label "Web surfing" :kbd "c") - (make-exwm/named-workspace + (make-window-manager--named-workspace :label "Briefcase" :kbd "d") - (make-exwm/named-workspace + (make-window-manager--named-workspace :label "Todos" :kbd "o") - (make-exwm/named-workspace + (make-window-manager--named-workspace :label "Chatter" :kbd "h")) - "List of `exwm/named-workspace' structs.") + "List of `window-manager--named-workspace' structs.") ;; Assert that no two workspaces share KBDs. -(prelude/assert (= (list/length exwm/named-workspaces) - (->> exwm/named-workspaces - (list/map #'exwm/named-workspace-kbd) +(prelude/assert (= (list/length window-manager--named-workspaces) + (->> window-manager--named-workspaces + (list/map #'window-manager--named-workspace-kbd) set/from-list set/count))) -(defun window-manager/alert (x) +(defun window-manager--alert (x) "Message X with a structured format." (alert (string/concat "[exwm] " x))) @@ -108,7 +106,7 @@ (evil-set-initial-state 'exwm-mode 'emacs) (setq exwm-workspace-number - (list/length exwm/named-workspaces)) + (list/length window-manager--named-workspaces)) ;; EXWM supports "line-mode" and "char-mode". ;; ;; Note: It appears that calling `exwm-input-set-key' works if it's called @@ -164,17 +162,17 @@ (:key "M-:" :fn eval-expression) (:key "M-SPC" :fn ivy-helpers/run-external-command) (:key "M-x" :fn counsel-M-x) - (:key "" :fn exwm/next-workspace) - (:key "" :fn exwm/prev-workspace) - (:key "" :fn exwm/prev-workspace) + (:key "" :fn window-manager-next-workspace) + (:key "" :fn window-manager-prev-workspace) + (:key "" :fn window-manager-prev-workspace) (:key "C-M-\\" :fn ivy-pass) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;; Workspaces ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; - (:key ,(kbd/raw 'workspace "l") :fn window-manager/logout) - (:key ,(kbd/raw 'workspace "i") :fn exwm/toggle-mode)))) + (:key ,(kbd/raw 'workspace "l") :fn window-manager-logout) + (:key ,(kbd/raw 'workspace "i") :fn window-manager-toggle-mode)))) (setq exwm-input-global-keys (->> kbds (-map (lambda (plist) @@ -198,75 +196,61 @@ ;; TODO: Package workspace management in another module. ;; Here is the code required to allow EXWM to cycle workspaces. -(defconst exwm/workspaces - (->> exwm/named-workspaces +(defconst window-manager--workspaces + (->> window-manager--named-workspaces cycle/from-list) "Cycle of the my EXWM workspaces.") (prelude/assert (= exwm-workspace-number - (list/length exwm/named-workspaces))) + (list/length window-manager--named-workspaces))) -(defun exwm/next-workspace () +(defun window-manager-next-workspace () "Cycle forwards to the next workspace." (interactive) - (exwm/change-workspace (cycle/next exwm/workspaces))) + (window-manager--change-workspace (cycle/next window-manager--workspaces))) -(defun exwm/prev-workspace () +(defun window-manager-prev-workspace () "Cycle backwards to the previous workspace." (interactive) - (exwm/change-workspace (cycle/prev exwm/workspaces))) + (window-manager--change-workspace (cycle/prev window-manager--workspaces))) ;; TODO: Create friendlier API for working with EXWM. ;; Here is the code required to toggle EXWM's modes. -(defun exwm/line-mode () +(defun window-manager--line-mode () "Switch exwm to line-mode." (call-interactively #'exwm-input-grab-keyboard) - (window-manager/alert "Switched to line-mode")) + (window-manager--alert "Switched to line-mode")) -(defun exwm/char-mode () +(defun window-manager--char-mode () "Switch exwm to char-mode." (call-interactively #'exwm-input-release-keyboard) - (window-manager/alert "Switched to char-mode")) + (window-manager--alert "Switched to char-mode")) -(defconst exwm/modes - (cycle/from-list (list #'exwm/char-mode - #'exwm/line-mode)) +(defconst window-manager--modes + (cycle/from-list (list #'window-manager--char-mode + #'window-manager--line-mode)) "Functions to switch exwm modes.") -(defun exwm/toggle-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 exwm/modes))))) + (funcall (cycle/next window-manager--modes))))) ;; Ensure exwm apps open in char-mode. -(add-hook 'exwm-manage-finish-hook #'exwm/char-mode) +(add-hook 'exwm-manage-finish-hook #'window-manager--char-mode) ;; Interface to the Linux password manager ;; TODO: Consider writing a better client for this. (use-package ivy-pass) ;; TODO: How do I handle this dependency? -(defconst exwm/preferred-browser "google-chrome" +(defconst window-manager--preferred-browser "google-chrome" "My preferred web browser.") -;; TODO: Support searching all "launchable" applications like OSX's Spotlight. -;; TODO: Model this as key-value pairs. -(defconst window-manager/applications - (list "google-chrome --new-window --app=https://chat.google.com" - "google-chrome --new-window --app=https://calendar.google.com" - "google-chrome --new-window --app=https://gmail.com" - "telegram-desktop" - "google-chrome --new-window --app=https://teknql.slack.com" - "google-chrome --new-window --app=https://web.whatsapp.com" - "google-chrome --new-window --app=https://irccloud.com" - exwm/preferred-browser) - "Applications that I commonly use. -These are the types of items that would usually appear in dmenu.") - ;; TODO: Consider replacing the `ivy-read' call with something like `hydra' that ;; can provide a small mode for accepting user-input. ;; TODO: Put this somewhere more diliberate. @@ -279,7 +263,7 @@ These are the types of items that would usually appear in dmenu.") ;; Maybe just create a ~/.xsecurelockrc ;; TODO: Is there a shell-command API that accepts an alist and serializes it ;; into variables to pass to the shell command? -(defconst window-manager/xsecurelock +(defconst window-manager--xsecurelock "/usr/share/goobuntu-desktop-files/xsecurelock.sh" "Path to the proper xsecurelock executable. The other path to xsecurelock is /usr/bin/xsecurelock, which works fine, but it @@ -289,7 +273,7 @@ login attempts fail with an \"unknown error\", which isn't very helpful. To avoid this, prefer the goobuntu wrapper around xsecurelock when on a goobuntu device. This all relates to PAM (i.e. pluggable authentication modules).") -(defun window-manager/logout () +(defun window-manager-logout () "Prompt the user for options for logging out, shutting down, etc. The following options are supported: @@ -302,13 +286,13 @@ The following options are supported: Ivy is used to capture the user's input." (interactive) - (let* ((name->cmd `(("Lock" . ,window-manager/xsecurelock) + (let* ((name->cmd `(("Lock" . ,window-manager--xsecurelock) ("Logout" . "sudo systemctl stop lightdm") ("Suspend" . ,(string/concat - window-manager/xsecurelock + window-manager--xsecurelock " && systemctl suspend")) ("Hibernate" . ,(string/concat - window-manager/xsecurelock + window-manager--xsecurelock " && systemctl hibernate")) ("Reboot" . "systemctl reboot") ("Shutdown" . "systemctl poweroff")))) @@ -318,80 +302,80 @@ Ivy is used to capture the user's input." (alist/get (ivy-read "System: " (alist/keys name->cmd)) name->cmd)))))) -(defun exwm/label->index (label workspaces) +(defun window-manager--label->index (label workspaces) "Return the index of the workspace in WORKSPACES named LABEL." - (let ((index (-elem-index label (-map #'exwm/named-workspace-label workspaces)))) + (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 exwm/register-kbd (workspace) +(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) - (exwm/switch (exwm/named-workspace-label workspace)))) - (key (exwm/named-workspace-kbd workspace))) + (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 exwm/change-workspace (workspace) +(defun window-manager--change-workspace (workspace) "Switch EXWM workspaces to the WORKSPACE struct." (exwm-workspace-switch - (exwm/label->index (exwm/named-workspace-label workspace) - exwm/named-workspaces)) - (window-manager/alert - (string/format "Switched to: %s" (exwm/named-workspace-label workspace)))) + (window-manager--label->index (window-manager--named-workspace-label workspace) + window-manager--named-workspaces)) + (window-manager--alert + (string/format "Switched to: %s" (window-manager--named-workspace-label workspace)))) -(defun exwm/switch (label) +(defun window-manager--switch (label) "Switch to a named workspaces using LABEL." (cycle/focus (lambda (x) (equal label - (exwm/named-workspace-label x))) - exwm/workspaces) - (exwm/change-workspace (cycle/current exwm/workspaces))) + (window-manager--named-workspace-label x))) + window-manager--workspaces) + (window-manager--change-workspace (cycle/current window-manager--workspaces))) -(exwm-input-set-key (kbd "C-S-f") #'exwm/toggle-previous) +(exwm-input-set-key (kbd "C-S-f") #'window-manager-toggle-previous) -(defun exwm/toggle-previous () +(defun window-manager-toggle-previous () "Focus the previously active EXWM workspace." (interactive) - (exwm/change-workspace (cycle/focus-previous! exwm/workspaces))) + (window-manager--change-workspace (cycle/focus-previous! window-manager--workspaces))) -(defun exwm/exwm-buffer? (x) +(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 exwm/application-name (buffer) +(defun window-manager--application-name (buffer) "Return the name of the application running in the EXWM BUFFER. -This function asssumes that BUFFER passes the `exwm/exwm-buffer?' predicate." +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 exwm/switch-to-exwm-buffer () +(defun window-manager-switch-to-exwm-buffer () "Use `completing-read' to focus an EXWM buffer." (interactive) (let* ((buffer-alist (->> (buffer-list) - (-filter #'exwm/exwm-buffer?) + (-filter #'window-manager--exwm-buffer?) (-map (lambda (buffer) - (cons (exwm/application-name buffer) + (cons (window-manager--application-name buffer) buffer))))) (label (completing-read "Switch to EXWM buffer: " buffer-alist))) (exwm-workspace-switch-to-buffer (alist-get label buffer-alist nil nil #'string=)))) -(when exwm/install-workspace-kbds? +(when window-manager--install-kbds? (progn - (->> exwm/named-workspaces - (list/map #'exwm/register-kbd)) - (window-manager/alert "Registered workspace KBDs!"))) + (->> window-manager--named-workspaces + (list/map #'window-manager--register-kbd)) + (window-manager--alert "Registered workspace KBDs!"))) ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -;; Startup Applications in `exwm/named-workspaces' +;; Startup Applications in `window-manager--named-workspaces' ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -(add-hook 'exwm-init-hook (lambda () (exwm/switch "Briefcase"))) +(add-hook 'exwm-init-hook (lambda () (window-manager--switch "Briefcase"))) (provide 'window-manager) ;;; window-manager.el ends here diff --git a/emacs/.emacs.d/wpc/wpc-misc.el b/emacs/.emacs.d/wpc/wpc-misc.el index 21dab767f..b5ecff44b 100644 --- a/emacs/.emacs.d/wpc/wpc-misc.el +++ b/emacs/.emacs.d/wpc/wpc-misc.el @@ -216,6 +216,11 @@ (add-to-list 'project-find-functions #'wpc-misc--briefcase-find) +(defun wpc-misc-pkill (name) + "Call the pkill executable using NAME as its argument." + (interactive "sProcess name: ") + (call-process "pkill" nil nil nil name)) + (use-package deadgrep :config (general-define-key