file_scanner.rb 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. # Copyright 2010-2014 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. require 'command-t/vim'
  24. require 'command-t/scanner'
  25. module CommandT
  26. # Reads the current directory recursively for the paths to all regular files.
  27. #
  28. # This is an abstract superclass; the real work is done by subclasses which
  29. # obtain file listings via different strategies (for examples, see the
  30. # RubyFileScanner and FindFileScanner subclasses).
  31. class FileScanner < Scanner
  32. class FileLimitExceeded < ::RuntimeError; end
  33. attr_accessor :path
  34. def initialize(path = Dir.pwd, options = {})
  35. @paths = {}
  36. @paths_keys = []
  37. @path = path
  38. @max_depth = options[:max_depth] || 15
  39. @max_files = options[:max_files] || 30_000
  40. @max_caches = options[:max_caches] || 1
  41. @scan_dot_directories = options[:scan_dot_directories] || false
  42. @wild_ignore = options[:wild_ignore]
  43. @base_wild_ignore = VIM::wild_ignore
  44. end
  45. def paths
  46. @paths[@path] || begin
  47. ensure_cache_under_limit
  48. @prefix_len = @path.chomp('/').length
  49. nil
  50. end
  51. end
  52. def flush
  53. @paths = {}
  54. end
  55. private
  56. def ensure_cache_under_limit
  57. # Ruby 1.8 doesn't have an ordered hash, so use a separate stack to
  58. # track and expire the oldest entry in the cache
  59. if @max_caches > 0 && @paths_keys.length >= @max_caches
  60. @paths.delete @paths_keys.shift
  61. end
  62. @paths_keys << @path
  63. end
  64. def path_excluded?(path)
  65. # first strip common prefix (@path) from path to match VIM's behavior
  66. path = path[(@prefix_len + 1)..-1]
  67. path = VIM::escape_for_single_quotes path
  68. ::VIM::evaluate("empty(expand(fnameescape('#{path}')))").to_i == 1
  69. end
  70. def set_wild_ignore(ignore)
  71. ::VIM::command("set wildignore=#{ignore}") if @wild_ignore
  72. end
  73. end # class FileScanner
  74. end # module CommandT