mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-05-25 18:34:08 +02:00
Add VimScriptFunctionServiceBase
This commit is contained in:
parent
37fb41fca8
commit
b2af8f153e
src/main/java/com/maddyhome/idea/vim/vimscript/services
vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api
@ -8,170 +8,11 @@
|
||||
|
||||
package com.maddyhome.idea.vim.vimscript.services
|
||||
|
||||
import com.intellij.openapi.diagnostic.logger
|
||||
import com.maddyhome.idea.vim.api.VimscriptFunctionService
|
||||
import com.maddyhome.idea.vim.ex.ExException
|
||||
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
|
||||
import com.maddyhome.idea.vim.vimscript.model.Script
|
||||
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.DefinedFunctionHandler
|
||||
import com.maddyhome.idea.vim.api.VimScriptFunctionServiceBase
|
||||
import com.maddyhome.idea.vim.vimscript.model.functions.EngineFunctionProvider
|
||||
import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler
|
||||
import com.maddyhome.idea.vim.vimscript.model.functions.IntellijFunctionProvider
|
||||
import com.maddyhome.idea.vim.vimscript.model.functions.LazyVimscriptFunction
|
||||
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
|
||||
import com.maddyhome.idea.vim.vimscript.model.functions.VimscriptFunctionProvider
|
||||
|
||||
internal class FunctionStorage : VimscriptFunctionService {
|
||||
|
||||
private val logger = logger<FunctionStorage>()
|
||||
|
||||
private val globalFunctions: MutableMap<String, FunctionDeclaration> = mutableMapOf()
|
||||
|
||||
private val builtInFunctions: MutableMap<String, LazyVimscriptFunction> = mutableMapOf()
|
||||
|
||||
override fun deleteFunction(name: String, scope: Scope?, vimContext: VimLContext) {
|
||||
if (name[0].isLowerCase() && scope != Scope.SCRIPT_VARIABLE) {
|
||||
throw ExException("E128: Function name must start with a capital or \"s:\": $name")
|
||||
}
|
||||
|
||||
if (scope != null) {
|
||||
when (scope) {
|
||||
Scope.GLOBAL_VARIABLE -> {
|
||||
if (globalFunctions.containsKey(name)) {
|
||||
globalFunctions[name]!!.isDeleted = true
|
||||
globalFunctions.remove(name)
|
||||
return
|
||||
} else {
|
||||
throw ExException("E130: Unknown function: ${scope.c}:$name")
|
||||
}
|
||||
}
|
||||
Scope.SCRIPT_VARIABLE -> {
|
||||
if (vimContext.getFirstParentContext() !is Script) {
|
||||
throw ExException("E81: Using <SID> not in a script context")
|
||||
}
|
||||
|
||||
if (getScriptFunction(name, vimContext) != null) {
|
||||
deleteScriptFunction(name, vimContext)
|
||||
return
|
||||
} else {
|
||||
throw ExException("E130: Unknown function: ${scope.c}:$name")
|
||||
}
|
||||
}
|
||||
else -> throw ExException("E130: Unknown function: ${scope.c}:$name")
|
||||
}
|
||||
}
|
||||
|
||||
if (globalFunctions.containsKey(name)) {
|
||||
globalFunctions[name]!!.isDeleted = true
|
||||
globalFunctions.remove(name)
|
||||
return
|
||||
}
|
||||
|
||||
val firstParentContext = vimContext.getFirstParentContext()
|
||||
if (firstParentContext is Script && getScriptFunction(name, vimContext) != null) {
|
||||
deleteScriptFunction(name, vimContext)
|
||||
return
|
||||
}
|
||||
throw ExException("E130: Unknown function: $name")
|
||||
}
|
||||
|
||||
override fun storeFunction(declaration: FunctionDeclaration) {
|
||||
val scope: Scope = declaration.scope ?: getDefaultFunctionScope()
|
||||
when (scope) {
|
||||
Scope.GLOBAL_VARIABLE -> {
|
||||
if (globalFunctions.containsKey(declaration.name) && !declaration.replaceExisting) {
|
||||
throw ExException("E122: Function ${declaration.name} already exists, add ! to replace it")
|
||||
} else {
|
||||
globalFunctions[declaration.name] = declaration
|
||||
}
|
||||
}
|
||||
Scope.SCRIPT_VARIABLE -> {
|
||||
if (declaration.getFirstParentContext() !is Script) {
|
||||
throw ExException("E81: Using <SID> not in a script context")
|
||||
}
|
||||
|
||||
if (getScriptFunction(declaration.name, declaration) != null && !declaration.replaceExisting) {
|
||||
throw ExException("E122: Function ${declaration.name} already exists, add ! to replace it")
|
||||
} else {
|
||||
storeScriptFunction(declaration)
|
||||
}
|
||||
}
|
||||
else -> throw ExException("E884: Function name cannot contain a colon: ${scope.c}:${declaration.name}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFunctionHandler(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler {
|
||||
return getFunctionHandlerOrNull(scope, name, vimContext)
|
||||
?: throw ExException("E117: Unknown function: ${scope?.toString() ?: ""}$name")
|
||||
}
|
||||
|
||||
override fun getFunctionHandlerOrNull(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler? {
|
||||
if (scope == null) {
|
||||
val builtInFunction = getBuiltInFunction(name)
|
||||
if (builtInFunction != null) {
|
||||
return builtInFunction
|
||||
}
|
||||
}
|
||||
|
||||
val definedFunction = getUserDefinedFunction(scope, name, vimContext)
|
||||
if (definedFunction != null) {
|
||||
return DefinedFunctionHandler(definedFunction)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getUserDefinedFunction(scope: Scope?, name: String, vimContext: VimLContext): FunctionDeclaration? {
|
||||
return when (scope) {
|
||||
Scope.GLOBAL_VARIABLE -> globalFunctions[name]
|
||||
Scope.SCRIPT_VARIABLE -> getScriptFunction(name, vimContext)
|
||||
null -> {
|
||||
val firstParentContext = vimContext.getFirstParentContext()
|
||||
when (firstParentContext) {
|
||||
is CommandLineVimLContext -> globalFunctions[name]
|
||||
is Script -> globalFunctions[name] ?: getScriptFunction(name, vimContext)
|
||||
else -> throw RuntimeException("Unknown parent context")
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBuiltInFunction(name: String): FunctionHandler? {
|
||||
return builtInFunctions[name]?.instance
|
||||
}
|
||||
|
||||
private fun storeScriptFunction(functionDeclaration: FunctionDeclaration) {
|
||||
val script = functionDeclaration.getScript() ?: throw ExException("E81: Using <SID> not in a script context")
|
||||
script.scriptFunctions[functionDeclaration.name] = functionDeclaration
|
||||
}
|
||||
|
||||
private fun getScriptFunction(name: String, vimContext: VimLContext): FunctionDeclaration? {
|
||||
val script = vimContext.getScript() ?: throw ExException("E120: Using <SID> not in a script context: s:$name")
|
||||
return script.scriptFunctions[name]
|
||||
}
|
||||
|
||||
private fun deleteScriptFunction(name: String, vimContext: VimLContext) {
|
||||
val script = vimContext.getScript() ?: throw ExException("E81: Using <SID> not in a script context")
|
||||
if (script.scriptFunctions[name] != null) {
|
||||
script.scriptFunctions[name]!!.isDeleted = true
|
||||
}
|
||||
script.scriptFunctions.remove(name)
|
||||
}
|
||||
|
||||
private fun getDefaultFunctionScope(): Scope {
|
||||
return Scope.GLOBAL_VARIABLE
|
||||
}
|
||||
|
||||
override fun registerHandlers() {
|
||||
val engineFunctions = EngineFunctionProvider.getFunctions()
|
||||
engineFunctions.forEach { addHandler(it) }
|
||||
|
||||
val intellijFunctions = IntellijFunctionProvider.getFunctions()
|
||||
intellijFunctions.forEach { addHandler(it) }
|
||||
}
|
||||
|
||||
override fun addHandler(handler: LazyVimscriptFunction) {
|
||||
builtInFunctions[handler.name] = handler
|
||||
}
|
||||
internal class FunctionStorage : VimScriptFunctionServiceBase() {
|
||||
override val functionProviders: List<VimscriptFunctionProvider> = listOf(EngineFunctionProvider, IntellijFunctionProvider)
|
||||
}
|
||||
|
@ -0,0 +1,172 @@
|
||||
/*
|
||||
* Copyright 2003-2024 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.api
|
||||
|
||||
import com.maddyhome.idea.vim.diagnostic.vimLogger
|
||||
import com.maddyhome.idea.vim.ex.ExException
|
||||
import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext
|
||||
import com.maddyhome.idea.vim.vimscript.model.Script
|
||||
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.DefinedFunctionHandler
|
||||
import com.maddyhome.idea.vim.vimscript.model.functions.EngineFunctionProvider
|
||||
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.functions.VimscriptFunctionProvider
|
||||
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
|
||||
|
||||
public abstract class VimScriptFunctionServiceBase : VimscriptFunctionService {
|
||||
private val logger = vimLogger<VimScriptFunctionServiceBase>()
|
||||
|
||||
protected abstract val functionProviders: List<VimscriptFunctionProvider>
|
||||
|
||||
private val globalFunctions: MutableMap<String, FunctionDeclaration> = mutableMapOf()
|
||||
private val builtInFunctions: MutableMap<String, LazyVimscriptFunction> = mutableMapOf()
|
||||
|
||||
override fun deleteFunction(name: String, scope: Scope?, vimContext: VimLContext) {
|
||||
if (name[0].isLowerCase() && scope != Scope.SCRIPT_VARIABLE) {
|
||||
throw ExException("E128: Function name must start with a capital or \"s:\": $name")
|
||||
}
|
||||
|
||||
if (scope != null) {
|
||||
when (scope) {
|
||||
Scope.GLOBAL_VARIABLE -> {
|
||||
if (globalFunctions.containsKey(name)) {
|
||||
globalFunctions[name]!!.isDeleted = true
|
||||
globalFunctions.remove(name)
|
||||
return
|
||||
} else {
|
||||
throw ExException("E130: Unknown function: ${scope.c}:$name")
|
||||
}
|
||||
}
|
||||
Scope.SCRIPT_VARIABLE -> {
|
||||
if (vimContext.getFirstParentContext() !is Script) {
|
||||
throw ExException("E81: Using <SID> not in a script context")
|
||||
}
|
||||
|
||||
if (getScriptFunction(name, vimContext) != null) {
|
||||
deleteScriptFunction(name, vimContext)
|
||||
return
|
||||
} else {
|
||||
throw ExException("E130: Unknown function: ${scope.c}:$name")
|
||||
}
|
||||
}
|
||||
else -> throw ExException("E130: Unknown function: ${scope.c}:$name")
|
||||
}
|
||||
}
|
||||
|
||||
if (globalFunctions.containsKey(name)) {
|
||||
globalFunctions[name]!!.isDeleted = true
|
||||
globalFunctions.remove(name)
|
||||
return
|
||||
}
|
||||
|
||||
val firstParentContext = vimContext.getFirstParentContext()
|
||||
if (firstParentContext is Script && getScriptFunction(name, vimContext) != null) {
|
||||
deleteScriptFunction(name, vimContext)
|
||||
return
|
||||
}
|
||||
throw ExException("E130: Unknown function: $name")
|
||||
}
|
||||
|
||||
override fun storeFunction(declaration: FunctionDeclaration) {
|
||||
val scope: Scope = declaration.scope ?: getDefaultFunctionScope()
|
||||
when (scope) {
|
||||
Scope.GLOBAL_VARIABLE -> {
|
||||
if (globalFunctions.containsKey(declaration.name) && !declaration.replaceExisting) {
|
||||
throw ExException("E122: Function ${declaration.name} already exists, add ! to replace it")
|
||||
} else {
|
||||
globalFunctions[declaration.name] = declaration
|
||||
}
|
||||
}
|
||||
Scope.SCRIPT_VARIABLE -> {
|
||||
if (declaration.getFirstParentContext() !is Script) {
|
||||
throw ExException("E81: Using <SID> not in a script context")
|
||||
}
|
||||
|
||||
if (getScriptFunction(declaration.name, declaration) != null && !declaration.replaceExisting) {
|
||||
throw ExException("E122: Function ${declaration.name} already exists, add ! to replace it")
|
||||
} else {
|
||||
storeScriptFunction(declaration)
|
||||
}
|
||||
}
|
||||
else -> throw ExException("E884: Function name cannot contain a colon: ${scope.c}:${declaration.name}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getFunctionHandler(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler {
|
||||
return getFunctionHandlerOrNull(scope, name, vimContext)
|
||||
?: throw ExException("E117: Unknown function: ${scope?.toString() ?: ""}$name")
|
||||
}
|
||||
|
||||
override fun getFunctionHandlerOrNull(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler? {
|
||||
if (scope == null) {
|
||||
val builtInFunction = getBuiltInFunction(name)
|
||||
if (builtInFunction != null) {
|
||||
return builtInFunction
|
||||
}
|
||||
}
|
||||
|
||||
val definedFunction = getUserDefinedFunction(scope, name, vimContext)
|
||||
if (definedFunction != null) {
|
||||
return DefinedFunctionHandler(definedFunction)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
override fun getUserDefinedFunction(scope: Scope?, name: String, vimContext: VimLContext): FunctionDeclaration? {
|
||||
return when (scope) {
|
||||
Scope.GLOBAL_VARIABLE -> globalFunctions[name]
|
||||
Scope.SCRIPT_VARIABLE -> getScriptFunction(name, vimContext)
|
||||
null -> {
|
||||
val firstParentContext = vimContext.getFirstParentContext()
|
||||
when (firstParentContext) {
|
||||
is CommandLineVimLContext -> globalFunctions[name]
|
||||
is Script -> globalFunctions[name] ?: getScriptFunction(name, vimContext)
|
||||
else -> throw RuntimeException("Unknown parent context")
|
||||
}
|
||||
}
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun getBuiltInFunction(name: String): FunctionHandler? {
|
||||
return builtInFunctions[name]?.instance
|
||||
}
|
||||
|
||||
private fun storeScriptFunction(functionDeclaration: FunctionDeclaration) {
|
||||
val script = functionDeclaration.getScript() ?: throw ExException("E81: Using <SID> not in a script context")
|
||||
script.scriptFunctions[functionDeclaration.name] = functionDeclaration
|
||||
}
|
||||
|
||||
private fun getScriptFunction(name: String, vimContext: VimLContext): FunctionDeclaration? {
|
||||
val script = vimContext.getScript() ?: throw ExException("E120: Using <SID> not in a script context: s:$name")
|
||||
return script.scriptFunctions[name]
|
||||
}
|
||||
|
||||
private fun deleteScriptFunction(name: String, vimContext: VimLContext) {
|
||||
val script = vimContext.getScript() ?: throw ExException("E81: Using <SID> not in a script context")
|
||||
if (script.scriptFunctions[name] != null) {
|
||||
script.scriptFunctions[name]!!.isDeleted = true
|
||||
}
|
||||
script.scriptFunctions.remove(name)
|
||||
}
|
||||
|
||||
private fun getDefaultFunctionScope(): Scope {
|
||||
return Scope.GLOBAL_VARIABLE
|
||||
}
|
||||
|
||||
override fun registerHandlers() {
|
||||
functionProviders.forEach { provider -> provider.getFunctions().forEach { addHandler(it) } }
|
||||
}
|
||||
|
||||
override fun addHandler(handler: LazyVimscriptFunction) {
|
||||
builtInFunctions[handler.name] = handler
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user