mirror of
https://github.com/pestctrl/emacs-config.git
synced 2026-02-16 08:14:15 +00:00
Reorder exwm configurations
This commit is contained in:
parent
57e4d88bf7
commit
97eda7e458
13 changed files with 485 additions and 402 deletions
|
|
@ -30,5 +30,28 @@
|
|||
(make-thread
|
||||
#'dmenu--cache-executable-files))
|
||||
|
||||
(dmenu-refresh-applist)
|
||||
|
||||
(add-to-list 'vertico-multiform-commands
|
||||
'(exwmx-launch-program flat (vertico-cycle . t)))
|
||||
|
||||
(defun read-program ()
|
||||
(completing-read
|
||||
"$ "
|
||||
(append dmenu--history-list
|
||||
(cl-remove-if (lambda (x)
|
||||
(member x dmenu--history-list))
|
||||
dmenu--cache-executable-files))))
|
||||
|
||||
(defun exwmx-launch-program (command &optional process-name)
|
||||
(interactive (list (read-program)))
|
||||
(setq dmenu--history-list (cons command (remove command dmenu--history-list)))
|
||||
(when (> (length dmenu--history-list)
|
||||
dmenu-history-size)
|
||||
(setcdr (nthcdr (- dmenu-history-size 1)
|
||||
dmenu--history-list)
|
||||
nil))
|
||||
(my/exwmx-quickrun command))
|
||||
|
||||
(provide 'exwm-launch-program)
|
||||
;;; exwm-launch-program.el ends here
|
||||
|
|
@ -25,8 +25,10 @@
|
|||
;;; Code:
|
||||
(use-package exwm-x)
|
||||
(use-package hydra)
|
||||
(require 'my-exwmx-quickrun-2)
|
||||
(require 'exwmx-appconfig)
|
||||
(require 'my-exwmx-quickrun-2)
|
||||
(require 'exwmx-firefox)
|
||||
(require 'exwm-launch-program)
|
||||
|
||||
(defun lock-screen ()
|
||||
(interactive)
|
||||
|
|
@ -106,9 +108,10 @@
|
|||
(or tag command)))))
|
||||
`(defun ,name-gensym ()
|
||||
(interactive)
|
||||
(if (zerop (length (exwmx-find-buffers '(:class "firefox"))))
|
||||
(exwmx/launch-firefox-windows)
|
||||
(my/exwmx-quickrun ,command nil '(:pretty-name ,tag))))))
|
||||
(if (not (zerop (length (exwmx-find-buffers '(:class "firefox")))))
|
||||
(my/exwmx-quickrun ,command nil '(:pretty-name ,tag))
|
||||
(exwmx-notify-x-window (exwmx-appconfig--search '((:pretty-name ,tag))))
|
||||
(exwmx/launch-firefox-windows)))))
|
||||
|
||||
(define-key *firefox-map* (kbd "c") (quickrun-lambda "google-chrome-stable" "chrome"))
|
||||
(define-key *firefox-map* (kbd "f") (quickrun-firefox "firefox" "firefox"))
|
||||
137
lisp/exwm-lib/exwm-tagging/exwmx-firefox.el
Normal file
137
lisp/exwm-lib/exwm-tagging/exwmx-firefox.el
Normal file
|
|
@ -0,0 +1,137 @@
|
|||
;;; exwmx-firefox.el --- -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2023 Benson Chu
|
||||
|
||||
;; Author: Benson Chu <bensonchu457@gmail.com>
|
||||
;; Created: [2023-09-01 14:47]
|
||||
|
||||
;; This file is not part of GNU Emacs
|
||||
|
||||
;; This program is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
(require 'exwmx-appconfig-predicates)
|
||||
(require 'my-exwmx-quickrun-2)
|
||||
|
||||
(add-to-list 'exwmx/disable-my-management
|
||||
#'exwmx/add-firefox-buffers)
|
||||
|
||||
(defvar exwmx/firefox-buffers nil)
|
||||
(defvar exwmx/buffer-name-timer nil)
|
||||
|
||||
(setq exwm-input--update-focus-interval 0.1)
|
||||
|
||||
(defun exwmx/launch-firefox-windows ()
|
||||
(interactive)
|
||||
(unless (zerop (length (exwmx-find-buffers '(:class "firefox"))))
|
||||
(user-error "Firefox already launched"))
|
||||
(add-hook 'exwm-manage-finish-hook #'exwmx/add-firefox-buffers)
|
||||
(my/exwmx-quickrun "firefox" nil nil t))
|
||||
|
||||
(defun exwmx/add-firefox-buffers ()
|
||||
(push (current-buffer) exwmx/firefox-buffers)
|
||||
(when (timerp exwmx/buffer-name-timer)
|
||||
(cancel-timer exwmx/buffer-name-timer))
|
||||
(setq exwmx/buffer-name-timer
|
||||
(run-at-time 4 nil #'exwmx/rename-firefox-windows)))
|
||||
|
||||
;; (setq exwm-manage-finish-hook
|
||||
;; (delq #'exwmx/add-firefox-buffers exwm-manage-finish-hook))
|
||||
|
||||
(defun display-buffers-split-vertically (lob)
|
||||
(delete-other-windows)
|
||||
(let ((last (car (last lob))))
|
||||
(dolist (b lob)
|
||||
(display-buffer-same-window b nil)
|
||||
(unless (eq b last)
|
||||
(select-window (split-window-vertically)))))
|
||||
(balance-windows))
|
||||
|
||||
;; (defun exwmx/rename-firefox-windows ()
|
||||
;; (interactive)
|
||||
;; (cl-labels ((rename (buffer name)
|
||||
;; (with-current-buffer buffer
|
||||
;; (exwm-workspace-rename-buffer name)
|
||||
;; (setq-local exwmx-pretty-name name))))
|
||||
;; (let ((buffers
|
||||
;; (remove-if-not
|
||||
;; #'(lambda (buffer)
|
||||
;; (with-current-buffer buffer
|
||||
;; (and (eq 'exwm-mode major-mode)
|
||||
;; (string-match-p "firefox" exwm-class-name))))
|
||||
;; (buffer-list)))
|
||||
;; yt others)
|
||||
;; (while buffers
|
||||
;; (let ((buffer (pop buffers)))
|
||||
;; (with-current-buffer buffer
|
||||
;; (cond ((string-match-p "youtube" (downcase exwm-title))
|
||||
;; (setq yt buffer))
|
||||
;; (t (push buffer others))))))
|
||||
;; (when yt
|
||||
;; (rename yt "youtube"))
|
||||
;; (dotimes (i (length others))
|
||||
;; (let ((buffer (nth i others)))
|
||||
;; (rename buffer
|
||||
;; (if (eq 0 i)
|
||||
;; "firefox"
|
||||
;; (concat "firefox" (number-to-string i)))))))))
|
||||
|
||||
(defun exwmx/rename-firefox-windows ()
|
||||
(unwind-protect
|
||||
(let ((appconfigs (exwmx-appconfig--search-all '((:class "firefox"))))
|
||||
(buffers exwmx/firefox-buffers))
|
||||
(when-let ((b (exwmx-find-buffer '((:title "YouTube" string-match-p)) t)))
|
||||
(when (member b buffers)
|
||||
(exwmx-name-buffer "youtube" b )
|
||||
(setq buffers
|
||||
(delete b buffers))
|
||||
(setq appconfigs
|
||||
(remove-if #'(lambda (x)
|
||||
(string= "youtube" (plist-get x :pretty-name)))
|
||||
appconfigs))))
|
||||
(if (= 1 (length buffers))
|
||||
(exwmx-name-buffer "firefox" (car buffers))
|
||||
(save-window-excursion
|
||||
(delete-other-windows)
|
||||
(let ((last (car (last buffers))))
|
||||
(display-buffers-split-vertically buffers)
|
||||
(dolist (b buffers)
|
||||
(let ((win (get-buffer-window b)))
|
||||
(select-window win)
|
||||
(-->
|
||||
(funcall-interactively #'exwmx-name-buffer nil b appconfigs)
|
||||
(setq appconfigs
|
||||
(remove-if #'(lambda (x)
|
||||
(string= it
|
||||
(plist-get x :pretty-name)))
|
||||
appconfigs)))
|
||||
(unless (eq b last)
|
||||
(delete-window win)))))))
|
||||
(when-let ((res
|
||||
(-some
|
||||
(lambda (buffer)
|
||||
(let ((candidates (exwmx-appconfig-candidates buffer)))
|
||||
(cl-assert (= 1 (length candidates)))
|
||||
(when-let ((window (gethash (car candidates)
|
||||
exwmx/destination-windows)))
|
||||
(cons buffer window))))
|
||||
exwmx/firefox-buffers)))
|
||||
(window--display-buffer (car res) (cdr res) 'reuse nil)))
|
||||
(remove-hook 'exwm-manage-finish-hook #'exwmx/add-firefox-buffers)
|
||||
(setq exwmx/firefox-buffers nil)))
|
||||
|
||||
(provide 'exwmx-firefox)
|
||||
;;; exwmx-firefox.el ends here
|
||||
150
lisp/exwm-lib/exwm-tagging/my-exwmx-quickrun-2.el
Normal file
150
lisp/exwm-lib/exwm-tagging/my-exwmx-quickrun-2.el
Normal file
|
|
@ -0,0 +1,150 @@
|
|||
;;; my-exwmx-quickrun-2.el --- -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2023 Benson Chu
|
||||
|
||||
;; Author: Benson Chu <bensonchu457@gmail.com>
|
||||
;; Created: [2023-08-31 14:21]
|
||||
|
||||
;; This file is not part of GNU Emacs
|
||||
|
||||
;; This program is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; TODO: add buffer name to appconfig
|
||||
|
||||
;; (add-hook 'exwm-update-class-hook #'exwmx-grocery--rename-exwm-buffer)
|
||||
;; (add-hook 'exwm-update-title-hook #'exwmx-grocery--rename-exwm-buffer)
|
||||
|
||||
;; Manage `exwm-manage-finish-hook'
|
||||
;; (add-hook 'exwm-manage-finish-hook #'exwmx-grocery--manage-finish-function)
|
||||
|
||||
(require 'exwmx-appconfig-predicates)
|
||||
|
||||
(defun my/exwmx-quickrun (command &optional search-alias ruler no-manage)
|
||||
"Run `command' to launch an application, if application's window is found,
|
||||
just switch to this window, when `search-alias' is t, `command' will be regard
|
||||
as an appconfig alias and search it from `exwmx-appconfig-file', by default,
|
||||
:class and :instance is used to search application, user can override
|
||||
it by argument `ruler', ruler can be a plist with keys: :class, :instance
|
||||
and :title or just a key list."
|
||||
(cl-assert (or (not ruler) (exwmx--plist-p ruler)))
|
||||
(let* ((keys
|
||||
;; Deal with ruler which is like (:class :instance :title)
|
||||
(or (and ruler (exwmx--clean-keylist ruler))
|
||||
'(:class :instance :pretty-name :pretty-name)))
|
||||
(name (plist-get ruler :pretty-name))
|
||||
(appconfigs (exwmx-appconfig--get-all-appconfigs))
|
||||
(matched-appconfig (exwmx-appconfig--search
|
||||
(if search-alias
|
||||
(cons `(:alias ,command)
|
||||
(and name `((:pretty-name ,name))))
|
||||
(cons `(:command ,command)
|
||||
(and name `((:pretty-name ,name)))))))
|
||||
(cmd (if (not search-alias)
|
||||
command
|
||||
(or (plist-get matched-appconfig :command)
|
||||
(when appconfigs
|
||||
(let ((appconfig (exwmx-appconfig--select-appconfig)))
|
||||
(plist-put appconfig :alias command)
|
||||
(exwmx-appconfig--add-appconfig appconfig)
|
||||
(plist-get appconfig :command))))))
|
||||
(buffer (exwmx-find-buffer
|
||||
(or ruler
|
||||
(exwmx-appconfig--get-subset matched-appconfig keys)))))
|
||||
(if (and search-alias (not cmd))
|
||||
(message "EXWM-X: please run `exwmx-appconfig' to add appconfig.")
|
||||
(message "EXWM-X Quick Run: %s" cmd))
|
||||
;; If current application window is a floating-window, minumize it.
|
||||
(when (and (eq major-mode 'exwm-mode)
|
||||
exwm--floating-frame)
|
||||
(exwm-floating-hide))
|
||||
(if buffer
|
||||
(let ((exwm-layout-show-all-buffers nil))
|
||||
(exwm-workspace-switch-to-buffer buffer))
|
||||
(when cmd
|
||||
(when (not no-manage)
|
||||
(exwmx-notify-x-window matched-appconfig))
|
||||
(exwmx-shell-command cmd)))))
|
||||
|
||||
(defmacro quickrun-lambda (cmd name)
|
||||
(let ((name-gensym (intern (format "quickrun-%s"
|
||||
(or name cmd)))))
|
||||
`(defun ,name-gensym ()
|
||||
(interactive)
|
||||
(my/exwmx-quickrun ,cmd nil '(:pretty-name ,name)))))
|
||||
|
||||
(defmacro exec (body)
|
||||
`#'(lambda ()
|
||||
(interactive)
|
||||
,body))
|
||||
|
||||
;;------------------------------------------------------------------;;
|
||||
(defvar exwmx/destination-windows (make-hash-table :test #'equal))
|
||||
|
||||
(defun exwmx-select-window ()
|
||||
(if (= 1 (length (window-list)))
|
||||
(selected-window)
|
||||
(let ((index (switch-window--prompt "Run command in window: ")))
|
||||
(cl-loop for c from 1
|
||||
for win in (switch-window--list)
|
||||
until (= c index)
|
||||
finally return win))))
|
||||
|
||||
(defun exwmx-notify-x-window (appconfig)
|
||||
(puthash appconfig (exwmx-select-window) exwmx/destination-windows))
|
||||
|
||||
(defvar exwmx/disable-my-management nil)
|
||||
|
||||
(defun exwmx-manage-x-window ()
|
||||
(unless (-any
|
||||
(lambda (it)
|
||||
(member it exwm-manage-finish-hook))
|
||||
exwmx/disable-my-management)
|
||||
(if-let* ((appconfigs (exwmx-appconfig-candidates))
|
||||
(matched-config
|
||||
(-any (lambda (c) (and (gethash c exwmx/destination-windows)
|
||||
c))
|
||||
appconfigs))
|
||||
(name (plist-get matched-config :pretty-name))
|
||||
(window (gethash matched-config exwmx/destination-windows)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(exwm-workspace-rename-buffer name)
|
||||
(when (and (window-live-p window)
|
||||
(not (eq window (selected-window))))
|
||||
(let ((curr (current-buffer)))
|
||||
(save-selected-window
|
||||
(previous-buffer)
|
||||
(window--display-buffer curr window 'reuse nil)))))
|
||||
(setq-local exwmx-pretty-name name)
|
||||
(remhash matched-config exwmx/destination-windows))
|
||||
(exwm-workspace-rename-buffer
|
||||
(or exwm-class-name exwm-instance-name exwm-title)))))
|
||||
|
||||
(add-hook 'exwm-manage-finish-hook 'exwmx-manage-x-window)
|
||||
|
||||
;;------------------------------------------------------------------;;
|
||||
;; (let ((debug/appconfig (exwmx-appconfig--search `((:command "pcmanfm"))))
|
||||
;; (debug/buffer (get-buffer "*EXWM*")))
|
||||
;; (cl-assert (exwmx-buffer-match-p debug/appconfig debug/buffer))
|
||||
;; (cl-assert (exwmx-buffer-match-p '(:class "Pcmanfm") debug/buffer))
|
||||
;; (cl-assert (exwmx-buffer-match-p '(:instance "pcmanfm") debug/buffer))
|
||||
;; (cl-assert (exwmx-find-buffer debug/appconfig))
|
||||
;; (cl-assert (eq debug/buffer (exwmx-find-buffer debug/appconfig))))
|
||||
|
||||
(provide 'my-exwmx-quickrun-2)
|
||||
;;; my-exwmx-quickrun-2.el ends here
|
||||
168
lisp/exwm-lib/exwmx-appconfig-predicates.el
Normal file
168
lisp/exwm-lib/exwmx-appconfig-predicates.el
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
;;; exwmx-appconfig-predicates.el --- -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2023 Benson Chu
|
||||
|
||||
;; Author: Benson Chu <bensonchu457@gmail.com>
|
||||
;; Created: [2023-09-01 13:53]
|
||||
|
||||
;; This file is not part of GNU Emacs
|
||||
|
||||
;; This program is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
(require 'exwmx-appconfig)
|
||||
|
||||
(defun my/exwmx-appconfig ()
|
||||
"EXWM-X's application configure tool, which will pop to a buffer.
|
||||
and insert an appconfig template to let user edit. then user can
|
||||
use `exwmx-appconfig-file' to save the appconfig to `exwmx-appconfig-file'
|
||||
or use `exwmx-appconfig-ignore' ignore."
|
||||
(interactive)
|
||||
(if (not (derived-mode-p 'exwm-mode))
|
||||
(message "EXWM-X: Current window is not a window of application.")
|
||||
(unless (file-readable-p exwmx-appconfig-file)
|
||||
(append-to-file "" nil exwmx-appconfig-file))
|
||||
(let* ((buffer (get-buffer-create exwmx-appconfig-buffer))
|
||||
(hash (md5 (concat exwm-class-name exwm-instance-name (or exwmx-pretty-name ""))))
|
||||
(history (exwmx-appconfig--search
|
||||
`((:key ,hash))))
|
||||
(appconfig (list :command exwm-instance-name
|
||||
:alias exwm-instance-name
|
||||
:pretty-name exwmx-pretty-name
|
||||
:paste-key exwmx-sendstring-default-paste-key
|
||||
:class exwm-class-name
|
||||
:instance exwm-instance-name
|
||||
:title exwm-title
|
||||
:floating nil
|
||||
:size-and-position 'default
|
||||
:workspace 'current-workspace
|
||||
:add-prefix-keys nil
|
||||
:remove-prefix-keys nil
|
||||
:ignore-simulation-keys nil
|
||||
:eval nil)))
|
||||
(while history
|
||||
(let ((prop (pop history))
|
||||
(value (pop history)))
|
||||
(when (keywordp prop)
|
||||
(plist-put appconfig prop value))))
|
||||
(plist-put appconfig :key hash)
|
||||
(with-current-buffer buffer
|
||||
(text-mode)
|
||||
(exwmx-appconfig-mode)
|
||||
(setq truncate-lines t)
|
||||
(erase-buffer)
|
||||
(exwmx-appconfig--insert-plist appconfig)
|
||||
(goto-char (point-min))
|
||||
(setq header-line-format
|
||||
(substitute-command-keys
|
||||
(concat
|
||||
"\\<exwmx-appconfig-mode-map>"
|
||||
"Appconfig: "
|
||||
"Finish with `\\[exwmx-appconfig-finish]', "
|
||||
"Ignore with `\\[exwmx-appconfig-ignore]'. "))))
|
||||
(pop-to-buffer buffer))))
|
||||
|
||||
(advice-add #'exwmx-appconfig
|
||||
:override
|
||||
#'my/exwmx-appconfig)
|
||||
|
||||
;;------------------------------------------------------------------;;
|
||||
(defun exwm-buffer-extract-prop (buffer prop)
|
||||
(with-current-buffer buffer
|
||||
(pcase prop
|
||||
(:class exwm-class-name)
|
||||
(:instance exwm-instance-name)
|
||||
(:title exwm-title)
|
||||
(:pretty-name exwmx-pretty-name))))
|
||||
|
||||
(defun exwmx-buffer-match-p (appconfig buffer)
|
||||
(cl-assert
|
||||
(eq 'exwm-mode
|
||||
(with-current-buffer buffer
|
||||
major-mode)))
|
||||
(cl-assert
|
||||
(plistp appconfig))
|
||||
(exwmx-buffer-match-alist
|
||||
(let ((configs appconfig)
|
||||
result)
|
||||
(while configs
|
||||
(push (list (pop configs) (pop configs))
|
||||
result))
|
||||
(reverse result))
|
||||
buffer))
|
||||
|
||||
(defun exwmx-buffer-match-alist (alist buffer)
|
||||
(cl-assert
|
||||
(eq 'exwm-mode
|
||||
(with-current-buffer buffer
|
||||
major-mode)))
|
||||
(with-current-buffer buffer
|
||||
(-every
|
||||
(lambda (rule)
|
||||
(let* ((key (nth 0 rule))
|
||||
(search-string (nth 1 rule))
|
||||
(test-function (or (nth 2 rule) #'equal))
|
||||
(prop-value (exwm-buffer-extract-prop buffer key)))
|
||||
(and (functionp test-function)
|
||||
(funcall test-function search-string prop-value))))
|
||||
alist)))
|
||||
|
||||
(defun exwmx-find-buffers (appconfig &optional alist)
|
||||
(let (result)
|
||||
(dolist (buffer (buffer-list))
|
||||
(when (and (eq 'exwm-mode (with-current-buffer buffer
|
||||
major-mode))
|
||||
(if alist
|
||||
(exwmx-buffer-match-alist appconfig buffer)
|
||||
(exwmx-buffer-match-p appconfig buffer)))
|
||||
(push buffer result)))
|
||||
(reverse result)))
|
||||
|
||||
(defun exwmx-find-buffer (appconfig &optional alist)
|
||||
(let ((current (current-buffer))
|
||||
(result (exwmx-find-buffers appconfig alist)))
|
||||
;; If two more buffers are found, switch between these buffer.
|
||||
(if (and (cadr result)
|
||||
(eq (car result) current))
|
||||
(cadr result)
|
||||
(car result))))
|
||||
|
||||
(defun exwmx-appconfig--search-all (search-ruler-alist)
|
||||
(let ((appconfigs (exwmx-appconfig--get-all-appconfigs))
|
||||
appconfig-matched)
|
||||
(while appconfigs
|
||||
(let ((appconfig (pop appconfigs)))
|
||||
(when (-all?
|
||||
(lambda (rule)
|
||||
(let* ((key (nth 0 rule))
|
||||
(search-string (nth 1 rule))
|
||||
(test-function (or (nth 2 rule) #'equal))
|
||||
(prop-value (plist-get appconfig key)))
|
||||
(and (functionp test-function)
|
||||
(funcall test-function search-string prop-value)) ))
|
||||
search-ruler-alist)
|
||||
(push appconfig appconfig-matched))))
|
||||
appconfig-matched))
|
||||
|
||||
(defun exwmx-appconfig-candidates (&optional buffer)
|
||||
(with-current-buffer (or buffer (current-buffer))
|
||||
(exwmx-appconfig--search-all
|
||||
(cons `(:class ,exwm-class-name)
|
||||
(and exwmx-pretty-name
|
||||
`((:pretty-name ,exwmx-pretty-name)))))))
|
||||
|
||||
(provide 'exwmx-appconfig-predicates)
|
||||
;;; exwmx-appconfig-predicates.el ends here
|
||||
|
|
@ -1,398 +0,0 @@
|
|||
;;; my-exwmx-quickrun-2.el --- -*- lexical-binding: t -*-
|
||||
|
||||
;; Copyright (C) 2023 Benson Chu
|
||||
|
||||
;; Author: Benson Chu <bensonchu457@gmail.com>
|
||||
;; Created: [2023-08-31 14:21]
|
||||
|
||||
;; This file is not part of GNU Emacs
|
||||
|
||||
;; This program is free software: you can redistribute it and/or modify
|
||||
;; it under the terms of the GNU General Public License as published by
|
||||
;; the Free Software Foundation, either version 3 of the License, or
|
||||
;; (at your option) any later version.
|
||||
|
||||
;; This program is distributed in the hope that it will be useful,
|
||||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
;; GNU General Public License for more details.
|
||||
|
||||
;; You should have received a copy of the GNU General Public License
|
||||
;; along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
;;; Commentary:
|
||||
|
||||
;;; Code:
|
||||
|
||||
;; TODO: add buffer name to appconfig
|
||||
|
||||
;; (add-hook 'exwm-update-class-hook #'exwmx-grocery--rename-exwm-buffer)
|
||||
;; (add-hook 'exwm-update-title-hook #'exwmx-grocery--rename-exwm-buffer)
|
||||
|
||||
;; Manage `exwm-manage-finish-hook'
|
||||
;; (add-hook 'exwm-manage-finish-hook #'exwmx-grocery--manage-finish-function)
|
||||
|
||||
(defun exwmx-appconfig ()
|
||||
"EXWM-X's application configure tool, which will pop to a buffer.
|
||||
and insert an appconfig template to let user edit. then user can
|
||||
use `exwmx-appconfig-file' to save the appconfig to `exwmx-appconfig-file'
|
||||
or use `exwmx-appconfig-ignore' ignore."
|
||||
(interactive)
|
||||
(if (not (derived-mode-p 'exwm-mode))
|
||||
(message "EXWM-X: Current window is not a window of application.")
|
||||
(unless (file-readable-p exwmx-appconfig-file)
|
||||
(append-to-file "" nil exwmx-appconfig-file))
|
||||
(let* ((buffer (get-buffer-create exwmx-appconfig-buffer))
|
||||
(hash (md5 (concat exwm-class-name exwm-instance-name (or exwmx-pretty-name ""))))
|
||||
(history (exwmx-appconfig--search
|
||||
`((:key ,hash))))
|
||||
(appconfig (list :command exwm-instance-name
|
||||
:alias exwm-instance-name
|
||||
:pretty-name exwmx-pretty-name
|
||||
:paste-key exwmx-sendstring-default-paste-key
|
||||
:class exwm-class-name
|
||||
:instance exwm-instance-name
|
||||
:title exwm-title
|
||||
:floating nil
|
||||
:size-and-position 'default
|
||||
:workspace 'current-workspace
|
||||
:add-prefix-keys nil
|
||||
:remove-prefix-keys nil
|
||||
:ignore-simulation-keys nil
|
||||
:eval nil)))
|
||||
(while history
|
||||
(let ((prop (pop history))
|
||||
(value (pop history)))
|
||||
(when (keywordp prop)
|
||||
(plist-put appconfig prop value))))
|
||||
(plist-put appconfig :key hash)
|
||||
(with-current-buffer buffer
|
||||
(text-mode)
|
||||
(exwmx-appconfig-mode)
|
||||
(setq truncate-lines t)
|
||||
(erase-buffer)
|
||||
(exwmx-appconfig--insert-plist appconfig)
|
||||
(goto-char (point-min))
|
||||
(setq header-line-format
|
||||
(substitute-command-keys
|
||||
(concat
|
||||
"\\<exwmx-appconfig-mode-map>"
|
||||
"Appconfig: "
|
||||
"Finish with `\\[exwmx-appconfig-finish]', "
|
||||
"Ignore with `\\[exwmx-appconfig-ignore]'. "))))
|
||||
(pop-to-buffer buffer))))
|
||||
|
||||
(defun exwmx-buffer-match-p (appconfig buffer)
|
||||
(cl-assert
|
||||
(eq 'exwm-mode
|
||||
(with-current-buffer buffer
|
||||
major-mode)))
|
||||
(cl-assert
|
||||
(plistp appconfig))
|
||||
(let ((class (plist-get appconfig :class))
|
||||
(instance (plist-get appconfig :instance))
|
||||
(title (plist-get appconfig :title))
|
||||
(pretty (plist-get appconfig :pretty-name)))
|
||||
(with-current-buffer buffer
|
||||
(and
|
||||
(or class instance title pretty)
|
||||
(or (not class) (exwmx--string-match-p class exwm-class-name))
|
||||
(or (not instance) (exwmx--string-match-p instance exwm-instance-name))
|
||||
(or (not title) (exwmx--string-match-p instance exwm-title))
|
||||
(or (not pretty) (exwmx--string-match-p (format "^%s$" pretty) exwmx-pretty-name))))))
|
||||
|
||||
(defun exwmx-buffer-match-alist (alist buffer)
|
||||
(cl-assert
|
||||
(eq 'exwm-mode
|
||||
(with-current-buffer buffer
|
||||
major-mode)))
|
||||
(with-current-buffer buffer
|
||||
(-every
|
||||
(lambda (rule)
|
||||
(let* ((key (nth 0 rule))
|
||||
(search-string (nth 1 rule))
|
||||
(test-function (or (nth 2 rule) #'equal))
|
||||
(prop-value
|
||||
(pcase key
|
||||
(:class exwm-class-name)
|
||||
(:instance exwm-instance-name)
|
||||
(:title exwm-title)
|
||||
(:pretty-name exwmx-pretty-name))))
|
||||
(and (functionp test-function)
|
||||
(funcall test-function search-string prop-value))))
|
||||
alist)))
|
||||
|
||||
(defun exwmx-find-buffer (appconfig &optional alist)
|
||||
(let ((current (current-buffer))
|
||||
(buffers (buffer-list))
|
||||
(result '()))
|
||||
(while buffers
|
||||
(let ((buffer (pop buffers)))
|
||||
(when (and (eq 'exwm-mode (with-current-buffer buffer
|
||||
major-mode))
|
||||
(if alist
|
||||
(exwmx-buffer-match-alist appconfig buffer)
|
||||
(exwmx-buffer-match-p appconfig buffer)))
|
||||
(push buffer result))))
|
||||
(setq result (reverse result))
|
||||
;; If two more buffers are found, switch between these buffer.
|
||||
(if (and (cadr result)
|
||||
(eq (car result) current))
|
||||
(cadr result)
|
||||
(car result))))
|
||||
|
||||
(defun exwmx-find-buffers (appconfig &optional alist)
|
||||
(let ((current (current-buffer))
|
||||
(buffers (buffer-list))
|
||||
(result '()))
|
||||
(while buffers
|
||||
(let ((buffer (pop buffers)))
|
||||
(when (and (eq 'exwm-mode (with-current-buffer buffer
|
||||
major-mode))
|
||||
(if alist
|
||||
(exwmx-buffer-match-alist appconfig buffer)
|
||||
(exwmx-buffer-match-p appconfig buffer)))
|
||||
(push buffer result))))
|
||||
(reverse result)))
|
||||
|
||||
(defun exwmx-select-window ()
|
||||
(if (= 1 (length (window-list)))
|
||||
(selected-window)
|
||||
(let ((index (switch-window--prompt "Run command in window: ")))
|
||||
(cl-loop for c from 1
|
||||
for win in (switch-window--list)
|
||||
until (= c index)
|
||||
finally return win))))
|
||||
|
||||
(defun my/exwmx-quickrun (command &optional search-alias ruler no-manage)
|
||||
"Run `command' to launch an application, if application's window is found,
|
||||
just switch to this window, when `search-alias' is t, `command' will be regard
|
||||
as an appconfig alias and search it from `exwmx-appconfig-file', by default,
|
||||
:class and :instance is used to search application, user can override
|
||||
it by argument `ruler', ruler can be a plist with keys: :class, :instance
|
||||
and :title or just a key list."
|
||||
(cl-assert (or (not ruler) (exwmx--plist-p ruler)))
|
||||
(let* ((keys
|
||||
;; Deal with ruler which is like (:class :instance :title)
|
||||
(or (and ruler (exwmx--clean-keylist ruler))
|
||||
'(:class :instance :pretty-name :pretty-name)))
|
||||
(name (plist-get ruler :pretty-name))
|
||||
(appconfigs (exwmx-appconfig--get-all-appconfigs))
|
||||
(matched-appconfig (exwmx-appconfig--search
|
||||
(if search-alias
|
||||
(cons `(:alias ,command)
|
||||
(and name `((:pretty-name ,name))))
|
||||
(cons `(:command ,command)
|
||||
(and name `((:pretty-name ,name)))))))
|
||||
(cmd (if (not search-alias)
|
||||
command
|
||||
(or (plist-get matched-appconfig :command)
|
||||
(when appconfigs
|
||||
(let ((appconfig (exwmx-appconfig--select-appconfig)))
|
||||
(plist-put appconfig :alias command)
|
||||
(exwmx-appconfig--add-appconfig appconfig)
|
||||
(plist-get appconfig :command))))))
|
||||
(buffer (exwmx-find-buffer
|
||||
(or ruler
|
||||
(exwmx-appconfig--get-subset matched-appconfig keys)))))
|
||||
(if (and search-alias (not cmd))
|
||||
(message "EXWM-X: please run `exwmx-appconfig' to add appconfig.")
|
||||
(message "EXWM-X Quick Run: %s" cmd))
|
||||
;; If current application window is a floating-window, minumize it.
|
||||
(when (and (eq major-mode 'exwm-mode)
|
||||
exwm--floating-frame)
|
||||
(exwm-floating-hide))
|
||||
(if buffer
|
||||
(let ((exwm-layout-show-all-buffers nil))
|
||||
(exwm-workspace-switch-to-buffer buffer))
|
||||
(when cmd
|
||||
(when (not no-manage)
|
||||
(exwmx-register-x-window
|
||||
matched-appconfig (exwmx-select-window)))
|
||||
(exwmx-shell-command cmd)))))
|
||||
|
||||
(defmacro quickrun-lambda (cmd name)
|
||||
(let ((name-gensym (intern (format "quickrun-%s"
|
||||
(or name cmd)))))
|
||||
`(defun ,name-gensym ()
|
||||
(interactive)
|
||||
(my/exwmx-quickrun ,cmd nil '(:pretty-name ,name)))))
|
||||
|
||||
(add-to-list 'vertico-multiform-commands
|
||||
'(exwmx-launch-program flat (vertico-cycle . t)))
|
||||
|
||||
(defun read-program ()
|
||||
(completing-read
|
||||
"$ "
|
||||
(append dmenu--history-list
|
||||
(cl-remove-if (lambda (x)
|
||||
(member x dmenu--history-list))
|
||||
dmenu--cache-executable-files))))
|
||||
|
||||
(defun exwmx-launch-program (command &optional process-name)
|
||||
(interactive (list (read-program)))
|
||||
(setq dmenu--history-list (cons command (remove command dmenu--history-list)))
|
||||
(when (> (length dmenu--history-list)
|
||||
dmenu-history-size)
|
||||
(setcdr (nthcdr (- dmenu-history-size 1)
|
||||
dmenu--history-list)
|
||||
nil))
|
||||
(my/exwmx-quickrun command))
|
||||
|
||||
(defmacro exec (body)
|
||||
`#'(lambda ()
|
||||
(interactive)
|
||||
,body))
|
||||
|
||||
(defun exwmx/rename-firefox-windows ()
|
||||
(interactive)
|
||||
(cl-labels ((rename (buffer name)
|
||||
(with-current-buffer buffer
|
||||
(exwm-workspace-rename-buffer name)
|
||||
(setq-local exwmx-pretty-name name))))
|
||||
(let ((buffers
|
||||
(remove-if-not
|
||||
#'(lambda (buffer)
|
||||
(with-current-buffer buffer
|
||||
(and (eq 'exwm-mode major-mode)
|
||||
(string-match-p "firefox" exwm-class-name))))
|
||||
(buffer-list)))
|
||||
yt others)
|
||||
(while buffers
|
||||
(let ((buffer (pop buffers)))
|
||||
(with-current-buffer buffer
|
||||
(cond ((string-match-p "youtube" (downcase exwm-title))
|
||||
(setq yt buffer))
|
||||
(t (push buffer others))))))
|
||||
(when yt
|
||||
(rename yt "youtube"))
|
||||
(dotimes (i (length others))
|
||||
(let ((buffer (nth i others)))
|
||||
(rename buffer
|
||||
(if (eq 0 i)
|
||||
"firefox"
|
||||
(concat "firefox" (number-to-string i)))))))))
|
||||
|
||||
;;------------------------------------------------------------------;;
|
||||
(defvar exwmx/destination-windows (make-hash-table :test #'equal))
|
||||
|
||||
(defun exwmx-register-x-window (appconfig window)
|
||||
(puthash appconfig window exwmx/destination-windows))
|
||||
|
||||
(defun exwmx-appconfig--search-all (search-ruler-alist)
|
||||
(let ((appconfigs (exwmx-appconfig--get-all-appconfigs))
|
||||
appconfig-matched)
|
||||
(while appconfigs
|
||||
(let ((appconfig (pop appconfigs)))
|
||||
(dolist (rule search-ruler-alist)
|
||||
(let* ((key (nth 0 rule))
|
||||
(search-string (nth 1 rule))
|
||||
(test-function (or (nth 2 rule) #'equal))
|
||||
(prop-value (plist-get appconfig key)))
|
||||
(when (and (functionp test-function)
|
||||
(funcall test-function search-string prop-value))
|
||||
(push appconfig appconfig-matched))))))
|
||||
appconfig-matched))
|
||||
|
||||
(defun exwmx-appconfig-candidates ()
|
||||
(exwmx-appconfig--search-all
|
||||
`((:class ,exwm-class-name))))
|
||||
|
||||
(defun exwmx-manage-x-window ()
|
||||
(when (not (member #'exwmx/add-firefox-buffers exwm-manage-finish-hook))
|
||||
(if-let* ((appconfigs (exwmx-appconfig-candidates))
|
||||
(matched-config
|
||||
(-any (lambda (c) (and (gethash c exwmx/destination-windows)
|
||||
c))
|
||||
appconfigs))
|
||||
(name (plist-get matched-config :pretty-name))
|
||||
(window (gethash matched-config exwmx/destination-windows)))
|
||||
(unwind-protect
|
||||
(progn
|
||||
(exwm-workspace-rename-buffer name)
|
||||
(when (and (window-live-p window)
|
||||
(not (eq window (selected-window))))
|
||||
(let ((curr (current-buffer)))
|
||||
(save-selected-window
|
||||
(previous-buffer)
|
||||
(window--display-buffer curr window 'reuse nil)))))
|
||||
(setq-local exwmx-pretty-name name)
|
||||
(remhash matched-config exwmx/destination-windows))
|
||||
(exwm-workspace-rename-buffer
|
||||
(or exwm-class-name exwm-instance-name exwm-title)))))
|
||||
|
||||
(defvar exwmx/firefox-buffers nil)
|
||||
(defvar exwmx/buffer-name-timer nil)
|
||||
|
||||
(defun exwmx/launch-firefox-windows ()
|
||||
(interactive)
|
||||
(unless (zerop (length (exwmx-find-buffers '(:class "firefox"))))
|
||||
(user-error "Firefox already launched"))
|
||||
(add-hook 'exwm-manage-finish-hook #'exwmx/add-firefox-buffers)
|
||||
(my/exwmx-quickrun "firefox" nil nil t))
|
||||
|
||||
(defun exwmx/add-firefox-buffers ()
|
||||
(push (current-buffer) exwmx/firefox-buffers)
|
||||
(when (timerp exwmx/buffer-name-timer)
|
||||
(cancel-timer exwmx/buffer-name-timer))
|
||||
(setq exwmx/buffer-name-timer
|
||||
(run-at-time 3 nil #'exwmx/rename-firefox-windows)))
|
||||
|
||||
;; (setq exwm-manage-finish-hook
|
||||
;; (delq #'exwmx/add-firefox-buffers exwm-manage-finish-hook))
|
||||
|
||||
(defun display-buffers-split-vertically (lob)
|
||||
(delete-other-windows)
|
||||
(let ((last (car (last lob))))
|
||||
(dolist (b lob)
|
||||
(display-buffer-same-window b nil)
|
||||
(unless (eq b last)
|
||||
(select-window (split-window-vertically)))))
|
||||
(balance-windows))
|
||||
|
||||
(defun exwmx/rename-firefox-windows ()
|
||||
(unwind-protect
|
||||
(save-window-excursion
|
||||
(let ((appconfigs (exwmx-appconfig--search-all '((:class "firefox")))))
|
||||
(when-let ((b (exwmx-find-buffer '((:title "YouTube" string-match-p)) t)))
|
||||
(when (member b exwmx/firefox-buffers)
|
||||
(exwmx-name-buffer "youtube" b )
|
||||
(setq exwmx/firefox-buffers
|
||||
(delete b exwmx/firefox-buffers))
|
||||
(setq appconfigs
|
||||
(remove-if #'(lambda (x)
|
||||
(string= "youtube" (plist-get x :pretty-name)))
|
||||
appconfigs))))
|
||||
(if (= 1 (length exwmx/firefox-buffers))
|
||||
(exwmx-name-buffer "firefox" (car exwmx/firefox-buffers))
|
||||
(delete-other-windows)
|
||||
(let ((last (car (last exwmx/firefox-buffers))))
|
||||
(display-buffers-split-vertically exwmx/firefox-buffers)
|
||||
(dolist (b exwmx/firefox-buffers)
|
||||
(let ((win (get-buffer-window b)))
|
||||
(select-window win)
|
||||
(-->
|
||||
(funcall-interactively #'exwmx-name-buffer nil b appconfigs)
|
||||
(setq appconfigs
|
||||
(remove-if #'(lambda (x)
|
||||
(string= it
|
||||
(plist-get x :pretty-name)))
|
||||
appconfigs)))
|
||||
(unless (eq b last)
|
||||
(delete-window win))))))))
|
||||
(remove-hook 'exwm-manage-finish-hook #'exwmx/add-firefox-buffers)
|
||||
(setq exwmx/firefox-buffers nil)))
|
||||
|
||||
(add-hook 'exwm-manage-finish-hook 'exwmx-manage-x-window)
|
||||
|
||||
;;------------------------------------------------------------------;;
|
||||
;; (let ((debug/appconfig (exwmx-appconfig--search `((:command "pcmanfm"))))
|
||||
;; (debug/buffer (get-buffer "*EXWM*")))
|
||||
;; (cl-assert (exwmx-buffer-match-p debug/appconfig debug/buffer))
|
||||
;; (cl-assert (exwmx-buffer-match-p '(:class "Pcmanfm") debug/buffer))
|
||||
;; (cl-assert (exwmx-buffer-match-p '(:instance "pcmanfm") debug/buffer))
|
||||
;; (cl-assert (exwmx-find-buffer debug/appconfig))
|
||||
;; (cl-assert (eq debug/buffer (exwmx-find-buffer debug/appconfig))))
|
||||
|
||||
(provide 'my-exwmx-quickrun-2)
|
||||
;;; my-exwmx-quickrun-2.el ends here
|
||||
Loading…
Reference in a new issue