branch: externals/hyperbole
commit b4cc99649b56e29706940904362fca77c460a128
Merge: c3ff71d9ce 4bb81f423b
Author: Robert Weiner <r...@gnu.org>
Commit: GitHub <nore...@github.com>

    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  <r...@gnu.org>
+
+* 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  <r...@gnu.org>
+
+* 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  <ma...@gnu.org>
 
 * 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."

Reply via email to