branch: elpa/smartparens
commit ff2b2f4eaf3e5800d974952b5e721c6321bbe8c8
Author: Matus Goljer <[email protected]>
Commit: Matus Goljer <[email protected]>

    feat: use correct skip function when skipping to pair or symbol
---
 smartparens.el | 101 ++++++++++++++++++++++++++++++++++++++++++++-------------
 1 file changed, 78 insertions(+), 23 deletions(-)

diff --git a/smartparens.el b/smartparens.el
index bca631b6c4..e15ac61c62 100644
--- a/smartparens.el
+++ b/smartparens.el
@@ -2322,6 +2322,27 @@ The value is fetched from `sp-local-pairs'.
 If PROP is non-nil, return the value of that property instead."
   (sp--get-pair-definition open sp-local-pairs prop))
 
+(defun sp-get-pairs-from-match (match)
+  "Get the definition of local pairs from MATCH.
+
+MATCH can be either opening or closing delimiter.  Since one
+closing delimiter can be shared by multiple pair definitions (for
+example ruby def-end and module-end pairs), this function returns
+a list of possible pairs.
+
+The pairs are fetched from `sp-local-pairs'."
+  (--filter
+   (or (equal (plist-get it :open) match)
+       (equal (plist-get it :close) match))
+   sp-local-pairs))
+
+(defun sp-get-skip-function-from-match (match)
+  "Get the :skip-match property of a pair from MATCH.
+
+MATCH can be either opening or closing delimiter, see
+`sp-get-pairs-from-match'."
+  (plist-get (car (sp-get-pairs-from-match match)) :skip-match))
+
 (defun sp--merge-pair-configurations (specific &optional current)
   "Merge SPECIFIC pair configuration to the CURRENT configuration.
 
@@ -2659,7 +2680,16 @@ can use this to skip over expressions that serve multiple
 functions, such as if/end pair or unary if in Ruby or * in
 markdown when it signifies list item instead of emphasis.  In
 addition, there is a global per major-mode option, see
-`sp-navigate-skip-match'."
+`sp-navigate-skip-match'.
+
+Please take notice that in case of multiple pairs sharing the
+same closing delimiter, they must all use the same SKIP-MATCH
+function or at least handle the skip logic for the closing
+delimiter in the same way, without assuming what the
+corresponding opening delimiter is.  This is because when the
+search is performed smartparens doesn't know yet which concrete
+pair it would parse upon only encountering the closing
+delimiter."
   (if (eq actions :rem)
       (dolist (m (-flatten (list modes)))
         (let ((mode-pairs (assq m sp-pairs)))
@@ -4168,21 +4198,23 @@ achieve this by using `sp-pair' or `sp-local-pair' with
       (cl-letf (((symbol-function 'sp--get-allowed-stringlike-list)
                  (lambda ()
                    (--filter (and (sp--do-action-p (car it) 'autoskip)
-                                  (equal (car it) (cdr it))) sp-pair-list))))
+                                  (equal (car it) (cdr it)))
+                             sp-pair-list))))
         ;; these two are pretty hackish ~_~
