Phase 2: commenter and brace matcher

Brace matching pairs the Jai-specific single-token openers .{ and .[ with the
ordinary } and ]; verified headlessly through the editor highlighter.
This commit is contained in:
hgranthorner
2026-08-04 10:29:43 -04:00
parent 2c5d7f713b
commit fa15109f0b
3 changed files with 115 additions and 0 deletions

View File

@@ -0,0 +1,52 @@
package dev.hgh.jai.editor
import com.intellij.lang.BracePair
import com.intellij.lang.Commenter
import com.intellij.lang.PairedBraceMatcher
import com.intellij.psi.PsiFile
import com.intellij.psi.tree.IElementType
import dev.hgh.jai.lexer.JaiTokenTypes
/** `//` line comments and nesting `/* */` block comments (language reference §2). */
class JaiCommenter : Commenter {
override fun getLineCommentPrefix(): String = "//"
override fun getBlockCommentPrefix(): String = "/*"
override fun getBlockCommentSuffix(): String = "*/"
// Jai block comments nest, so a commented-out region can be commented again.
override fun getCommentedBlockCommentPrefix(): String = "/*"
override fun getCommentedBlockCommentSuffix(): String = "*/"
}
/**
* Brace matching. Note the two Jai-specific openers: `.{` starts a struct literal and
* `.[` starts an array literal (language reference §14.4) — they are single tokens, and
* close with an ordinary `}` / `]`.
*/
class JaiBraceMatcher : PairedBraceMatcher {
override fun getPairs(): Array<BracePair> = PAIRS
override fun isPairedBracesAllowedBeforeType(
lbraceType: IElementType,
next: IElementType?,
): Boolean = true
override fun getCodeConstructStart(
file: PsiFile?,
openingBraceOffset: Int,
): Int = openingBraceOffset
companion object {
private val PAIRS =
arrayOf(
BracePair(JaiTokenTypes.LBRACE, JaiTokenTypes.RBRACE, true),
BracePair(JaiTokenTypes.LPAREN, JaiTokenTypes.RPAREN, false),
BracePair(JaiTokenTypes.LBRACKET, JaiTokenTypes.RBRACKET, false),
BracePair(JaiTokenTypes.BEGIN_STRUCT_LITERAL, JaiTokenTypes.RBRACE, false),
BracePair(JaiTokenTypes.BEGIN_ARRAY_LITERAL, JaiTokenTypes.RBRACKET, false),
)
}
}