Byte-compile warnings swept 57 -> 0 across all modules, tests, and
doctest (docstring rewraps and quoting, defvar declarations for the
reactive test variables, prefixed doctest counters, dead-binding
removal, one impossible eq -> equal in a face-merge assertion) with
behavior preserved. GitHub Actions workflow runs an Emacs 28.1/29.4/
30.1 matrix: compile-all with warnings-as-errors, the 443-test suite,
a genuinely shuffled-order rerun (tp-run-shuffled.el runs each test
individually; ERT's member selector cannot reorder), and the 63
README doctests. Makefile gains WERROR, compile-all, and
test-shuffled. Autoload cookies added for the four interactive
commands and the define-tp/define-tps macros. package-lint: 0
findings (main file tp.el); draft MELPA recipe in docs/.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
tp-forward-do/tp-backward-do target the TIMES-th match specifically;
when fewer matches exist the string paths applied FUNCTION to the last
available match -- the wrong target -- while buffer paths applied
nothing. Both now apply nothing on shortfall and return the available
count. Updates the two legacy with-range tests that codified the
string behavior, adds four shortfall/exact-count regression tests, and
documents the contract in both READMEs and the docstrings. Suite
443/443 green.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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>
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>
- 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>
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>
- 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>
Added tp--parse-face-list helper function to parse mixed face lists
that contain both symbols and inline plist keys/values:
- (bold :foreground "green") -> symbols: (bold), plist: (:foreground "green")
- (bold (:foreground "green")) -> symbols: (bold), plist: (:foreground "green")
- (:foreground "green") -> symbols: nil, plist: (:foreground "green")
Updated tp--merge-face-values to use this helper when merging face lists.
Added test case for mixed format to tp-test-tp-add-face-override-subprops.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
When tp-add merges face properties, new props values should now
override embedded values for the same sub-properties (e.g., if
new face has :foreground "green" and embedded has :foreground "red",
result should be :foreground "green").
Updated tp--merge-string-props-into-plist to pass props as the
override value when merging faces.
Updated tp--merge-face-values to properly handle mixed face lists
(symbols + plists) when the base face is a plist.
Added test tp-test-tp-add-face-override-subprops to verify this behavior.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- tp-set: props override embedded text properties in tp-text value
- tp-add: props are merged with embedded text properties
- tp-reset: embedded properties are ignored, only props used
Added merge-mode parameter to tp--handle-tp-text-property:
- :override - props take precedence (tp-set)
- :merge - embedded props merged with props (tp-add)
- :reset - embedded props ignored (tp-reset)
Updated tests to reflect correct semantics.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Add tp--merge-string-props-into-plist to merge embedded properties
from tp-text value into props plist with proper face merging
- Simplify tp--handle-tp-text-property to use the new merge function
and return merged props directly
- Simplify tp-set, tp-reset, tp-add by removing marker-based handling
- Fix tp-add to avoid duplicate face merging for strings with tp-text
- Remove unused tp--apply-string-props-to-region and
tp--remove-internal-markers functions
- Update tests to match the simplified implementation
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
Use tp--string-has-properties-p helper function instead of checking
only position 0. This properly detects text properties that start at
non-zero positions in the string.
Added test tp-test-tp-text-with-properties-starting-at-nonzero to
verify this fix.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Modify tp--handle-tp-text-property to detect and preserve embedded text
properties in tp-text values for both strings and buffers
- Add tp--apply-string-props-to-region helper to apply string properties
- Update tp-set, tp-reset, tp-add to preserve embedded tp-text properties
by using put-text-property instead of set-text-properties when needed
- Update tp--replace-reactive-text-in-buffer to preserve embedded properties
- Add tests for tp-text with embedded text properties
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
The bug occurred because tp--parse-args was incorrectly omitting nil values
from the property list, producing (face) instead of (face nil).
Fixed the same bug pattern in:
- tp--parse-args (used by tp-set, tp-reset, tp-add)
- tp-add-to-layers
- tp-add-to-all-layers
Added 6 new regression tests for nil property values.
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
When a define-tp layer returns a plist containing other custom layer names,
those are now recursively expanded to their built-in text properties.
This fixes the issue where tp-button using tp-palette internally would
leave tp-palette as a text property instead of resolving it to the
actual face properties.
Changes:
- Added tp--plist-has-layer-key-p helper function
- Updated tp--expand-layer-in-plist to recursively expand layer props
- Updated tp-layer-props to expand nested layers in returned plist
- Updated tp-layer-props-with-arg to expand nested layers in returned plist
- Added 3 tests for nested layer resolution
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
When using tp-set on a string with tp-text, the returned string now
contains the tp-text value instead of the original string content.
For example, (tp-set "2" 'tp-text "6") now returns "6" with properties.
- Updated tp--handle-tp-text-property to return new string object
- Updated tp-set, tp-reset, tp-add to handle the new return format
- Added test for string object tp-text replacement
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Modified tp--resolve-props to not add tp-name for non-reactive plists
- Added tp-text property support for reactive text content
- Created tp--handle-tp-text-property helper for code reuse
- Added tp--update-reactive-text and tp--replace-reactive-text-in-buffer
- Updated tp-set, tp-reset, tp-add to handle tp-text property
- Added comprehensive tests for tp-text functionality
- Updated documentation with reactive text examples
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
- Convert tp-define-layer from macro to function that accepts evaluated args
- Add define-tp macro wrapper for convenient syntax
- Convert tp-define-layer-group from macro to function that accepts evaluated args
- Add define-tp-group macro wrapper for convenient syntax
- Update all tests to use new quoted format
Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>