contrib/anything-grep.el: anything-grep-multiline: revert to `t'
[anything-config.git] / anything-match-plugin.el
blob9b372c7564f630d3ef8d3750cc6331d21a5148f6
1 ;;; anything-match-plugin.el --- Multiple regexp matching methods for anything
3 ;; Author: rubikitch <rubikitch@ruby-lang.org>
5 ;; Maintainers: rubikitch <rubikitch@ruby-lang.org>
6 ;; Thierry Volpiatto <thierry.volpiatto@gmail.com>
8 ;; Copyright (C) 2008~2012, rubikitch, all rights reserved.
9 ;; Copyright (C) 2011~2012, Thierry Volpiatto, all rights reserved.
11 ;; Keywords: anything, matching
12 ;; X-URL: <http://repo.or.cz/w/anything-config.git>
14 ;; This file is free software; you can redistribute it and/or modify
15 ;; it under the terms of the GNU General Public License as published by
16 ;; the Free Software Foundation; either version 2, or (at your option)
17 ;; any later version.
19 ;; This file is distributed in the hope that it will be useful,
20 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
21 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 ;; GNU General Public License for more details.
24 ;; You should have received a copy of the GNU General Public License
25 ;; along with GNU Emacs; see the file COPYING. If not, write to
26 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
27 ;; Boston, MA 02110-1301, USA.
29 ;;; Auto documentation
30 ;; ------------------
32 ;; * User variables
33 ;; [EVAL] (autodoc-document-lisp-buffer :type 'user-variable :prefix "anything-mp" :var-value t)
34 ;; `anything-mp-matching-method'
35 ;; Default Value: multi3
36 ;; `anything-mp-highlight-delay'
37 ;; Default Value: 0.7
38 ;; `anything-mp-highlight-threshold'
39 ;; Default Value: 2
41 ;; * Internal variables
42 ;; [EVAL] (autodoc-document-lisp-buffer :type 'internal-variable :prefix "anything-mp" :var-value t)
43 ;; `anything-mp-default-match-functions'
44 ;; Default Value: (anything-mp-exact-match anything-mp-3-match)
45 ;; `anything-mp-default-search-functions'
46 ;; Default Value: (anything-mp-exact-search anything-mp-3-search)
47 ;; `anything-mp-default-search-backward-functions'
48 ;; Default Value: (anything-mp-exact-search-backward anything-mp-3-search-backward)
49 ;; `anything-mp-space-regexp'
50 ;; Default Value: "[\\ ] "
51 ;; `anything-mp-exact-pattern-str'
52 ;; Default Value: "autod"
53 ;; `anything-mp-exact-pattern-real'
54 ;; Default Value: "\nautod\n"
55 ;; `anything-mp-prefix-pattern-str'
56 ;; Default Value: nil
57 ;; `anything-mp-prefix-pattern-real'
58 ;; Default Value: nil
59 ;; `anything-mp-1-pattern-str'
60 ;; Default Value: nil
61 ;; `anything-mp-1-pattern-real'
62 ;; Default Value: nil
63 ;; `anything-mp-2-pattern-str'
64 ;; Default Value: nil
65 ;; `anything-mp-2-pattern-real'
66 ;; Default Value: nil
67 ;; `anything-mp-3-pattern-str'
68 ;; Default Value: "autod"
69 ;; `anything-mp-3-pattern-list'
70 ;; Default Value: ((identity . "autod"))
71 ;; `anything-mp-initial-highlight-delay'
72 ;; Default Value: nil
74 ;; * Anything match plugin Functions
75 ;; [EVAL] (autodoc-document-lisp-buffer :type 'function :prefix "anything-mp")
76 ;; `anything-mp-set-matching-method'
77 ;; `anything-mp-make-regexps'
78 ;; `anything-mp-1-make-regexp'
79 ;; `anything-mp-exact-get-pattern'
80 ;; `anything-mp-exact-match'
81 ;; `anything-mp-exact-search'
82 ;; `anything-mp-exact-search-backward'
83 ;; `anything-mp-prefix-get-pattern'
84 ;; `anything-mp-prefix-match'
85 ;; `anything-mp-prefix-search'
86 ;; `anything-mp-prefix-search-backward'
87 ;; `anything-mp-1-get-pattern'
88 ;; `anything-mp-1-match'
89 ;; `anything-mp-1-search'
90 ;; `anything-mp-1-search-backward'
91 ;; `anything-mp-2-get-pattern'
92 ;; `anything-mp-2-match'
93 ;; `anything-mp-2-search'
94 ;; `anything-mp-2-search-backward'
95 ;; `anything-mp-3-get-patterns'
96 ;; `anything-mp-3-get-patterns-internal'
97 ;; `anything-mp-3-match'
98 ;; `anything-mp-3-search-base'
99 ;; `anything-mp-3-search'
100 ;; `anything-mp-3-search-backward'
101 ;; `anything-mp-3p-match'
102 ;; `anything-mp-3p-search'
103 ;; `anything-mp-3p-search-backward'
104 ;; `anything-mp-highlight-match'
105 ;; `anything-mp-highlight-region'
106 ;; `anything-mp-highlight-match-internal'
108 ;; *** END auto-documentation
110 ;;; Commentary:
112 ;; Change anything.el matching algorithm humanely.
113 ;; It gives anything.el search refinement functionality.
114 ;; exact match -> prefix match -> multiple regexp match
116 ;;; Commands:
118 ;; Below are complete command list:
120 ;; `anything-mp-toggle-match-plugin'
121 ;; Turn on/off multiple regexp matching in anything.
123 ;;; Customizable Options:
125 ;; Below are customizable option list:
127 ;; `anything-mp-matching-method'
128 ;; Matching method for anything match plugin.
129 ;; default = (quote multi3)
130 ;; `anything-mp-highlight-delay'
131 ;; Highlight matches with `anything-match' face after this many seconds.
132 ;; default = 0.7
133 ;; `anything-mp-highlight-threshold'
134 ;; Minimum length of pattern to highlight.
135 ;; default = 2
136 ;; `anything-grep-candidates-fast-directory-regexp'
137 ;; *Directory regexp where a RAM disk (or tmpfs) is mounted.
138 ;; default = nil
139 ;; `anything-grep-candidates-requires-pattern'
140 ;; *Required length of input to grep search.
141 ;; default = 2
143 ;; A query of multiple regexp match is space-delimited string.
144 ;; Anything displays candidates which matches all the regexps.
145 ;; A regexp with "!" prefix means not matching the regexp.
146 ;; To include spaces to a regexp, prefix "\" before space,
147 ;; it is controlled by `anything-mp-space-regexp' variable.
149 ;; If multiple regexps are specified, first one also tries to match the source name.
150 ;; If you want to disable this feature, evaluate
151 ;; (setq anything-mp-match-source-name nil) .
152 ;; NOTE: This is obsolete and disabled in anything versions >= 1.3.7
154 ;; This file highlights patterns like `occur'. Note that patterns
155 ;; longer than `anything-mp-highlight-threshold' are highlighted. And
156 ;; region out of screen is highlighted after
157 ;; `anything-mp-highlight-delay' seconds.
159 ;; Highlight in Emacs is time-consuming process for slow computers. To
160 ;; disable it is to set nil to `anything-mp-highlight-delay'.
162 ;; anything-match-plugin is enable by default in anything.
163 ;; To disable/enable it use M-x anything-c-toggle-match-plugin.
165 ;;; Code:
167 (require 'anything)
168 (require 'cl)
171 ;;;; Match-plugin
173 ;; Internal
174 (defvar anything-mp-default-match-functions nil)
175 (defvar anything-mp-default-search-functions nil)
176 (defvar anything-mp-default-search-backward-functions nil)
178 (defun anything-mp-set-matching-method (var key)
179 "Default function to set matching methods in anything match plugin."
180 (set-default var key)
181 (case (symbol-value var)
182 (multi1 (setq anything-mp-default-match-functions
183 '(anything-mp-exact-match anything-mp-1-match)
184 anything-mp-default-search-functions
185 '(anything-mp-exact-search anything-mp-1-search)
186 anything-mp-default-search-backward-functions
187 '(anything-mp-exact-search-backward
188 anything-mp-1-search-backward)))
189 (multi2 (setq anything-mp-default-match-functions
190 '(anything-mp-exact-match anything-mp-2-match)
191 anything-mp-default-search-functions
192 '(anything-mp-exact-search anything-mp-2-search)
193 anything-mp-default-search-backward-functions
194 '(anything-mp-exact-search-backward
195 anything-mp-2-search-backward)))
196 (multi3 (setq anything-mp-default-match-functions
197 '(anything-mp-exact-match anything-mp-3-match)
198 anything-mp-default-search-functions
199 '(anything-mp-exact-search anything-mp-3-search)
200 anything-mp-default-search-backward-functions
201 '(anything-mp-exact-search-backward
202 anything-mp-3-search-backward)))
203 (multi3p (setq anything-mp-default-match-functions
204 '(anything-mp-exact-match anything-mp-3p-match)
205 anything-mp-default-search-functions
206 '(anything-mp-exact-search anything-mp-3p-search)
207 anything-mp-default-search-backward-functions
208 '(anything-mp-exact-search-backward
209 anything-mp-3p-search-backward)))
210 (t (error "Unknow value: %s" anything-mp-matching-method))))
212 (defgroup anything-match-plugin nil
213 "Anything match plugin."
214 :group 'anything)
216 (defcustom anything-mp-matching-method 'multi3
217 "Matching method for anything match plugin.
218 You can set here different methods to match candidates in anything.
219 Here are the possible value of this symbol and their meaning:
220 - multi1: Respect order, prefix of pattern must match.
221 - multi2: Same but with partial match.
222 - multi3: The best, multiple regexp match, allow negation.
223 - multi3p: Same but prefix must match.
224 Default is multi3."
225 :type '(radio :tag "Matching methods for anything"
226 (const :tag "Multiple regexp 1 ordered with prefix match" multi1)
227 (const :tag "Multiple regexp 2 ordered with partial match" multi2)
228 (const :tag "Multiple regexp 3 matching no order, partial, best." multi3)
229 (const :tag "Multiple regexp 3p matching with prefix match" multi3p))
230 :set 'anything-mp-set-matching-method
231 :group 'anything-match-plugin)
233 (defface anything-match
234 '((t (:inherit match)))
235 "Face used to highlight matches."
236 :group 'anything-match-plugin)
238 (defcustom anything-mp-highlight-delay 0.7
239 "Highlight matches with `anything-match' face after this many seconds.
240 If nil, no highlight. "
241 :type 'integer
242 :group 'anything-match-plugin)
244 (defcustom anything-mp-highlight-threshold 2
245 "Minimum length of pattern to highlight.
246 The smaller this value is, the slower highlight is."
247 :type 'integer
248 :group 'anything-match-plugin)
252 ;;; Build regexps
255 (defvar anything-mp-space-regexp "[\\ ] "
256 "Regexp to represent space itself in multiple regexp match.")
258 (defun anything-mp-make-regexps (pattern)
259 "Split PATTERN if it contain spaces and return resulting list.
260 If spaces in PATTERN are escaped, don't split at this place.
261 i.e \"foo bar\"=> (\"foo\" \"bar\")
262 but \"foo\ bar\"=> (\"foobar\")."
263 (if (string= pattern "")
264 '("")
265 (loop for s in (split-string
266 (replace-regexp-in-string anything-mp-space-regexp
267 "\000\000" pattern)
268 " " t)
269 collect (replace-regexp-in-string "\000\000" " " s))))
271 (defun anything-mp-1-make-regexp (pattern)
272 "Replace spaces in PATTERN with \"\.*\"."
273 (mapconcat 'identity (anything-mp-make-regexps pattern) ".*"))
276 ;;; Exact match.
279 ;; Internal.
280 (defvar anything-mp-exact-pattern-str nil)
281 (defvar anything-mp-exact-pattern-real nil)
283 (defun anything-mp-exact-get-pattern (pattern)
284 (unless (equal pattern anything-mp-exact-pattern-str)
285 (setq anything-mp-exact-pattern-str pattern
286 anything-mp-exact-pattern-real (concat "\n" pattern "\n")))
287 anything-mp-exact-pattern-real)
290 (defun anything-mp-exact-match (str &optional pattern)
291 (string= str (or pattern anything-pattern)))
293 (defun anything-mp-exact-search (pattern &rest ignore)
294 (and (search-forward (anything-mp-exact-get-pattern pattern) nil t)
295 (forward-line -1)))
297 (defun anything-mp-exact-search-backward (pattern &rest ignore)
298 (and (search-backward (anything-mp-exact-get-pattern pattern) nil t)
299 (forward-line 1)))
302 ;;; Prefix match
305 ;; Internal
306 (defvar anything-mp-prefix-pattern-str nil)
307 (defvar anything-mp-prefix-pattern-real nil)
309 (defun anything-mp-prefix-get-pattern (pattern)
310 (unless (equal pattern anything-mp-prefix-pattern-str)
311 (setq anything-mp-prefix-pattern-str pattern
312 anything-mp-prefix-pattern-real (concat "\n" pattern)))
313 anything-mp-prefix-pattern-real)
315 (defun anything-mp-prefix-match (str &optional pattern)
316 (setq pattern (or pattern anything-pattern))
317 (let ((len (length pattern)))
318 (and (<= len (length str))
319 (string= (substring str 0 len) pattern ))))
321 (defun anything-mp-prefix-search (pattern &rest ignore)
322 (search-forward (anything-mp-prefix-get-pattern pattern) nil t))
324 (defun anything-mp-prefix-search-backward (pattern &rest ignore)
325 (and (search-backward (anything-mp-prefix-get-pattern pattern) nil t)
326 (forward-line 1)))
329 ;;; Multiple regexp patterns 1 (order is preserved / prefix).
332 ;; Internal
333 (defvar anything-mp-1-pattern-str nil)
334 (defvar anything-mp-1-pattern-real nil)
336 (defun anything-mp-1-get-pattern (pattern)
337 (unless (equal pattern anything-mp-1-pattern-str)
338 (setq anything-mp-1-pattern-str pattern
339 anything-mp-1-pattern-real
340 (concat "^" (anything-mp-1-make-regexp pattern))))
341 anything-mp-1-pattern-real)
343 (defun* anything-mp-1-match (str &optional (pattern anything-pattern))
344 (string-match (anything-mp-1-get-pattern pattern) str))
346 (defun anything-mp-1-search (pattern &rest ignore)
347 (re-search-forward (anything-mp-1-get-pattern pattern) nil t))
349 (defun anything-mp-1-search-backward (pattern &rest ignore)
350 (re-search-backward (anything-mp-1-get-pattern pattern) nil t))
353 ;;; Multiple regexp patterns 2 (order is preserved / partial).
356 ;; Internal
357 (defvar anything-mp-2-pattern-str nil)
358 (defvar anything-mp-2-pattern-real nil)
360 (defun anything-mp-2-get-pattern (pattern)
361 (unless (equal pattern anything-mp-2-pattern-str)
362 (setq anything-mp-2-pattern-str pattern
363 anything-mp-2-pattern-real
364 (concat "^.*" (anything-mp-1-make-regexp pattern))))
365 anything-mp-2-pattern-real)
367 (defun* anything-mp-2-match (str &optional (pattern anything-pattern))
368 (string-match (anything-mp-2-get-pattern pattern) str))
370 (defun anything-mp-2-search (pattern &rest ignore)
371 (re-search-forward (anything-mp-2-get-pattern pattern) nil t))
373 (defun anything-mp-2-search-backward (pattern &rest ignore)
374 (re-search-backward (anything-mp-2-get-pattern pattern) nil t))
377 ;;; Multiple regexp patterns 3 (permutation).
380 ;; Internal
381 (defvar anything-mp-3-pattern-str nil)
382 (defvar anything-mp-3-pattern-list nil)
384 (defun anything-mp-3-get-patterns (pattern)
385 "Return `anything-mp-3-pattern-list', a list of predicate/regexp cons cells.
386 e.g ((identity . \"foo\") (identity . \"bar\")).
387 This is done only if `anything-mp-3-pattern-str' is same as PATTERN."
388 (unless (equal pattern anything-mp-3-pattern-str)
389 (setq anything-mp-3-pattern-str pattern
390 anything-mp-3-pattern-list
391 (anything-mp-3-get-patterns-internal pattern)))
392 anything-mp-3-pattern-list)
394 (defun anything-mp-3-get-patterns-internal (pattern)
395 "Return a list of predicate/regexp cons cells.
396 e.g ((identity . \"foo\") (identity . \"bar\"))."
397 (unless (string= pattern "")
398 (if (string-match "^!" pattern)
399 (anything-mp-3-get-patterns-internal (concat ". " pattern))
400 (loop for pat in (anything-mp-make-regexps pattern)
401 collect (if (string= "!" (substring pat 0 1))
402 (cons 'not (substring pat 1))
403 (cons 'identity pat))))))
405 (defun anything-mp-3-match (str &optional pattern)
406 "Check if PATTERN match STR.
407 When PATTERN contain a space, it is splitted and matching is done
408 with the several resulting regexps against STR.
409 e.g \"bar foo\" will match \"foobar\" and \"barfoo\".
410 Argument PATTERN, a string, is transformed in a list of
411 cons cell with `anything-mp-3-get-patterns' if it contain a space.
412 e.g \"foo bar\"=>((identity . \"foo\") (identity . \"bar\")).
413 Then each predicate of cons cell(s) is called with regexp of same
414 cons cell against STR (a candidate).
415 i.e (identity (string-match \"foo\" \"foo bar\")) => t."
416 (let ((pat (anything-mp-3-get-patterns (or pattern anything-pattern))))
417 (loop for (predicate . regexp) in pat
418 always (funcall predicate (string-match regexp str)))))
420 (defun anything-mp-3-search-base (pattern searchfn1 searchfn2)
421 (loop with pat = (if (stringp pattern)
422 (anything-mp-3-get-patterns pattern)
423 pattern)
424 while (funcall searchfn1 (or (cdar pat) "") nil t)
425 for bol = (point-at-bol)
426 for eol = (point-at-eol)
427 for (b . e) = (if (eq searchfn2 're-search-backward)
428 (cons eol bol)
429 (cons bol eol))
430 if (loop for (pred . str) in (cdr pat) always
431 (progn (goto-char b)
432 (funcall pred (funcall searchfn2 str e t))))
433 do (goto-char e) and return t
434 else do (goto-char e)
435 finally return nil))
437 (defun anything-mp-3-search (pattern &rest ignore)
438 (when (stringp pattern)
439 (setq pattern (anything-mp-3-get-patterns pattern)))
440 (anything-mp-3-search-base
441 pattern 're-search-forward 're-search-forward))
443 (defun anything-mp-3-search-backward (pattern &rest ignore)
444 (when (stringp pattern)
445 (setq pattern (anything-mp-3-get-patterns pattern)))
446 (anything-mp-3-search-base
447 pattern 're-search-backward 're-search-backward))
450 ;;; mp-3p- (multiple regexp pattern 3 with prefix search)
453 (defun anything-mp-3p-match (str &optional pattern)
454 "Check if PATTERN match STR.
455 Same as `anything-mp-3-match' but more strict, matching against prefix also.
456 e.g \"bar foo\" will match \"barfoo\" but not \"foobar\" contrarily to
457 `anything-mp-3-match'."
458 (let* ((pat (anything-mp-3-get-patterns (or pattern anything-pattern)))
459 (first (car pat)))
460 (and (funcall (car first) (anything-mp-prefix-match str (cdr first)))
461 (loop for (predicate . regexp) in (cdr pat)
462 always (funcall predicate (string-match regexp str))))))
464 (defun anything-mp-3p-search (pattern &rest ignore)
465 (when (stringp pattern)
466 (setq pattern (anything-mp-3-get-patterns pattern)))
467 (anything-mp-3-search-base
468 pattern 'anything-mp-prefix-search 're-search-forward))
470 (defun anything-mp-3p-search-backward (pattern &rest ignore)
471 (when (stringp pattern)
472 (setq pattern (anything-mp-3-get-patterns pattern)))
473 (anything-mp-3-search-base
474 pattern 'anything-mp-prefix-search-backward 're-search-backward))
477 ;;; source compiler
480 (defun anything-compile-source--match-plugin (source)
481 (let ((searchers (if (assoc 'search-from-end source)
482 anything-mp-default-search-backward-functions
483 anything-mp-default-search-functions)))
484 `(,(if (or (assoc 'candidates-in-buffer source)
485 (equal '(identity) (assoc-default 'match source)))
486 '(match identity)
487 `(match ,@anything-mp-default-match-functions
488 ,@(assoc-default 'match source)))
489 (search ,@searchers
490 ,@(assoc-default 'search source))
491 ,@source)))
492 (add-to-list 'anything-compile-source-functions 'anything-compile-source--match-plugin t)
495 ;;; Highlight matches.
498 (defun anything-mp-highlight-match ()
499 "Highlight matches after `anything-mp-highlight-delay' seconds."
500 (when (and anything-mp-highlight-delay
501 (not (string= anything-pattern "")))
502 (anything-mp-highlight-match-internal (window-end (anything-window)))
503 (run-with-idle-timer anything-mp-highlight-delay nil
504 'anything-mp-highlight-match-internal
505 (with-current-buffer anything-buffer (point-max)))))
506 (add-hook 'anything-update-hook 'anything-mp-highlight-match)
508 (defun anything-mp-highlight-region (start end regexp face)
509 (save-excursion
510 (goto-char start)
511 (let (me)
512 (while (and (setq me (re-search-forward regexp nil t))
513 (< (point) end)
514 (< 0 (- (match-end 0) (match-beginning 0))))
515 (unless (anything-pos-header-line-p)
516 (put-text-property (match-beginning 0) me 'face face))))))
518 (defun anything-mp-highlight-match-internal (end)
519 (when (anything-window)
520 (set-buffer anything-buffer)
521 (let ((requote (loop for (pred . re) in
522 (anything-mp-3-get-patterns anything-pattern)
523 when (and (eq pred 'identity)
524 (>= (length re)
525 anything-mp-highlight-threshold))
526 collect re into re-list
527 finally return
528 (if (and re-list (>= (length re-list) 1))
529 (mapconcat 'identity re-list "\\|")
530 (regexp-quote anything-pattern)))))
531 (when (>= (length requote) anything-mp-highlight-threshold)
532 (anything-mp-highlight-region
533 (point-min) end requote 'anything-match)))))
536 ;;; Toggle anything-match-plugin
539 (defvar anything-mp-initial-highlight-delay nil)
541 ;;;###autoload
542 (defun anything-mp-toggle-match-plugin ()
543 "Turn on/off multiple regexp matching in anything.
544 i.e anything-match-plugin."
545 (interactive)
546 (let ((anything-match-plugin-enabled
547 (member 'anything-compile-source--match-plugin
548 anything-compile-source-functions)))
549 (flet ((disable-match-plugin ()
550 (setq anything-compile-source-functions
551 (delq 'anything-compile-source--match-plugin
552 anything-compile-source-functions))
553 (setq anything-mp-initial-highlight-delay
554 anything-mp-highlight-delay)
555 (setq anything-mp-highlight-delay nil))
556 (enable-match-plugin ()
557 (unless anything-mp-initial-highlight-delay
558 (setq anything-mp-initial-highlight-delay
559 anything-mp-highlight-delay))
560 (setq anything-compile-source-functions
561 (cons 'anything-compile-source--match-plugin
562 anything-compile-source-functions))
563 (unless anything-mp-highlight-delay
564 (setq anything-mp-highlight-delay
565 anything-mp-initial-highlight-delay))))
566 (if anything-match-plugin-enabled
567 (when (y-or-n-p "Really disable match-plugin? ")
568 (disable-match-plugin)
569 (message "Anything-match-plugin disabled"))
570 (when (y-or-n-p "Really enable match-plugin? ")
571 (enable-match-plugin)
572 (message "Anything-match-plugin enabled"))))))
575 ;;;; Grep-candidates plug-in
577 (defcustom anything-grep-candidates-fast-directory-regexp nil
578 "*Directory regexp where a RAM disk (or tmpfs) is mounted.
580 If non-nil, grep-candidates plugin gets faster because it uses
581 grep as synchronous process.
583 ex. (setq anything-grep-candidates-fast-directory-regexp \"^/tmp/\")"
584 :type 'string
585 :group 'anything)
587 (defcustom anything-grep-candidates-requires-pattern 2
588 "*Required length of input to grep search.
590 The greater this value is, the faster grep-candidates works."
591 :type 'integer
592 :group 'anything)
594 (defun agp-candidates (&optional filter)
595 "Normal version of grep-candidates candidates function.
596 Grep is run by asynchronous process."
597 (start-process-shell-command
598 "anything-grep-candidates" nil
599 (agp-command-line-2 filter (anything-attr-defined 'search-from-end))))
601 (defun agp-candidates-synchronous-grep (&optional filter)
602 "Faster version of grep-candidates candidates function.
603 Grep is run by synchronous process.
604 It is faster when candidate files are in ramdisk."
605 (let ((x (split-string
606 (shell-command-to-string
607 (agp-command-line-2 filter (anything-attr-defined 'search-from-end)))
608 "\n")))
609 (unless (equal x '("")) x)))
611 (defun agp-candidates-synchronous-grep--direct-insert-match (&optional filter)
612 "[EXPERIMENTAL]Fastest version of grep-candidates candidates function at the cost of absense of transformers.
613 Grep is run by synchronous process.
614 It is faster when candidate files are in ramdisk.
616 If (direct-insert-match) is in the source, this function is used."
617 (with-current-buffer (anything-candidate-buffer 'global)
618 (call-process-shell-command
619 (agp-command-line-2 filter (anything-attr-defined 'search-from-end))
620 nil t)))
622 (defun agp-command-line (query files &optional limit filter search-from-end)
623 "Build command line used by grep-candidates from QUERY, FILES, LIMIT, and FILTER."
624 (let ((allfiles (mapconcat (lambda (f) (shell-quote-argument (expand-file-name f)))
625 files " ")))
626 (with-temp-buffer
627 (when search-from-end
628 (insert "tac " allfiles))
629 (if (< (length query) anything-grep-candidates-requires-pattern)
630 (unless search-from-end
631 (insert "cat " allfiles))
632 (when search-from-end (insert " | "))
633 (loop with exist-ary = (file-exists-p (concat (car files) ".ary"))
634 for (flag . re) in (anything-mp-3-get-patterns-internal query)
635 for i from 0
637 (setq re (replace-regexp-in-string "^-" "\\-" re))
638 (unless (zerop i) (insert " | "))
639 (if (and (not (cdr files))
640 (not search-from-end)
641 (eq flag 'identity)
642 (zerop i)
643 exist-ary)
644 (insert "sary " (shell-quote-argument re))
645 (insert "grep -ih "
646 (if (eq flag 'identity) "" "-v ")
647 (shell-quote-argument re)))
648 (when (and (not search-from-end) (zerop i))
649 (insert " " allfiles))))
651 (when limit (insert (format " | head -n %d" limit)))
652 (when filter (insert " | " filter))
653 (buffer-string))))
655 (defun agp-command-line-2 (filter &optional search-from-end)
656 "Build command line used by grep-candidates from FILTER and current source."
657 (agp-command-line
658 anything-pattern
659 (anything-mklist (anything-interpret-value (anything-attr 'grep-candidates)))
660 (anything-candidate-number-limit (anything-get-current-source))
661 filter search-from-end))
663 (defun anything-compile-source--grep-candidates (source)
664 (anything-aif (assoc-default 'grep-candidates source)
665 (append
666 source
667 (let ((use-fast-directory
668 (and anything-grep-candidates-fast-directory-regexp
669 (string-match
670 anything-grep-candidates-fast-directory-regexp
671 (or (car (anything-mklist (anything-interpret-value it))) "")))))
672 (cond ((not (anything-interpret-value it)) nil)
673 ((and use-fast-directory (assq 'direct-insert-match source))
674 (anything-log "fastest version (use-fast-directory and direct-insert-match)")
675 `((candidates . agp-candidates-synchronous-grep--direct-insert-match)
676 (match identity)
677 (volatile)))
678 (use-fast-directory
679 (anything-log "faster version (use-fast-directory)")
680 `((candidates . agp-candidates-synchronous-grep)
681 (match identity)
682 (volatile)))
684 (anything-log "normal version")
685 '((candidates . agp-candidates)
686 (delayed))))))
687 source))
688 (add-to-list 'anything-compile-source-functions 'anything-compile-source--grep-candidates)
690 (anything-document-attribute 'grep-candidates "grep-candidates plug-in"
691 "grep-candidates plug-in provides anything-match-plugin.el feature with grep and head program.
692 It is MUCH FASTER than normal match-plugin to search from vary large (> 1MB) candidates.
693 Make sure to install these programs.
695 It expands `candidates' and `delayed' attributes.
697 `grep-candidates' attribute accepts a filename or list of filename.
698 It also accepts 0-argument function name or variable name.")
700 ;; (anything '(((name . "grep-test") (grep-candidates . "~/.emacs.el") (action . message))))
701 ;; (let ((a "~/.emacs.el")) (anything '(((name . "grep-test") (grep-candidates . a) (action . message) (delayed)))))
702 ;; (let ((a "~/.emacs.el")) (anything '(((name . "grep-test") (grep-candidates . (lambda () a)) (action . message) (delayed)))))
703 ;; (anything '(((name . "grep-test") (grep-candidates . "~/.emacs.el") (action . message) (delayed) (candidate-number-limit . 2))))
704 ;; (let ((anything-candidate-number-limit 2)) (anything '(((name . "grep-test") (grep-candidates . "~/.emacs.el") (action . message) (delayed)))))
706 ;;;; unit test
707 ;; unit test for match plugin are now in developper-tools/unit-test-match-plugin.el
709 (provide 'anything-match-plugin)
711 ;;; anything-match-plugin.el ends here