mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-05-06 21:34:02 +02:00
funcref()
function
This commit is contained in:
parent
07d753f413
commit
dbf0444110
resources/META-INF/includes
src/com/maddyhome/idea/vim/vimscript/model/functions/handlers
test/org/jetbrains/plugins/ideavim/ex/implementation/functions
vimscript-info
@ -8,5 +8,6 @@
|
||||
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.ExistsFunctionHandler" name="exists"/>
|
||||
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.LenFunctionHandler" name="len"/>
|
||||
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.FunctionFunctionHandler" name="function"/>
|
||||
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.FuncrefFunctionHandler" name="funcref"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
@ -28,6 +28,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimList
|
||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
|
||||
import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
|
||||
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.FunctionHandler
|
||||
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
|
||||
|
||||
@ -72,14 +73,58 @@ object FunctionFunctionHandler : FunctionHandler() {
|
||||
}
|
||||
return VimFuncref(function, arglist ?: VimList(mutableListOf()), dictionary ?: VimDictionary(LinkedHashMap()), VimFuncref.Type.FUNCTION)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.extractScopeAndName(): Pair<Scope?, String> {
|
||||
val colonIndex = this.indexOf(":")
|
||||
if (colonIndex == -1) {
|
||||
return Pair(null, this)
|
||||
object FuncrefFunctionHandler : FunctionHandler() {
|
||||
override val name = "function"
|
||||
override val minimumNumberOfArguments: Int = 1
|
||||
override val maximumNumberOfArguments: Int = 3
|
||||
|
||||
override fun doFunction(
|
||||
argumentValues: List<Expression>,
|
||||
editor: Editor,
|
||||
context: DataContext,
|
||||
parent: Executable,
|
||||
): VimFuncref {
|
||||
val arg1 = argumentValues[0].evaluate(editor, context, parent)
|
||||
if (arg1 !is VimString) {
|
||||
throw ExException("E129: Function name required")
|
||||
}
|
||||
val scopeString = this.substring(0, colonIndex)
|
||||
val nameString = this.substring(colonIndex + 1)
|
||||
return Pair(Scope.getByValue(scopeString), nameString)
|
||||
val scopeAndName = arg1.value.extractScopeAndName()
|
||||
val function = FunctionStorage.getUserDefinedFunction(scopeAndName.first, scopeAndName.second, parent)
|
||||
?: throw ExException("E700: Unknown function: ${if (scopeAndName.first != null) scopeAndName.first!!.c + ":" else ""}${scopeAndName.second}")
|
||||
val handler = DefinedFunctionHandler(function)
|
||||
|
||||
var arglist: VimList? = null
|
||||
var dictionary: VimDictionary? = null
|
||||
val arg2 = argumentValues.getOrNull(1)?.evaluate(editor, context, parent)
|
||||
val arg3 = argumentValues.getOrNull(2)?.evaluate(editor, context, parent)
|
||||
|
||||
if (arg2 is VimDictionary && arg3 is VimDictionary) {
|
||||
throw ExException("E923: Second argument of function() must be a list or a dict")
|
||||
}
|
||||
|
||||
if (arg2 != null) {
|
||||
when (arg2) {
|
||||
is VimList -> arglist = arg2
|
||||
is VimDictionary -> dictionary = arg2
|
||||
else -> throw ExException("E923: Second argument of function() must be a list or a dict")
|
||||
}
|
||||
}
|
||||
|
||||
if (arg3 != null && arg3 !is VimDictionary) {
|
||||
throw ExException("E922: expected a dict")
|
||||
}
|
||||
return VimFuncref(handler, arglist ?: VimList(mutableListOf()), dictionary ?: VimDictionary(LinkedHashMap()), VimFuncref.Type.FUNCREF)
|
||||
}
|
||||
}
|
||||
|
||||
private fun String.extractScopeAndName(): Pair<Scope?, String> {
|
||||
val colonIndex = this.indexOf(":")
|
||||
if (colonIndex == -1) {
|
||||
return Pair(null, this)
|
||||
}
|
||||
val scopeString = this.substring(0, colonIndex)
|
||||
val nameString = this.substring(colonIndex + 1)
|
||||
return Pair(Scope.getByValue(scopeString), nameString)
|
||||
}
|
||||
|
@ -0,0 +1,158 @@
|
||||
/*
|
||||
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||
* Copyright (C) 2003-2021 The IdeaVim authors
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
package org.jetbrains.plugins.ideavim.ex.implementation.functions
|
||||
|
||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||
|
||||
class FuncrefTest : VimTestCase() {
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test funcref for built-in function`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = funcref('abs')"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E700: Unknown function: abs")
|
||||
}
|
||||
|
||||
fun `test funcref with arglist`() {
|
||||
configureByText("\n")
|
||||
typeText(
|
||||
commandToKeys(
|
||||
"""
|
||||
function! Abs(number) |
|
||||
return abs(a:number) |
|
||||
endfunction
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
typeText(commandToKeys("let Ff = funcref('Abs', [-10])"))
|
||||
typeText(commandToKeys("echo Ff()"))
|
||||
assertExOutput("10\n")
|
||||
|
||||
typeText(commandToKeys("echo Ff"))
|
||||
assertExOutput("function('Abs', [-10])\n")
|
||||
|
||||
typeText(commandToKeys("delfunction! Abs"))
|
||||
}
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test funcref for unknown function`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = funcref('Unknown')"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E700: Unknown function: Unknown")
|
||||
}
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test funcref with wrong function name`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = funcref(32)"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E129: Function name required")
|
||||
}
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test funcref with wrong second argument`() {
|
||||
configureByText("\n")
|
||||
typeText(
|
||||
commandToKeys(
|
||||
"""
|
||||
function! Abs(number) |
|
||||
return abs(a:number) |
|
||||
endfunction
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
typeText(commandToKeys("let Ff = funcref('Abs', 10)"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E923: Second argument of function() must be a list or a dict")
|
||||
|
||||
typeText(commandToKeys("delfunction! Abs"))
|
||||
}
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test funcref with wrong third argument`() {
|
||||
configureByText("\n")
|
||||
typeText(
|
||||
commandToKeys(
|
||||
"""
|
||||
function! Abs(number) |
|
||||
return abs(a:number) |
|
||||
endfunction
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
typeText(commandToKeys("let Ff = funcref('Abs', [], 40)"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E922: expected a dict")
|
||||
|
||||
typeText(commandToKeys("delfunction! Abs"))
|
||||
}
|
||||
|
||||
fun `test redefining a function`() {
|
||||
configureByText("\n")
|
||||
typeText(
|
||||
commandToKeys(
|
||||
"""
|
||||
function! SayHi() |
|
||||
echo 'hello' |
|
||||
endfunction
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
typeText(commandToKeys("let Ff = funcref('SayHi')"))
|
||||
typeText(commandToKeys("call Ff()"))
|
||||
assertExOutput("hello\n")
|
||||
|
||||
typeText(
|
||||
commandToKeys(
|
||||
"""
|
||||
function! SayHi() |
|
||||
echo 'hi' |
|
||||
endfunction
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
typeText(commandToKeys("call Ff()"))
|
||||
assertExOutput("hello\n")
|
||||
|
||||
typeText(commandToKeys("delfunction! SayHi"))
|
||||
}
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test deleting function`() {
|
||||
configureByText("\n")
|
||||
typeText(
|
||||
commandToKeys(
|
||||
"""
|
||||
function! SayHi() |
|
||||
echo 'hello' |
|
||||
endfunction
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
typeText(commandToKeys("let Ff = funcref('SayHi')"))
|
||||
typeText(commandToKeys("delfunction! SayHi"))
|
||||
typeText(commandToKeys("call Ff()"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E933: Function was deleted: SayHi")
|
||||
}
|
||||
}
|
@ -26,7 +26,7 @@
|
||||
- [x] lambdas
|
||||
- [x] function as method
|
||||
- [x] `function` function
|
||||
- [ ] `funcref` function
|
||||
- [x] `funcref` function
|
||||
- [ ] dictionary functions
|
||||
- [ ] anonymous functions
|
||||
- [ ] `dict` function flag
|
||||
|
Loading…
Reference in New Issue
Block a user