]>
Commit | Line | Data |
---|---|---|
0d23b6e5 BB |
1 | # Copyright 2010-2011 Wincent Colaiuta. All rights reserved. |
2 | # | |
3 | # Redistribution and use in source and binary forms, with or without | |
4 | # modification, are permitted provided that the following conditions are met: | |
5 | # | |
6 | # 1. Redistributions of source code must retain the above copyright notice, | |
7 | # this list of conditions and the following disclaimer. | |
8 | # 2. Redistributions in binary form must reproduce the above copyright notice, | |
9 | # this list of conditions and the following disclaimer in the documentation | |
10 | # and/or other materials provided with the distribution. | |
11 | # | |
12 | # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | |
13 | # AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | |
14 | # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | |
15 | # ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE | |
16 | # LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | |
17 | # CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | |
18 | # SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | |
19 | # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | |
20 | # CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | |
21 | # ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | |
22 | # POSSIBILITY OF SUCH DAMAGE. | |
23 | ||
24 | require 'command-t/vim' | |
25 | require 'command-t/scanner' | |
26 | ||
27 | module CommandT | |
28 | # Reads the current directory recursively for the paths to all regular files. | |
29 | class FileScanner < Scanner | |
30 | class FileLimitExceeded < ::RuntimeError; end | |
31 | ||
32 | def initialize path = Dir.pwd, options = {} | |
33 | @path = path | |
34 | @max_depth = options[:max_depth] || 15 | |
35 | @max_files = options[:max_files] || 10_000 | |
36 | @scan_dot_directories = options[:scan_dot_directories] || false | |
37 | end | |
38 | ||
39 | def paths | |
40 | return @paths unless @paths.nil? | |
41 | begin | |
42 | @paths = [] | |
43 | @depth = 0 | |
44 | @files = 0 | |
45 | @prefix_len = @path.chomp('/').length | |
46 | add_paths_for_directory @path, @paths | |
47 | rescue FileLimitExceeded | |
48 | end | |
49 | @paths | |
50 | end | |
51 | ||
52 | def flush | |
53 | @paths = nil | |
54 | end | |
55 | ||
56 | def path= str | |
57 | if @path != str | |
58 | @path = str | |
59 | flush | |
60 | end | |
61 | end | |
62 | ||
63 | private | |
64 | ||
65 | def path_excluded? path | |
66 | # first strip common prefix (@path) from path to match VIM's behavior | |
67 | path = path[(@prefix_len + 1)..-1] | |
68 | path = VIM::escape_for_single_quotes path | |
69 | ::VIM::evaluate("empty(expand(fnameescape('#{path}')))").to_i == 1 | |
70 | end | |
71 | ||
72 | def add_paths_for_directory dir, accumulator | |
73 | Dir.foreach(dir) do |entry| | |
74 | next if ['.', '..'].include?(entry) | |
75 | path = File.join(dir, entry) | |
76 | unless path_excluded?(path) | |
77 | if File.file?(path) | |
78 | @files += 1 | |
79 | raise FileLimitExceeded if @files > @max_files | |
80 | accumulator << path[@prefix_len + 1..-1] | |
81 | elsif File.directory?(path) | |
82 | next if @depth >= @max_depth | |
83 | next if (entry.match(/\A\./) && !@scan_dot_directories) | |
84 | @depth += 1 | |
85 | add_paths_for_directory path, accumulator | |
86 | @depth -= 1 | |
87 | end | |
88 | end | |
89 | end | |
90 | rescue Errno::EACCES | |
91 | # skip over directories for which we don't have access | |
92 | end | |
93 | end # class FileScanner | |
94 | end # module CommandT |