mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-21 7074318d7ab58aca124f590c42fd820e8eb258a5
commit | author | age
5cb5f7 1 ;;; helm-find.el --- helm interface for find command. -*- lexical-binding: t -*-
C 2
3 ;; Copyright (C) 2012 ~ 2018 Thierry Volpiatto <thierry.volpiatto@gmail.com>
4
5 ;; This program is free software; you can redistribute it and/or modify
6 ;; it under the terms of the GNU General Public License as published by
7 ;; the Free Software Foundation, either version 3 of the License, or
8 ;; (at your option) any later version.
9
10 ;; This program is distributed in the hope that it will be useful,
11 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
12 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 ;; GNU General Public License for more details.
14
15 ;; You should have received a copy of the GNU General Public License
16 ;; along with this program.  If not, see <http://www.gnu.org/licenses/>.
17
18 ;;; Code:
19
20 (require 'helm-files)
21 (require 'helm-external)
22
23 (defcustom helm-findutils-skip-boring-files t
24   "Ignore boring files in find command results."
25   :group 'helm-files
26   :type  'boolean)
27
28 (defcustom helm-findutils-search-full-path nil
29   "Search in full path with shell command find when non--nil.
30 I.e use the -path/ipath arguments of find instead of -name/iname."
31   :group 'helm-files
32   :type 'boolean)
33
34 (defvar helm-find-map
35   (let ((map (make-sparse-keymap)))
36     (set-keymap-parent map helm-generic-files-map)
37     (define-key map (kbd "DEL") 'helm-delete-backward-no-update)
38     map))
39
40 (defvar helm-source-findutils
41   (helm-build-async-source "Find"
42     :header-name (lambda (name)
43                    (concat name " in [" (helm-default-directory) "]"))
44     :candidates-process 'helm-find-shell-command-fn
45     :filtered-candidate-transformer 'helm-findutils-transformer
46     :action-transformer 'helm-transform-file-load-el
47     :persistent-action 'helm-ff-kill-or-find-buffer-fname
48     :action 'helm-type-file-actions
49     :help-message 'helm-generic-file-help-message
50     :keymap helm-find-map
51     :candidate-number-limit 9999
52     :requires-pattern 3))
53
54 (defun helm-findutils-transformer (candidates _source)
55   (let (non-essential
56         (default-directory (helm-default-directory)))
57     (cl-loop for i in candidates
58              for abs = (expand-file-name
59                         (helm-aif (file-remote-p default-directory)
60                             (concat it i) i))
61              for type = (car (file-attributes abs))
62              for disp = (if (and helm-ff-transformer-show-only-basename
63                                  (not (string-match "[.]\\{1,2\\}$" i)))
64                             (helm-basename abs) abs)
65              collect (cond ((eq t type)
66                             (cons (propertize disp 'face 'helm-ff-directory)
67                                   abs))
68                            ((stringp type)
69                             (cons (propertize disp 'face 'helm-ff-symlink)
70                                   abs))
71                            (t (cons (propertize disp 'face 'helm-ff-file)
72                                     abs))))))
73
74 (defun helm-find--build-cmd-line ()
75   (require 'find-cmd)
76   (let* ((default-directory (or (file-remote-p default-directory 'localname)
77                                 default-directory))
78          (patterns+options (split-string helm-pattern "\\(\\`\\| +\\)\\* +"))
79          (fold-case (helm-set-case-fold-search (car patterns+options)))
80          (patterns (split-string (car patterns+options)))
81          (additional-options (and (cdr patterns+options)
82                                   (list (concat (cadr patterns+options) " "))))
83          (ignored-dirs ())
84          (ignored-files (when helm-findutils-skip-boring-files
85                           (cl-loop for f in completion-ignored-extensions
86                                    if (string-match "/$" f)
87                                    do (push (replace-match "" nil t f)
88                                             ignored-dirs)
89                                    else collect (concat "*" f))))
90          (path-or-name (if helm-findutils-search-full-path
91                            '(ipath path) '(iname name)))
92          (name-or-iname (if fold-case
93                             (car path-or-name) (cadr path-or-name))))
94     (find-cmd (and ignored-dirs
95                    `(prune (name ,@ignored-dirs)))
96               (and ignored-files
97                    `(not (name ,@ignored-files)))
98               `(and ,@(mapcar
99                        (lambda (pattern)
100                          `(,name-or-iname ,(concat "*" pattern "*")))
101                        patterns)
102                     ,@additional-options))))
103
104 (defun helm-find-shell-command-fn ()
105   "Asynchronously fetch candidates for `helm-find'.
106 Additional find options can be specified after a \"*\"
107 separator."
108   (let* (process-connection-type
109          non-essential
110          (cmd (helm-find--build-cmd-line))
111          (proc (start-file-process-shell-command "hfind" helm-buffer cmd)))
112     (helm-log "Find command:\n%s" cmd)
113     (prog1 proc
114       (set-process-sentinel
115        proc
116        (lambda (process event)
117            (helm-process-deferred-sentinel-hook
118             process event (helm-default-directory))
119            (if (string= event "finished\n")
120                (with-helm-window
121                  (setq mode-line-format
122                        '(" " mode-line-buffer-identification " "
123                          (:eval (format "L%s" (helm-candidate-number-at-point))) " "
124                          (:eval (propertize
125                                  (format "[Find process finished - (%s results)]"
126                                          (max (1- (count-lines
127                                                    (point-min) (point-max)))
128                                               0))
129                                  'face 'helm-locate-finish))))
130                  (force-mode-line-update))
131                (helm-log "Error: Find %s"
132                          (replace-regexp-in-string "\n" "" event))))))))
133
134 (defun helm-find-1 (dir)
135   (let ((default-directory (file-name-as-directory dir)))
136     (helm :sources 'helm-source-findutils
137           :buffer "*helm find*"
138           :ff-transformer-show-only-basename nil
139           :case-fold-search helm-file-name-case-fold-search)))
140
141
142 ;;; Preconfigured commands
143 ;;
144 ;;
145 ;;;###autoload
146 (defun helm-find (arg)
147   "Preconfigured `helm' for the find shell command.
148
149 Recursively find files whose names are matched by all specified
150 globbing PATTERNs under the current directory using the external
151 program specified in `find-program' (usually \"find\").  Every
152 input PATTERN is silently wrapped into two stars: *PATTERN*.
153
154 With prefix argument, prompt for a directory to search.
155
156 When user option `helm-findutils-search-full-path' is non-nil,
157 match against complete paths, otherwise, against file names
158 without directory part.
159
160 The (possibly empty) list of globbing PATTERNs can be followed by
161 the separator \"*\" plus any number of additional arguments that
162 are passed to \"find\" literally."
163   (interactive "P")
164   (let ((directory
165          (if arg
166              (file-name-as-directory
167               (read-directory-name "DefaultDirectory: "))
168            default-directory)))
169     (helm-find-1 directory)))
170
171 (provide 'helm-find)
172
173 ;; Local Variables:
174 ;; byte-compile-warnings: (not obsolete)
175 ;; coding: utf-8
176 ;; indent-tabs-mode: nil
177 ;; End:
178
179 ;;; helm-find.el ends here