aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorStefan Monnier2025-05-18 15:44:35 -0400
committerStefan Monnier2025-05-18 15:44:35 -0400
commit168b67b1eeb2e2b79d2e5f3712d8ebfda31fd753 (patch)
tree5fcdbb6e1e3bbd3b48712a237983bbc58a3eac15
parent48c66f26c1454c449ac40407651d22dc5cc57424 (diff)
downloademacs-168b67b1eeb2e2b79d2e5f3712d8ebfda31fd753.tar.gz
emacs-168b67b1eeb2e2b79d2e5f3712d8ebfda31fd753.zip
eww.el: Use `track-changes`
* lisp/net/eww.el: Require `track-changes`. (eww-display-document): Don't `inhibit-modification-hooks` any more. Use `track-changes-register` *at the end* instead. (eww-mode): Don't use `after-change-functions` any more. (eww--track-changes): New function. (eww--process-text-input): Rename from `eww-process-text-input`. Try and be more careful: don't presume `point` is near the modification. Check for a form both at BEG and at END. Don't rely on `:start/:end` pointing to the right places. Use `:length` instead and shrink the field back to its original length when possible. (eww-size-text-inputs): Set `:length` rather than `:start/:end`.
-rw-r--r--lisp/net/eww.el77
1 files changed, 49 insertions, 28 deletions
diff --git a/lisp/net/eww.el b/lisp/net/eww.el
index 736e42e94fa..ad2355db3c6 100644
--- a/lisp/net/eww.el
+++ b/lisp/net/eww.el
@@ -35,6 +35,7 @@
35(require 'url-file) 35(require 'url-file)
36(require 'vtable) 36(require 'vtable)
37(require 'xdg) 37(require 'xdg)
38(require 'track-changes)
38(eval-when-compile (require 'subr-x)) 39(eval-when-compile (require 'subr-x))
39 40
40(defgroup eww nil 41(defgroup eww nil
@@ -812,7 +813,6 @@ This replaces the region with the preprocessed HTML."
812 (setq bidi-paragraph-direction nil) 813 (setq bidi-paragraph-direction nil)
813 (plist-put eww-data :dom document) 814 (plist-put eww-data :dom document)
814 (let ((inhibit-read-only t) 815 (let ((inhibit-read-only t)
815 (inhibit-modification-hooks t)
816 ;; Possibly set by the caller, e.g., `eww-render' which 816 ;; Possibly set by the caller, e.g., `eww-render' which
817 ;; preserves the old URL #target before chasing redirects. 817 ;; preserves the old URL #target before chasing redirects.
818 (shr-target-id (or shr-target-id 818 (shr-target-id (or shr-target-id
@@ -848,6 +848,10 @@ This replaces the region with the preprocessed HTML."
848 (while (and (not (eobp)) 848 (while (and (not (eobp))
849 (get-text-property (point) 'eww-form)) 849 (get-text-property (point) 'eww-form))
850 (forward-line 1))))) 850 (forward-line 1)))))
851 ;; We used to enable this in `eww-mode', but it cause tracking
852 ;; of changes while we insert the document, whereas we only care about
853 ;; changes performed afterwards.
854 (track-changes-register #'eww--track-changes :nobefore t)
851 (eww-size-text-inputs)))) 855 (eww-size-text-inputs))))
852 856
853(defun eww-display-html (charset url &optional document point buffer) 857(defun eww-display-html (charset url &optional document point buffer)
@@ -1350,14 +1354,11 @@ within text input fields."
1350;; Autoload cookie needed by desktop.el. 1354;; Autoload cookie needed by desktop.el.
1351;;;###autoload 1355;;;###autoload
1352(define-derived-mode eww-mode special-mode "eww" 1356(define-derived-mode eww-mode special-mode "eww"
1353 "Mode for browsing the web. 1357 "Mode for browsing the web."
1354
1355\\{eww-mode-map}"
1356 :interactive nil 1358 :interactive nil
1357 (setq-local eww-data (list :title "")) 1359 (setq-local eww-data (list :title ""))
1358 (setq-local browse-url-browser-function #'eww-browse-url) 1360 (setq-local browse-url-browser-function #'eww-browse-url)
1359 (add-hook 'after-change-functions #'eww-process-text-input nil t) 1361 (add-hook 'context-menu-functions #'eww-context-menu 5 t)
1360 (add-hook 'context-menu-functions 'eww-context-menu 5 t)
1361 (setq-local eww-history nil) 1362 (setq-local eww-history nil)
1362 (setq-local eww-history-position 0) 1363 (setq-local eww-history-position 0)
1363 (when (boundp 'tool-bar-map) 1364 (when (boundp 'tool-bar-map)
@@ -1485,7 +1486,6 @@ instead of `browse-url-new-window-flag'."
1485 1486
1486(defun eww-restore-history (elem) 1487(defun eww-restore-history (elem)
1487 (let ((inhibit-read-only t) 1488 (let ((inhibit-read-only t)
1488 (inhibit-modification-hooks t)
1489 (text (plist-get elem :text))) 1489 (text (plist-get elem :text)))
1490 (setq eww-data elem) 1490 (setq eww-data elem)
1491 (if (null text) 1491 (if (null text)
@@ -1756,16 +1756,34 @@ Interactively, EVENT is the value of `last-nonmenu-event'."
1756 "List of input types which represent a text input. 1756 "List of input types which represent a text input.
1757See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.") 1757See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.")
1758 1758
1759(defun eww-process-text-input (beg end replace-length) 1759(defun eww--track-changes (tracker-id)
1760 (when-let* ((pos (field-beginning (point)))) 1760 (track-changes-fetch
1761 (let* ((form (get-text-property pos 'eww-form)) 1761 tracker-id
1762 (properties (text-properties-at pos)) 1762 (lambda (beg end len)
1763 (eww--process-text-input beg end len)
1764 ;; Disregard our own changes.
1765 (track-changes-fetch tracker-id #'ignore))))
1766
1767(defun eww--process-text-input (beg end replace-length)
1768 (when-let* ((_ (integerp replace-length))
1769 (pos end)
1770 (form (or (get-text-property pos 'eww-form)
1771 (progn
1772 (setq pos (max (point-min) (1- beg)))
1773 (get-text-property pos 'eww-form)))))
1774 (let* ((properties (text-properties-at pos))
1763 (buffer-undo-list t) 1775 (buffer-undo-list t)
1764 (inhibit-read-only t) 1776 (inhibit-read-only t)
1765 (length (- end beg replace-length)) 1777 (length (- end beg replace-length))
1766 (type (plist-get form :type))) 1778 (type (plist-get form :type)))
1767 (when (and form 1779 (when (member type eww-text-input-types)
1768 (member type eww-text-input-types)) 1780 ;; Make sure the new text has the right properties, which also
1781 ;; integrates the new text into the "current field".
1782 (set-text-properties beg end properties)
1783 ;; FIXME: This tries to preserve the "length" of the input field,
1784 ;; but we should try to preserve the *width* instead.
1785 ;; FIXME: Maybe instead of inserting/deleting spaces, we should
1786 ;; have a single stretch-space character at the end.
1769 (cond 1787 (cond
1770 ((> length 0) 1788 ((> length 0)
1771 ;; Delete some space at the end. 1789 ;; Delete some space at the end.
@@ -1781,18 +1799,21 @@ See URL `https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Input'.")
1781 ((< length 0) 1799 ((< length 0)
1782 ;; Add padding. 1800 ;; Add padding.
1783 (save-excursion 1801 (save-excursion
1784 (goto-char end) 1802 (goto-char pos)
1785 (goto-char 1803 (let* ((field-length (- (eww-end-of-field)
1786 (if (equal type "textarea") 1804 (eww-beginning-of-field)))
1787 (1- (line-end-position)) 1805 (ideal-length (cdr (assq :length form))))
1788 (1+ (eww-end-of-field)))) 1806 ;; FIXME: This test isn't right for multiline fields.
1789 (let ((start (point))) 1807 (when (or (null ideal-length) (> ideal-length field-length))
1790 (insert (make-string (abs length) ? )) 1808 (goto-char
1791 (set-text-properties start (point) properties)) 1809 (if (equal type "textarea")
1792 (goto-char (1- end))))) 1810 (1- (line-end-position))
1793 (set-text-properties (cdr (assq :start form)) 1811 (1+ (eww-end-of-field))))
1794 (cdr (assq :end form)) 1812 (let ((start (point)))
1795 properties) 1813 (insert (make-string (min (abs length)
1814 (- ideal-length field-length))
1815 ? ))
1816 (set-text-properties start (point) properties)))))))
1796 (let ((value (buffer-substring-no-properties 1817 (let ((value (buffer-substring-no-properties
1797 (eww-beginning-of-field) 1818 (eww-beginning-of-field)
1798 (eww-end-of-field)))) 1819 (eww-end-of-field))))
@@ -2014,11 +2035,11 @@ Interactively, EVENT is the value of `last-nonmenu-event'."
2014 (< start (point-max))) 2035 (< start (point-max)))
2015 (when (or (get-text-property start 'eww-form) 2036 (when (or (get-text-property start 'eww-form)
2016 (setq start (next-single-property-change start 'eww-form))) 2037 (setq start (next-single-property-change start 'eww-form)))
2017 (let ((props (get-text-property start 'eww-form))) 2038 (let ((props (get-text-property start 'eww-form))
2018 (nconc props (list (cons :start start))) 2039 (beg start))
2019 (setq start (next-single-property-change 2040 (setq start (next-single-property-change
2020 start 'eww-form nil (point-max))) 2041 start 'eww-form nil (point-max)))
2021 (nconc props (list (cons :end start)))))))) 2042 (nconc props (list (cons :length (- start beg)))))))))
2022 2043
2023(defun eww-input-value (input) 2044(defun eww-input-value (input)
2024 (let ((type (plist-get input :type)) 2045 (let ((type (plist-get input :type))