aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorF. Jason Park2023-10-03 23:15:40 -0700
committerF. Jason Park2023-10-13 07:47:01 -0700
commita4bae965e06c982871cf01bb0fc3afc43c915bc5 (patch)
tree628df10ab9e00382967881485b2617f737945828
parentf97fdf5e50ebf1aab236b4b8bbd09c203a56aac5 (diff)
downloademacs-a4bae965e06c982871cf01bb0fc3afc43c915bc5.tar.gz
emacs-a4bae965e06c982871cf01bb0fc3afc43c915bc5.zip
Easily excise list-valued text prop members in ERC
* lisp/erc/erc.el (erc--remove-from-prop-value-list): New function for removing `invisible' and `face' prop members cleanly. * test/lisp/erc/erc-tests.el (erc--remove-from-prop-value-list, erc--remove-from-prop-value-list/many): New tests. (Bug#60936)
-rw-r--r--lisp/erc/erc.el24
-rw-r--r--test/lisp/erc/erc-tests.el169
2 files changed, 193 insertions, 0 deletions
diff --git a/lisp/erc/erc.el b/lisp/erc/erc.el
index 3a0337eae9a..c3312000ffd 100644
--- a/lisp/erc/erc.el
+++ b/lisp/erc/erc.el
@@ -3079,6 +3079,30 @@ value. See also `erc-button-add-face'."
3079 old (get-text-property pos prop object) 3079 old (get-text-property pos prop object)
3080 end (next-single-property-change pos prop object to))))) 3080 end (next-single-property-change pos prop object to)))))
3081 3081
3082(defun erc--remove-from-prop-value-list (from to prop val &optional object)
3083 "Remove VAL from text prop value between FROM and TO.
3084If current value is VAL itself, remove the property entirely.
3085When VAL is a list, act as if this function were called
3086repeatedly with VAL set to each of VAL's members."
3087 (let ((old (get-text-property from prop object))
3088 (pos from)
3089 (end (next-single-property-change from prop object to))
3090 new)
3091 (while (< pos to)
3092 (when old
3093 (if (setq new (and (consp old) (if (consp val)
3094 (seq-difference old val)
3095 (remq val old))))
3096 (put-text-property pos end prop
3097 (if (cdr new) new (car new)) object)
3098 (when (pcase val
3099 ((pred consp) (or (consp old) (memq old val)))
3100 (_ (if (consp old) (memq val old) (eq old val))))
3101 (remove-text-properties pos end (list prop nil) object))))
3102 (setq pos end
3103 old (get-text-property pos prop object)
3104 end (next-single-property-change pos prop object to)))))
3105
3082(defvar erc-legacy-invisible-bounds-p nil 3106(defvar erc-legacy-invisible-bounds-p nil
3083 "Whether to hide trailing rather than preceding newlines. 3107 "Whether to hide trailing rather than preceding newlines.
3084Beginning in ERC 5.6, invisibility extends from a message's 3108Beginning in ERC 5.6, invisibility extends from a message's
diff --git a/test/lisp/erc/erc-tests.el b/test/lisp/erc/erc-tests.el
index 0b88ad9cfa9..ed89fd01d93 100644
--- a/test/lisp/erc/erc-tests.el
+++ b/test/lisp/erc/erc-tests.el
@@ -1475,6 +1475,175 @@
1475 (when noninteractive 1475 (when noninteractive
1476 (kill-buffer)))) 1476 (kill-buffer))))
1477 1477
1478(ert-deftest erc--remove-from-prop-value-list ()
1479 (with-current-buffer (get-buffer-create "*erc-test*")
1480 ;; Non-list match.
1481 (insert "abc\n")
1482 (put-text-property 1 2 'erc-test 'a)
1483 (put-text-property 2 3 'erc-test 'b)
1484 (put-text-property 3 4 'erc-test 'c)
1485 (should (erc-tests--equal-including-properties
1486 (buffer-substring 1 4) #("abc"
1487 0 1 (erc-test a)
1488 1 2 (erc-test b)
1489 2 3 (erc-test c))))
1490
1491 (erc--remove-from-prop-value-list 1 4 'erc-test 'b)
1492 (should (erc-tests--equal-including-properties
1493 (buffer-substring 1 4) #("abc"
1494 0 1 (erc-test a)
1495 2 3 (erc-test c))))
1496 (erc--remove-from-prop-value-list 1 4 'erc-test 'a)
1497 (should (erc-tests--equal-including-properties
1498 (buffer-substring 1 4) #("abc" 2 3 (erc-test c))))
1499 (erc--remove-from-prop-value-list 1 4 'erc-test 'c)
1500 (should (erc-tests--equal-including-properties
1501 (buffer-substring 1 4) "abc"))
1502
1503 ;; List match.
1504 (goto-char (point-min))
1505 (insert "def\n")
1506 (put-text-property 1 2 'erc-test '(d x))
1507 (put-text-property 2 3 'erc-test '(e y))
1508 (put-text-property 3 4 'erc-test '(f z))
1509 (should (erc-tests--equal-including-properties
1510 (buffer-substring 1 4) #("def"
1511 0 1 (erc-test (d x))
1512 1 2 (erc-test (e y))
1513 2 3 (erc-test (f z)))))
1514 (erc--remove-from-prop-value-list 1 4 'erc-test 'y)
1515 (should (erc-tests--equal-including-properties
1516 (buffer-substring 1 4) #("def"
1517 0 1 (erc-test (d x))
1518 1 2 (erc-test e)
1519 2 3 (erc-test (f z)))))
1520 (erc--remove-from-prop-value-list 1 4 'erc-test 'd)
1521 (erc--remove-from-prop-value-list 1 4 'erc-test 'f)
1522 (should (erc-tests--equal-including-properties
1523 (buffer-substring 1 4) #("def"
1524 0 1 (erc-test x)
1525 1 2 (erc-test e)
1526 2 3 (erc-test z))))
1527 (erc--remove-from-prop-value-list 1 4 'erc-test 'e)
1528 (erc--remove-from-prop-value-list 1 4 'erc-test 'z)
1529 (erc--remove-from-prop-value-list 1 4 'erc-test 'x)
1530 (should (erc-tests--equal-including-properties
1531 (buffer-substring 1 4) "def"))
1532
1533 ;; List match.
1534 (goto-char (point-min))
1535 (insert "ghi\n")
1536 (put-text-property 1 2 'erc-test '(g x))
1537 (put-text-property 2 3 'erc-test '(h x))
1538 (put-text-property 3 4 'erc-test '(i y))
1539 (should (erc-tests--equal-including-properties
1540 (buffer-substring 1 4) #("ghi"
1541 0 1 (erc-test (g x))
1542 1 2 (erc-test (h x))
1543 2 3 (erc-test (i y)))))
1544 (erc--remove-from-prop-value-list 1 4 'erc-test 'x)
1545 (should (erc-tests--equal-including-properties
1546 (buffer-substring 1 4) #("ghi"
1547 0 1 (erc-test g)
1548 1 2 (erc-test h)
1549 2 3 (erc-test (i y)))))
1550 (erc--remove-from-prop-value-list 1 2 'erc-test 'g) ; narrowed
1551 (erc--remove-from-prop-value-list 3 4 'erc-test 'i) ; narrowed
1552 (should (erc-tests--equal-including-properties
1553 (buffer-substring 1 4) #("ghi"
1554 1 2 (erc-test h)
1555 2 3 (erc-test y))))
1556
1557 ;; Pathological (,c) case (hopefully not created by ERC)
1558 (goto-char (point-min))
1559 (insert "jkl\n")
1560 (put-text-property 1 2 'erc-test '(j x))
1561 (put-text-property 2 3 'erc-test '(k))
1562 (put-text-property 3 4 'erc-test '(k))
1563 (erc--remove-from-prop-value-list 1 4 'erc-test 'k)
1564 (should (erc-tests--equal-including-properties
1565 (buffer-substring 1 4) #("jkl" 0 1 (erc-test (j x)))))
1566
1567 (when noninteractive
1568 (kill-buffer))))
1569
1570(ert-deftest erc--remove-from-prop-value-list/many ()
1571 (with-current-buffer (get-buffer-create "*erc-test*")
1572 ;; Non-list match.
1573 (insert "abc\n")
1574 (put-text-property 1 2 'erc-test 'a)
1575 (put-text-property 2 3 'erc-test 'b)
1576 (put-text-property 3 4 'erc-test 'c)
1577 (should (erc-tests--equal-including-properties
1578 (buffer-substring 1 4) #("abc"
1579 0 1 (erc-test a)
1580 1 2 (erc-test b)
1581 2 3 (erc-test c))))
1582
1583 (erc--remove-from-prop-value-list 1 4 'erc-test '(a b))
1584 (should (erc-tests--equal-including-properties
1585 (buffer-substring 1 4) #("abc" 2 3 (erc-test c))))
1586 (erc--remove-from-prop-value-list 1 4 'erc-test 'a)
1587 (should (erc-tests--equal-including-properties
1588 (buffer-substring 1 4) #("abc" 2 3 (erc-test c))))
1589 (erc--remove-from-prop-value-list 1 4 'erc-test '(c))
1590 (should (erc-tests--equal-including-properties
1591 (buffer-substring 1 4) "abc"))
1592
1593 ;; List match.
1594 (goto-char (point-min))
1595 (insert "def\n")
1596 (put-text-property 1 2 'erc-test '(d x y))
1597 (put-text-property 2 3 'erc-test '(e y))
1598 (put-text-property 3 4 'erc-test '(f z))
1599 (should (erc-tests--equal-including-properties
1600 (buffer-substring 1 4) #("def"
1601 0 1 (erc-test (d x y))
1602 1 2 (erc-test (e y))
1603 2 3 (erc-test (f z)))))
1604 (erc--remove-from-prop-value-list 1 4 'erc-test '(d y f))
1605 (should (erc-tests--equal-including-properties
1606 (buffer-substring 1 4) #("def"
1607 0 1 (erc-test x)
1608 1 2 (erc-test e)
1609 2 3 (erc-test z))))
1610 (erc--remove-from-prop-value-list 1 4 'erc-test '(e z x))
1611 (should (erc-tests--equal-including-properties
1612 (buffer-substring 1 4) "def"))
1613
1614 ;; Narrowed beg.
1615 (goto-char (point-min))
1616 (insert "ghi\n")
1617 (put-text-property 1 2 'erc-test '(g x))
1618 (put-text-property 2 3 'erc-test '(h x))
1619 (put-text-property 3 4 'erc-test '(i x))
1620 (should (erc-tests--equal-including-properties
1621 (buffer-substring 1 4) #("ghi"
1622 0 1 (erc-test (g x))
1623 1 2 (erc-test (h x))
1624 2 3 (erc-test (i x)))))
1625 (erc--remove-from-prop-value-list 1 3 'erc-test '(x g i))
1626 (should (erc-tests--equal-including-properties
1627 (buffer-substring 1 4) #("ghi"
1628 1 2 (erc-test h)
1629 2 3 (erc-test (i x)))))
1630
1631 ;; Narrowed middle.
1632 (goto-char (point-min))
1633 (insert "jkl\n")
1634 (put-text-property 1 2 'erc-test '(j x))
1635 (put-text-property 2 3 'erc-test '(k))
1636 (put-text-property 3 4 'erc-test '(l y z))
1637 (erc--remove-from-prop-value-list 3 4 'erc-test '(k x y z))
1638 (should (erc-tests--equal-including-properties
1639 (buffer-substring 1 4) #("jkl"
1640 0 1 (erc-test (j x))
1641 1 2 (erc-test (k))
1642 2 3 (erc-test l))))
1643
1644 (when noninteractive
1645 (kill-buffer))))
1646
1478(ert-deftest erc--split-string-shell-cmd () 1647(ert-deftest erc--split-string-shell-cmd ()
1479 1648
1480 ;; Leading and trailing space 1649 ;; Leading and trailing space