1678 lines
70 KiB
EmacsLisp
1678 lines
70 KiB
EmacsLisp
|
;;; helm-swoop.el --- Efficiently hopping squeezed lines powered by helm interface -*- coding: utf-8; lexical-binding: t -*-
|
||
|
|
||
|
;; Copyright (C) 2013 by Shingo Fukuyama
|
||
|
|
||
|
;; Version: 1.7.2
|
||
|
;; Package-Version: 20160619.953
|
||
|
;; Author: Shingo Fukuyama - http://fukuyama.co
|
||
|
;; URL: https://github.com/ShingoFukuyama/helm-swoop
|
||
|
;; Created: Oct 24 2013
|
||
|
;; Keywords: helm swoop inner buffer search
|
||
|
;; Package-Requires: ((helm "1.0") (emacs "24.3"))
|
||
|
|
||
|
;; This program 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 2 of
|
||
|
;; the License, 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.
|
||
|
|
||
|
;;; Commentary:
|
||
|
|
||
|
;; List the all lines to another buffer, which is able to squeeze
|
||
|
;; by any words you input. At the same time, the original buffer's
|
||
|
;; cursor is jumping line to line according to moving up and down
|
||
|
;; the list.
|
||
|
|
||
|
;; Example config
|
||
|
;; ----------------------------------------------------------------
|
||
|
;; ;; helm from https://github.com/emacs-helm/helm
|
||
|
;; (require 'helm)
|
||
|
|
||
|
;; ;; Locate the helm-swoop folder to your path
|
||
|
;; ;; This line is unnecessary if you get this program from MELPA
|
||
|
;; (add-to-list 'load-path "~/.emacs.d/elisp/helm-swoop")
|
||
|
|
||
|
;; (require 'helm-swoop)
|
||
|
|
||
|
;; ;; Change keybinds to whatever you like :)
|
||
|
;; (global-set-key (kbd "M-i") 'helm-swoop)
|
||
|
;; (global-set-key (kbd "M-I") 'helm-swoop-back-to-last-point)
|
||
|
;; (global-set-key (kbd "C-c M-i") 'helm-multi-swoop)
|
||
|
;; (global-set-key (kbd "C-x M-i") 'helm-multi-swoop-all)
|
||
|
|
||
|
;; ;; When doing isearch, hand the word over to helm-swoop
|
||
|
;; (define-key isearch-mode-map (kbd "M-i") 'helm-swoop-from-isearch)
|
||
|
;; (define-key helm-swoop-map (kbd "M-i") 'helm-multi-swoop-all-from-helm-swoop)
|
||
|
|
||
|
;; ;; Save buffer when helm-multi-swoop-edit complete
|
||
|
;; (setq helm-multi-swoop-edit-save t)
|
||
|
|
||
|
;; ;; If this value is t, split window inside the current window
|
||
|
;; (setq helm-swoop-split-with-multiple-windows nil)
|
||
|
|
||
|
;; ;; Split direction. 'split-window-vertically or 'split-window-horizontally
|
||
|
;; (setq helm-swoop-split-direction 'split-window-vertically)
|
||
|
|
||
|
;; ;; If nil, you can slightly boost invoke speed in exchange for text color
|
||
|
;; (setq helm-swoop-speed-or-color nil)
|
||
|
|
||
|
;; ;; Go to the opposite side of line from the end or beginning of line
|
||
|
;; (setq helm-swoop-move-to-line-cycle t)
|
||
|
|
||
|
;; ;; Optional face for line numbers
|
||
|
;; ;; Face name is `helm-swoop-line-number-face`
|
||
|
;; (setq helm-swoop-use-line-number-face t)
|
||
|
|
||
|
;; ----------------------------------------------------------------
|
||
|
|
||
|
;; * `M-x helm-swoop` when region active
|
||
|
;; * `M-x helm-swoop` when the cursor is at any symbol
|
||
|
;; * `M-x helm-swoop` when the cursor is not at any symbol
|
||
|
;; * `M-3 M-x helm-swoop` or `C-u 5 M-x helm-swoop` multi separated line culling
|
||
|
;; * `M-x helm-multi-swoop` multi-occur like feature
|
||
|
;; * `M-x helm-multi-swoop-all` apply all buffers
|
||
|
;; * `C-u M-x helm-multi-swoop` apply last selected buffers from the second time
|
||
|
;; * `M-x helm-swoop-same-face-at-point` list lines have the same face at the cursor is on
|
||
|
;; * During isearch `M-i` to hand the word over to helm-swoop
|
||
|
;; * During helm-swoop `M-i` to hand the word over to helm-multi-swoop-all
|
||
|
;; * While doing `helm-swoop` press `C-c C-e` to edit mode, apply changes to original buffer by `C-x C-s`
|
||
|
|
||
|
;; Helm Swoop Edit
|
||
|
;; While doing helm-swoop, press keybind [C-c C-e] to move to edit buffer.
|
||
|
;; Edit the list and apply by [C-x C-s]. If you'd like to cancel, [C-c C-g]
|
||
|
|
||
|
;;; Code:
|
||
|
|
||
|
(require 'cl-lib)
|
||
|
(require 'helm)
|
||
|
(require 'helm-utils)
|
||
|
(require 'helm-grep)
|
||
|
|
||
|
(declare-function migemo-search-pattern-get "migemo")
|
||
|
(declare-function projectile-buffers-with-file-or-process "projectile")
|
||
|
(declare-function projectile-project-buffers "projectile")
|
||
|
(defvar projectile-buffers-filter-function)
|
||
|
|
||
|
;;; @ helm-swoop ----------------------------------------------
|
||
|
|
||
|
(defgroup helm-swoop nil
|
||
|
"Open helm-swoop."
|
||
|
:prefix "helm-swoop-" :group 'helm)
|
||
|
|
||
|
(defface helm-swoop-target-line-face
|
||
|
'((t (:background "#e3e300" :foreground "#222222")))
|
||
|
"Face for helm-swoop target line"
|
||
|
:group 'helm-swoop)
|
||
|
(defface helm-swoop-target-line-block-face
|
||
|
'((t (:background "#cccc00" :foreground "#222222")))
|
||
|
"Face for target line"
|
||
|
:group 'helm-swoop)
|
||
|
(defface helm-swoop-target-word-face
|
||
|
'((t (:background "#7700ff" :foreground "#ffffff")))
|
||
|
"Face for target word"
|
||
|
:group 'helm-swoop)
|
||
|
(defface helm-swoop-line-number-face
|
||
|
'((t (:foreground "#999999")))
|
||
|
"Face for line numbers"
|
||
|
:group 'helm-swoop)
|
||
|
|
||
|
(defcustom helm-swoop-speed-or-color nil
|
||
|
"If nil, you can slightly boost invoke speed in exchange for text color"
|
||
|
:group 'helm-swoop :type 'boolean)
|
||
|
(defcustom helm-swoop-use-line-number-face nil
|
||
|
"Use face to line numbers on helm-swoop buffer"
|
||
|
:group 'helm-swoop :type 'boolean)
|
||
|
(defcustom helm-swoop-split-with-multiple-windows nil
|
||
|
"Split window when having multiple windows open"
|
||
|
:group 'helm-swoop :type 'boolean)
|
||
|
(defcustom helm-swoop-move-to-line-cycle t
|
||
|
"Return to the opposite side of line"
|
||
|
:group 'helm-swoop :type 'boolean)
|
||
|
(defcustom helm-swoop-split-direction 'split-window-vertically
|
||
|
"Split direction"
|
||
|
:type '(choice (const :tag "vertically" split-window-vertically)
|
||
|
(const :tag "horizontally" split-window-horizontally))
|
||
|
:group 'helm-swoop)
|
||
|
(defcustom helm-swoop-use-fuzzy-match nil
|
||
|
"If t, use fuzzy matching functions as well as exact matches."
|
||
|
:group 'helm-swoop :type 'boolean)
|
||
|
|
||
|
(defvar helm-swoop-split-window-function
|
||
|
(lambda ($buf)
|
||
|
(if helm-swoop-split-with-multiple-windows
|
||
|
(funcall helm-swoop-split-direction)
|
||
|
(when (one-window-p)
|
||
|
(funcall helm-swoop-split-direction)))
|
||
|
(other-window 1)
|
||
|
(switch-to-buffer $buf))
|
||
|
"Change the way to split window only when `helm-swoop' is calling")
|
||
|
|
||
|
(defvar helm-swoop-candidate-number-limit 19999)
|
||
|
(defvar helm-swoop-buffer "*Helm Swoop*")
|
||
|
(defvar helm-swoop-prompt "Swoop: ")
|
||
|
(defvar helm-swoop-last-point nil)
|
||
|
(defvar helm-swoop-invisible-targets nil)
|
||
|
(defvar helm-swoop-last-line-info nil)
|
||
|
|
||
|
;; Buffer local variables
|
||
|
(defvar helm-swoop-list-cache)
|
||
|
(defvar helm-swoop-pattern) ; Keep helm-pattern value
|
||
|
(defvar helm-swoop-last-query) ; Last search query for resume
|
||
|
(defvar-local helm-swoop-last-prefix-number 1) ; For multiline highlight
|
||
|
|
||
|
;; Global variables
|
||
|
(defvar helm-swoop-synchronizing-window nil
|
||
|
"Window object where `helm-swoop' called from")
|
||
|
(defvar helm-swoop-target-buffer nil
|
||
|
"Buffer object where `helm-swoop' called from")
|
||
|
(defvar helm-swoop-line-overlay nil
|
||
|
"Overlay object to indicate other window's line")
|
||
|
|
||
|
(defvar helm-swoop-map
|
||
|
(let (($map (make-sparse-keymap)))
|
||
|
(set-keymap-parent $map helm-map)
|
||
|
(define-key $map (kbd "C-c C-e") 'helm-swoop-edit)
|
||
|
(define-key $map (kbd "M-i") 'helm-multi-swoop-all-from-helm-swoop)
|
||
|
(define-key $map (kbd "C-w") 'helm-swoop-yank-thing-at-point)
|
||
|
(define-key $map (kbd "^") 'helm-swoop-caret-match)
|
||
|
(delq nil $map))
|
||
|
"Keymap for helm-swoop")
|
||
|
|
||
|
(defvar helm-multi-swoop-map
|
||
|
(let (($map (make-sparse-keymap)))
|
||
|
(set-keymap-parent $map helm-map)
|
||
|
(define-key $map (kbd "C-c C-e") 'helm-multi-swoop-edit)
|
||
|
(delq nil $map)))
|
||
|
|
||
|
(defvar helm-c-source-swoop-match-functions
|
||
|
'(helm-mm-exact-match
|
||
|
helm-mm-match
|
||
|
helm-mm-3-migemo-match))
|
||
|
|
||
|
(defvar helm-c-source-swoop-search-functions
|
||
|
'(helm-mm-exact-search
|
||
|
helm-mm-search
|
||
|
helm-candidates-in-buffer-search-default-fn
|
||
|
helm-mm-3-migemo-search))
|
||
|
|
||
|
(defun helm-swoop-match-functions ()
|
||
|
(if helm-swoop-use-fuzzy-match
|
||
|
(append helm-c-source-swoop-match-functions '(helm-fuzzy-match))
|
||
|
helm-c-source-swoop-match-functions))
|
||
|
|
||
|
(defun helm-swoop-search-functions ()
|
||
|
(if helm-swoop-use-fuzzy-match
|
||
|
(append helm-c-source-swoop-search-functions '(helm-fuzzy-search))
|
||
|
helm-c-source-swoop-search-functions))
|
||
|
|
||
|
(defcustom helm-swoop-pre-input-function
|
||
|
(lambda () (thing-at-point 'symbol))
|
||
|
"This function can pre-input keywords when helm-swoop invoked"
|
||
|
:group 'helm-swoop :type 'function)
|
||
|
|
||
|
(defun helm-swoop-pre-input-optimize ($query)
|
||
|
(when $query
|
||
|
(let (($regexp (list '("\+" . "\\\\+")
|
||
|
'("\*" . "\\\\*")
|
||
|
'("\#" . "\\\\#"))))
|
||
|
(mapc (lambda ($r)
|
||
|
(setq $query (replace-regexp-in-string (car $r) (cdr $r) $query)))
|
||
|
$regexp)
|
||
|
$query)))
|
||
|
|
||
|
(defsubst helm-swoop--goto-line ($line)
|
||
|
(goto-char (point-min))
|
||
|
(forward-line (1- $line)))
|
||
|
|
||
|
(defsubst helm-swoop--recenter ()
|
||
|
(recenter (/ (window-height) 2)))
|
||
|
|
||
|
(defsubst helm-swoop--key-of-function ($function &optional $mode-map)
|
||
|
(edmacro-format-keys (car (where-is-internal $function $mode-map))))
|
||
|
|
||
|
(defsubst helm-swoop--delete-overlay ($identity &optional $beg $end)
|
||
|
(or $beg (setq $beg (point-min)))
|
||
|
(or $end (setq $end (point-max)))
|
||
|
(overlay-recenter $end)
|
||
|
(mapc (lambda ($o)
|
||
|
(if (overlay-get $o $identity)
|
||
|
(delete-overlay $o)))
|
||
|
(overlays-in $beg $end)))
|
||
|
|
||
|
(defsubst helm-swoop--get-string-at-line ()
|
||
|
(buffer-substring-no-properties (point-at-bol) (point-at-eol)))
|
||
|
|
||
|
(defsubst helm-swoop--buffer-substring ($point-min $point-max)
|
||
|
(if helm-swoop-speed-or-color
|
||
|
(let (($content (buffer-substring $point-min $point-max)))
|
||
|
(with-temp-buffer
|
||
|
(let ((inhibit-read-only t))
|
||
|
(insert $content)
|
||
|
(remove-text-properties (point-min) (point-max) '(read-only t))
|
||
|
(setq $content (buffer-substring (point-min) (point-max)))))
|
||
|
$content)
|
||
|
(buffer-substring-no-properties $point-min $point-max)))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-swoop-back-to-last-point (&optional $cancel)
|
||
|
"Go back to last position where `helm-swoop' was called"
|
||
|
(interactive)
|
||
|
(if helm-swoop-last-point
|
||
|
(let (($po (point)))
|
||
|
(switch-to-buffer (cdr helm-swoop-last-point))
|
||
|
(goto-char (car helm-swoop-last-point))
|
||
|
(unless $cancel
|
||
|
(setq helm-swoop-last-point
|
||
|
(cons $po (buffer-name (current-buffer))))))))
|
||
|
|
||
|
(defun helm-swoop--split-lines-by ($string $regexp $step)
|
||
|
"split-string by $step for multiline"
|
||
|
(or $step (setq $step 1))
|
||
|
(let (($from1 0) ;; last match point
|
||
|
($from2 0) ;; last substring point
|
||
|
$list
|
||
|
($i 1)) ;; from line 1
|
||
|
(while (string-match $regexp $string $from1)
|
||
|
(setq $i (1+ $i))
|
||
|
(if (eq 0 (% $i $step))
|
||
|
(progn
|
||
|
(setq $list (cons (substring $string $from2 (match-beginning 0))
|
||
|
$list))
|
||
|
(setq $from2 (match-end 0))
|
||
|
(setq $from1 (match-end 0)))
|
||
|
(setq $from1 (match-end 0))))
|
||
|
(setq $list (cons (substring $string $from2) $list))
|
||
|
(nreverse $list)))
|
||
|
|
||
|
(defun helm-swoop--target-line-overlay-move (&optional $buf)
|
||
|
"Add color to the target line"
|
||
|
(move-overlay
|
||
|
helm-swoop-line-overlay
|
||
|
(progn
|
||
|
(search-backward
|
||
|
"\n" nil t (% (line-number-at-pos) helm-swoop-last-prefix-number))
|
||
|
(goto-char (point-at-bol)))
|
||
|
;; For multiline highlight
|
||
|
(save-excursion
|
||
|
(goto-char (point-at-bol))
|
||
|
(or (re-search-forward "\n" nil t helm-swoop-last-prefix-number)
|
||
|
;; For the end of buffer error
|
||
|
(point-max)))
|
||
|
$buf)
|
||
|
(helm-swoop--unveil-invisible-overlay))
|
||
|
|
||
|
(defun helm-swoop--validate-regexp (regexp)
|
||
|
(condition-case nil
|
||
|
(progn
|
||
|
(string-match-p regexp "")
|
||
|
t)
|
||
|
(invalid-regexp nil)))
|
||
|
|
||
|
(defun helm-swoop--target-word-overlay ($identity &optional $threshold)
|
||
|
(interactive)
|
||
|
(or $threshold (setq $threshold 2))
|
||
|
(save-excursion
|
||
|
(let (($pat (split-string helm-pattern " "))
|
||
|
$o)
|
||
|
(mapc (lambda ($wd)
|
||
|
(when (and (helm-swoop--validate-regexp $wd) (< $threshold (length $wd)))
|
||
|
(goto-char (point-min))
|
||
|
;; Optional require migemo.el
|
||
|
(if (and (featurep 'migemo) helm-migemo-mode)
|
||
|
(setq $wd (migemo-search-pattern-get $wd)))
|
||
|
;; For caret begging match
|
||
|
(if (string-match "^\\^\\[0\\-9\\]\\+\\.\\(.+\\)" $wd)
|
||
|
(setq $wd (concat "^" (match-string 1 $wd))))
|
||
|
(overlay-recenter (point-max))
|
||
|
(let (finish)
|
||
|
(while (and (not finish) (re-search-forward $wd nil t))
|
||
|
(if (= (match-beginning 0) (match-end 0))
|
||
|
(forward-char 1)
|
||
|
(setq $o (make-overlay (match-beginning 0) (match-end 0)))
|
||
|
(overlay-put $o 'face 'helm-swoop-target-word-face)
|
||
|
(overlay-put $o $identity t))
|
||
|
(when (eobp)
|
||
|
(setq finish t))))))
|
||
|
$pat))))
|
||
|
|
||
|
(defun helm-swoop--restore-unveiled-overlay ()
|
||
|
(when helm-swoop-invisible-targets
|
||
|
(mapc (lambda ($ov) (overlay-put (car $ov) 'invisible (cdr $ov)))
|
||
|
helm-swoop-invisible-targets)
|
||
|
(setq helm-swoop-invisible-targets nil)))
|
||
|
|
||
|
(defun helm-swoop--unveil-invisible-overlay ()
|
||
|
"Show hidden text temporarily to view it during helm-swoop.
|
||
|
This function needs to call after latest helm-swoop-line-overlay set."
|
||
|
(helm-swoop--restore-unveiled-overlay)
|
||
|
(mapc (lambda ($ov)
|
||
|
(let (($type (overlay-get $ov 'invisible)))
|
||
|
(when $type
|
||
|
(overlay-put $ov 'invisible nil)
|
||
|
(setq helm-swoop-invisible-targets
|
||
|
(cons (cons $ov $type) helm-swoop-invisible-targets)))))
|
||
|
(overlays-in (overlay-start helm-swoop-line-overlay)
|
||
|
(overlay-end helm-swoop-line-overlay))))
|
||
|
|
||
|
;; helm action ------------------------------------------------
|
||
|
|
||
|
(defadvice helm-next-line (around helm-swoop-next-line disable)
|
||
|
(let ((helm-move-to-line-cycle-in-source t))
|
||
|
ad-do-it
|
||
|
(when (called-interactively-p 'any)
|
||
|
(helm-swoop--move-line-action))))
|
||
|
|
||
|
(defadvice helm-previous-line (around helm-swoop-previous-line disable)
|
||
|
(let ((helm-move-to-line-cycle-in-source t))
|
||
|
ad-do-it
|
||
|
(when (called-interactively-p 'any)
|
||
|
(helm-swoop--move-line-action))))
|
||
|
|
||
|
(defadvice helm-toggle-visible-mark (around helm-swoop-toggle-visible-mark disable)
|
||
|
(let ((helm-move-to-line-cycle-in-source t))
|
||
|
ad-do-it
|
||
|
(when (called-interactively-p 'any)
|
||
|
(helm-swoop--move-line-action))))
|
||
|
|
||
|
(defun helm-swoop--move-line-action ()
|
||
|
(with-helm-window
|
||
|
(let* (($key (helm-swoop--get-string-at-line))
|
||
|
($num (when (string-match "^[0-9]+" $key)
|
||
|
(string-to-number (match-string 0 $key)))))
|
||
|
;; Synchronizing line position
|
||
|
(when (and $key $num)
|
||
|
(with-selected-window helm-swoop-synchronizing-window
|
||
|
(progn
|
||
|
(helm-swoop--goto-line $num)
|
||
|
(with-current-buffer helm-swoop-target-buffer
|
||
|
(delete-overlay helm-swoop-line-overlay)
|
||
|
(helm-swoop--target-line-overlay-move))
|
||
|
(helm-swoop--recenter)))
|
||
|
(setq helm-swoop-last-line-info
|
||
|
(cons helm-swoop-target-buffer $num))))))
|
||
|
|
||
|
(defun helm-swoop--nearest-line ($target $list)
|
||
|
"Return the nearest number of $target out of $list."
|
||
|
(when (and $target $list)
|
||
|
(let ($result)
|
||
|
(cl-labels ((filter ($fn $elem $list)
|
||
|
(let ($r)
|
||
|
(mapc (lambda ($e)
|
||
|
(if (funcall $fn $elem $e)
|
||
|
(setq $r (cons $e $r))))
|
||
|
$list) $r)))
|
||
|
(if (eq 1 (length $list))
|
||
|
(setq $result (car $list))
|
||
|
(let* (($lts (filter '> $target $list))
|
||
|
($gts (filter '< $target $list))
|
||
|
($lt (if $lts (apply 'max $lts)))
|
||
|
($gt (if $gts (apply 'min $gts)))
|
||
|
($ltg (if $lt (- $target $lt)))
|
||
|
($gtg (if $gt (- $gt $target))))
|
||
|
(setq $result
|
||
|
(cond ((memq $target $list) $target)
|
||
|
((and (not $lt) (not $gt)) nil)
|
||
|
((not $gtg) $lt)
|
||
|
((not $ltg) $gt)
|
||
|
((eq $ltg $gtg) $gt)
|
||
|
((< $ltg $gtg) $lt)
|
||
|
((> $ltg $gtg) $gt)
|
||
|
(t 1))))))
|
||
|
$result)))
|
||
|
|
||
|
(defun helm-swoop--keep-nearest-position ()
|
||
|
(with-helm-window
|
||
|
(let (($p (point-min)) $list $bound
|
||
|
$nearest-line $target-point
|
||
|
($buf (rx-to-string (buffer-name (car helm-swoop-last-line-info)) t)))
|
||
|
(save-excursion
|
||
|
(goto-char $p)
|
||
|
(while (if $p (setq $p (re-search-forward (concat "^" $buf "$") nil t)))
|
||
|
(when (get-text-property (point-at-bol) 'helm-header)
|
||
|
(forward-char 1)
|
||
|
(setq $bound (next-single-property-change (point) 'helm-header))
|
||
|
(while (re-search-forward "^[0-9]+" $bound t)
|
||
|
(setq $list (cons
|
||
|
(string-to-number (match-string 0))
|
||
|
$list)))
|
||
|
(setq $nearest-line (helm-swoop--nearest-line
|
||
|
(cdr helm-swoop-last-line-info)
|
||
|
$list))
|
||
|
(goto-char $p)
|
||
|
(re-search-forward (concat "^"
|
||
|
(number-to-string $nearest-line)
|
||
|
"\\s-") $bound t)
|
||
|
(setq $target-point (point))
|
||
|
(setq $p nil))))
|
||
|
(when $target-point
|
||
|
(goto-char $target-point)
|
||
|
(helm-mark-current-line)
|
||
|
(if (equal helm-swoop-buffer (buffer-name (current-buffer)))
|
||
|
(helm-swoop--move-line-action)
|
||
|
(helm-multi-swoop--move-line-action))))))
|
||
|
|
||
|
(defun helm-swoop--pattern-match ()
|
||
|
"Overlay target words"
|
||
|
(with-helm-window
|
||
|
(setq helm-swoop-pattern helm-pattern)
|
||
|
(when (< 2 (length helm-pattern))
|
||
|
(helm-swoop--delete-overlay 'target-buffer)
|
||
|
(helm-swoop--target-word-overlay 'target-buffer)
|
||
|
(with-selected-window helm-swoop-synchronizing-window
|
||
|
(helm-swoop--delete-overlay 'target-buffer)
|
||
|
(helm-swoop--target-word-overlay 'target-buffer)))))
|
||
|
|
||
|
(defun helm-swoop-flash-word ($match-beg $match-end)
|
||
|
(interactive)
|
||
|
(unwind-protect
|
||
|
(let (($o (make-overlay $match-beg $match-end)))
|
||
|
(when $o
|
||
|
(overlay-put $o 'face 'helm-swoop-target-word-face)
|
||
|
(overlay-put $o 'helm-swoop-overlay-word-frash t)))
|
||
|
(run-with-idle-timer
|
||
|
0.6 nil (lambda () (helm-swoop--delete-overlay 'helm-swoop-overlay-word-frash)))))
|
||
|
|
||
|
;; core ------------------------------------------------
|
||
|
|
||
|
(defun helm-swoop--get-content ($buffer &optional $linum)
|
||
|
"Get the whole content in buffer and add line number at the head.
|
||
|
If $linum is number, lines are separated by $linum"
|
||
|
(let (($buf (get-buffer $buffer)))
|
||
|
(when $buf
|
||
|
(with-current-buffer $buf
|
||
|
(let (($bufstr (helm-swoop--buffer-substring (point-min) (point-max)))
|
||
|
$return)
|
||
|
(with-temp-buffer
|
||
|
(insert $bufstr)
|
||
|
(goto-char (point-min))
|
||
|
(let (($i 1))
|
||
|
(insert (format "%s " $i))
|
||
|
(while (re-search-forward "\n" nil t)
|
||
|
(cl-incf $i)
|
||
|
(if helm-swoop-use-line-number-face
|
||
|
(insert (propertize (format "%s" $i) 'font-lock-face 'helm-swoop-line-number-face) " ")
|
||
|
(insert (format "%s " $i))))
|
||
|
;; Delete empty lines
|
||
|
(unless $linum
|
||
|
(goto-char (point-min))
|
||
|
(while (re-search-forward "^[0-9]+\\s-*$" nil t)
|
||
|
(replace-match ""))))
|
||
|
(setq $return (helm-swoop--buffer-substring (point-min) (point-max))))
|
||
|
$return)))))
|
||
|
|
||
|
(defun helm-c-source-swoop ()
|
||
|
`((name . ,(buffer-name helm-swoop-target-buffer))
|
||
|
(candidates . ,(if helm-swoop-list-cache
|
||
|
(progn
|
||
|
(helm-swoop--split-lines-by
|
||
|
helm-swoop-list-cache "\n" helm-swoop-last-prefix-number))
|
||
|
(helm-swoop--split-lines-by
|
||
|
(setq helm-swoop-list-cache
|
||
|
(helm-swoop--get-content helm-swoop-target-buffer t))
|
||
|
"\n" helm-swoop-last-prefix-number)))
|
||
|
(get-line . ,(if helm-swoop-speed-or-color
|
||
|
'helm-swoop--buffer-substring
|
||
|
'buffer-substring-no-properties))
|
||
|
(keymap . ,helm-swoop-map)
|
||
|
(header-line . "[C-c C-e] Edit mode, [M-i] apply all buffers")
|
||
|
(action . (("Go to Line"
|
||
|
. (lambda ($line)
|
||
|
(helm-swoop--goto-line
|
||
|
(when (string-match "^[0-9]+" $line)
|
||
|
(string-to-number (match-string 0 $line))))
|
||
|
(let (($regex
|
||
|
(mapconcat 'identity
|
||
|
(split-string helm-pattern " ")
|
||
|
"\\|")))
|
||
|
(when (or (and (and (featurep 'migemo) helm-migemo-mode)
|
||
|
(migemo-forward $regex nil t))
|
||
|
(re-search-forward $regex nil t))
|
||
|
(helm-swoop-flash-word (match-beginning 0) (match-end 0))
|
||
|
(goto-char (match-beginning 0))))
|
||
|
(helm-swoop--recenter)))))
|
||
|
,(if (and helm-swoop-last-prefix-number
|
||
|
(> helm-swoop-last-prefix-number 1))
|
||
|
'(multiline))
|
||
|
(match . ,(helm-swoop-match-functions))
|
||
|
(search . ,(helm-swoop-search-functions))))
|
||
|
|
||
|
(defun helm-c-source-multi-swoop ($buf $func $action $multiline)
|
||
|
`((name . ,$buf)
|
||
|
(candidates . ,(funcall $func))
|
||
|
(action . ,$action)
|
||
|
(header-line . ,(concat $buf " [C-c C-e] Edit mode"))
|
||
|
(keymap . ,helm-multi-swoop-map)
|
||
|
(requires-pattern . 2)
|
||
|
,(if (and $multiline
|
||
|
(> $multiline 1))
|
||
|
'(multiline))
|
||
|
(match . ,(helm-swoop-match-functions))
|
||
|
(search . ,(helm-swoop-search-functions))))
|
||
|
|
||
|
(defun helm-swoop--set-prefix ($multiline)
|
||
|
;; Enable scrolling margin
|
||
|
(setq helm-swoop-last-prefix-number
|
||
|
(or $multiline 1))) ;; $multiline is for resume
|
||
|
|
||
|
;; Delete cache when modified file is saved
|
||
|
(defun helm-swoop--clear-cache ()
|
||
|
(if (boundp 'helm-swoop-list-cache) (setq helm-swoop-list-cache nil)))
|
||
|
(add-hook 'after-save-hook 'helm-swoop--clear-cache)
|
||
|
|
||
|
(defadvice narrow-to-region (around helm-swoop-advice-narrow-to-region activate)
|
||
|
(helm-swoop--clear-cache)
|
||
|
ad-do-it)
|
||
|
(defadvice narrow-to-defun (around helm-swoop-advice-narrow-to-defun activate)
|
||
|
(helm-swoop--clear-cache)
|
||
|
ad-do-it)
|
||
|
(defadvice narrow-to-page (around helm-swoop-advice-narrow-to-page activate)
|
||
|
(helm-swoop--clear-cache)
|
||
|
ad-do-it)
|
||
|
(defadvice widen (around helm-swoop-advice-widen activate)
|
||
|
(helm-swoop--clear-cache)
|
||
|
ad-do-it)
|
||
|
|
||
|
(defun helm-swoop--restore ()
|
||
|
(when (= 1 helm-exit-status)
|
||
|
(helm-swoop-back-to-last-point t)
|
||
|
(helm-swoop--restore-unveiled-overlay))
|
||
|
(setq helm-swoop-invisible-targets nil)
|
||
|
(ad-disable-advice 'helm-next-line 'around 'helm-swoop-next-line)
|
||
|
(ad-activate 'helm-next-line)
|
||
|
(ad-disable-advice 'helm-previous-line 'around 'helm-swoop-previous-line)
|
||
|
(ad-activate 'helm-previous-line)
|
||
|
(ad-disable-advice 'helm-toggle-visible-mark 'around 'helm-swoop-toggle-visible-mark)
|
||
|
(ad-activate 'helm-toggle-visible-mark)
|
||
|
(ad-disable-advice 'helm-move--next-line-fn 'around
|
||
|
'helm-multi-swoop-next-line-cycle)
|
||
|
(ad-activate 'helm-move--next-line-fn)
|
||
|
(ad-disable-advice 'helm-move--previous-line-fn 'around
|
||
|
'helm-multi-swoop-previous-line-cycle)
|
||
|
(ad-activate 'helm-move--previous-line-fn)
|
||
|
(remove-hook 'helm-update-hook 'helm-swoop--pattern-match)
|
||
|
(remove-hook 'helm-after-update-hook 'helm-swoop--keep-nearest-position)
|
||
|
(setq helm-swoop-last-query helm-swoop-pattern)
|
||
|
(mapc (lambda ($ov)
|
||
|
(when (or (eq 'helm-swoop-target-line-face (overlay-get $ov 'face))
|
||
|
(eq 'helm-swoop-target-line-block-face
|
||
|
(overlay-get $ov 'face)))
|
||
|
(delete-overlay $ov)))
|
||
|
(overlays-in (point-min) (point-max)))
|
||
|
(helm-swoop--delete-overlay 'target-buffer)
|
||
|
(deactivate-mark t))
|
||
|
|
||
|
;;;###autoload
|
||
|
(cl-defun helm-swoop (&key $query $source ($multiline current-prefix-arg))
|
||
|
"List the all lines to another buffer, which is able to squeeze by
|
||
|
any words you input. At the same time, the original buffer's cursor
|
||
|
is jumping line to line according to moving up and down the list."
|
||
|
(interactive)
|
||
|
(setq helm-swoop-synchronizing-window (selected-window))
|
||
|
(setq helm-swoop-last-point (cons (point) (buffer-name (current-buffer))))
|
||
|
(setq helm-swoop-last-line-info
|
||
|
(cons (current-buffer) (line-number-at-pos)))
|
||
|
(unless (boundp 'helm-swoop-last-query)
|
||
|
(set (make-local-variable 'helm-swoop-last-query) ""))
|
||
|
(setq helm-swoop-target-buffer (current-buffer))
|
||
|
(helm-swoop--set-prefix (prefix-numeric-value $multiline))
|
||
|
;; Overlay
|
||
|
(setq helm-swoop-line-overlay (make-overlay (point) (point)))
|
||
|
(overlay-put helm-swoop-line-overlay
|
||
|
'face (if (< 1 helm-swoop-last-prefix-number)
|
||
|
'helm-swoop-target-line-block-face
|
||
|
'helm-swoop-target-line-face))
|
||
|
;; Cache
|
||
|
(cond ((not (boundp 'helm-swoop-list-cache))
|
||
|
(set (make-local-variable 'helm-swoop-list-cache) nil))
|
||
|
((buffer-modified-p)
|
||
|
(setq helm-swoop-list-cache nil)))
|
||
|
(unwind-protect
|
||
|
(progn
|
||
|
;; For synchronizing line position
|
||
|
(ad-enable-advice 'helm-next-line 'around 'helm-swoop-next-line)
|
||
|
(ad-activate 'helm-next-line)
|
||
|
(ad-enable-advice 'helm-previous-line 'around 'helm-swoop-previous-line)
|
||
|
(ad-activate 'helm-previous-line)
|
||
|
(ad-enable-advice 'helm-toggle-visible-mark 'around 'helm-swoop-toggle-visible-mark)
|
||
|
(ad-activate 'helm-toggle-visible-mark)
|
||
|
(ad-enable-advice 'helm-move--next-line-fn 'around
|
||
|
'helm-multi-swoop-next-line-cycle)
|
||
|
(ad-activate 'helm-move--next-line-fn)
|
||
|
(ad-enable-advice 'helm-move--previous-line-fn 'around
|
||
|
'helm-multi-swoop-previous-line-cycle)
|
||
|
(ad-activate 'helm-move--previous-line-fn)
|
||
|
(add-hook 'helm-update-hook 'helm-swoop--pattern-match)
|
||
|
(add-hook 'helm-after-update-hook 'helm-swoop--keep-nearest-position t)
|
||
|
(cond ($query
|
||
|
(if (string-match
|
||
|
"\\(\\^\\[0\\-9\\]\\+\\.\\)\\(.*\\)" $query)
|
||
|
$query ;; NEED FIX #1 to appear as a "^"
|
||
|
$query))
|
||
|
(mark-active
|
||
|
(let (($st (buffer-substring-no-properties
|
||
|
(region-beginning) (region-end))))
|
||
|
(if (string-match "\n" $st)
|
||
|
(message "Multi line region is not allowed")
|
||
|
(setq $query (helm-swoop-pre-input-optimize $st)))))
|
||
|
((setq $query (helm-swoop-pre-input-optimize
|
||
|
(funcall helm-swoop-pre-input-function))))
|
||
|
(t (setq $query "")))
|
||
|
;; First behavior
|
||
|
(helm-swoop--recenter)
|
||
|
(move-beginning-of-line 1)
|
||
|
(helm-swoop--target-line-overlay-move)
|
||
|
;; Execute helm
|
||
|
(let ((helm-display-function helm-swoop-split-window-function)
|
||
|
(helm-display-source-at-screen-top nil)
|
||
|
(helm-completion-window-scroll-margin 5))
|
||
|
(helm :sources
|
||
|
(or $source
|
||
|
(helm-c-source-swoop))
|
||
|
:buffer helm-swoop-buffer
|
||
|
:input $query
|
||
|
:prompt helm-swoop-prompt
|
||
|
:preselect
|
||
|
;; Get current line has content or else near one
|
||
|
(if (string-match "^[\t\n\s]*$" (helm-swoop--get-string-at-line))
|
||
|
(save-excursion
|
||
|
(if (re-search-forward "[^\t\n\s]" nil t)
|
||
|
(format "^%s\s" (line-number-at-pos))
|
||
|
(re-search-backward "[^\t\n\s]" nil t)
|
||
|
(format "^%s\s" (line-number-at-pos))))
|
||
|
(format "^%s\s" (line-number-at-pos)))
|
||
|
:candidate-number-limit helm-swoop-candidate-number-limit)))
|
||
|
;; Restore helm's hook and window function etc
|
||
|
(helm-swoop--restore)))
|
||
|
|
||
|
;; Receive word from isearch ---------------
|
||
|
;;;###autoload
|
||
|
(defun helm-swoop-from-isearch ()
|
||
|
"Invoke `helm-swoop' from isearch."
|
||
|
(interactive)
|
||
|
(let (($query (if isearch-regexp
|
||
|
isearch-string
|
||
|
(regexp-quote isearch-string))))
|
||
|
(let (search-nonincremental-instead)
|
||
|
(isearch-exit))
|
||
|
(helm-swoop :$query $query)))
|
||
|
;; When doing isearch, hand the word over to helm-swoop
|
||
|
(define-key isearch-mode-map (kbd "M-i") 'helm-swoop-from-isearch)
|
||
|
|
||
|
;; Receive word from evil search ---------------
|
||
|
(defun helm-swoop-from-evil-search ()
|
||
|
"Invoke `helm-swoop' from evil isearch"
|
||
|
(interactive)
|
||
|
(if (string-match "\\(isearch-\\|evil.*search\\)" (symbol-name real-last-command))
|
||
|
(helm-swoop :$query (if isearch-regexp
|
||
|
isearch-string
|
||
|
(regexp-quote isearch-string)))
|
||
|
(helm-swoop)))
|
||
|
;; When doing evil-search, hand the word over to helm-swoop
|
||
|
;; (define-key evil-motion-state-map (kbd "M-i") 'helm-swoop-from-evil-search)
|
||
|
|
||
|
;; Receive word from evil search ---------------
|
||
|
(defun helm-swoop-yank-thing-at-point ()
|
||
|
"Insert string at which the point helm-swoop started."
|
||
|
(interactive)
|
||
|
(let ($amend $buf)
|
||
|
(with-selected-window helm-swoop-synchronizing-window
|
||
|
(setq $buf (get-buffer (cdr helm-swoop-last-point)))
|
||
|
(when $buf
|
||
|
(with-current-buffer $buf
|
||
|
(save-excursion
|
||
|
(goto-char (car helm-swoop-last-point))
|
||
|
(setq $amend (thing-at-point 'symbol))))))
|
||
|
(when $amend
|
||
|
(with-selected-window (minibuffer-window)
|
||
|
(insert $amend)))))
|
||
|
|
||
|
;; For helm-resume ------------------------
|
||
|
(defadvice helm-resume-select-buffer
|
||
|
(around helm-swoop-if-selected-as-resume activate)
|
||
|
"Resume if *Helm Swoop* buffer selected as a resume
|
||
|
when helm-resume with prefix"
|
||
|
(if (boundp 'helm-swoop-last-query)
|
||
|
ad-do-it
|
||
|
;; If the buffer hasn't called helm-swoop, just hide from options
|
||
|
(let ((helm-buffers (delete helm-swoop-buffer helm-buffers)))
|
||
|
ad-do-it))
|
||
|
(when (and (equal ad-return-value helm-swoop-buffer)
|
||
|
(boundp 'helm-swoop-last-query))
|
||
|
(helm-swoop :$query helm-swoop-last-query
|
||
|
:$multiline helm-swoop-last-prefix-number)
|
||
|
(setq ad-return-value nil)))
|
||
|
|
||
|
(defadvice helm-resume (around helm-swoop-resume activate)
|
||
|
"Resume if the last used helm buffer is helm-swoop-buffer"
|
||
|
(if (equal helm-last-buffer helm-swoop-buffer)
|
||
|
(if (boundp 'helm-swoop-last-query)
|
||
|
(if (not (ad-get-arg 0))
|
||
|
(helm-swoop :$query helm-swoop-last-query
|
||
|
:$multiline helm-swoop-last-prefix-number))
|
||
|
;; Temporary apply second last buffer
|
||
|
(let ((helm-last-buffer (cadr helm-buffers))) ad-do-it))
|
||
|
ad-do-it))
|
||
|
|
||
|
;; For caret beginning-match -----------------------------
|
||
|
(defun helm-swoop--caret-match-delete ($o $aft $beg $end &optional $len)
|
||
|
(if $aft
|
||
|
(- $end $beg $len) ;; Unused argument? To avoid byte compile error
|
||
|
(delete-region (overlay-start $o) (1- (overlay-end $o)))))
|
||
|
|
||
|
(defun helm-swoop-caret-match (&optional _$resume)
|
||
|
(interactive)
|
||
|
(let* (($prompt helm-swoop-prompt) ;; Accept change of the variable
|
||
|
($line-number-regexp "^[0-9]+.")
|
||
|
($prompt-regexp
|
||
|
(funcall `(lambda ()
|
||
|
(rx bol ,$prompt))))
|
||
|
($prompt-regexp-with-line-number
|
||
|
(funcall `(lambda ()
|
||
|
(rx bol ,$prompt (group ,$line-number-regexp)))))
|
||
|
($disguise-caret
|
||
|
(lambda ()
|
||
|
(save-excursion
|
||
|
(re-search-backward $prompt-regexp-with-line-number nil t)
|
||
|
(let (($o (make-overlay (match-beginning 1) (match-end 1))))
|
||
|
(overlay-put $o 'face 'helm-swoop-target-word-face)
|
||
|
(overlay-put $o 'modification-hooks '(helm-swoop--caret-match-delete))
|
||
|
(overlay-put $o 'display "^")
|
||
|
(overlay-put $o 'evaporate t))))))
|
||
|
(if (and (minibufferp)
|
||
|
(string-match $prompt-regexp
|
||
|
(buffer-substring-no-properties
|
||
|
(point-min) (point-max)))
|
||
|
(eq (point) (+ 1 (length helm-swoop-prompt))))
|
||
|
(progn
|
||
|
(insert $line-number-regexp)
|
||
|
(funcall $disguise-caret))
|
||
|
(insert "^"))))
|
||
|
|
||
|
;;; @ helm-swoop-edit -----------------------------------------
|
||
|
|
||
|
(defvar helm-swoop-edit-target-buffer)
|
||
|
(defvar helm-swoop-edit-buffer "*Helm Swoop Edit*")
|
||
|
(defvar helm-swoop-edit-map
|
||
|
(let (($map (make-sparse-keymap)))
|
||
|
(define-key $map (kbd "C-x C-s") 'helm-swoop--edit-complete)
|
||
|
(define-key $map (kbd "C-c C-g") 'helm-swoop--edit-cancel)
|
||
|
(define-key $map (kbd "C-c C-q C-k") 'helm-swoop--edit-delete-all-lines)
|
||
|
$map))
|
||
|
|
||
|
(defun helm-swoop--clear-edit-buffer ($prop)
|
||
|
(let ((inhibit-read-only t))
|
||
|
(mapc (lambda ($ov)
|
||
|
(when (overlay-get $ov $prop)
|
||
|
(delete-overlay $ov)))
|
||
|
(overlays-in (point-min) (point-max)))
|
||
|
(set-text-properties (point-min) (point-max) nil)
|
||
|
(goto-char (point-min))
|
||
|
(erase-buffer)))
|
||
|
|
||
|
(defun helm-swoop--collect-edited-lines ()
|
||
|
"Create a list of edited lines with each its own line number"
|
||
|
(interactive)
|
||
|
(let ($list)
|
||
|
(goto-char (point-min))
|
||
|
(while (re-search-forward "^\\([0-9]+\\)\s" nil t)
|
||
|
(setq $list
|
||
|
(cons (cons (string-to-number (match-string 1))
|
||
|
(buffer-substring-no-properties
|
||
|
(point)
|
||
|
(save-excursion
|
||
|
(if (re-search-forward
|
||
|
"^\\([0-9]+\\)\s\\|^\\(\\-+\\)" nil t)
|
||
|
(1- (match-beginning 0))
|
||
|
(goto-char (point-max))
|
||
|
(re-search-backward "\n" nil t)))))
|
||
|
$list)))
|
||
|
$list))
|
||
|
|
||
|
(defun helm-swoop--edit ($candidate)
|
||
|
"This function will only be called from `helm-swoop-edit'"
|
||
|
(interactive)
|
||
|
(setq helm-swoop-edit-target-buffer helm-swoop-target-buffer)
|
||
|
(delete-overlay helm-swoop-line-overlay)
|
||
|
(helm-swoop--delete-overlay 'target-buffer)
|
||
|
(with-current-buffer (get-buffer-create helm-swoop-edit-buffer)
|
||
|
|
||
|
(helm-swoop--clear-edit-buffer 'helm-swoop-edit)
|
||
|
(let (($bufstr ""))
|
||
|
;; Get target line number to edit
|
||
|
(with-current-buffer helm-swoop-buffer
|
||
|
;; Use selected line by [C-SPC] or [M-SPC]
|
||
|
(mapc (lambda ($ov)
|
||
|
(when (eq 'helm-visible-mark (overlay-get $ov 'face))
|
||
|
(setq $bufstr (concat (buffer-substring-no-properties
|
||
|
(overlay-start $ov) (overlay-end $ov))
|
||
|
$bufstr))))
|
||
|
(overlays-in (point-min) (point-max)))
|
||
|
(if (equal "" $bufstr)
|
||
|
;; Not found selected line
|
||
|
(setq $bufstr (buffer-substring-no-properties
|
||
|
(point-min) (point-max)))
|
||
|
;; Attach title
|
||
|
(setq $bufstr (concat "Helm Swoop\n" $bufstr))))
|
||
|
|
||
|
;; Set for edit buffer
|
||
|
(insert $bufstr)
|
||
|
(add-text-properties (point-min) (point-max)
|
||
|
'(read-only t rear-nonsticky t front-sticky t))
|
||
|
|
||
|
;; Set for editable context
|
||
|
(let ((inhibit-read-only t))
|
||
|
;; Title and explanation
|
||
|
(goto-char (point-min))
|
||
|
(let (($o (make-overlay (point) (point-at-eol))))
|
||
|
(overlay-put $o 'helm-swoop-edit t)
|
||
|
(overlay-put $o 'face 'font-lock-function-name-face)
|
||
|
(overlay-put $o 'after-string
|
||
|
(propertize
|
||
|
(format " [%s] Complete, [%s] Cancel, [%s] Delete All"
|
||
|
(helm-swoop--key-of-function 'helm-swoop--edit-complete helm-swoop-edit-map)
|
||
|
(helm-swoop--key-of-function 'helm-swoop--edit-cancel helm-swoop-edit-map)
|
||
|
(helm-swoop--key-of-function 'helm-swoop--edit-delete-all-lines helm-swoop-edit-map))
|
||
|
'face 'helm-bookmark-addressbook)))
|
||
|
;; Line number and editable area
|
||
|
(while (re-search-forward "^\\([0-9]+\s\\)\\(.*\\)$" nil t)
|
||
|
(let* (($bol1 (match-beginning 1))
|
||
|
($eol1 (match-end 1))
|
||
|
($bol2 (match-beginning 2))
|
||
|
($eol2 (match-end 2)))
|
||
|
;; Line number
|
||
|
(add-text-properties $bol1 $eol1
|
||
|
'(face font-lock-function-name-face
|
||
|
intangible t))
|
||
|
;; Editable area
|
||
|
(remove-text-properties $bol2 $eol2 '(read-only t))
|
||
|
;; For line tail
|
||
|
(set-text-properties $eol2 (or (1+ $eol2) (point-max))
|
||
|
'(read-only t rear-nonsticky t))))
|
||
|
(helm-swoop--target-word-overlay 'edit-buffer 0))))
|
||
|
|
||
|
(other-window 1)
|
||
|
(switch-to-buffer helm-swoop-edit-buffer)
|
||
|
(goto-char (point-min))
|
||
|
(if (string-match "^[0-9]+" $candidate)
|
||
|
(re-search-forward
|
||
|
(concat "^" (match-string 0 $candidate)) nil t))
|
||
|
(use-local-map helm-swoop-edit-map))
|
||
|
|
||
|
(defun helm-swoop--edit-complete ()
|
||
|
"Apply changes and kill temporary edit buffer"
|
||
|
(interactive)
|
||
|
(let (($list (helm-swoop--collect-edited-lines)))
|
||
|
(with-current-buffer helm-swoop-edit-target-buffer
|
||
|
;; Replace from the end of buffer
|
||
|
(save-excursion
|
||
|
(mapc (lambda ($cell)
|
||
|
(let (($k (car $cell))
|
||
|
($v (cdr $cell)))
|
||
|
(goto-char (point-min))
|
||
|
(delete-region (point-at-bol $k) (point-at-eol $k))
|
||
|
(goto-char (point-at-bol $k))
|
||
|
(insert $v)))
|
||
|
$list)))
|
||
|
(select-window helm-swoop-synchronizing-window)
|
||
|
(kill-buffer (get-buffer helm-swoop-edit-buffer)))
|
||
|
(message "Successfully helm-swoop-edit applied to original buffer"))
|
||
|
|
||
|
(defun helm-swoop--edit-delete-all-lines ()
|
||
|
"Apply changes and kill temporary edit buffer"
|
||
|
(interactive)
|
||
|
(let (($list (helm-swoop--collect-edited-lines)))
|
||
|
(with-current-buffer helm-swoop-edit-target-buffer
|
||
|
;; Replace from the end of buffer
|
||
|
(save-excursion
|
||
|
(mapc (lambda ($cell)
|
||
|
(let (($k (car $cell)))
|
||
|
(goto-char (point-min))
|
||
|
(delete-region (point-at-bol $k)
|
||
|
(if (eq (point-at-eol $k) (point-max))
|
||
|
(point-at-eol $k)
|
||
|
(1+ (point-at-eol $k))))))
|
||
|
$list)))
|
||
|
(select-window helm-swoop-synchronizing-window)
|
||
|
(kill-buffer (get-buffer helm-swoop-edit-buffer)))
|
||
|
(message "Successfully helm-swoop-edit applied to original buffer"))
|
||
|
|
||
|
(defun helm-swoop--edit-cancel ()
|
||
|
"Cancel edit and kill temporary buffer"
|
||
|
(interactive)
|
||
|
(select-window helm-swoop-synchronizing-window)
|
||
|
(kill-buffer (get-buffer helm-swoop-edit-buffer))
|
||
|
(message "helm-swoop-edit canceled"))
|
||
|
|
||
|
(defun helm-swoop-edit ()
|
||
|
(interactive)
|
||
|
(helm-exit-and-execute-action 'helm-swoop--edit))
|
||
|
|
||
|
;;; @ helm-multi-swoop ----------------------------------------
|
||
|
(defvar helm-multi-swoop-buffer-list "*helm-multi-swoop buffers list*"
|
||
|
"Buffer name")
|
||
|
(defvar helm-multi-swoop-ignore-buffers-match "^\\*"
|
||
|
"Regexp to eliminate buffers you don't want to see")
|
||
|
(defvar helm-multi-swoop-candidate-number-limit 250)
|
||
|
(defvar helm-multi-swoop-last-selected-buffers nil)
|
||
|
(defvar helm-multi-swoop-last-query nil)
|
||
|
(defvar helm-multi-swoop-query nil)
|
||
|
(defvar helm-multi-swoop-buffer "*Helm Multi Swoop*")
|
||
|
(defvar helm-multi-swoop-all-from-helm-swoop-last-point nil
|
||
|
"For the last position, when helm-multi-swoop-all-from-helm-swoop canceled")
|
||
|
(defvar helm-multi-swoop-move-line-action-last-buffer nil)
|
||
|
|
||
|
(defvar helm-multi-swoop-buffers-map
|
||
|
(let (($map (make-sparse-keymap)))
|
||
|
(set-keymap-parent $map helm-map)
|
||
|
(define-key $map (kbd "RET")
|
||
|
(lambda () (interactive)
|
||
|
(helm-exit-and-execute-action 'helm-multi-swoop--exec)))
|
||
|
(delq nil $map)))
|
||
|
|
||
|
(defvar helm-multi-swoop-projectile-buffers-filter
|
||
|
#'projectile-buffers-with-file-or-process)
|
||
|
;; action -----------------------------------------------------
|
||
|
|
||
|
(defadvice helm-next-line (around helm-multi-swoop-next-line disable)
|
||
|
(let ((helm-move-to-line-cycle-in-source nil))
|
||
|
ad-do-it
|
||
|
(when (called-interactively-p 'any)
|
||
|
(helm-multi-swoop--move-line-action))))
|
||
|
|
||
|
(defadvice helm-previous-line (around helm-multi-swoop-previous-line disable)
|
||
|
(let ((helm-move-to-line-cycle-in-source nil))
|
||
|
ad-do-it
|
||
|
(when (called-interactively-p 'any)
|
||
|
(helm-multi-swoop--move-line-action))))
|
||
|
|
||
|
(defadvice helm-toggle-visible-mark (around helm-multi-swoop-toggle-visible-mark disable)
|
||
|
(let ((helm-move-to-line-cycle-in-source nil))
|
||
|
ad-do-it
|
||
|
(when (called-interactively-p 'any)
|
||
|
(helm-multi-swoop--move-line-action))))
|
||
|
|
||
|
(defadvice helm-move--next-line-fn (around helm-multi-swoop-next-line-cycle disable)
|
||
|
(if (not (helm-pos-multiline-p))
|
||
|
(if (eq (point-max) (save-excursion (forward-line 1) (point)))
|
||
|
(when helm-swoop-move-to-line-cycle
|
||
|
(helm-beginning-of-buffer)
|
||
|
(helm-swoop--recenter))
|
||
|
(forward-line 1))
|
||
|
(let ((line-num (line-number-at-pos)))
|
||
|
(helm-move--next-multi-line-fn)
|
||
|
(when (and helm-swoop-move-to-line-cycle
|
||
|
(eq line-num (line-number-at-pos)))
|
||
|
(helm-beginning-of-buffer)))))
|
||
|
|
||
|
(defadvice helm-move--previous-line-fn (around helm-multi-swoop-previous-line-cycle disable)
|
||
|
(if (not (helm-pos-multiline-p))
|
||
|
(forward-line -1)
|
||
|
(helm-move--previous-multi-line-fn))
|
||
|
(when (and (helm-pos-header-line-p)
|
||
|
(eq (point) (save-excursion (forward-line -1) (point))))
|
||
|
(when helm-swoop-move-to-line-cycle
|
||
|
(helm-end-of-buffer))
|
||
|
(when (helm-pos-multiline-p)
|
||
|
(helm-move--previous-multi-line-fn))))
|
||
|
|
||
|
(defun helm-multi-swoop--move-line-action ()
|
||
|
(with-helm-window
|
||
|
(let* (($key (buffer-substring (point-at-bol) (point-at-eol)))
|
||
|
($num (when (string-match "^[0-9]+" $key)
|
||
|
(string-to-number (match-string 0 $key))))
|
||
|
($source (helm-get-current-source))
|
||
|
($buf (let (($name (assoc-default 'name $source)))
|
||
|
(when $name (get-buffer $name)))))
|
||
|
(when $buf
|
||
|
;; Synchronizing line position
|
||
|
(with-selected-window helm-swoop-synchronizing-window
|
||
|
(with-current-buffer $buf
|
||
|
(when (not (eq $buf helm-multi-swoop-move-line-action-last-buffer))
|
||
|
(set-window-buffer nil $buf)
|
||
|
(helm-swoop--pattern-match))
|
||
|
(helm-swoop--goto-line $num)
|
||
|
(helm-swoop--target-line-overlay-move $buf)
|
||
|
(helm-swoop--recenter))
|
||
|
(setq helm-multi-swoop-move-line-action-last-buffer $buf))
|
||
|
(setq helm-swoop-last-line-info (cons $buf $num))))))
|
||
|
|
||
|
(defun helm-multi-swoop--get-marked-buffers ()
|
||
|
(let ($list
|
||
|
($buf (get-buffer helm-multi-swoop-buffer-list)))
|
||
|
(when $buf
|
||
|
(with-current-buffer (get-buffer helm-multi-swoop-buffer-list)
|
||
|
(mapc (lambda ($ov)
|
||
|
(when (eq 'helm-visible-mark (overlay-get $ov 'face))
|
||
|
(setq $list (cons
|
||
|
(let (($word (buffer-substring-no-properties
|
||
|
(overlay-start $ov) (overlay-end $ov))))
|
||
|
(mapc (lambda ($r)
|
||
|
(setq $word (replace-regexp-in-string
|
||
|
(car $r) (cdr $r) $word)))
|
||
|
(list '("\\`[ \t\n\r]+" . "")
|
||
|
'("[ \t\n\r]+\\'" . "")))
|
||
|
$word)
|
||
|
$list))))
|
||
|
(overlays-in (point-min) (point-max))))
|
||
|
(delete "" $list))))
|
||
|
|
||
|
;; core --------------------------------------------------------
|
||
|
|
||
|
(cl-defun helm-multi-swoop--exec (ignored &key $query $buflist $func $action)
|
||
|
(interactive)
|
||
|
(setq helm-swoop-synchronizing-window (selected-window))
|
||
|
(setq helm-swoop-last-point
|
||
|
(or helm-multi-swoop-all-from-helm-swoop-last-point
|
||
|
(cons (point) (buffer-name (current-buffer)))))
|
||
|
(setq helm-swoop-last-line-info
|
||
|
(cons (current-buffer) (line-number-at-pos)))
|
||
|
(unless (get-buffer helm-multi-swoop-buffer-list)
|
||
|
(get-buffer-create helm-multi-swoop-buffer-list))
|
||
|
(helm-swoop--set-prefix (prefix-numeric-value current-prefix-arg))
|
||
|
(let (($buffs (or $buflist
|
||
|
(helm-multi-swoop--get-marked-buffers)
|
||
|
`(,(buffer-name helm-swoop-target-buffer))
|
||
|
(error "No buffer selected")))
|
||
|
$contents
|
||
|
$preserve-position
|
||
|
($prefix-arg (prefix-numeric-value
|
||
|
(or current-prefix-arg helm-swoop-last-prefix-number 1))))
|
||
|
(helm-swoop--set-prefix $prefix-arg)
|
||
|
(setq helm-multi-swoop-last-selected-buffers $buffs)
|
||
|
;; Create buffer sources
|
||
|
(mapc (lambda ($buf)
|
||
|
(when (get-buffer $buf)
|
||
|
(with-current-buffer (get-buffer $buf)
|
||
|
(let* (($func
|
||
|
(or $func
|
||
|
(lambda ()
|
||
|
(helm-swoop--split-lines-by
|
||
|
(helm-swoop--get-content $buf t)
|
||
|
"\n" $prefix-arg))))
|
||
|
($action
|
||
|
(or $action
|
||
|
`(("Go to Line"
|
||
|
. (lambda ($line)
|
||
|
(switch-to-buffer ,$buf)
|
||
|
(helm-swoop--goto-line
|
||
|
(when (string-match "^[0-9]+" $line)
|
||
|
(string-to-number
|
||
|
(match-string 0 $line))))
|
||
|
(when (re-search-forward
|
||
|
(mapconcat 'identity
|
||
|
(split-string
|
||
|
helm-pattern " ") "\\|")
|
||
|
nil t)
|
||
|
(helm-swoop-flash-word (match-beginning 0) (match-end 0))
|
||
|
(goto-char (match-beginning 0)))
|
||
|
(helm-swoop--recenter)))))))
|
||
|
(setq $preserve-position
|
||
|
(cons (cons $buf (point)) $preserve-position))
|
||
|
(setq
|
||
|
$contents
|
||
|
(cons
|
||
|
(helm-c-source-multi-swoop $buf $func $action $prefix-arg)
|
||
|
$contents))))))
|
||
|
$buffs)
|
||
|
(unwind-protect
|
||
|
(progn
|
||
|
(ad-enable-advice 'helm-next-line 'around
|
||
|
'helm-multi-swoop-next-line)
|
||
|
(ad-activate 'helm-next-line)
|
||
|
(ad-enable-advice 'helm-previous-line 'around
|
||
|
'helm-multi-swoop-previous-line)
|
||
|
(ad-activate 'helm-previous-line)
|
||
|
(ad-enable-advice 'helm-toggle-visible-mark 'around
|
||
|
'helm-multi-swoop-toggle-visible-mark)
|
||
|
(ad-activate 'helm-toggle-visible-mark)
|
||
|
(ad-enable-advice 'helm-move--next-line-fn 'around
|
||
|
'helm-multi-swoop-next-line-cycle)
|
||
|
(ad-activate 'helm-move--next-line-fn)
|
||
|
(ad-enable-advice 'helm-move--previous-line-fn 'around
|
||
|
'helm-multi-swoop-previous-line-cycle)
|
||
|
(ad-activate 'helm-move--previous-line-fn)
|
||
|
(add-hook 'helm-update-hook 'helm-swoop--pattern-match)
|
||
|
(add-hook 'helm-after-update-hook 'helm-swoop--keep-nearest-position t)
|
||
|
(setq helm-swoop-line-overlay
|
||
|
(make-overlay (point) (point)))
|
||
|
(overlay-put helm-swoop-line-overlay
|
||
|
'face 'helm-swoop-target-line-face)
|
||
|
(helm-swoop--target-line-overlay-move)
|
||
|
;; Execute helm
|
||
|
(let ((helm-display-function helm-swoop-split-window-function)
|
||
|
(helm-display-source-at-screen-top nil)
|
||
|
(helm-completion-window-scroll-margin 5))
|
||
|
(helm :sources $contents
|
||
|
:buffer helm-multi-swoop-buffer
|
||
|
:input (or $query helm-multi-swoop-query "")
|
||
|
:prompt helm-swoop-prompt
|
||
|
:candidate-number-limit
|
||
|
helm-multi-swoop-candidate-number-limit
|
||
|
:preselect
|
||
|
(format "%s %s" (line-number-at-pos)
|
||
|
(helm-swoop--get-string-at-line)))))
|
||
|
;; Restore
|
||
|
(progn
|
||
|
(when (= 1 helm-exit-status)
|
||
|
(helm-swoop-back-to-last-point t)
|
||
|
(helm-swoop--restore-unveiled-overlay))
|
||
|
(setq helm-swoop-invisible-targets nil)
|
||
|
(ad-disable-advice 'helm-next-line 'around
|
||
|
'helm-multi-swoop-next-line)
|
||
|
(ad-activate 'helm-next-line)
|
||
|
(ad-disable-advice 'helm-previous-line 'around
|
||
|
'helm-multi-swoop-previous-line)
|
||
|
(ad-activate 'helm-previous-line)
|
||
|
(ad-disable-advice 'helm-toggle-visible-mark 'around
|
||
|
'helm-multi-swoop-toggle-visible-mark)
|
||
|
(ad-activate 'helm-toggle-visible-mark)
|
||
|
(ad-disable-advice 'helm-move--next-line-fn 'around
|
||
|
'helm-multi-swoop-next-line-cycle)
|
||
|
(ad-activate 'helm-move--next-line-fn)
|
||
|
(ad-disable-advice 'helm-move--previous-line-fn 'around
|
||
|
'helm-multi-swoop-previous-line-cycle)
|
||
|
(ad-activate 'helm-move--previous-line-fn)
|
||
|
(remove-hook 'helm-update-hook 'helm-swoop--pattern-match)
|
||
|
(remove-hook 'helm-after-update-hook 'helm-swoop--keep-nearest-position)
|
||
|
(setq helm-multi-swoop-last-query helm-swoop-pattern)
|
||
|
(helm-swoop--restore-unveiled-overlay)
|
||
|
(setq helm-multi-swoop-query nil)
|
||
|
(setq helm-multi-swoop-all-from-helm-swoop-last-point nil)
|
||
|
(mapc (lambda ($buf)
|
||
|
(let (($current-buffer (buffer-name (current-buffer))))
|
||
|
(with-current-buffer (car $buf)
|
||
|
;; Delete overlay
|
||
|
(delete-overlay helm-swoop-line-overlay)
|
||
|
(helm-swoop--delete-overlay 'target-buffer)
|
||
|
;; Restore each buffer's position
|
||
|
(unless (equal (car $buf) $current-buffer)
|
||
|
(goto-char (cdr $buf))))))
|
||
|
$preserve-position)))))
|
||
|
|
||
|
(defun helm-multi-swoop--get-buffer-list ()
|
||
|
(let ($buflist1 $buflist2)
|
||
|
;; eliminate buffers start with whitespace and dired buffers
|
||
|
(mapc (lambda ($buf)
|
||
|
(setq $buf (buffer-name $buf))
|
||
|
(unless (string-match "^\\s-" $buf)
|
||
|
(unless (eq 'dired-mode (with-current-buffer $buf major-mode))
|
||
|
(setq $buflist1 (cons $buf $buflist1)))))
|
||
|
(buffer-list))
|
||
|
;; eliminate buffers match pattern
|
||
|
(mapc (lambda ($buf)
|
||
|
(unless (string-match
|
||
|
helm-multi-swoop-ignore-buffers-match
|
||
|
$buf)
|
||
|
(setq $buflist2 (cons $buf $buflist2))))
|
||
|
$buflist1)
|
||
|
$buflist2))
|
||
|
|
||
|
(defun helm-c-source-helm-multi-swoop-buffers ()
|
||
|
"Show buffer list to select"
|
||
|
`((name . "helm-multi-swoop select buffers")
|
||
|
(candidates . helm-multi-swoop--get-buffer-list)
|
||
|
(header-line . "[C-SPC]/[M-SPC] select, [RET] next step")
|
||
|
(keymap . ,helm-multi-swoop-buffers-map)
|
||
|
(match . ,(helm-swoop-match-functions))
|
||
|
(search . ,(helm-swoop-search-functions))))
|
||
|
|
||
|
(defun helm-multi-swoop--get-query ($query)
|
||
|
(cond ($query
|
||
|
(setq helm-multi-swoop-query $query))
|
||
|
(mark-active
|
||
|
(let (($st (buffer-substring-no-properties
|
||
|
(region-beginning) (region-end))))
|
||
|
(if (string-match "\n" $st)
|
||
|
(message "Multi line region is not allowed")
|
||
|
(setq helm-multi-swoop-query
|
||
|
(helm-swoop-pre-input-optimize $st)))))
|
||
|
((setq helm-multi-swoop-query
|
||
|
(helm-swoop-pre-input-optimize
|
||
|
(funcall helm-swoop-pre-input-function))))
|
||
|
(t (setq helm-multi-swoop-query ""))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-multi-swoop (&optional $query $buflist)
|
||
|
"\
|
||
|
Usage:
|
||
|
M-x helm-multi-swoop
|
||
|
1. Select any buffers by [C-SPC] or [M-SPC]
|
||
|
2. Press [RET] to start helm-multi-swoop
|
||
|
|
||
|
C-u M-x helm-multi-swoop
|
||
|
If you have done helm-multi-swoop before, you can skip select buffers step.
|
||
|
Last selected buffers will be applied to helm-multi-swoop.
|
||
|
"
|
||
|
(interactive)
|
||
|
(setq helm-multi-swoop-query (helm-multi-swoop--get-query $query))
|
||
|
(if (equal current-prefix-arg '(4))
|
||
|
(helm-multi-swoop--exec nil
|
||
|
:$query helm-multi-swoop-query
|
||
|
:$buflist $buflist)
|
||
|
(if $buflist
|
||
|
(helm-multi-swoop--exec nil
|
||
|
:$query $query
|
||
|
:$buflist $buflist)
|
||
|
(helm :sources (helm-c-source-helm-multi-swoop-buffers)
|
||
|
:buffer helm-multi-swoop-buffer-list
|
||
|
:prompt "Mark any buffers by [C-SPC] or [M-SPC]: "))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-multi-swoop-all (&optional $query)
|
||
|
"Apply all buffers to helm-multi-swoop"
|
||
|
(interactive)
|
||
|
(setq helm-multi-swoop-query (helm-multi-swoop--get-query $query))
|
||
|
(helm-multi-swoop--exec nil
|
||
|
:$query helm-multi-swoop-query
|
||
|
:$buflist (helm-multi-swoop--get-buffer-list)))
|
||
|
|
||
|
(defun get-buffers-matching-mode ($mode)
|
||
|
"Returns a list of buffers where their major-mode is equal to MODE"
|
||
|
(let ($buffer-mode-matches)
|
||
|
(mapc (lambda ($buf)
|
||
|
(when (get-buffer $buf)
|
||
|
(with-current-buffer (get-buffer $buf)
|
||
|
(if (eq $mode major-mode)
|
||
|
(add-to-list '$buffer-mode-matches (buffer-name $buf))))))
|
||
|
(buffer-list))
|
||
|
$buffer-mode-matches))
|
||
|
|
||
|
(defun helm-multi-swoop-by-mode ($mode &optional $query)
|
||
|
"Apply all buffers whose mode is MODE to helm-multi-swoop"
|
||
|
(setq helm-multi-swoop-query (helm-multi-swoop--get-query $query))
|
||
|
(if (get-buffers-matching-mode $mode)
|
||
|
(helm-multi-swoop--exec nil
|
||
|
:$query helm-multi-swoop-query
|
||
|
:$buflist (get-buffers-matching-mode $mode))
|
||
|
(message "there are no buffers in that mode right now")))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-multi-swoop-org (&optional $query)
|
||
|
"Applies all org-mode buffers to helm-multi-swoop"
|
||
|
(interactive)
|
||
|
(helm-multi-swoop-by-mode 'org-mode $query))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-multi-swoop-current-mode (&optional $query)
|
||
|
"Applies all buffers of the same mode as the current buffer to helm-multi-swoop"
|
||
|
(interactive)
|
||
|
(helm-multi-swoop-by-mode major-mode $query))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-multi-swoop-projectile (&optional $query)
|
||
|
"Apply all opened buffers of the current project to helm-multi-swoop"
|
||
|
(interactive)
|
||
|
(setq helm-multi-swoop-query (helm-multi-swoop--get-query $query))
|
||
|
(if (require 'projectile nil 'noerror)
|
||
|
;; set filter function that is used in projectile-project-buffers
|
||
|
(let ((projectile-buffers-filter-function
|
||
|
helm-multi-swoop-projectile-buffers-filter))
|
||
|
(helm-multi-swoop--exec nil
|
||
|
:$query helm-multi-swoop-query
|
||
|
:$buflist (mapcar #'buffer-name
|
||
|
(projectile-project-buffers))))
|
||
|
(error "Package 'projectile' is not available")))
|
||
|
|
||
|
|
||
|
(defun helm-swoop--wrap-function-with-pre-input-function ($target-func $pre-input-func)
|
||
|
(let (($restore helm-swoop-pre-input-function))
|
||
|
(unwind-protect
|
||
|
(progn
|
||
|
(setq helm-swoop-pre-input-function $pre-input-func)
|
||
|
(funcall $target-func))
|
||
|
(setq helm-swoop-pre-input-function $restore))))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-swoop-without-pre-input ()
|
||
|
"Start helm-swoop without pre input query."
|
||
|
(interactive)
|
||
|
(helm-swoop--wrap-function-with-pre-input-function
|
||
|
'helm-swoop (lambda () nil)))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-swoop-symble-pre-input ()
|
||
|
"Start helm-swoop without pre input query."
|
||
|
(interactive)
|
||
|
(helm-swoop--wrap-function-with-pre-input-function
|
||
|
'helm-swoop (lambda () (format "\\_<%s\\_> " (thing-at-point 'symbol)))))
|
||
|
|
||
|
;; option -------------------------------------------------------
|
||
|
|
||
|
(defun helm-multi-swoop-all-from-isearch ()
|
||
|
"Invoke `helm-multi-swoop-all' from isearch."
|
||
|
(interactive)
|
||
|
(let (($query (if isearch-regexp
|
||
|
isearch-string
|
||
|
(regexp-quote isearch-string))))
|
||
|
(let (search-nonincremental-instead)
|
||
|
(isearch-exit))
|
||
|
(helm-multi-swoop-all $query)))
|
||
|
;; When doing isearch, hand the word over to helm-swoop
|
||
|
;; (define-key isearch-mode-map (kbd "C-x M-i") 'helm-multi-swoop-all-from-isearch)
|
||
|
|
||
|
(defun helm-multi-swoop-all-from-helm-swoop ()
|
||
|
"Invoke `helm-multi-swoop-all' from helm-swoop."
|
||
|
(interactive)
|
||
|
(helm-swoop--restore)
|
||
|
(delete-overlay helm-swoop-line-overlay)
|
||
|
(setq helm-multi-swoop-all-from-helm-swoop-last-point helm-swoop-last-point)
|
||
|
(let (($query helm-pattern))
|
||
|
(run-with-timer 0 nil (lambda () (helm-multi-swoop-all $query))))
|
||
|
(helm-exit-minibuffer))
|
||
|
|
||
|
(defun helm-multi-swoop-current-mode-from-helm-swoop ()
|
||
|
"Invoke `helm-multi-swoop-all' from helm-swoop."
|
||
|
(interactive)
|
||
|
(helm-swoop--restore)
|
||
|
(delete-overlay helm-swoop-line-overlay)
|
||
|
(setq helm-multi-swoop-all-from-helm-swoop-last-point helm-swoop-last-point)
|
||
|
(let (($query helm-pattern))
|
||
|
(run-with-timer 0 nil (lambda () (helm-multi-swoop-current-mode $query))))
|
||
|
(helm-exit-minibuffer))
|
||
|
;; (define-key helm-swoop-map (kbd "M-m") 'helm-multi-swoop-current-mode-from-helm-swoop)
|
||
|
|
||
|
(defadvice helm-resume (around helm-multi-swoop-resume activate)
|
||
|
"Resume if the last used helm buffer is *Helm Swoop*"
|
||
|
(if (equal helm-last-buffer helm-multi-swoop-buffer)
|
||
|
|
||
|
(if (boundp 'helm-multi-swoop-last-query)
|
||
|
(if (not (ad-get-arg 0))
|
||
|
(helm-multi-swoop helm-multi-swoop-last-query
|
||
|
helm-multi-swoop-last-selected-buffers))
|
||
|
;; Temporary apply second last buffer
|
||
|
(let ((helm-last-buffer (cadr helm-buffers))) ad-do-it))
|
||
|
ad-do-it))
|
||
|
|
||
|
;;; @ helm-multi-swoop-edit -----------------------------------
|
||
|
(defvar helm-multi-swoop-edit-save t
|
||
|
"Save each buffer you edit when editing is complete")
|
||
|
(defvar helm-multi-swoop-edit-buffer "*Helm Multi Swoop Edit*")
|
||
|
|
||
|
(defvar helm-multi-swoop-edit-map
|
||
|
(let (($map (make-sparse-keymap)))
|
||
|
(define-key $map (kbd "C-x C-s") 'helm-multi-swoop--edit-complete)
|
||
|
(define-key $map (kbd "C-c C-g") 'helm-multi-swoop--edit-cancel)
|
||
|
(define-key $map (kbd "C-c C-q C-k") 'helm-multi-swoop--edit-delete-all-lines)
|
||
|
$map))
|
||
|
|
||
|
(defun helm-multi-swoop--edit ($candidate)
|
||
|
"This function will only be called from `helm-swoop-edit'"
|
||
|
(interactive)
|
||
|
(delete-overlay helm-swoop-line-overlay)
|
||
|
(helm-swoop--delete-overlay 'target-buffer)
|
||
|
(with-current-buffer (get-buffer-create helm-multi-swoop-edit-buffer)
|
||
|
(helm-swoop--clear-edit-buffer 'helm-multi-swoop-edit)
|
||
|
(let (($bufstr "")
|
||
|
($mark nil)
|
||
|
($buf (get-buffer helm-multi-swoop-buffer)))
|
||
|
;; Get target line number to edit
|
||
|
(when $buf
|
||
|
(with-current-buffer $buf
|
||
|
;; Set overlay to helm-source-header for editing marked lines
|
||
|
(save-excursion
|
||
|
(goto-char (point-min))
|
||
|
(let (($beg (point)) $end)
|
||
|
(overlay-recenter (point-max))
|
||
|
(while (setq $beg (text-property-any $beg (point-max)
|
||
|
'face 'helm-source-header))
|
||
|
(setq $end (next-single-property-change $beg 'face))
|
||
|
(overlay-put (make-overlay $beg $end) 'source-header t)
|
||
|
(setq $beg $end)
|
||
|
(goto-char $end))))
|
||
|
;; Use selected line by [C-SPC] or [M-SPC]
|
||
|
(mapc (lambda ($ov)
|
||
|
(when (overlay-get $ov 'source-header)
|
||
|
(setq $bufstr (concat (buffer-substring
|
||
|
(overlay-start $ov) (overlay-end $ov))
|
||
|
$bufstr)))
|
||
|
(when (eq 'helm-visible-mark (overlay-get $ov 'face))
|
||
|
(let (($str (buffer-substring (overlay-start $ov) (overlay-end $ov))))
|
||
|
(unless (equal "" $str) (setq $mark t))
|
||
|
(setq $bufstr (concat (buffer-substring
|
||
|
(overlay-start $ov) (overlay-end $ov))
|
||
|
$bufstr)))))
|
||
|
(overlays-in (point-min) (point-max)))
|
||
|
(if $mark
|
||
|
(progn (setq $bufstr (concat "Helm Multi Swoop\n" $bufstr))
|
||
|
(setq $mark nil))
|
||
|
(setq $bufstr (concat "Helm Multi Swoop\n"
|
||
|
(buffer-substring
|
||
|
(point-min) (point-max)))))))
|
||
|
|
||
|
;; Set for edit buffer
|
||
|
(insert $bufstr)
|
||
|
(add-text-properties (point-min) (point-max)
|
||
|
'(read-only t rear-nonsticky t front-sticky t))
|
||
|
|
||
|
;; Set for editable context
|
||
|
(let ((inhibit-read-only t))
|
||
|
;; Title and explanation
|
||
|
(goto-char (point-min))
|
||
|
(let (($o (make-overlay (point) (point-at-eol))))
|
||
|
(overlay-put $o 'helm-multi-swoop-edit t)
|
||
|
(overlay-put $o 'face 'font-lock-function-name-face)
|
||
|
(overlay-put $o 'after-string
|
||
|
(propertize
|
||
|
(format " [%s] Complete, [%s] Cancel, [%s] Delete All"
|
||
|
(helm-swoop--key-of-function 'helm-swoop--edit-complete helm-swoop-edit-map)
|
||
|
(helm-swoop--key-of-function 'helm-swoop--edit-cancel helm-swoop-edit-map)
|
||
|
(helm-swoop--key-of-function 'helm-swoop--edit-delete-all-lines helm-swoop-edit-map))
|
||
|
'face 'helm-bookmark-addressbook)))
|
||
|
;; Line number and editable area
|
||
|
(while (re-search-forward "^\\([0-9]+\s\\)\\(.*\\)$" nil t)
|
||
|
(let* (($bol1 (match-beginning 1))
|
||
|
($eol1 (match-end 1))
|
||
|
($bol2 (match-beginning 2))
|
||
|
($eol2 (match-end 2)))
|
||
|
|
||
|
;; Line number
|
||
|
(add-text-properties $bol1 $eol1
|
||
|
'(face font-lock-function-name-face
|
||
|
intangible t))
|
||
|
;; Editable area
|
||
|
(remove-text-properties $bol2 $eol2 '(read-only t))
|
||
|
;; (add-text-properties $bol2 $eol2 '(font-lock-face helm-match))
|
||
|
|
||
|
;; For line tail
|
||
|
(set-text-properties $eol2 (or (1+ $eol2) (point-max))
|
||
|
'(read-only t rear-nonsticky t))))
|
||
|
(helm-swoop--target-word-overlay 'edit-buffer 0))))
|
||
|
|
||
|
(other-window 1)
|
||
|
(switch-to-buffer helm-multi-swoop-edit-buffer)
|
||
|
(goto-char (point-min))
|
||
|
(if (string-match "^[0-9]+" $candidate)
|
||
|
(re-search-forward
|
||
|
(concat "^" (match-string 0 $candidate)) nil t))
|
||
|
(use-local-map helm-multi-swoop-edit-map))
|
||
|
|
||
|
(defun helm-multi-swoop--separate-text-property-into-list ($property)
|
||
|
(interactive)
|
||
|
(let ($list $end)
|
||
|
(save-excursion
|
||
|
(goto-char (point-min))
|
||
|
(while (setq $end (next-single-property-change (point) $property))
|
||
|
;; Must eliminate last return because of unexpected edit result
|
||
|
(setq $list (cons
|
||
|
(let (($str (buffer-substring-no-properties (point) $end)))
|
||
|
(if (string-match "\n\n\\'" $str)
|
||
|
(replace-regexp-in-string "\n\\'" "" $str)
|
||
|
$str))
|
||
|
$list))
|
||
|
(goto-char $end))
|
||
|
(setq $list (cons (buffer-substring-no-properties (point) (point-max))
|
||
|
$list)))
|
||
|
(nreverse $list)))
|
||
|
|
||
|
(defun helm-multi-swoop--collect-edited-lines ()
|
||
|
"Create a list of edited lines with each its own line number"
|
||
|
(interactive)
|
||
|
(let* (($list
|
||
|
(helm-multi-swoop--separate-text-property-into-list 'helm-header))
|
||
|
($length (length $list))
|
||
|
($i 1) ;; 0th $list is header
|
||
|
$pairs)
|
||
|
(while (<= $i $length)
|
||
|
(let ($contents)
|
||
|
;; Make ((number . line) (number . line) (number . line) ...)
|
||
|
(with-temp-buffer
|
||
|
(insert (format "%s" (nth (1+ $i) $list)))
|
||
|
(goto-char (point-min))
|
||
|
(while (re-search-forward "^\\([0-9]+\\)\s" nil t)
|
||
|
(setq $contents
|
||
|
(cons (cons (string-to-number (match-string 1))
|
||
|
(buffer-substring-no-properties
|
||
|
(point)
|
||
|
(save-excursion
|
||
|
(if (re-search-forward
|
||
|
"^\\([0-9]+\\)\s\\|^\\(\\-+\\)" nil t)
|
||
|
(1- (match-beginning 0))
|
||
|
(goto-char (point-max))
|
||
|
(re-search-backward "\n" nil t)))))
|
||
|
$contents))))
|
||
|
;; Make ((buffer-name (number . line) (number . line) ...)
|
||
|
;; (buffer-name (number . line) (number . line) ...) ...)
|
||
|
(setq $pairs (cons (cons (nth $i $list) $contents) $pairs)))
|
||
|
(setq $i (+ $i 2)))
|
||
|
(delete '(nil) $pairs)))
|
||
|
|
||
|
(defun helm-multi-swoop--edit-complete ()
|
||
|
"Delete all extracted lines, and apply changes to buffers and kill temporary edit buffer"
|
||
|
(interactive)
|
||
|
(let (($list (helm-multi-swoop--collect-edited-lines))
|
||
|
$read-only)
|
||
|
(mapc (lambda ($x)
|
||
|
(with-current-buffer (car $x)
|
||
|
(unless buffer-read-only
|
||
|
(save-excursion
|
||
|
(mapc (lambda ($cell)
|
||
|
(let (($k (car $cell))
|
||
|
($v (cdr $cell)))
|
||
|
(goto-char (point-min))
|
||
|
(delete-region (point-at-bol $k) (point-at-eol $k))
|
||
|
(goto-char (point-at-bol $k))
|
||
|
(insert $v)))
|
||
|
(cdr $x))))
|
||
|
(if helm-multi-swoop-edit-save
|
||
|
(if buffer-read-only
|
||
|
(setq $read-only t)
|
||
|
(save-buffer)))))
|
||
|
$list)
|
||
|
(select-window helm-swoop-synchronizing-window)
|
||
|
(kill-buffer (get-buffer helm-multi-swoop-edit-buffer))
|
||
|
(if $read-only
|
||
|
(message "Couldn't save some buffers because of read-only")
|
||
|
(message "Successfully helm-multi-swoop-edit applied to original buffer"))))
|
||
|
|
||
|
(defun helm-multi-swoop--edit-delete-all-lines ()
|
||
|
"Delete all extracted lines, and apply changes to buffers and kill temporary edit buffer"
|
||
|
(interactive)
|
||
|
(let (($list (helm-multi-swoop--collect-edited-lines))
|
||
|
$read-only)
|
||
|
(mapc (lambda ($x)
|
||
|
(with-current-buffer (car $x)
|
||
|
(unless buffer-read-only
|
||
|
(save-excursion
|
||
|
(mapc (lambda ($cell)
|
||
|
(let (($k (car $cell)))
|
||
|
(goto-char (point-min))
|
||
|
(delete-region (point-at-bol $k)
|
||
|
(if (eq (point-at-eol $k) (point-max))
|
||
|
(point-at-eol $k)
|
||
|
(1+ (point-at-eol $k))))))
|
||
|
(cdr $x))))
|
||
|
(if helm-multi-swoop-edit-save
|
||
|
(if buffer-read-only
|
||
|
(setq $read-only t)
|
||
|
(save-buffer)))))
|
||
|
$list)
|
||
|
(select-window helm-swoop-synchronizing-window)
|
||
|
(kill-buffer (get-buffer helm-multi-swoop-edit-buffer))
|
||
|
(if $read-only
|
||
|
(message "Couldn't save some buffers because of read-only")
|
||
|
(message "Successfully helm-multi-swoop-edit applied to original buffer"))))
|
||
|
|
||
|
(defun helm-multi-swoop--edit-cancel ()
|
||
|
"Cancel edit and kill temporary buffer"
|
||
|
(interactive)
|
||
|
(select-window helm-swoop-synchronizing-window)
|
||
|
(kill-buffer (get-buffer helm-multi-swoop-edit-buffer))
|
||
|
(message "helm-multi-swoop-edit canceled"))
|
||
|
|
||
|
;;;###autoload
|
||
|
(defun helm-multi-swoop-edit ()
|
||
|
(interactive)
|
||
|
(helm-exit-and-execute-action 'helm-multi-swoop--edit))
|
||
|
|
||
|
;;; @ helm-swoop-same-face-at-point -----------------------------------
|
||
|
|
||
|
(defsubst helm-swoop--get-at-face (&optional $point)
|
||
|
(or $point (setq $point (point)))
|
||
|
(let (($face (or (get-char-property $point 'read-face-name)
|
||
|
(get-char-property $point 'face))))
|
||
|
$face))
|
||
|
|
||
|
(defun helm-swoop--cull-face-include-line ($face)
|
||
|
(let (($list) ($po (point-min)))
|
||
|
(save-excursion
|
||
|
(while (setq $po (next-single-property-change $po 'face))
|
||
|
(when (equal $face (helm-swoop--get-at-face $po))
|
||
|
(goto-char $po)
|
||
|
(setq $list (cons (format "%s %s"
|
||
|
(line-number-at-pos $po)
|
||
|
(buffer-substring (point-at-bol) (point-at-eol)))
|
||
|
$list))
|
||
|
(let (($ov (make-overlay $po (or (next-single-property-change $po 'face)
|
||
|
(point-max)))))
|
||
|
(overlay-put $ov 'face 'helm-swoop-target-word-face)
|
||
|
(overlay-put $ov 'target-buffer 'helm-swoop-target-word-face)))))
|
||
|
(nreverse (delete-dups $list))))
|
||
|
|
||
|
(defun helm-swoop-same-face-at-point (&optional $face)
|
||
|
(interactive)
|
||
|
(or $face (setq $face (helm-swoop--get-at-face)))
|
||
|
(helm-swoop :$query ""
|
||
|
:$source
|
||
|
`((name . "helm-swoop-same-face-at-point")
|
||
|
(candidates . ,(helm-swoop--cull-face-include-line $face))
|
||
|
(header-line . ,(format "%s" $face))
|
||
|
(action
|
||
|
. (("Go to Line"
|
||
|
. (lambda ($line)
|
||
|
(helm-swoop--goto-line
|
||
|
(when (string-match "^[0-9]+" $line)
|
||
|
(string-to-number (match-string 0 $line))))
|
||
|
(let (($po (point))
|
||
|
($poe (point-at-eol)))
|
||
|
(while (<= (setq $po (next-single-property-change $po 'face)) $poe)
|
||
|
(when (eq 'helm-swoop-target-word-face (helm-swoop--get-at-face $po))
|
||
|
(goto-char $po))))
|
||
|
(helm-swoop--recenter))))))))
|
||
|
|
||
|
(defun helm-multi-swoop-same-face-at-point (&optional $face)
|
||
|
(interactive)
|
||
|
(or $face (setq $face (helm-swoop--get-at-face)))
|
||
|
(helm-multi-swoop--exec
|
||
|
nil
|
||
|
:$query ""
|
||
|
:$func (lambda () (helm-swoop--cull-face-include-line $face))
|
||
|
:$action (lambda ($line)
|
||
|
(switch-to-buffer (assoc-default 'name (helm-get-current-source)))
|
||
|
(helm-swoop--goto-line
|
||
|
(when (string-match "^[0-9]+" $line)
|
||
|
(string-to-number (match-string 0 $line))))
|
||
|
(let (($po (point))
|
||
|
($poe (point-at-eol)))
|
||
|
(while (<= (setq $po (next-single-property-change $po 'face)) $poe)
|
||
|
(when (eq 'helm-swoop-target-word-face (helm-swoop--get-at-face $po))
|
||
|
(goto-char $po))))
|
||
|
(helm-swoop--recenter))
|
||
|
:$buflist (helm-multi-swoop--get-buffer-list)))
|
||
|
|
||
|
(provide 'helm-swoop)
|
||
|
;;; helm-swoop.el ends here
|