ammonite.interp.script.PositionOffsetConversion.scala Maven / Gradle / Ivy
package ammonite.interp.script
import scala.collection.mutable
object PositionOffsetConversion {
private def lineStartIndices(content: String): Array[Int] = {
val content0 = content.toCharArray
// adapted from scala/scala SourceFile.scala
val length = content0.length
val CR = '\r'
val LF = '\n'
def charAtIsEOL(idx: Int)(p: Char => Boolean) = {
// don't identify the CR in CR LF as a line break, since LF will do.
def notCRLF0 =
content0(idx) != CR ||
!content0.isDefinedAt(idx + 1) ||
content0(idx + 1) != LF
idx < length && notCRLF0 && p(content0(idx))
}
def isAtEndOfLine(idx: Int) = charAtIsEOL(idx) {
case CR | LF => true
case _ => false
}
val buf = new mutable.ArrayBuffer[Int]
buf += 0
for (i <- 0 until content0.length if isAtEndOfLine(i))
buf += i + 1
buf.toArray
}
/** Converts a character offset from beginning of `content` to a `Position` */
def offsetToPos(content: String): Int => Position = {
val lineStartIndices0 = lineStartIndices(content)
def offsetToLine(offset: Int): Int = {
assert(lineStartIndices0.nonEmpty)
if (offset >= lineStartIndices0.last) lineStartIndices0.length - 1
else {
def find(a: Int, b: Int): Int =
if (a + 1 >= b) a
else {
val c = (a + b) / 2
val idx = lineStartIndices0(c)
if (idx == offset) c
else if (idx < offset) find(c, b)
else find(a, c)
}
find(0, lineStartIndices0.length - 1)
}
}
offset =>
assert(offset >= 0)
assert(offset <= content.length)
val line = offsetToLine(offset)
Position(line, offset - lineStartIndices0(line))
}
private def indicesOf(input: String, elem: String): Array[Int] = {
val b = new mutable.ArrayBuffer[Int]
var idx = 0
while (idx >= 0 && idx < input.length) {
val nextIdx = input.indexOf(elem, idx)
if (nextIdx >= 0) {
b += nextIdx
idx = nextIdx + 1
} else
idx = -1
}
b.toArray
}
/** Returns the start and end indices of sections delimited by `start` and `end` in `input` */
def sections(input: String, start: String, end: String): Array[(Int, Int)] = {
val b = new mutable.ArrayBuffer[(Int, Int)]
var idx = 0
while (idx < input.length) {
val startIdx = input.indexOf(start, idx)
if (startIdx >= 0) {
val endIdx = input.indexOf(end, startIdx + start.length)
if (endIdx >= 0) {
idx = endIdx + end.length
b.append((startIdx, idx))
} else
idx = input.length
} else
idx = input.length
}
b.toArray
}
/** Removes sections delimited by `ignoreSections` from offset `idx` */
def extraOffset(ignoreSections: Seq[(Int, Int)], idx: Int): Int =
ignoreSections
.iterator
.takeWhile(_._2 <= idx)
.map {
case (start, end) =>
end - start
}
.sum
private val firstLineWrapperPrefix = "/*