-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
TECH: extend intelllij plugin with refactor options (#29)
Co-authored-by: Jerre van Veluw <[email protected]>
- Loading branch information
1 parent
12b2905
commit fc6e521
Showing
14 changed files
with
331 additions
and
80 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
package community.flock.wirespec.lsp.intellij_plugin | ||
|
||
import com.intellij.lang.cacheBuilder.DefaultWordsScanner | ||
import com.intellij.lang.cacheBuilder.WordsScanner | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.tree.TokenSet | ||
import com.intellij.lang.findUsages.FindUsagesProvider as IntellijFindUsagesProvider | ||
|
||
|
||
class FindUsagesProvider : IntellijFindUsagesProvider { | ||
|
||
override fun getWordsScanner(): WordsScanner = DefaultWordsScanner( | ||
Lexer(), | ||
TokenSets.CUSTOM_TYPE, | ||
TokenSet.EMPTY, | ||
TokenSet.EMPTY | ||
) | ||
|
||
override fun canFindUsagesFor(psiElement: PsiElement) = psiElement is CustomTypeElement | ||
|
||
override fun getHelpId(psiElement: PsiElement) = null | ||
|
||
override fun getType(element: PsiElement) = if (element is CustomTypeElement) "custom Type" else "" | ||
|
||
override fun getDescriptiveName(element: PsiElement) = if (element is CustomTypeElement) element.name ?: "" else "" | ||
|
||
override fun getNodeText(element: PsiElement, useFullName: Boolean) = getDescriptiveName(element) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,53 +1,159 @@ | ||
package community.flock.wirespec.lsp.intellij_plugin | ||
|
||
import com.intellij.extapi.psi.ASTWrapperPsiElement | ||
import com.intellij.lang.ASTNode | ||
import com.intellij.lang.PsiBuilder | ||
import com.intellij.lang.PsiParser | ||
import com.intellij.navigation.ItemPresentation | ||
import com.intellij.openapi.project.Project | ||
import com.intellij.psi.FileViewProvider | ||
import com.intellij.psi.PsiElement | ||
import com.intellij.psi.PsiFileFactory | ||
import com.intellij.psi.PsiNameIdentifierOwner | ||
import com.intellij.psi.PsiNamedElement | ||
import com.intellij.psi.PsiReference | ||
import com.intellij.psi.tree.IElementType | ||
import com.intellij.psi.tree.IFileElementType | ||
import com.intellij.psi.tree.TokenSet | ||
import com.intellij.psi.util.PsiTreeUtil | ||
import community.flock.wirespec.lsp.intellij_plugin.Types.Companion.CUSTOM_TYPE | ||
import community.flock.wirespec.lsp.intellij_plugin.Types.Companion.LEFT_CURLY | ||
import community.flock.wirespec.lsp.intellij_plugin.Types.Companion.RIGHT_CURLY | ||
import com.intellij.lang.ParserDefinition as IntellijParserDefinition | ||
import com.intellij.psi.tree.TokenSet as IntellijTokenSet | ||
|
||
|
||
class Parser : PsiParser { | ||
override fun parse(root: IElementType, builder: PsiBuilder): ASTNode { | ||
|
||
val rootMarker = builder.mark() | ||
class TypeDef : IElementType("TYPE_DEF", Language.INSTANCE) | ||
class CustomTypeDef : IElementType("CUSTOM_TYPE_DEF", Language.INSTANCE) | ||
class CustomTypeRef : IElementType("CUSTOM_TYPE_REF", Language.INSTANCE) | ||
class Body : IElementType("BODY", Language.INSTANCE) | ||
|
||
while (!builder.eof()) { | ||
val token = builder.tokenType | ||
if (token != null) { | ||
builder.mark().done(token) | ||
|
||
override fun parse(root: IElementType, builder: PsiBuilder): ASTNode { | ||
val rootMarker = builder.mark() | ||
var typeMarker: PsiBuilder.Marker? = null | ||
var bodyMarker: PsiBuilder.Marker? = null | ||
|
||
fun parseNode() { | ||
when (builder.tokenType) { | ||
CUSTOM_TYPE -> { | ||
builder.mark() | ||
.also { builder.advanceLexer() } | ||
.done(CustomTypeDef()) | ||
parseNode() | ||
} | ||
|
||
LEFT_CURLY -> { | ||
bodyMarker = builder.mark() | ||
builder.advanceLexer() | ||
parseNode() | ||
} | ||
|
||
RIGHT_CURLY -> { | ||
builder.advanceLexer() | ||
bodyMarker?.done(Body()).also { bodyMarker = null } | ||
typeMarker?.done(TypeDef()).also { typeMarker = null } | ||
} | ||
|
||
else -> { | ||
builder.advanceLexer() | ||
parseNode() | ||
} | ||
} | ||
} | ||
|
||
fun parseDef() { | ||
typeMarker = builder.mark() | ||
builder.advanceLexer() | ||
if (!builder.eof() && builder.tokenType != Types.TYPE_DEF) { | ||
parseNode() | ||
} | ||
} | ||
|
||
while (!builder.eof()) { | ||
when (builder.tokenType) { | ||
Types.TYPE_DEF -> parseDef() | ||
else -> builder.advanceLexer() | ||
} | ||
} | ||
rootMarker.done(root) | ||
|
||
return builder.treeBuilt | ||
} | ||
|
||
} | ||
|
||
|
||
class ParserDefinition : IntellijParserDefinition { | ||
override fun createLexer(project: Project) = Lexer() | ||
|
||
override fun getCommentTokens() = TokenSet.COMMENTS | ||
override fun getCommentTokens() = TokenSet.create() | ||
|
||
override fun getStringLiteralElements() = IntellijTokenSet.EMPTY | ||
override fun getStringLiteralElements(): TokenSet = IntellijTokenSet.EMPTY | ||
|
||
override fun createParser(project: Project) = Parser() | ||
|
||
override fun getFileNodeType() = FILE | ||
|
||
override fun createFile(viewProvider: FileViewProvider) = File(viewProvider) | ||
|
||
override fun createElement(node: ASTNode): PsiElement = Element(node) | ||
override fun createElement(node: ASTNode): PsiElement = when (node.elementType) { | ||
is Parser.TypeDef -> TypeDefElement(node) | ||
is Parser.CustomTypeDef -> CustomTypeElementDef(node) | ||
is Parser.CustomTypeRef -> CustomTypeElementRef(node) | ||
is Parser.Body -> BodyElement(node) | ||
else -> error("Cannot create type") | ||
} | ||
|
||
companion object { | ||
val FILE = IFileElementType(Language.INSTANCE) | ||
} | ||
} | ||
|
||
} | ||
|
||
class TypeDefElement(ast: ASTNode) : ASTWrapperPsiElement(ast) | ||
class BodyElement(ast: ASTNode) : ASTWrapperPsiElement(ast) | ||
|
||
fun createDefNode(project: Project, name: String) = PsiFileFactory | ||
.getInstance(project) | ||
.createFileFromText("dummy.ws", FileType.INSTANCE, "type $name {}") | ||
.firstChild | ||
.let { PsiTreeUtil.findChildOfType(it, CustomTypeElementDef::class.java) } | ||
?.node | ||
?: error("Cannot create new node") | ||
|
||
fun createRefNode(project: Project, name: String) = PsiFileFactory | ||
.getInstance(project) | ||
.createFileFromText("dummy.ws", FileType.INSTANCE, "type X { y: $name }") | ||
.firstChild | ||
.let { PsiTreeUtil.findChildOfType(it, CustomTypeElementRef::class.java) } | ||
?.node | ||
?: error("Cannot create new node") | ||
|
||
abstract class CustomTypeElement(ast: ASTNode) : ASTWrapperPsiElement(ast), PsiNamedElement { | ||
override fun getName(): String? = text | ||
|
||
override fun getPresentation(): ItemPresentation = Utils.getPresentation(this) | ||
} | ||
|
||
class CustomTypeElementDef(private val ast: ASTNode) : CustomTypeElement(ast), PsiNameIdentifierOwner { | ||
|
||
override fun setName(name: String): PsiElement { | ||
parent.node.replaceChild(node, createDefNode(project, name)) | ||
return this | ||
} | ||
|
||
override fun getNameIdentifier(): PsiElement = ast.firstChildNode.psi | ||
} | ||
|
||
class CustomTypeElementRef(private val ast: ASTNode) : CustomTypeElement(ast), PsiNameIdentifierOwner { | ||
|
||
override fun setName(name: String): PsiElement { | ||
this.parent.node.replaceChild(this.node, createRefNode(project, name)) | ||
return this | ||
} | ||
|
||
override fun getNameIdentifier(): PsiElement = ast.firstChildNode.psi | ||
|
||
override fun getReference(): PsiReference = Reference(this) | ||
} |
9 changes: 9 additions & 0 deletions
9
lsp/intellij-plugin/src/main/kotlin/RefactoringSupportProvider.kt
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
package community.flock.wirespec.lsp.intellij_plugin | ||
|
||
import com.intellij.lang.refactoring.RefactoringSupportProvider | ||
import com.intellij.psi.PsiElement | ||
|
||
class RefactoringSupportProvider : RefactoringSupportProvider() { | ||
override fun isMemberInplaceRenameAvailable(elementToRename: PsiElement, context: PsiElement?) = | ||
elementToRename is CustomTypeElement | ||
} |
Oops, something went wrong.