mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-06-07 01:34:03 +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.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.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.FunctionFunctionHandler" name="function"/>
|
||||||
|
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.FuncrefFunctionHandler" name="funcref"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
</idea-plugin>
|
</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.datatypes.VimString
|
||||||
import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
|
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.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.model.functions.FunctionHandler
|
||||||
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
|
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
|
||||||
|
|
||||||
@ -72,8 +73,53 @@ object FunctionFunctionHandler : FunctionHandler() {
|
|||||||
}
|
}
|
||||||
return VimFuncref(function, arglist ?: VimList(mutableListOf()), dictionary ?: VimDictionary(LinkedHashMap()), VimFuncref.Type.FUNCTION)
|
return VimFuncref(function, arglist ?: VimList(mutableListOf()), dictionary ?: VimDictionary(LinkedHashMap()), VimFuncref.Type.FUNCTION)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun String.extractScopeAndName(): Pair<Scope?, String> {
|
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 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(":")
|
val colonIndex = this.indexOf(":")
|
||||||
if (colonIndex == -1) {
|
if (colonIndex == -1) {
|
||||||
return Pair(null, this)
|
return Pair(null, this)
|
||||||
@ -81,5 +127,4 @@ object FunctionFunctionHandler : FunctionHandler() {
|
|||||||
val scopeString = this.substring(0, colonIndex)
|
val scopeString = this.substring(0, colonIndex)
|
||||||
val nameString = this.substring(colonIndex + 1)
|
val nameString = this.substring(colonIndex + 1)
|
||||||
return Pair(Scope.getByValue(scopeString), nameString)
|
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] lambdas
|
||||||
- [x] function as method
|
- [x] function as method
|
||||||
- [x] `function` function
|
- [x] `function` function
|
||||||
- [ ] `funcref` function
|
- [x] `funcref` function
|
||||||
- [ ] dictionary functions
|
- [ ] dictionary functions
|
||||||
- [ ] anonymous functions
|
- [ ] anonymous functions
|
||||||
- [ ] `dict` function flag
|
- [ ] `dict` function flag
|
||||||
|
Loading…
Reference in New Issue
Block a user