diff --git a/ki-shell/pom.xml b/ki-shell/pom.xml index 26cca23..917d4c1 100644 --- a/ki-shell/pom.xml +++ b/ki-shell/pom.xml @@ -4,7 +4,7 @@ org.jetbrains.kotlinx ki - 0.4.5-SNAPSHOT + 0.4.5 ki-shell diff --git a/ki-shell/src/main/kotlin/org/jetbrains/kotlinx/ki/shell/parser/KotlinParserListenerForHighlighting.kt b/ki-shell/src/main/kotlin/org/jetbrains/kotlinx/ki/shell/parser/KotlinParserListenerForHighlighting.kt index 943b0d4..6a911e0 100644 --- a/ki-shell/src/main/kotlin/org/jetbrains/kotlinx/ki/shell/parser/KotlinParserListenerForHighlighting.kt +++ b/ki-shell/src/main/kotlin/org/jetbrains/kotlinx/ki/shell/parser/KotlinParserListenerForHighlighting.kt @@ -6,6 +6,20 @@ import org.antlr.v4.runtime.tree.ErrorNode import org.antlr.v4.runtime.tree.TerminalNode import org.jetbrains.kotlinx.ki.shell.parser.KotlinParser.* +/** + * Magic constants are taken from official grammar. + * https://kotlinlang.org/docs/reference/grammar.html#ifExpression + * https://kotlinlang.org/docs/reference/grammar.html#forStatement + * https://kotlinlang.org/docs/reference/grammar.html#whileStatement + * https://kotlinlang.org/docs/reference/grammar.html#doWhileStatement + * The goal is navigating to the sub-elements not directly represented in it and + * granular control over keywords space to be taken into account by highlighting. + */ +private const val IF_EXPR_OFFSET = 2 +private const val ELSE_OFFSET = 4 +private const val FOR_EXPR_OFFSET = 3 +private const val WHILE_EXPR_OFFSET = 5 + /** * This class provides an empty implementation of [KotlinParserListener], * which can be extended to create a listener which only needs to handle a subset @@ -82,6 +96,12 @@ class KotlinParserListenerForHighlighting : KotlinParserListener { } } + fun highlightKeywordWithOffset(ctx: ParserRuleContext, start: Int, offset: Int) { + exitHighlightingElement(ctx) + result.add(ElementWithPos(start, start + offset, RecogizedElements.Keyword)) + lastElementStart = start + } + override fun enterKotlinFile(ctx: KotlinFileContext) {} override fun exitKotlinFile(ctx: KotlinFileContext) {} @@ -401,13 +421,13 @@ class KotlinParserListenerForHighlighting : KotlinParserListener { override fun exitLoopStatement(ctx: LoopStatementContext) {} override fun enterForStatement(ctx: ForStatementContext) { - enterHighlightingKeyword(ctx) + highlightKeywordWithOffset(ctx, ctx.start.startIndex, FOR_EXPR_OFFSET) } override fun exitForStatement(ctx: ForStatementContext) {} override fun enterWhileStatement(ctx: WhileStatementContext) { - enterHighlightingKeyword(ctx) + highlightKeywordWithOffset(ctx, ctx.start.startIndex, WHILE_EXPR_OFFSET) } override fun exitWhileStatement(ctx: WhileStatementContext) {} @@ -416,7 +436,10 @@ class KotlinParserListenerForHighlighting : KotlinParserListener { enterHighlightingKeyword(ctx) } - override fun exitDoWhileStatement(ctx: DoWhileStatementContext) {} + override fun exitDoWhileStatement(ctx: DoWhileStatementContext) { + val whileToken = ctx.WHILE().symbol + highlightKeywordWithOffset(ctx, whileToken.startIndex, WHILE_EXPR_OFFSET) + } override fun enterAssignment(ctx: AssignmentContext) {} @@ -649,10 +672,13 @@ class KotlinParserListenerForHighlighting : KotlinParserListener { override fun exitSuperExpression(ctx: SuperExpressionContext) {} override fun enterIfExpression(ctx: IfExpressionContext) { - enterHighlightingKeyword(ctx) + highlightKeywordWithOffset(ctx, ctx.start.startIndex, IF_EXPR_OFFSET) } - override fun exitIfExpression(ctx: IfExpressionContext) {} + override fun exitIfExpression(ctx: IfExpressionContext) { + val elseToken = ctx.ELSE().symbol + highlightKeywordWithOffset(ctx, elseToken.startIndex, ELSE_OFFSET) + } override fun enterWhenSubject(ctx: WhenSubjectContext) { exitHighlightingElement(ctx) diff --git a/ki-shell/src/test/kotlin/org/jetbrains/kotlinx/ki/shell/plugins/KotlinHighlighterTest.kt b/ki-shell/src/test/kotlin/org/jetbrains/kotlinx/ki/shell/plugins/KotlinHighlighterTest.kt index 06caf76..cbf6af2 100644 --- a/ki-shell/src/test/kotlin/org/jetbrains/kotlinx/ki/shell/plugins/KotlinHighlighterTest.kt +++ b/ki-shell/src/test/kotlin/org/jetbrains/kotlinx/ki/shell/plugins/KotlinHighlighterTest.kt @@ -99,6 +99,42 @@ class KotlinHighlighterTest : TestCase() { assertEquals("fun const(x: P, y: K): P = x", ht.highlight("fun const(x: P, y: K): P = x").mnemonics()) } + @Test + fun testIfElse() { + val ht = KotlinHighlighter( styles.filter(listOf(keyword, parenthesis)) ) + assertEquals( + "kkk(1 > 2) 11 kkkkkkkk(1 > 2) { 12 } kkkkk{ 13 }", + ht.highlight("if (1 > 2) 11 else if (1 > 2) { 12 } else { 13 }").mnemonics() + ) + } + + @Test + fun testForLoop() { + val ht = KotlinHighlighter( styles.filter(listOf(keyword, parenthesis)) ) + assertEquals( + "kkkk(x in \"gg\") x + 1", + ht.highlight("for (x in \"gg\") x + 1").mnemonics() + ) + } + + @Test + fun testWhileLoop() { + val ht = KotlinHighlighter( styles.filter(listOf(keyword, parenthesis)) ) + assertEquals( + "kkkkkk(1 > 2) { 1 + 2 }", + ht.highlight("while (1 > 2) { 1 + 2 }").mnemonics() + ) + } + + @Test + fun testDoWhileLoop() { + val ht = KotlinHighlighter( styles.filter(listOf(keyword, parenthesis)) ) + assertEquals( + "kkk{ 1 + 2 } kkkkkk(1 > 2)", + ht.highlight("do { 1 + 2 } while (1 > 2)").mnemonics() + ) + } + private fun Map.filter(list: List): HighlightStylesFromMap = HighlightStylesFromMap(map { if (list.contains(it.key)) Pair(it.key, it.value) else Pair(it.key, null) }.toMap()) diff --git a/pom.xml b/pom.xml index ba46ed2..f1f0e80 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ org.jetbrains.kotlinx ki - 0.4.5-SNAPSHOT + 0.4.5 pom Ki Shell :: parent