branch: externals/hyperbole
commit b4cc99649b56e29706940904362fca77c460a128
Merge: c3ff71d9ce 4bb81f423b
Author: Robert Weiner <[email protected]>
Commit: GitHub <[email protected]>
Merge pull request #668 from rswgnu/rsw
Fix yanking and deleting one paired delimiter properly; fix double-quoted
string selection
---
ChangeLog | 16 ++++++++++
hui-select.el | 101 ++++++++++++++++++++++++++++++++++------------------------
hywiki.el | 73 +++++++++++++++++++++++++++++++++++++-----
3 files changed, 140 insertions(+), 50 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 5c0ed49ae6..51e731c4f8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -15,6 +15,22 @@
* hywiki.el (hywiki-make-referent-hasht): Return hasht when rebuilding from
load data.
+2025-02-07 Bob Weiner <[email protected]>
+
+* hywiki.el (hywiki--extend-yanked-region): Add and call in
'hywiki-highlight-on-yank'
+ to extend a yanked region to include the rest of a delimited pair or
string.
+
+* hui-select.el (hui-select-string-p): Fix to make multi-line string selection
+ work properly whether on the opening or closing double quote mark, using
+ 'scan-sexps'. Update doc string.
+
+2025-02-06 Bob Weiner <[email protected]>
+
+* hywiki.el (hywiki-debuttonize-non-character-commands,
+ hywiki-buttonize-non-character-commands): Add support for 'kill'
+ commands and fix that removing a trailing delimiter did not rehighlight
+ HyWikiWords properly.
+
2025-02-05 Mats Lidell <[email protected]>
* hywiki.el (hywiki-add-org-id): Suppress byte compile warnings for calling
org-id-get with
diff --git a/hui-select.el b/hui-select.el
index a67d40a8aa..fd949b42f8 100644
--- a/hui-select.el
+++ b/hui-select.el
@@ -3,7 +3,7 @@
;; Author: Bob Weiner
;;
;; Orig-Date: 19-Oct-96 at 02:25:27
-;; Last-Mod: 26-Jan-25 at 17:04:55 by Bob Weiner
+;; Last-Mod: 7-Feb-25 at 00:15:47 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
@@ -108,6 +108,7 @@
;;; ************************************************************************
(require 'hvar)
+(require 'hypb) ;; for hypb:in-string-p
(eval-when-compile
(require 'mhtml-mode) ;; for MHTML and HTML modes
(require 'sgml-mode) ;; for SGML mode
@@ -1036,49 +1037,65 @@ Return the updated cons cell."
nil
hui-select-region))
+
(defun hui-select-string-p (&optional start-delim end-delim)
- "Return (start . end) of string whose first line point is in or directly
before.
-Positions include delimiters. String is delimited by double quotes unless
-optional START-DELIM and END-DELIM (strings) are given.
-Returns nil if not within a string."
- (let ((opoint (point))
- (count 0)
- bol start delim-regexp start-regexp end-regexp)
- (or start-delim (setq start-delim "\""))
- (or end-delim (setq end-delim "\""))
- ;; Special case for the empty string.
- (if (looking-at (concat (regexp-quote start-delim)
- (regexp-quote end-delim)))
- (hui-select-set-region (point) (match-end 0))
- (setq start-regexp (concat "\\(^\\|[^\\]\\)\\("
- (regexp-quote start-delim) "\\)")
- end-regexp (concat "[^\\]\\(" (regexp-quote end-delim) "\\)")
- delim-regexp (concat start-regexp "\\|" end-regexp))
- (save-excursion
- (beginning-of-line)
- (setq bol (point))
- (while (re-search-forward delim-regexp opoint t)
- (setq count (1+ count))
- ;; This is so we don't miss the closing delimiter of an empty
- ;; string.
- (if (and (= (point) (1+ bol))
- (looking-at (regexp-quote end-delim)))
+ "Return (start . end) of a string.
+Works when on a delim or on the first line with point in the
+string or directly before it. Positions include delimiters.
+String is delimited by double quotes unless optional START-DELIM
+and END-DELIM (strings) are given. Returns nil if not within a
+string."
+ (unless start-delim (setq start-delim "\""))
+ (unless end-delim (setq end-delim "\""))
+ (or (and (equal start-delim "\"") (equal end-delim "\"")
+ (ignore-errors
+ (cond ((and (= (char-after) ?\")
+ (/= (char-before) ?\\))
+ (if (hypb:in-string-p)
+ (hui-select-set-region (scan-sexps (1+ (point)) -1)
+ (1+ (point)))
+ (hui-select-set-region (point) (scan-sexps (point) 1))))
+ ((and (= (char-before) ?\")
+ (/= (char-before (1- (point))) ?\\))
+ (if (hypb:in-string-p)
+ (hui-select-set-region (1- (point)) (scan-sexps (1-
(point)) 1))
+ (hui-select-set-region (scan-sexps (1- (point)) -1)
+ (point)))))))
+ (let ((opoint (point))
+ (count 0)
+ bol start delim-regexp start-regexp end-regexp)
+ ;; Special case for the empty string.
+ (if (looking-at (concat (regexp-quote start-delim)
+ (regexp-quote end-delim)))
+ (hui-select-set-region (point) (match-end 0))
+ (setq start-regexp (concat "\\(^\\|[^\\]\\)\\("
+ (regexp-quote start-delim) "\\)")
+ end-regexp (concat "[^\\]\\(" (regexp-quote end-delim) "\\)")
+ delim-regexp (concat start-regexp "\\|" end-regexp))
+ (save-excursion
+ (beginning-of-line)
+ (setq bol (point))
+ (while (re-search-forward delim-regexp opoint t)
(setq count (1+ count))
- (unless (bobp)
- (backward-char 1))))
- (goto-char opoint)
- ;; If found an even # of starting and ending delimiters before
- ;; opoint, then opoint is at the start of a string, where we want it.
- (if (zerop (mod count 2))
- (unless (bobp)
- (backward-char 1))
- (re-search-backward start-regexp nil t))
- ;; Point is now before the start of the string.
- (when (re-search-forward start-regexp nil t)
- (setq start (match-beginning 2))
- (when (re-search-forward end-regexp nil t)
- (hui-select-set-region start (point))))))))
-
+ ;; This is so we don't miss the closing delimiter of an empty
+ ;; string.
+ (if (and (= (point) (1+ bol))
+ (looking-at (regexp-quote end-delim)))
+ (setq count (1+ count))
+ (unless (bobp)
+ (backward-char 1))))
+ (goto-char opoint)
+ ;; If found an even # of starting and ending delimiters before
+ ;; opoint, then opoint is at the start of a string, where we want
it.
+ (if (zerop (mod count 2))
+ (unless (bobp)
+ (backward-char 1))
+ (re-search-backward start-regexp nil t))
+ ;; Point is now before the start of the string.
+ (when (re-search-forward start-regexp nil t)
+ (setq start (match-beginning 2))
+ (when (re-search-forward end-regexp nil t)
+ (hui-select-set-region start (point)))))))))
;;;
;;; Code selections
;;;
diff --git a/hywiki.el b/hywiki.el
index 04190ac5fc..ddd716e0e2 100644
--- a/hywiki.el
+++ b/hywiki.el
@@ -3,7 +3,7 @@
;; Author: Bob Weiner
;;
;; Orig-Date: 21-Acpr-24 at 22:41:13
-;; Last-Mod: 8-Feb-25 at 22:56:32 by Mats Lidell
+;; Last-Mod: 9-Feb-25 at 10:10:14 by Bob Weiner
;;
;; SPDX-License-Identifier: GPL-3.0-or-later
;;
@@ -564,16 +564,18 @@ deletion commands and those in
`hywiki-non-character-commands'."
(active-minibuffer-window)))
(when (or (memq this-command hywiki-non-character-commands)
(and (symbolp this-command)
- (string-match-p
"^\\(org-\\)?delete-\\|-delete-\\|insert\\(-\\|$\\)" (symbol-name
this-command))))
+ (string-match-p
"^\\(org-\\)?\\(delete-\\|kill-\\)\\|\\(-delete\\|-kill\\|insert\\)\\(-\\|$\\)"
(symbol-name this-command))))
(if (and (marker-position hywiki--buttonize-start)
(marker-position hywiki--buttonize-end))
+ ;; This means the command just deleted an opening or closing
+ ;; delimiter of a range that now needs any HyWikiWords
+ ;; inside to be re-highlighted.
(save-excursion
(goto-char hywiki--buttonize-start)
(let ((opening-char (char-after))
closing-char)
(when (memq opening-char '(?\( ?\"))
- (delete-char 1)
- (insert " "))
+ (delete-char 1))
(goto-char hywiki--buttonize-end)
(setq closing-char (char-before))
(when (memq closing-char '(?\) ?\"))
@@ -582,7 +584,6 @@ deletion commands and those in
`hywiki-non-character-commands'."
(goto-char hywiki--buttonize-start)
(hywiki-maybe-highlight-between-page-names)
(when (memq opening-char '(?\( ?\"))
- (delete-char 1)
(insert opening-char))
(when (memq closing-char '(?\) ?\"))
(goto-char (1+ hywiki--buttonize-end))
@@ -599,7 +600,7 @@ deletion commands and those in
`hywiki-non-character-commands'."
(set-marker hywiki--buttonize-end nil))
(when (or (memq this-command hywiki-non-character-commands)
(and (symbolp this-command)
- (string-match-p "\\`\\(org-\\)?delete-\\|-delete-"
+ (string-match-p
"\\`\\(org-\\)?\\(delete-\\|kill-\\)\\|-delete-\\|-kill-"
(symbol-name this-command))))
(cl-destructuring-bind (start end)
(hywiki-get-delimited-range) ;; includes delimiters
@@ -1543,10 +1544,16 @@ After successfully finding any kind of referent, run
Have to add one character to the length of the yanked text so that any
needed word-separator after the last character is included to induce
highlighting any last HyWikiWord."
- (hywiki-maybe-highlight-page-names start (min (1+ end) (point-max))))
+ ;; When yank only part of a delimited pair, expand the range to
+ ;; include the whole delimited pair before re-highlighting
+ ;; HyWikiWords therein, so that the whole delimited expression is
+ ;; included.
+ (cl-destructuring-bind (start end)
+ (hywiki--extend-yanked-region start end)
+ (hywiki-maybe-highlight-page-names start (min (1+ end) (point-max)))))
(defun hywiki-map-words (func)
- "Apply FUNC across all HyWikiWords in the current buffer and return nil.
+ "Apply FUNC across highlighted HyWikiWords in the current buffer and return
nil.
FUNC takes 1 argument, the Emacs overlay spanning the start and end buffer
positions of each HyWikiWord and its optional #section."
(save-excursion
@@ -2934,6 +2941,56 @@ invalid. Appended only if the referent-type supports
suffixes."
(cons referent-type referent-value))
referent))))))
+(defun hywiki--extend-yanked-region (start end)
+ "Return a list of (START END) with the specified range extended to include
any delimited regions.
+Typically used to extend a yanked region to fully include any strings or
balanced pair delimiters."
+ (let ((delim-distance 0)
+ (result (list start end))
+ opoint)
+
+ ;; Skip past all delimited ranges and extend `end' as needed
+ (save-excursion
+ (goto-char start)
+ (while (and (<= (point) end)
+ (not (zerop (setq delim-distance (skip-syntax-forward "^\("
end)))))
+ (condition-case nil
+ (progn (goto-char (+ (point) delim-distance))
+ (setq opoint (point))
+ (setq end (max end (goto-char (scan-sexps (point) 1)))
+ result (list start end)))
+ (error (goto-char (min (1+ opoint) end))))))
+
+ ;; Skip past all double-quoted ranges and extend `start' and `end' as
needed
+ (save-excursion
+ (goto-char start)
+ (while (and (<= (point) end)
+ (not (zerop (setq delim-distance (skip-syntax-forward "^\""
end)))))
+ (condition-case nil
+ (progn (goto-char (+ (point) delim-distance))
+ (setq opoint (point))
+ (if (hypb:in-string-p)
+ (progn (goto-char (1+ (point)))
+ (setq start (min start (goto-char (scan-sexps (1+
(point)) -1))))
+ (goto-char (min (1+ opoint) end)))
+ ;; before a string
+ (setq end (max end (goto-char (scan-sexps (point) 1)))))
+ (setq result (list start end)))
+ (error (goto-char (min (1+ opoint) end))))))
+
+ ;; Skip past closing delimiter and extend `start' if needed
+ (save-excursion
+ (goto-char start)
+ (while (and (<= (point) end)
+ (not (zerop (setq delim-distance (skip-syntax-forward "^\)"
end)))))
+ (condition-case nil
+ (progn (goto-char (+ (point) delim-distance))
+ (setq opoint (point))
+ (setq start (min start (goto-char (scan-sexps (1+ (point))
-1)))
+ result (list start end))
+ (goto-char (min (1+ opoint) end)))
+ (error (goto-char (min (1+ opoint) end))))))
+ result))
+
(defun hywiki--get-delimited-range-backward ()
"Return a list of (start end) if not between/after end ]] or >>.
Otherwise, return nil."