@@ -76,6 +76,15 @@ def slice(byte_offset, length)
7676 source . byteslice ( byte_offset , length ) or raise
7777 end
7878
79+ # Converts the line number to a byte offset corresponding to the start of that line
80+ def line_to_byte_offset ( line )
81+ l = line - @start_line
82+ if l < 0 || l >= offsets . size
83+ raise ArgumentError , "line #{ line } is out of range"
84+ end
85+ offsets [ l ]
86+ end
87+
7988 # Binary search through the offsets to find the line number for the given
8089 # byte offset.
8190 def line ( byte_offset )
@@ -145,9 +154,10 @@ def code_units_column(byte_offset, encoding)
145154
146155 # Returns the byte offset for a given line number and column number
147156 def line_and_character_column_to_byte_offset ( line , column )
148- line_start = offsets [ line - 1 ]
149- line_end = offsets [ line ]
150- byte_column = ( @source . byteslice ( line_start , line_end ) or raise ) [ 0 ...column ] &.bytesize #: Integer
157+ line_start = line_to_byte_offset ( line )
158+ line_end = offsets [ line + 1 - @start_line ] || source . bytesize
159+ byteslice = @source . byteslice ( line_start , line_end ) or raise ArgumentError , "line #{ line } is out of range"
160+ byte_column = ( byteslice [ 0 ...column ] or raise ) . bytesize
151161 line_start + byte_column
152162 end
153163
@@ -284,8 +294,7 @@ def code_units_column(byte_offset, encoding)
284294 # Specialized version of `line_and_character_column_to_byte_offset`
285295 # which does not need to access the source String
286296 def line_and_character_column_to_byte_offset ( line , column )
287- line_start = offsets [ line - 1 ]
288- line_start + column
297+ line_to_byte_offset ( line ) + column
289298 end
290299 end
291300
0 commit comments