-        (cl-labels ((get-sexp
+        (cl-labels ((inc-end
+                     (thing)
+                     (when thing
+                       (plist-put thing :end (1+ (sp-get thing :end)))))
+                    (get-sexp
                      (last)
                      (delete-char -1)
-                     (insert " ")
-                     (prog1 (sp-get-sexp)
-                       (delete-char -1)
+                     (prog1 (inc-end (sp-get-sexp))
                        (insert last)))
                     (get-enclosing-sexp
                      (last)
                      (delete-char -1)
-                     (insert " ")
-                     (prog1 (sp-get-enclosing-sexp)
-                       (delete-char -1)
+                     (prog1  (inc-end (sp-get-enclosing-sexp))
+                       (sp-get-enclosing-sexp)
                        (insert last))))
           (let ((last (or last (sp--single-key-description 
last-command-event))))
             (-if-let (active-sexp
@@ -4236,7 +4268,7 @@ achieve this by using `sp-pair' or `sp-local-pair' with
                          (or (not (sp-point-in-string))
                              (not (sp-char-is-escaped-p (1- (point))))))
                     (-when-let (re (cond
-                                    ((= (point) (sp-get active-sexp :beg))
+                                    ((= (1- (point)) (sp-get active-sexp :beg))
                                      ;; we are in front of a string-like sexp
                                      (when sp-autoskip-opening-pair
                                        (if test-only t
@@ -4565,7 +4597,7 @@ If the point is not inside a quoted string, return nil."
                                 (cdr (--first
                                       (memq major-mode (car it))
                                       sp-navigate-skip-match)))
-                               (pair-skip (sp-get-pair ms :skip-match)))
+                               (pair-skip (sp-get-skip-function-from-match 
ms)))
   "Return non-nil if this match should be skipped.
 
 This function uses two tests, one specified in
@@ -4587,11 +4619,7 @@ be a function call that sets the match data."
         (pair-skip (make-symbol "pair-skip")))
     `(and ,form
           (let* ((,match (match-string 0))
-                 (,pair-skip (or (sp-get-pair ,match :skip-match)
-                                 (sp-get-pair (car (--first
-                                                    (equal (cdr it) ,match)
-                                                    sp-pair-list))
-                                              :skip-match))))
+                 (,pair-skip (sp-get-skip-function-from-match ,match)))
             (not (sp--skip-match-p
                   ,match
                   (match-beginning 0)
@@ -4848,10 +4876,24 @@ and the skip-match predicate."
                                  (not (sp-point-in-string))
                                  (sp--looking-back-p "?" 1)))))
                     ;; TODO: HACK: global-skip is hack here!!!
-                    (sp--skip-match-p match (match-beginning 0) (match-end 0)
-                                      :pair-skip (or skip-fn
-                                                     (sp-get-pair match 
:skip-match))
-                                      :global-skip nil))
+                    (sp--skip-match-p
+                     match (match-beginning 0) (match-end 0)
+                     :pair-skip (or skip-fn
+                                    (sp-get-skip-function-from-match match))
+                     ;; TODO: should this be removed?
+                     :global-skip nil))
+          (setq hit (match-data)))))
+    hit))
+
+(defun sp--find-next-paired-delimiter (needle search-fn-f &optional limit)
+  "Find the next paired delimiter, considering the escapes
+and the skip-match predicate."
+  (let (hit match)
+    (while (and (not hit)
+                (funcall search-fn-f needle limit t))
+      (save-match-data
+        (setq match (match-string-no-properties 0))
+        (unless (sp--skip-match-p match (match-beginning 0) (match-end 0))
           (setq hit (match-data)))))
     hit))
 
@@ -5073,11 +5115,20 @@ By default, this is enabled in all modes derived from
   (let ((pre (sp--get-allowed-regexp))
         (sre (sp--get-stringlike-regexp))
         (search-fn (if (not back) 'sp--search-forward-regexp 
'sp--search-backward-regexp))
+        ;; start of paired delimiter
         (ps (if back (1- (point-min)) (1+ (point-max))))
+        ;; start of string delimiter
         (ss (if back (1- (point-min)) (1+ (point-max))))
-        (string-delim nil))
+        (string-delim nil)
+        (paired-delim nil))
     (setq ps (if (equal pre "") ps
-               (or (save-excursion (funcall search-fn pre nil t)) ps)))
+               (or (--when-let (save-excursion
+                                 (sp--find-next-paired-delimiter pre 
search-fn))
+                     (setq paired-delim (match-string 0))
+                     (save-match-data
+                       (set-match-data it)
+                       (if back (match-beginning 0) (match-end 0))))
+                   ps)))
     (setq ss (if (equal sre "") ss
                (or (--when-let (save-excursion
                                  (sp--find-next-stringlike-delimiter sre 
search-fn))
@@ -7702,7 +7753,11 @@ Examples:
                                  (sp-point-in-string)
                                  (not (sp-point-in-string (,inc (point)))))
                             (and (,looking allowed-pairs)
-                                 (or in-comment (not (sp-point-in-comment))))
+                                 (or in-comment (not (sp-point-in-comment)))
+                                 (not (sp--skip-match-p
+                                       (match-string-no-properties 0)
+                                       (match-beginning 0)
+                                       (match-end 0))))
                             (and (,looking allowed-strings)
                                  (or in-comment (not (sp-point-in-comment))))))
                    (or (member

Reply via email to