From 134fe3396f975fb1ad261f52cd113f42ac1da4fc Mon Sep 17 00:00:00 2001 From: Tom Dalziel <33435574+tomdl89@users.noreply.github.com> Date: Sun, 1 Oct 2023 16:23:26 +0200 Subject: [PATCH] fix: handle escaped parentheses (#110) * fix: handle escaped parentheses Currently, if an escaped paren is encountered in Clojure code; it's interpreted as a delimiter and breaks deletion * Bypass sp-get-enclosing-sexp for deletion Use evil-cp--matching-paren-pos's value instead. * Fix deletion for escaped parens --------- Co-authored-by: Ellis Kenyo --- evil-cleverparens-tests.el | 24 ++++++++++++++++++++++-- evil-cleverparens-util.el | 12 ++++++++++++ evil-cleverparens.el | 14 ++++++++------ 3 files changed, 42 insertions(+), 8 deletions(-) diff --git a/evil-cleverparens-tests.el b/evil-cleverparens-tests.el index 890c311..269c152 100644 --- a/evil-cleverparens-tests.el +++ b/evil-cleverparens-tests.el @@ -283,8 +283,21 @@ golf foxtrot deltahotel india")) (evil-cp-test-buffer "(alpha (bravo[ ]charlie))" ("d^") - "(( charlie))"))) - + "(( charlie))")) + (ert-info ("Can delete line containing escaped parens") + (evil-test-buffer ;; As we need to enable evil-cp later anyway + "(alpha\n(b[r]avo ?\\))\ncharlie)" + (emacs-lisp-mode) + (evil-cleverparens-mode t) + ("dd") + "(alpha\ncharlie)")) + (ert-info ("Can delete unbalanced line containing escaped parens") + (evil-test-buffer ;; As we need to enable evil-cp later anyway + "(alpha\n(b[r]avo ?\\)\ncharlie)\ndelta)" + (emacs-lisp-mode) + (evil-cleverparens-mode t) + ("dd") + "(alpha\n (charlie)\n delta)"))) ;; (alpha[ ]bravo) charlie ;; charlie (bravo[ ]alpha) @@ -668,6 +681,13 @@ golf foxtrot deltahotel india")) "alpha bravo (charlie [d]elta echo) foxtrot golf" (">") "alpha bravo (charlie [d]elta echo foxtrot) golf")) + (ert-info ("Can slurp escaped parens") + (evil-test-buffer ;; As we need to enable evil-cp later anyway + "(alpha[)] ?\\) bravo" + (emacs-lisp-mode) + (evil-cleverparens-mode t) + (">") + "(alpha ?\\)) bravo")) (ert-info ("Can barf backwards when on opening delimiter") (evil-cp-test-buffer "alpha bravo [(]charlie delta echo) foxtrot golf" diff --git a/evil-cleverparens-util.el b/evil-cleverparens-util.el index c6c71c4..fa83465 100644 --- a/evil-cleverparens-util.el +++ b/evil-cleverparens-util.el @@ -47,6 +47,15 @@ (when pos (goto-char pos)) (looking-at-p evil-cp--ws-regexp))) +(defun evil-cp--looking-at-escape-p (&optional pos) + (save-excursion + (when pos (goto-char pos)) + (looking-at-p (regexp-quote (or sp-escape-char "\\"))))) + +(defun evil-cp--looking-at-escaped-p (&optional pos) + (or (evil-cp--looking-at-escape-p pos) + (evil-cp--looking-at-escape-p (1- (or pos (point)))))) + (defun evil-cp--pair-for (pair pairs) (cond ((not pairs) @@ -72,6 +81,7 @@ question. Ignores parentheses inside strings." (save-excursion (when pos (goto-char pos)) (and (sp--looking-at-p (evil-cp--get-opening-regexp)) + (not (evil-cp--looking-at-escaped-p)) (not (evil-cp--inside-string-p))))) (defun evil-cp--looking-at-opening-anywhere-p (&optional pos) @@ -81,6 +91,7 @@ question. Includes parentheses inside strings." (save-excursion (when pos (goto-char pos)) (and (sp--looking-at-p (evil-cp--get-opening-regexp)) + (not (evil-cp--looking-at-escaped-p)) (not (evil-cp--looking-at-string-closing-p))))) (defun evil-cp--looking-at-closing-p (&optional pos) @@ -90,6 +101,7 @@ question. Ignores parentheses inside strings." (save-excursion (when pos (goto-char pos)) (and (sp--looking-at-p (evil-cp--get-closing-regexp)) + (not (evil-cp--looking-at-escaped-p)) (not (evil-cp--inside-string-p))))) (defun evil-cp--looking-at-paren-p (&optional pos) diff --git a/evil-cleverparens.el b/evil-cleverparens.el index b7d415f..7179a63 100644 --- a/evil-cleverparens.el +++ b/evil-cleverparens.el @@ -597,17 +597,19 @@ delimiters in the region defined by BEG and END." (delete-char diff) (setq chars-left (- chars-left diff)))) ((evil-cp--looking-at-any-opening-p) - (let ((other-end (evil-cp--matching-paren-pos))) + (let ((p (point)) + (other-end (evil-cp--matching-paren-pos))) ;; matching paren is in the range of the command - (if (<= (point) other-end end) - (let ((char-count - (evil-cp--guard-point - (sp-get (sp-get-enclosing-sexp) - (- :end :beg))))) + (if (<= p other-end end) + ;; 1+ makes the char-count inclusive + (let ((char-count (1+ (- other-end p)))) (delete-char char-count) (setq chars-left (- chars-left char-count))) (forward-char) (cl-decf chars-left)))) + ((and (evil-cp--looking-at-escape-p) (< 1 chars-left)) + (delete-char 2) + (cl-decf chars-left 2)) ((and (evil-cp--looking-at-any-closing-p) (= chars-left 1)) (cl-decf chars-left)) ((evil-cp--looking-at-any-closing-p)