Refactor: Extract helper functions to reduce code duplication in match/regexp functions and single-property setters

Co-authored-by: Kinneyzhang <38454496+Kinneyzhang@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-12-14 11:42:07 +00:00
parent 58daa712db
commit 39c1c6333b
3 changed files with 75 additions and 4246 deletions

9
.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
# Dependencies
dash.el
# Emacs compiled files
*.elc
# Backup files
*~
\#*\#

4164
dash.el

File diff suppressed because it is too large Load Diff

148
tp.el
View File

@ -199,6 +199,26 @@ Return the modified object (string) or region (START . END) for buffer."
(defalias 'tp-put 'tp-set (defalias 'tp-put 'tp-set
"Alias for `tp-set'.") "Alias for `tp-set'.")
(defun tp--parse-single-prop-args (start-or-string end-or-val val-or-object rest)
"Parse arguments for single-property functions like tp-set-face.
Returns (OBJECT START END VALUE)."
(let (object start finish value)
(cond
;; First arg is a string - apply to entire string
((stringp start-or-string)
(setq object start-or-string
start 0
finish (length start-or-string)
value end-or-val))
;; First arg is a number - region convention
((numberp start-or-string)
(setq start start-or-string
finish end-or-val
value val-or-object
object (car rest)))
(t (error "Invalid first argument: %S" start-or-string)))
(list object start finish value)))
(defun tp-set-face (start-or-string &optional end-or-face face-or-object &rest rest) (defun tp-set-face (start-or-string &optional end-or-face face-or-object &rest rest)
"Set face property on string or buffer region. "Set face property on string or buffer region.
@ -218,21 +238,8 @@ This function supports four calling conventions:
This replaces only the face property, preserving other properties. This replaces only the face property, preserving other properties.
Return the modified object (string) or region (START . END) for buffer." Return the modified object (string) or region (START . END) for buffer."
(let (object start finish face) (pcase-let ((`(,object ,start ,finish ,face)
(cond (tp--parse-single-prop-args start-or-string end-or-face face-or-object rest)))
;; First arg is a string - apply to entire string
((stringp start-or-string)
(setq object start-or-string
start 0
finish (length start-or-string)
face end-or-face))
;; First arg is a number - region convention
((numberp start-or-string)
(setq start start-or-string
finish end-or-face
face face-or-object
object (car rest)))
(t (error "Invalid first argument: %S" start-or-string)))
(put-text-property start finish 'face face object) (put-text-property start finish 'face face object)
(if (stringp object) (if (stringp object)
object object
@ -257,21 +264,8 @@ This function supports four calling conventions:
This replaces only the display property, preserving other properties. This replaces only the display property, preserving other properties.
Return the modified object (string) or region (START . END) for buffer." Return the modified object (string) or region (START . END) for buffer."
(let (object start finish display) (pcase-let ((`(,object ,start ,finish ,display)
(cond (tp--parse-single-prop-args start-or-string end-or-display display-or-object rest)))
;; First arg is a string - apply to entire string
((stringp start-or-string)
(setq object start-or-string
start 0
finish (length start-or-string)
display end-or-display))
;; First arg is a number - region convention
((numberp start-or-string)
(setq start start-or-string
finish end-or-display
display display-or-object
object (car rest)))
(t (error "Invalid first argument: %S" start-or-string)))
(put-text-property start finish 'display display object) (put-text-property start finish 'display display object)
(if (stringp object) (if (stringp object)
object object
@ -1099,6 +1093,34 @@ Returns (OBJECT . PROPERTIES)."
(setq properties (car properties))) (setq properties (car properties)))
(cons object properties))) (cons object properties)))
(defun tp--parse-pattern-format (pattern object)
"Parse PATTERN for (PATTERN STRING) format.
Returns (PARSED-PATTERN . OBJECT)."
(if (and (listp pattern) (stringp (car pattern)))
(cons (car pattern)
(if (stringp (cadr pattern))
(cadr pattern)
object))
(cons pattern object)))
(defun tp--deep-merge-apply (start end props obj)
"Apply PROPS to OBJ from START to END with deep merge.
Merges nested plists instead of replacing them."
(let ((pos start))
(while (< pos end)
(let* ((current-props (text-properties-at pos obj))
(next-pos (or (next-property-change pos obj end) end)))
(cl-loop for (key val) on props by #'cddr
do (let* ((current-val (plist-get current-props key))
(new-val
(cond
((and (listp val) (keywordp (car-safe val))
(listp current-val) (keywordp (car-safe current-val)))
(tp--deep-merge-plist current-val val))
(t val))))
(put-text-property pos next-pos key new-val obj)))
(setq pos next-pos)))))
(defun tp-match (pattern &rest args) (defun tp-match (pattern &rest args)
"Set properties on all occurrences of PATTERN. "Set properties on all occurrences of PATTERN.
@ -1123,12 +1145,10 @@ Returns:
- For buffers: list of (START . END) pairs for all matches." - For buffers: list of (START . END) pairs for all matches."
(let* ((parsed (tp--parse-match-args args)) (let* ((parsed (tp--parse-match-args args))
(object (car parsed)) (object (car parsed))
(properties (cdr parsed))) (properties (cdr parsed))
;; Handle (PATTERN STRING) format (parsed-pattern (tp--parse-pattern-format pattern object)))
(when (and (listp pattern) (stringp (car pattern))) (setq pattern (car parsed-pattern)
(when (stringp (cadr pattern)) object (cdr parsed-pattern))
(setq object (cadr pattern)))
(setq pattern (car pattern)))
(tp--match-apply pattern properties #'tp-set object))) (tp--match-apply pattern properties #'tp-set object)))
(defun tp-match-reset (pattern &rest args) (defun tp-match-reset (pattern &rest args)
@ -1137,11 +1157,10 @@ Same calling conventions as `tp-match'.
Unlike `tp-match', this completely replaces all existing properties." Unlike `tp-match', this completely replaces all existing properties."
(let* ((parsed (tp--parse-match-args args)) (let* ((parsed (tp--parse-match-args args))
(object (car parsed)) (object (car parsed))
(properties (cdr parsed))) (properties (cdr parsed))
(when (and (listp pattern) (stringp (car pattern))) (parsed-pattern (tp--parse-pattern-format pattern object)))
(when (stringp (cadr pattern)) (setq pattern (car parsed-pattern)
(setq object (cadr pattern))) object (cdr parsed-pattern))
(setq pattern (car pattern)))
(tp--match-apply pattern properties (tp--match-apply pattern properties
(lambda (start end props obj) (lambda (start end props obj)
(set-text-properties start end props obj)) (set-text-properties start end props obj))
@ -1153,29 +1172,11 @@ Same calling conventions as `tp-match'.
Unlike `tp-match', this deeply merges nested properties." Unlike `tp-match', this deeply merges nested properties."
(let* ((parsed (tp--parse-match-args args)) (let* ((parsed (tp--parse-match-args args))
(object (car parsed)) (object (car parsed))
(properties (cdr parsed))) (properties (cdr parsed))
(when (and (listp pattern) (stringp (car pattern))) (parsed-pattern (tp--parse-pattern-format pattern object)))
(when (stringp (cadr pattern)) (setq pattern (car parsed-pattern)
(setq object (cadr pattern))) object (cdr parsed-pattern))
(setq pattern (car pattern))) (tp--match-apply pattern properties #'tp--deep-merge-apply object)))
(tp--match-apply pattern properties
(lambda (start end props obj)
;; Deep merge for each position
(let ((pos start))
(while (< pos end)
(let* ((current-props (text-properties-at pos obj))
(next-pos (or (next-property-change pos obj end) end)))
(cl-loop for (key val) on props by #'cddr
do (let* ((current-val (plist-get current-props key))
(new-val
(cond
((and (listp val) (keywordp (car-safe val))
(listp current-val) (keywordp (car-safe current-val)))
(tp--deep-merge-plist current-val val))
(t val))))
(put-text-property pos next-pos key new-val obj)))
(setq pos next-pos)))))
object)))
(defun tp-regexp (pattern &rest args) (defun tp-regexp (pattern &rest args)
"Set properties on all matches of PATTERN (regexp). "Set properties on all matches of PATTERN (regexp).
@ -1220,24 +1221,7 @@ Unlike `tp-regexp', this deeply merges nested properties."
(let* ((parsed (tp--parse-match-args args)) (let* ((parsed (tp--parse-match-args args))
(object (car parsed)) (object (car parsed))
(properties (cdr parsed))) (properties (cdr parsed)))
(tp--regexp-apply pattern properties (tp--regexp-apply pattern properties #'tp--deep-merge-apply object)))
(lambda (start end props obj)
;; Deep merge for each position
(let ((pos start))
(while (< pos end)
(let* ((current-props (text-properties-at pos obj))
(next-pos (or (next-property-change pos obj end) end)))
(cl-loop for (key val) on props by #'cddr
do (let* ((current-val (plist-get current-props key))
(new-val
(cond
((and (listp val) (keywordp (car-safe val))
(listp current-val) (keywordp (car-safe current-val)))
(tp--deep-merge-plist current-val val))
(t val))))
(put-text-property pos next-pos key new-val obj)))
(setq pos next-pos)))))
object)))
;;; Layer list and query functions ;;; Layer list and query functions