]> code.delx.au - gnu-emacs-elpa/blobdiff - packages/swiper/swiper.el
Merge commit 'e084b5d9feab3dd1246e51ce1fddde3db6024f7d' from swiper
[gnu-emacs-elpa] / packages / swiper / swiper.el
index c58f20fed6ce2ea9739ad50ce97cc5f735d137d4..2f95a312c43cd7dc629be2579dd08425a813c4c8 100644 (file)
@@ -4,7 +4,7 @@
 
 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
 ;; URL: https://github.com/abo-abo/swiper
-;; Version: 0.3.0
+;; Version: 0.4.1
 ;; Package-Requires: ((emacs "24.1"))
 ;; Keywords: matching
 
 ;; candidates.  The search regex can be split into groups with a
 ;; space.  Each group is highlighted with a different face.
 ;;
-;; The overview back end is `ivy'.
-;;
 ;; It can double as a quick `regex-builder', although only single
 ;; lines will be matched.
+;;
+;; It also provides `ivy-mode': a global minor mode that uses the
+;; matching back end of `swiper' for all matching on your system,
+;; including file matching. You can use it in place of `ido-mode'
+;; (can't have both on at once).
 
 ;;; Code:
 (require 'ivy)
 
 (defface swiper-match-face-1
   '((t (:inherit isearch-lazy-highlight-face)))
-  "Face for `swiper' matches.")
+  "The background face for `swiper' matches.")
 
 (defface swiper-match-face-2
   '((t (:inherit isearch)))
-  "Face for `swiper' matches.")
+  "Face for `swiper' matches modulo 1.")
 
 (defface swiper-match-face-3
   '((t (:inherit match)))
-  "Face for `swiper' matches.")
+  "Face for `swiper' matches modulo 2.")
 
 (defface swiper-match-face-4
-  '((t (:inherit isearch)))
-  "Face for `swiper' matches.")
+  '((t (:inherit isearch-fail)))
+  "Face for `swiper' matches modulo 3.")
 
 (defface swiper-line-face
   '((t (:inherit highlight)))
   (let ((map (make-sparse-keymap)))
     (define-key map (kbd "M-q") 'swiper-query-replace)
     (define-key map (kbd "C-l") 'swiper-recenter-top-bottom)
+    (define-key map (kbd "C-'") 'swiper-avy)
     map)
   "Keymap for swiper.")
 
+(defvar swiper--window nil
+  "Store the current window.")
+
 (defun swiper-query-replace ()
   "Start `query-replace' with string to replace from last search string."
   (interactive)
            (from (ivy--regex ivy-text))
            (to (query-replace-read-to from "Query replace" t)))
       (delete-minibuffer-contents)
-      (setq ivy--action
-            (lambda ()
-              (with-selected-window swiper--window
-                (perform-replace from to
-                                 t t t))))
+      (ivy-set-action (lambda (_)
+                        (with-selected-window swiper--window
+                          (perform-replace from to
+                                           t t nil))))
       (swiper--cleanup)
       (exit-minibuffer))))
 
-(defvar swiper--window nil
-  "Store the current window.")
+(defvar avy-background)
+(declare-function avy--regex-candidates "ext:avy")
+(declare-function avy--process "ext:avy")
+(declare-function avy--overlay-post "ext:avy")
+(declare-function avy--goto "ext:avy")
+
+;;;###autoload
+(defun swiper-avy ()
+  "Jump to one of the current swiper candidates."
+  (interactive)
+  (with-selected-window (ivy-state-window ivy-last)
+    (let* ((candidates
+            (avy--regex-candidates
+             (ivy--regex ivy-text)))
+           (avy-background nil)
+           (candidate
+            (avy--process candidates #'avy--overlay-post)))
+      (ivy-quit-and-run
+       (avy--goto candidate)))))
 
 (defun swiper-recenter-top-bottom (&optional arg)
   "Call (`recenter-top-bottom' ARG) in `swiper--window'."
                                  gnus-group-mode
                                  emms-playlist-mode erc-mode
                                  org-agenda-mode
-                                 dired-mode)))
+                                 dired-mode
+                                 jabber-chat-mode
+                                 elfeed-search-mode
+                                 fundamental-mode)))
     (unless (> (buffer-size) 100000)
       (if (fboundp 'font-lock-ensure)
           (font-lock-ensure)
 (defvar swiper--format-spec ""
   "Store the current candidates format spec.")
 
+(defvar swiper--width nil
+  "Store the amount of digits needed for the longest line nubmer.")
+
 (defun swiper--candidates ()
   "Return a list of this buffer lines."
   (let ((n-lines (count-lines (point-min) (point-max))))
     (unless (zerop n-lines)
+      (setq swiper--width (1+ (floor (log n-lines 10))))
       (setq swiper--format-spec
-            (format "%%-%dd %%s" (1+ (floor (log n-lines 10)))))
+            (format "%%-%dd %%s" swiper--width))
       (let ((line-number 0)
             candidates)
         (save-excursion
@@ -168,10 +198,34 @@ When non-nil, INITIAL-INPUT is the initial search pattern."
   (setq swiper--anchor (line-number-at-pos))
   (setq swiper--window (selected-window)))
 
+(defun swiper--re-builder (str)
+  "Transform STR into a swiper regex.
+This is the regex used in the minibuffer, since the candidates
+there have line numbers. In the buffer, `ivy--regex' should be used."
+  (cond
+    ((equal str "")
+     "")
+    ((equal str "^")
+     ".")
+    ((string-match "^\\^" str)
+     (setq ivy--old-re "")
+     (let ((re (ivy--regex-plus (substring str 1))))
+       (format "^[0-9][0-9 ]\\{%d\\}%s"
+               swiper--width
+               (if (zerop ivy--subexps)
+                   (prog1 (format "\\(%s\\)" re)
+                     (setq ivy--subexps 1))
+                 re))))
+    (t
+     (ivy--regex-plus str))))
+
 (defun swiper--ivy (&optional initial-input)
   "`isearch' with an overview using `ivy'.
 When non-nil, INITIAL-INPUT is the initial search pattern."
   (interactive)
+  (unless (eq (length (help-function-arglist 'ivy-read)) 4)
+    (warn "You seem to be using the outdated stand-alone \"ivy\" package.
+Please remove it and update the \"swiper\" package."))
   (swiper--init)
   (let ((candidates (swiper--candidates))
         (preselect (format
@@ -191,8 +245,9 @@ When non-nil, INITIAL-INPUT is the initial search pattern."
                     :keymap swiper-map
                     :preselect preselect
                     :require-match t
-                    :update-fn #'swiper--update-input-ivy))
-      (swiper--cleanup)
+                    :update-fn #'swiper--update-input-ivy
+                    :unwind #'swiper--cleanup
+                    :re-builder #'swiper--re-builder))
       (if (null ivy-exit)
           (goto-char swiper--opoint)
         (swiper--action res ivy-text)))))
@@ -266,11 +321,11 @@ BEG and END, when specified, are the point bounds."
                                              (match-end i)))
                       (face
                        (cond ((zerop ivy--subexps)
-                              (cl-caddr swiper-faces))
+                              (cadr swiper-faces))
                              ((zerop i)
                               (car swiper-faces))
                              (t
-                              (nth (1+ (mod (1- i) (1- (length swiper-faces))))
+                              (nth (1+ (mod (+ i 2) (1- (length swiper-faces))))
                                    swiper-faces)))))
                   (push overlay swiper--overlays)
                   (overlay-put overlay 'face face)