diff --git a/shared/src/main/scala/scala/util/parsing/input/OffsetPosition.scala b/shared/src/main/scala/scala/util/parsing/input/OffsetPosition.scala index cb72ec80..f8c573b0 100644 --- a/shared/src/main/scala/scala/util/parsing/input/OffsetPosition.scala +++ b/shared/src/main/scala/scala/util/parsing/input/OffsetPosition.scala @@ -34,10 +34,14 @@ case class OffsetPosition(source: CharSequence, offset: Int) extends Position { private def genIndex: Array[Int] = { val lineStarts = new ArrayBuffer[Int] - lineStarts += 0 - for (i <- 0 until source.length) - if (source.charAt(i) == '\n') lineStarts += (i + 1) - lineStarts += source.length + lineStarts += 0 // first line + for (i <- 1 until source.length) { + if (source.charAt(i - 1) == '\n') // \n or \r\n + lineStarts += i + else if (source.charAt(i - 1) == '\r' && source.charAt(i) != '\n') // \r but not \r\n + lineStarts += i + } + lineStarts += source.length // eof lineStarts.toArray } @@ -63,11 +67,14 @@ case class OffsetPosition(source: CharSequence, offset: Int) extends Position { def lineContents: String = { val lineStart = index(line - 1) val lineEnd = index(line) - val endIndex = if ( lineStart < lineEnd && source.charAt(lineEnd - 1) == '\n') { - lineEnd - 1 - } else { - lineEnd - } + val endIndex = + if (lineStart < lineEnd - 1 && source.charAt(lineEnd - 2) == '\r' && source.charAt(lineEnd - 1) == '\n') { + lineEnd - 2 + } else if (lineStart < lineEnd && (source.charAt(lineEnd - 1) == '\r' || source.charAt(lineEnd - 1) == '\n')) { + lineEnd - 1 + } else { + lineEnd + } source.subSequence(lineStart, endIndex).toString } diff --git a/shared/src/test/scala/scala/util/parsing/combinator/t5669.scala b/shared/src/test/scala/scala/util/parsing/combinator/t5669.scala new file mode 100644 index 00000000..a03f4d6a --- /dev/null +++ b/shared/src/test/scala/scala/util/parsing/combinator/t5669.scala @@ -0,0 +1,14 @@ +package scala.util.parsing.combinator + +import scala.util.parsing.input.OffsetPosition + +import org.junit.Test +import org.junit.Assert.assertEquals + +class t5669 { + @Test + def test: Unit = { + val op = new OffsetPosition("foo\rbar", 4) + assertEquals(2, op.line) + } +} diff --git a/shared/src/test/scala/scala/util/parsing/input/OffsetPositionTest.scala b/shared/src/test/scala/scala/util/parsing/input/OffsetPositionTest.scala index bbd9c9c4..cda8f6f0 100644 --- a/shared/src/test/scala/scala/util/parsing/input/OffsetPositionTest.scala +++ b/shared/src/test/scala/scala/util/parsing/input/OffsetPositionTest.scala @@ -5,14 +5,44 @@ import org.junit.Assert.assertEquals class OffsetPositionTest { @Test - def printLineContentsWithTrailingNewLine: Unit = { + def lineContentsWithTrailingLF: Unit = { val op = new OffsetPosition("\n", 1) - assertEquals(op.lineContents, "") + assertEquals("", op.lineContents) } @Test - def printLineContentsWithEmptySource: Unit = { + def lineContentsWithTrailingCR: Unit = { + val op = new OffsetPosition("\r", 1) + assertEquals("", op.lineContents) + } + + @Test + def lineContentsWithTrailingCRLF: Unit = { + val op = new OffsetPosition("\r\n", 1) + assertEquals("", op.lineContents) + } + + @Test + def lineContentsWithEmptySource: Unit = { val op = new OffsetPosition("", 0) - assertEquals(op.lineContents, "") + assertEquals("", op.lineContents) + } + + @Test + def linesWithLF: Unit = { + val op = new OffsetPosition("foo\nbar", 4) + assertEquals(2, op.line) + } + + @Test + def linesWithCR: Unit = { + val op = new OffsetPosition("foo\rbar", 4) + assertEquals(2, op.line) + } + + @Test + def linesWithCRLF: Unit = { + val op = new OffsetPosition("foo\r\nbar", 5) + assertEquals(2, op.line) } }