branch: externals/ivy-hydra
commit e598b044e2728f5e3b163db99c0f0c4d7c56c6e4
Author: Oleh Krehel <[email protected]>
Commit: Oleh Krehel <[email protected]>
ivy.el (ivy--regex): Improve handling of capture groups
Suppose we have this buffer, and we want to capture the symlink name
and location:
2019 .Xmodmap -> git/home/.Xmodmap
2019 .authinfo.gpg -> git/home/.authinfo.gpg
2019 .bashrc -> git/home/.bashrc
Old approach: search for "[^ ]+ -> .*".
The equivalent regex is "\\([^ ]+\).*\\(->\).*\\(.*\)".
This does not work, since "[^ ]+" will capture "2019", and the
important part will be captured by .*.
New approach: search for "[^ ]+\( -> \).*".
The equivalent regex is "\\([^ ]+\\)\\( -> \\).*?\\(.*\\)".
Note:
- A capture group is a boundary for splitting the regex into parts,
instead of a space
- The space inside the capture group is literal
- No .* is inserted after the first capture group
---
ivy-test.el | 14 ++++++++++++--
ivy.el | 22 +++++++++++++---------
swiper.el | 9 +++++----
3 files changed, 30 insertions(+), 15 deletions(-)
diff --git a/ivy-test.el b/ivy-test.el
index b7ba0bb..6054e3b 100644
--- a/ivy-test.el
+++ b/ivy-test.el
@@ -240,7 +240,13 @@ will bring the behavior in line with the newer Emacsen."
(should (equal (ivy--split "abc[^ \n]+\\( -> \\)def")
'("abc[^ \n]+" "\\( -> \\)" "def")))
(should (equal (ivy--split "\\(?:interactive\\|swiper\\)
\\(?:list\\|symbol\\)")
- '("\\(?:interactive\\|swiper\\)" "\\(?:list\\|symbol\\)"))))
+ '("\\(?:interactive\\|swiper\\)" "\\(?:list\\|symbol\\)")))
+ (should (equal (ivy--split "\\([^ \n]+\\)\\( -> \\).*")
+ '("\\([^ \n]+\\)"
+ "\\( -> \\)"
+ ".*")))
+ (should (equal (ivy--split "[^ ]\\( -> \\).*")
+ '("[^ ]" "\\( -> \\)" ".*"))))
(ert-deftest ivy--regex ()
(should (equal (ivy--regex
@@ -256,7 +262,11 @@ will bring the behavior in line with the newer Emacsen."
".org")
"\\.org"))
(should (equal (ivy--regex "foo\\") "foo"))
- (should (equal (ivy--regex "foo\\|") "foo")))
+ (should (equal (ivy--regex "foo\\|") "foo"))
+ (should (equal (ivy--regex "[^ \n]+\\( -> \\).*")
+ "\\([^ \n]+\\)\\( -> \\).*?\\(.*\\)"))
+ (should (equal (ivy--regex "\\([^ \\n]+\\)\\( -> \\).*")
+ "\\([^ \\n]+\\)\\( -> \\).*?\\(.*\\)")))
(ert-deftest ivy--split-negation ()
(should (equal (ivy--split-negation "") ()))
diff --git a/ivy.el b/ivy.el
index b4d82b5..a7788a8 100644
--- a/ivy.el
+++ b/ivy.el
@@ -2673,7 +2673,7 @@ regexp is passed to `regexp-quote'."
(progn
(when (> i start)
(push (substring str start i) res))
- (if (string-match "\\\\(.*?\\\\)" str i)
+ (if (eq (string-match "\\\\([^\0]*?\\\\)" str i) i)
(progn
(push (match-string 0 str) res)
(setq i (match-end 0))
@@ -2715,7 +2715,7 @@ regexp is passed to `regexp-quote'."
(cl-decf open-count)))
(cl-incf i))
(when (= open-count 0)
- (if (string-match "[+*?]" str i)
+ (if (eq (string-match "[+*?]" str i) i)
(match-end 0)
i))))
@@ -2748,13 +2748,17 @@ When GREEDY is non-nil, join words in a greedy way."
(car subs)))
(cons
(setq ivy--subexps (length subs))
- (mapconcat
- (lambda (x)
- (if (string-match-p "\\`\\\\([^?].*\\\\)\\'" x)
- x
- (format "\\(%s\\)" x)))
- subs
- (if greedy ".*" ".*?")))))
+ (replace-regexp-in-string
+ "\\.\\*\\??\\\\( "
+ "\\( "
+ (mapconcat
+ (lambda (x)
+ (if (string-match-p "\\`\\\\([^?][^\0]*\\\\)\\'"
x)
+ x
+ (format "\\(%s\\)" x)))
+ subs
+ (if greedy ".*" ".*?"))
+ nil t))))
ivy--regex-hash)))))
(defun ivy--regex-p (object)
diff --git a/swiper.el b/swiper.el
index 55bfd88..3f2ec3c 100644
--- a/swiper.el
+++ b/swiper.el
@@ -1047,10 +1047,11 @@ WND, when specified is the window."
(em (match-end j)))
(when (and (integerp em)
(integerp bm))
- (while (and (< j ivy--subexps)
- (integerp (match-beginning (+ j 1)))
- (= em (match-beginning (+ j 1))))
- (setq em (match-end (cl-incf j))))
+ (when (eq (ivy-alist-setting ivy-re-builders-alist t)
#'ivy--regex-fuzzy)
+ (while (and (< j ivy--subexps)
+ (integerp (match-beginning (+ j 1)))
+ (= em (match-beginning (+ j 1))))
+ (setq em (match-end (cl-incf j)))))
(funcall adder-fn
bm em
(nth (1+ (mod (+ i 2) (1- (length faces))))