Complete refactoring: remove tp-define-layer and tp-define-layer-group, use only define-tp and define-tps
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
parent
4607f50a13
commit
7934749397
96
README.md
96
README.md
@ -210,7 +210,7 @@ Native APIs only have simple set and get. tp.el provides three clear operation s
|
|||||||
**This is tp.el's most innovative feature**, completely unsupported by native Emacs. The property layer system allows stacking multiple sets of properties on the same text region:
|
**This is tp.el's most innovative feature**, completely unsupported by native Emacs. The property layer system allows stacking multiple sets of properties on the same text region:
|
||||||
|
|
||||||
- ✅ **Property Layer Stack Concept**: Multiple property layers stack like a stack, only the top layer is visible, lower layers are preserved
|
- ✅ **Property Layer Stack Concept**: Multiple property layers stack like a stack, only the top layer is visible, lower layers are preserved
|
||||||
- ✅ **Property Layer Definition & Reuse**: Define reusable property layers and layer groups via `tp-define-layer`
|
- ✅ **Property Layer Definition & Reuse**: Define reusable property layers and layer groups via `define-tp` and `define-tps`
|
||||||
- ✅ **Rich Property Layer Operations**:
|
- ✅ **Rich Property Layer Operations**:
|
||||||
- Placement: `tp-put-layer` (specific position), `tp-push-layer` (top)
|
- Placement: `tp-put-layer` (specific position), `tp-push-layer` (top)
|
||||||
- Deletion: `tp-delete-layer` (by name/index), `tp-pop-layer` (top layer)
|
- Deletion: `tp-delete-layer` (by name/index), `tp-pop-layer` (top layer)
|
||||||
@ -264,7 +264,7 @@ Native APIs require manual searching and looping. tp.el provides convenient patt
|
|||||||
;; Define a layer with reactive properties
|
;; Define a layer with reactive properties
|
||||||
(defvar my-color "red") ;; Reactive variable
|
(defvar my-color "red") ;; Reactive variable
|
||||||
|
|
||||||
(tp-define-layer 'my-highlight
|
(define-tp my-highlight ()
|
||||||
:props '(face (:foreground $my-color)))
|
:props '(face (:foreground $my-color)))
|
||||||
|
|
||||||
;; Apply the layer
|
;; Apply the layer
|
||||||
@ -274,7 +274,7 @@ Native APIs require manual searching and looping. tp.el provides convenient patt
|
|||||||
(setq my-color "blue") ;; All text with my-highlight layer updates to blue!
|
(setq my-color "blue") ;; All text with my-highlight layer updates to blue!
|
||||||
|
|
||||||
;; Advanced example with :data, :compute, and :watch
|
;; Advanced example with :data, :compute, and :watch
|
||||||
(tp-define-layer 'full-name-layer
|
(define-tp full-name-layer ()
|
||||||
:props '(help-echo $full-name face (:foreground $name-color))
|
:props '(help-echo $full-name face (:foreground $name-color))
|
||||||
:data ((first-name . "John") (last-name . "Doe")) ;; With initial values
|
:data ((first-name . "John") (last-name . "Doe")) ;; With initial values
|
||||||
:compute ((full-name (lambda () (concat first-name " " last-name))))
|
:compute ((full-name (lambda () (concat first-name " " last-name))))
|
||||||
@ -442,7 +442,7 @@ Set text properties on a string or buffer region. Replaces only the specified pr
|
|||||||
(tp-set STRING LAYER-NAME)
|
(tp-set STRING LAYER-NAME)
|
||||||
```
|
```
|
||||||
|
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
@ -460,7 +460,7 @@ LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or
|
|||||||
;; => (1 . 10)
|
;; => (1 . 10)
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'warning-style
|
(define-tp warning-style ()
|
||||||
'(face (:foreground "orange" :weight bold)))
|
'(face (:foreground "orange" :weight bold)))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -485,7 +485,7 @@ LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or
|
|||||||
;; => #("Hello" 0 5 (face bold mouse-face highlight))
|
;; => #("Hello" 0 5 (face bold mouse-face highlight))
|
||||||
|
|
||||||
;; Use a defined layer name on entire string
|
;; Use a defined layer name on entire string
|
||||||
(tp-define-layer 'my-style
|
(define-tp my-style ()
|
||||||
:props '(face (:foreground $my-color))
|
:props '(face (:foreground $my-color))
|
||||||
:data ((my-color . "blue")))
|
:data ((my-color . "blue")))
|
||||||
(tp-set " " 'my-style)
|
(tp-set " " 'my-style)
|
||||||
@ -523,7 +523,7 @@ Completely replace ALL text properties with the specified ones.
|
|||||||
(tp-reset STRING PROPERTY VALUE ...)
|
(tp-reset STRING PROPERTY VALUE ...)
|
||||||
```
|
```
|
||||||
|
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
@ -541,7 +541,7 @@ LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or
|
|||||||
;; => #("Hello" 0 5 (face italic))
|
;; => #("Hello" 0 5 (face italic))
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'error-style
|
(define-tp error-style ()
|
||||||
'(face (:foreground "red" :weight bold)))
|
'(face (:foreground "red" :weight bold)))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -561,7 +561,7 @@ Add or update properties with deep merge support for nested plists.
|
|||||||
(tp-add STRING PROPERTY VALUE ...)
|
(tp-add STRING PROPERTY VALUE ...)
|
||||||
```
|
```
|
||||||
|
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
|
|
||||||
@ -589,7 +589,7 @@ LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or
|
|||||||
;; => (shadow bold)
|
;; => (shadow bold)
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'highlight-style
|
(define-tp highlight-style ()
|
||||||
'(face (:background "yellow")))
|
'(face (:background "yellow")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -867,7 +867,7 @@ Clear all text properties from a region.
|
|||||||
Set properties on all occurrences of a string pattern.
|
Set properties on all occurrences of a string pattern.
|
||||||
PATTERN can be a string (single pattern) or a list of strings (multiple patterns).
|
PATTERN can be a string (single pattern) or a list of strings (multiple patterns).
|
||||||
PLIST is a property list like `'(face bold help-echo "tip")`.
|
PLIST is a property list like `'(face bold help-echo "tip")`.
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
OBJECT is a buffer or string; nil means current buffer.
|
OBJECT is a buffer or string; nil means current buffer.
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
@ -894,7 +894,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
;; => #("Hello world" 0 5 (face bold) 6 11 (face bold))
|
;; => #("Hello world" 0 5 (face bold) 6 11 (face bold))
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'todo-style
|
(define-tp todo-style ()
|
||||||
'(face (:foreground "orange" :weight bold)))
|
'(face (:foreground "orange" :weight bold)))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "TODO: fix this. TODO: also this.")
|
(insert "TODO: fix this. TODO: also this.")
|
||||||
@ -909,7 +909,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
Reset (completely replace) all properties on matches.
|
Reset (completely replace) all properties on matches.
|
||||||
PATTERN can be a string or list of strings (multiple patterns).
|
PATTERN can be a string or list of strings (multiple patterns).
|
||||||
PLIST is a property list like `'(face bold help-echo "tip")`.
|
PLIST is a property list like `'(face bold help-echo "tip")`.
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
OBJECT is a buffer or string; nil means current buffer.
|
OBJECT is a buffer or string; nil means current buffer.
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
@ -935,7 +935,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
;; => ((1 . 5) (12 . 17))
|
;; => ((1 . 5) (12 . 17))
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'alert-style
|
(define-tp alert-style ()
|
||||||
'(face (:background "red" :foreground "white")))
|
'(face (:background "red" :foreground "white")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "TODO: fix this")
|
(insert "TODO: fix this")
|
||||||
@ -950,7 +950,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
Add/merge properties on matches with deep merge support.
|
Add/merge properties on matches with deep merge support.
|
||||||
PATTERN can be a string or list of strings (multiple patterns).
|
PATTERN can be a string or list of strings (multiple patterns).
|
||||||
PLIST is a property list like `'(face bold help-echo "tip")`.
|
PLIST is a property list like `'(face bold help-echo "tip")`.
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
OBJECT is a buffer or string; nil means current buffer.
|
OBJECT is a buffer or string; nil means current buffer.
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
@ -976,7 +976,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
;; => ((1 . 5) (12 . 17))
|
;; => ((1 . 5) (12 . 17))
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'underline-style
|
(define-tp underline-style ()
|
||||||
'(face (:underline (:color "blue" :style wave))))
|
'(face (:underline (:color "blue" :style wave))))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "TODO: fix this")
|
(insert "TODO: fix this")
|
||||||
@ -996,7 +996,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
Set properties on all matches of a regular expression.
|
Set properties on all matches of a regular expression.
|
||||||
PATTERN can be a string (single regexp) or a list of strings (multiple regexps).
|
PATTERN can be a string (single regexp) or a list of strings (multiple regexps).
|
||||||
PLIST is a property list like `'(face bold help-echo "tip")`.
|
PLIST is a property list like `'(face bold help-echo "tip")`.
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
OBJECT is a buffer or string; nil means current buffer.
|
OBJECT is a buffer or string; nil means current buffer.
|
||||||
|
|
||||||
**Examples:**
|
**Examples:**
|
||||||
@ -1018,7 +1018,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
;; => #("abc 123 XYZ" 4 7 (face bold) 8 11 (face bold))
|
;; => #("abc 123 XYZ" 4 7 (face bold) 8 11 (face bold))
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'number-style
|
(define-tp number-style ()
|
||||||
'(face (:foreground "green")))
|
'(face (:foreground "green")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "abc 123 def 456")
|
(insert "abc 123 def 456")
|
||||||
@ -1033,7 +1033,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
Reset (completely replace) all properties on regexp matches.
|
Reset (completely replace) all properties on regexp matches.
|
||||||
PATTERN can be a string or list of strings (multiple regexps).
|
PATTERN can be a string or list of strings (multiple regexps).
|
||||||
PLIST is a property list like `'(face bold help-echo "tip")`.
|
PLIST is a property list like `'(face bold help-echo "tip")`.
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
OBJECT is a buffer or string; nil means current buffer.
|
OBJECT is a buffer or string; nil means current buffer.
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
@ -1060,7 +1060,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
;; => (face italic)
|
;; => (face italic)
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'code-number
|
(define-tp code-number ()
|
||||||
'(face (:foreground "cyan")))
|
'(face (:foreground "cyan")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "abc 123 def 456")
|
(insert "abc 123 def 456")
|
||||||
@ -1075,7 +1075,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
Add/merge properties on regexp matches with deep merge support.
|
Add/merge properties on regexp matches with deep merge support.
|
||||||
PATTERN can be a string or list of strings (multiple regexps).
|
PATTERN can be a string or list of strings (multiple regexps).
|
||||||
PLIST is a property list like `'(face bold help-echo "tip")`.
|
PLIST is a property list like `'(face bold help-echo "tip")`.
|
||||||
LAYER-NAME can be a symbol representing a layer defined by `tp-define-layer` or a group defined by `tp-define-layer-group`.
|
LAYER-NAME can be a symbol representing a layer defined by `define-tp` or a group defined by `define-tps`.
|
||||||
OBJECT is a buffer or string; nil means current buffer.
|
OBJECT is a buffer or string; nil means current buffer.
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
@ -1102,7 +1102,7 @@ OBJECT is a buffer or string; nil means current buffer.
|
|||||||
;; => (face italic help-echo "number")
|
;; => (face italic help-echo "number")
|
||||||
|
|
||||||
;; Use a defined layer name
|
;; Use a defined layer name
|
||||||
(tp-define-layer 'bold-underline
|
(define-tp bold-underline ()
|
||||||
'(face (:weight bold :underline t)))
|
'(face (:weight bold :underline t)))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "abc 123 def 456")
|
(insert "abc 123 def 456")
|
||||||
@ -1649,7 +1649,7 @@ This is useful when you want to remove all reactive bindings but keep the layer
|
|||||||
;; Define a reactive layer
|
;; Define a reactive layer
|
||||||
(progn
|
(progn
|
||||||
(defvar my-reactive-color "red")
|
(defvar my-reactive-color "red")
|
||||||
(tp-define-layer 'reactive-layer
|
(define-tp reactive-layer ()
|
||||||
:props '(face (:foreground $my-reactive-color)))
|
:props '(face (:foreground $my-reactive-color)))
|
||||||
;; Clear reactive bindings only
|
;; Clear reactive bindings only
|
||||||
(tp-reactive-reset)
|
(tp-reactive-reset)
|
||||||
@ -2460,12 +2460,12 @@ Return t if OBJECT has no text properties.
|
|||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
;; Define layers for different highlighting purposes
|
;; Define layers for different highlighting purposes
|
||||||
(tp-define-layer 'code-base
|
(define-tp code-base ()
|
||||||
'(face font-lock-keyword-face))
|
'(face font-lock-keyword-face))
|
||||||
(tp-define-layer 'code-error
|
(define-tp code-error ()
|
||||||
'(face (:underline (:color "red" :style wave))
|
'(face (:underline (:color "red" :style wave))
|
||||||
help-echo "Syntax error"))
|
help-echo "Syntax error"))
|
||||||
(tp-define-layer 'code-debug
|
(define-tp code-debug ()
|
||||||
'(face (:background "dark blue")))
|
'(face (:background "dark blue")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert (make-string 100 ?x)) ; Create 100-char buffer
|
(insert (make-string 100 ?x)) ; Create 100-char buffer
|
||||||
@ -2491,10 +2491,10 @@ Return t if OBJECT has no text properties.
|
|||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
;; Define status layers as a group
|
;; Define status layers as a group
|
||||||
(tp-define-layer 'status-todo '(face (:foreground "gray")))
|
(define-tp status-todo () '(face (:foreground "gray")))
|
||||||
(tp-define-layer 'status-progress '(face (:foreground "yellow")))
|
(define-tp status-progress () '(face (:foreground "yellow")))
|
||||||
(tp-define-layer 'status-done '(face (:foreground "green")))
|
(define-tp status-done () '(face (:foreground "green")))
|
||||||
(tp-define-layer-group 'task-status 'status-todo 'status-progress 'status-done)
|
(define-tps task-status 'status-todo 'status-progress 'status-done)
|
||||||
;; Check group is defined
|
;; Check group is defined
|
||||||
(length (tp-group-props 'task-status)))
|
(length (tp-group-props 'task-status)))
|
||||||
;; => 3
|
;; => 3
|
||||||
@ -2512,7 +2512,7 @@ Return t if OBJECT has no text properties.
|
|||||||
;; Define temporary highlight layer
|
;; Define temporary highlight layer
|
||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
(tp-define-layer 'temp-highlight
|
(define-tp temp-highlight ()
|
||||||
'(face (:background "yellow")))
|
'(face (:background "yellow")))
|
||||||
(tp-layer-props 'temp-highlight))
|
(tp-layer-props 'temp-highlight))
|
||||||
;; => (face (:background "yellow") tp-name temp-highlight)
|
;; => (face (:background "yellow") tp-name temp-highlight)
|
||||||
@ -2551,7 +2551,7 @@ Traditional text property manipulation requires manually updating all affected t
|
|||||||
|
|
||||||
;; Reactive approach (automatic updates)
|
;; Reactive approach (automatic updates)
|
||||||
(defvar my-color "red")
|
(defvar my-color "red")
|
||||||
(tp-define-layer 'my-layer
|
(define-tp my-layer ()
|
||||||
:props '(face (:foreground $my-color)))
|
:props '(face (:foreground $my-color)))
|
||||||
(tp-push-layer 1 10 'my-layer)
|
(tp-push-layer 1 10 'my-layer)
|
||||||
;; Just change the variable - all text updates automatically!
|
;; Just change the variable - all text updates automatically!
|
||||||
@ -2573,7 +2573,7 @@ Traditional text property manipulation requires manually updating all affected t
|
|||||||
```elisp
|
```elisp
|
||||||
(defvar highlight-color "yellow")
|
(defvar highlight-color "yellow")
|
||||||
|
|
||||||
(tp-define-layer 'my-highlight
|
(define-tp my-highlight ()
|
||||||
:props '(face (:background $highlight-color)))
|
:props '(face (:background $highlight-color)))
|
||||||
|
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
@ -2592,7 +2592,7 @@ Traditional text property manipulation requires manually updating all affected t
|
|||||||
(defvar fg-color "white")
|
(defvar fg-color "white")
|
||||||
(defvar bg-color "black")
|
(defvar bg-color "black")
|
||||||
|
|
||||||
(tp-define-layer 'themed-text
|
(define-tp themed-text ()
|
||||||
:props '(face (:foreground $fg-color :background $bg-color)))
|
:props '(face (:foreground $fg-color :background $bg-color)))
|
||||||
|
|
||||||
;; Changing either variable updates the text
|
;; Changing either variable updates the text
|
||||||
@ -2605,7 +2605,7 @@ Traditional text property manipulation requires manually updating all affected t
|
|||||||
The `:data` keyword defines additional reactive variables that aren't directly used in `:props` but can trigger computed value updates or be watched:
|
The `:data` keyword defines additional reactive variables that aren't directly used in `:props` but can trigger computed value updates or be watched:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'user-info
|
(define-tp user-info ()
|
||||||
:props '(help-echo $full-name)
|
:props '(help-echo $full-name)
|
||||||
:data '(first-name last-name) ; Not used directly in props
|
:data '(first-name last-name) ; Not used directly in props
|
||||||
:compute '((full-name (lambda () (concat first-name " " last-name)))))
|
:compute '((full-name (lambda () (concat first-name " " last-name)))))
|
||||||
@ -2616,7 +2616,7 @@ The `:data` keyword defines additional reactive variables that aren't directly u
|
|||||||
You can specify initial values using cons cells:
|
You can specify initial values using cons cells:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'user-info
|
(define-tp user-info ()
|
||||||
:props '(help-echo $full-name)
|
:props '(help-echo $full-name)
|
||||||
:data '((first-name . "John") (last-name . "Doe"))
|
:data '((first-name . "John") (last-name . "Doe"))
|
||||||
:compute '((full-name (lambda () (concat first-name " " last-name)))))
|
:compute '((full-name (lambda () (concat first-name " " last-name)))))
|
||||||
@ -2629,7 +2629,7 @@ You can specify initial values using cons cells:
|
|||||||
The `:compute` keyword creates derived values that are automatically recalculated when their dependencies change:
|
The `:compute` keyword creates derived values that are automatically recalculated when their dependencies change:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'progress-display
|
(define-tp progress-display ()
|
||||||
:props '(display $progress-text face (:foreground $progress-color))
|
:props '(display $progress-text face (:foreground $progress-color))
|
||||||
:data '((current . 0) (total . 100))
|
:data '((current . 0) (total . 100))
|
||||||
:compute '((progress-text (lambda () (format "%d%%" (/ (* current 100) total))))
|
:compute '((progress-text (lambda () (format "%d%%" (/ (* current 100) total))))
|
||||||
@ -2648,7 +2648,7 @@ The `:compute` keyword creates derived values that are automatically recalculate
|
|||||||
The `:watch` keyword lets you execute callbacks when reactive variables change:
|
The `:watch` keyword lets you execute callbacks when reactive variables change:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'monitored-layer
|
(define-tp monitored-layer ()
|
||||||
:props '(face (:foreground $status-color))
|
:props '(face (:foreground $status-color))
|
||||||
:watch ((status-color
|
:watch ((status-color
|
||||||
(lambda (new-val old-val layer-name)
|
(lambda (new-val old-val layer-name)
|
||||||
@ -2668,7 +2668,7 @@ The `:transform` keyword allows you to register a transformation function that p
|
|||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
;; Number formatting
|
;; Number formatting
|
||||||
(tp-define-layer 'price-display
|
(define-tp price-display ()
|
||||||
:props '(tp-text $price)
|
:props '(tp-text $price)
|
||||||
:data '((price . "99.9"))
|
:data '((price . "99.9"))
|
||||||
:transform (lambda (text)
|
:transform (lambda (text)
|
||||||
@ -2676,7 +2676,7 @@ The `:transform` keyword allows you to register a transformation function that p
|
|||||||
;; 99.9 displays as $99.00
|
;; 99.9 displays as $99.00
|
||||||
|
|
||||||
;; Date formatting
|
;; Date formatting
|
||||||
(tp-define-layer 'date-display
|
(define-tp date-display ()
|
||||||
:props '(tp-text $timestamp)
|
:props '(tp-text $timestamp)
|
||||||
:data '((timestamp . "1703865600"))
|
:data '((timestamp . "1703865600"))
|
||||||
:transform (lambda (text)
|
:transform (lambda (text)
|
||||||
@ -2684,7 +2684,7 @@ The `:transform` keyword allows you to register a transformation function that p
|
|||||||
(seconds-to-time (string-to-number text)))))
|
(seconds-to-time (string-to-number text)))))
|
||||||
|
|
||||||
;; Uppercase conversion
|
;; Uppercase conversion
|
||||||
(tp-define-layer 'uppercase-text
|
(define-tp uppercase-text ()
|
||||||
:props '(tp-text $content)
|
:props '(tp-text $content)
|
||||||
:data '((content . "hello"))
|
:data '((content . "hello"))
|
||||||
:transform #'upcase)
|
:transform #'upcase)
|
||||||
@ -2699,7 +2699,7 @@ The transform function:
|
|||||||
|
|
||||||
### Anonymous Reactive Layers
|
### Anonymous Reactive Layers
|
||||||
|
|
||||||
You can use reactive variables even without `tp-define-layer`. When you use `$`-prefixed symbols in an anonymous plist, tp.el automatically generates a unique layer name:
|
You can use reactive variables even without `define-tp`. When you use `$`-prefixed symbols in an anonymous plist, tp.el automatically generates a unique layer name:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(defvar my-face-color "blue")
|
(defvar my-face-color "blue")
|
||||||
@ -2716,7 +2716,7 @@ You can use reactive variables even without `tp-define-layer`. When you use `$`-
|
|||||||
All text property APIs (`tp-set`, `tp-match-set`, `tp-regexp-set`, etc.) now accept layer names directly:
|
All text property APIs (`tp-set`, `tp-match-set`, `tp-regexp-set`, etc.) now accept layer names directly:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'warning-style
|
(define-tp warning-style ()
|
||||||
:props '(face (:foreground "orange" :weight bold)))
|
:props '(face (:foreground "orange" :weight bold)))
|
||||||
|
|
||||||
;; Use layer name instead of plist
|
;; Use layer name instead of plist
|
||||||
@ -2732,7 +2732,7 @@ All text property APIs (`tp-set`, `tp-match-set`, `tp-regexp-set`, etc.) now acc
|
|||||||
Layer groups can also use reactive features:
|
Layer groups can also use reactive features:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer-group 'status-indicators
|
(define-tps status-indicators
|
||||||
'("success" :props (face (:foreground $success-color))
|
'("success" :props (face (:foreground $success-color))
|
||||||
:data ((success-color . "green")))
|
:data ((success-color . "green")))
|
||||||
'("warning" :props (face (:foreground $warning-color))
|
'("warning" :props (face (:foreground $warning-color))
|
||||||
@ -2746,7 +2746,7 @@ Layer groups can also use reactive features:
|
|||||||
When modifying multiple reactive variables simultaneously, each `setq` triggers a separate buffer update. Use `tp-with-batch-updates` to consolidate all changes and apply them once at the end:
|
When modifying multiple reactive variables simultaneously, each `setq` triggers a separate buffer update. Use `tp-with-batch-updates` to consolidate all changes and apply them once at the end:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'themed-text
|
(define-tp themed-text ()
|
||||||
:props '(face (:foreground $fg-color :background $bg-color))
|
:props '(face (:foreground $fg-color :background $bg-color))
|
||||||
:data '((fg-color . "white") (bg-color . "black")))
|
:data '((fg-color . "white") (bg-color . "black")))
|
||||||
|
|
||||||
@ -2818,13 +2818,13 @@ To clear all reactive dependencies and watchers:
|
|||||||
(defvar theme-accent "cyan")
|
(defvar theme-accent "cyan")
|
||||||
|
|
||||||
;; Define theme-aware layers
|
;; Define theme-aware layers
|
||||||
(tp-define-layer 'code-keyword
|
(define-tp code-keyword ()
|
||||||
:props '(face (:foreground $theme-accent :weight bold)))
|
:props '(face (:foreground $theme-accent :weight bold)))
|
||||||
|
|
||||||
(tp-define-layer 'code-comment
|
(define-tp code-comment ()
|
||||||
:props '(face (:foreground "gray" :slant italic)))
|
:props '(face (:foreground "gray" :slant italic)))
|
||||||
|
|
||||||
(tp-define-layer 'code-string
|
(define-tp code-string ()
|
||||||
:props '(face (:foreground "green")))
|
:props '(face (:foreground "green")))
|
||||||
|
|
||||||
;; Apply layers to code
|
;; Apply layers to code
|
||||||
|
|||||||
92
README_CN.md
92
README_CN.md
@ -273,10 +273,10 @@
|
|||||||
;; 之后只需改变变量 - 文本自动更新!
|
;; 之后只需改变变量 - 文本自动更新!
|
||||||
(setq my-color "blue") ;; 所有 my-highlight 层的文本自动变成蓝色!
|
(setq my-color "blue") ;; 所有 my-highlight 层的文本自动变成蓝色!
|
||||||
|
|
||||||
;; 高级响应式示例(使用内部函数 tp-define-layer):
|
;; 高级响应式示例(使用 define-tp):
|
||||||
;; 对于需要 :data、:compute、:watch 等高级特性的场景,
|
;; 对于需要 :data、:compute、:watch 等高级特性的场景,
|
||||||
;; 可以使用内部函数 tp-define-layer
|
;; 可以使用 define-tp
|
||||||
(tp-define-layer 'full-name-layer
|
(define-tp full-name-layer ()
|
||||||
:props '(help-echo $full-name face (:foreground $name-color))
|
:props '(help-echo $full-name face (:foreground $name-color))
|
||||||
:data '((first-name . "John") (last-name . "Doe")) ;; 带初始值
|
:data '((first-name . "John") (last-name . "Doe")) ;; 带初始值
|
||||||
:compute '((full-name (lambda () (concat first-name " " last-name))))
|
:compute '((full-name (lambda () (concat first-name " " last-name))))
|
||||||
@ -479,7 +479,7 @@ LAYER-NAME 可以是通过 `define-tp` 定义的自定义文本属性名称或
|
|||||||
;; => #("Hello" 0 5 (face bold mouse-face highlight))
|
;; => #("Hello" 0 5 (face bold mouse-face highlight))
|
||||||
|
|
||||||
;; 在整个字符串上使用已定义的层名称
|
;; 在整个字符串上使用已定义的层名称
|
||||||
(tp-define-layer 'my-style
|
(define-tp my-style ()
|
||||||
:props '(face (:foreground $my-color))
|
:props '(face (:foreground $my-color))
|
||||||
:data '((my-color . "blue")))
|
:data '((my-color . "blue")))
|
||||||
(tp-set " " 'my-style)
|
(tp-set " " 'my-style)
|
||||||
@ -535,7 +535,7 @@ LAYER-NAME 可以是通过 `define-tp` 定义的自定义文本属性名称或
|
|||||||
;; => #("Hello" 0 5 (face italic))
|
;; => #("Hello" 0 5 (face italic))
|
||||||
|
|
||||||
;; 使用已定义的层名称
|
;; 使用已定义的层名称
|
||||||
(tp-define-layer 'error-style
|
(define-tp error-style ()
|
||||||
'(face (:foreground "red" :weight bold)))
|
'(face (:foreground "red" :weight bold)))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -583,7 +583,7 @@ LAYER-NAME 可以是通过 `define-tp` 定义的自定义文本属性名称或
|
|||||||
;; => (shadow bold)
|
;; => (shadow bold)
|
||||||
|
|
||||||
;; 使用已定义的层名称
|
;; 使用已定义的层名称
|
||||||
(tp-define-layer 'highlight-style
|
(define-tp highlight-style ()
|
||||||
'(face (:background "yellow")))
|
'(face (:background "yellow")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -888,7 +888,7 @@ OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
|
|||||||
;; => #("Hello world" 0 5 (face bold) 6 11 (face bold))
|
;; => #("Hello world" 0 5 (face bold) 6 11 (face bold))
|
||||||
|
|
||||||
;; 使用已定义的层名称
|
;; 使用已定义的层名称
|
||||||
(tp-define-layer 'todo-style
|
(define-tp todo-style ()
|
||||||
'(face (:foreground "orange" :weight bold)))
|
'(face (:foreground "orange" :weight bold)))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "TODO: fix this. TODO: also this.")
|
(insert "TODO: fix this. TODO: also this.")
|
||||||
@ -929,7 +929,7 @@ OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
|
|||||||
;; => ((1 . 5) (12 . 17))
|
;; => ((1 . 5) (12 . 17))
|
||||||
|
|
||||||
;; 使用已定义的层名称
|
;; 使用已定义的层名称
|
||||||
(tp-define-layer 'alert-style
|
(define-tp alert-style ()
|
||||||
'(face (:background "red" :foreground "white")))
|
'(face (:background "red" :foreground "white")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "TODO: fix this")
|
(insert "TODO: fix this")
|
||||||
@ -970,7 +970,7 @@ OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
|
|||||||
;; => ((1 . 5) (12 . 17))
|
;; => ((1 . 5) (12 . 17))
|
||||||
|
|
||||||
;; 使用已定义的层名称
|
;; 使用已定义的层名称
|
||||||
(tp-define-layer 'underline-style
|
(define-tp underline-style ()
|
||||||
'(face (:underline (:color "blue" :style wave))))
|
'(face (:underline (:color "blue" :style wave))))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "TODO: fix this")
|
(insert "TODO: fix this")
|
||||||
@ -1012,7 +1012,7 @@ OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
|
|||||||
;; => #("abc 123 XYZ" 4 7 (face bold) 8 11 (face bold))
|
;; => #("abc 123 XYZ" 4 7 (face bold) 8 11 (face bold))
|
||||||
|
|
||||||
;; 使用已定义的层名称
|
;; 使用已定义的层名称
|
||||||
(tp-define-layer 'number-style
|
(define-tp number-style ()
|
||||||
'(face (:foreground "green")))
|
'(face (:foreground "green")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "abc 123 def 456")
|
(insert "abc 123 def 456")
|
||||||
@ -1054,7 +1054,7 @@ OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
|
|||||||
;; => (face italic)
|
;; => (face italic)
|
||||||
|
|
||||||
;; 使用已定义的层名称
|
;; 使用已定义的层名称
|
||||||
(tp-define-layer 'code-number
|
(define-tp code-number ()
|
||||||
'(face (:foreground "cyan")))
|
'(face (:foreground "cyan")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "abc 123 def 456")
|
(insert "abc 123 def 456")
|
||||||
@ -1096,7 +1096,7 @@ OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
|
|||||||
;; => (face italic help-echo "number")
|
;; => (face italic help-echo "number")
|
||||||
|
|
||||||
;; 使用已定义的层名称
|
;; 使用已定义的层名称
|
||||||
(tp-define-layer 'bold-underline
|
(define-tp bold-underline ()
|
||||||
'(face (:weight bold :underline t)))
|
'(face (:weight bold :underline t)))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "abc 123 def 456")
|
(insert "abc 123 def 456")
|
||||||
@ -1612,8 +1612,8 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(progn
|
(progn
|
||||||
(setq tp-layer-alist nil)
|
(setq tp-layer-alist nil)
|
||||||
(setq tp-layer-groups nil)
|
(setq tp-layer-groups nil)
|
||||||
(tp-define-layer 'l1 '(face bold))
|
(define-tp l1 () '(face bold))
|
||||||
(tp-define-layer-group 'my-group 'l1)
|
(define-tps my-group 'l1)
|
||||||
(tp-undefine-group 'my-group)
|
(tp-undefine-group 'my-group)
|
||||||
(assoc 'my-group tp-layer-groups))
|
(assoc 'my-group tp-layer-groups))
|
||||||
;; => nil
|
;; => nil
|
||||||
@ -1657,7 +1657,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
;; 定义一个响应式层
|
;; 定义一个响应式层
|
||||||
(progn
|
(progn
|
||||||
(defvar my-reactive-color "red")
|
(defvar my-reactive-color "red")
|
||||||
(tp-define-layer 'reactive-layer
|
(define-tp reactive-layer ()
|
||||||
:props '(face (:foreground $my-reactive-color)))
|
:props '(face (:foreground $my-reactive-color)))
|
||||||
;; 仅清除响应式绑定
|
;; 仅清除响应式绑定
|
||||||
(tp-reactive-reset)
|
(tp-reactive-reset)
|
||||||
@ -1716,7 +1716,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
(define-tp base () '(face default))
|
(define-tp base () '(face default))
|
||||||
(tp-define-layer 'info '(face (:foreground "blue")))
|
(define-tp info () '(face (:foreground "blue")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
(tp-put-layer 1 10 'base 0)
|
(tp-put-layer 1 10 'base 0)
|
||||||
@ -2093,7 +2093,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
(define-tp layer1 () '(face bold))
|
(define-tp layer1 () '(face bold))
|
||||||
(tp-define-layer 'layer2 '(help-echo "tip"))
|
(define-tp layer2 () '(help-echo "tip"))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
(tp-push-layer 1 10 'layer1)
|
(tp-push-layer 1 10 'layer1)
|
||||||
@ -2106,7 +2106,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
(define-tp layer1 () '(face bold))
|
(define-tp layer1 () '(face bold))
|
||||||
(tp-define-layer 'layer2 '(help-echo "tip"))
|
(define-tp layer2 () '(help-echo "tip"))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
(tp-push-layer 1 10 'layer1)
|
(tp-push-layer 1 10 'layer1)
|
||||||
@ -2137,7 +2137,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
(define-tp layer1 () '(face bold))
|
(define-tp layer1 () '(face bold))
|
||||||
(tp-define-layer 'layer2 '(help-echo "tip"))
|
(define-tp layer2 () '(help-echo "tip"))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
(tp-push-layer 1 10 'layer1)
|
(tp-push-layer 1 10 'layer1)
|
||||||
@ -2283,8 +2283,8 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
```elisp
|
```elisp
|
||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
(tp-define-layer 'layer1 '(face (:foreground "red")))
|
(define-tp layer1 () '(face (:foreground "red")))
|
||||||
(tp-define-layer 'layer2 '(face (:foreground "blue")))
|
(define-tp layer2 () '(face (:foreground "blue")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
(tp-push-layer 1 10 'layer1)
|
(tp-push-layer 1 10 'layer1)
|
||||||
@ -2468,12 +2468,12 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
;; 为不同高亮目的定义属性层
|
;; 为不同高亮目的定义属性层
|
||||||
(tp-define-layer 'code-base
|
(define-tp code-base ()
|
||||||
'(face font-lock-keyword-face))
|
'(face font-lock-keyword-face))
|
||||||
(tp-define-layer 'code-error
|
(define-tp code-error ()
|
||||||
'(face (:underline (:color "red" :style wave))
|
'(face (:underline (:color "red" :style wave))
|
||||||
help-echo "语法错误"))
|
help-echo "语法错误"))
|
||||||
(tp-define-layer 'code-debug
|
(define-tp code-debug ()
|
||||||
'(face (:background "dark blue")))
|
'(face (:background "dark blue")))
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
(insert (make-string 100 ?x)) ; 创建 100 字符缓冲区
|
(insert (make-string 100 ?x)) ; 创建 100 字符缓冲区
|
||||||
@ -2499,10 +2499,10 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
;; 将状态属性层定义为一个组
|
;; 将状态属性层定义为一个组
|
||||||
(tp-define-layer 'status-todo '(face (:foreground "gray")))
|
(define-tp status-todo () '(face (:foreground "gray")))
|
||||||
(tp-define-layer 'status-progress '(face (:foreground "yellow")))
|
(define-tp status-progress () '(face (:foreground "yellow")))
|
||||||
(tp-define-layer 'status-done '(face (:foreground "green")))
|
(define-tp status-done () '(face (:foreground "green")))
|
||||||
(tp-define-layer-group 'task-status 'status-todo 'status-progress 'status-done)
|
(define-tps task-status 'status-todo 'status-progress 'status-done)
|
||||||
;; 检查组是否已定义
|
;; 检查组是否已定义
|
||||||
(length (tp-group-props 'task-status)))
|
(length (tp-group-props 'task-status)))
|
||||||
;; => 3
|
;; => 3
|
||||||
@ -2520,7 +2520,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
;; 定义临时高亮属性层
|
;; 定义临时高亮属性层
|
||||||
(progn
|
(progn
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
(tp-define-layer 'temp-highlight
|
(define-tp temp-highlight ()
|
||||||
'(face (:background "yellow")))
|
'(face (:background "yellow")))
|
||||||
(tp-layer-props 'temp-highlight))
|
(tp-layer-props 'temp-highlight))
|
||||||
;; => (face (:background "yellow") tp-name temp-highlight)
|
;; => (face (:background "yellow") tp-name temp-highlight)
|
||||||
@ -2559,7 +2559,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
|
|
||||||
;; 响应式方式(自动更新)
|
;; 响应式方式(自动更新)
|
||||||
(defvar my-color "red")
|
(defvar my-color "red")
|
||||||
(tp-define-layer 'my-layer
|
(define-tp my-layer ()
|
||||||
:props '(face (:foreground $my-color)))
|
:props '(face (:foreground $my-color)))
|
||||||
(tp-push-layer 1 10 'my-layer)
|
(tp-push-layer 1 10 'my-layer)
|
||||||
;; 只需改变变量 - 所有文本自动更新!
|
;; 只需改变变量 - 所有文本自动更新!
|
||||||
@ -2581,7 +2581,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
```elisp
|
```elisp
|
||||||
(defvar highlight-color "yellow")
|
(defvar highlight-color "yellow")
|
||||||
|
|
||||||
(tp-define-layer 'my-highlight
|
(define-tp my-highlight ()
|
||||||
:props '(face (:background $highlight-color)))
|
:props '(face (:background $highlight-color)))
|
||||||
|
|
||||||
(with-temp-buffer
|
(with-temp-buffer
|
||||||
@ -2600,7 +2600,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(defvar fg-color "white")
|
(defvar fg-color "white")
|
||||||
(defvar bg-color "black")
|
(defvar bg-color "black")
|
||||||
|
|
||||||
(tp-define-layer 'themed-text
|
(define-tp themed-text ()
|
||||||
:props '(face (:foreground $fg-color :background $bg-color)))
|
:props '(face (:foreground $fg-color :background $bg-color)))
|
||||||
|
|
||||||
;; 改变任一变量都会更新文本
|
;; 改变任一变量都会更新文本
|
||||||
@ -2613,7 +2613,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
`:data` 关键字定义不直接用于 `:props` 但可以触发计算值更新或被监听的额外响应式变量:
|
`:data` 关键字定义不直接用于 `:props` 但可以触发计算值更新或被监听的额外响应式变量:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'user-info
|
(define-tp user-info ()
|
||||||
:props '(help-echo $full-name)
|
:props '(help-echo $full-name)
|
||||||
:data '(first-name last-name) ;; 不直接用于 props
|
:data '(first-name last-name) ;; 不直接用于 props
|
||||||
:compute '((full-name (lambda () (concat first-name " " last-name)))))
|
:compute '((full-name (lambda () (concat first-name " " last-name)))))
|
||||||
@ -2624,7 +2624,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
你可以使用 cons cell 指定初始值:
|
你可以使用 cons cell 指定初始值:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'user-info
|
(define-tp user-info ()
|
||||||
:props '(help-echo $full-name)
|
:props '(help-echo $full-name)
|
||||||
:data '((first-name . "张") (last-name . "三"))
|
:data '((first-name . "张") (last-name . "三"))
|
||||||
:compute '((full-name (lambda () (concat first-name last-name)))))
|
:compute '((full-name (lambda () (concat first-name last-name)))))
|
||||||
@ -2637,7 +2637,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
`:compute` 关键字创建派生值,当它们的依赖项改变时会自动重新计算:
|
`:compute` 关键字创建派生值,当它们的依赖项改变时会自动重新计算:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'progress-display
|
(define-tp progress-display ()
|
||||||
:props '(display $progress-text face (:foreground $progress-color))
|
:props '(display $progress-text face (:foreground $progress-color))
|
||||||
:data '((current . 0) (total . 100))
|
:data '((current . 0) (total . 100))
|
||||||
:compute '((progress-text (lambda () (format "%d%%" (/ (* current 100) total))))
|
:compute '((progress-text (lambda () (format "%d%%" (/ (* current 100) total))))
|
||||||
@ -2656,7 +2656,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
`:watch` 关键字让你在响应式变量改变时执行回调:
|
`:watch` 关键字让你在响应式变量改变时执行回调:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'monitored-layer
|
(define-tp monitored-layer ()
|
||||||
:props '(face (:foreground $status-color))
|
:props '(face (:foreground $status-color))
|
||||||
:watch '((status-color
|
:watch '((status-color
|
||||||
(lambda (new-val old-val layer-name)
|
(lambda (new-val old-val layer-name)
|
||||||
@ -2676,7 +2676,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
;; 数字格式化
|
;; 数字格式化
|
||||||
(tp-define-layer 'price-display
|
(define-tp price-display ()
|
||||||
:props '(tp-text $price)
|
:props '(tp-text $price)
|
||||||
:data '((price . "99.9"))
|
:data '((price . "99.9"))
|
||||||
:transform (lambda (text)
|
:transform (lambda (text)
|
||||||
@ -2684,7 +2684,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
;; 99.9 显示为 $99.00
|
;; 99.9 显示为 $99.00
|
||||||
|
|
||||||
;; 日期格式化
|
;; 日期格式化
|
||||||
(tp-define-layer 'date-display
|
(define-tp date-display ()
|
||||||
:props '(tp-text $timestamp)
|
:props '(tp-text $timestamp)
|
||||||
:data '((timestamp . "1703865600"))
|
:data '((timestamp . "1703865600"))
|
||||||
:transform (lambda (text)
|
:transform (lambda (text)
|
||||||
@ -2692,7 +2692,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
(seconds-to-time (string-to-number text)))))
|
(seconds-to-time (string-to-number text)))))
|
||||||
|
|
||||||
;; 大写转换
|
;; 大写转换
|
||||||
(tp-define-layer 'uppercase-text
|
(define-tp uppercase-text ()
|
||||||
:props '(tp-text $content)
|
:props '(tp-text $content)
|
||||||
:data '((content . "hello"))
|
:data '((content . "hello"))
|
||||||
:transform #'upcase)
|
:transform #'upcase)
|
||||||
@ -2707,7 +2707,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
|
|
||||||
### 匿名响应式层
|
### 匿名响应式层
|
||||||
|
|
||||||
即使不使用 `tp-define-layer`,你也可以使用响应式变量。当你在匿名 plist 中使用 `$` 前缀的符号时,tp.el 会自动生成唯一的层名:
|
即使不使用 `define-tp`,你也可以使用响应式变量。当你在匿名 plist 中使用 `$` 前缀的符号时,tp.el 会自动生成唯一的层名:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(defvar my-face-color "blue")
|
(defvar my-face-color "blue")
|
||||||
@ -2724,7 +2724,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
所有文本属性 API(`tp-set`、`tp-match-set`、`tp-regexp-set` 等)现在可以直接接受层名:
|
所有文本属性 API(`tp-set`、`tp-match-set`、`tp-regexp-set` 等)现在可以直接接受层名:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'warning-style
|
(define-tp warning-style ()
|
||||||
:props '(face (:foreground "orange" :weight bold)))
|
:props '(face (:foreground "orange" :weight bold)))
|
||||||
|
|
||||||
;; 使用层名代替 plist
|
;; 使用层名代替 plist
|
||||||
@ -2740,7 +2740,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
层组也可以使用响应式特性:
|
层组也可以使用响应式特性:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer-group 'status-indicators
|
(define-tps status-indicators
|
||||||
'("success" :props (face (:foreground $success-color))
|
'("success" :props (face (:foreground $success-color))
|
||||||
:data ((success-color . "green")))
|
:data ((success-color . "green")))
|
||||||
'("warning" :props (face (:foreground $warning-color))
|
'("warning" :props (face (:foreground $warning-color))
|
||||||
@ -2754,7 +2754,7 @@ tp.el 统一了"自定义文本属性"和"文本属性层"两个概念:
|
|||||||
同时修改多个响应式变量时,每个 `setq` 都会触发一次缓冲区更新。使用 `tp-with-batch-updates` 可以合并所有更改,在结束时一次性应用:
|
同时修改多个响应式变量时,每个 `setq` 都会触发一次缓冲区更新。使用 `tp-with-batch-updates` 可以合并所有更改,在结束时一次性应用:
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
(tp-define-layer 'themed-text
|
(define-tp themed-text ()
|
||||||
:props '(face (:foreground $fg-color :background $bg-color))
|
:props '(face (:foreground $fg-color :background $bg-color))
|
||||||
:data '((fg-color . "white") (bg-color . "black")))
|
:data '((fg-color . "white") (bg-color . "black")))
|
||||||
|
|
||||||
@ -2826,13 +2826,13 @@ tp.el 提供调试模式来帮助理解响应式更新流程:
|
|||||||
(defvar theme-accent "cyan")
|
(defvar theme-accent "cyan")
|
||||||
|
|
||||||
;; 定义主题感知层
|
;; 定义主题感知层
|
||||||
(tp-define-layer 'code-keyword
|
(define-tp code-keyword ()
|
||||||
:props '(face (:foreground $theme-accent :weight bold)))
|
:props '(face (:foreground $theme-accent :weight bold)))
|
||||||
|
|
||||||
(tp-define-layer 'code-comment
|
(define-tp code-comment ()
|
||||||
:props '(face (:foreground "gray" :slant italic)))
|
:props '(face (:foreground "gray" :slant italic)))
|
||||||
|
|
||||||
(tp-define-layer 'code-string
|
(define-tp code-string ()
|
||||||
:props '(face (:foreground "green")))
|
:props '(face (:foreground "green")))
|
||||||
|
|
||||||
;; 将层应用到代码
|
;; 将层应用到代码
|
||||||
|
|||||||
106
tp-tests.el
106
tp-tests.el
@ -1816,7 +1816,7 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(defvar tp-test-var-color "red" "Test color variable.")
|
(defvar tp-test-var-color "red" "Test color variable.")
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-reactive-layer '(face (:foreground $tp-test-var-color)))
|
(define-tp test-reactive-layer () '(face (:foreground $tp-test-var-color)))
|
||||||
;; Check the layer is defined with resolved value
|
;; Check the layer is defined with resolved value
|
||||||
(let ((props (cdr (assoc 'test-reactive-layer tp-layer-alist))))
|
(let ((props (cdr (assoc 'test-reactive-layer tp-layer-alist))))
|
||||||
(should (equal (plist-get (plist-get props 'face) :foreground) "red")))
|
(should (equal (plist-get (plist-get props 'face) :foreground) "red")))
|
||||||
@ -1838,7 +1838,7 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(setq tp-test-reactive-color "red")
|
(setq tp-test-reactive-color "red")
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-reactive-update '(face (:foreground $tp-test-reactive-color)))
|
(define-tp test-reactive-update () '(face (:foreground $tp-test-reactive-color)))
|
||||||
;; Verify initial value
|
;; Verify initial value
|
||||||
(let ((props (cdr (assoc 'test-reactive-update tp-layer-alist))))
|
(let ((props (cdr (assoc 'test-reactive-update tp-layer-alist))))
|
||||||
(should (equal (plist-get (plist-get props 'face) :foreground) "red")))
|
(should (equal (plist-get (plist-get props 'face) :foreground) "red")))
|
||||||
@ -1857,7 +1857,7 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(setq tp-test-region-color "red")
|
(setq tp-test-region-color "red")
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-reactive-region '(face (:foreground $tp-test-region-color)))
|
(define-tp test-reactive-region () '(face (:foreground $tp-test-region-color)))
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
;; Apply the layer to text
|
;; Apply the layer to text
|
||||||
(tp-push-layer 1 6 'test-reactive-region)
|
(tp-push-layer 1 6 'test-reactive-region)
|
||||||
@ -1877,7 +1877,7 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(setq tp-test-reset-color "red")
|
(setq tp-test-reset-color "red")
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-reactive-reset '(face (:foreground $tp-test-reset-color)))
|
(define-tp test-reactive-reset () '(face (:foreground $tp-test-reset-color)))
|
||||||
(should tp-reactive-deps)
|
(should tp-reactive-deps)
|
||||||
(tp-reactive-reset)
|
(tp-reactive-reset)
|
||||||
(should-not tp-reactive-deps))
|
(should-not tp-reactive-deps))
|
||||||
@ -1891,7 +1891,7 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(setq tp-test-reset2-color "red")
|
(setq tp-test-reset2-color "red")
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-reactive-reset2 '(face (:foreground $tp-test-reset2-color)))
|
(define-tp test-reactive-reset2 () '(face (:foreground $tp-test-reset2-color)))
|
||||||
(should tp-reactive-deps)
|
(should tp-reactive-deps)
|
||||||
(tp-layer-reset)
|
(tp-layer-reset)
|
||||||
(should-not tp-reactive-deps))
|
(should-not tp-reactive-deps))
|
||||||
@ -1905,7 +1905,7 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(setq tp-test-group-color "red")
|
(setq tp-test-group-color "red")
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer-group 'test-reactive-group
|
(define-tps test-reactive-group ()
|
||||||
'("first" :props (face (:foreground $tp-test-group-color)))
|
'("first" :props (face (:foreground $tp-test-group-color)))
|
||||||
'("second" :props (face (:foreground "blue"))))
|
'("second" :props (face (:foreground "blue"))))
|
||||||
;; Check the reactive layer is defined with resolved value
|
;; Check the reactive layer is defined with resolved value
|
||||||
@ -1930,7 +1930,7 @@ Returns list of (START END VALUE) intervals."
|
|||||||
(setq tp-test-undef-color "red")
|
(setq tp-test-undef-color "red")
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-undef-reactive '(face (:foreground $tp-test-undef-color)))
|
(define-tp test-undef-reactive () '(face (:foreground $tp-test-undef-color)))
|
||||||
;; Check the dependency is registered
|
;; Check the dependency is registered
|
||||||
(should (assoc 'tp-test-undef-color tp-reactive-deps))
|
(should (assoc 'tp-test-undef-color tp-reactive-deps))
|
||||||
(let* ((deps (cdr (assoc 'tp-test-undef-color tp-reactive-deps)))
|
(let* ((deps (cdr (assoc 'tp-test-undef-color tp-reactive-deps)))
|
||||||
@ -1977,7 +1977,7 @@ This tests the fix for the bug where (tp-set str 'layer-name) would
|
|||||||
incorrectly generate an anonymous tp-name instead of using the layer name."
|
incorrectly generate an anonymous tp-name instead of using the layer name."
|
||||||
(tp-test-with-temp-buffer
|
(tp-test-with-temp-buffer
|
||||||
;; Define a layer with reactive variables
|
;; Define a layer with reactive variables
|
||||||
(tp-define-layer 'my-entire-string-layer :props '(face (:background $my-entire-string-color))
|
(define-tp my-entire-string-layer () :props '(face (:background $my-entire-string-color))
|
||||||
:data '((my-entire-string-color . "blue")))
|
:data '((my-entire-string-color . "blue")))
|
||||||
(let ((str (tp-set " " 'my-entire-string-layer)))
|
(let ((str (tp-set " " 'my-entire-string-layer)))
|
||||||
;; tp-name should be the defined layer name, not an anonymous tp-anon-X
|
;; tp-name should be the defined layer name, not an anonymous tp-anon-X
|
||||||
@ -2275,7 +2275,7 @@ preserving the native text property behavior."
|
|||||||
(setq tp-test-watch-log nil)
|
(setq tp-test-watch-log nil)
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-watch-layer :props '(face (:foreground $tp-test-watch-var))
|
(define-tp test-watch-layer () :props '(face (:foreground $tp-test-watch-var))
|
||||||
:watch '((tp-test-watch-var
|
:watch '((tp-test-watch-var
|
||||||
(lambda (new old layer)
|
(lambda (new old layer)
|
||||||
(push (list new old layer) tp-test-watch-log)))))
|
(push (list new old layer) tp-test-watch-log)))))
|
||||||
@ -2304,7 +2304,7 @@ preserving the native text property behavior."
|
|||||||
(tp-test-with-temp-buffer
|
(tp-test-with-temp-buffer
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-data-layer :props '(face (:foreground $tp-test-data-color))
|
(define-tp test-data-layer () :props '(face (:foreground $tp-test-data-color))
|
||||||
:data '(tp-test-data-extra))
|
:data '(tp-test-data-extra))
|
||||||
;; Check that variables were auto-defined
|
;; Check that variables were auto-defined
|
||||||
(should (boundp 'tp-test-data-color))
|
(should (boundp 'tp-test-data-color))
|
||||||
@ -2325,7 +2325,7 @@ preserving the native text property behavior."
|
|||||||
;; Set up the source variables
|
;; Set up the source variables
|
||||||
(setq tp-test-first-name "John")
|
(setq tp-test-first-name "John")
|
||||||
(setq tp-test-last-name "Doe")
|
(setq tp-test-last-name "Doe")
|
||||||
(tp-define-layer 'test-compute-layer
|
(define-tp test-compute-layer ()
|
||||||
:props '(help-echo $tp-test-full-name)
|
:props '(help-echo $tp-test-full-name)
|
||||||
:data '(tp-test-first-name tp-test-last-name)
|
:data '(tp-test-first-name tp-test-last-name)
|
||||||
:compute '((tp-test-full-name
|
:compute '((tp-test-full-name
|
||||||
@ -2355,7 +2355,7 @@ preserving the native text property behavior."
|
|||||||
(setq tp-test-dc-first "Jane")
|
(setq tp-test-dc-first "Jane")
|
||||||
(setq tp-test-dc-last "Smith")
|
(setq tp-test-dc-last "Smith")
|
||||||
;; Define layer with :data and :compute
|
;; Define layer with :data and :compute
|
||||||
(tp-define-layer 'test-dc-layer
|
(define-tp test-dc-layer ()
|
||||||
:props '(face (:foreground $tp-test-dc-color) help-echo $tp-test-dc-full-name)
|
:props '(face (:foreground $tp-test-dc-color) help-echo $tp-test-dc-full-name)
|
||||||
:data '(tp-test-dc-first tp-test-dc-last)
|
:data '(tp-test-dc-first tp-test-dc-last)
|
||||||
:compute '((tp-test-dc-full-name
|
:compute '((tp-test-dc-full-name
|
||||||
@ -2377,21 +2377,21 @@ preserving the native text property behavior."
|
|||||||
"Test that :watch requires :props to be explicitly specified."
|
"Test that :watch requires :props to be explicitly specified."
|
||||||
(tp-test-with-temp-buffer
|
(tp-test-with-temp-buffer
|
||||||
(should-error
|
(should-error
|
||||||
(tp-define-layer 'test-invalid
|
(define-tp test-invalid ()
|
||||||
:watch '((some-var (lambda (new old layer) nil)))))))
|
:watch '((some-var (lambda (new old layer) nil)))))))
|
||||||
|
|
||||||
(ert-deftest tp-test-define-layer-compute-requires-props ()
|
(ert-deftest tp-test-define-layer-compute-requires-props ()
|
||||||
"Test that :compute requires :props to be explicitly specified."
|
"Test that :compute requires :props to be explicitly specified."
|
||||||
(tp-test-with-temp-buffer
|
(tp-test-with-temp-buffer
|
||||||
(should-error
|
(should-error
|
||||||
(tp-define-layer 'test-invalid
|
(define-tp test-invalid ()
|
||||||
:compute '((some-var (lambda () "computed")))))))
|
:compute '((some-var (lambda () "computed")))))))
|
||||||
|
|
||||||
(ert-deftest tp-test-define-layer-data-requires-props ()
|
(ert-deftest tp-test-define-layer-data-requires-props ()
|
||||||
"Test that :data requires :props to be explicitly specified."
|
"Test that :data requires :props to be explicitly specified."
|
||||||
(tp-test-with-temp-buffer
|
(tp-test-with-temp-buffer
|
||||||
(should-error
|
(should-error
|
||||||
(tp-define-layer 'test-invalid
|
(define-tp test-invalid ()
|
||||||
:data '(some-var)))))
|
:data '(some-var)))))
|
||||||
|
|
||||||
(ert-deftest tp-test-undefine-layer-clears-watch-compute-data ()
|
(ert-deftest tp-test-undefine-layer-clears-watch-compute-data ()
|
||||||
@ -2399,7 +2399,7 @@ preserving the native text property behavior."
|
|||||||
(tp-test-with-temp-buffer
|
(tp-test-with-temp-buffer
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-undef-wcd
|
(define-tp test-undef-wcd ()
|
||||||
:props '(face (:foreground $tp-test-undef-color) help-echo $tp-test-undef-full)
|
:props '(face (:foreground $tp-test-undef-color) help-echo $tp-test-undef-full)
|
||||||
:data '(tp-test-undef-first tp-test-undef-last)
|
:data '(tp-test-undef-first tp-test-undef-last)
|
||||||
:watch '((tp-test-undef-color (lambda (n o l) nil)))
|
:watch '((tp-test-undef-color (lambda (n o l) nil)))
|
||||||
@ -2431,7 +2431,7 @@ preserving the native text property behavior."
|
|||||||
(setq tp-test-group-watch-log nil)
|
(setq tp-test-group-watch-log nil)
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer-group 'test-watch-group
|
(define-tps test-watch-group ()
|
||||||
'("reactive" :props (face (:foreground $tp-test-group-watch-var))
|
'("reactive" :props (face (:foreground $tp-test-group-watch-var))
|
||||||
:watch ((tp-test-group-watch-var
|
:watch ((tp-test-group-watch-var
|
||||||
(lambda (new old layer)
|
(lambda (new old layer)
|
||||||
@ -2458,7 +2458,7 @@ preserving the native text property behavior."
|
|||||||
(progn
|
(progn
|
||||||
(setq tp-test-group-first "Group")
|
(setq tp-test-group-first "Group")
|
||||||
(setq tp-test-group-last "Test")
|
(setq tp-test-group-last "Test")
|
||||||
(tp-define-layer-group 'test-compute-group
|
(define-tps test-compute-group ()
|
||||||
'("computed" :props (help-echo $tp-test-group-full)
|
'("computed" :props (help-echo $tp-test-group-full)
|
||||||
:data (tp-test-group-first tp-test-group-last)
|
:data (tp-test-group-first tp-test-group-last)
|
||||||
:compute '((tp-test-group-full
|
:compute '((tp-test-group-full
|
||||||
@ -2483,7 +2483,7 @@ preserving the native text property behavior."
|
|||||||
(tp-test-with-temp-buffer
|
(tp-test-with-temp-buffer
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-reset-all
|
(define-tp test-reset-all ()
|
||||||
:props '(face (:foreground $tp-test-reset-color) help-echo $tp-test-reset-full)
|
:props '(face (:foreground $tp-test-reset-color) help-echo $tp-test-reset-full)
|
||||||
:data '(tp-test-reset-first tp-test-reset-last)
|
:data '(tp-test-reset-first tp-test-reset-last)
|
||||||
:watch '((tp-test-reset-color (lambda (n o l) nil)))
|
:watch '((tp-test-reset-color (lambda (n o l) nil)))
|
||||||
@ -2514,7 +2514,7 @@ preserving the native text property behavior."
|
|||||||
;; Variables should not exist before
|
;; Variables should not exist before
|
||||||
(should-not (boundp 'tp-test-auto-var1))
|
(should-not (boundp 'tp-test-auto-var1))
|
||||||
(should-not (boundp 'tp-test-auto-var2))
|
(should-not (boundp 'tp-test-auto-var2))
|
||||||
(tp-define-layer 'test-auto-layer :props '(face (:foreground $tp-test-auto-var1))
|
(define-tp test-auto-layer () :props '(face (:foreground $tp-test-auto-var1))
|
||||||
:data '(tp-test-auto-var2))
|
:data '(tp-test-auto-var2))
|
||||||
;; Variables should now exist
|
;; Variables should now exist
|
||||||
(should (boundp 'tp-test-auto-var1))
|
(should (boundp 'tp-test-auto-var1))
|
||||||
@ -2529,7 +2529,7 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define layer with auto-created variable (nil initial value)
|
;; Define layer with auto-created variable (nil initial value)
|
||||||
(tp-define-layer 'test-local-layer :props '(face (:foreground $tp-test-local-color)))
|
(define-tp test-local-layer () :props '(face (:foreground $tp-test-local-color)))
|
||||||
;; Apply layer to text
|
;; Apply layer to text
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
(tp-set 1 6 'test-local-layer)
|
(tp-set 1 6 'test-local-layer)
|
||||||
@ -2548,7 +2548,7 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define layer with :data and :compute
|
;; Define layer with :data and :compute
|
||||||
(tp-define-layer 'test-data-compute-layer
|
(define-tp test-data-compute-layer ()
|
||||||
:props '(help-echo $tp-test-dc-full)
|
:props '(help-echo $tp-test-dc-full)
|
||||||
:data '(tp-test-dc-first tp-test-dc-last)
|
:data '(tp-test-dc-first tp-test-dc-last)
|
||||||
:compute '((tp-test-dc-full
|
:compute '((tp-test-dc-full
|
||||||
@ -2578,7 +2578,7 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define layer with :data having initial values
|
;; Define layer with :data having initial values
|
||||||
(tp-define-layer 'test-data-init-layer
|
(define-tp test-data-init-layer ()
|
||||||
:props '(face (:foreground $tp-test-init-color) help-echo $tp-test-init-name)
|
:props '(face (:foreground $tp-test-init-color) help-echo $tp-test-init-name)
|
||||||
:data '((tp-test-init-color . "blue")
|
:data '((tp-test-init-color . "blue")
|
||||||
(tp-test-init-name . "Initial Name")
|
(tp-test-init-name . "Initial Name")
|
||||||
@ -2605,7 +2605,7 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define a reactive layer
|
;; Define a reactive layer
|
||||||
(tp-define-layer 'test-multi-buf-layer :props '(face (:foreground $tp-test-multi-color)))
|
(define-tp test-multi-buf-layer () :props '(face (:foreground $tp-test-multi-color)))
|
||||||
;; Create first buffer with layer applied
|
;; Create first buffer with layer applied
|
||||||
(setq buf1 (generate-new-buffer " *test-buf1*"))
|
(setq buf1 (generate-new-buffer " *test-buf1*"))
|
||||||
(with-current-buffer buf1
|
(with-current-buffer buf1
|
||||||
@ -2637,7 +2637,7 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define a reactive layer
|
;; Define a reactive layer
|
||||||
(tp-define-layer 'test-global-layer :props '(face (:foreground $tp-test-global-color)))
|
(define-tp test-global-layer () :props '(face (:foreground $tp-test-global-color)))
|
||||||
;; Create first buffer with layer applied
|
;; Create first buffer with layer applied
|
||||||
(setq buf1 (generate-new-buffer " *test-buf1*"))
|
(setq buf1 (generate-new-buffer " *test-buf1*"))
|
||||||
(with-current-buffer buf1
|
(with-current-buffer buf1
|
||||||
@ -2670,7 +2670,7 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; First definition with gray color
|
;; First definition with gray color
|
||||||
(tp-define-layer 'test-redef-layer :props '(face (:background $tp-test-redef-color))
|
(define-tp test-redef-layer () :props '(face (:background $tp-test-redef-color))
|
||||||
:data '((tp-test-redef-color . "gray")))
|
:data '((tp-test-redef-color . "gray")))
|
||||||
;; Check initial value
|
;; Check initial value
|
||||||
(should (equal tp-test-redef-color "gray"))
|
(should (equal tp-test-redef-color "gray"))
|
||||||
@ -2678,7 +2678,7 @@ preserving the native text property behavior."
|
|||||||
(let ((props (cdr (assoc 'test-redef-layer tp-layer-alist))))
|
(let ((props (cdr (assoc 'test-redef-layer tp-layer-alist))))
|
||||||
(should (equal (plist-get (plist-get props 'face) :background) "gray")))
|
(should (equal (plist-get (plist-get props 'face) :background) "gray")))
|
||||||
;; Re-define with different color
|
;; Re-define with different color
|
||||||
(tp-define-layer 'test-redef-layer :props '(face (:background $tp-test-redef-color))
|
(define-tp test-redef-layer () :props '(face (:background $tp-test-redef-color))
|
||||||
:data '((tp-test-redef-color . "blue")))
|
:data '((tp-test-redef-color . "blue")))
|
||||||
;; Check variable is updated
|
;; Check variable is updated
|
||||||
(should (equal tp-test-redef-color "blue"))
|
(should (equal tp-test-redef-color "blue"))
|
||||||
@ -2694,12 +2694,12 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; First definition
|
;; First definition
|
||||||
(tp-define-layer 'test-redef-props :props '(face (:foreground $tp-test-redef-fg))
|
(define-tp test-redef-props () :props '(face (:foreground $tp-test-redef-fg))
|
||||||
:data '((tp-test-redef-fg . "red")))
|
:data '((tp-test-redef-fg . "red")))
|
||||||
(let ((props (cdr (assoc 'test-redef-props tp-layer-alist))))
|
(let ((props (cdr (assoc 'test-redef-props tp-layer-alist))))
|
||||||
(should (equal (plist-get (plist-get props 'face) :foreground) "red")))
|
(should (equal (plist-get (plist-get props 'face) :foreground) "red")))
|
||||||
;; Re-define with different props structure
|
;; Re-define with different props structure
|
||||||
(tp-define-layer 'test-redef-props
|
(define-tp test-redef-props ()
|
||||||
:props '(face (:background $tp-test-redef-bg) help-echo "new")
|
:props '(face (:background $tp-test-redef-bg) help-echo "new")
|
||||||
:data '((tp-test-redef-bg . "yellow")))
|
:data '((tp-test-redef-bg . "yellow")))
|
||||||
;; Check new props are applied
|
;; Check new props are applied
|
||||||
@ -2718,14 +2718,14 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; First definition with $old-var
|
;; First definition with $old-var
|
||||||
(tp-define-layer 'test-redef-deps :props '(face (:foreground $tp-test-old-var))
|
(define-tp test-redef-deps () :props '(face (:foreground $tp-test-old-var))
|
||||||
:data '((tp-test-old-var . "red")))
|
:data '((tp-test-old-var . "red")))
|
||||||
;; Check old var is in dependencies
|
;; Check old var is in dependencies
|
||||||
(should (assoc 'tp-test-old-var tp-reactive-deps))
|
(should (assoc 'tp-test-old-var tp-reactive-deps))
|
||||||
(let ((deps (cdr (assoc 'tp-test-old-var tp-reactive-deps))))
|
(let ((deps (cdr (assoc 'tp-test-old-var tp-reactive-deps))))
|
||||||
(should (assoc 'test-redef-deps deps)))
|
(should (assoc 'test-redef-deps deps)))
|
||||||
;; Re-define with $new-var
|
;; Re-define with $new-var
|
||||||
(tp-define-layer 'test-redef-deps :props '(face (:foreground $tp-test-new-var))
|
(define-tp test-redef-deps () :props '(face (:foreground $tp-test-new-var))
|
||||||
:data '((tp-test-new-var . "blue")))
|
:data '((tp-test-new-var . "blue")))
|
||||||
;; Check old var is no longer in dependencies for this layer
|
;; Check old var is no longer in dependencies for this layer
|
||||||
(when-let ((deps (cdr (assoc 'tp-test-old-var tp-reactive-deps))))
|
(when-let ((deps (cdr (assoc 'tp-test-old-var tp-reactive-deps))))
|
||||||
@ -2749,13 +2749,13 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; First definition with old watcher
|
;; First definition with old watcher
|
||||||
(tp-define-layer 'test-redef-watch :props '(face (:foreground $tp-test-watch-var))
|
(define-tp test-redef-watch () :props '(face (:foreground $tp-test-watch-var))
|
||||||
:data '((tp-test-watch-var . "red"))
|
:data '((tp-test-watch-var . "red"))
|
||||||
:watch '((tp-test-watch-var
|
:watch '((tp-test-watch-var
|
||||||
(lambda (new old layer)
|
(lambda (new old layer)
|
||||||
(push (list 'old new) tp-test-watch-log-old)))))
|
(push (list 'old new) tp-test-watch-log-old)))))
|
||||||
;; Re-define with new watcher
|
;; Re-define with new watcher
|
||||||
(tp-define-layer 'test-redef-watch :props '(face (:foreground $tp-test-watch-var))
|
(define-tp test-redef-watch () :props '(face (:foreground $tp-test-watch-var))
|
||||||
:data '((tp-test-watch-var . "red"))
|
:data '((tp-test-watch-var . "red"))
|
||||||
:watch '((tp-test-watch-var
|
:watch '((tp-test-watch-var
|
||||||
(lambda (new old layer)
|
(lambda (new old layer)
|
||||||
@ -2779,14 +2779,14 @@ preserving the native text property behavior."
|
|||||||
(progn
|
(progn
|
||||||
;; First definition with old compute
|
;; First definition with old compute
|
||||||
(setq tp-test-compute-src "hello")
|
(setq tp-test-compute-src "hello")
|
||||||
(tp-define-layer 'test-redef-compute
|
(define-tp test-redef-compute ()
|
||||||
:props '(help-echo $tp-test-compute-out)
|
:props '(help-echo $tp-test-compute-out)
|
||||||
:data '(tp-test-compute-src)
|
:data '(tp-test-compute-src)
|
||||||
:compute '((tp-test-compute-out
|
:compute '((tp-test-compute-out
|
||||||
(lambda () (upcase tp-test-compute-src)))))
|
(lambda () (upcase tp-test-compute-src)))))
|
||||||
(should (equal tp-test-compute-out "HELLO"))
|
(should (equal tp-test-compute-out "HELLO"))
|
||||||
;; Re-define with different compute
|
;; Re-define with different compute
|
||||||
(tp-define-layer 'test-redef-compute
|
(define-tp test-redef-compute ()
|
||||||
:props '(help-echo $tp-test-compute-out)
|
:props '(help-echo $tp-test-compute-out)
|
||||||
:data '(tp-test-compute-src)
|
:data '(tp-test-compute-src)
|
||||||
:compute '((tp-test-compute-out
|
:compute '((tp-test-compute-out
|
||||||
@ -2806,17 +2806,17 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; First definition with reactive variable
|
;; First definition with reactive variable
|
||||||
(tp-define-layer 'test-reactive-to-static :props '(face (:foreground $tp-test-r2s-color))
|
(define-tp test-reactive-to-static () :props '(face (:foreground $tp-test-r2s-color))
|
||||||
:data '((tp-test-r2s-color . "red")))
|
:data '((tp-test-r2s-color . "red")))
|
||||||
;; Check reactive dependency is registered
|
;; Check reactive dependency is registered
|
||||||
(should (assoc 'tp-test-r2s-color tp-reactive-deps))
|
(should (assoc 'tp-test-r2s-color tp-reactive-deps))
|
||||||
;; Re-define as static (non-reactive)
|
;; Re-define as static (non-reactive)
|
||||||
(tp-define-layer 'test-reactive-to-static '(face bold))
|
(define-tp test-reactive-to-static () '(face bold))
|
||||||
;; Check reactive dependency is cleared
|
;; Check reactive dependency is cleared
|
||||||
(when-let ((deps (cdr (assoc 'tp-test-r2s-color tp-reactive-deps))))
|
(when-let ((deps (cdr (assoc 'tp-test-r2s-color tp-reactive-deps))))
|
||||||
(should-not (assoc 'test-reactive-to-static deps)))
|
(should-not (assoc 'test-reactive-to-static deps)))
|
||||||
;; Check layer has new static props
|
;; Check layer has new static props
|
||||||
(let ((props (cdr (assoc 'test-reactive-to-static tp-layer-alist))))
|
(let ((props (tp-layer-props 'test-reactive-to-static)))
|
||||||
(should (eq (plist-get props 'face) 'bold))))
|
(should (eq (plist-get props 'face) 'bold))))
|
||||||
;; Cleanup
|
;; Cleanup
|
||||||
(ignore-errors (makunbound 'tp-test-r2s-color)))))
|
(ignore-errors (makunbound 'tp-test-r2s-color)))))
|
||||||
@ -2827,13 +2827,13 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; First definition
|
;; First definition
|
||||||
(tp-define-layer-group 'test-redef-group
|
(define-tps test-redef-group ()
|
||||||
'("layer1" :props (face (:background $tp-test-group-color))
|
'("layer1" :props (face (:background $tp-test-group-color))
|
||||||
:data ((tp-test-group-color . "gray"))))
|
:data ((tp-test-group-color . "gray"))))
|
||||||
;; Check initial value
|
;; Check initial value
|
||||||
(should (equal tp-test-group-color "gray"))
|
(should (equal tp-test-group-color "gray"))
|
||||||
;; Re-define with different color
|
;; Re-define with different color
|
||||||
(tp-define-layer-group 'test-redef-group
|
(define-tps test-redef-group ()
|
||||||
'("layer1" :props (face (:background $tp-test-group-color))
|
'("layer1" :props (face (:background $tp-test-group-color))
|
||||||
:data ((tp-test-group-color . "blue"))))
|
:data ((tp-test-group-color . "blue"))))
|
||||||
;; Check variable is updated
|
;; Check variable is updated
|
||||||
@ -2850,7 +2850,7 @@ preserving the native text property behavior."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; First definition
|
;; First definition
|
||||||
(tp-define-layer 'test-redef-applied :props '(face (:background $tp-test-applied-color))
|
(define-tp test-redef-applied () :props '(face (:background $tp-test-applied-color))
|
||||||
:data '((tp-test-applied-color . "gray")))
|
:data '((tp-test-applied-color . "gray")))
|
||||||
;; Apply to text
|
;; Apply to text
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -2858,10 +2858,10 @@ preserving the native text property behavior."
|
|||||||
;; Check initial color
|
;; Check initial color
|
||||||
(should (equal (plist-get (get-text-property 1 'face) :background) "gray"))
|
(should (equal (plist-get (get-text-property 1 'face) :background) "gray"))
|
||||||
;; Re-define with different color
|
;; Re-define with different color
|
||||||
(tp-define-layer 'test-redef-applied :props '(face (:background $tp-test-applied-color))
|
(define-tp test-redef-applied () :props '(face (:background $tp-test-applied-color))
|
||||||
:data '((tp-test-applied-color . "blue")))
|
:data '((tp-test-applied-color . "blue")))
|
||||||
;; The text should now have the new color
|
;; The text should now have the new color
|
||||||
;; This happens because tp-define-layer calls tp--update-layer-regions
|
;; This happens because define-tp calls tp--update-layer-regions
|
||||||
;; at the end to update all text regions with the new properties
|
;; at the end to update all text regions with the new properties
|
||||||
(should (equal (plist-get (get-text-property 1 'face) :background) "blue")))
|
(should (equal (plist-get (get-text-property 1 'face) :background) "blue")))
|
||||||
;; Cleanup
|
;; Cleanup
|
||||||
@ -2948,7 +2948,7 @@ preserving the native text property behavior."
|
|||||||
(setq tp-test-reactive-text "Initial")
|
(setq tp-test-reactive-text "Initial")
|
||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
(tp-define-layer 'test-reactive-text-layer
|
(define-tp test-reactive-text-layer ()
|
||||||
:props '(face bold tp-text $tp-test-reactive-text))
|
:props '(face bold tp-text $tp-test-reactive-text))
|
||||||
;; Apply layer to text
|
;; Apply layer to text
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -2976,7 +2976,7 @@ the source text should be used and the reactive variable should be updated."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define layer with tp-text bound to a reactive variable
|
;; Define layer with tp-text bound to a reactive variable
|
||||||
(tp-define-layer 'test-init-text-layer
|
(define-tp test-init-text-layer ()
|
||||||
:props '(face bold tp-text $tp-test-text-var))
|
:props '(face bold tp-text $tp-test-text-var))
|
||||||
;; Apply layer to string - variable is nil, so source text should be used
|
;; Apply layer to string - variable is nil, so source text should be used
|
||||||
(let ((result (tp-set "2" 'test-init-text-layer)))
|
(let ((result (tp-set "2" 'test-init-text-layer)))
|
||||||
@ -2992,7 +2992,7 @@ the source text should be used and the reactive variable should be updated."
|
|||||||
;; This is necessary because the layer definition caches the resolved
|
;; This is necessary because the layer definition caches the resolved
|
||||||
;; tp-text value, and we want to test the behavior when the variable
|
;; tp-text value, and we want to test the behavior when the variable
|
||||||
;; already has a non-nil value at layer application time.
|
;; already has a non-nil value at layer application time.
|
||||||
(tp-define-layer 'test-init-text-layer
|
(define-tp test-init-text-layer ()
|
||||||
:props '(face bold tp-text $tp-test-text-var))
|
:props '(face bold tp-text $tp-test-text-var))
|
||||||
(let ((result (tp-set "2" 'test-init-text-layer)))
|
(let ((result (tp-set "2" 'test-init-text-layer)))
|
||||||
;; Result should be the variable value "18", not source "2"
|
;; Result should be the variable value "18", not source "2"
|
||||||
@ -3019,7 +3019,7 @@ the inserted text should be that string, not the source text."
|
|||||||
(progn
|
(progn
|
||||||
(setq tp-test-name-part1 "Hello")
|
(setq tp-test-name-part1 "Hello")
|
||||||
(setq tp-test-name-part2 "World")
|
(setq tp-test-name-part2 "World")
|
||||||
(tp-define-layer 'test-computed-text-layer
|
(define-tp test-computed-text-layer ()
|
||||||
:props '(face bold tp-text $tp-test-full-text)
|
:props '(face bold tp-text $tp-test-full-text)
|
||||||
:data '(tp-test-name-part1 tp-test-name-part2)
|
:data '(tp-test-name-part1 tp-test-name-part2)
|
||||||
:compute '((tp-test-full-text
|
:compute '((tp-test-full-text
|
||||||
@ -3346,7 +3346,7 @@ When using tp-set (direct property setting), tp-name is NOT added."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define a reactive layer
|
;; Define a reactive layer
|
||||||
(tp-define-layer 'test-batch-layer
|
(define-tp test-batch-layer ()
|
||||||
:props '(face (:foreground $tp-test-batch-color))
|
:props '(face (:foreground $tp-test-batch-color))
|
||||||
:data '((tp-test-batch-color . "red")))
|
:data '((tp-test-batch-color . "red")))
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -3370,7 +3370,7 @@ When using tp-set (direct property setting), tp-name is NOT added."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define a reactive layer with multiple vars
|
;; Define a reactive layer with multiple vars
|
||||||
(tp-define-layer 'test-multi-batch
|
(define-tp test-multi-batch ()
|
||||||
:props '(face (:foreground $tp-test-fg :background $tp-test-bg))
|
:props '(face (:foreground $tp-test-fg :background $tp-test-bg))
|
||||||
:data '((tp-test-fg . "white") (tp-test-bg . "black")))
|
:data '((tp-test-fg . "white") (tp-test-bg . "black")))
|
||||||
(insert "Hello World")
|
(insert "Hello World")
|
||||||
@ -3427,7 +3427,7 @@ When using tp-set (direct property setting), tp-name is NOT added."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define a layer with transform
|
;; Define a layer with transform
|
||||||
(tp-define-layer 'test-transform-layer
|
(define-tp test-transform-layer ()
|
||||||
:props '(face bold tp-text $tp-test-value)
|
:props '(face bold tp-text $tp-test-value)
|
||||||
:data '((tp-test-value . "hello"))
|
:data '((tp-test-value . "hello"))
|
||||||
:transform #'upcase)
|
:transform #'upcase)
|
||||||
@ -3444,7 +3444,7 @@ When using tp-set (direct property setting), tp-name is NOT added."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define a layer with transform (format as currency)
|
;; Define a layer with transform (format as currency)
|
||||||
(tp-define-layer 'test-currency-layer
|
(define-tp test-currency-layer ()
|
||||||
:props '(face bold tp-text $tp-test-amount)
|
:props '(face bold tp-text $tp-test-amount)
|
||||||
:data '((tp-test-amount . "100"))
|
:data '((tp-test-amount . "100"))
|
||||||
:transform (lambda (text)
|
:transform (lambda (text)
|
||||||
@ -3466,14 +3466,14 @@ When using tp-set (direct property setting), tp-name is NOT added."
|
|||||||
(unwind-protect
|
(unwind-protect
|
||||||
(progn
|
(progn
|
||||||
;; Define with transform
|
;; Define with transform
|
||||||
(tp-define-layer 'test-redef-transform
|
(define-tp test-redef-transform ()
|
||||||
:props '(face bold tp-text $tp-test-text)
|
:props '(face bold tp-text $tp-test-text)
|
||||||
:data '((tp-test-text . "hello"))
|
:data '((tp-test-text . "hello"))
|
||||||
:transform #'upcase)
|
:transform #'upcase)
|
||||||
;; Check transform is registered
|
;; Check transform is registered
|
||||||
(should (assoc 'test-redef-transform tp-layer-transforms))
|
(should (assoc 'test-redef-transform tp-layer-transforms))
|
||||||
;; Redefine without transform
|
;; Redefine without transform
|
||||||
(tp-define-layer 'test-redef-transform
|
(define-tp test-redef-transform ()
|
||||||
:props '(face bold tp-text $tp-test-text)
|
:props '(face bold tp-text $tp-test-text)
|
||||||
:data '((tp-test-text . "hello")))
|
:data '((tp-test-text . "hello")))
|
||||||
;; Transform should be removed
|
;; Transform should be removed
|
||||||
|
|||||||
93
tp.el
93
tp.el
@ -2300,7 +2300,7 @@ Example:
|
|||||||
;;;============================================================================
|
;;;============================================================================
|
||||||
|
|
||||||
(defun tp--parse-define-layer-args (args)
|
(defun tp--parse-define-layer-args (args)
|
||||||
"Parse ARGS for tp-define-layer function.
|
"Parse ARGS for tp--define-layer-internal function.
|
||||||
Returns plist with keys :props, :data, :watch, :compute, :transform.
|
Returns plist with keys :props, :data, :watch, :compute, :transform.
|
||||||
- Keyword arguments: :props PLIST [:data DATA] [:watch WATCH] [:compute COMPUTE] [:transform FN]"
|
- Keyword arguments: :props PLIST [:data DATA] [:watch WATCH] [:compute COMPUTE] [:transform FN]"
|
||||||
(let (props data watch compute transform has-keywords)
|
(let (props data watch compute transform has-keywords)
|
||||||
@ -2318,7 +2318,7 @@ Returns plist with keys :props, :data, :watch, :compute, :transform.
|
|||||||
(:watch (setq watch (cadr rest) rest (cddr rest)))
|
(:watch (setq watch (cadr rest) rest (cddr rest)))
|
||||||
(:compute (setq compute (cadr rest) rest (cddr rest)))
|
(:compute (setq compute (cadr rest) rest (cddr rest)))
|
||||||
(:transform (setq transform (cadr rest) rest (cddr rest)))
|
(:transform (setq transform (cadr rest) rest (cddr rest)))
|
||||||
(_ (error "Unknown keyword in tp-define-layer: %s" (car rest))))))
|
(_ (error "Unknown keyword in tp--define-layer-internal: %s" (car rest))))))
|
||||||
;; Validate: if :watch, :compute, or :data present, :props must be present
|
;; Validate: if :watch, :compute, or :data present, :props must be present
|
||||||
(when (and (or watch compute data) (null props))
|
(when (and (or watch compute data) (null props))
|
||||||
(error "When using :watch, :compute, or :data, :props must be explicitly specified")))
|
(error "When using :watch, :compute, or :data, :props must be explicitly specified")))
|
||||||
@ -2326,20 +2326,20 @@ Returns plist with keys :props, :data, :watch, :compute, :transform.
|
|||||||
((and (= (length args) 1)
|
((and (= (length args) 1)
|
||||||
(listp (car args)))
|
(listp (car args)))
|
||||||
(setq props (car args)))
|
(setq props (car args)))
|
||||||
(t (error "Invalid tp-define-layer format")))
|
(t (error "Invalid tp--define-layer-internal format")))
|
||||||
(list :props props :data data :watch watch :compute compute :transform transform)))
|
(list :props props :data data :watch watch :compute compute :transform transform)))
|
||||||
|
|
||||||
(defun tp-define-layer (name &rest args)
|
(defun tp--define-layer-internal (name &rest args)
|
||||||
"Define a single text property layer named NAME.
|
"Define a single text property layer named NAME.
|
||||||
|
|
||||||
This function supports two formats:
|
This function supports two formats:
|
||||||
|
|
||||||
Format 1 - Direct plist (no :watch/:compute/:data/:transform support):
|
Format 1 - Direct plist (no :watch/:compute/:data/:transform support):
|
||||||
(tp-define-layer \\='layer-name
|
(tp--define-layer-internal \\='layer-name
|
||||||
\\='(display \"🌑\" face (:height 1.0)))
|
\\='(display \"🌑\" face (:height 1.0)))
|
||||||
|
|
||||||
Format 2 - With :props, :data, :watch, :compute, and/or :transform (Vue 3 style reactivity):
|
Format 2 - With :props, :data, :watch, :compute, and/or :transform (Vue 3 style reactivity):
|
||||||
(tp-define-layer \\='layer-name
|
(tp--define-layer-internal \\='layer-name
|
||||||
;; props: $-prefixed symbols are reactive variables; auto-defined if not bound
|
;; props: $-prefixed symbols are reactive variables; auto-defined if not bound
|
||||||
:props \\='(face (:foreground $my-color) help-echo $full-name)
|
:props \\='(face (:foreground $my-color) help-echo $full-name)
|
||||||
;; data: additional reactive variables not used in props; auto-defined if not bound
|
;; data: additional reactive variables not used in props; auto-defined if not bound
|
||||||
@ -2444,17 +2444,17 @@ The layer is stored in `tp-layer-alist'."
|
|||||||
(defmacro define-tp (name arglist &rest body)
|
(defmacro define-tp (name arglist &rest body)
|
||||||
"Define a text property layer named NAME.
|
"Define a text property layer named NAME.
|
||||||
|
|
||||||
This macro supports three formats:
|
This macro supports four formats:
|
||||||
|
|
||||||
Format 1 - Non-parameterized simple (empty arglist, simple body):
|
Format 1 - Non-parameterized simple (empty arglist, simple body):
|
||||||
(define-tp tp-bold ()
|
(define-tp tp-bold ()
|
||||||
\\='(face bold))
|
\\='(face bold))
|
||||||
|
|
||||||
Format 2 - Parameterized (single argument):
|
Format 2 - Parameterized simple (single argument, simple body):
|
||||||
(define-tp tp-space (pixel)
|
(define-tp tp-space (pixel)
|
||||||
\\=`(display (space :width (,pixel))))
|
\\=`(display (space :width (,pixel))))
|
||||||
|
|
||||||
Format 3 - With reactive features (supports :props, :data, :compute, :watch, :transform):
|
Format 3 - Non-parameterized with reactive features:
|
||||||
(define-tp my-layer ()
|
(define-tp my-layer ()
|
||||||
:props \\='(face (:foreground $my-color))
|
:props \\='(face (:foreground $my-color))
|
||||||
:data \\='((my-color . \"red\"))
|
:data \\='((my-color . \"red\"))
|
||||||
@ -2462,6 +2462,12 @@ Format 3 - With reactive features (supports :props, :data, :compute, :watch, :tr
|
|||||||
:watch \\='((my-color (lambda (new old layer) (message \"Color changed!\"))))
|
:watch \\='((my-color (lambda (new old layer) (message \"Color changed!\"))))
|
||||||
:transform (lambda (text) (upcase text)))
|
:transform (lambda (text) (upcase text)))
|
||||||
|
|
||||||
|
Format 4 - Parameterized with reactive features:
|
||||||
|
(define-tp my-color-layer (color)
|
||||||
|
:props \\=`(face (:foreground ,color))
|
||||||
|
:data \\='((my-var . \"value\"))
|
||||||
|
:compute ...)
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
(tp-set \"emacs\" \\='tp-bold t)
|
(tp-set \"emacs\" \\='tp-bold t)
|
||||||
(tp-set 0 5 \\='(tp-bold t) \"emacs\")
|
(tp-set 0 5 \\='(tp-bold t) \"emacs\")
|
||||||
@ -2474,7 +2480,7 @@ ARGLIST must be either:
|
|||||||
BODY is either:
|
BODY is either:
|
||||||
- A single property list expression (simple format)
|
- A single property list expression (simple format)
|
||||||
- Keyword arguments starting with :props, :data, :compute, :watch, or :transform
|
- Keyword arguments starting with :props, :data, :compute, :watch, or :transform
|
||||||
(reactive format - only supported for non-parameterized layers)
|
(reactive format)
|
||||||
|
|
||||||
Note: NAME cannot be a built-in Emacs text property name like `face',
|
Note: NAME cannot be a built-in Emacs text property name like `face',
|
||||||
`display', `invisible', etc. See `tp--builtin-text-properties' for the
|
`display', `invisible', etc. See `tp--builtin-text-properties' for the
|
||||||
@ -2489,10 +2495,15 @@ complete list of reserved names."
|
|||||||
(let ((first-elem (car body)))
|
(let ((first-elem (car body)))
|
||||||
(if (and (keywordp first-elem)
|
(if (and (keywordp first-elem)
|
||||||
(memq first-elem '(:props :data :compute :watch :transform)))
|
(memq first-elem '(:props :data :compute :watch :transform)))
|
||||||
;; Reactive format - use tp-define-layer
|
;; Reactive format
|
||||||
(if arglist
|
(if arglist
|
||||||
(error "define-tp: reactive features (:props, :data, etc.) are only supported for non-parameterized layers")
|
;; Parameterized reactive: store as function that calls tp--define-layer-internal
|
||||||
`(tp-define-layer ',name ,@body))
|
(let ((arg (car arglist)))
|
||||||
|
`(tp--define-layer-parameterized-reactive
|
||||||
|
',name ',arglist
|
||||||
|
(lambda (,arg) (list ,@body))))
|
||||||
|
;; Non-parameterized reactive: use tp--define-layer-internal directly
|
||||||
|
`(tp--define-layer-internal ',name ,@body))
|
||||||
;; Simple format (original behavior)
|
;; Simple format (original behavior)
|
||||||
(let ((simple-body (car body)))
|
(let ((simple-body (car body)))
|
||||||
(cond
|
(cond
|
||||||
@ -2506,19 +2517,47 @@ complete list of reserved names."
|
|||||||
(t
|
(t
|
||||||
(error "define-tp ARGLIST must be empty or contain exactly one symbol")))))))
|
(error "define-tp ARGLIST must be empty or contain exactly one symbol")))))))
|
||||||
|
|
||||||
|
(defun tp--define-layer-parameterized-reactive (name arglist body-fn)
|
||||||
|
"Define a parameterized layer NAME with ARGLIST and reactive BODY-FN.
|
||||||
|
BODY-FN is a function that takes the parameter and returns a keyword plist
|
||||||
|
like (:props ... :data ... :compute ... :watch ... :transform ...).
|
||||||
|
The layer is stored and evaluated when tp-layer-props-with-arg is called."
|
||||||
|
;; Store the parameterized reactive definition
|
||||||
|
;; Format: (ARGLIST BODY-FN) where BODY-FN returns keyword plist
|
||||||
|
(let ((entry (list arglist body-fn)))
|
||||||
|
(if (assoc name tp-layer-alist)
|
||||||
|
(setf (cdr (assoc name tp-layer-alist)) entry)
|
||||||
|
(push (cons name entry) tp-layer-alist)))
|
||||||
|
(assoc name tp-layer-alist))
|
||||||
|
|
||||||
(defun tp--define-layer-unified (name arglist body)
|
(defun tp--define-layer-unified (name arglist body)
|
||||||
"Define a layer NAME with ARGLIST and BODY using unified structure.
|
"Define a layer NAME with ARGLIST and BODY using unified structure.
|
||||||
For non-parameterized layers, ARGLIST is nil and BODY is the evaluated plist.
|
For non-parameterized layers, ARGLIST is nil and BODY is the evaluated plist.
|
||||||
For parameterized layers, ARGLIST contains one symbol and BODY is the unevaluated form.
|
For parameterized layers, ARGLIST contains one symbol and BODY is the unevaluated form.
|
||||||
Stores the layer in `tp-layer-alist' with format: (LAYER-NAME ARGLIST BODY-FORM)."
|
Stores the layer in `tp-layer-alist' with format: (LAYER-NAME ARGLIST BODY-FORM).
|
||||||
;; Store in tp-layer-alist with unified format: (LAYER-NAME ARGLIST BODY-FORM)
|
|
||||||
;; For non-parameterized, quote the body so eval returns the plist
|
For non-parameterized layers, if BODY contains reactive symbols ($-prefixed),
|
||||||
(let ((stored-body (if arglist body `',body)))
|
delegates to `tp--define-layer-internal' for proper reactive handling."
|
||||||
(let ((entry (list arglist stored-body)))
|
(if arglist
|
||||||
(if (assoc name tp-layer-alist)
|
;; Parameterized - store for later evaluation
|
||||||
(setf (cdr (assoc name tp-layer-alist)) entry)
|
(let ((entry (list arglist body)))
|
||||||
(push (cons name entry) tp-layer-alist))))
|
(if (assoc name tp-layer-alist)
|
||||||
(assoc name tp-layer-alist))
|
(setf (cdr (assoc name tp-layer-alist)) entry)
|
||||||
|
(push (cons name entry) tp-layer-alist))
|
||||||
|
(assoc name tp-layer-alist))
|
||||||
|
;; Non-parameterized - check for reactive symbols
|
||||||
|
(let ((reactive-syms (tp--collect-reactive-symbols body)))
|
||||||
|
(if reactive-syms
|
||||||
|
;; Has reactive symbols - use tp--define-layer-internal for proper handling
|
||||||
|
(tp--define-layer-internal name body)
|
||||||
|
;; No reactive symbols - store as static layer
|
||||||
|
;; Clean up old reactive dependencies if the layer was previously reactive
|
||||||
|
(tp--unregister-reactive-deps name)
|
||||||
|
(let ((entry (list nil `',body)))
|
||||||
|
(if (assoc name tp-layer-alist)
|
||||||
|
(setf (cdr (assoc name tp-layer-alist)) entry)
|
||||||
|
(push (cons name entry) tp-layer-alist))
|
||||||
|
(assoc name tp-layer-alist))))))
|
||||||
|
|
||||||
(defun tp--layer-group-element-format (element)
|
(defun tp--layer-group-element-format (element)
|
||||||
"Determine the format type of ELEMENT.
|
"Determine the format type of ELEMENT.
|
||||||
@ -2639,7 +2678,7 @@ COMPUTE is the list of computed variable definitions."
|
|||||||
(tp--update-layer-regions layer-name)))
|
(tp--update-layer-regions layer-name)))
|
||||||
layer-name))
|
layer-name))
|
||||||
|
|
||||||
(defun tp-define-layer-group (name &rest elements)
|
(defun tp--define-layer-internal-group (name &rest elements)
|
||||||
"Define a layer group named NAME containing multiple layers.
|
"Define a layer group named NAME containing multiple layers.
|
||||||
|
|
||||||
This function accepts a list of layer definitions in ELEMENTS.
|
This function accepts a list of layer definitions in ELEMENTS.
|
||||||
@ -2654,7 +2693,7 @@ Each element in ELEMENTS should be one of:
|
|||||||
All property lists should be evaluated (quoted in the call).
|
All property lists should be evaluated (quoted in the call).
|
||||||
|
|
||||||
Example:
|
Example:
|
||||||
(tp-define-layer-group \\='my-group
|
(tp--define-layer-internal-group \\='my-group
|
||||||
\\='existing-layer
|
\\='existing-layer
|
||||||
\\='(face bold)
|
\\='(face bold)
|
||||||
\\='(\"named\" . (face italic))
|
\\='(\"named\" . (face italic))
|
||||||
@ -2707,8 +2746,8 @@ ELEMENTS is the list of layer definitions."
|
|||||||
(setf (cdr (assoc name tp-layer-groups)) entry)
|
(setf (cdr (assoc name tp-layer-groups)) entry)
|
||||||
(push (cons name entry) tp-layer-groups))
|
(push (cons name entry) tp-layer-groups))
|
||||||
(assoc name tp-layer-groups))
|
(assoc name tp-layer-groups))
|
||||||
;; Non-parameterized - define immediately using tp-define-layer-group
|
;; Non-parameterized - define immediately using tp--define-layer-internal-group
|
||||||
(apply #'tp-define-layer-group name elements)))
|
(apply #'tp--define-layer-internal-group name elements)))
|
||||||
|
|
||||||
(defun tp--define-layer-group-unified (name arglist body-form)
|
(defun tp--define-layer-group-unified (name arglist body-form)
|
||||||
"Define a parameterized layer group NAME with ARGLIST and BODY-FORM.
|
"Define a parameterized layer group NAME with ARGLIST and BODY-FORM.
|
||||||
@ -3192,7 +3231,7 @@ Returns a list of (START END PROPERTIES) for matching intervals."
|
|||||||
Used by layer stack functions that need tp-name for identification.
|
Used by layer stack functions that need tp-name for identification.
|
||||||
|
|
||||||
LAYER-SPEC can be:
|
LAYER-SPEC can be:
|
||||||
- A symbol (non-parameterized layer name from define-tp or tp-define-layer)
|
- A symbol (non-parameterized layer name from define-tp or tp--define-layer-internal)
|
||||||
- A list (LAYER-NAME ARG) for parameterized layers from define-tp
|
- A list (LAYER-NAME ARG) for parameterized layers from define-tp
|
||||||
- A plist for inline layer definition
|
- A plist for inline layer definition
|
||||||
- A list (NAME &rest PLIST) for named inline layer"
|
- A list (NAME &rest PLIST) for named inline layer"
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user