Lint window-manager.el

- change `exwm/` prefixes to `window-manager-`
- add Version, URL, Package-Requires sections
- move `pkill` into wpc-misc.el
- unify `window-manager,` `exwm` competing prefixes
This commit is contained in:
William Carroll 2020-08-31 14:36:55 +01:00
parent a2d45c8db7
commit 84d6fb8f39
3 changed files with 81 additions and 92 deletions

View file

@ -128,7 +128,7 @@
(keybinding/exwm "<XF86AudioMicMute>" #'pulse-audio/toggle-microphone) (keybinding/exwm "<XF86AudioMicMute>" #'pulse-audio/toggle-microphone)
(keybinding/exwm "C-M-c" #'chrome/browse) (keybinding/exwm "C-M-c" #'chrome/browse)
(keybinding/exwm (kbd/raw 'x11 "s") #'scrot/select) (keybinding/exwm (kbd/raw 'x11 "s") #'scrot/select)
(keybinding/exwm "<C-M-tab>" #'exwm/switch-to-exwm-buffer) (keybinding/exwm "<C-M-tab>" #'window-manager-switch-to-exwm-buffer)
(general-define-key (general-define-key
:keymaps 'override :keymaps 'override

View file

@ -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 <wpcarro@gmail.com> ;; Author: William Carroll <wpcarro@gmail.com>
;; Version: 0.0.1
;; URL: https://git.wpcarro.dev/wpcarro/briefcase
;; Package-Requires: ((emacs "25.1"))
;;; Commentary: ;;; Commentary:
;; I switched to EXWM from i3, and I haven't looked back. One day I may write a ;; I switched to EXWM from i3, and I haven't looked back. One day I may write a
@ -32,12 +36,6 @@
;; Library ;; 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 ;; TODO: Associate `window-purpose' window-layouts with each of these named
;; workspaces. ;; workspaces.
@ -58,37 +56,37 @@
;; TODO: Support MRU cache of workspaces for easily switching back-and-forth ;; TODO: Support MRU cache of workspaces for easily switching back-and-forth
;; between workspaces. ;; 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.") "When t, install the keybindings to switch between named-workspaces.")
;; TODO: Consume `cache/touch' after changing workspaces. Use this to enable ;; TODO: Consume `cache/touch' after changing workspaces. Use this to enable
;; cycling through workspaces. ;; cycling through workspaces.
(defconst exwm/named-workspaces (defconst window-manager--named-workspaces
(list (make-exwm/named-workspace (list (make-window-manager--named-workspace
:label "Web surfing" :label "Web surfing"
:kbd "c") :kbd "c")
(make-exwm/named-workspace (make-window-manager--named-workspace
:label "Briefcase" :label "Briefcase"
:kbd "d") :kbd "d")
(make-exwm/named-workspace (make-window-manager--named-workspace
:label "Todos" :label "Todos"
:kbd "o") :kbd "o")
(make-exwm/named-workspace (make-window-manager--named-workspace
:label "Chatter" :label "Chatter"
:kbd "h")) :kbd "h"))
"List of `exwm/named-workspace' structs.") "List of `window-manager--named-workspace' structs.")
;; Assert that no two workspaces share KBDs. ;; Assert that no two workspaces share KBDs.
(prelude/assert (= (list/length exwm/named-workspaces) (prelude/assert (= (list/length window-manager--named-workspaces)
(->> exwm/named-workspaces (->> window-manager--named-workspaces
(list/map #'exwm/named-workspace-kbd) (list/map #'window-manager--named-workspace-kbd)
set/from-list set/from-list
set/count))) set/count)))
(defun window-manager/alert (x) (defun window-manager--alert (x)
"Message X with a structured format." "Message X with a structured format."
(alert (string/concat "[exwm] " x))) (alert (string/concat "[exwm] " x)))
@ -108,7 +106,7 @@
(evil-set-initial-state 'exwm-mode 'emacs) (evil-set-initial-state 'exwm-mode 'emacs)
(setq exwm-workspace-number (setq exwm-workspace-number
(list/length exwm/named-workspaces)) (list/length window-manager--named-workspaces))
;; EXWM supports "line-mode" and "char-mode". ;; EXWM supports "line-mode" and "char-mode".
;; ;;
;; Note: It appears that calling `exwm-input-set-key' works if it's called ;; 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-:" :fn eval-expression)
(:key "M-SPC" :fn ivy-helpers/run-external-command) (:key "M-SPC" :fn ivy-helpers/run-external-command)
(:key "M-x" :fn counsel-M-x) (:key "M-x" :fn counsel-M-x)
(:key "<M-tab>" :fn exwm/next-workspace) (:key "<M-tab>" :fn window-manager-next-workspace)
(:key "<M-S-iso-lefttab>" :fn exwm/prev-workspace) (:key "<M-S-iso-lefttab>" :fn window-manager-prev-workspace)
(:key "<M-iso-lefttab>" :fn exwm/prev-workspace) (:key "<M-iso-lefttab>" :fn window-manager-prev-workspace)
(:key "C-M-\\" :fn ivy-pass) (:key "C-M-\\" :fn ivy-pass)
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Workspaces ;; Workspaces
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(:key ,(kbd/raw 'workspace "l") :fn window-manager/logout) (:key ,(kbd/raw 'workspace "l") :fn window-manager-logout)
(:key ,(kbd/raw 'workspace "i") :fn exwm/toggle-mode)))) (:key ,(kbd/raw 'workspace "i") :fn window-manager-toggle-mode))))
(setq exwm-input-global-keys (setq exwm-input-global-keys
(->> kbds (->> kbds
(-map (lambda (plist) (-map (lambda (plist)
@ -198,75 +196,61 @@
;; TODO: Package workspace management in another module. ;; TODO: Package workspace management in another module.
;; Here is the code required to allow EXWM to cycle workspaces. ;; Here is the code required to allow EXWM to cycle workspaces.
(defconst exwm/workspaces (defconst window-manager--workspaces
(->> exwm/named-workspaces (->> window-manager--named-workspaces
cycle/from-list) cycle/from-list)
"Cycle of the my EXWM workspaces.") "Cycle of the my EXWM workspaces.")
(prelude/assert (prelude/assert
(= exwm-workspace-number (= 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." "Cycle forwards to the next workspace."
(interactive) (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." "Cycle backwards to the previous workspace."
(interactive) (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. ;; TODO: Create friendlier API for working with EXWM.
;; Here is the code required to toggle EXWM's modes. ;; Here is the code required to toggle EXWM's modes.
(defun exwm/line-mode () (defun window-manager--line-mode ()
"Switch exwm to line-mode." "Switch exwm to line-mode."
(call-interactively #'exwm-input-grab-keyboard) (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." "Switch exwm to char-mode."
(call-interactively #'exwm-input-release-keyboard) (call-interactively #'exwm-input-release-keyboard)
(window-manager/alert "Switched to char-mode")) (window-manager--alert "Switched to char-mode"))
(defconst exwm/modes (defconst window-manager--modes
(cycle/from-list (list #'exwm/char-mode (cycle/from-list (list #'window-manager--char-mode
#'exwm/line-mode)) #'window-manager--line-mode))
"Functions to switch exwm modes.") "Functions to switch exwm modes.")
(defun exwm/toggle-mode () (defun window-manager-toggle-mode ()
"Switch between line- and char- mode." "Switch between line- and char- mode."
(interactive) (interactive)
(with-current-buffer (window-buffer) (with-current-buffer (window-buffer)
(when (eq major-mode 'exwm-mode) (when (eq major-mode 'exwm-mode)
(funcall (cycle/next exwm/modes))))) (funcall (cycle/next window-manager--modes)))))
;; Ensure exwm apps open in char-mode. ;; 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 ;; Interface to the Linux password manager
;; TODO: Consider writing a better client for this. ;; TODO: Consider writing a better client for this.
(use-package ivy-pass) (use-package ivy-pass)
;; TODO: How do I handle this dependency? ;; TODO: How do I handle this dependency?
(defconst exwm/preferred-browser "google-chrome" (defconst window-manager--preferred-browser "google-chrome"
"My preferred web browser.") "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 ;; TODO: Consider replacing the `ivy-read' call with something like `hydra' that
;; can provide a small mode for accepting user-input. ;; can provide a small mode for accepting user-input.
;; TODO: Put this somewhere more diliberate. ;; 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 ;; Maybe just create a ~/.xsecurelockrc
;; TODO: Is there a shell-command API that accepts an alist and serializes it ;; TODO: Is there a shell-command API that accepts an alist and serializes it
;; into variables to pass to the shell command? ;; into variables to pass to the shell command?
(defconst window-manager/xsecurelock (defconst window-manager--xsecurelock
"/usr/share/goobuntu-desktop-files/xsecurelock.sh" "/usr/share/goobuntu-desktop-files/xsecurelock.sh"
"Path to the proper xsecurelock executable. "Path to the proper xsecurelock executable.
The other path to xsecurelock is /usr/bin/xsecurelock, which works fine, but it 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 avoid this, prefer the goobuntu wrapper around xsecurelock when on a goobuntu
device. This all relates to PAM (i.e. pluggable authentication modules).") 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. "Prompt the user for options for logging out, shutting down, etc.
The following options are supported: The following options are supported:
@ -302,13 +286,13 @@ The following options are supported:
Ivy is used to capture the user's input." Ivy is used to capture the user's input."
(interactive) (interactive)
(let* ((name->cmd `(("Lock" . ,window-manager/xsecurelock) (let* ((name->cmd `(("Lock" . ,window-manager--xsecurelock)
("Logout" . "sudo systemctl stop lightdm") ("Logout" . "sudo systemctl stop lightdm")
("Suspend" . ,(string/concat ("Suspend" . ,(string/concat
window-manager/xsecurelock window-manager--xsecurelock
" && systemctl suspend")) " && systemctl suspend"))
("Hibernate" . ,(string/concat ("Hibernate" . ,(string/concat
window-manager/xsecurelock window-manager--xsecurelock
" && systemctl hibernate")) " && systemctl hibernate"))
("Reboot" . "systemctl reboot") ("Reboot" . "systemctl reboot")
("Shutdown" . "systemctl poweroff")))) ("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)) (alist/get (ivy-read "System: " (alist/keys name->cmd))
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." "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))))) (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. "Registers a keybinding for WORKSPACE struct.
Currently using super- as the prefix for switching workspaces." Currently using super- as the prefix for switching workspaces."
(let ((handler (lambda () (let ((handler (lambda ()
(interactive) (interactive)
(exwm/switch (exwm/named-workspace-label workspace)))) (window-manager--switch (window-manager--named-workspace-label workspace))))
(key (exwm/named-workspace-kbd workspace))) (key (window-manager--named-workspace-kbd workspace)))
(exwm-input-set-key (exwm-input-set-key
(kbd/for 'workspace key) (kbd/for 'workspace key)
handler))) handler)))
(defun exwm/change-workspace (workspace) (defun window-manager--change-workspace (workspace)
"Switch EXWM workspaces to the WORKSPACE struct." "Switch EXWM workspaces to the WORKSPACE struct."
(exwm-workspace-switch (exwm-workspace-switch
(exwm/label->index (exwm/named-workspace-label workspace) (window-manager--label->index (window-manager--named-workspace-label workspace)
exwm/named-workspaces)) window-manager--named-workspaces))
(window-manager/alert (window-manager--alert
(string/format "Switched to: %s" (exwm/named-workspace-label workspace)))) (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." "Switch to a named workspaces using LABEL."
(cycle/focus (lambda (x) (cycle/focus (lambda (x)
(equal label (equal label
(exwm/named-workspace-label x))) (window-manager--named-workspace-label x)))
exwm/workspaces) window-manager--workspaces)
(exwm/change-workspace (cycle/current exwm/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." "Focus the previously active EXWM workspace."
(interactive) (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." "Return t if buffer X is an EXWM buffer."
(equal 'exwm-mode (buffer-local-value 'major-mode x))) (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. "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)) (with-current-buffer buffer exwm-class-name))
;; TODO: Support disambiguating between two or more instances of the same ;; TODO: Support disambiguating between two or more instances of the same
;; application. For instance if two `exwm-class-name' values are ;; application. For instance if two `exwm-class-name' values are
;; "Google-chrome", find a encode this information in the `buffer-alist'. ;; "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." "Use `completing-read' to focus an EXWM buffer."
(interactive) (interactive)
(let* ((buffer-alist (->> (buffer-list) (let* ((buffer-alist (->> (buffer-list)
(-filter #'exwm/exwm-buffer?) (-filter #'window-manager--exwm-buffer?)
(-map (lambda (buffer) (-map (lambda (buffer)
(cons (exwm/application-name buffer) (cons (window-manager--application-name buffer)
buffer))))) buffer)))))
(label (completing-read "Switch to EXWM buffer: " buffer-alist))) (label (completing-read "Switch to EXWM buffer: " buffer-alist)))
(exwm-workspace-switch-to-buffer (exwm-workspace-switch-to-buffer
(alist-get label buffer-alist nil nil #'string=)))) (alist-get label buffer-alist nil nil #'string=))))
(when exwm/install-workspace-kbds? (when window-manager--install-kbds?
(progn (progn
(->> exwm/named-workspaces (->> window-manager--named-workspaces
(list/map #'exwm/register-kbd)) (list/map #'window-manager--register-kbd))
(window-manager/alert "Registered workspace KBDs!"))) (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) (provide 'window-manager)
;;; window-manager.el ends here ;;; window-manager.el ends here

View file

@ -216,6 +216,11 @@
(add-to-list 'project-find-functions #'wpc-misc--briefcase-find) (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 (use-package deadgrep
:config :config
(general-define-key (general-define-key