branch: master commit d2b2813b7e1a2af771063be17b1a2062f3778707 Author: Oleh Krehel <ohwoeo...@gmail.com> Commit: Oleh Krehel <ohwoeo...@gmail.com>
swiper-helm.el: Copy all helm stuff here --- swiper-helm.el | 181 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 files changed, 181 insertions(+), 0 deletions(-) diff --git a/swiper-helm.el b/swiper-helm.el new file mode 100644 index 0000000..f358870 --- /dev/null +++ b/swiper-helm.el @@ -0,0 +1,181 @@ +;;; swiper.el --- Help version of Swiper -*- lexical-binding: t -*- + +;; Copyright (C) 2015 Oleh Krehel + +;; Author: Oleh Krehel <ohwoeo...@gmail.com> +;; URL: https://github.com/abo-abo/swiper +;; Version: 0.1.0 +;; Package-Requires: ((emacs "24.1") (swiper "0.1.0") (helm "1.5.3")) +;; 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. The search regex can be split into groups with a +;; space. Each group is highlighted with a different face. +;; +;; The overview back end is `helm'. +;; +;; It can double as a quick `regex-builder', although only single +;; lines will be matched. + +;;; Code: + +(require 'swiper) +(require 'helm) + +(defvar swiper-helm-keymap + (let ((map (make-sparse-keymap))) + (define-key map (kbd "C-s") 'helm-next-line) + (define-key map (kbd "C-r") 'helm-previous-line) + map) + "Allows you to go to next and previous hit isearch-style.") + +(defun swiper-helm (&optional initial-input) + "`isearch' with an overview using `helm'. +When non-nil, INITIAL-INPUT is the initial search pattern." + (interactive) + (require 'helm) + (require 'helm-match-plugin) + (swiper--init) + (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 () + (add-hook 'helm-move-selection-after-hook + #'swiper--update-sel) + (add-hook 'helm-update-hook + #'swiper--update-input-helm) + (add-hook 'helm-after-update-hook + #'swiper--reanchor))) + (match-strict . (lambda (x) + (ignore-errors + (string-match (ivy--regex helm-input) x)))) + (candidates . ,(swiper--candidates)) + (filtered-candidate-transformer + helm-fuzzy-highlight-matches) + (action . swiper--action-helm)) + :keymap (make-composed-keymap + swiper-helm-keymap + helm-map) + :input initial-input + :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-helm) + (remove-hook 'helm-after-update-hook #'swiper--reanchor) + (swiper--cleanup))) + +(defun swiper--update-input-helm () + "Update selection." + (swiper--cleanup) + (with-selected-window swiper--window + (swiper--add-overlays + (ivy--regex helm-input) + (window-start swiper--window) + (window-end swiper--window t))) + (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)) + (cl-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 (ivy--regex helm-input)) + (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-selected-window swiper--window + (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-helm)))) + (with-selected-window swiper--window + (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-selected-window (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)))) + +(defun swiper--action-helm (x) + "Goto line X." + (swiper--action x helm-input)) + +(provide 'swiper-helm) + +;;; swiper-helm.el ends here