module VER
  class Executor
    # Grepping made easy
    class ExGrep < Entry
      def setup
        @root = caller.project_root || Pathname(Dir.pwd)

        tree.configure(
          show: [:headings],
          columns:        %w[file line source],
          displaycolumns: %w[file line source]
        )
        tree.heading('file', text: 'File')
        tree.heading('line', text: 'Line')
        tree.heading('source', text: 'Source')
      end

      def after_update
        total = tree.winfo_width - 50

        tree.column('file',   width: (total * 0.3).to_i, stretch: false, anchor: :w)
        tree.column('line',   width: 50, stretch: false, anchor: :e)
        tree.column('source', width: (total * 0.7).to_i, stretch: false, anchor: :w)
      end

      def choices(glob_needle)
        choices = []

        return [] if glob_needle =~ /^\s*$/

        glob, needle = glob_needle.split(/\s+/, 2)
        unless needle
          needle = glob
          glob = '*'
          self.value = "#{glob} #{needle}"
        end

        return [] if needle =~ /^\s*$/

        begin
          regexp = Regexp.new(needle)
        rescue RegexpError, SyntaxError
          regexp = Regexp.new(Regexp.escape(needle))
        end

        grep_with(glob, regexp)
      end

      def grep_with(glob, regexp, with_root = true)
        results = []
        root = with_root ? @root / glob : glob

        root.glob do |path|
          next unless path.file?

          path.open do |io|
            begin
              io.each_line.with_index do |line, index|
                next unless line =~ regexp
                results << [path.to_s, index + 1, line]
              end
            rescue ArgumentError # why isn't that RegexpError or EncodingError
            end
          end
        end

        results
      end

      def action(_selected)
        item = tree.focus_item
        file, line, = item.options(:values)
        return unless file && line
        VER.find_or_create_buffer(file.to_s, line.to_i)
        callback.destroy(false)
      end

      # Ignore sync
      def sync_value_with_tree_selection; end
    end

    # Grep the open buffers interactively
    class ExGrepBuffers < ExGrep
      def choices(needle)
        choices = []
        return choices if needle =~ /^\s*$/

        files = VER.buffers.map { |_name, buffer| buffer.filename }
        glob = Pathname("{#{files.join(',')}}")

        begin
          regexp = Regexp.new(needle)
        rescue RegexpError, SyntaxError
          regexp = Regexp.new(Regexp.escape(needle))
        end

        grep_with(glob, regexp, false)
      end
    end
  end
end
