1117 lines
23 KiB
Markdown
1117 lines
23 KiB
Markdown
# tp.el - Text Properties Library for Emacs
|
|
|
|
<p align="center">
|
|
<strong>A powerful text properties manipulation library with an innovative layer system</strong>
|
|
</p>
|
|
|
|
<p align="center">
|
|
<a href="#features">Features</a> •
|
|
<a href="#installation">Installation</a> •
|
|
<a href="#quick-start">Quick Start</a> •
|
|
<a href="#api-reference">API Reference</a> •
|
|
<a href="#the-layer-system">Layer System</a> •
|
|
<a href="README_CN.md">中文文档</a>
|
|
</p>
|
|
|
|
---
|
|
|
|
**tp.el** provides a convenient and unified API for manipulating Emacs text properties. Inspired by [ov.el](https://github.com/emacsorphanage/ov) for overlays, tp.el offers:
|
|
|
|
- **Unified API**: All property-setting functions work on both **strings** and **buffers**
|
|
- **Layer System**: Stack multiple property sets on the same text region
|
|
- **Pattern Matching**: Apply properties to text matching strings or regexps
|
|
|
|
## Features
|
|
|
|
- ✅ **Unified Object Support**: Functions like `tp-set`, `tp-match`, `tp-regexp` work on both strings and buffers
|
|
- ✅ **Clear Semantics**: `tp-reset` (replace all), `tp-set` (replace specified), `tp-add` (deep merge)
|
|
- ✅ **Nested Property Access**: Get/set/remove nested sub-properties with path syntax
|
|
- ✅ **Innovative Layer System**: Stack, rotate, and manage multiple layers of properties
|
|
- ✅ **Layer Groups**: Define reusable sets of related layers
|
|
- ✅ **Search & Navigation**: Find and navigate through propertized text
|
|
- ✅ **Pattern Matching**: Apply properties to string/regexp matches with reset/add variants
|
|
- ✅ **Clean API**: Consistent naming and calling conventions
|
|
|
|
## Requirements
|
|
|
|
- **Emacs 28.1+** (uses `object-intervals` function)
|
|
- **dash.el** (list manipulation utilities)
|
|
|
|
## Installation
|
|
|
|
```elisp
|
|
;; Add to your load-path
|
|
(add-to-list 'load-path "/path/to/tp")
|
|
(require 'tp)
|
|
```
|
|
|
|
Or with `use-package`:
|
|
|
|
```elisp
|
|
(use-package tp
|
|
:load-path "/path/to/tp")
|
|
```
|
|
|
|
---
|
|
|
|
## Quick Start
|
|
|
|
### Setting Properties
|
|
|
|
tp.el provides three main functions for setting properties, each with different semantics:
|
|
|
|
```elisp
|
|
;; tp-set: Replace only specified properties, preserve others
|
|
(tp-set 1 10 '(face bold help-echo "Hello!"))
|
|
|
|
;; tp-reset: Completely replace ALL properties
|
|
(tp-reset 1 10 '(face bold)) ; Any other properties are removed
|
|
|
|
;; tp-add: Deep merge nested properties
|
|
(tp-add 1 10 '(face (:underline t))) ; Merges with existing face
|
|
```
|
|
|
|
All three functions support four calling conventions:
|
|
|
|
```elisp
|
|
;; On current buffer (properties as a list)
|
|
(tp-set 1 10 '(face bold help-echo "Hello!"))
|
|
|
|
;; On a specific buffer
|
|
(tp-set 1 10 '(face bold) some-buffer)
|
|
|
|
;; On a string with range (0-indexed)
|
|
(tp-set 0 5 '(face bold) "Hello World")
|
|
;; => #("Hello World" 0 5 (face bold))
|
|
|
|
;; On entire string (flat properties)
|
|
(tp-set "Hello World" 'face 'bold 'help-echo "test")
|
|
;; => #("Hello World" 0 11 (face bold help-echo "test"))
|
|
```
|
|
|
|
### Single-Property Setters
|
|
|
|
```elisp
|
|
;; Set only face property
|
|
(tp-set-face 1 10 'bold)
|
|
(tp-set-face "Hello" 'italic) ; entire string
|
|
|
|
;; Set only display property
|
|
(tp-set-display 1 10 '(space :width 10))
|
|
```
|
|
|
|
### Getting Properties
|
|
|
|
```elisp
|
|
;; Get specific property at position
|
|
(tp-get 5 'face) ; => bold
|
|
|
|
;; Get nested sub-property
|
|
(tp-get 5 'face :foreground) ; => "red"
|
|
(tp-get 5 'face :box :color) ; => "blue" (deeply nested)
|
|
|
|
;; Get specific property from range
|
|
(tp-get 1 10 'face) ; => bold
|
|
|
|
;; Get all properties from range
|
|
(tp-get 1 10) ; => (face bold help-echo "Hello!")
|
|
|
|
;; Get all properties at point
|
|
(tp-at 5) ; => (face bold help-echo "Hello!")
|
|
```
|
|
|
|
### Removing Properties
|
|
|
|
```elisp
|
|
;; Remove entire property
|
|
(tp-remove 1 10 'face)
|
|
|
|
;; Remove sub-property
|
|
(tp-remove 1 10 '(face :underline))
|
|
|
|
;; Remove nested sub-properties (keep others)
|
|
(tp-remove 1 10 '(face :underline (:style :position)))
|
|
;; Removes :style and :position from :underline, keeps :color if present
|
|
```
|
|
|
|
### Pattern Matching
|
|
|
|
```elisp
|
|
;; Apply properties to all occurrences of "TODO" in buffer
|
|
(tp-match "TODO" '(face warning))
|
|
|
|
;; Apply to string
|
|
(tp-match "world" "Hello world world" '(face bold))
|
|
;; => #("Hello world world" 6 11 (face bold) 12 17 (face bold))
|
|
|
|
;; Match with (PATTERN STRING) format
|
|
(tp-match '("world" "Hello world") '(face bold))
|
|
;; => #("Hello world" 6 11 (face bold))
|
|
|
|
;; Using regexp
|
|
(tp-regexp "\\b[0-9]+\\b" '(face font-lock-number-face))
|
|
|
|
;; Reset variants (replace ALL properties on matches)
|
|
(tp-match-reset "TODO" '(face warning))
|
|
(tp-regexp-reset "[0-9]+" '(face bold))
|
|
|
|
;; Add variants (deep merge properties on matches)
|
|
(tp-match-add "TODO" '(face (:underline t)))
|
|
(tp-regexp-add "[0-9]+" '(face (:weight bold)))
|
|
```
|
|
|
|
---
|
|
|
|
## API Reference
|
|
|
|
### Core Property Functions
|
|
|
|
#### `tp-set` - Set Text Properties
|
|
|
|
Set text properties on a string or buffer region. Replaces only the specified properties, preserving others.
|
|
|
|
```elisp
|
|
;; Current buffer (properties as a list)
|
|
(tp-set START END '(PROPERTY VALUE ...))
|
|
|
|
;; Specific buffer or string
|
|
(tp-set START END '(PROPERTY VALUE ...) OBJECT)
|
|
|
|
;; Entire string (flat properties)
|
|
(tp-set STRING PROPERTY VALUE ...)
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Set face on buffer region
|
|
(tp-set 1 10 '(face bold)) ; => (1 . 10)
|
|
|
|
;; Set multiple properties
|
|
(tp-set 1 10 '(face bold help-echo "Click me"))
|
|
|
|
;; Set on specific buffer
|
|
(tp-set 1 10 '(face italic) my-buffer)
|
|
|
|
;; Set properties on a string (0-indexed)
|
|
(setq my-string (tp-set 0 5 '(face italic) "Hello World"))
|
|
;; => #("Hello World" 0 5 (face italic))
|
|
|
|
;; Set properties on entire string
|
|
(tp-set "Hello" 'face 'bold 'mouse-face 'highlight)
|
|
;; => #("Hello" 0 5 (face bold mouse-face highlight))
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-reset` - Replace All Properties
|
|
|
|
Completely replace ALL text properties with the specified ones.
|
|
|
|
```elisp
|
|
(tp-reset START END '(PROPERTY VALUE ...) &optional OBJECT)
|
|
(tp-reset STRING PROPERTY VALUE ...)
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Replace all properties in region
|
|
(tp-reset 1 10 '(face bold)) ; Any existing properties are removed
|
|
|
|
;; On string
|
|
(tp-reset "Hello" 'face 'italic)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-add` - Add/Merge Properties
|
|
|
|
Add or update properties with deep merge support for nested plists.
|
|
|
|
```elisp
|
|
(tp-add START END '(PROPERTY VALUE ...) &optional OBJECT)
|
|
(tp-add STRING PROPERTY VALUE ...)
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Add properties (preserves existing, merges nested)
|
|
(tp-add 1 10 '(help-echo "tooltip"))
|
|
|
|
;; Deep merge face properties
|
|
(tp-set 1 10 '(face (:foreground "red")))
|
|
(tp-add 1 10 '(face (:background "blue")))
|
|
;; Result: face is (:foreground "red" :background "blue")
|
|
|
|
;; Face prepending - symbol faces are prepended to face list
|
|
(tp-set "Hello" 'face 'bold)
|
|
(tp-add "Hello" 'face 'shadow)
|
|
;; Result: face is (shadow bold)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-set-face` - Set Face Property
|
|
|
|
Set only the face property, preserving other properties.
|
|
|
|
```elisp
|
|
(tp-set-face START END FACE &optional OBJECT)
|
|
(tp-set-face STRING FACE)
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-set-face 1 10 'bold)
|
|
(tp-set-face 1 10 '(:foreground "red" :weight bold))
|
|
(tp-set-face "Hello" 'italic)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-set-display` - Set Display Property
|
|
|
|
Set only the display property, preserving other properties.
|
|
|
|
```elisp
|
|
(tp-set-display START END DISPLAY &optional OBJECT)
|
|
(tp-set-display STRING DISPLAY)
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-set-display 1 10 '(space :width 10))
|
|
(tp-set-display " " '(space :width 20))
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-get` - Get Property Value
|
|
|
|
Get property value(s) from position or range, with support for nested sub-properties.
|
|
|
|
For range and entire string queries, returns a list of `(START END VALUE)` intervals, allowing you to see all property values across the range.
|
|
|
|
```elisp
|
|
;; Single position
|
|
(tp-get POSITION PROPERTY)
|
|
(tp-get POSITION PROPERTY OBJECT)
|
|
|
|
;; Nested sub-property access
|
|
(tp-get POSITION PROPERTY SUB-KEY ...)
|
|
|
|
;; Range - specific property (returns list of intervals)
|
|
(tp-get START END PROPERTY)
|
|
(tp-get START END PROPERTY OBJECT)
|
|
|
|
;; Range with property path as list
|
|
(tp-get START END '(PROPERTY) OBJECT)
|
|
(tp-get START END '(PROPERTY SUB-KEY ...) OBJECT)
|
|
|
|
;; Range with deeply nested property path
|
|
(tp-get START END '(PROPERTY SUB-KEY SUB-SUB-KEY ...) OBJECT)
|
|
|
|
;; Range extracting multiple keys from nested property
|
|
(tp-get START END '(PROPERTY SUB-KEY (KEY1 KEY2 ...)) OBJECT)
|
|
|
|
;; Range - all properties (returns list of intervals)
|
|
(tp-get START END)
|
|
(tp-get START END OBJECT)
|
|
|
|
;; Entire string (returns list of intervals)
|
|
(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 ...))
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Get from current buffer
|
|
(tp-get 5 'face) ; => bold
|
|
|
|
;; Get nested sub-property
|
|
(tp-get 5 'face :foreground) ; => "red"
|
|
(tp-get 5 'face :box :color) ; => "blue"
|
|
(tp-get 5 'display :width) ; => 10
|
|
|
|
;; Get from string (0-indexed)
|
|
(tp-get 0 'face my-string) ; => italic
|
|
|
|
;; Get from range - returns list of (START END VALUE) intervals
|
|
(tp-get 1 10 'face) ; => ((1 6 bold))
|
|
|
|
;; Get with multiple intervals
|
|
(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))
|
|
|
|
;; Get with property path as list
|
|
(tp-get 5 20 '(face :underline :style) my-string) ; => ((5 20 wave))
|
|
|
|
;; Get deeply nested property from entire string
|
|
(tp-get str 'face :underline :color) ; => ((0 5 "green") (6 11 "yellow"))
|
|
|
|
;; Get multiple keys from nested property
|
|
(tp-get str 'face :underline '(:color :style))
|
|
;; => ((0 5 (:color "green" :style wave)) (6 11 (:color "yellow" :style line)))
|
|
|
|
;; Get all properties from range
|
|
(tp-get 1 10) ; => ((1 6 (face bold help-echo "test")))
|
|
|
|
;; Get from entire string - returns list of intervals
|
|
(tp-get str) ; => ((0 5 (face bold)) (12 17 (face italic)))
|
|
(tp-get str 'face) ; => ((0 5 bold) (12 17 italic))
|
|
(tp-get str 'face :foreground) ; => ((0 5 "red") (12 17 "blue"))
|
|
(tp-get str '(face :foreground)) ; => ((0 5 "red") (12 17 "blue"))
|
|
```
|
|
|
|
---
|
|
|
|
#### Fine-grained Property Functions
|
|
|
|
For manipulating sub-properties within complex properties like `face` or `display`:
|
|
|
|
```elisp
|
|
;; Get sub-property
|
|
(tp-get-sub POSITION PROPERTY SUB-PROPERTY &optional OBJECT)
|
|
|
|
;; Set sub-property
|
|
(tp-put-sub START END PROPERTY SUB-PROPERTY VALUE &optional OBJECT)
|
|
|
|
;; Remove sub-property
|
|
(tp-remove-sub START END PROPERTY SUB-PROPERTY &optional OBJECT)
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Get :foreground from face
|
|
(tp-get-sub 1 'face :foreground) ; => "red"
|
|
|
|
;; Set :weight on face
|
|
(tp-put-sub 1 6 'face :weight 'bold)
|
|
|
|
;; Remove :background from face
|
|
(tp-remove-sub 1 6 'face :background)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-at` - Get All Properties
|
|
|
|
```elisp
|
|
(tp-at &optional POINT OBJECT)
|
|
```
|
|
|
|
Get all text properties at POINT as a plist.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-at 5) ; => (face bold help-echo "test")
|
|
(tp-at 0 my-string) ; Get from string
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-remove` - Remove Property
|
|
|
|
Remove a property or nested sub-property from a region or entire string.
|
|
|
|
```elisp
|
|
;; Remove entire property (buffer)
|
|
(tp-remove START END PROPERTY &optional OBJECT)
|
|
|
|
;; Remove sub-property (buffer)
|
|
(tp-remove START END '(PROPERTY SUB-KEY) &optional OBJECT)
|
|
|
|
;; Remove nested sub-properties (buffer)
|
|
(tp-remove START END '(PROPERTY SUB-KEY (NESTED-KEYS...)) &optional OBJECT)
|
|
|
|
;; Remove from entire string
|
|
(tp-remove STRING PROP1 PROP2 ...)
|
|
(tp-remove STRING PROPERTY SUB-KEY)
|
|
(tp-remove STRING PROPERTY SUB-KEY '(NESTED-KEYS...))
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Remove entire property
|
|
(tp-remove 1 10 'face)
|
|
|
|
;; Remove sub-property from face
|
|
(tp-remove 1 10 '(face :underline))
|
|
|
|
;; Remove specific nested keys, keep others
|
|
(tp-remove 1 10 '(face :underline (:style :position)))
|
|
;; Removes :style and :position from :underline
|
|
;; If :color exists in :underline, it's preserved
|
|
|
|
;; Remove from entire string
|
|
(tp-remove "Hello World" 'face 'help-echo) ; Remove multiple properties
|
|
(tp-remove "Hello World" 'face :underline) ; Remove sub-property
|
|
(tp-remove "Hello World" 'face :underline '(:style :position)) ; Remove nested
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-remove-list` - Remove Multiple Properties
|
|
|
|
```elisp
|
|
(tp-remove-list START END PROPERTIES &optional OBJECT)
|
|
```
|
|
|
|
Remove multiple properties at once.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-remove-list 1 10 '(face help-echo mouse-face))
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-clear` - Clear All Properties
|
|
|
|
```elisp
|
|
(tp-clear &optional START END OBJECT)
|
|
```
|
|
|
|
Clear all text properties from a region.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-clear 1 10) ; Clear region
|
|
(tp-clear) ; Clear entire buffer
|
|
```
|
|
|
|
---
|
|
|
|
### Pattern Matching Functions
|
|
|
|
#### `tp-match` - Match String
|
|
|
|
```elisp
|
|
;; Buffer
|
|
(tp-match PATTERN '(PROPERTY VALUE ...))
|
|
|
|
;; String or Buffer object
|
|
(tp-match PATTERN OBJECT '(PROPERTY VALUE ...))
|
|
|
|
;; Pattern as (PATTERN STRING) format
|
|
(tp-match '(PATTERN STRING) '(PROPERTY VALUE ...))
|
|
```
|
|
|
|
Set properties on all occurrences of a string pattern.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; In buffer - returns list of (START . END) pairs
|
|
(tp-match "TODO" '(face warning))
|
|
;; => ((10 . 14) (50 . 54) ...)
|
|
|
|
;; On string - returns modified string
|
|
(tp-match "o" "Hello World" '(face bold))
|
|
;; => #("Hello World" 4 5 (face bold) 7 8 (face bold))
|
|
|
|
;; Using (PATTERN STRING) format
|
|
(tp-match '("world" "Hello world") '(face bold))
|
|
;; => #("Hello world" 6 11 (face bold))
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-match-reset` - Match and Reset
|
|
|
|
Reset (completely replace) all properties on matches.
|
|
|
|
```elisp
|
|
(tp-match-reset PATTERN '(PROPERTY VALUE ...) &optional OBJECT)
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-match-reset "TODO" '(face warning))
|
|
;; Replaces ALL properties on matched text
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-match-add` - Match and Add
|
|
|
|
Add/merge properties on matches with deep merge support.
|
|
|
|
```elisp
|
|
(tp-match-add PATTERN '(PROPERTY VALUE ...) &optional OBJECT)
|
|
```
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-match-add "TODO" '(face (:underline t)))
|
|
;; Merges with existing properties
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-regexp` - Match Regexp
|
|
|
|
```elisp
|
|
;; Buffer
|
|
(tp-regexp PATTERN '(PROPERTY VALUE ...))
|
|
|
|
;; String or Buffer object
|
|
(tp-regexp PATTERN OBJECT '(PROPERTY VALUE ...))
|
|
```
|
|
|
|
Set properties on all matches of a regular expression.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Highlight all numbers in buffer
|
|
(tp-regexp "[0-9]+" '(face font-lock-number-face))
|
|
|
|
;; On string
|
|
(tp-regexp "[A-Z]+" "Hello WORLD" '(face bold))
|
|
;; => #("Hello WORLD" 6 11 (face bold))
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-regexp-reset` - Regexp and Reset
|
|
|
|
Reset (completely replace) all properties on regexp matches.
|
|
|
|
```elisp
|
|
(tp-regexp-reset PATTERN '(PROPERTY VALUE ...) &optional OBJECT)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-regexp-add` - Regexp and Add
|
|
|
|
Add/merge properties on regexp matches with deep merge support.
|
|
|
|
```elisp
|
|
(tp-regexp-add PATTERN '(PROPERTY VALUE ...) &optional OBJECT)
|
|
```
|
|
|
|
---
|
|
|
|
### Propertize Functions
|
|
|
|
#### `tp-layer-propertize` - Apply Layer to Object
|
|
|
|
```elisp
|
|
(tp-layer-propertize OBJECT LAYER &optional START END)
|
|
```
|
|
|
|
Apply a predefined layer's properties to an object.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Define a layer first
|
|
(tp-layer-define highlight '(face (:background "yellow")))
|
|
|
|
;; Apply to string
|
|
(tp-layer-propertize "Important" 'highlight)
|
|
|
|
;; Apply to substring
|
|
(tp-layer-propertize "Hello World" 'highlight 0 5)
|
|
|
|
;; Apply to buffer region
|
|
(tp-layer-propertize (current-buffer) 'highlight 1 10)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-group-propertize` - Apply Layer Group
|
|
|
|
```elisp
|
|
(tp-group-propertize OBJECT LAYER-GROUP &optional START END)
|
|
```
|
|
|
|
Apply all layers from a layer group to an object.
|
|
|
|
---
|
|
|
|
### Search & Navigation Functions
|
|
|
|
#### `tp-forward` / `tp-backward`
|
|
|
|
```elisp
|
|
(tp-forward PROPERTY &optional VALUE PREDICATE NOT-CURRENT)
|
|
(tp-backward PROPERTY &optional VALUE PREDICATE NOT-CURRENT)
|
|
```
|
|
|
|
Search forward/backward for text with PROPERTY.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Find next text with 'marker property
|
|
(tp-forward 'marker)
|
|
|
|
;; Find next text where 'type equals 'heading
|
|
(tp-forward 'type 'heading)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-next` / `tp-prev`
|
|
|
|
```elisp
|
|
(tp-next &optional POINT PROPERTY VALUE)
|
|
(tp-prev &optional POINT PROPERTY VALUE)
|
|
```
|
|
|
|
Get the next/previous position with text properties.
|
|
|
|
---
|
|
|
|
#### `tp-goto-next` / `tp-goto-prev`
|
|
|
|
```elisp
|
|
(tp-goto-next &optional PROPERTY VALUE)
|
|
(tp-goto-prev &optional PROPERTY VALUE)
|
|
```
|
|
|
|
Move point to next/previous text with PROPERTY.
|
|
|
|
---
|
|
|
|
#### `tp-regions-map` / `tp-strings-map`
|
|
|
|
```elisp
|
|
(tp-regions-map FUNCTION PROPERTY &optional VALUE PREDICATE COLLECT)
|
|
(tp-strings-map FUNCTION PROPERTY &optional VALUE PREDICATE COLLECT)
|
|
```
|
|
|
|
Apply a function to all regions/strings with PROPERTY.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Upcase all marked text
|
|
(tp-strings-map
|
|
(lambda (str idx)
|
|
(message "Found: %s at index %d" str idx))
|
|
'marker)
|
|
```
|
|
|
|
---
|
|
|
|
### Query Functions
|
|
|
|
#### `tp-in` - Find Regions with Property
|
|
|
|
```elisp
|
|
(tp-in PROPERTY &optional VALUE START END)
|
|
```
|
|
|
|
Get all regions with PROPERTY in current buffer.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Get all regions with 'marker property
|
|
(tp-in 'marker)
|
|
;; => ((1 5 (marker t ...)) (10 15 (marker t ...)))
|
|
|
|
;; Filter by value
|
|
(tp-in 'type 'heading)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-all` - Get All Propertized Regions
|
|
|
|
```elisp
|
|
(tp-all &optional START END)
|
|
```
|
|
|
|
Get all regions with any text properties.
|
|
|
|
---
|
|
|
|
#### `tp-intervals` - Get Property Intervals
|
|
|
|
```elisp
|
|
(tp-intervals START END &optional OBJECT)
|
|
```
|
|
|
|
Get all text property intervals in a region.
|
|
|
|
---
|
|
|
|
#### `tp-empty-p` - Check for Properties
|
|
|
|
```elisp
|
|
(tp-empty-p OBJECT)
|
|
```
|
|
|
|
Return t if OBJECT has no text properties.
|
|
|
|
---
|
|
|
|
#### `tp-plist` - Get Merged Properties
|
|
|
|
```elisp
|
|
(tp-plist START END &optional OBJECT)
|
|
```
|
|
|
|
Get a merged plist of all properties in a region.
|
|
|
|
---
|
|
|
|
## The Layer System
|
|
|
|
The **layer system** is tp.el's innovative feature that allows stacking multiple sets of properties on the same text region. Only the **top layer** is visible, but lower layers are preserved and can be revealed through rotation or pinning.
|
|
|
|
### Layer Concept
|
|
|
|
```
|
|
┌─────────────────────────────┐
|
|
│ TOP LAYER (visible) │ ← What you see
|
|
├─────────────────────────────┤
|
|
│ Middle Layer (hidden) │ ← Preserved
|
|
├─────────────────────────────┤
|
|
│ Bottom Layer (hidden) │ ← Preserved
|
|
└─────────────────────────────┘
|
|
```
|
|
|
|
### Layer Definition Functions
|
|
|
|
#### `tp-layer-define` - Define a Layer
|
|
|
|
```elisp
|
|
(tp-layer-define NAME PROPERTIES)
|
|
```
|
|
|
|
Define a named layer with properties.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-layer-define highlight
|
|
'(face (:background "yellow" :foreground "black")))
|
|
|
|
(tp-layer-define error
|
|
'(face (:background "red" :foreground "white")
|
|
help-echo "Error!"))
|
|
|
|
(tp-layer-define info
|
|
'(face (:background "blue" :foreground "white")))
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-group-define` - Define Layer Group
|
|
|
|
```elisp
|
|
(tp-group-define NAME
|
|
LAYER1 PROPERTIES1
|
|
LAYER2 PROPERTIES2
|
|
...)
|
|
```
|
|
|
|
Define a group of related layers.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-group-define status-colors
|
|
status-ok '(face (:foreground "green"))
|
|
status-warning '(face (:foreground "orange"))
|
|
status-error '(face (:foreground "red")))
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-layer-props` / `tp-group-props`
|
|
|
|
```elisp
|
|
(tp-layer-props LAYER-NAME)
|
|
(tp-group-props GROUP-NAME)
|
|
```
|
|
|
|
Get properties for a layer or all layers in a group.
|
|
|
|
---
|
|
|
|
#### `tp-layer-undefine` / `tp-group-undefine`
|
|
|
|
```elisp
|
|
(tp-layer-undefine NAME)
|
|
(tp-group-undefine NAME)
|
|
```
|
|
|
|
Remove layer or group definition.
|
|
|
|
---
|
|
|
|
#### `tp-layer-reset`
|
|
|
|
```elisp
|
|
(tp-layer-reset)
|
|
```
|
|
|
|
Clear all layer and group definitions.
|
|
|
|
---
|
|
|
|
### Layer Manipulation Functions
|
|
|
|
#### `tp-layer-push` - Add Layer
|
|
|
|
```elisp
|
|
(tp-layer-push START END NAME &optional OBJECT)
|
|
```
|
|
|
|
Push a layer to the top of the stack.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-layer-define base '(face default))
|
|
(tp-layer-define highlight '(face (:background "yellow")))
|
|
|
|
;; Push base layer first
|
|
(tp-layer-push 1 10 'base)
|
|
|
|
;; Push highlight on top (now visible)
|
|
(tp-layer-push 1 10 'highlight)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-layer-delete` - Remove Layer
|
|
|
|
```elisp
|
|
(tp-layer-delete START END NAME &optional OBJECT)
|
|
```
|
|
|
|
Delete a layer from anywhere in the stack.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Remove the highlight layer
|
|
(tp-layer-delete 1 10 'highlight)
|
|
;; base layer is now visible
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-layer-rotate` - Cycle Layers
|
|
|
|
```elisp
|
|
(tp-layer-rotate START END &optional OBJECT)
|
|
```
|
|
|
|
Rotate layers - top goes to bottom, next becomes visible.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Stack: highlight (top) -> base (bottom)
|
|
(tp-layer-rotate 1 10)
|
|
;; Stack: base (top) -> highlight (bottom)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-layer-pin` - Bring Layer to Top
|
|
|
|
```elisp
|
|
(tp-layer-pin START END NAME &optional OBJECT)
|
|
```
|
|
|
|
Move a specific layer to the top.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
;; Make 'base the top layer
|
|
(tp-layer-pin 1 10 'base)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-layer-hide` / `tp-layer-show`
|
|
|
|
```elisp
|
|
(tp-layer-hide START END NAME &optional OBJECT)
|
|
(tp-layer-show START END NAME &optional OBJECT)
|
|
```
|
|
|
|
Hide layer (move to bottom) or show layer (move to top).
|
|
|
|
---
|
|
|
|
#### `tp-layer-merge`
|
|
|
|
```elisp
|
|
(tp-layer-merge START END LAYER1 LAYER2 NEW-NAME &optional OBJECT)
|
|
```
|
|
|
|
Merge two layers into one new layer.
|
|
|
|
---
|
|
|
|
### Layer Query Functions
|
|
|
|
#### `tp-layer-list` - List All Layers
|
|
|
|
```elisp
|
|
(tp-layer-list START END &optional OBJECT)
|
|
```
|
|
|
|
Get list of all layer names in region.
|
|
|
|
**Examples:**
|
|
|
|
```elisp
|
|
(tp-layer-list 1 10) ; => (highlight base)
|
|
```
|
|
|
|
---
|
|
|
|
#### `tp-layer-count`
|
|
|
|
```elisp
|
|
(tp-layer-count START END &optional OBJECT)
|
|
```
|
|
|
|
Count layers in region.
|
|
|
|
---
|
|
|
|
#### `tp-layer-exists-p`
|
|
|
|
```elisp
|
|
(tp-layer-exists-p START END NAME &optional OBJECT)
|
|
```
|
|
|
|
Check if layer exists in region.
|
|
|
|
---
|
|
|
|
#### `tp-layer-top`
|
|
|
|
```elisp
|
|
(tp-layer-top START END &optional OBJECT)
|
|
```
|
|
|
|
Get name of the top (visible) layer.
|
|
|
|
---
|
|
|
|
## Practical Examples
|
|
|
|
### Syntax Highlighting with Multiple Layers
|
|
|
|
```elisp
|
|
;; Define layers for different highlighting purposes
|
|
(tp-layer-define code-base
|
|
'(face font-lock-keyword-face))
|
|
|
|
(tp-layer-define code-error
|
|
'(face (:underline (:color "red" :style wave))
|
|
help-echo "Syntax error"))
|
|
|
|
(tp-layer-define code-debug
|
|
'(face (:background "dark blue")))
|
|
|
|
;; Apply base highlighting
|
|
(tp-layer-push 1 100 'code-base)
|
|
|
|
;; Add error highlight on problematic code
|
|
(tp-layer-push 50 60 'code-error)
|
|
|
|
;; Toggle between error and normal view
|
|
(defun toggle-error-view ()
|
|
(interactive)
|
|
(tp-layer-rotate 50 60))
|
|
```
|
|
|
|
### Status Indicator
|
|
|
|
```elisp
|
|
(tp-group-define task-status
|
|
status-todo '(face (:foreground "gray"))
|
|
status-progress '(face (:foreground "yellow"))
|
|
status-done '(face (:foreground "green")))
|
|
|
|
;; Cycle through statuses
|
|
(defun cycle-task-status ()
|
|
(interactive)
|
|
(tp-layer-rotate (line-beginning-position) (line-end-position)))
|
|
```
|
|
|
|
### Temporary Highlights
|
|
|
|
```elisp
|
|
(tp-layer-define temp-highlight
|
|
'(face (:background "yellow")))
|
|
|
|
(defun flash-region (start end)
|
|
"Flash a region temporarily."
|
|
(tp-layer-push start end 'temp-highlight)
|
|
(run-with-timer 0.5 nil
|
|
(lambda ()
|
|
(tp-layer-delete start end 'temp-highlight))))
|
|
```
|
|
|
|
---
|
|
|
|
## Aliases
|
|
|
|
For convenience, tp.el provides these aliases:
|
|
|
|
| Alias | Original Function |
|
|
|-------|-------------------|
|
|
| `tp-put` | `tp-set` |
|
|
| `tp-layer-properties` | `tp-layer-props` |
|
|
| `tp-layer-group-define` | `tp-group-define` |
|
|
| `tp-layer-group-properties` | `tp-group-props` |
|
|
| `tp-layer-group-propertize` | `tp-group-propertize` |
|
|
| `tp-layer-group-undefine` | `tp-group-undefine` |
|
|
|
|
### Deprecated Functions
|
|
|
|
| Function | Replacement | Notes |
|
|
|----------|-------------|-------|
|
|
| `tp-propertize` | `tp-set` | Use `tp-set` for new code |
|
|
|
|
---
|
|
|
|
## License
|
|
|
|
GNU General Public License v2 or later.
|
|
|
|
---
|
|
|
|
## Contributing
|
|
|
|
Contributions are welcome! Please feel free to submit issues or pull requests.
|
|
|
|
---
|
|
|
|
<p align="center">
|
|
<em>tp.el - Making text properties powerful and easy to use</em>
|
|
</p>
|