support: basic idea plugin

This commit is contained in:
2023-09-10 01:27:53 -04:00
parent 0024a8b141
commit 0bc3128b9d
17 changed files with 298 additions and 9 deletions

View File

@ -0,0 +1,26 @@
package gay.pizza.pork.intellij
import com.intellij.openapi.fileTypes.LanguageFileType
import com.intellij.openapi.util.NlsContexts
import com.intellij.openapi.util.NlsSafe
import org.jetbrains.annotations.NonNls
import javax.swing.Icon
@Suppress("UnstableApiUsage")
object PorkFileType : LanguageFileType(PorkLanguage) {
override fun getName(): @NonNls String {
return "Pork File"
}
override fun getDescription(): @NlsContexts.Label String {
return "Pork file"
}
override fun getDefaultExtension(): @NlsSafe String {
return "pork"
}
override fun getIcon(): Icon {
return PorkIcon
}
}

View File

@ -0,0 +1,6 @@
package gay.pizza.pork.intellij
import com.intellij.openapi.util.IconLoader.getIcon
import javax.swing.Icon
val PorkIcon: Icon = getIcon("/icons/pork.png", PorkLanguage::class.java)

View File

@ -0,0 +1,5 @@
package gay.pizza.pork.intellij
import com.intellij.lang.Language
object PorkLanguage : Language("Pork")

View File

@ -0,0 +1,96 @@
package gay.pizza.pork.intellij
import com.intellij.lexer.LexerBase
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProcessCanceledException
import com.intellij.psi.tree.IElementType
import gay.pizza.pork.parser.*
import com.intellij.psi.TokenType as PsiTokenType
class PorkLexer : LexerBase() {
private val log: Logger = Logger.getInstance(PorkLexer::class.java)
private lateinit var source: StringCharSource
private lateinit var tokenizer: Tokenizer
private var internalTokenStart: Int = 0
private var internalTokenEnd: Int = 0
private var internalState: Int = 0
private var currentTokenType: IElementType? = null
override fun start(buffer: CharSequence, startOffset: Int, endOffset: Int, initialState: Int) {
source = StringCharSource(
input = buffer,
startIndex = startOffset,
endIndex = endOffset
)
tokenizer = Tokenizer(source)
internalState = initialState
internalTokenStart = startOffset
internalTokenEnd = startOffset
currentTokenType = null
advance()
}
override fun getState(): Int {
return internalState
}
override fun getTokenType(): IElementType? {
return currentTokenType
}
override fun getTokenStart(): Int {
return internalTokenStart
}
override fun getTokenEnd(): Int {
return internalTokenEnd
}
override fun advance() {
internalTokenStart = internalTokenEnd
if (internalTokenStart == bufferEnd) {
currentTokenType = null
return
}
try {
val currentToken = tokenizer.next()
currentTokenType = tokenAsElement(currentToken)
internalTokenStart = currentToken.start
internalTokenEnd = currentToken.start + currentToken.text.length
} catch (e: ProcessCanceledException) {
throw e
} catch (e: Throwable) {
currentTokenType = PsiTokenType.BAD_CHARACTER
internalTokenEnd = bufferEnd
log.warn(Tokenizer::class.java.name, e)
}
}
override fun getBufferSequence(): CharSequence {
return source.input
}
override fun getBufferEnd(): Int {
return source.endIndex
}
private fun tokenAsElement(token: Token): IElementType = when {
token.type.family == TokenFamily.KeywordFamily ->
PorkTokenTypes.Keyword
token.type.family == TokenFamily.SymbolFamily ->
PorkTokenTypes.Symbol
token.type.family == TokenFamily.OperatorFamily ->
PorkTokenTypes.Operator
token.type.family == TokenFamily.StringLiteralFamily ->
PorkTokenTypes.String
token.type.family == TokenFamily.NumericLiteralFamily ->
PorkTokenTypes.Number
token.type == TokenType.Whitespace ->
PorkTokenTypes.Whitespace
else -> PsiTokenType.CODE_FRAGMENT
}
override fun toString(): String = "Lexer(start=$internalTokenStart, end=$internalTokenEnd)"
}

View File

@ -0,0 +1,49 @@
package gay.pizza.pork.intellij
import com.intellij.lexer.Lexer
import com.intellij.openapi.editor.DefaultLanguageHighlighterColors
import com.intellij.openapi.editor.colors.TextAttributesKey
import com.intellij.openapi.fileTypes.SyntaxHighlighter
import com.intellij.openapi.fileTypes.SyntaxHighlighterBase
import com.intellij.psi.tree.IElementType
object PorkSyntaxHighlighter : SyntaxHighlighter {
override fun getHighlightingLexer(): Lexer {
return PorkLexer()
}
override fun getTokenHighlights(tokenType: IElementType?): Array<TextAttributesKey> {
if (tokenType == null) return emptyArray()
val attributes = when (tokenType) {
PorkTokenTypes.Keyword ->
TextAttributesKey.createTextAttributesKey(
"PORK.KEYWORD",
DefaultLanguageHighlighterColors.KEYWORD
)
PorkTokenTypes.Symbol ->
TextAttributesKey.createTextAttributesKey(
"PORK.SYMBOL",
DefaultLanguageHighlighterColors.LOCAL_VARIABLE
)
PorkTokenTypes.Operator ->
TextAttributesKey.createTextAttributesKey(
"PORK.OPERATOR",
DefaultLanguageHighlighterColors.OPERATION_SIGN
)
PorkTokenTypes.String ->
TextAttributesKey.createTextAttributesKey(
"PORK.STRING",
DefaultLanguageHighlighterColors.STRING
)
PorkTokenTypes.Number ->
TextAttributesKey.createTextAttributesKey(
"PORK.NUMBER",
DefaultLanguageHighlighterColors.NUMBER
)
else -> null
}
return if (attributes == null)
emptyArray()
else SyntaxHighlighterBase.pack(attributes)
}
}

View File

@ -0,0 +1,12 @@
package gay.pizza.pork.intellij
import com.intellij.openapi.fileTypes.SyntaxHighlighter
import com.intellij.openapi.fileTypes.SyntaxHighlighterFactory
import com.intellij.openapi.project.Project
import com.intellij.openapi.vfs.VirtualFile
class PorkSyntaxHighlighterFactory : SyntaxHighlighterFactory() {
override fun getSyntaxHighlighter(project: Project?, virtualFile: VirtualFile?): SyntaxHighlighter {
return PorkSyntaxHighlighter
}
}

View File

@ -0,0 +1,13 @@
package gay.pizza.pork.intellij
import com.intellij.psi.TokenType
import com.intellij.psi.tree.IElementType
object PorkTokenTypes {
val Whitespace = TokenType.WHITE_SPACE
val Keyword = IElementType("keyword", PorkLanguage)
val Symbol = IElementType("symbol", PorkLanguage)
val Operator = IElementType("operator", PorkLanguage)
val String = IElementType("string", PorkLanguage)
val Number = IElementType("number", PorkLanguage)
}