48 KiB
tp.el - Emacs 文本属性操作库
一个功能强大的文本属性操作库,具有创新的属性层系统
功能特性 • 安装 • 快速开始 • API 参考 • 属性层系统
概述
tp.el 是一个全面增强 Emacs 文本属性操作的库。它不仅仅是对原生文本属性 API(如 put-text-property、get-text-property)的简单封装,更提供了许多原生函数所不具备的功能拓展。
灵感来自用于叠加层的 ov.el,tp.el 在以下方面进行了创新:
核心创新
- 统一的 API 参数规范:所有函数支持多种灵活的调用方式,同时适用于字符串和缓冲区
- 子属性的精细操作:支持嵌套属性的路径式访问、修改和深度合并
- 创新的属性层系统:在同一文本区域上堆叠、管理多组属性,实现属性的分层控制
- 模式匹配批量操作:通过字符串或正则表达式批量应用属性
- 增强的搜索导航:丰富的属性搜索和遍历功能
功能特性
统一的 API 参数规范
原生 Emacs API 针对字符串和缓冲区有不同的函数和参数顺序,tp.el 统一了这一切:
- ✅ 三种调用约定:所有核心函数(
tp-set、tp-get、tp-remove等)支持三种灵活的调用方式:;; 1. 当前缓冲区 (tp-set START END '(face bold)) ;; 2. 指定缓冲区或字符串 (tp-set START END '(face bold) OBJECT) ;; 3. 整个字符串(平铺属性) (tp-set STRING 'face 'bold 'help-echo "tip") - ✅ 统一对象支持:同一个函数同时支持字符串和缓冲区,无需记忆不同的 API
三种属性操作语义
原生 API 只有简单的设置和获取,tp.el 提供了三种清晰的操作语义:
- ✅
tp-reset:完全替换 - 清除所有现有属性,设置新属性 - ✅
tp-set:部分替换 - 只替换指定属性,保留其他属性 - ✅
tp-add:深度合并 - 智能合并嵌套属性,而非简单覆盖
;; 深度合并示例
(tp-set 1 10 '(face (:foreground "red")))
(tp-add 1 10 '(face (:background "blue")))
;; 结果: face 是 (:foreground "red" :background "blue")
;; 原生 API 会完全覆盖,而 tp-add 会智能合并
子属性的精细操作
这是原生 API 完全不具备的功能。tp.el 支持对嵌套属性进行精细的读取、修改和删除:
- ✅ 路径式访问:通过路径语法访问深层嵌套的属性值
;; 获取嵌套属性 (tp-get str 'face :underline :style) ; => wave (tp-at 5 '(face :box :color)) ; => "blue" ;; 获取多个嵌套键 (tp-get str 'face :underline '(:color :style)) ;; => ((:color "green" :style wave)) - ✅ 子属性删除:精确移除嵌套属性中的特定键
;; 只删除 :underline 中的 :style,保留 :color (tp-remove 1 10 '(face :underline (:style))) - ✅ 深度合并:
tp-add递归合并嵌套的 plist 结构 - ✅ Face 智能合并:符号 face 自动前置到 face 列表,plist face 深度合并
创新的属性层系统
这是 tp.el 最具创新性的功能,原生 Emacs 完全不支持。属性层系统允许在同一文本区域上堆叠多组属性:
- ✅ 属性层栈概念:多个属性层像栈一样堆叠,只有顶层可见,下层被保留
- ✅ 属性层定义与复用:通过
tp-define-layer定义可复用的属性层和属性层组 - ✅ 丰富的属性层操作:
- 放置:
tp-put-layer(指定位置)、tp-push-layer(顶部) - 删除:
tp-delete-layer(按名称/索引)、tp-pop-layer(顶层) - 移动:
tp-raise-layer(上下移动)、tp-rotate-layer(轮换)、tp-pin-layer(置顶)、tp-switch-layer(交换) - 合并:
tp-merge-layers(合并指定层)、tp-flatten-layers(扁平化所有层)
- 放置:
- ✅ 属性层查询:
tp-layer-list、tp-layer-count、tp-layer-exists-p、tp-layer-top
;; 属性层使用示例
(tp-define-layer highlight (face (:background "yellow")))
(tp-define-layer error (face (:foreground "red")))
;; 堆叠多个属性层
(tp-push-layer 1 10 'highlight)
(tp-push-layer 1 10 'error) ; error 现在可见
;; 轮换显示
(tp-rotate-layer 1 10) ; highlight 现在可见
模式匹配与批量操作
原生 API 需要手动搜索和循环,tp.el 提供了便捷的模式匹配功能:
- ✅ 字符串匹配:
tp-match-set、tp-match-reset、tp-match-add - ✅ 正则匹配:
tp-regexp-set、tp-regexp-reset、tp-regexp-add - ✅ 三种语义变体:每种匹配都支持 set/reset/add 三种操作语义
;; 高亮所有 TODO
(tp-match-set "TODO" '(face warning))
;; 正则匹配所有数字
(tp-regexp-set "[0-9]+" '(face font-lock-number-face))
;; 深度合并方式添加属性
(tp-match-add "TODO" '(face (:underline t)))
增强的搜索与导航
- ✅ 范围搜索:
tp-search返回所有匹配区间的列表 - ✅ N次搜索:
tp-forward/tp-backward支持向前/向后搜索N次 - ✅ 搜索并执行:
tp-forward-do/tp-backward-do搜索并对匹配文本执行函数 - ✅ 批量转换:
tp-search-map对所有匹配应用转换函数
;; 搜索所有标记
(tp-search my-string 'marker) ; => ((0 5 t) (12 17 t))
;; 将所有标记文本转为大写
(tp-search-map #'upcase my-string 'marker)
系统要求
- Emacs 28.1+(使用
object-intervals函数) - dash.el(列表操作工具库)
安装
;; 添加到 load-path
(add-to-list 'load-path "/path/to/tp")
(require 'tp)
或使用 use-package:
(use-package tp
:load-path "/path/to/tp")
API 参考
API 快速参考
tp.el 所有函数按类别组织的完整概览:
核心属性函数
| 函数 | 描述 |
|---|---|
tp-set |
设置文本属性(仅替换指定属性) |
tp-reset |
替换所有文本属性 |
tp-add |
添加/合并属性,支持深度合并 |
tp-get |
从范围或字符串获取属性值 |
tp-at |
获取单个位置的属性值 |
tp-remove |
移除属性或子属性 |
tp-clear |
清除区域中的所有文本属性 |
模式匹配函数
| 函数 | 描述 |
|---|---|
tp-match-set |
在字符串匹配处设置属性 |
tp-match-reset |
在字符串匹配处重置所有属性 |
tp-match-add |
在字符串匹配处添加/合并属性 |
tp-regexp-set |
在正则匹配处设置属性 |
tp-regexp-reset |
在正则匹配处重置所有属性 |
tp-regexp-add |
在正则匹配处添加/合并属性 |
搜索和导航函数
| 函数 | 描述 |
|---|---|
tp-search-forward |
text-property-search-forward 的原始包装 |
tp-search-backward |
text-property-search-backward 的原始包装 |
tp-forward |
向前搜索 N 次具有属性的文本(支持缓冲区和字符串) |
tp-backward |
向后搜索 N 次具有属性的文本(支持缓冲区和字符串) |
tp-forward-do |
对 N 个向前匹配的文本应用函数(支持起始位置) |
tp-backward-do |
对 N 个向后匹配的文本应用函数(支持起始位置) |
tp-search |
在范围或字符串中搜索所有匹配的属性 |
tp-search-map |
对所有匹配的文本应用函数 |
属性层定义函数
| 函数 | 描述 |
|---|---|
tp-define-layer |
定义属性层或属性层组 |
tp-layer-props |
获取属性层的属性 |
tp-group-props |
获取属性层组中所有属性层的属性 |
tp-layer-undefine |
移除属性层定义 |
tp-group-undefine |
移除属性层组定义 |
tp-layer-reset |
清除所有属性层/属性层组定义 |
属性层放置函数
| 函数 | 描述 |
|---|---|
tp-put-layer |
在指定索引位置设置属性层 |
tp-push-layer |
将属性层推到堆栈顶部 |
属性层删除函数
| 函数 | 描述 |
|---|---|
tp-delete-layer |
按名称或索引删除属性层 |
tp-pop-layer |
移除顶层属性层 |
属性层移动函数
| 函数 | 描述 |
|---|---|
tp-raise-layer |
将属性层上移/下移 N 个位置 |
tp-rotate-layer |
轮换属性层(顶层移到底部) |
tp-pin-layer |
将属性层置顶(使其可见) |
tp-switch-layer |
交换两个属性层的位置 |
属性层合并函数
| 函数 | 描述 |
|---|---|
tp-merge-layers |
将指定属性层合并为新属性层 |
tp-flatten-layers |
将所有属性层扁平化为单一属性层 |
属性层查询函数
| 函数 | 描述 |
|---|---|
tp-layer-list |
列出区域中的所有属性层名称 |
tp-layer-count |
计算区域中的属性层数量 |
tp-layer-exists-p |
检查区域中是否存在某属性层 |
tp-layer-top |
获取顶层(可见)属性层的名称 |
核心属性函数
tp-set - 设置文本属性
在字符串或缓冲区区域上设置文本属性。只替换指定的属性,保留其他属性。
;; 当前缓冲区(属性作为列表)
(tp-set START END '(PROPERTY VALUE ...))
;; 特定缓冲区或字符串
(tp-set START END '(PROPERTY VALUE ...) OBJECT)
;; 整个字符串(平铺属性)
(tp-set STRING PROPERTY VALUE ...)
示例:
;; 在缓冲区区域设置 face
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face bold)))
;; => (1 . 10)
;; 设置多个属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face bold help-echo "Click me")))
;; => (1 . 10)
;; 在特定缓冲区设置
(let ((my-buffer (generate-new-buffer "*test*")))
(with-current-buffer my-buffer
(insert "Hello World"))
(tp-set 1 10 '(face italic) my-buffer)
(kill-buffer my-buffer))
;; => (1 . 10)
;; 在字符串上设置属性(0 索引)
(let ((my-string (tp-set 0 5 '(face italic) "Hello World")))
my-string)
;; => #("Hello World" 0 5 (face italic))
;; 在整个字符串上设置属性
(tp-set "Hello" 'face 'bold 'mouse-face 'highlight)
;; => #("Hello" 0 5 (face bold mouse-face highlight))
tp-reset - 替换所有属性
用指定的属性完全替换所有文本属性。
(tp-reset START END '(PROPERTY VALUE ...) &optional OBJECT)
(tp-reset STRING PROPERTY VALUE ...)
示例:
;; 替换区域中的所有属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(help-echo "old")) ; 设置已有属性
(tp-reset 1 10 '(face bold)) ; 任何现有属性都会被移除
(tp-at 1))
;; => (face bold) ; help-echo 被移除了
;; 在字符串上
(tp-reset "Hello" 'face 'italic)
;; => #("Hello" 0 5 (face italic))
tp-add - 添加/合并属性
添加或更新属性,支持嵌套属性列表的深度合并。
(tp-add START END '(PROPERTY VALUE ...) &optional OBJECT)
(tp-add STRING PROPERTY VALUE ...)
示例:
;; 添加属性(保留现有,合并嵌套)
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face bold))
(tp-add 1 10 '(help-echo "tooltip"))
(tp-at 1))
;; => (face bold help-echo "tooltip")
;; 深度合并 face 属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face (:foreground "red")))
(tp-add 1 10 '(face (:background "blue")))
(tp-at 1 'face))
;; => (:foreground "red" :background "blue")
;; Face 前置 - 符号 face 会被添加到 face 列表的开头
(let ((str (tp-set "Hello" 'face 'bold)))
(tp-add str 'face 'shadow)
(tp-at 0 'face str))
;; => (shadow bold)
tp-get - 获取属性值
从范围或字符串获取属性值,支持嵌套子属性访问。
返回 (START END VALUE) 区间列表,让你可以查看范围内所有的属性值。
对于单个位置的查询,请使用 tp-at。
;; 范围 - 特定属性(返回区间列表)
(tp-get START END PROPERTY)
(tp-get START END PROPERTY OBJECT)
;; 范围 - 属性路径作为列表
(tp-get START END '(PROPERTY) OBJECT)
(tp-get START END '(PROPERTY SUB-KEY ...) OBJECT)
;; 范围 - 深层嵌套属性路径
(tp-get START END '(PROPERTY SUB-KEY SUB-SUB-KEY ...) OBJECT)
;; 范围 - 从嵌套属性中提取多个键
(tp-get START END '(PROPERTY SUB-KEY (KEY1 KEY2 ...)) OBJECT)
;; 范围 - 所有属性(返回区间列表)
(tp-get START END)
(tp-get START END OBJECT)
;; 整个字符串(返回区间列表)
(tp-get STRING)
(tp-get STRING PROPERTY)
(tp-get STRING PROPERTY SUB-KEY ...)
(tp-get STRING PROPERTY SUB-KEY '(KEY1 KEY2 ...))
(tp-get STRING '(PROPERTY SUB-KEY ...))
示例:
;; 从范围获取 - 返回 (START END VALUE) 区间列表
(with-temp-buffer
(insert "Hello World")
(tp-set 1 6 '(face bold))
(tp-get 1 10 'face))
;; => ((1 6 bold))
;; 获取多个区间
(let ((str (copy-sequence "Hello World Hello")))
(tp-set 0 5 '(face bold) str)
(tp-set 12 17 '(face italic) str)
(tp-get 0 17 'face str))
;; => ((0 5 bold) (12 17 italic))
;; 使用列表形式的属性路径
(let ((my-string (copy-sequence "Hello World Hello World")))
(tp-set 5 20 '(face (:underline (:style wave))) my-string)
(tp-get 5 20 '(face :underline :style) my-string))
;; => ((5 20 wave))
;; 从整个字符串获取深层嵌套属性
(let ((str (copy-sequence "Hello World")))
(tp-set 0 5 '(face (:underline (:color "green"))) str)
(tp-set 6 11 '(face (:underline (:color "yellow"))) str)
(tp-get str 'face :underline :color))
;; => ((0 5 "green") (6 11 "yellow"))
;; 从嵌套属性中获取多个键
(let ((str (copy-sequence "Hello World")))
(tp-set 0 5 '(face (:underline (:color "green" :style wave))) str)
(tp-set 6 11 '(face (:underline (:color "yellow" :style line))) str)
(tp-get str 'face :underline '(:color :style)))
;; => ((0 5 (:color "green" :style wave)) (6 11 (:color "yellow" :style line)))
;; 获取范围内的所有属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 6 '(face bold help-echo "test"))
(tp-get 1 10))
;; => ((1 6 (face bold help-echo "test")))
;; 从整个字符串获取 - 返回区间列表
(let ((str (copy-sequence "Hello World Hello")))
(tp-set 0 5 '(face bold) str)
(tp-set 12 17 '(face italic) str)
(list (tp-get str) ; => ((0 5 (face bold)) (12 17 (face italic)))
(tp-get str 'face))) ; => ((0 5 bold) (12 17 italic))
;; => (((0 5 (face bold)) (12 17 (face italic))) ((0 5 bold) (12 17 italic)))
tp-at - 获取位置属性
;; 获取位置的所有属性
(tp-at POS)
(tp-at POS OBJECT)
;; 获取位置的特定属性
(tp-at POS PROPERTY)
(tp-at POS PROPERTY OBJECT)
;; 获取位置的嵌套子属性
(tp-at POS '(PROPERTY SUB-KEY ...))
(tp-at POS '(PROPERTY SUB-KEY ...) OBJECT)
获取 POS 位置的文本属性,可选择按 PROPERTY 过滤。
对于单位置属性查询(以前使用 tp-get),现在使用 tp-at。
示例:
;; 获取当前缓冲区位置 5 的所有属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face bold help-echo "test"))
(tp-at 5))
;; => (face bold help-echo "test")
;; 获取字符串位置 0 的所有属性
(let ((my-string (tp-set "Hello" 'face 'italic 'help-echo "greeting")))
(tp-at 0 my-string))
;; => (face italic help-echo "greeting")
;; 获取位置的特定属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face bold))
(tp-at 5 'face))
;; => bold
;; 获取字符串位置的特定属性
(let ((my-string (tp-set "Hello" 'face 'italic)))
(tp-at 0 'face my-string))
;; => italic
;; 获取位置的嵌套子属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face (:foreground "red" :box (:color "blue"))))
(list (tp-at 5 '(face :foreground))
(tp-at 5 '(face :box :color))))
;; => ("red" "blue")
;; 从字符串获取嵌套子属性
(let ((str (copy-sequence "Hello")))
(tp-set 0 5 '(face (:foreground "red" :underline t)) str)
(tp-at 0 '(face :foreground) str))
;; => "red"
tp-remove - 移除属性
从区域或整个字符串中移除属性或嵌套子属性。
;; 移除整个属性(缓冲区)
(tp-remove START END PROPERTY &optional OBJECT)
;; 移除子属性(缓冲区)
(tp-remove START END '(PROPERTY SUB-KEY) &optional OBJECT)
;; 移除嵌套子属性(缓冲区)
(tp-remove START END '(PROPERTY SUB-KEY (NESTED-KEYS...)) &optional OBJECT)
;; 从整个字符串移除
(tp-remove STRING PROP1 PROP2 ...)
(tp-remove STRING PROPERTY SUB-KEY)
(tp-remove STRING PROPERTY SUB-KEY '(NESTED-KEYS...))
示例:
;; 移除整个属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face bold help-echo "test"))
(tp-remove 1 10 'face)
(tp-at 1))
;; => (help-echo "test")
;; 从 face 移除子属性
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face (:foreground "red" :underline t)))
(tp-remove 1 10 '(face :underline))
(tp-at 1 'face))
;; => (:foreground "red")
;; 移除特定嵌套键,保留其他
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face (:underline (:style wave :position t :color "blue"))))
(tp-remove 1 10 '(face :underline (:style :position)))
(tp-at 1 '(face :underline)))
;; => (:color "blue") ; :style 和 :position 被移除, :color 保留
;; 从整个字符串移除 - 移除多个属性
(let ((str (tp-set "Hello World" 'face 'bold 'help-echo "tip")))
(tp-remove str 'face 'help-echo)
(tp-at 0 str))
;; => nil
;; 从字符串移除子属性
(let ((str (copy-sequence "Hello World")))
(tp-set 0 11 '(face (:foreground "red" :underline t)) str)
(tp-remove str 'face :underline)
(tp-at 0 'face str))
;; => (:foreground "red")
;; 从字符串移除嵌套键
(let ((str (copy-sequence "Hello World")))
(tp-set 0 11 '(face (:underline (:style wave :color "blue"))) str)
(tp-remove str 'face :underline '(:style))
(tp-at 0 '(face :underline) str))
;; => (:color "blue")
tp-clear - 清除所有属性
(tp-clear &optional START END OBJECT)
清除区域中的所有文本属性。
示例:
;; 清除区域
(with-temp-buffer
(insert "Hello World")
(tp-set 1 10 '(face bold))
(tp-clear 1 10)
(tp-at 1))
;; => nil
;; 清除整个缓冲区
(with-temp-buffer
(insert "Hello World")
(tp-set 1 12 '(face bold))
(tp-clear)
(tp-at 5))
;; => nil
模式匹配函数
tp-match-set - 匹配字符串
(tp-match-set PATTERN PLIST &optional OBJECT)
在所有字符串模式匹配处设置属性。
PATTERN 可以是字符串(单个模式)或字符串列表(多个模式)。
PLIST 是属性列表,如 '(face bold help-echo "tip")。
OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
示例:
;; 在缓冲区中 - 返回 (START . END) 对的列表
(with-temp-buffer
(insert "TODO: fix this. TODO: also this.")
(tp-match-set "TODO" '(face warning)))
;; => ((1 . 5) (17 . 21))
;; 在字符串上 - 返回修改后的字符串
(tp-match-set "o" '(face bold) "Hello World")
;; => #("Hello World" 4 5 (face bold) 7 8 (face bold))
;; 多个模式 - 同时匹配 "world" 和 "Hello"
(with-temp-buffer
(insert "Hello world, Hello again")
(tp-match-set '("world" "Hello") '(face bold)))
;; => ((1 . 6) (7 . 12) (14 . 19)) ; 匹配 "Hello", "world", "Hello"
;; 在字符串上使用多个模式
(tp-match-set '("Hello" "world") '(face bold) "Hello world")
;; => #("Hello world" 0 5 (face bold) 6 11 (face bold))
tp-match-reset - 匹配并重置
重置(完全替换)匹配处的所有属性。
PATTERN 可以是字符串或字符串列表(多个模式)。
PLIST 是属性列表,如 '(face bold help-echo "tip")。
OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
(tp-match-reset PATTERN PLIST &optional OBJECT)
示例:
;; 替换匹配文本上的所有属性
(with-temp-buffer
(insert "TODO: fix this")
(tp-set 1 5 '(help-echo "original")) ; 设置已有属性
(tp-match-reset "TODO" '(face warning))
(tp-at 1))
;; => (face warning) ; help-echo 被移除
;; 多个模式
(with-temp-buffer
(insert "TODO: fix. FIXME: also fix.")
(tp-match-reset '("TODO" "FIXME") '(face warning)))
;; => ((1 . 5) (12 . 17))
tp-match-add - 匹配并添加
在匹配处添加/合并属性,支持深度合并。
PATTERN 可以是字符串或字符串列表(多个模式)。
PLIST 是属性列表,如 '(face bold help-echo "tip")。
OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
(tp-match-add PATTERN PLIST &optional OBJECT)
示例:
;; 与现有属性合并
(with-temp-buffer
(insert "TODO: fix this")
(tp-set 1 5 '(help-echo "important"))
(tp-match-add "TODO" '(face (:underline t)))
(tp-at 1))
;; => (face (:underline t) help-echo "important")
;; 多个模式
(with-temp-buffer
(insert "TODO: fix. FIXME: also fix.")
(tp-match-add '("TODO" "FIXME") '(face (:underline t))))
;; => ((1 . 5) (12 . 17))
tp-regexp-set - 匹配正则表达式
(tp-regexp-set PATTERN PLIST &optional OBJECT)
在所有正则表达式匹配处设置属性。
PATTERN 可以是字符串(单个正则)或字符串列表(多个正则)。
PLIST 是属性列表,如 '(face bold help-echo "tip")。
OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
示例:
;; 高亮缓冲区中的所有数字
(with-temp-buffer
(insert "abc 123 def 456")
(tp-regexp-set "[0-9]+" '(face font-lock-number-face))
(list (tp-at 5 'face) (tp-at 13 'face)))
;; => (font-lock-number-face font-lock-number-face)
;; 在字符串上
(tp-regexp-set "[A-Z]+" '(face bold) "Hello WORLD")
;; => #("Hello WORLD" 6 11 (face bold))
;; 多个正则 - 同时匹配数字和大写字母
(tp-regexp-set '("[0-9]+" "[A-Z]+") '(face bold) "abc 123 XYZ")
;; => #("abc 123 XYZ" 4 7 (face bold) 8 11 (face bold))
tp-regexp-reset - 正则匹配并重置
重置(完全替换)正则匹配处的所有属性。
PATTERN 可以是字符串或字符串列表(多个正则)。
PLIST 是属性列表,如 '(face bold help-echo "tip")。
OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
(tp-regexp-reset PATTERN PLIST &optional OBJECT)
示例:
;; 重置正则匹配处的所有属性
(with-temp-buffer
(insert "abc 123 def 456")
(tp-set 5 8 '(help-echo "original"))
(tp-regexp-reset "[0-9]+" '(face bold))
(tp-at 5))
;; => (face bold) ; help-echo 被移除
;; 在字符串上
(let ((str (copy-sequence "abc 123 def")))
(tp-set 4 7 '(help-echo "original") str)
(tp-regexp-reset "[0-9]+" '(face italic) str)
(tp-at 4 str))
;; => (face italic)
tp-regexp-add - 正则匹配并添加
在正则匹配处添加/合并属性,支持深度合并。
PATTERN 可以是字符串或字符串列表(多个正则)。
PLIST 是属性列表,如 '(face bold help-echo "tip")。
OBJECT 是缓冲区或字符串;nil 表示当前缓冲区。
(tp-regexp-add PATTERN PLIST &optional OBJECT)
示例:
;; 添加属性到正则匹配处(保留现有)
(with-temp-buffer
(insert "abc 123 def 456")
(tp-set 5 8 '(help-echo "number"))
(tp-regexp-add "[0-9]+" '(face bold))
(tp-at 5))
;; => (face bold help-echo "number")
;; 在字符串上
(let ((str (copy-sequence "abc 123 def")))
(tp-set 4 7 '(help-echo "number") str)
(tp-regexp-add "[0-9]+" '(face italic) str)
(tp-at 4 str))
;; => (face italic help-echo "number")
搜索和导航函数
tp-search-forward / tp-search-backward
(tp-search-forward PROPERTY &optional VALUE PREDICATE NOT-CURRENT)
(tp-search-backward PROPERTY &optional VALUE PREDICATE NOT-CURRENT)
Emacs 的 text-property-search-forward 和 text-property-search-backward 的原始包装。
这些是直接使用 prop-match 对象的底层搜索函数。
tp-forward / tp-backward
(tp-forward PROPERTY &optional VALUE OBJECT N)
(tp-backward PROPERTY &optional VALUE OBJECT N)
向前/向后搜索 N 次具有 PROPERTY 的文本。
- N 是搜索次数,默认为 1。
- VALUE 是可选的匹配值。
- OBJECT 可以是缓冲区或字符串;nil 默认为当前缓冲区。
- 对于缓冲区,返回最后一次成功搜索的 prop-match 对象。
- 对于字符串,返回所有匹配的 (START END VALUE) 列表。
示例:
;; 查找下一个具有 'marker 属性的文本
(with-temp-buffer
(insert "Hello World Test")
(tp-set 7 12 '(marker t))
(goto-char 1)
(let ((match (tp-forward 'marker)))
(when match
(prop-match-beginning match))))
;; => 7
;; 查找下一个 'type 等于 'heading 的文本
(with-temp-buffer
(insert "Hello World")
(tp-set 1 6 '(type heading))
(goto-char 1)
(let ((match (tp-forward 'type 'heading)))
(when match
(prop-match-value match))))
;; => heading
;; 在字符串中搜索
(let ((my-string (copy-sequence "Hello World Hello")))
(tp-set 0 5 '(marker t) my-string)
(tp-set 12 17 '(marker t) my-string)
(tp-forward 'marker nil my-string 2))
;; => ((0 5 t) (12 17 t))
tp-forward-do / tp-backward-do
(tp-forward-do FUNCTION PROPERTY &optional VALUE OBJECT POINT N)
(tp-backward-do FUNCTION PROPERTY &optional VALUE OBJECT POINT N)
向前/向后搜索 N 次具有 PROPERTY 的文本,并对匹配的文本应用 FUNCTION。
- FUNCTION 接收匹配到的文本作为唯一参数。FUNCTION 的返回值将替换字符串或缓冲区中的匹配文本。
- N 是搜索次数,默认为 1。
- OBJECT 可以是缓冲区或字符串;nil 默认为当前缓冲区。
- POINT 是搜索的起始位置;对于缓冲区 nil 表示当前位置,对于字符串 nil 表示 0(向前)或字符串末尾(向后)。
- 返回成功匹配的数量。
示例:
;; 将缓冲区中匹配的文本转为大写(从当前位置开始)
(with-temp-buffer
(insert "hello world test")
(tp-set 1 6 '(marker t))
(tp-set 13 17 '(marker t))
(goto-char 1)
(tp-forward-do #'upcase 'marker nil nil nil 2)
(buffer-string))
;; => "HELLO world TEST"
;; 将字符串中匹配的文本转为大写(从位置 0 开始)
(let ((my-string (copy-sequence "hello world hello")))
(tp-set 0 5 '(marker t) my-string)
(tp-set 12 17 '(marker t) my-string)
(tp-forward-do #'upcase 'marker nil my-string nil 2)
my-string)
;; => "HELLO world HELLO"
;; 从特定位置开始搜索
(let ((my-string (copy-sequence "hello world hello")))
(tp-set 0 5 '(marker t) my-string)
(tp-set 12 17 '(marker t) my-string)
(tp-forward-do #'upcase 'marker nil my-string 6 2)
my-string)
;; => "hello world HELLO" ; 只处理位置 6 之后的匹配
;; 自定义转换
(with-temp-buffer
(insert "hello world test")
(tp-set 1 6 '(marker t))
(goto-char 1)
(tp-forward-do
(lambda (text)
(concat "[" text "]"))
'marker nil nil nil 1)
(buffer-string))
;; => "[hello] world test"
tp-search - 搜索所有匹配
;; 缓冲区/字符串区域
(tp-search START END PROPERTY &optional VALUE OBJECT)
;; 整个字符串
(tp-search STRING PROPERTY &optional VALUE)
在缓冲区/字符串范围或整个字符串中搜索所有具有 PROPERTY 的文本。
返回所有匹配区域的 (START END VALUE) 列表。
示例:
;; 在缓冲区范围内查找所有 'marker 属性
(with-temp-buffer
(insert "Hello World Test Again")
(tp-set 1 6 '(marker t))
(tp-set 13 17 '(marker t))
(tp-search 1 22 'marker))
;; => ((1 6 t) (13 17 t))
;; 在字符串中查找所有值为 'heading 的 'type 属性
(let ((my-string (copy-sequence "Title Here Body Text")))
(tp-set 0 10 '(type heading) my-string)
(tp-search my-string 'type 'heading))
;; => ((0 10 heading))
;; 按值过滤
(with-temp-buffer
(insert "Heading1 Body Heading2")
(tp-set 1 9 '(type heading))
(tp-set 10 14 '(type body))
(tp-set 15 23 '(type heading))
(tp-search 1 23 'type 'heading))
;; => ((1 9 heading) (15 23 heading))
tp-search-map - 对匹配文本应用函数
;; 缓冲区/字符串区域
(tp-search-map FUNCTION START END PROPERTY &optional VALUE OBJECT)
;; 整个字符串
(tp-search-map FUNCTION STRING PROPERTY &optional VALUE)
对所有 PROPERTY 匹配的文本应用 FUNCTION。
- FUNCTION 接收匹配到的文本作为唯一参数。FUNCTION 的返回值将替换字符串或缓冲区中的匹配文本。
- 返回处理的匹配数量。
示例:
;; 将字符串中所有 marker 文本转为大写
(let ((my-string (copy-sequence "hello world hello")))
(tp-set 0 5 '(marker t) my-string)
(tp-set 12 17 '(marker t) my-string)
(tp-search-map #'upcase my-string 'marker)
my-string)
;; => "HELLO world HELLO"
;; 将缓冲区范围内所有 marker 文本转为大写
(with-temp-buffer
(insert "hello world test")
(tp-set 1 6 '(marker t))
(tp-set 13 17 '(marker t))
(tp-search-map #'upcase 1 17 'marker)
(buffer-string))
;; => "HELLO world TEST"
;; 自定义转换
(let ((my-string (copy-sequence "hello world")))
(tp-set 0 5 '(marker t) my-string)
(tp-search-map
(lambda (text)
(concat "[" text "]"))
my-string 'marker)
my-string)
;; => "[hello] world"
属性层系统
属性层系统是 tp.el 的创新功能,允许在同一文本区域堆叠多组属性。只有顶层属性可见,但下层属性会被保留,并可通过轮转或固定操作使其显现。
属性层概念
┌─────────────────────────────┐ │ 顶层(可见) │ ← idx=0,你看到的 ├─────────────────────────────┤ │ 中间层(隐藏) │ ← idx=1,被保留 ├─────────────────────────────┤ │ 底层(隐藏) │ ← idx=-1,被保留 └─────────────────────────────┘
属性层定义
tp-define-layer - 定义属性层
定义单个属性层或多个属性层组。
单个属性层:
(tp-define-layer layer-name
(face (:background "cyan") line-prefix ">>"))
多个属性层(属性层组):
(tp-define-layer my-group
layer-1 ; 引用已存在的属性层
(face (:background "red") line-prefix ">>") ; 匿名属性层
(face (:background "green" :weight bold))) ; 另一个匿名属性层
定义中的第一个属性层是顶层(默认可见)。
示例:
;; 定义单个属性层
(progn
(setq tp-layer-alist nil) ; 重置以确保干净的示例
(tp-define-layer highlight
(face (:background "yellow" :foreground "black")))
(tp-layer-props 'highlight))
;; => (face (:background "yellow" :foreground "black") tp-name highlight)
(progn
(tp-define-layer error
(face (:background "red" :foreground "white")
help-echo "错误!"))
(tp-layer-props 'error))
;; => (face (:background "red" :foreground "white") help-echo "错误!" tp-name error)
(progn
(tp-define-layer info
(face (:background "blue" :foreground "white")))
(tp-layer-props 'info))
;; => (face (:background "blue" :foreground "white") tp-name info)
;; 定义属性层组
(progn
(tp-define-layer status-colors
highlight
error
info)
(length (tp-group-props 'status-colors)))
;; => 3
tp-layer-props / tp-group-props
(tp-layer-props LAYER-NAME)
(tp-group-props GROUP-NAME)
获取属性层或属性层组中所有属性层的属性。
示例:
;; 获取属性层属性
(progn
(setq tp-layer-alist nil)
(tp-define-layer my-layer (face bold help-echo "tip"))
(tp-layer-props 'my-layer))
;; => (face bold help-echo "tip" tp-name my-layer)
;; 获取属性层组属性
(progn
(setq tp-layer-alist nil)
(setq tp-layer-groups nil)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(tp-define-layer my-group layer1 layer2)
(length (tp-group-props 'my-group)))
;; => 2
tp-layer-undefine / tp-group-undefine
(tp-layer-undefine NAME)
(tp-group-undefine NAME)
移除属性层或属性层组定义。
示例:
;; 取消定义属性层
(progn
(setq tp-layer-alist nil)
(tp-define-layer temp-layer (face bold))
(tp-layer-undefine 'temp-layer)
(tp-layer-props 'temp-layer))
;; => nil
;; 取消定义属性层组
(progn
(setq tp-layer-alist nil)
(setq tp-layer-groups nil)
(tp-define-layer l1 (face bold))
(tp-define-layer my-group l1)
(tp-group-undefine 'my-group)
(assoc 'my-group tp-layer-groups))
;; => nil
tp-layer-reset
(tp-layer-reset)
清除所有属性层和属性层组定义。
示例:
(progn
(tp-define-layer test-layer (face bold))
(tp-layer-reset)
(list tp-layer-alist tp-layer-groups))
;; => (nil nil)
属性层放置
tp-put-layer - 在指定位置设置属性层
;; 缓冲区/字符串区域
(tp-put-layer START END LAYER IDX OBJECT)
;; 整个字符串
(tp-put-layer STRING LAYER IDX)
在属性层堆栈的指定索引位置设置属性层。
IDX = 0:顶部(可见属性层)IDX = -1:底部- 其他值在该位置插入
示例:
;; 将 base 属性层放在顶部
(progn
(tp-layer-reset)
(tp-define-layer base (face default))
(tp-define-layer highlight (face (:background "yellow")))
(with-temp-buffer
(insert "Hello World")
(tp-put-layer 1 10 'base 0)
(tp-at 1 'tp-name)))
;; => base
;; 将 highlight 放在索引 1(顶部下面)
(progn
(tp-layer-reset)
(tp-define-layer base (face default))
(tp-define-layer highlight (face (:background "yellow")))
(with-temp-buffer
(insert "Hello World")
(tp-put-layer 1 10 'base 0)
(tp-put-layer 1 10 'highlight 1)
(tp-layer-count 1 10)))
;; => 2
;; 将属性层放在底部
(progn
(tp-layer-reset)
(tp-define-layer base (face default))
(tp-define-layer info (face (:foreground "blue")))
(with-temp-buffer
(insert "Hello World")
(tp-put-layer 1 10 'base 0)
(tp-put-layer 1 10 'info -1)
(tp-layer-top 1 10)))
;; => base ; info 在底部,base 可见
tp-push-layer - 推送属性层到顶部
;; 缓冲区/字符串区域
(tp-push-layer START END LAYER OBJECT)
;; 整个字符串
(tp-push-layer STRING LAYER)
将属性层推到堆栈顶部(相当于 tp-put-layer ... 0)。
示例:
;; 首先推入 base 属性层
(progn
(tp-layer-reset)
(tp-define-layer base (face default))
(tp-define-layer highlight (face (:background "yellow")))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'base)
(tp-at 1 'tp-name)))
;; => base
;; 将 highlight 推到顶部(现在可见)
(progn
(tp-layer-reset)
(tp-define-layer base (face default))
(tp-define-layer highlight (face (:background "yellow")))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'base)
(tp-push-layer 1 10 'highlight)
(tp-at 1 'tp-name)))
;; => highlight
属性层删除
tp-delete-layer - 按名称/索引删除属性层
;; 缓冲区/字符串区域
(tp-delete-layer START END LAYER-NAME/IDX OBJECT)
;; 整个字符串
(tp-delete-layer STRING LAYER-NAME/IDX)
通过名称或索引从堆栈任意位置删除属性层。
示例:
;; 按名称删除
(progn
(tp-layer-reset)
(tp-define-layer highlight (face (:background "yellow")))
(tp-define-layer base (face default))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'base)
(tp-push-layer 1 10 'highlight)
(tp-delete-layer 1 10 'highlight)
(tp-at 1 'tp-name)))
;; => base
;; 删除顶层(idx=0)
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-delete-layer 1 10 0)
(tp-at 1 'tp-name)))
;; => layer1
;; 删除底层
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-delete-layer 1 10 -1)
(tp-layer-count 1 10)))
;; => 1
tp-pop-layer - 弹出顶层
;; 缓冲区/字符串区域
(tp-pop-layer START END OBJECT)
;; 整个字符串
(tp-pop-layer STRING)
删除顶层(相当于 tp-delete-layer ... 0)。
示例:
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-pop-layer 1 10)
(tp-at 1 'tp-name)))
;; => layer1
属性层移动
tp-raise-layer - 上移/下移属性层
;; 缓冲区/字符串区域
(tp-raise-layer START END IDX/LAYER-NAME N OBJECT)
;; 整个字符串
(tp-raise-layer STRING IDX/LAYER-NAME N)
将属性层上移 N 个位置。正数 N 向顶部移动,负数向底部移动。
示例:
;; 将 layer1 上移 2 个位置(到顶部)
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(tp-define-layer layer3 (face underline))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-push-layer 1 10 'layer3)
;; 堆栈: layer3 (顶), layer2, layer1 (底)
(tp-raise-layer 1 10 'layer1 2)
(tp-layer-top 1 10)))
;; => layer1
;; 将索引 0 的属性层下移 1 个位置
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
;; 堆栈: layer2 (idx 0), layer1 (idx 1)
(tp-raise-layer 1 10 0 -1)
(tp-layer-top 1 10)))
;; => layer1
tp-rotate-layer - 轮换属性层
;; 缓冲区/字符串区域
(tp-rotate-layer START END OBJECT)
;; 整个字符串
(tp-rotate-layer STRING)
轮换属性层 - 顶层移到底部,下一层变为可见。
示例:
;; 堆栈: highlight (顶) -> base (底)
(progn
(tp-layer-reset)
(tp-define-layer base (face default))
(tp-define-layer highlight (face (:background "yellow")))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'base)
(tp-push-layer 1 10 'highlight)
;; 堆栈: highlight (顶) -> base (底)
(tp-rotate-layer 1 10)
;; 堆栈: base (顶) -> highlight (底)
(tp-layer-top 1 10)))
;; => base
tp-pin-layer - 将属性层置顶
;; 缓冲区/字符串区域
(tp-pin-layer START END IDX/LAYER-NAME OBJECT)
;; 整个字符串
(tp-pin-layer STRING IDX/LAYER-NAME)
将特定属性层移到顶部(使其可见)。
示例:
;; 将 'base 设为顶层
(progn
(tp-layer-reset)
(tp-define-layer base (face default))
(tp-define-layer highlight (face (:background "yellow")))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'base)
(tp-push-layer 1 10 'highlight)
;; highlight 在顶部
(tp-pin-layer 1 10 'base)
(tp-layer-top 1 10)))
;; => base
tp-switch-layer - 交换两个属性层
;; 缓冲区/字符串区域
(tp-switch-layer START END IDX1/NAME1 IDX2/NAME2 OBJECT)
;; 整个字符串
(tp-switch-layer STRING IDX1/NAME1 IDX2/NAME2)
交换两个属性层的位置。
示例:
;; 交换 layer1 和 layer2
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
;; layer2 在顶部
(tp-switch-layer 1 10 'layer1 'layer2)
;; 现在 layer1 在顶部
(tp-layer-top 1 10)))
;; => layer1
属性层合并
tp-merge-layers - 合并多个属性层
;; 缓冲区/字符串区域
(tp-merge-layers START END NEW-LAYER-NAME '(IDX1 LAYER-NAME1 IDX2 ...) OBJECT)
;; 整个字符串
(tp-merge-layers STRING NEW-LAYER-NAME '(IDX1 LAYER-NAME1 IDX2 ...))
将指定的属性层合并为一个新属性层。列表中靠前的属性层优先级更高。
示例:
;; 将 layer1 和 layer2 合并为 merged-layer
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (help-echo "tip"))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-merge-layers 1 10 'merged-layer '(layer1 layer2))
(tp-at 1 'tp-name)))
;; => merged-layer
;; 按索引合并
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (help-echo "tip"))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-merge-layers 1 10 'merged '(0 1))
(tp-layer-count 1 10)))
;; => 1
tp-flatten-layers - 扁平化所有属性层
;; 缓冲区/字符串区域
(tp-flatten-layers START END NAME OBJECT)
;; 整个字符串
(tp-flatten-layers STRING NAME)
将所有属性层扁平化为一个具有给定名称的单一属性层。
示例:
;; 将所有属性层扁平化为 'flat-layer
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (help-echo "tip"))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-flatten-layers 1 10 'flat-layer)
(tp-at 1 'tp-name)))
;; => flat-layer
;; 使用 nil 名称扁平化(无名属性层)
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-flatten-layers 1 10 nil)
(tp-at 1 'tp-name)))
;; => nil
属性层查询函数
tp-layer-list - 列出所有属性层
(tp-layer-list START END &optional OBJECT)
获取区域中所有属性层名称的列表。
示例:
(progn
(tp-layer-reset)
(tp-define-layer highlight (face (:background "yellow")))
(tp-define-layer base (face default))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'base)
(tp-push-layer 1 10 'highlight)
(tp-layer-list 1 10)))
;; => (highlight base)
tp-layer-count
(tp-layer-count START END &optional OBJECT)
计算区域中的属性层数量。
示例:
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-layer-count 1 10)))
;; => 2
tp-layer-exists-p
(tp-layer-exists-p START END NAME &optional OBJECT)
检查区域中是否存在某属性层。
示例:
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(list (tp-layer-exists-p 1 10 'layer1)
(tp-layer-exists-p 1 10 'layer2))))
;; => (t nil)
tp-layer-top
(tp-layer-top START END &optional OBJECT)
获取顶层(可见)属性层的名称。
示例:
(progn
(tp-layer-reset)
(tp-define-layer layer1 (face bold))
(tp-define-layer layer2 (face italic))
(with-temp-buffer
(insert "Hello World")
(tp-push-layer 1 10 'layer1)
(tp-push-layer 1 10 'layer2)
(tp-layer-top 1 10)))
;; => layer2
实用示例
多属性层语法高亮
;; 可以在缓冲区中运行的完整示例
(progn
(tp-layer-reset)
;; 为不同高亮目的定义属性层
(tp-define-layer code-base
(face font-lock-keyword-face))
(tp-define-layer code-error
(face (:underline (:color "red" :style wave))
help-echo "语法错误"))
(tp-define-layer code-debug
(face (:background "dark blue")))
(with-temp-buffer
(insert (make-string 100 ?x)) ; 创建 100 字符缓冲区
;; 应用基础高亮
(tp-push-layer 1 100 'code-base)
;; 在有问题的代码上添加错误高亮
(tp-push-layer 50 60 'code-error)
;; 检查位置 55 的顶层
(tp-layer-top 50 60)))
;; => code-error
;; 切换函数(用于实际缓冲区)
(defun toggle-error-view (start end)
"在错误和正常视图之间切换。"
(interactive "r")
(tp-rotate-layer start end))
状态指示器
;; 包含属性层组的完整示例
(progn
(tp-layer-reset)
;; 将状态属性层定义为一个组
(tp-define-layer status-todo (face (:foreground "gray")))
(tp-define-layer status-progress (face (:foreground "yellow")))
(tp-define-layer status-done (face (:foreground "green")))
(tp-define-layer task-status status-todo status-progress status-done)
;; 检查组是否已定义
(length (tp-group-props 'task-status)))
;; => 3
;; 循环切换状态(用于实际缓冲区)
(defun cycle-task-status ()
"循环切换当前行的任务状态属性层。"
(interactive)
(tp-rotate-layer (line-beginning-position) (line-end-position)))
临时高亮
;; 定义临时高亮属性层
(progn
(tp-layer-reset)
(tp-define-layer temp-highlight
(face (:background "yellow")))
(tp-layer-props 'temp-highlight))
;; => (face (:background "yellow") tp-name temp-highlight)
;; 闪烁函数(用于实际缓冲区)
(defun flash-region (start end)
"临时闪烁一个区域。"
(tp-push-layer start end 'temp-highlight)
(run-with-timer 0.5 nil
(lambda (s e)
(tp-delete-layer s e 'temp-highlight))
start end))
别名
为方便使用,tp.el 提供以下别名:
| 别名 | 原函数 |
|---|---|
tp-layer-properties |
tp-layer-props |
tp-layer-group-properties |
tp-group-props |
tp-layer-group-undefine |
tp-group-undefine |
许可证
GNU 通用公共许可证 v2 或更高版本。
贡献
欢迎贡献!请随时提交 issues 或 pull requests。
tp.el - 让文本属性变得强大且易用