aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCraig Jennings <c@cjennings.net>2026-06-24 15:48:43 -0400
committerCraig Jennings <c@cjennings.net>2026-06-24 15:48:43 -0400
commitab8cc4da57fce5d0a59f4db34fb550919a06ea79 (patch)
tree5155c062f6c24d2629cae17fe16243d07509ce3a
parent3814d633ec7087f7d720123a2a2054d14f646ea6 (diff)
downloadchime-ab8cc4da57fce5d0a59f4db34fb550919a06ea79.tar.gz
chime-ab8cc4da57fce5d0a59f4db34fb550919a06ea79.zip
refactor: drive chime--sanitize-title delimiters from one alist
The function matched parens, brackets, and braces with three near-identical cond branches plus a parallel opener-to-closer mapping. That's one balancing algorithm written three times. I replaced it with a single ((open . close) ...) alist driven by assq/rassq. Adding or changing a delimiter pair is now a one-line edit, and there's one code path to reason about. Behavior is unchanged. The existing 30 characterization tests stay green.
-rw-r--r--chime.el50
1 files changed, 15 insertions, 35 deletions
diff --git a/chime.el b/chime.el
index 3988f35..df05d30 100644
--- a/chime.el
+++ b/chime.el
@@ -2038,48 +2038,28 @@ delimiters for unmatched openings.
Returns sanitized title or empty string if TITLE is nil."
(if (not title)
""
- (let ((chars (string-to-list title))
- (stack '()) ; Stack to track opening delimiters in order
+ (let ((pairs '((?\( . ?\)) (?\[ . ?\]) (?\{ . ?\})))
+ (stack '()) ; opening delimiters seen, most recent first
(result '()))
- ;; Process each character
- (dolist (char chars)
+ (dolist (char (string-to-list title))
(cond
- ;; Opening delimiters - add to stack and result
- ((memq char '(?\( ?\[ ?\{))
+ ;; Opening delimiter - remember it and keep it.
+ ((assq char pairs)
(push char stack)
(push char result))
- ;; Closing delimiters - check if they match
- ((eq char ?\))
- (if (and stack (eq (car stack) ?\())
- (progn
- (pop stack)
- (push char result))
- ;; Unmatched closing paren - skip it
- nil))
- ((eq char ?\])
- (if (and stack (eq (car stack) ?\[))
- (progn
- (pop stack)
- (push char result))
- ;; Unmatched closing bracket - skip it
- nil))
- ((eq char ?\})
- (if (and stack (eq (car stack) ?\{))
- (progn
- (pop stack)
- (push char result))
- ;; Unmatched closing brace - skip it
- nil))
- ;; Regular characters - add to result
+ ;; Closing delimiter - keep only when it closes the current opener;
+ ;; an unmatched closer is dropped.
+ ((rassq char pairs)
+ (when (and stack (eq (cdr (assq (car stack) pairs)) char))
+ (pop stack)
+ (push char result)))
+ ;; Regular character.
(t
(push char result))))
- ;; Add closing delimiters for any remaining opening delimiters
+ ;; Close any still-open delimiters, innermost first.
(dolist (opener stack)
- (cond
- ((eq opener ?\() (push ?\) result))
- ((eq opener ?\[) (push ?\] result))
- ((eq opener ?\{) (push ?\} result))))
- ;; Convert back to string (reverse because we built it backwards)
+ (push (cdr (assq opener pairs)) result))
+ ;; Convert back to string (reverse because we built it backwards).
(concat (nreverse result)))))
(defun chime--extract-title (marker)