class Parslet::Source::LineCache

A cache for line start positions.

Public Class Methods

new() click to toggle source
# File lib/parslet/source/line_cache.rb, line 7
def initialize
  # Stores line endings as a simple position number. The first line always
  # starts at 0; numbers beyond the biggest entry are on any line > size, 
  # but probably make a scan to that position neccessary.
  @line_ends = []
  @line_ends.extend RangeSearch
  @last_line_end = nil
end

Public Instance Methods

line_and_column(pos) click to toggle source

Returns a <line, column> tuple for the given input position. Input position must be given as byte offset into original string.

# File lib/parslet/source/line_cache.rb, line 19
def line_and_column(pos)
  pos = pos.bytepos if pos.respond_to? :bytepos
  eol_idx = @line_ends.lbound(pos)

  if eol_idx
    # eol_idx points to the offset that ends the current line.
    # Let's try to find the offset that starts it: 
    offset = eol_idx>0 && @line_ends[eol_idx-1] || 0
    return [eol_idx+1, pos-offset+1]
  else
    # eol_idx is nil, that means that we're beyond the last line end that
    # we know about. Pretend for now that we're just on the last line.
    offset = @line_ends.last || 0
    return [@line_ends.size+1, pos-offset+1]
  end
end
scan_for_line_endings(start_pos, buf) click to toggle source
# File lib/parslet/source/line_cache.rb, line 36
def scan_for_line_endings(start_pos, buf)
  return unless buf

  buf = StringScanner.new(buf)
  return unless buf.exist?(/\n/)

  ## If we have already read part or all of buf, we already know about
  ## line ends in that portion. remove it and correct cur (search index)
  if @last_line_end && start_pos < @last_line_end
    # Let's not search the range from start_pos to last_line_end again.
    buf.pos = @last_line_end - start_pos
  end

  ## Scan the string for line endings; store the positions of all endings
  ## in @line_ends. 
  while buf.skip_until(/\n/)
    @last_line_end = start_pos + buf.pos
    @line_ends << @last_line_end
  end
end