]> code.delx.au - gnu-emacs-elpa/blobdiff - swiper.el
swiper.el (swiper--add-overlays): Make bounds optional
[gnu-emacs-elpa] / swiper.el
index bd88a5155c75562f394117c9b246152884346fba..f123c7327d0352b3a3e55fa56fb85e2ff40e8477 100644 (file)
--- a/swiper.el
+++ b/swiper.el
@@ -1,14 +1,14 @@
 ;;; swiper.el --- Isearch with an overview. Oh, man! -*- lexical-binding: t -*-
 
-;; Copyright (C) 2015 Oleh Krehel
+;; Copyright (C) 2015  Free Software Foundation, Inc.
 
 ;; Author: Oleh Krehel <ohwoeowho@gmail.com>
 ;; URL: https://github.com/abo-abo/swiper
-;; Version: 0.1.0
-;; Package-Requires: ((emacs "24.1") (ivy "0.1.0"))
+;; Version: 0.3.0
+;; Package-Requires: ((emacs "24.1"))
 ;; Keywords: matching
 
-;; This file is not part of GNU Emacs
+;; This file is part of GNU Emacs.
 
 ;; This file is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
                           swiper-match-face-4)
   "List of `swiper' faces for group matches.")
 
+(defcustom swiper-min-highlight 2
+  "Only highlight matches for regexps at least this long."
+  :type 'integer)
+
+(defvar swiper-map
+  (let ((map (make-sparse-keymap)))
+    (define-key map (kbd "M-q") 'swiper-query-replace)
+    (define-key map (kbd "C-l") 'swiper-recenter-top-bottom)
+    map)
+  "Keymap for swiper.")
+
+(defun swiper-query-replace ()
+  "Start `query-replace' with string to replace from last search string."
+  (interactive)
+  (if (null (window-minibuffer-p))
+      (user-error "Should only be called in the minibuffer through `swiper-map'")
+    (let* ((enable-recursive-minibuffers t)
+           (from (ivy--regex ivy-text))
+           (to (query-replace-read-to from "Query replace" t)))
+      (delete-minibuffer-contents)
+      (setq ivy--action
+            (lambda ()
+              (perform-replace from to
+                               t t t)))
+      (swiper--cleanup)
+      (exit-minibuffer))))
+
 (defvar swiper--window nil
   "Store the current window.")
 
+(defun swiper-recenter-top-bottom (&optional arg)
+  "Call (`recenter-top-bottom' ARG) in `swiper--window'."
+  (interactive "P")
+  (with-selected-window swiper--window
+    (recenter-top-bottom arg)))
+
 (defun swiper-font-lock-ensure ()
   "Ensure the entired buffer is highlighted."
   (unless (or (derived-mode-p 'magit-mode)
-              (memq major-mode '(package-menu-mode emms-playlist-mode)))
-    (if (fboundp 'font-lock-ensure)
-        (font-lock-ensure)
-      (font-lock-fontify-buffer))))
+              (memq major-mode '(package-menu-mode
+                                 gnus-summary-mode
+                                 gnus-article-mode
+                                 gnus-group-mode
+                                 emms-playlist-mode erc-mode
+                                 org-agenda-mode
+                                 dired-mode)))
+    (unless (> (buffer-size) 100000)
+      (if (fboundp 'font-lock-ensure)
+          (font-lock-ensure)
+        (with-no-warnings (font-lock-fontify-buffer))))))
 
 (defvar swiper--format-spec ""
   "Store the current candidates format spec.")
                            (line-beginning-position)
                            (line-end-position)))
                   candidates)
-            (zerop (forward-line 1)))
+            (forward-line 1))
           (nreverse candidates))))))
 
 (defvar swiper--opoint 1
   "`isearch' with an overview.
 When non-nil, INITIAL-INPUT is the initial search pattern."
   (interactive)
-  (setq swiper--opoint (point))
   (swiper--ivy initial-input))
 
+(defvar swiper--anchor nil
+  "A line number to which the search should be anchored.")
+
+(defvar swiper--len 0
+  "The last length of input for which an anchoring was made.")
+
 (defun swiper--init ()
   "Perform initialization common to both completion methods."
   (deactivate-mark)
+  (setq swiper--opoint (point))
   (setq swiper--len 0)
   (setq swiper--anchor (line-number-at-pos))
   (setq swiper--window (selected-window)))
@@ -125,7 +171,6 @@ When non-nil, INITIAL-INPUT is the initial search pattern."
   "`isearch' with an overview using `ivy'.
 When non-nil, INITIAL-INPUT is the initial search pattern."
   (interactive)
