class Utils::Finder

def ascii_file?(stat, path)

def ascii_file?(stat, path)
  stat.file? && (@binary || stat.size == 0 || File.ascii?(path))
end

def attempt_match?(path)

def attempt_match?(path)
  stat = path.stat
  stat.symlink? and stat = path.lstat
  if @only_directory
    stat.directory?
  elsif @directory
    stat.directory? || ascii_file?(stat, path)
  else
    ascii_file?(stat, path)
  end
rescue SystemCallError => e
  warn "Caught #{e.class}: #{e}"
  nil
end

def initialize(opts = {})

def initialize(opts = {})
  @args    = opts[:args] || {}
  @roots   = opts[:roots] || []
  @config = opts[:config] || Utils::Config::ConfigFile.new
  pattern_opts = opts.subhash(:pattern) | {
    :cset  => @args['a'],
    :icase => @args['i'],
  }
  @binary = @args['b']
  @pattern = @args['r'] ?
    RegexpPattern.new(pattern_opts) :
    FuzzyPattern.new(pattern_opts)
  @directory = @args['d']
  @only_directory = @args['D']
  @paths  = []
end

def search

def search
  paths = []
  suffixes = @args['I'].ask_and_send(:split, /[\s,]+/).to_a
  find(*(@roots + [ { :suffix => suffixes } ])) do |filename|
    begin
      bn, s = filename.pathname.basename, filename.stat
      if !s || s.directory? && @config.discover.prune?(bn)
        @args['v'] and warn "Pruning #{filename.inspect}."
        prune
      end
      if s.file? && @config.discover.skip?(bn)
        @args['v'] and warn "Skipping #{filename.inspect}."
        next
      end
      paths << filename
    end
  end
  paths.uniq!
  paths.map! { |p| a = File.split(p) ; a.unshift(p) ; a }
  paths = paths.map! do |path, dir, file|
    if do_match = attempt_match?(path) and @args['v']
      warn "Attempt match of #{path.inspect}"
    end
    if do_match and match = @pattern.match(file)
      if FuzzyPattern === @pattern
        current = 0
        marked_file = ''
        score, e = 0, 0
        for i in 1...(match.size)
          match[i] or next
          b = match.begin(i)
          marked_file << file[current...b]
          marked_file << red(file[b, 1])
          score += (b - e)
          e = match.end(i)
          current = b + 1
        end
        marked_file << match.post_match
        [ score, file.size, path, File.join(dir, marked_file) ]
      else
        marked_file = file[0...match.begin(0)] <<
          red(file[match.begin(0)...match.end(0)]) <<
          file[match.end(0)..-1]
        [ 0, file.size, path, File.join(dir, marked_file) ]
      end
    end
  end
  paths.compact!
  @paths, @output = paths.sort.transpose.values_at(-2, -1)
  if !@args['e'] && @output && !@output.empty?
    yield @output if block_given?
  end
  self
end