module Pluginscan class ErrorListPrinter < Printer def initialize(hide_ignores = false, output = $stdout) @hide_ignores = hide_ignores @output = output @line_printer = ErrorLinePrinter.new end def print(data) issues = data[:issues] @output.puts error_lines(issues) end # TODO: this should be the print method; return an array of lines, and let the caller be responsible for outputting it def error_lines(issues) issues.inject([]) do |output, (file, file_findings)| output + file_error_lines(file, file_findings) end end private def file_error_lines(file, file_findings) file_findings.inject([]) do |checks_output, check_findings| checks_output + check_output(file, check_findings.check, check_findings.findings) end end private def check_output(file, check, findings) findings.reject!(&:ignored) if @hide_ignores findings.map do |finding| error_line = ErrorLineFactory.build(file, check.name, finding) @line_printer.print(error_line) end end end class ErrorLinePrinter def print(el) "\"#{el.file}\", line #{el.line_number}, col #{el.column_number}: #{el.message}" end end # This is almost like a view model: exposes methods for use in a template class ErrorLine attr_reader :file def initialize(file, check_name, finding) @file = file @check_name = check_name @finding = PrintableFinding.new(finding) end def line_number # TODO: why is the original called lineno?? That's a rubbish name! @finding.lineno end def column_number @finding.col_number end def message "[#{@check_name}] #{@finding.line}" end end class IgnoredErrorLine < ErrorLine # TODO: would decoration be better here? def message super.sub("]", "][IGNORE]") end end class ErrorLineFactory def self.build(file, check_name, finding) klass(finding.ignored).new(file, check_name, finding) end def self.klass(ignored) ignored ? IgnoredErrorLine : ErrorLine end end class PrintableFinding < SimpleDelegator def col_number # Seems like vim treats tabs as single spaces for the purposes of calculating columns - at least on my setup # so we don't need to expand the tabs __getobj__.line.index(match) + 1 end def line escape_special_chars(__getobj__.line.strip) end private def escape_special_chars(string) # Vim interprets `:` as a delimiter string.gsub(":", '\:') end end end