mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-05-10 21:34:06 +02:00
function()
function
This commit is contained in:
parent
f516e89a5f
commit
07d753f413
resources/META-INF/includes
src/com/maddyhome/idea/vim/vimscript/model
test/org/jetbrains/plugins/ideavim/ex/implementation/functions
vimscript-info
@ -7,5 +7,6 @@
|
||||
<vimLibraryFunction implementation="com.maddyhome.idea.vim.vimscript.model.functions.handlers.SinFunctionHandler" name="sin"/>
|
||||
<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"/>
|
||||
</extensions>
|
||||
</idea-plugin>
|
@ -30,8 +30,8 @@ enum class Scope(val c: String) {
|
||||
VIM_VARIABLE("v");
|
||||
|
||||
companion object {
|
||||
fun getByValue(s: String): Scope {
|
||||
return values().first { it.c == s }
|
||||
fun getByValue(s: String): Scope? {
|
||||
return values().firstOrNull { it.c == s }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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 com.maddyhome.idea.vim.vimscript.model.functions.handlers
|
||||
|
||||
import com.intellij.openapi.actionSystem.DataContext
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.maddyhome.idea.vim.ex.ExException
|
||||
import com.maddyhome.idea.vim.vimscript.model.Executable
|
||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary
|
||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
|
||||
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.FunctionHandler
|
||||
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
|
||||
|
||||
object FunctionFunctionHandler : 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.getFunctionHandlerOrNull(scopeAndName.first, scopeAndName.second, parent)
|
||||
?: throw ExException("E700: Unknown function: ${if (scopeAndName.first != null) scopeAndName.first!!.c + ":" else ""}${scopeAndName.second}")
|
||||
|
||||
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(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)
|
||||
}
|
||||
val scopeString = this.substring(0, colonIndex)
|
||||
val nameString = this.substring(colonIndex + 1)
|
||||
return Pair(Scope.getByValue(scopeString), nameString)
|
||||
}
|
||||
}
|
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* 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 FunctionTest : VimTestCase() {
|
||||
|
||||
fun `test function for built-in function`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = function('abs')"))
|
||||
typeText(commandToKeys("echo Ff(-10)"))
|
||||
assertExOutput("10\n")
|
||||
|
||||
typeText(commandToKeys("echo Ff"))
|
||||
assertExOutput("abs\n")
|
||||
}
|
||||
|
||||
fun `test function with arglist`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = function('abs', [-10])"))
|
||||
typeText(commandToKeys("echo Ff()"))
|
||||
assertExOutput("10\n")
|
||||
|
||||
typeText(commandToKeys("echo Ff"))
|
||||
assertExOutput("function('abs', [-10])\n")
|
||||
}
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test function for unknown function`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = function('unknown')"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E700: Unknown function: unknown")
|
||||
}
|
||||
|
||||
// todo in release 1.9 (good example of multiple exceptions at once)
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test function with wrong function name`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = function(32)"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E129: Function name required")
|
||||
}
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test function with wrong second argument`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = function('abs', 10)"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E923: Second argument of function() must be a list or a dict")
|
||||
}
|
||||
|
||||
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||
fun `test function with wrong third argument`() {
|
||||
configureByText("\n")
|
||||
typeText(commandToKeys("let Ff = function('abs', [], 40)"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E922: expected a dict")
|
||||
}
|
||||
|
||||
fun `test redefining a function`() {
|
||||
configureByText("\n")
|
||||
typeText(
|
||||
commandToKeys(
|
||||
"""
|
||||
function! SayHi() |
|
||||
echo 'hello' |
|
||||
endfunction
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
typeText(commandToKeys("let Ff = function('SayHi')"))
|
||||
typeText(commandToKeys("call Ff()"))
|
||||
assertExOutput("hello\n")
|
||||
|
||||
typeText(
|
||||
commandToKeys(
|
||||
"""
|
||||
function! SayHi() |
|
||||
echo 'hi' |
|
||||
endfunction
|
||||
""".trimIndent()
|
||||
)
|
||||
)
|
||||
typeText(commandToKeys("call Ff()"))
|
||||
assertExOutput("hi\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 = function('SayHi')"))
|
||||
typeText(commandToKeys("delfunction! SayHi"))
|
||||
typeText(commandToKeys("call Ff()"))
|
||||
assertPluginError(true)
|
||||
assertPluginErrorMessageContains("E933: Function was deleted: SayHi")
|
||||
}
|
||||
}
|
@ -25,7 +25,7 @@
|
||||
- [x] funcref type
|
||||
- [x] lambdas
|
||||
- [x] function as method
|
||||
- [ ] `function` function
|
||||
- [x] `function` function
|
||||
- [ ] `funcref` function
|
||||
- [ ] dictionary functions
|
||||
- [ ] anonymous functions
|
||||
|
Loading…
Reference in New Issue
Block a user