-  (ido-mode -1)
   (swiper--init)
   (let ((candidates (swiper--candidates))
         (preselect (format
@@ -141,10 +186,11 @@ When non-nil, INITIAL-INPUT is the initial search pattern."
                     (replace-regexp-in-string
                      "%s" "pattern: " swiper--format-spec)
                     candidates
+                    nil
                     initial-input
-                    #'swiper--update-input-ivy
-                    preselect))
-      (ido-mode 1)
+                    swiper-map
+                    preselect
+                    #'swiper--update-input-ivy))
       (swiper--cleanup)
       (if (null ivy-exit)
           (goto-char swiper--opoint)
@@ -159,6 +205,9 @@ When non-nil, INITIAL-INPUT is the initial search pattern."
                (setq expose (overlay-get ov 'isearch-open-invisible)))
           (funcall expose ov)))))
 
+(defvar swiper--overlays nil
+  "Store overlays.")
+
 (defun swiper--cleanup ()
   "Clean up the overlays."
   (while swiper--overlays
@@ -167,15 +216,6 @@ When non-nil, INITIAL-INPUT is the initial search pattern."
     (goto-char (point-min))
     (isearch-clean-overlays)))
 
-(defvar swiper--overlays nil
-  "Store overlays.")
-
-(defvar swiper--anchor nil
-  "A line number to which the search should be anchored.")
-
-(defvar swiper--len 0
-  "The last length of input for which an anchoring was made.")
-
 (defun swiper--update-input-ivy ()
   "Called when `ivy' input is updated."
   (swiper--cleanup)
@@ -191,46 +231,51 @@ When non-nil, INITIAL-INPUT is the initial search pattern."
         (forward-line (1- num))
         (isearch-range-invisible (line-beginning-position)
                                  (line-end-position))
-        (unless (and (> (point) (window-start))
-                     (< (point) (window-end swiper--window t)))
+        (unless (and (>= (point) (window-start))
+                     (<= (point) (window-end swiper--window t)))
           (recenter)))
-      (let ((ov (make-overlay
-                 (line-beginning-position)
-                 (1+ (line-end-position)))))
-        (overlay-put ov 'face 'swiper-line-face)
-        (overlay-put ov 'window swiper--window)
-        (push ov swiper--overlays))
-      (swiper--add-overlays
-       re
-       (window-start swiper--window)
-       (window-end swiper--window t)))))
-
-(defun swiper--add-overlays (re beg end)
-  "Add overlays for RE regexp in current buffer between BEG and END."
-  (when (> (length re) 1)
-    (save-excursion
-      (goto-char beg)
-      ;; RE can become an invalid regexp
-      (while (and (ignore-errors (re-search-forward re end t))
-                  (> (- (match-end 0) (match-beginning 0)) 0))
-        (let ((i 0))
-          (while (<= i ivy--subexps)
-            (when (match-beginning i)
-              (let ((overlay (make-overlay (match-beginning i)
-                                           (match-end i)))
-                    (face
-                     (cond ((zerop ivy--subexps)
-                            (cl-caddr swiper-faces))
-                           ((zerop i)
-                            (car swiper-faces))
-                           (t
-                            (nth (1+ (mod (1- i) (1- (length swiper-faces))))
-                                 swiper-faces)))))
-                (push overlay swiper--overlays)
-                (overlay-put overlay 'face face)
-                (overlay-put overlay 'window swiper--window)
-                (overlay-put overlay 'priority i)))
-            (cl-incf i)))))))
+      (swiper--add-overlays re))))
+
+(defun swiper--add-overlays (re &optional beg end)
+  "Add overlays for RE regexp in visible part of the current buffer.
+BEG and END, when specified, are the point bounds."
+  (let ((ov (make-overlay
+             (line-beginning-position)
+             (1+ (line-end-position)))))
+    (overlay-put ov 'face 'swiper-line-face)
+    (overlay-put ov 'window swiper--window)
+    (push ov swiper--overlays))
+  (let* ((wh (window-height))
+         (beg (or beg (save-excursion
+                        (forward-line (- wh))
+                        (point))))
+         (end (or end (save-excursion
+                        (forward-line wh)
+                        (point)))))
+    (when (>= (length re) swiper-min-highlight)
+      (save-excursion
+        (goto-char beg)
+        ;; RE can become an invalid regexp
+        (while (and (ignore-errors (re-search-forward re end t))
+                    (> (- (match-end 0) (match-beginning 0)) 0))
+          (let ((i 0))
+            (while (<= i ivy--subexps)
+              (when (match-beginning i)
+                (let ((overlay (make-overlay (match-beginning i)
+                                             (match-end i)))
+                      (face
+                       (cond ((zerop ivy--subexps)
+                              (cl-caddr swiper-faces))
+                             ((zerop i)
+                              (car swiper-faces))
+                             (t
+                              (nth (1+ (mod (1- i) (1- (length swiper-faces))))
+                                   swiper-faces)))))
+                  (push overlay swiper--overlays)
+                  (overlay-put overlay 'face face)
+                  (overlay-put overlay 'window swiper--window)
+                  (overlay-put overlay 'priority i)))
+              (cl-incf i))))))))
 
 (defun swiper--action (x input)
   "Goto line X and search for INPUT."