Skip to content

Commit d0c01ca

Browse files
som-snytttgodzik
authored andcommitted
Improve dentation at EOF
Check trailing blank line at EOF for OUTDENT If EOF is preceded by only spaces on the last line, do not outdent because it will complain about alignment during an edit. Preserve EOF token when probing arrow EOL For REPL, `: x =>` at EOF sees an EOF in order to detect lambda eol.
1 parent 0ac0542 commit d0c01ca

File tree

3 files changed

+26
-3
lines changed

3 files changed

+26
-3
lines changed

compiler/src/dotty/tools/dotc/parsing/Scanners.scala

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -601,6 +601,20 @@ object Scanners {
601601
lastWidth = r.knownWidth
602602
newlineIsSeparating = r.isInstanceOf[InBraces]
603603

604+
// can emit OUTDENT if line is not non-empty blank line at EOF
605+
inline def isTrailingBlankLine: Boolean =
606+
token == EOF && {
607+
val end = buf.length - 1 // take terminal NL as empty last line
608+
val prev = buf.lastIndexWhere(!isWhitespace(_), end = end)
609+
prev < 0 || end - prev > 0 && isLineBreakChar(buf(prev))
610+
}
611+
612+
inline def canDedent: Boolean =
613+
lastToken != INDENT
614+
&& !isLeadingInfixOperator(nextWidth)
615+
&& !statCtdTokens.contains(lastToken)
616+
&& !isTrailingBlankLine
617+
604618
if newlineIsSeparating
605619
&& canEndStatTokens.contains(lastToken)
606620
&& canStartStatTokens.contains(token)
@@ -613,9 +627,8 @@ object Scanners {
613627
|| nextWidth == lastWidth && (indentPrefix == MATCH || indentPrefix == CATCH) && token != CASE then
614628
if currentRegion.isOutermost then
615629
if nextWidth < lastWidth then currentRegion = topLevelRegion(nextWidth)
616-
else if !isLeadingInfixOperator(nextWidth) && !statCtdTokens.contains(lastToken) && lastToken != INDENT then
630+
else if canDedent then
617631
currentRegion match
618-
case _ if token == EOF => // no OUTDENT at EOF
619632
case r: Indented =>
620633
insert(OUTDENT, offset)
621634
handleNewIndentWidth(r.enclosing, ir =>

compiler/src/dotty/tools/dotc/util/Chars.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ object Chars:
5050
}
5151

5252
/** Is character a whitespace character (but not a new line)? */
53-
def isWhitespace(c: Char): Boolean =
53+
inline def isWhitespace(c: Char): Boolean =
5454
c == ' ' || c == '\t' || c == CR
5555

5656
/** Can character form part of a doc comment variable $xxx? */

compiler/test/dotty/tools/repl/ReplCompilerTests.scala

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -400,6 +400,16 @@ class ReplCompilerTests extends ReplTest:
400400
assertTrue(all.head.startsWith("-- [E103] Syntax Error"))
401401
assertTrue(all.exists(_.trim().startsWith("| Illegal start of statement: this modifier is not allowed here")))
402402

403+
@Test def `i22844 regression colon eol`: Unit = initially:
404+
run:
405+
"""|println:
406+
| "hello, world"
407+
|""".stripMargin // outdent, but this test does not exercise the bug
408+
assertEquals(List("hello, world"), lines())
409+
410+
@Test def `i22844b regression colon arrow eol`: Unit = contextually:
411+
assertTrue(ParseResult.isIncomplete("List(42).map: x =>"))
412+
403413
object ReplCompilerTests:
404414

405415
private val pattern = Pattern.compile("\\r[\\n]?|\\n");

0 commit comments

Comments
 (0)