Skip to content

Commit

Permalink
add in more test covereage for rangeFormatting and empty line support
Browse files Browse the repository at this point in the history
  • Loading branch information
ckipp01 committed Oct 11, 2019
1 parent 7891c17 commit 5b0d559
Show file tree
Hide file tree
Showing 2 changed files with 137 additions and 49 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,23 @@ import org.eclipse.lsp4j.Position

/*in order to use onTypeFormatting in vscode,
you'll have to set editor.formatOnType = true
and editor.formatOnPaste = true in settings*/
and editor.formatOnPaste= true in settings*/
final class MultilineStringFormattingProvider(
semanticdbs: Semanticdbs,
buffer: Buffers
semanticdbs: Semanticdbs,
buffer: Buffers
)(implicit ec: ExecutionContext) {

private val quote = '"'
private val space = " "
private val stripMargin = "stripMargin"

private def hasStripMarginSuffix(stringTokenIndex: Int,
tokens: Tokens): Boolean = {
private def hasStripMarginSuffix(
stringTokenIndex: Int,
tokens: Tokens
): Boolean = {
var methodIndex = stringTokenIndex + 1
while (tokens(methodIndex).isWhiteSpaceOrComment ||
tokens(methodIndex).isInstanceOf[Token.Dot]) methodIndex += 1
tokens(methodIndex).isInstanceOf[Token.Dot]) methodIndex += 1
tokens(methodIndex) match {
case token: Token.Ident if token.value == stripMargin =>
true
Expand All @@ -43,16 +45,18 @@ final class MultilineStringFormattingProvider(

private def charIsPipe(charToCheck: Char): Boolean = charToCheck == '|'

private def indent(sourceText: String, start: Int): String = {
private def determineDefaultIndent(sourceText: String, start: Int): String = {
val lastPipe = sourceText.lastIndexBetween('|', upperBound = start)
val lastNewline = sourceText.lastIndexBetween('\n', upperBound = lastPipe)
space * (lastPipe - lastNewline - 1)
}

private def indent(sourceText: String,
start: Int,
position: Position): TextEdit = {
val defaultIndent = indent(sourceText, start)
private def indent(
sourceText: String,
start: Int,
position: Position
): TextEdit = {
val defaultIndent = determineDefaultIndent(sourceText, start)
val existingSpaces = position.getCharacter()
val addedSpaces = defaultIndent.drop(existingSpaces)
val startChar = defaultIndent.size - addedSpaces.size
Expand All @@ -73,9 +77,11 @@ final class MultilineStringFormattingProvider(
pos.start >= token.start && pos.end <= token.end
}

private def pipeInScope(pos: meta.Position,
text: String,
newlineAdded: Boolean): Boolean = {
private def pipeInScope(
pos: meta.Position,
text: String,
newlineAdded: Boolean
): Boolean = {
val newLineBeforePos =
text.lastIndexBetween('\n', upperBound = pos.start - 1)
val pipeSearchStop =
Expand All @@ -86,9 +92,11 @@ final class MultilineStringFormattingProvider(
lastPipe > pipeSearchStop
}

private def multilineStringInTokens(tokens: Tokens,
pos: meta.Position,
sourceText: String): Boolean = {
private def multilineStringInTokens(
tokens: Tokens,
pos: meta.Position,
sourceText: String
): Boolean = {
var tokenIndex = 0
var stringFound = false
var shouldAddPipes = false
Expand All @@ -101,7 +109,7 @@ final class MultilineStringFormattingProvider(
case start: Interpolation.Start if start.start < pos.start =>
var endIndex = tokenIndex + 1
while (!tokens(endIndex)
.isInstanceOf[Interpolation.End]) endIndex += 1
.isInstanceOf[Interpolation.End]) endIndex += 1
val end = tokens(endIndex)
stringFound = end.end > pos.end
shouldAddPipes = stringFound && isMultilineString(sourceText, start) &&
Expand All @@ -114,9 +122,9 @@ final class MultilineStringFormattingProvider(
}

private def withToken(
textId: TextDocumentIdentifier,
range: Range,
newlineAdded: Boolean
textId: TextDocumentIdentifier,
range: Range,
newlineAdded: Boolean
)(fn: (String, meta.Position) => List[TextEdit]): Future[List[TextEdit]] =
Future {
val source = textId.getUri.toAbsolutePath
Expand All @@ -135,6 +143,45 @@ final class MultilineStringFormattingProvider(
} else Nil
}

private def formatPipeLine(
line: Int,
lines: Array[String],
defaultIndent: String
): TextEdit = {
val zeroPos = new Position(line, 0)
val lineText = lines(line)
val firstChar = lineText.trim.headOption

firstChar match {
case Some(char) =>
if (charIsPipe(char)) {
val firstPipeIndex = lineText.indexOf('|')
val firstCharAfterPipe = lineText.trim.tail.trim.headOption

firstCharAfterPipe match {
case Some(char) =>
if (charIsPipe(char)) {
val secondPipeIndex = lineText.indexOf('|', firstPipeIndex + 1)
val secondPipePos = new Position(line, secondPipeIndex)
new TextEdit(new Range(zeroPos, secondPipePos), defaultIndent)
} else {
val pipePos = new Position(line, firstPipeIndex)
new TextEdit(new Range(zeroPos, pipePos), defaultIndent)
}
case None =>
val pipePos = new Position(line, firstPipeIndex)
new TextEdit(new Range(zeroPos, pipePos), defaultIndent)
}
} else {
val newText = defaultIndent + "|"
new TextEdit(new Range(zeroPos, zeroPos), newText)
}
case None =>
val newText = defaultIndent + "|"
new TextEdit(new Range(zeroPos, zeroPos), newText)
}
}

def format(params: DocumentOnTypeFormattingParams): Future[List[TextEdit]] = {
val range = new Range(params.getPosition, params.getPosition)
val doc = params.getTextDocument()
Expand All @@ -150,34 +197,14 @@ final class MultilineStringFormattingProvider(
val doc = params.getTextDocument()
withToken(doc, range, newlineAdded = false) { (sourceText, position) =>
val splitLines = sourceText.split('\n')
val defaultIndent = indent(sourceText, position.start)
val linesToFormat = (range.getStart().getLine()) to range.getEnd().getLine()

linesToFormat.map { line =>
val zeroPos = new Position(line, 0)
val lineText = splitLines(line)
val firstChar = lineText.trim.head
if (charIsPipe(firstChar)) {
val firstPipeIndex = lineText.indexOf('|')

/* There may be an existing pipe on the line the text
was pasted into. We need to see if the first char after
the initial pipe is also a pipe confirming a multilineString
being pasted into another multilineString*/
val firstCharAfterPipe = lineText.trim.tail.trim.head
if (charIsPipe(firstCharAfterPipe)) {
val secondPipeIndex = lineText.indexOf('|', firstPipeIndex + 1)
val secondPipePos = new Position(line, secondPipeIndex)
new TextEdit(new Range(zeroPos, secondPipePos), defaultIndent)
} else {
val pipePos = new Position(line, firstPipeIndex)
new TextEdit(new Range(zeroPos, pipePos), defaultIndent)
}
} else {
val newText = defaultIndent + "|"
new TextEdit(new Range(zeroPos, zeroPos), newText)
}
}.toList
val defaultIndent = determineDefaultIndent(sourceText, position.start)
val linesToFormat = (range.getStart().getLine()) to range
.getEnd()
.getLine()

linesToFormat
.map(line => formatPipeLine(line, splitLines, defaultIndent))
.toList
}
}

Expand Down
61 changes: 61 additions & 0 deletions tests/unit/src/test/scala/tests/RangeFormattingSuite.scala
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,67 @@ object RangeFormattingSuite extends BaseSlowSuite("rangeFormatting") {
|}""".stripMargin
)

check(
"with-pipe",
s"""
|object Main {
| val str = '''
| |@@
| '''.stripMargin
|}""".stripMargin,
s"""| |single line
|""".stripMargin,
s"""
|object Main {
| val str = '''
| |single line
| |
| '''.stripMargin
|}""".stripMargin
)

check(
"with-pipes",
s"""
|object Main {
| val str = '''
| |@@
| '''.stripMargin
|}""".stripMargin,
s"""| |first line
| |second line
| | different indent""".stripMargin,
s"""
|object Main {
| val str = '''
| |first line
| |second line
| | different indent
| '''.stripMargin
|}""".stripMargin
)

check(
"with-pipes-skip-line",
s"""
|object Main {
| val str = '''
| |@@
| '''.stripMargin
|}""".stripMargin,
s"""| |first line
|
| |second line""".stripMargin,
s"""
|object Main {
| val str = '''
| |first line
| |
| |second line
| '''.stripMargin
|}""".stripMargin
)

def check(
name: String,
testCase: String,
Expand Down

0 comments on commit 5b0d559

Please sign in to comment.