[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] externals-release/activities 003df257af 002/103: WIP
|
From: |
ELPA Syncer |
|
Subject: |
[elpa] externals-release/activities 003df257af 002/103: WIP |
|
Date: |
Tue, 30 Jan 2024 03:57:45 -0500 (EST) |
branch: externals-release/activities
commit 003df257afa7224b26616d71a64d497d9ee1d974
Author: Adam Porter <adam@alphapapa.net>
Commit: Adam Porter <adam@alphapapa.net>
WIP
---
activity.el | 233 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 233 insertions(+)
diff --git a/activity.el b/activity.el
index d7e4a17b98..b05f62c8c4 100644
--- a/activity.el
+++ b/activity.el
@@ -5,6 +5,7 @@
;; Author: Adam Porter <adam@alphapapa.net>
;; Keywords: convenience
;; Version: 0.1-pre
+;; Package-Requires: ((emacs "29.1"))
;; 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
@@ -51,6 +52,29 @@
;;; Code:
+;;;; Requirements
+
+(require 'cl-lib)
+(require 'bookmark)
+(require 'map)
+(require 'subr-x)
+
+;;;; Variables
+
+(defvar activity-completing-read-history nil
+ "History for `activity-completing-read'.")
+
+(defvar activity-window-parameters-translators
+ `((window-preserved-size
+ (serialize . ,(pcase-lambda (`(,buffer ,direction ,size))
+ `(,(buffer-name buffer) ,direction ,size)))
+ (deserialize . ,(pcase-lambda (`(,buffer-name ,direction ,size))
+ `(,(get-buffer buffer-name) ,direction ,size)))))
+ "Functions used to serialize and deserialize certain window parameters.
+For example, the value of `window-preserved-size' includes a
+buffer, which must be serialized to a buffer name, and then
+deserialized back to the buffer after it is reincarnated.")
+
;;;; Customization
(defgroup activity nil
@@ -59,6 +83,215 @@
:link '(url-link "https://github.com/alphapapa/activity.el")
:group 'convenience)
+(defcustom activity-bookmark-prefix "Activity: "
+ "Prefix applied to activity bookmark names."
+ :type 'string)
+
+(defcustom activity-window-persistent-parameters
+ (list (cons 'header-line-format 'writable)
+ (cons 'mode-line-format 'writable)
+ (cons 'tab-line-format 'writable)
+ (cons 'no-other-window 'writable)
+ (cons 'no-delete-other-windows 'writable)
+ (cons 'window-preserved-size 'writable)
+ (cons 'window-side 'writable)
+ (cons 'window-slot 'writable))
+ "Additional window parameters to persist.
+See Info node `(elisp)Window Parameters'. See also option
+`activity-set-window-persistent-parameters'."
+ :type '(alist :key-type (symbol :tag "Window parameter")
+ :value-type (choice (const :tag "Not saved" nil)
+ (const :tag "Saved" writable))))
+
+(cl-defstruct activity
+ "FIXME: Docstring."
+ name default-state last-state etc)
+
+(cl-defstruct activity-state
+ "FIXME: Docstring."
+ window-state etc)
+
+;;;; Commands
+
+(defun activity-save (name)
+ "Save activity as NAME."
+ (interactive (list (activity-completing-read :prompt "Save activity as: ")))
+ (let ((record `((handler . activity-bookmark-handler)
+ (activity . ,(make-activity :name name :default-state
(activity-state))))))
+ (bookmark-store name record nil)))
+
+;;;; Functions
+
+(defun activity-state ()
+ "Return the current activity's state."
+ (make-activity-state
+ :window-state (activity--window-state (selected-frame))))
+
+(defun activity--window-state (frame)
+ "Return FRAME's window state."
+ (let* ((window-persistent-parameters (append
activity-window-persistent-parameters
+ window-persistent-parameters))
+ (window-state (with-selected-frame frame
+ (window-state-get nil 'writable))))
+ (activity--window-serialized window-state)))
+
+(defun activity--window-serialized (state)
+ "Return window STATE having serialized its parameters."
+ (cl-labels ((translate-state (state)
+ "Set windows' buffers in STATE."
+ (pcase state
+ (`(leaf . ,_attrs) (translate-leaf state))
+ ((pred atom) state)
+ (`(,_key . ,(pred atom)) state)
+ ((pred list) (mapcar #'translate-state state))))
+ (translate-leaf (leaf)
+ "Translate window parameters in LEAF."
+ (pcase-let* ((`(leaf . ,attrs) leaf)
+ ((map parameters) attrs))
+ (pcase-dolist (`(,parameter . ,(map serialize))
+ activity-window-parameters-translators)
+ (when (map-elt parameters parameter)
+ (setf (map-elt parameters parameter)
+ (funcall serialize (map-elt parameters
parameter)))))
+ (setf (map-elt attrs 'parameters) parameters)
+ (cons 'leaf attrs))))
+ (translate-state state)))
+
+(defun activity--windows-set (config)
+ "Set window configuration according to CONFIG."
+ (setf window-persistent-parameters (copy-sequence
activity-window-persistent-parameters))
+ (pcase-let* ((window-persistent-parameters (append
activity-window-persistent-parameters
+
window-persistent-parameters))
+ (state (activity--bufferize-window-state state)))
+ ;; HACK: Since `bookmark--jump-via' insists on calling a buffer-display
+ ;; function after handling the bookmark, we use an immediate timer to
+ ;; set the window configuration.
+ (run-at-time nil nil (lambda ()
+ (window-state-put state (frame-root-window))))))
+
+(defun activity--bufferize-window-state (state)
+ "Return window state STATE with its buffers reincarnated."
+ (cl-labels ((bufferize-state (state)
+ "Set windows' buffers in STATE."
+ (pcase state
+ (`(leaf . ,_attrs) (translate-leaf (bufferize-leaf state)))
+ ((pred atom) state)
+ (`(,_key . ,(pred atom)) state)
+ ((pred list) (mapcar #'bufferize-state state))))
+ (bufferize-leaf (leaf)
+ "Recreate buffers in LEAF."
+ (pcase-let* ((`(leaf . ,attrs) leaf)
+ ((map parameters buffer) attrs)
+ ((map activity-buffer-record) parameters)
+ (`(,_buffer-name . ,buffer-attrs) buffer)
+ (new-buffer (activity--buffer-for
activity-buffer-record)))
+ (setf (map-elt attrs 'buffer) (cons new-buffer buffer-attrs))
+ (cons 'leaf attrs)))
+ (translate-leaf (leaf)
+ "Translate window parameters in LEAF."
+ (pcase-let* ((`(leaf . ,attrs) leaf)
+ ((map parameters) attrs))
+ (pcase-dolist (`(,parameter . ,(map deserialize))
+ activity-window-parameters-translators)
+ (when (map-elt parameters parameter)
+ (setf (map-elt parameters parameter)
+ (funcall deserialize (map-elt parameters
parameter)))))
+ (setf (map-elt attrs 'parameters) parameters)
+ (cons 'leaf attrs))))
+ (if-let ((leaf-pos (cl-position 'leaf state)))
+ ;; A one-window frame: the elements following `leaf' are that window's
params.
+ (append (cl-subseq state 0 leaf-pos)
+ (translate-leaf (bufferize-leaf (cl-subseq state leaf-pos))))
+ ;; Multi-window frame.
+ (bufferize-state state))))
+
+(cl-defstruct activity-buffer
+ "FIXME: Docstring."
+ (bookmark nil :documentation "Bookmark record")
+ (filename nil :documentation "Filename, if file-backed")
+ (name nil :documentation "Buffer name")
+ (etc nil :documentation "Alist for other data."))
+
+(defun activity--buffer-for (record)
+ "Return buffer for activity buffer RECORD."
+ (pcase-let (((cl-struct activity-buffer bookmark filename name) record))
+ (cond (bookmark (activity--bookmark-buffer record))
+ (filename (activity--filename-buffer record))
+ (name (activity--name-buffer record))
+ (t (error "Activity record is invalid: %S")))))
+
+(defun activity--bookmark-buffer (record)
+ "Return buffer for bookmark RECORD."
+ ;; NOTE: Be aware of the following note from burly.el:
+ ;; NOTE: Due to changes in help-mode.el which serialize natively
+ ;; compiled subrs in the bookmark record, which cannot be read
+ ;; back (which actually break the entire bookmark system when
+ ;; such a record is saved in the bookmarks file), we have to
+ ;; workaround a failure to read here. See bug#56643.
+ (pcase-let* (((cl-struct activity-buffer bookmark) record))
+ (save-window-excursion
+ (condition-case err
+ (progn
+ (bookmark-jump record)
+ (when-let ((local-variable-map
+ (bookmark-prop-get bookmark
'activity-buffer-local-variables)))
+ (cl-loop for (variable . value) in local-variable-map
+ do (setf (buffer-local-value variable (current-buffer))
value))))
+ (error (delay-warning 'activity
+ (format "Error while opening bookmark: ERROR:%S
RECORD:%S" err record))))
+ (current-buffer))))
+
+(defcustom activity-major-mode-alist
+ (list (cons 'org-mode
+ (list (cons 'make-url-fn #'activity--org-mode-buffer-url)
+ (cons 'follow-url-fn #'activity-follow-url-org-mode))))
+ "Alist mapping major modes to the appropriate Activity functions."
+ :type '(alist :key-type symbol
+ :value-type (set (cons (const make-url-fn) (function :tag
"Make-URL function"))
+ (cons (const follow-url-fn) (function :tag
"Follow-URL function")))))
+
+(defun activity--filename-buffer (record)
+ "Return buffer for filename RECORD."
+ (pcase-let* (((cl-struct activity-buffer filename) record)
+ (buffer (find-file-noselect filename))
+ (major-mode (buffer-local-value 'major-mode buffer))
+ (follow-fn (map-nested-elt activity-major-mode-alist (list
major-mode 'follow-url-fn))))
+ (cl-assert follow-fn nil "Major mode not in `activity-major-mode-alist':
%s" major-mode)
+ (funcall follow-fn :buffer buffer :record record)))
+
+(defun activity--name-buffer (record)
+ "Return buffer for name RECORD."
+ (pcase-let (((cl-struct activity-buffer name) record))
+ (or (get-buffer name)
+ (with-current-buffer (get-buffer-create (concat "*Activity (error): "
name "*"))
+ (insert "Activity was unable to get a buffer named: " name "\n"
+ "Record: " (format "%S" record) "\n"
+ "Please report this error to the developer\n\n")
+ (current-buffer)))))
+
+(cl-defun activity-completing-read (&key (prompt "Open activity: "))
+ "Return an activity name read with completion.
+PROMPT is passed to `completing-read', which see."
+ (completing-read prompt (activity-names)
+ nil nil activity-bookmark-prefix
activity-completing-read-history))
+
+(defun activity-activities ()
+ "Return list of activities."
+ (bookmark-maybe-load-default-file)
+ (cl-remove-if-not (pcase-lambda (`(,_name . ,(map handler)))
+ (equal #'activity-bookmark-handler handler))
+ bookmark-alist))
+
+(cl-defun activity-names (&optional (activities (activity-activities)))
+ "Return list of names of ACTIVITIES."
+ (thread-last activities
+ (mapcar #'car)
+ (mapcar (lambda (name)
+ (string-remove-prefix activity-bookmark-prefix
name)))))
+
+(defun activity-bookmark-handler (bookmark)
+ "Switch to BOOKMARK's activity.")
+
;;;; Footer
(provide 'activity)
- [elpa] externals-release/activities 0ea9b84880 088/103: Change: (-switch) Offer current activity as default completion, (continued)
- [elpa] externals-release/activities 0ea9b84880 088/103: Change: (-switch) Offer current activity as default completion, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 6938717945 090/103: Docs: Update changelog, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 70f75f1d2a 086/103: Fix: (activities-mode) Fix parent group, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities ee788599ba 103/103: Release: v0.3, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 6d2aa1a381 003/103: WIP, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 388f31f686 007/103: WIP, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 2027ede904 001/103: Initial commit, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 9de2334d94 011/103: Tabs WIP, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 10c1a7f629 010/103: WIP, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities a337656530 014/103: WIP, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 003df257af 002/103: WIP,
ELPA Syncer <=
- [elpa] externals-release/activities 3738d539e9 018/103: Add FAQ, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities bf181fa512 019/103: Update FAQ, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities bf84de5214 022/103: WIP (multisession doesn't seem to work with alists, trying persist next), ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities f55b63a1cf 023/103: Seems to work, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 43c4524b47 025/103: Fix: (activity-switch) Set frame name, call make-frame correctly, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 4bc5b0f757 026/103: Fixes and additions, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities e0bdd210bd 027/103: Fix, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 42f9e302be 031/103: Tidy, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 68dc0e0d55 033/103: Fix: Don't redisplay, ELPA Syncer, 2024/01/30
- [elpa] externals-release/activities 31d563422f 030/103: Fix, tidy, ELPA Syncer, 2024/01/30