[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[elpa] master 16be7e1 01/67: Initial import
From: |
Oleh Krehel |
Subject: |
[elpa] master 16be7e1 01/67: Initial import |
Date: |
Sun, 22 Mar 2015 17:33:47 +0000 |
branch: master
commit 16be7e1bd96cec8e9de2feee59c23760dd234957
Author: Oleh Krehel <address@hidden>
Commit: Oleh Krehel <address@hidden>
Initial import
---
swiper.el | 278 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 278 insertions(+), 0 deletions(-)
diff --git a/swiper.el b/swiper.el
new file mode 100644
index 0000000..6eb0484
--- /dev/null
+++ b/swiper.el
@@ -0,0 +1,278 @@
+;;; swiper.el --- Isearch with an overview. Oh, man! -*- lexical-binding: t -*-
+
+;; Copyright (C) 2015 Oleh Krehel
+
+;; Author: Oleh Krehel <address@hidden>
+;; URL: https://github.com/abo-abo/swiper
+;; Version: 0.1.0
+;; Package-Requires: ((helm "1.6.7"))
+;; Keywords: matching
+
+;; This file is not 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
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; This program is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+;; GNU General Public License for more details.
+
+;; For a full copy of the GNU General Public License
+;; see <http://www.gnu.org/licenses/>.
+
+;;; Commentary:
+;;
+;; This package gives an overview of the current regex search
+;; candidates in a `helm' buffer. The search regex can be split into
+;; groups with a space. Each group is highlighted with a different
+;; face.
+;;
+;; It can double as a quick `regex-builder', although only single
+;; lines will be matched.
+
+;;; Code:
+(require 'helm)
+
+(defgroup swiper nil
+ "Interactive `occur' using `helm'."
+ :group 'matching
+ :prefix "swiper-")
+
+(defface swiper-match-face-1
+ '((t (:background "#FEEA89")))
+ "Face for `swiper' matches.")
+
+(defface swiper-match-face-2
+ '((t (:background "#F15C79")))
+ "Face for `swiper' matches.")
+
+(defface swiper-match-face-3
+ '((t (:background "#F9A35A")))
+ "Face for `swiper' matches.")
+
+(defface swiper-match-face-4
+ '((t (:background "#fb7905")))
+ "Face for `swiper' matches.")
+
+(defface swiper-line-face
+ '((t (:background "#f3d3d3")))
+ "Face for current `swiper' line.")
+
+(defcustom swiper-faces '(swiper-match-face-1
+ swiper-match-face-2
+ swiper-match-face-3
+ swiper-match-face-4)
+ "List of `swiper' faces for group matches.")
+
+(defvar swiper--buffer nil
+ "Store current buffer.")
+
+(defun swiper--candidates ()
+ "Return a list of this buffer lines."
+ (let* ((line-width (1+ (floor (log (count-lines
+ (point-min) (point-max))
+ 10))))
+ (fspec (format "%%-%dd %%s" line-width))
+ (line-number 0)
+ candidates)
+ (save-excursion
+ (goto-char (point-min))
+ (font-lock-ensure (point-min) (point-max))
+ (while (< (point) (point-max))
+ (push (format fspec
+ (incf line-number)
+ (buffer-substring
+ (line-beginning-position)
+ (line-end-position)))
+ candidates)
+ (zerop (forward-line 1)))
+ (nreverse candidates))))
+
+(defun swiper ()
+ "Interactive `occur' using `helm'."
+ (interactive)
+ (deactivate-mark)
+ (setq swiper--len 0)
+ (setq swiper--anchor (line-number-at-pos))
+ (unwind-protect
+ (let ((helm-display-function
+ (lambda (buf)
+ (when (one-window-p)
+ (split-window-vertically))
+ (other-window 1)
+ (switch-to-buffer buf)))
+ helm-candidate-number-limit)
+ (helm :sources
+ `((name . ,(buffer-name))
+ (init . (lambda ()
+ (setq swiper--buffer (current-buffer))
+ (add-hook 'helm-move-selection-after-hook
+ #'swiper--update-sel)
+ (add-hook 'helm-update-hook
+ #'swiper--update-input)
+ (add-hook 'helm-after-update-hook
+ #'swiper--reanchor)))
+ (match-strict . (lambda (x) (ignore-errors
+ (string-match (swiper--regex) x))))
+ (candidates . ,(swiper--candidates))
+ (filtered-candidate-transformer
+ helm-fuzzy-highlight-matches)
+ (action . swiper--action))
+ :preselect
+ (format "^%d " swiper--anchor)
+ :buffer "*swiper*"))
+ ;; cleanup
+ (remove-hook 'helm-move-selection-after-hook
+ #'swiper--update-sel)
+ (remove-hook 'helm-update-hook
+ #'swiper--update-input)
+ (remove-hook 'helm-after-update-hook
+ #'swiper--reanchor)
+ (while swiper--overlays
+ (delete-overlay (pop swiper--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 `helm-input' for which an anchoring was made.")
+
+(defun swiper--update-input ()
+ "Update selection."
+ (with-current-buffer swiper--buffer
+ (let ((re (swiper--regex))
+ (we (window-end nil t)))
+ (while swiper--overlays
+ (delete-overlay (pop swiper--overlays)))
+ (when (> (length helm-input) 1)
+ (save-excursion
+ (goto-char (window-start))
+ (while (ignore-errors (re-search-forward re we t))
+ (let ((i 0))
+ (while (<= i swiper--subexps)
+ (when (match-beginning i)
+ (let ((overlay (make-overlay (match-beginning i)
+ (match-end i)))
+ (face
+ (if (zerop i)
+ (car swiper-faces)
+ (nth (1+ (mod i (1- (length swiper-faces))))
+ swiper-faces))))
+ (push overlay swiper--overlays)
+ (overlay-put overlay 'face face)
+ (overlay-put overlay 'priority i)
+ (incf i))))))))))
+ (when (/= (length helm-input) swiper--len)
+ (setq swiper--len (length helm-input))
+ (swiper--reanchor)))
+
+(defun swiper--binary (beg end)
+ "Find anchor between BEG and END."
+ (if (<= (- end beg) 10)
+ (let ((min 1000)
+ n
+ ln
+ d)
+ (goto-char (point-min))
+ (forward-line (1- beg))
+ (while (< beg end)
+ (beginning-of-line)
+ (setq n (read (current-buffer)))
+ (when (< (setq d (abs (- n swiper--anchor))) min)
+ (setq min d)
+ (setq ln beg))
+ (incf beg)
+ (forward-line 1))
+ (goto-char (point-min))
+ (when ln
+ (forward-line (1- ln))))
+ (let ((mid (+ beg (/ (- end beg) 2))))
+ (goto-char (point-min))
+ (forward-line mid)
+ (beginning-of-line)
+ (let ((n (read (current-buffer))))
+ (if (> n swiper--anchor)
+ (swiper--binary beg mid)
+ (swiper--binary mid end))))))
+
+(defun swiper--update-sel ()
+ "Update selection."
+ (let* ((re (swiper--regex))
+ (str (buffer-substring-no-properties
+ (line-beginning-position)
+ (line-end-position)))
+ (num (if (string-match "^[0-9]+" str)
+ (string-to-number (match-string 0 str))
+ 0))
+ pt)
+ (when (> (length re) 0)
+ (with-current-buffer swiper--buffer
+ (goto-char (point-min))
+ (forward-line (1- num))
+ (when (re-search-forward re (point-max) t)
+ (setq pt (match-beginning 0))))
+ (when pt
+ (with-selected-window
+ (helm-persistent-action-display-window)
+ (goto-char pt)
+ (recenter)
+ (swiper--update-input))))
+ (with-current-buffer swiper--buffer
+ (let ((ov (make-overlay
+ (line-beginning-position)
+ (1+ (line-end-position)))))
+ (overlay-put ov 'face 'swiper-line-face)
+ (push ov swiper--overlays)))))
+
+(defun swiper--reanchor ()
+ "Move to a valid match closest to `swiper--anchor'."
+ (with-helm-window
+ (goto-char (point-min))
+ (if (re-search-forward (format "^%d " swiper--anchor) nil t)
+ nil
+ (forward-line 1)
+ (swiper--binary 2 (1+ (count-lines (point) (point-max)))))
+ (when (> (count-lines (point-min) (point-max)) 1)
+ (forward-line -1)
+ (helm-next-line 1))))
+
+(defvar swiper--subexps 1
+ "Number of groups in `(swiper--regex)'.")
+
+(defvar swiper--regex-hash
+ (make-hash-table :test 'equal)
+ "Store pre-computed regex.")
+
+(defun swiper--regex ()
+ "Re-build regex in case it has a space."
+ (cdr
+ (let ((hashed (gethash helm-input swiper--regex-hash)))
+ (if hashed
+ (prog1 hashed
+ (setq swiper--subexps (car hashed)))
+ (puthash helm-input
+ (let ((subs (split-string helm-input " +" t)))
+ (cons
+ (setq swiper--subexps (length subs))
+ (mapconcat
+ (lambda (x) (format "\\(%s\\)" x))
+ subs
+ ".*")))
+ swiper--regex-hash)))))
+
+(defun swiper--action (x)
+ "Goto line X."
+ (goto-char (point-min))
+ (forward-line (1- (read x)))
+ (re-search-forward
+ (swiper--regex) (line-end-position) t))
+
+(provide 'swiper)
+
+;;; swiper.el ends here
- [elpa] master updated (5aa7896 -> 302a16a), Oleh Krehel, 2015/03/22
- [elpa] master c990320 02/67: Update call to `font-lock-ensure', Oleh Krehel, 2015/03/22
- [elpa] master 7159d84 03/67: swiper.el (swiper--regex): Zero groups without space, Oleh Krehel, 2015/03/22
- [elpa] master 3a4cb1f 05/67: Add compatibility alias for `font-lock-ensure', Oleh Krehel, 2015/03/22
- [elpa] master fed3aff 04/67: README.md: Add, Oleh Krehel, 2015/03/22
- [elpa] master 16be7e1 01/67: Initial import,
Oleh Krehel <=
- [elpa] master ff0ee94 06/67: Add dependency on emacs 24.1, Oleh Krehel, 2015/03/22
- [elpa] master 1c0b30b 07/67: add autoload cookie for lazy loading, Oleh Krehel, 2015/03/22
- [elpa] master 1099ebf 08/67: Use cl-lib macros instead of cl.el, Oleh Krehel, 2015/03/22
- [elpa] master 7b86747 09/67: swiper.el (swiper--regex): Update signature, Oleh Krehel, 2015/03/22
- [elpa] master a267b34 10/67: familiar isearch key bindings while helm is active, Oleh Krehel, 2015/03/22
- [elpa] master a817342 14/67: ivy.el: Improve the highlighting in the minibuffer, Oleh Krehel, 2015/03/22
- [elpa] master 97ab66a 13/67: README.md: Update, Oleh Krehel, 2015/03/22
- [elpa] master eb829a9 16/67: Account for zero-length regex matches, Oleh Krehel, 2015/03/22
- [elpa] master 9bcf1dc 12/67: Update dependencies., Oleh Krehel, 2015/03/22
- [elpa] master 7cea819 18/67: ivy.el: Add `ivy-exit', Oleh Krehel, 2015/03/22