Skip to content

Commit c3f8797

Browse files
authored
Merge pull request #164 from Philippus/issue-5669
Support '\r' and '\r\n' line endings, closes scala/bug#5669
2 parents 0a8f96c + 7fe2897 commit c3f8797

File tree

3 files changed

+64
-13
lines changed

3 files changed

+64
-13
lines changed

shared/src/main/scala/scala/util/parsing/input/OffsetPosition.scala

+16-9
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,14 @@ case class OffsetPosition(source: CharSequence, offset: Int) extends Position {
3434

3535
private def genIndex: Array[Int] = {
3636
val lineStarts = new ArrayBuffer[Int]
37-
lineStarts += 0
38-
for (i <- 0 until source.length)
39-
if (source.charAt(i) == '\n') lineStarts += (i + 1)
40-
lineStarts += source.length
37+
lineStarts += 0 // first line
38+
for (i <- 1 until source.length) {
39+
if (source.charAt(i - 1) == '\n') // \n or \r\n
40+
lineStarts += i
41+
else if (source.charAt(i - 1) == '\r' && source.charAt(i) != '\n') // \r but not \r\n
42+
lineStarts += i
43+
}
44+
lineStarts += source.length // eof
4145
lineStarts.toArray
4246
}
4347

@@ -63,11 +67,14 @@ case class OffsetPosition(source: CharSequence, offset: Int) extends Position {
6367
def lineContents: String = {
6468
val lineStart = index(line - 1)
6569
val lineEnd = index(line)
66-
val endIndex = if ( lineStart < lineEnd && source.charAt(lineEnd - 1) == '\n') {
67-
lineEnd - 1
68-
} else {
69-
lineEnd
70-
}
70+
val endIndex =
71+
if (lineStart < lineEnd - 1 && source.charAt(lineEnd - 2) == '\r' && source.charAt(lineEnd - 1) == '\n') {
72+
lineEnd - 2
73+
} else if (lineStart < lineEnd && (source.charAt(lineEnd - 1) == '\r' || source.charAt(lineEnd - 1) == '\n')) {
74+
lineEnd - 1
75+
} else {
76+
lineEnd
77+
}
7178
source.subSequence(lineStart, endIndex).toString
7279
}
7380

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package scala.util.parsing.combinator
2+
3+
import scala.util.parsing.input.OffsetPosition
4+
5+
import org.junit.Test
6+
import org.junit.Assert.assertEquals
7+
8+
class t5669 {
9+
@Test
10+
def test: Unit = {
11+
val op = new OffsetPosition("foo\rbar", 4)
12+
assertEquals(2, op.line)
13+
}
14+
}

shared/src/test/scala/scala/util/parsing/input/OffsetPositionTest.scala

+34-4
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,44 @@ import org.junit.Assert.assertEquals
55

66
class OffsetPositionTest {
77
@Test
8-
def printLineContentsWithTrailingNewLine: Unit = {
8+
def lineContentsWithTrailingLF: Unit = {
99
val op = new OffsetPosition("\n", 1)
10-
assertEquals(op.lineContents, "")
10+
assertEquals("", op.lineContents)
1111
}
1212

1313
@Test
14-
def printLineContentsWithEmptySource: Unit = {
14+
def lineContentsWithTrailingCR: Unit = {
15+
val op = new OffsetPosition("\r", 1)
16+
assertEquals("", op.lineContents)
17+
}
18+
19+
@Test
20+
def lineContentsWithTrailingCRLF: Unit = {
21+
val op = new OffsetPosition("\r\n", 1)
22+
assertEquals("", op.lineContents)
23+
}
24+
25+
@Test
26+
def lineContentsWithEmptySource: Unit = {
1527
val op = new OffsetPosition("", 0)
16-
assertEquals(op.lineContents, "")
28+
assertEquals("", op.lineContents)
29+
}
30+
31+
@Test
32+
def linesWithLF: Unit = {
33+
val op = new OffsetPosition("foo\nbar", 4)
34+
assertEquals(2, op.line)
35+
}
36+
37+
@Test
38+
def linesWithCR: Unit = {
39+
val op = new OffsetPosition("foo\rbar", 4)
40+
assertEquals(2, op.line)
41+
}
42+
43+
@Test
44+
def linesWithCRLF: Unit = {
45+
val op = new OffsetPosition("foo\r\nbar", 5)
46+
assertEquals(2, op.line)
1747
}
1848
}

0 commit comments

Comments
 (0)