diff options
author | bd <bdunahu@operationnull.com> | 2024-10-27 21:11:19 -0400 |
---|---|---|
committer | bd <bdunahu@operationnull.com> | 2024-10-27 21:11:19 -0400 |
commit | 05791ee8b63f37513fb1eaf1dcef77de5227994d (patch) | |
tree | 90c2c3838945b91f7ce26821b1f3d0d5a83db12c /.config/emacs | |
parent | 70507e97d5a5523c2667638f09208d47fdbcf670 (diff) |
read desc: browsing+bookmarking interface, remove popper, no work...
browsing+bookmarking interface, remove popper, no workspaces only tabs, custom password-store, exwm use window title, colonq selector, theme changes
Diffstat (limited to '.config/emacs')
-rw-r--r-- | .config/emacs/gnus.el | 4 | ||||
-rw-r--r-- | .config/emacs/init.el | 2 | ||||
-rw-r--r-- | .config/emacs/libraries/selector.el | 654 | ||||
-rw-r--r-- | .config/emacs/modules/bd--browse.el | 58 | ||||
-rw-r--r-- | .config/emacs/modules/bd--essentials.el | 15 | ||||
-rw-r--r-- | .config/emacs/modules/bd--exwm-windowing.el | 92 | ||||
-rw-r--r-- | .config/emacs/modules/bd--files.el | 21 | ||||
-rw-r--r-- | .config/emacs/modules/bd--gpg.el | 73 | ||||
-rw-r--r-- | .config/emacs/modules/bd--minibuffer.el | 8 | ||||
-rw-r--r-- | .config/emacs/modules/bd--shells.el | 4 | ||||
-rw-r--r-- | .config/emacs/modules/bd--tabs.el | 3 | ||||
-rw-r--r-- | .config/emacs/modules/bd--themes.el | 11 | ||||
-rw-r--r-- | .config/emacs/modules/bd--windows.el | 42 |
13 files changed, 827 insertions, 160 deletions
diff --git a/.config/emacs/gnus.el b/.config/emacs/gnus.el index 986d0d0..2be2cf9 100644 --- a/.config/emacs/gnus.el +++ b/.config/emacs/gnus.el @@ -47,9 +47,7 @@ "%s\n")) (setopt message-from-style 'angles - mml-secure-openpgp-encrypt-to-self t) - -(require 'bd--mail) ;; (gitignored) + mml-secure-openpgp-encrypt-to-self t) ;;; gnus.el ends here diff --git a/.config/emacs/init.el b/.config/emacs/init.el index 20767cd..baae521 100644 --- a/.config/emacs/init.el +++ b/.config/emacs/init.el @@ -62,6 +62,7 @@ (require 'bd--essentials) (require 'bd--rss) (require 'bd--browse) +(require 'bd--gpg) (require 'bd--tabs) (require 'bd--files) (require 'bd--image) @@ -77,6 +78,7 @@ (require 'bd--modeline) (require 'bd--themes) (require 'bd--exwm-windowing) +(require 'bd--secret) ;; (gitignored) ;;; init.el ends here diff --git a/.config/emacs/libraries/selector.el b/.config/emacs/libraries/selector.el new file mode 100644 index 0000000..8b16637 --- /dev/null +++ b/.config/emacs/libraries/selector.el @@ -0,0 +1,654 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;; modified version of lcolonq: https://github.com/lcolonq/emacs +;;; Code: + + +(require 'dash) +(require 'recentf) + +(defgroup selector nil + "Efficient selection and navigation." + :group 'convenience) + +(defgroup selector-faces nil + "Faces for `selector'." + :group 'selector + :group 'faces) + +(defface selector-source-name + '((default :underline t :inherit bold) + (((class color) (background dark)) :foreground "white")) + "Face used to highlight source names.") + +(defface selector-highlight + '((t :inherit highlight)) + "Face used to highlight the current selection.") + +(defvar selector-minibuffer-lines 20 + "Number of lines to display in the minibuffer.") + +(defvar selector-exit-hook nil + "Hook run when exiting minibuffer selection.") + +(defvar selector--sources '()) +(defvar selector--last nil) +(defvar selector--matching '()) +(defvar selector--source 0) +(defvar selector--index 0) +(defvar selector--action nil) +(defvar selector--result nil) +(defvar selector--drawn-this-frame 0) + +(defvar selector-minibuffer-map (make-sparse-keymap)) +(define-key selector-minibuffer-map (kbd "\\") (lambda () (interactive) nil)) +(define-key selector-minibuffer-map (kbd "\\") (lambda () (interactive) nil)) +(define-key selector-minibuffer-map (kbd "C-g") 'selector-quit) +(define-key selector-minibuffer-map (kbd "C-c") 'selector-quit) +(define-key selector-minibuffer-map (kbd "<return>") 'selector-do) +(define-key selector-minibuffer-map (kbd "<backtab>") 'selector-previous) +(define-key selector-minibuffer-map (kbd "<tab>") 'selector-next) +(define-key selector-minibuffer-map (kbd "<up>") 'selector-previous) +(define-key selector-minibuffer-map (kbd "<down>") 'selector-next) +(define-key selector-minibuffer-map (kbd "<left>") 'selector-previous-source) +(define-key selector-minibuffer-map (kbd "<right>") 'selector-next-source) +(define-key selector-minibuffer-map (kbd "C-p") 'selector-previous) +(define-key selector-minibuffer-map (kbd "C-n") 'selector-next) +(define-key selector-minibuffer-map (kbd "C-b") 'selector-previous-source) +(define-key selector-minibuffer-map (kbd "C-f") 'selector-next-source) +(defun selector-minibuffer-line (str) + "Write STR to the minibuffer." + (goto-char (point-max)) + (insert (concat "\n" str))) + +(defun selector-minibuffer-line-face (str face) + "Write STR to the minibuffer in FACE." + (cl-incf selector--drawn-this-frame) ;; sort of an ugly hack, + ;; but this fixes the annoying "cursor jumping" glitch when multiple monitors + ;; are active. the real fix probably should live in selector-nearby? + (when (< selector--drawn-this-frame selector-minibuffer-lines) + (let ((before (point))) + (selector-minibuffer-line str) + (goto-char before) + (forward-line) + (put-text-property (line-beginning-position) (point-max) 'face face)))) + +(defun selector-minibuffer-clear () + "Clear minibuffer." + (save-excursion + (goto-char (minibuffer-prompt-end)) + (delete-region (line-end-position) (point-max)))) + +(defun selector-minibuffer-input () + "Get current minibuffer input." + (buffer-substring-no-properties + (minibuffer-prompt-end) + (line-end-position))) + +(cl-defstruct (selector-candidate (:constructor selector-candidate--create) + (:copier nil) + (:conc-name selector-candidate--)) + type (display nil :type string) face value action) + +(cl-defun selector-candidate-create + (display &key + value + (type 'normal) + (face 'default) + (action '())) + "Create a candidate. +DISPLAY is the string to display (using FACE) / match against. +VALUE is the value to pass to actions when the candidate is selected. +TYPE is either normal or dummy - dummy candidates always appear in the +results list regardless of the input pattern. +ACTION is an alist mapping keybindings to candidate-specific actions." + (selector-candidate--create + :type type + :display display + :face face + :value (if value value display) + :action action)) + +(defun selector-candidate-display (candidate) + "Return the display string for CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--display candidate)) + (t candidate))) + +(defun selector-candidate-value (candidate) + "Return the value of CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--value candidate)) + (t candidate))) + +(defun selector-candidate-type (candidate) + "Return the candidate type of CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--type candidate)) + (t 'normal))) + +(defun selector-candidate-face (candidate) + "Return the display face for CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--face candidate)) + (t 'default))) + +(defun selector-candidate-action (candidate) + "Return the actions for CANDIDATE." + (cond ((selector-candidate-p candidate) (selector-candidate--action candidate)) + (t '()))) + +(defun selector-candidate-display-string (candidate) + "Return the display of CANDIDATE as a string." + (let ((display (selector-candidate-display candidate))) + (cond ((stringp display) display) + (t (error "Invalid candidate display %s for candidate %s (of type %s)" + display candidate (type-of display)))))) + +(defun selector-highlight-candidate (candidate) + "Return a copy of CANDIDATE with the face set to selector-highlight." + (selector-candidate--create + :type (selector-candidate-type candidate) + :display (selector-candidate-display candidate) + :face 'selector-highlight + :value (selector-candidate-value candidate) + :action (selector-candidate-action candidate))) + +(defun selector-match (candidate regex) + "Determine whether CANDIDATE is a match for REGEX." + (let ((type (selector-candidate-type candidate))) + (cond ((eq 'dummy type) t) + (t (string-match-p regex (selector-candidate-display-string candidate)))))) + +(cl-defstruct (selector-source (:constructor selector-source--create) + (:copier nil)) + name candidates actions keymap) + +(defun selector-action-function (action) + "Return the function associated with ACTION." + (if (functionp action) + action + (cdr action))) + +(defun selector-actions-keymap (actions) + "Return a keymap for ACTIONS." + (let ((keymap (make-sparse-keymap))) + (set-keymap-parent keymap selector-minibuffer-map) + (mapc + (lambda (a) + (unless (functionp a) + (define-key keymap (car a) + (lambda () (interactive) + (selector-do (cdr a)))))) + actions) + keymap)) + +(cl-defun selector-source-create (name &key candidates (actions '())) + "Create a new source named NAME with the given CANDIDATES and ACTIONS. + +CANDIDATES is either: +- A list of candidates +- A function returning a list of candidates given a regex +ACTIONS is a list of actions, which can be: +- functions taking candidate values as arguments +- pairs of key strings and such functions" + (selector-source--create + :name name + :candidates + (if (functionp candidates) candidates + (--map (if (selector-candidate-p it) it (selector-candidate-create it)) + candidates)) + :actions actions + :keymap (selector-actions-keymap actions))) + +(defun selector-matching-candidates (candidates pattern) + "Return the candidates in CANDIDATES matching PATTERN." + (cond ((functionp candidates) (funcall candidates pattern)) + (t (let ((regex (selector-pattern-regex pattern))) + (--filter (selector-match it regex) candidates))))) + +(defun selector-filter-source (source pattern) + "Return a copy of SOURCE including only the candidates matching PATTERN." + (selector-source--create + :name (selector-source-name source) + :candidates (selector-matching-candidates (selector-source-candidates source) pattern) + :actions (selector-source-actions source) + :keymap (selector-source-keymap source))) + +(defun selector-pattern-regex (pattern) + "Convert PATTERN into a regular expression." + (apply #'string-join + (--map (concat "\\(" it "\\)") (split-string pattern)) + '(".*"))) + +(defun selector-matching-sources (sources pattern) + "Return the sources in SOURCES matching PATTERN." + (let* ((matches (--map (selector-filter-source it pattern) sources))) + (-filter #'selector-source-candidates matches))) + +(defun selector-display-source (source) + "Display SOURCE." + (when source + (selector-minibuffer-line-face (selector-source-name source) 'selector-source-name) + (--map (selector-minibuffer-line-face + (selector-candidate-display-string it) + (selector-candidate-face it)) + (selector-source-candidates source)))) + +(defun selector-nearby (sources) + "Filter SOURCES to only include candidates close to the selected candidate." + (let* ((adjacent + (--map + (cond ((and (< (cdr it) (+ selector--source selector-minibuffer-lines)) + (> (cdr it) selector--source)) + (cons (car it) 'g)) + ((= (cdr it) selector--source) + (cons (car it) 'e)) + (t nil)) + (-zip-pair sources (number-sequence 0 (length sources)))))) + (--map + (when it + (let* ((candidates (selector-source-candidates (car it)))) + (selector-source--create + :name (selector-source-name (car it)) + :candidates + (cond ((eq (cdr it) 'g) + (-take selector-minibuffer-lines candidates)) + (t + (cl-loop for i from (max (- selector--index + (- (/ selector-minibuffer-lines 2) 1)) + 0) + for j in (-take + selector-minibuffer-lines + (-drop + (- selector--index + (- (/ selector-minibuffer-lines 2) 1)) + candidates)) + collect (if (= i selector--index) + (selector-highlight-candidate j) + j)))) + :actions (selector-source-actions (car it)) + :keymap (selector-source-keymap (car it))))) + adjacent))) + +(defun selector-update-transient-map () + "Update the transient keymap to match the current source." + (let ((source (car (nthcdr selector--source selector--matching)))) + (when source + (set-transient-map (selector-source-keymap source))))) + +(defun selector-minibuffer-render () + "Draw matching candidates to minibuffer." + (setq selector--drawn-this-frame 0) + (save-excursion + (let ((pattern (selector-minibuffer-input))) + (unless (string= pattern selector--last) + (setq selector--last pattern + selector--index 0 + selector--source 0 + selector--matching (selector-matching-sources selector--sources pattern)))) + (-map #'selector-display-source (selector-nearby selector--matching)) + (goto-char (minibuffer-prompt-end)) + (put-text-property (line-end-position) (point-max) 'readonly t)) + (selector-update-transient-map)) + +(defun selector-minibuffer-setup (initial) + "Ready minibuffer for completion with INITIAL as initial input." + (add-hook 'pre-command-hook 'selector-minibuffer-clear nil t) + (add-hook 'post-command-hook 'selector-minibuffer-render nil t) + (setq-local max-mini-window-height selector-minibuffer-lines) + (when initial + (save-excursion + (minibuffer-prompt-end) + (insert initial))) + (end-of-line) + (selector-update-transient-map)) + +(defun selector-previous-source () + "Move to the previous source." + (interactive) + (setq selector--index 0) + (setq selector--source (if (= selector--source 0) + (- (length selector--matching) 1) + (- selector--source 1)))) + +(defun selector-next-source () + "Move to the next source." + (interactive) + (setq selector--index 0) + (setq selector--source (% (+ selector--source 1) (length selector--matching)))) + +(defun selector-previous () + "Move to the previous candidate." + (interactive) + (let* ((new-source-index (if (= selector--source 0) + (- (length selector--matching) 1) + (- selector--source 1))) + (source (car (nthcdr new-source-index selector--matching)))) + (setq selector--index (- selector--index 1)) + (when (< selector--index 0) + (setq selector--index (- (length (selector-source-candidates source)) 1) + selector--source new-source-index)))) + +(defun selector-next () + "Move to the next candidate." + (interactive) + (let* ((source (car (nthcdr selector--source selector--matching)))) + (setq selector--index (+ selector--index 1)) + (when (= selector--index (length (selector-source-candidates source))) + (setq selector--index 0 + selector--source (% (+ selector--source 1) (length selector--matching)))))) + +(defun selector-quit () + "Quit the selection interface without running an action." + (interactive) + (run-hooks 'selector-exit-hook) + (keyboard-escape-quit)) + +(defun selector-do (&optional action-function) + "Act upon selected candidate. +If ACTION-FUNCTION is given use it, otherwise use the first action for the candidate." + (interactive) + (if (null selector--matching) + (progn + (setq selector--action (lambda (x) x) + selector--result nil)) + (progn + (let* ((source (car (nthcdr selector--source selector--matching))) + (candidate (car (nthcdr selector--index (selector-source-candidates source))))) + (setq selector--action (cond (action-function + action-function) + ((selector-candidate-action candidate) + (selector-candidate-action candidate)) + (t + (let ((actions (selector-source-actions source))) + (if actions + (selector-action-function (car actions)) + (lambda (x) x))))) + selector--result (selector-candidate-value candidate))))) + (run-hooks 'selector-exit-hook) + (exit-minibuffer)) + +;;;###autoload +(cl-defun selector (sources &key prompt initial) + "Select a candidate and run an action using SOURCES. +Display PROMPT as the prompt, or \"pattern: \" if not given. +Use INITIAL as the initial input." + (setq selector--sources sources + selector--last nil + selector--matching (selector-matching-sources sources "") + selector--source 0 + selector--index 0 + selector--action nil + selector--result nil) + (let ((inhibit-message t)) + (minibuffer-with-setup-hook + (apply-partially 'selector-minibuffer-setup initial) + (read-from-minibuffer (or prompt "pattern: ") nil selector-minibuffer-map))) + (funcall selector--action selector--result)) + +(defvar selector-completing-read-candidate-transformer (lambda (x) x)) + +;;;###autoload +(defun selector-completing-read (prompt collection &optional predicate require-match + initial-input hist def inherit-input-method) + "Replacement for `completing-read'. +PROMPT, COLLECTION, PREDICATE, REQUIRE-MATCH, INITIAL-INPUT, HIST, DEF, and +INHERIT-INPUT-METHOD have the same meaning as in `completing-read'." + (ignore predicate hist def inherit-input-method) + (let ((unspecified-source + (if require-match + '() + (list + (selector-source-create + "Other" + :candidates + (list (selector-candidate-create + "Specify" + :type 'dummy + :action (lambda (_) (selector-input))))))))) + (or + (cond ((functionp collection) + (selector + (cons + (selector-source-create + "Completions" + :candidates + (-non-nil + (--map + (when-let ((disp (funcall selector-completing-read-candidate-transformer it))) + (selector-candidate-create disp :value it)) + (funcall collection "" nil t)))) + unspecified-source) + :prompt prompt + :initial initial-input)) + ((hash-table-p collection) + (selector + (cons + (selector-source-create + "Completions" + :candidates (hash-table-keys collection)) + unspecified-source) + :prompt prompt + :initial initial-input)) + ((obarrayp collection) + (let ((candidates (list))) + (mapatoms (lambda (x) (push (selector-candidate-create (symbol-name x)) candidates)) collection) + (selector + (cons (selector-source-create "Completions" :candidates candidates) unspecified-source) + :prompt prompt + :initial initial-input))) + (t (selector + (cons (selector-source-create + "Completions" + :candidates + (--map (if (consp it) + (selector-candidate-create (car it)) + it) + collection)) + unspecified-source) + :prompt prompt + :initial initial-input))) + (selector-input)))) + +(defun selector-input () "Return last minibuffer input." selector--last) + +(defvar selector-extended-command-actions + (list (lambda (c) + (add-to-list 'extended-command-history c) + (command-execute (intern-soft c))) + (cons (kbd "C-h") (lambda (c) (describe-function (intern-soft c)))))) + +;;;###autoload +(defun selector-extended-commands-source () + "Source for extended commands (`M-x')." + (selector-source-create + "Commands" + :candidates + (-map + #'selector-candidate-create + (all-completions "" obarray #'commandp)) + :actions + selector-extended-command-actions)) + +;;;###autoload +(defun selector-extended-command-history-source () + "Source for extended command history." + (selector-source-create + "Command History" + :candidates + (-map + #'selector-candidate-create + extended-command-history) + :actions + selector-extended-command-actions)) + +;;;###autoload +(defun selector-apropos-command-source () + "Source for command lookup." + (selector-source-create + "Commands" + :candidates + (lambda (r) (-map #'selector-candidate-create (all-completions r obarray #'commandp))) + :actions + (list (lambda (c) (describe-function (intern-soft c)))))) + +;;;###autoload +(defun selector-apropos-function-source () + "Source for function lookup." + (selector-source-create + "Functions" + :candidates + (lambda (r) (-map #'selector-candidate-create (all-completions r obarray #'fboundp))) + :actions + (list (lambda (c) (describe-function (intern-soft c)))))) + +;;;###autoload +(defun selector-apropos-variable-source () + "Source for variable lookup." + (selector-source-create + "Variables" + :candidates + (lambda (r) (-map #'selector-candidate-create + (all-completions + r obarray + (lambda (x) (let ((sym (intern-soft x))) + (and (boundp sym) (not (keywordp sym)))))))) + :actions + (list (lambda (c) (describe-variable (intern-soft c)))))) + +(defvar selector-buffer-actions + (list 'switch-to-buffer + (cons (kbd "M-D") 'kill-buffer))) + +;;;###autoload +(defun selector-buffers-source (&optional sort-pred) + "Source for open buffers. +An optional SORT-PRED may be provided to sort the buffers (see `sort')." + (selector-source-create + "Buffers" + :candidates + (--map (selector-candidate-create (buffer-name it)) + (if sort-pred (sort (buffer-list) sort-pred) (buffer-list))) + :actions + selector-buffer-actions)) + +;;;###autoload +(defun selector-create-buffer-source () + "Dummy source to create a buffer." + (selector-source-create + "Other" + :candidates + (list (selector-candidate-create + "Create buffer" + :type 'dummy + :action (lambda (_) (switch-to-buffer (selector-input))))))) + +(defvar selector-file-actions + (list 'find-file + (cons (kbd "M-D") (lambda (f) + (when (y-or-n-p (concat "Delete file " f "? ")) + (delete-file f)))))) + +;;;###autoload +(defun selector-files-source () + "Source for files in current directory." + (selector-source-create + "Files" + :candidates + (-map #'selector-candidate-create (directory-files default-directory)) + :actions + selector-file-actions)) + +;;;###autoload +(defun selector-create-file-source () + "Dummy source to create a file." + (selector-source-create + "Other" + :candidates + (list (selector-candidate-create + "Create file" + :type 'dummy + :action (lambda (_) (find-file (selector-input))))))) + +;;;###autoload +(defun selector-recentf-source () + "Source for recentf." + (selector-source-create + "Recent Files" + :candidates + (-map #'selector-candidate-create recentf-list) + :actions + selector-file-actions)) + +;;;###autoload +(defun selector-M-x () + "Preconfigured `selector' interface to replace `execute-external-command'." + (interactive) + (selector (list (selector-extended-command-history-source) + (selector-extended-commands-source)))) + +;;;###autoload +(defun selector-apropos (&optional initial) + "Preconfigured `selector' interface to replace `apropos'. +INITIAL is the initial text to match." + (interactive) + (selector (list (selector-apropos-command-source) + (selector-apropos-function-source) + (selector-apropos-variable-source)) + :initial (if initial initial (thing-at-point 'symbol t)))) + +;;;###autoload +(defun selector-for-buffers () + "Preconfigured `selector' interface for open buffers and recentf." + (interactive) + (selector (list (selector-buffers-source) + (selector-recentf-source) + (selector-create-buffer-source)))) + +;;;###autoload +(defun selector-for-files () + "Preconfigured `selector' interface for files in the current directory." + (interactive) + (selector (list (selector-files-source) + (selector-create-file-source)))) + +;;;###autoload +(defun selector-read-file-name (prompt &optional dir default-filename mustmatch initial predicate) + "Replacement for `read-file-name'. +PROMPT, DIR, DEFAULT-FILENAME, MUSTMATCH, INITIAL and PREDICATE have the same +meaning as in `read-file-name'." + (ignore default-filename mustmatch predicate) + (let ((d (if dir dir default-directory))) + (concat d (selector (list (selector-source-create + "Files" + :candidates (-map #'selector-candidate-create (directory-files d))) + (selector-source-create + "Other" + :candidates (list (selector-candidate-create + "New file" + :type 'dummy + :action (lambda (_) (selector-input)))))) + :prompt prompt + :initial initial)))) + +(defun selector-file-contents-actions (file) + "Actions for candidate values corresponding to lines in FILE." + (list + (lambda (index) + (find-file file) + (goto-char (point-min)) + (forward-line index) + (pulse-momentary-highlight-one-line (point))))) + +(defun selector-file-contents-source (file) + "Source for lines in FILE." + (selector-source-create + file + :candidates + (-map-indexed + (lambda (index l) + (selector-candidate-create l :value index)) + (split-string (f-read-text file) "\n")) + :actions + (selector-file-contents-actions file))) + + +(provide 'selector) +;;; selector ends here diff --git a/.config/emacs/modules/bd--browse.el b/.config/emacs/modules/bd--browse.el index 1dd5b4a..83bf0a2 100644 --- a/.config/emacs/modules/bd--browse.el +++ b/.config/emacs/modules/bd--browse.el @@ -2,10 +2,60 @@ ;;; Commentary: ;;; Code: +(require 'selector) +(require 'dash) -;; do not use an external browser -(setopt browse-url-browser-function 'eww-browse-url - shr-use-fonts t +(defvar bd/bookmarks nil) ;; in secret file +;;;; searching +(defun bd/browse (url &optional pref &rest _) + "Given PREF, launches URL in one of librewolf, torbrowser, +icecat, or eww." + (interactive) + (pcase pref + (0 (eww url)) + (1 (start-process "icecat" nil "icecat" "--new-window" url)) + (2 (start-process "torbrowser" nil "torbrowser" "--new-window" url)) + (_ (start-process "librewolf" nil "librewolf" "--new-window" url)))) +(setopt browse-url-browser-function 'bd/browse) + +(defun bd/selector-bookmarks () + (selector-source-create + "Bookmarks" + :candidates + (-map + (lambda (b) (selector-candidate-create (car b) :value (cdr b))) + bd/bookmarks) + :actions + (list (lambda (x) (apply #'bd/browse x))))) + +(defmacro bd/search-candidate (name url pref) + `(selector-candidate-create + ,(concat "Search " name) + :type 'dummy + :action (lambda (_) (browse-url (concat ,url (selector-input)) ,pref)))) + +(defun bd/selector-search () + (selector-source-create + "Browser" + :candidates + (list (bd/search-candidate "DuckDuckGo" "https://www.duckduckgo.com/?q=" 3) + (bd/search-candidate "Wikipedia" "https://en.wikipedia.org/w/index.php?search=" 3) + (bd/search-candidate "Invidious" "https://yewtu.be/search?q=" 0) + (bd/search-candidate "Urban Dictionary" "https://www.urbandictionary.com/define.php?term=" 1) + (bd/search-candidate "Archwiki" "https://wiki.archlinux.org/index.php?title=Special%3ASearch&search=" 1) + (bd/search-candidate "Web" "" 3)))) + +(defun bd/visit-bookmark () + "Select and `browse-url' a bookmark." + (interactive) + (unwind-protect + (selector + (list (bd/selector-bookmarks) + (bd/selector-search))))) + + +;;;; eww +(setopt shr-use-fonts t shr-cookie-policy nil shr-max-width 85 ;; send only user agent @@ -16,7 +66,7 @@ "youtube.com" "youtu.be")) browse-url-handlers - `((,(regexp-opt'("youtube.com" "youtu.be")) . + `((,(regexp-opt '("youtube.com" "youtu.be")) . (lambda (url &rest _) (message "Ludu %s" url) (start-process-shell-command "rip-video" nil (concat "rip-video " url)))))) diff --git a/.config/emacs/modules/bd--essentials.el b/.config/emacs/modules/bd--essentials.el index 04fc3a2..e8ea502 100644 --- a/.config/emacs/modules/bd--essentials.el +++ b/.config/emacs/modules/bd--essentials.el @@ -30,21 +30,6 @@ (advice-add command :after #'pulse-line)) -;;;; insecure passwording -(use-package pinentry - :config - (pinentry-start) - :custom - (pinentry-popup-prompt-window nil)) - -(defun pinentry-toggle () - "Stops and starts Pinentry service. Workaround -for a bug I've encountered." - (interactive) - (pinentry-stop) - (pinentry-start)) - - ;;;; defaults ;; basic editing (setopt kill-whole-line t diff --git a/.config/emacs/modules/bd--exwm-windowing.el b/.config/emacs/modules/bd--exwm-windowing.el index 1dc5056..ab5b243 100644 --- a/.config/emacs/modules/bd--exwm-windowing.el +++ b/.config/emacs/modules/bd--exwm-windowing.el @@ -19,68 +19,20 @@ (desktop-environment-volume-increment-slowly "+2%") (desktop-environment-volume-toggle-regexp nil)) - -(defun bd/exwm-update-class () - "Changes the buffer name to reflect the class name for -that buffer." - (exwm-workspace-rename-buffer exwm-class-name)) - -(defun bd/exwm-init-hook () - "Make workspace 1 the default startup workspace." - (exwm-workspace-switch-create 1)) - - -;;;; bookmarks, passwords -(defun insert-bookmark () - "Inserts a url or string from permanent -bookmark file. If an x window, place in kill-ring." - ;; note xdotool had issues with repeated keys when sending to windowid - (interactive) - (let ((url (car (last (split-string (choose-line-from-file "~/.local/bin/bookmarks.txt")))))) - (if (exwm--buffer->id (current-buffer)) - (kill-new url) - (insert url)))) - -(defun choose-line-from-file (file) - "Uses completion-framework to allow user to -select a line from a file." - (let* ((choices (read-file-into-list file))) - (completing-read "Recall: " choices))) - -(defun read-file-into-list (file) - (with-current-buffer - (find-file-noselect file) - (split-string - (save-restriction - (widen) - (buffer-substring-no-properties - (point-min) - (point-max))) - "\n" t))) - -(use-package password-store - :custom - (password-store-time-before-clipboard-restore 20)) - (use-package exwm :config - (add-hook 'exwm-init-hook #'bd/exwm-init-hook) - (add-hook 'exwm-update-class-hook #'bd/exwm-update-class) - ;; order is important - ;; (dolist (k '(("s-B" "icecat"))) - ;; (let ((f (lambda () (interactive) - ;; (save-window-excursion - ;; (start-process-shell-command (cadr k) nil (cadr k)))))) - ;; (exwm-input-set-key (kbd (car k)) f) - ;; (define-key exwm-mode-map (kbd (car k)) f))) + (defun bd/exwm-update-title () + "Changes the buffer name to reflect the class name for +that buffer." + (exwm-workspace-rename-buffer exwm-title)) + (add-hook 'exwm-update-title-hook #'bd/exwm-update-title) (define-key exwm-mode-map [?\C-q] 'exwm-input-send-next-key) (exwm-enable) (server-start) :custom - (exwm-workspace-number 2) ;; two workspaces (exwm-input-prefix-keys - '(?\C-x + `(?\C-x ?\C-u ?\C-g ?\C-h @@ -90,9 +42,11 @@ select a line from a file." ?\M-` ?\M-& ?\M-: - )) + ,@(mapcar (lambda (i) + (kbd (concat "s-" (number-to-string i)))) + (number-sequence 0 9)))) (exwm-input-global-keys - `(([?\s-n] . other-window) + '(([?\s-n] . other-window) ([?\s-p] . (lambda () (interactive) (other-window -1))) @@ -107,20 +61,14 @@ select a line from a file." ([f10] . emms-next) ([print] . desktop-environment-screenshot-part) ([S-print] . desktop-environment-screenshot) - ([?\s-O] . insert-bookmark) - ([?\s-P] . password-store-copy) + ([?\s-O] . bd/visit-bookmark) + ([?\s-P] . bd/password) ([?\s-r] . exwm-reset) ([?\s-d] . toggle-current-window-dedication) ([?\s-q] . kill-current-buffer) ([?\s-x] . (lambda (command) (interactive (list (read-shell-command "s-x "))) - (start-process-shell-command command nil command))) - ,@(mapcar (lambda (i) - `(,(kbd (format "s-%d" i)) . - (lambda () - (interactive) - (exwm-workspace-switch-create ,i)))) - (number-sequence 0 9)))) + (start-process-shell-command command nil command))))) (exwm-input-simulation-keys '(([?\C-b] . [left]) ([?\C-f] . [right]) @@ -133,10 +81,12 @@ select a line from a file." ([?\C-d] . [delete]) ([?\C-k] . [S-end delete]) ([?\M-w] . [C-c]) - ([?\C-y] . [C-v]))) + ([?\C-y] . [C-v]) + ([?\M-d] . [C-delete]) + ([?\M-b] . [C-left]) + ([?\M-f] . [C-right])))) - (exwm-workspace-show-all-buffers t) - (exwm-layout-show-all-buffers t)) +(setopt tab-bar-select-tab-modifiers '(super)) (defvar new-mode-line nil) (defun set-new-mode-line () @@ -145,9 +95,9 @@ select a line from a file." (replace-regexp-in-string "%" "%%" (format " %s %s %s" - (shell-command-to-string "mail-string") - (shell-command-to-string "power-string") - (shell-command-to-string "t1-string"))))) + (shell-command-to-string "/home/bdunahu/.local/bin/mail-string 2>/dev/null") + (shell-command-to-string "/home/bdunahu/.local/bin/power-string 2>/dev/null") + (shell-command-to-string "/home/bdunahu/.local/bin/t1-string 2>/dev/null"))))) (defvar-local bd/external-mode-line '(:eval (when new-mode-line diff --git a/.config/emacs/modules/bd--files.el b/.config/emacs/modules/bd--files.el index b8a5f4a..6ea121b 100644 --- a/.config/emacs/modules/bd--files.el +++ b/.config/emacs/modules/bd--files.el @@ -3,14 +3,15 @@ ;;; Code: +(require 'recentf) (defmacro bd/defun-find-file-wrapper (name types open-f) `(defun ,name (f &rest args) "Wrapper around F (find-file), passing ARGS." (if (string-match (regexp-opt ,types) (or (file-name-extension (car args)) "")) - (progn - (,(eval open-f) (car args)) - (recentf-add-file (car args)) - nil) + (progn + (,(eval open-f) (car args)) + (recentf-add-file (car args)) + nil) (apply f args)))) ;;;; dired @@ -39,8 +40,8 @@ (start-process (concat "zathura (" (file-name-base file) ")") nil "zathura" (expand-file-name file))) (bd/defun-find-file-wrapper bd/pdf-find-file-wrapper - '("epub" "pdf") - #'bd/zathura) + '("epub" "pdf") + #'bd/zathura) (advice-add 'find-file :around #'bd/pdf-find-file-wrapper) ;; video @@ -50,8 +51,8 @@ (bd/defun-find-file-wrapper bd/video-find-file-wrapper - '("mkv" "mov" "mp4" "webm" "m4v" "wav" "mp3" "opus" "ogv" "flac") - #'bd/mpv) + '("mkv" "mov" "mp4" "webm" "m4v" "wav" "mp3" "opus" "ogv" "flac") + #'bd/mpv) (advice-add 'find-file :around 'bd/video-find-file-wrapper) ;; image @@ -59,8 +60,8 @@ "Open FILE with nsxiv" (start-process (concat "nsxiv (" (file-name-base file) ")") nil "nsxiv" (expand-file-name file))) (bd/defun-find-file-wrapper bd/image-find-file-wrapper - '("jpg" "jpeg" "png" "webp" "bmp" "ico" "gif" "JPG" "PNG") - #'bd/nsxiv) + '("jpg" "jpeg" "png" "webp" "bmp" "ico" "gif" "JPG" "PNG") + #'bd/nsxiv) (advice-add 'find-file :around 'bd/image-find-file-wrapper) diff --git a/.config/emacs/modules/bd--gpg.el b/.config/emacs/modules/bd--gpg.el new file mode 100644 index 0000000..f3d55cb --- /dev/null +++ b/.config/emacs/modules/bd--gpg.el @@ -0,0 +1,73 @@ +;;; -*- lexical-binding: t; -*- +;;; Commentary: +;;; Code: + + +(require 'f) + +(defvar bd/password-store-kill-ring-pointer nil + "The tail of the kill ring whose car is the password.") +(defvar bd/password-store-time-before-clear 10 + "The time before a killed password is cleared.") + +;;;; passwords +(defun bd/password-store-list () + "List password-store entries." + (mapcar (lambda (file) + (f-no-ext (f-relative file "~/.password-store/"))) + (f-files "~/.password-store" (lambda (file) (equal (f-ext file) "gpg")) t))) + +(defun bd/password-store-clear (id) + "Clears the most recent password copied to the kill ring." + (when bd/password-store-kill-ring-pointer + (setcar bd/password-store-kill-ring-pointer nil) + (kill-new "") + (setq bd/password-store-kill-ring-pointer nil) + (message "Cleared password for %s from the kill ring and system clipboard." id))) + +(defun bd/read-password (id) + "Read the password-store entry corresponding to ID." + (bd/password-store-clear "id") + (let ((find-file-hook (remq 'recentf-track-opened-file find-file-hook))) + (find-file (concat "~/.password-store/" id ".gpg")) + (goto-char 1) + (kill-new (buffer-substring-no-properties (line-beginning-position) (line-end-position))) + (setq bd/password-store-kill-ring-pointer kill-ring-yank-pointer) + (kill-buffer (current-buffer)) + (run-at-time bd/password-store-time-before-clear nil + (lambda () (funcall #'bd/password-store-clear id))) + (message "Copied password for %s to the kill ring and system clipboard. Will clear in %s seconds." + id bd/password-store-time-before-clear))) + +(defun bd/selector-passwords () + "Selector source for password-store passwords." + (selector-source-create + "Passwords" + :candidates + (bd/password-store-list) + :actions + (list #'bd/read-password))) + +(defun bd/password () + "Interactively select a password-store password." + (interactive) + (selector (list (bd/selector-passwords)))) + +;; pinentry +(use-package pinentry + :config + (pinentry-start) + :custom + (enable-recursive-minibuffers t) + (pinentry-popup-prompt-window nil)) + +(defun pinentry-toggle () + "Stops and starts Pinentry service. Workaround +for a bug I've encountered." + (interactive) + (pinentry-stop) + (pinentry-start)) + + +(provide 'bd--gpg) +;;; bd-gpg ends here diff --git a/.config/emacs/modules/bd--minibuffer.el b/.config/emacs/modules/bd--minibuffer.el index 66dffa5..02451bb 100644 --- a/.config/emacs/modules/bd--minibuffer.el +++ b/.config/emacs/modules/bd--minibuffer.el @@ -6,13 +6,9 @@ (setopt use-short-answers t vc-follow-symlinks t completion-ignore-case t - read-buffer-completion-ignore-case t - ;; required for exwm (pass) but - ;; always useful - enable-recursive-minibuffers t) + read-buffer-completion-ignore-case t) (minibuffer-depth-indicate-mode 1) - (use-package vertico :init (vertico-mode) @@ -43,7 +39,7 @@ ("H-s G" . consult-git-grep) ("H-s r" . consult-ripgrep) ("H-s l" . consult-line) - ("H-s i" . consult-info) + ("H-s i" . consult-info) ("H-s L" . consult-line-multi) ("H-s k" . consult-keep-lines) ("H-s u" . consult-focus-lines))) diff --git a/.config/emacs/modules/bd--shells.el b/.config/emacs/modules/bd--shells.el index dbb2f25..0bc41e2 100644 --- a/.config/emacs/modules/bd--shells.el +++ b/.config/emacs/modules/bd--shells.el @@ -44,6 +44,10 @@ clear the scrollback contents. Outputs banner message." (unless eshell-non-interactive-p (eval eshell-banner-message))))) +(defun eshell/open (file) + (interactive) + (find-file file)) + ;;;; shell (require 'shell) diff --git a/.config/emacs/modules/bd--tabs.el b/.config/emacs/modules/bd--tabs.el index 3ef18d8..f8ceab1 100644 --- a/.config/emacs/modules/bd--tabs.el +++ b/.config/emacs/modules/bd--tabs.el @@ -32,8 +32,7 @@ tab-bar-auto-width-max nil) ;;;; add useless text elements -(setopt tab-bar-tab-hints nil - tab-bar-select-tab-modifiers '(meta)) +(setopt tab-bar-tab-hints nil) (defun bd/tab-bar-name-function () (concat (tab-bar-tab-name-current) diff --git a/.config/emacs/modules/bd--themes.el b/.config/emacs/modules/bd--themes.el index 9f7f404..220b181 100644 --- a/.config/emacs/modules/bd--themes.el +++ b/.config/emacs/modules/bd--themes.el @@ -48,21 +48,18 @@ to.") (ef-themes-to-toggle '(ef-autumn ef-frost)) (ef-themes-common-palette-overrides - '((bg-mode-line bg-main) - (fg-mode-line fg-main) - (bg-dim bg-main) + '((bg-dim bg-main) (bg-alt bg-main) (bg-tab-bar bg-main) - (bg-tab-current bg-main) + (bg-tab-current bg-mode-line) (bg-tab-other bg-inactive))) - (ef-winter-palette-overrides - '((bg-main "#000000"))) (ef-bio-palette-overrides '((bg-main "#000000"))) (ef-autumn-palette-overrides '((bg-main "#000000")))) -(load-theme 'ef-autumn :no-confirm) +(load-theme 'ef-winter :no-confirm) + (provide 'bd--themes) ;;; bd-themes ends here diff --git a/.config/emacs/modules/bd--windows.el b/.config/emacs/modules/bd--windows.el index 5a338bf..282ca14 100644 --- a/.config/emacs/modules/bd--windows.el +++ b/.config/emacs/modules/bd--windows.el @@ -52,48 +52,6 @@ Due to a bug with guix-packaged emacs, only uses true-transparency on wayland." (add-to-list 'default-frame-alist '(alpha . (82 . 82)))) -(require 'project) -;;;; popper -(use-package popper - :demand t - :bind (("C-`" . 'popper-toggle-latest) - ("M-`" . 'popper-cycle) - ("C-M-`" . popper-toggle-type)) - :config - (popper-mode) - (popper-echo-mode) - :custom - (popper-reference-buffers - '( - ;; native - ("\\*Async Shell Command\\*.*" . hide) - compilation-mode - completion-list-mode - messages-buffer-mode - occur-mode - ("Output\\*$" . hide) - ;; info - help-mode - Info-mode - "^\\*slime-description.*\\*$" - ;; repls - geiser-repl-mode - slime-repl-mode - ;; shells - "^\\*eshell.*\\*$" eshell-mode - "^\\*shell.*\\*$" shell-mode - "^\\*term.*\\*$" term-mode - ;; magit - magit-diff-mode - magit-status-mode - ;; emms - emms-playlist-mode - )) - (popper-display-control 'nil) - (popper-mode-line nil) - (popper-group-function #'popper-group-by-project)) - - ;;;; shackle (use-package shackle :demand t |