module BetterHtml class NodeIterator class Location attr_accessor :start, :stop def initialize(document, start, stop, line = nil, column = nil) @document = document @start = start @stop = stop @line = line @column = column end def range Range.new(start, stop-1) end def source @document[range] end def line @line ||= calculate_line end def column @column ||= calculate_column end def line_source_with_underline line_content = @document.lines[line-1] line_content = line_content.nil? ? "" : line_content.gsub(/\n$/, '') spaces = line_content.scan(/\A\s*/).first column_without_spaces = column - spaces.length underscore_length = [[stop - start, line_content.length - column_without_spaces].min, 1].max "#{line_content.gsub(/\A\s*/, '')}\n#{' ' * column_without_spaces}#{'^' * underscore_length}" end private def calculate_line @document[0..start-1].scan("\n").count + 1 end def calculate_column @document[0..start-1]&.split("\n", -1)&.last&.length || 0 end end end end