1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-04-23 13:15:45 +02:00

Add VimscriptFunction annotation

This commit is contained in:
filipp 2023-05-05 09:53:33 +03:00
parent 06021c1b79
commit bae52964cd
12 changed files with 243 additions and 1 deletions

42
annotation-processors/.gitignore vendored Normal file
View File

@ -0,0 +1,42 @@
.gradle
build/
!gradle/wrapper/gradle-wrapper.jar
!**/src/main/**/build/
!**/src/test/**/build/
### IntelliJ IDEA ###
.idea/modules.xml
.idea/jarRepositories.xml
.idea/compiler.xml
.idea/libraries/
*.iws
*.iml
*.ipr
out/
!**/src/main/**/out/
!**/src/test/**/out/
### Eclipse ###
.apt_generated
.classpath
.factorypath
.project
.settings
.springBeans
.sts4-cache
bin/
!**/src/main/**/bin/
!**/src/test/**/bin/
### NetBeans ###
/nbproject/private/
/nbbuild/
/dist/
/nbdist/
/.nb-gradle/
### VS Code ###
.vscode/
### Mac OS ###
.DS_Store

View File

@ -0,0 +1,23 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
plugins {
kotlin("jvm")
}
group = "com.intellij"
version = "SNAPSHOT"
repositories {
mavenCentral()
}
dependencies {
implementation("com.google.devtools.ksp:symbol-processing-api:1.8.0-1.0.8")
implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.15.0")
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.intellij.vim
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import java.io.File
class FileWriter {
fun generateResourceFile(fileName: String, content: String, environment: SymbolProcessorEnvironment) {
val resourcesDir = environment.options["resourcesDir"]
val file = File("$resourcesDir/$fileName")
file.writeText(content)
}
}

View File

@ -0,0 +1,13 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.intellij.vim.annotations
@Target(AnnotationTarget.CLASS)
@Retention(AnnotationRetention.SOURCE)
annotation class VimscriptFunction(val name: String)

View File

@ -0,0 +1,22 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.intellij.vim.model
import java.lang.invoke.MethodHandles
import java.lang.invoke.MethodType
open class LazyInstance<T>(private val className: String, private val classLoader: ClassLoader) {
val instance: T by lazy {
val aClass = classLoader.loadClass(className)
val lookup = MethodHandles.privateLookupIn(aClass, MethodHandles.lookup())
val instance = lookup.findConstructor(aClass, MethodType.methodType(Void.TYPE)).invoke()
@Suppress("UNCHECKED_CAST")
instance as T
}
}

View File

@ -0,0 +1,59 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.intellij.vim.processors
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper
import com.google.devtools.ksp.KspExperimental
import com.google.devtools.ksp.getAnnotationsByType
import com.google.devtools.ksp.processing.Resolver
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.symbol.KSAnnotated
import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSFile
import com.google.devtools.ksp.symbol.KSVisitorVoid
import com.intellij.vim.FileWriter
import com.intellij.vim.annotations.VimscriptFunction
class VimscriptFunctionProcessor(private val environment: SymbolProcessorEnvironment) : SymbolProcessor {
private val visitor = VimscriptFunctionVisitor()
private val writer = FileWriter()
private val nameToFunction = mutableMapOf<String, KSClassDeclaration>()
override fun process(resolver: Resolver): List<KSAnnotated> {
resolver.getAllFiles().forEach { it.accept(visitor, Unit) }
writer.generateResourceFile("VimscriptFunctions.yaml", generateFunctionDict(), environment)
return emptyList()
}
private fun generateFunctionDict(): String {
val mapper = YAMLMapper()
val dictToWrite: Map<String, String> = nameToFunction
.map { it.key to it.value.qualifiedName!!.asString() }
.toMap()
return mapper.writeValueAsString(dictToWrite)
}
// todo inspection that annotation is properly used on proper classes
private inner class VimscriptFunctionVisitor : KSVisitorVoid() {
@OptIn(KspExperimental::class)
override fun visitClassDeclaration(classDeclaration: KSClassDeclaration, data: Unit) {
val vimscriptFunctionAnnotation = classDeclaration.getAnnotationsByType(VimscriptFunction::class).firstOrNull() ?: return
val functionName = vimscriptFunctionAnnotation.name
nameToFunction[functionName] = classDeclaration
}
override fun visitFile(file: KSFile, data: Unit) {
file.declarations.forEach { it.accept(this, Unit) }
}
}
}

View File

@ -0,0 +1,20 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.intellij.vim.providers
import com.google.devtools.ksp.processing.SymbolProcessor
import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
import com.google.devtools.ksp.processing.SymbolProcessorProvider
import com.intellij.vim.processors.VimscriptFunctionProcessor
public class VimscriptFunctionProcessorProvider : SymbolProcessorProvider {
override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
return VimscriptFunctionProcessor(environment)
}
}

View File

@ -0,0 +1 @@
com.intellij.vim.providers.VimscriptFunctionProcessorProvider

View File

@ -11,4 +11,5 @@ pluginManagement {
rootProject.name = 'IdeaVIM'
include 'vim-engine'
include 'scripts'
include 'annotation-processors'

View File

@ -11,6 +11,7 @@ package com.maddyhome.idea.vim.api
import com.maddyhome.idea.vim.vimscript.model.VimLContext
import com.maddyhome.idea.vim.vimscript.model.expressions.Scope
import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler
import com.maddyhome.idea.vim.vimscript.model.functions.LazyVimscriptFunction
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
public interface VimscriptFunctionService {
@ -22,5 +23,5 @@ public interface VimscriptFunctionService {
public fun getUserDefinedFunction(scope: Scope?, name: String, vimContext: VimLContext): FunctionDeclaration?
public fun getBuiltInFunction(name: String): FunctionHandler?
public fun registerHandlers()
public fun addHandler(handlerHolder: Any)
public fun addHandler(handler: LazyVimscriptFunction)
}

View File

@ -0,0 +1,14 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.vimscript.model.functions
import com.intellij.vim.model.LazyInstance
public class LazyVimscriptFunction(public val name: String, className: String, classLoader: ClassLoader):
LazyInstance<FunctionHandler>(className, classLoader)

View File

@ -0,0 +1,26 @@
/*
* Copyright 2003-2023 The IdeaVim authors
*
* Use of this source code is governed by an MIT-style
* license that can be found in the LICENSE.txt file or at
* https://opensource.org/licenses/MIT.
*/
package com.maddyhome.idea.vim.vimscript.model.functions
import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.dataformat.yaml.YAMLMapper
import java.io.InputStream
import javax.swing.InputMap
public interface VimscriptFunctionProvider {
public val functionListFile: InputStream
public fun getFunctions(): Collection<LazyVimscriptFunction> {
val mapper = YAMLMapper()
val classLoader = this.javaClass.classLoader
val typeReference = object : TypeReference<HashMap<String, String>>() {}
val functionDict = mapper.readValue(functionListFile, typeReference)
return functionDict.map { LazyVimscriptFunction(it.key, it.value, classLoader) }
}
}