35 fixes across tp-layer.el, tp-stack.el, tp-search.el, tp-reactive.el
and tp-render.el, each empirically reproduced before and after:
layer-definition resolution/cycles/copying/cleanup, clipped region-local
stack mutators, symmetric backward search matching, length-changing
replacements, and reactive re-render correctness (replace-not-accumulate,
buffer-local isolation, batching union, per-interval props).
Adds four per-module regression suites (100 new tests); combined suite
is 438/438 green. tp-test-backward updated to the now-symmetric backward
matching contract it previously codified inverted. The string-vs-buffer
shortfall divergence in tp-forward-do/tp-backward-do is documented in
CHANGELOG as a known divergence rather than changed. Adds CHANGELOG.md.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Like tp-at but distinguishes a property present with value nil from an
absent property, returning (PROPERTY VALUE) or nil. Covered by four
new tests in tp-ops-tests.el; full suite 338/338 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
ops/core (B1-B8): tp-remove no longer drops 3rd+ properties; string
removal is per-interval via tp--map-intervals instead of smearing
position-0 props; tp-clear defaults bounds from OBJECT; (tp-get STR N N)
works like the buffer region form; no bogus (:key nil) from trailing
bare keywords; region form signals immediately on flat PROP/VAL args;
face-family prepend semantics extended to font-lock-face/mouse-face.
builtins/palette (B45-B51): Emacs 28.1 compat for plistp/subr-x;
display-buffer macros use a minor-mode keymap instead of mutating the
major-mode map; tp-link resolves palette colors lazily (theme-correct);
tp-palette-alist is the single source of truth (stale defvars dropped);
tp-headline handles integer heights; tp-space matches its documented
pixel spec; tp-parse-color accepts one-sided cons colors.
Test infra: fixture gains unwind-protect teardown via tp-layer-reset
(incl. transforms); file header/provide renamed to tp-tests; suite is
order-independent (verified with shuffled runs). Adds Makefile with
test/compile/clean targets.
334 tests green (280 legacy + 54 new regression tests).
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tp.el (4866 lines) is now an umbrella over nine modules with an
enforceable dependency order: tp-core -> tp-reactive -> tp-layer ->
tp-ops -> tp-search -> tp-render -> tp-stack -> tp-palette ->
tp-builtins. Upward dependencies are inverted through four hook
variables installed by tp-render.el.
Also: require text-property-search (fixes tp-backward void-function),
clip tp-intervals to the requested range, add the shared clipping
interval walker tp--map-intervals and tp-face-properties, remove
synced-conflict junk files, byte-compilation now succeeds (define-tp
macroexpansion previously failed at compile time).
All 280 legacy tests pass plus 8 new tp-core tests.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
When (frame-parameter nil 'background-mode) returns nil (e.g., in
batch mode or certain configurations), both tp-theme-light-p and
tp-theme-dark-p return nil, causing color parsing to fail for
cons cell ("light" . "dark") and plist (:light "l" :dark "d") formats.
Added default fallback to light color when background-mode is unknown.
This is the root cause of tp-palette settings not taking effect.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
Fixed the pcase branches for tp-palette-bg-p and tp-palette-fbg-p
predicates which had an extra `symbol` keyword incorrectly placed
between the pattern and the return expression. This caused these
branches to return the original symbol instead of the processed
intern result, leading to tp-palette settings not taking effect
when using palettes with -bg or -fbg suffixes.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Rename second tp--remove-nested-keys to tp--remove-nested-sub-keys
- Fix logic in tp--remove-props-from-string to properly handle nil face subtraction result
- Fix tests to properly use return values from tp-set and tp-remove
- Add face-was-modified tracking variable
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Add tp--remove-sub-from-face-value to handle complex face structures
- Add tp--subtract-face-from-face-value to remove layer face contributions
- Add tp--get-layer-face-contribution helper function
- Update tp--remove-props-from-string to handle layer face subtraction
- Update tp--remove-sub-from-string to use new helper
- Update tp--expand-layer-to-props-list to detect layer properties
- Fix missing closing paren in tp--remove-property function
- Update tests to match expected behavior
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
When tp-remove is called with a layer name (defined with define-tp),
it now correctly identifies and removes all properties that the layer
adds, plus the tp-name property.
Example:
(define-tp tp-delete (color)
`(face (:strike-through ,color)))
(let ((str "emacs"))
(setq str (tp-set str 'face 'bold 'tp-delete t))
(insert (tp-remove str 'tp-delete)))
Changes:
- Added tp--expand-layer-to-props-list helper function
- Added tp--expand-props-to-remove helper function
- Modified tp--remove-props-from-string to expand layer names
- Modified tp--remove-property for buffer regions to handle layer names
- Added tests for custom layer removal
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
Added detailed behavior table and examples to README_CN.md:
- tp-set, tp-reset, tp-add, tp-remove sections now explain:
- Entire string form creates a NEW string (non-destructive)
- Region form with string modifies in-place
- Underlying implementation (propertize vs put-text-property)
- Updated return value documentation
- Updated tp-add-to-layers and tp-add-to-all-layers sections
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Collect all match positions before applying transformations to avoid
string-match position invalidation issues
- Use list* instead of nested cons for better readability
- Improve plist building efficiency by iterating instead of copy-sequence
- Add detailed comment explaining :reset mode usage with tp-text
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
Updated the implementation to clearly distinguish:
- (tp-set/add/reset START END PROPS STRING): Modifies original string in-place
- (tp-set/add/reset "string" PROP VAL ...): Creates NEW string using propertize
Also fixed code review issues:
- Removed unused 'offset' variable
- Made tp--remove-nested-keys non-destructive
Updated documentation with detailed behavior table and examples.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This change makes tp-set, tp-add, tp-reset, and tp-remove return a NEW
propertized string when operating on strings, rather than modifying the
original string in-place. This is more idiomatic for Emacs Lisp and
prevents unintended side effects.
For buffer operations, the existing in-place modification behavior is
preserved.
Key changes:
- Added tp--apply-props-to-string helper function that uses propertize
- Updated tp-set, tp-add, tp-reset to use the new helper for strings
- Updated tp-remove with new helper functions for non-destructive removal
- Updated tp--match-apply and tp--regexp-apply to accumulate changes
- Added tests verifying original strings are not modified
- Updated documentation to reflect the new behavior
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
When face values contain mixed lists (symbols and plists like
(bold (:foreground "green"))), the plist parts are now correctly
merged with earlier plists. This ensures that later values for
the same sub-property (like :foreground) properly override earlier
values without creating duplicates.
Example that now works correctly:
(tp-add
(tp-add
(tp-set "emacs" 'face 'bold)
'face '(:foreground "red"))
'face '(bold (:foreground "green")))
=> face is (bold (:foreground "green")) instead of
(bold (:foreground "green") (:foreground "red"))
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Fix tp--equal-including-string-properties to only use
equal-including-properties when BOTH args are strings
- Improve test to use (point-min) and (point-max) instead of
hardcoded positions
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
Changed from using tp-add to set-text-properties when text content is
same but properties differ. This prevents duplicate property merging
since merged-props already contains the complete set of properties.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Added `tp--equal-including-string-properties` helper function that uses
`equal-including-properties` for strings to properly detect changes in
text properties when the text content is the same
- Updated `tp--reactive-variable-watcher` to use this new comparison function
- Updated `tp--replace-reactive-text-in-buffer` to use `tp-add` when text
content is the same but properties may differ
- Added test `tp-test-tp-text-same-text-different-properties` to verify
the fix
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>