Update define-tp format: use empty arglist () for non-parameterized layers
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
parent
0b44d1f57b
commit
a24bd264c1
63
README.md
63
README.md
@ -58,6 +58,7 @@
|
||||
- [Property Layer Definition](#property-layer-definition)
|
||||
- [tp-define-layer](#tp-define-layer---define-single-layer)
|
||||
- [tp-define-layer-group](#tp-define-layer-group---define-layer-group)
|
||||
- [define-tp / define-tp-group](#define-tp--define-tp-group---convenience-macros)
|
||||
- [tp-layer-props / tp-group-props](#tp-layer-props--tp-group-props)
|
||||
- [tp-undefine-layer / tp-undefine-group](#tp-undefine-layer--tp-undefine-group)
|
||||
- [tp-layer-reset](#tp-layer-reset)
|
||||
@ -338,6 +339,8 @@ A complete overview of all tp.el functions organized by category:
|
||||
|----------|-------------|
|
||||
| [`tp-define-layer`](#tp-define-layer---define-single-layer) | Define a single layer with optional reactive features (:props, :data, :watch, :compute) |
|
||||
| [`tp-define-layer-group`](#tp-define-layer-group---define-layer-group) | Define a group of layers with optional reactive features |
|
||||
| [`define-tp`](#define-tp--define-tp-group---convenience-macros) | Convenience macro for defining layers (supports parameterized layers) |
|
||||
| [`define-tp-group`](#define-tp--define-tp-group---convenience-macros) | Convenience macro for defining layer groups |
|
||||
| [`tp-layer-props`](#tp-layer-props--tp-group-props) | Get properties for a layer |
|
||||
| [`tp-group-props`](#tp-layer-props--tp-group-props) | Get properties for all layers in a group |
|
||||
| [`tp-undefine-layer`](#tp-undefine-layer--tp-undefine-group) | Remove layer definition |
|
||||
@ -1479,6 +1482,66 @@ The first layer in the definition is the top layer (visible by default).
|
||||
|
||||
---
|
||||
|
||||
#### `define-tp` / `define-tp-group` - Convenience Macros
|
||||
|
||||
`define-tp` and `define-tp-group` are convenience macros that provide a more concise syntax for `tp-define-layer` and `tp-define-layer-group`.
|
||||
|
||||
**`define-tp` - Define Single Layer**
|
||||
|
||||
Supports two formats:
|
||||
|
||||
**Format 1 - Non-parameterized (empty arglist):**
|
||||
|
||||
```elisp
|
||||
(define-tp tp-bold ()
|
||||
'(face bold))
|
||||
```
|
||||
|
||||
**Format 2 - Parameterized (with a single parameter):**
|
||||
|
||||
```elisp
|
||||
(define-tp tp-space (pixel)
|
||||
`(display (space :width (,pixel))))
|
||||
```
|
||||
|
||||
**Usage with `tp-set`:**
|
||||
|
||||
For non-parameterized layers, use `t` as the value:
|
||||
|
||||
```elisp
|
||||
;; Entire string
|
||||
(tp-set "emacs" 'tp-bold t)
|
||||
;; => #("emacs" 0 5 (tp-name tp-bold face bold))
|
||||
|
||||
;; Region (with plist-like format)
|
||||
(tp-set 0 5 '(tp-bold t) "emacs")
|
||||
;; => #("emacs" 0 5 (tp-name tp-bold face bold))
|
||||
```
|
||||
|
||||
For parameterized layers, pass the argument value:
|
||||
|
||||
```elisp
|
||||
;; Entire string
|
||||
(tp-set "emacs" 'tp-space 2)
|
||||
;; => #("emacs" 0 5 (tp-name tp-space display (space :width (2))))
|
||||
|
||||
;; Region (with plist-like format)
|
||||
(tp-set 0 5 '(tp-space 2) "emacs")
|
||||
;; => #("emacs" 0 5 (tp-name tp-space display (space :width (2))))
|
||||
```
|
||||
|
||||
**`define-tp-group` - Define Layer Group**
|
||||
|
||||
Convenience macro wrapping `tp-define-layer-group`:
|
||||
|
||||
```elisp
|
||||
(define-tp-group tp-moon-phases
|
||||
'(display "🌑")
|
||||
'(display "🌕"))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `tp-layer-props` / `tp-group-props`
|
||||
|
||||
```elisp
|
||||
|
||||
63
README_CN.md
63
README_CN.md
@ -57,6 +57,7 @@
|
||||
- [属性层定义](#属性层定义)
|
||||
- [tp-define-layer](#tp-define-layer---定义单个属性层)
|
||||
- [tp-define-layer-group](#tp-define-layer-group---定义属性层组)
|
||||
- [define-tp / define-tp-group](#define-tp--define-tp-group---便捷宏)
|
||||
- [tp-layer-props / tp-group-props](#tp-layer-props--tp-group-props)
|
||||
- [tp-undefine-layer / tp-undefine-group](#tp-undefine-layer--tp-undefine-group)
|
||||
- [tp-layer-reset](#tp-layer-reset)
|
||||
@ -337,6 +338,8 @@ tp.el 所有函数按类别组织的完整概览:
|
||||
|------|------|
|
||||
| [`tp-define-layer`](#tp-define-layer---定义单个属性层) | 定义单个属性层,支持响应式特性(:props、:data、:watch、:compute) |
|
||||
| [`tp-define-layer-group`](#tp-define-layer-group---定义属性层组) | 定义属性层组,支持响应式特性 |
|
||||
| [`define-tp`](#define-tp--define-tp-group---便捷宏) | 定义属性层的便捷宏(支持参数化属性层) |
|
||||
| [`define-tp-group`](#define-tp--define-tp-group---便捷宏) | 定义属性层组的便捷宏 |
|
||||
| [`tp-layer-props`](#tp-layer-props--tp-group-props) | 获取属性层的属性 |
|
||||
| [`tp-group-props`](#tp-layer-props--tp-group-props) | 获取属性层组中所有属性层的属性 |
|
||||
| [`tp-undefine-layer`](#tp-undefine-layer--tp-undefine-group) | 移除属性层定义 |
|
||||
@ -1468,6 +1471,66 @@ Emacs 的 `text-property-search-forward` 和 `text-property-search-backward` 的
|
||||
|
||||
---
|
||||
|
||||
#### `define-tp` / `define-tp-group` - 便捷宏
|
||||
|
||||
`define-tp` 和 `define-tp-group` 是便捷宏,为 `tp-define-layer` 和 `tp-define-layer-group` 提供更简洁的语法。
|
||||
|
||||
**`define-tp` - 定义单个属性层**
|
||||
|
||||
支持两种格式:
|
||||
|
||||
**格式一 - 无参数(空参数列表):**
|
||||
|
||||
```elisp
|
||||
(define-tp tp-bold ()
|
||||
'(face bold))
|
||||
```
|
||||
|
||||
**格式二 - 有参数(带单个参数):**
|
||||
|
||||
```elisp
|
||||
(define-tp tp-space (pixel)
|
||||
`(display (space :width (,pixel))))
|
||||
```
|
||||
|
||||
**`tp-set` 用法:**
|
||||
|
||||
对于无参数属性层,使用 `t` 作为值:
|
||||
|
||||
```elisp
|
||||
;; 整个字符串
|
||||
(tp-set "emacs" 'tp-bold t)
|
||||
;; => #("emacs" 0 5 (tp-name tp-bold face bold))
|
||||
|
||||
;; 区域(使用类似 plist 的格式)
|
||||
(tp-set 0 5 '(tp-bold t) "emacs")
|
||||
;; => #("emacs" 0 5 (tp-name tp-bold face bold))
|
||||
```
|
||||
|
||||
对于有参数属性层,传递参数值:
|
||||
|
||||
```elisp
|
||||
;; 整个字符串
|
||||
(tp-set "emacs" 'tp-space 2)
|
||||
;; => #("emacs" 0 5 (tp-name tp-space display (space :width (2))))
|
||||
|
||||
;; 区域(使用类似 plist 的格式)
|
||||
(tp-set 0 5 '(tp-space 2) "emacs")
|
||||
;; => #("emacs" 0 5 (tp-name tp-space display (space :width (2))))
|
||||
```
|
||||
|
||||
**`define-tp-group` - 定义属性层组**
|
||||
|
||||
包装 `tp-define-layer-group` 的便捷宏:
|
||||
|
||||
```elisp
|
||||
(define-tp-group tp-moon-phases
|
||||
'(display "🌑")
|
||||
'(display "🌕"))
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
#### `tp-layer-props` / `tp-group-props`
|
||||
|
||||
```elisp
|
||||
|
||||
46
tp-tests.el
46
tp-tests.el
@ -3123,13 +3123,34 @@ the inserted text should be that string, not the source text."
|
||||
;;; ============================================================
|
||||
|
||||
(ert-deftest tp-test-define-tp-non-parameterized ()
|
||||
"Test define-tp with non-parameterized format."
|
||||
"Test define-tp with non-parameterized format (empty arglist)."
|
||||
(tp-test-with-temp-buffer
|
||||
(define-tp tp-bold
|
||||
(define-tp tp-bold ()
|
||||
'(face bold))
|
||||
(should (assoc 'tp-bold tp-layer-alist))
|
||||
(should (equal (cdr (assoc 'tp-bold tp-layer-alist)) '(face bold)))))
|
||||
|
||||
(ert-deftest tp-test-define-tp-non-parameterized-usage-string ()
|
||||
"Test non-parameterized layer usage with string: (tp-set string 'layer-name t)."
|
||||
(tp-test-with-temp-buffer
|
||||
(define-tp tp-bold ()
|
||||
'(face bold))
|
||||
(let ((result (tp-set "emacs" 'tp-bold t)))
|
||||
;; Result should have the correct properties
|
||||
(should (eq (get-text-property 0 'tp-name result) 'tp-bold))
|
||||
(should (eq (get-text-property 0 'face result) 'bold)))))
|
||||
|
||||
(ert-deftest tp-test-define-tp-non-parameterized-usage-region ()
|
||||
"Test non-parameterized layer usage with region: (tp-set start end '(layer-name t))."
|
||||
(tp-test-with-temp-buffer
|
||||
(insert "emacs")
|
||||
(define-tp tp-bold ()
|
||||
'(face bold))
|
||||
(tp-set 1 6 '(tp-bold t))
|
||||
;; Check properties in buffer
|
||||
(should (eq (tp-at 1 'tp-name) 'tp-bold))
|
||||
(should (eq (tp-at 1 'face) 'bold))))
|
||||
|
||||
(ert-deftest tp-test-define-tp-parameterized ()
|
||||
"Test define-tp with parameterized format."
|
||||
(tp-test-with-temp-buffer
|
||||
@ -3162,27 +3183,6 @@ the inserted text should be that string, not the source text."
|
||||
(should (eq (tp-at 1 'tp-name) 'tp-space))
|
||||
(should (equal (tp-at 1 'display) '(space :width (5))))))
|
||||
|
||||
(ert-deftest tp-test-define-tp-non-parameterized-usage-string ()
|
||||
"Test non-parameterized layer usage with string: (tp-set string 'layer-name t)."
|
||||
(tp-test-with-temp-buffer
|
||||
(define-tp tp-bold
|
||||
'(face bold))
|
||||
(let ((result (tp-set "emacs" 'tp-bold t)))
|
||||
;; Result should have the correct properties
|
||||
(should (eq (get-text-property 0 'tp-name result) 'tp-bold))
|
||||
(should (eq (get-text-property 0 'face result) 'bold)))))
|
||||
|
||||
(ert-deftest tp-test-define-tp-non-parameterized-usage-region ()
|
||||
"Test non-parameterized layer usage with region: (tp-set start end '(layer-name t))."
|
||||
(tp-test-with-temp-buffer
|
||||
(insert "emacs")
|
||||
(define-tp tp-bold
|
||||
'(face bold))
|
||||
(tp-set 1 6 '(tp-bold t))
|
||||
;; Check properties in buffer
|
||||
(should (eq (tp-at 1 'tp-name) 'tp-bold))
|
||||
(should (eq (tp-at 1 'face) 'bold))))
|
||||
|
||||
(ert-deftest tp-test-define-tp-parameterized-backquote ()
|
||||
"Test parameterized layer with backquote syntax."
|
||||
(tp-test-with-temp-buffer
|
||||
|
||||
43
tp.el
43
tp.el
@ -2130,14 +2130,13 @@ The layer is stored in `tp-layer-alist'."
|
||||
(tp--update-layer-regions name)
|
||||
(assoc name tp-layer-alist)))))
|
||||
|
||||
(defmacro define-tp (name &rest args)
|
||||
"Define a single text property layer named NAME.
|
||||
(defmacro define-tp (name arglist body)
|
||||
"Define a text property layer named NAME.
|
||||
|
||||
This macro provides a convenient syntax for `tp-define-layer'.
|
||||
Supports two formats: with parameters and without parameters.
|
||||
This macro supports two formats:
|
||||
|
||||
Format 1 - Without parameters (static properties):
|
||||
(define-tp tp-bold
|
||||
Format 1 - Non-parameterized (empty arglist):
|
||||
(define-tp tp-bold ()
|
||||
\\='(face bold))
|
||||
|
||||
Usage:
|
||||
@ -2145,7 +2144,7 @@ Usage:
|
||||
(tp-set 0 5 \\='(tp-bold t) \"emacs\")
|
||||
;; => #(\"emacs\" 0 5 (tp-name tp-bold face bold))
|
||||
|
||||
Format 2 - With a single parameter:
|
||||
Format 2 - Parameterized (single argument):
|
||||
(define-tp tp-space (pixel)
|
||||
\\=`(display (space :width (,pixel))))
|
||||
|
||||
@ -2154,19 +2153,25 @@ Usage:
|
||||
(tp-set 0 5 \\='(tp-space 2) \"emacs\")
|
||||
;; => #(\"emacs\" 0 5 (tp-name tp-space display (space :width (2))))
|
||||
|
||||
Note: The parameterized form stores the body as a function that takes
|
||||
the parameter and returns the resolved property list."
|
||||
ARGLIST must be either:
|
||||
- An empty list () for non-parameterized layers
|
||||
- A list containing exactly one symbol for parameterized layers
|
||||
|
||||
BODY is the property list expression. For parameterized layers,
|
||||
it will be evaluated with the argument bound."
|
||||
(declare (indent defun))
|
||||
(if (and (car args) (listp (car args)) (not (eq (caar args) 'quote)))
|
||||
;; Parameterized form: (define-tp name (arg) body)
|
||||
(let ((arglist (car args))
|
||||
(body (cadr args)))
|
||||
(unless (and (= (length arglist) 1)
|
||||
(symbolp (car arglist)))
|
||||
(error "define-tp with parameters only supports exactly one argument"))
|
||||
`(tp--define-parameterized-layer ',name ',arglist ',body))
|
||||
;; Non-parameterized form: (define-tp name 'props) or (define-tp name :props 'props ...)
|
||||
`(tp-define-layer ',name ,@args)))
|
||||
(unless (listp arglist)
|
||||
(error "define-tp ARGLIST must be a list"))
|
||||
(cond
|
||||
;; Non-parameterized: empty arglist
|
||||
((null arglist)
|
||||
`(tp-define-layer ',name ,body))
|
||||
;; Parameterized: single argument
|
||||
((and (= (length arglist) 1)
|
||||
(symbolp (car arglist)))
|
||||
`(tp--define-parameterized-layer ',name ',arglist ',body))
|
||||
(t
|
||||
(error "define-tp ARGLIST must be empty or contain exactly one symbol"))))
|
||||
|
||||
(defun tp--define-parameterized-layer (name arglist body)
|
||||
"Define a parameterized layer NAME with ARGLIST and BODY.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user