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)
|
- [Property Layer Definition](#property-layer-definition)
|
||||||
- [tp-define-layer](#tp-define-layer---define-single-layer)
|
- [tp-define-layer](#tp-define-layer---define-single-layer)
|
||||||
- [tp-define-layer-group](#tp-define-layer-group---define-layer-group)
|
- [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-layer-props / tp-group-props](#tp-layer-props--tp-group-props)
|
||||||
- [tp-undefine-layer / tp-undefine-group](#tp-undefine-layer--tp-undefine-group)
|
- [tp-undefine-layer / tp-undefine-group](#tp-undefine-layer--tp-undefine-group)
|
||||||
- [tp-layer-reset](#tp-layer-reset)
|
- [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`](#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 |
|
| [`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-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-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 |
|
| [`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`
|
#### `tp-layer-props` / `tp-group-props`
|
||||||
|
|
||||||
```elisp
|
```elisp
|
||||||
|
|||||||
63
README_CN.md
63
README_CN.md
@ -57,6 +57,7 @@
|
|||||||
- [属性层定义](#属性层定义)
|
- [属性层定义](#属性层定义)
|
||||||
- [tp-define-layer](#tp-define-layer---定义单个属性层)
|
- [tp-define-layer](#tp-define-layer---定义单个属性层)
|
||||||
- [tp-define-layer-group](#tp-define-layer-group---定义属性层组)
|
- [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-layer-props / tp-group-props](#tp-layer-props--tp-group-props)
|
||||||
- [tp-undefine-layer / tp-undefine-group](#tp-undefine-layer--tp-undefine-group)
|
- [tp-undefine-layer / tp-undefine-group](#tp-undefine-layer--tp-undefine-group)
|
||||||
- [tp-layer-reset](#tp-layer-reset)
|
- [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`](#tp-define-layer---定义单个属性层) | 定义单个属性层,支持响应式特性(:props、:data、:watch、:compute) |
|
||||||
| [`tp-define-layer-group`](#tp-define-layer-group---定义属性层组) | 定义属性层组,支持响应式特性 |
|
| [`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-layer-props`](#tp-layer-props--tp-group-props) | 获取属性层的属性 |
|
||||||
| [`tp-group-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) | 移除属性层定义 |
|
| [`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`
|
#### `tp-layer-props` / `tp-group-props`
|
||||||
|
|
||||||
```elisp
|
```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 ()
|
(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
|
(tp-test-with-temp-buffer
|
||||||
(define-tp tp-bold
|
(define-tp tp-bold ()
|
||||||
'(face bold))
|
'(face bold))
|
||||||
(should (assoc 'tp-bold tp-layer-alist))
|
(should (assoc 'tp-bold tp-layer-alist))
|
||||||
(should (equal (cdr (assoc 'tp-bold tp-layer-alist)) '(face bold)))))
|
(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 ()
|
(ert-deftest tp-test-define-tp-parameterized ()
|
||||||
"Test define-tp with parameterized format."
|
"Test define-tp with parameterized format."
|
||||||
(tp-test-with-temp-buffer
|
(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 (eq (tp-at 1 'tp-name) 'tp-space))
|
||||||
(should (equal (tp-at 1 'display) '(space :width (5))))))
|
(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 ()
|
(ert-deftest tp-test-define-tp-parameterized-backquote ()
|
||||||
"Test parameterized layer with backquote syntax."
|
"Test parameterized layer with backquote syntax."
|
||||||
(tp-test-with-temp-buffer
|
(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)
|
(tp--update-layer-regions name)
|
||||||
(assoc name tp-layer-alist)))))
|
(assoc name tp-layer-alist)))))
|
||||||
|
|
||||||
(defmacro define-tp (name &rest args)
|
(defmacro define-tp (name arglist body)
|
||||||
"Define a single text property layer named NAME.
|
"Define a text property layer named NAME.
|
||||||
|
|
||||||
This macro provides a convenient syntax for `tp-define-layer'.
|
This macro supports two formats:
|
||||||
Supports two formats: with parameters and without parameters.
|
|
||||||
|
|
||||||
Format 1 - Without parameters (static properties):
|
Format 1 - Non-parameterized (empty arglist):
|
||||||
(define-tp tp-bold
|
(define-tp tp-bold ()
|
||||||
\\='(face bold))
|
\\='(face bold))
|
||||||
|
|
||||||
Usage:
|
Usage:
|
||||||
@ -2145,7 +2144,7 @@ Usage:
|
|||||||
(tp-set 0 5 \\='(tp-bold t) \"emacs\")
|
(tp-set 0 5 \\='(tp-bold t) \"emacs\")
|
||||||
;; => #(\"emacs\" 0 5 (tp-name tp-bold face bold))
|
;; => #(\"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)
|
(define-tp tp-space (pixel)
|
||||||
\\=`(display (space :width (,pixel))))
|
\\=`(display (space :width (,pixel))))
|
||||||
|
|
||||||
@ -2154,19 +2153,25 @@ Usage:
|
|||||||
(tp-set 0 5 \\='(tp-space 2) \"emacs\")
|
(tp-set 0 5 \\='(tp-space 2) \"emacs\")
|
||||||
;; => #(\"emacs\" 0 5 (tp-name tp-space display (space :width (2))))
|
;; => #(\"emacs\" 0 5 (tp-name tp-space display (space :width (2))))
|
||||||
|
|
||||||
Note: The parameterized form stores the body as a function that takes
|
ARGLIST must be either:
|
||||||
the parameter and returns the resolved property list."
|
- 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))
|
(declare (indent defun))
|
||||||
(if (and (car args) (listp (car args)) (not (eq (caar args) 'quote)))
|
(unless (listp arglist)
|
||||||
;; Parameterized form: (define-tp name (arg) body)
|
(error "define-tp ARGLIST must be a list"))
|
||||||
(let ((arglist (car args))
|
(cond
|
||||||
(body (cadr args)))
|
;; Non-parameterized: empty arglist
|
||||||
(unless (and (= (length arglist) 1)
|
((null arglist)
|
||||||
(symbolp (car arglist)))
|
`(tp-define-layer ',name ,body))
|
||||||
(error "define-tp with parameters only supports exactly one argument"))
|
;; Parameterized: single argument
|
||||||
`(tp--define-parameterized-layer ',name ',arglist ',body))
|
((and (= (length arglist) 1)
|
||||||
;; Non-parameterized form: (define-tp name 'props) or (define-tp name :props 'props ...)
|
(symbolp (car arglist)))
|
||||||
`(tp-define-layer ',name ,@args)))
|
`(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)
|
(defun tp--define-parameterized-layer (name arglist body)
|
||||||
"Define a parameterized layer NAME with ARGLIST and BODY.
|
"Define a parameterized layer NAME with ARGLIST and BODY.
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user