mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-05-18 00:34:04 +02:00
Dictionary functions
This commit is contained in:
parent
769d900383
commit
e0b356c12d
src/com/maddyhome/idea/vim/vimscript/model
commands
datatypes
expressions
DictionaryExpression.ktFuncrefCallExpression.ktFunctionCallExpression.ktLambdaFunctionCallExpression.kt
functions/handlers
statements
test/org/jetbrains/plugins/ideavim/ex/implementation/functions
vimscript-info
@ -55,20 +55,15 @@ class CallCommand(val ranges: Ranges, val functionCall: Expression) : Command.Si
|
|||||||
return ExecutionResult.Success
|
return ExecutionResult.Success
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val name = (if (functionCall.scope != null) functionCall.scope.c + ":" else "") + functionCall.functionName
|
||||||
val funcref = VariableService.getNullableVariableValue(Variable(functionCall.scope, functionCall.functionName), editor, context, parent)
|
val funcref = VariableService.getNullableVariableValue(Variable(functionCall.scope, functionCall.functionName), editor, context, parent)
|
||||||
if (funcref is VimFuncref) {
|
if (funcref is VimFuncref) {
|
||||||
if (funcref.handler is DefinedFunctionHandler && funcref.handler.function.flags.contains(FunctionFlag.DICT) && funcref.handler.function.self == null) {
|
|
||||||
throw ExException(
|
|
||||||
"E725: Calling dict function without Dictionary: " +
|
|
||||||
((if (functionCall.scope != null) functionCall.scope.c + ":" else "") + functionCall.functionName)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
funcref.handler.ranges = ranges
|
funcref.handler.ranges = ranges
|
||||||
funcref.execute(functionCall.arguments, editor, context, parent)
|
funcref.execute(name, functionCall.arguments, editor, context, parent)
|
||||||
return ExecutionResult.Success
|
return ExecutionResult.Success
|
||||||
}
|
}
|
||||||
|
|
||||||
throw ExException("E117: Unknown function: ${if (functionCall.scope != null) functionCall.scope.c + ":" else ""}${functionCall.functionName}")
|
throw ExException("E117: Unknown function: $name")
|
||||||
} else if (functionCall is FuncrefCallExpression) {
|
} else if (functionCall is FuncrefCallExpression) {
|
||||||
functionCall.evaluateWithRange(ranges, editor, context, parent)
|
functionCall.evaluateWithRange(ranges, editor, context, parent)
|
||||||
return ExecutionResult.Success
|
return ExecutionResult.Success
|
||||||
|
@ -14,6 +14,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
|
|||||||
import com.maddyhome.idea.vim.vimscript.model.Script
|
import com.maddyhome.idea.vim.vimscript.model.Script
|
||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimBlob
|
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimBlob
|
||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary
|
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.VimInt
|
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
|
||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimList
|
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
|
||||||
@ -28,6 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.SublistExpression
|
|||||||
import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
|
import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
|
||||||
import com.maddyhome.idea.vim.vimscript.model.expressions.operators.AssignmentOperator
|
import com.maddyhome.idea.vim.vimscript.model.expressions.operators.AssignmentOperator
|
||||||
import com.maddyhome.idea.vim.vimscript.model.expressions.toVimDataType
|
import com.maddyhome.idea.vim.vimscript.model.expressions.toVimDataType
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.functions.DefinedFunctionHandler
|
||||||
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
|
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
|
||||||
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag
|
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag
|
||||||
import com.maddyhome.idea.vim.vimscript.services.VariableService
|
import com.maddyhome.idea.vim.vimscript.services.VariableService
|
||||||
@ -66,15 +68,19 @@ data class LetCommand(
|
|||||||
if (operator != AssignmentOperator.ASSIGNMENT && !variableValue.dictionary.containsKey(dictKey)) {
|
if (operator != AssignmentOperator.ASSIGNMENT && !variableValue.dictionary.containsKey(dictKey)) {
|
||||||
throw ExException("E716: Key not present in Dictionary: $dictKey")
|
throw ExException("E716: Key not present in Dictionary: $dictKey")
|
||||||
}
|
}
|
||||||
if (variableValue.dictionary.containsKey(dictKey)) {
|
var valueToStore = if (variableValue.dictionary.containsKey(dictKey)) {
|
||||||
variableValue.dictionary[dictKey] =
|
operator.getNewValue(SimpleExpression(variableValue.dictionary[dictKey]!!), expression, editor, context, this)
|
||||||
operator.getNewValue(
|
|
||||||
SimpleExpression(variableValue.dictionary[dictKey]!!), expression, editor,
|
|
||||||
context, this
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
variableValue.dictionary[dictKey] = expression.evaluate(editor, context, this)
|
expression.evaluate(editor, context, this)
|
||||||
}
|
}
|
||||||
|
if (valueToStore is VimFuncref && !valueToStore.isSelfFixed &&
|
||||||
|
valueToStore.handler is DefinedFunctionHandler &&
|
||||||
|
(valueToStore.handler as DefinedFunctionHandler).function.flags.contains(FunctionFlag.DICT)
|
||||||
|
) {
|
||||||
|
valueToStore = valueToStore.copy()
|
||||||
|
valueToStore.dictionary = variableValue
|
||||||
|
}
|
||||||
|
variableValue.dictionary[dictKey] = valueToStore
|
||||||
}
|
}
|
||||||
is VimList -> {
|
is VimList -> {
|
||||||
// we use Integer.parseInt(........asString()) because in case if index's type is Float, List, Dictionary etc
|
// we use Integer.parseInt(........asString()) because in case if index's type is Float, List, Dictionary etc
|
||||||
|
@ -18,14 +18,17 @@ data class VimDictionary(val dictionary: LinkedHashMap<VimString, VimDataType>)
|
|||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
val result = StringBuffer("{")
|
val result = StringBuffer("{")
|
||||||
result.append(dictionary.map { it.stringOfEntry() }.joinToString(separator = ", "))
|
result.append(dictionary.map { stringOfEntry(it) }.joinToString(separator = ", "))
|
||||||
result.append("}")
|
result.append("}")
|
||||||
return result.toString()
|
return result.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun Map.Entry<VimString, VimDataType>.stringOfEntry(): String {
|
private fun stringOfEntry(entry: Map.Entry<VimString, VimDataType>): String {
|
||||||
val valueString = if (this.value is VimString) "'${this.value}'" else this.value.toString()
|
val valueString = when (entry.value) {
|
||||||
return "'${this.key}': $valueString"
|
is VimString -> "'${entry.value}'"
|
||||||
|
else -> entry.value.toString()
|
||||||
|
}
|
||||||
|
return "'${entry.key}': $valueString"
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun asBoolean(): Boolean {
|
override fun asBoolean(): Boolean {
|
||||||
|
@ -23,22 +23,27 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.maddyhome.idea.vim.ex.ExException
|
import com.maddyhome.idea.vim.ex.ExException
|
||||||
import com.maddyhome.idea.vim.vimscript.model.Executable
|
import com.maddyhome.idea.vim.vimscript.model.Executable
|
||||||
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.SimpleExpression
|
import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
|
||||||
import com.maddyhome.idea.vim.vimscript.model.functions.DefinedFunctionHandler
|
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.model.statements.FunctionFlag
|
||||||
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
|
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
|
||||||
|
import com.maddyhome.idea.vim.vimscript.services.VariableService
|
||||||
|
|
||||||
data class VimFuncref(
|
data class VimFuncref(
|
||||||
val handler: FunctionHandler,
|
val handler: FunctionHandler,
|
||||||
val arguments: VimList,
|
val arguments: VimList,
|
||||||
val dictionary: VimDictionary,
|
var dictionary: VimDictionary?,
|
||||||
val type: Type,
|
val type: Type,
|
||||||
) : VimDataType() {
|
) : VimDataType(), Cloneable {
|
||||||
|
|
||||||
var isSelfFixed = false
|
var isSelfFixed = false
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
var lambdaCounter = 0
|
var lambdaCounter = 1
|
||||||
|
var anonymousCounter = 1
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun asDouble(): Double {
|
override fun asDouble(): Double {
|
||||||
@ -50,14 +55,19 @@ data class VimFuncref(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun toString(): String {
|
override fun toString(): String {
|
||||||
return if (arguments.values.isEmpty()) {
|
return if (arguments.values.isEmpty() && dictionary == null) {
|
||||||
when (type) {
|
when (type) {
|
||||||
Type.LAMBDA -> "function('${handler.name}')"
|
Type.LAMBDA -> "function('${handler.name}')"
|
||||||
Type.FUNCREF -> "function('${handler.name}')"
|
Type.FUNCREF -> "function('${handler.name}')"
|
||||||
Type.FUNCTION -> handler.name
|
Type.FUNCTION -> handler.name
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
"function('${handler.name}', $arguments)"
|
val result = StringBuffer("function('${handler.name}'")
|
||||||
|
if (arguments.values.isNotEmpty()) {
|
||||||
|
result.append(", ").append(arguments.toString())
|
||||||
|
}
|
||||||
|
result.append(")")
|
||||||
|
return result.toString()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -65,7 +75,21 @@ data class VimFuncref(
|
|||||||
throw ExException("E703: using Funcref as a Number")
|
throw ExException("E703: using Funcref as a Number")
|
||||||
}
|
}
|
||||||
|
|
||||||
fun execute(args: List<Expression>, editor: Editor, context: DataContext, parent: Executable): VimDataType {
|
fun execute(name: String, args: List<Expression>, editor: Editor, context: DataContext, parent: Executable): VimDataType {
|
||||||
|
if (handler is DefinedFunctionHandler && handler.function.flags.contains(FunctionFlag.DICT)) {
|
||||||
|
if (dictionary == null) {
|
||||||
|
throw ExException("E725: Calling dict function without Dictionary: $name")
|
||||||
|
} else {
|
||||||
|
VariableService.storeVariable(
|
||||||
|
Variable(Scope.LOCAL_VARIABLE, "self"),
|
||||||
|
dictionary!!,
|
||||||
|
editor,
|
||||||
|
context,
|
||||||
|
handler.function
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val allArguments = listOf(this.arguments.values.map { SimpleExpression(it) }, args).flatten()
|
val allArguments = listOf(this.arguments.values.map { SimpleExpression(it) }, args).flatten()
|
||||||
if (handler is DefinedFunctionHandler && handler.function.isDeleted) {
|
if (handler is DefinedFunctionHandler && handler.function.isDeleted) {
|
||||||
throw ExException("E933: Function was deleted: ${handler.name}")
|
throw ExException("E933: Function was deleted: ${handler.name}")
|
||||||
@ -80,6 +104,10 @@ data class VimFuncref(
|
|||||||
return handler.executeFunction(allArguments, editor, context, parent)
|
return handler.executeFunction(allArguments, editor, context, parent)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun clone(): Any {
|
||||||
|
return VimFuncref(handler, arguments, dictionary, type)
|
||||||
|
}
|
||||||
|
|
||||||
enum class Type {
|
enum class Type {
|
||||||
LAMBDA,
|
LAMBDA,
|
||||||
FUNCREF,
|
FUNCREF,
|
||||||
|
@ -23,15 +23,23 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.maddyhome.idea.vim.vimscript.model.Executable
|
import com.maddyhome.idea.vim.vimscript.model.Executable
|
||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
|
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
|
||||||
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary
|
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.VimString
|
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
|
||||||
|
import com.maddyhome.idea.vim.vimscript.model.functions.DefinedFunctionHandler
|
||||||
|
|
||||||
data class DictionaryExpression(val dictionary: LinkedHashMap<Expression, Expression>) : Expression() {
|
data class DictionaryExpression(val dictionary: LinkedHashMap<Expression, Expression>) : Expression() {
|
||||||
|
|
||||||
override fun evaluate(editor: Editor, context: DataContext, parent: Executable): VimDataType {
|
override fun evaluate(editor: Editor, context: DataContext, parent: Executable): VimDataType {
|
||||||
val dict: LinkedHashMap<VimString, VimDataType> = linkedMapOf()
|
val dict = VimDictionary(linkedMapOf())
|
||||||
for ((key, value) in dictionary) {
|
for ((key, value) in dictionary) {
|
||||||
dict[VimString(key.evaluate(editor, context, parent).asString())] = value.evaluate(editor, context, parent)
|
val evaluatedVal = value.evaluate(editor, context, parent)
|
||||||
|
var newFuncref = evaluatedVal
|
||||||
|
if (evaluatedVal is VimFuncref && evaluatedVal.handler is DefinedFunctionHandler && !evaluatedVal.isSelfFixed) {
|
||||||
|
newFuncref = evaluatedVal.copy()
|
||||||
|
newFuncref.dictionary = dict
|
||||||
|
}
|
||||||
|
dict.dictionary[VimString(key.evaluate(editor, context, parent).asString())] = newFuncref
|
||||||
}
|
}
|
||||||
return VimDictionary(dict)
|
return dict
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -32,7 +32,7 @@ data class FuncrefCallExpression(val expression: Expression, val args: List<Expr
|
|||||||
val value = expression.evaluate(editor, context, parent)
|
val value = expression.evaluate(editor, context, parent)
|
||||||
if (value is VimFuncref) {
|
if (value is VimFuncref) {
|
||||||
value.handler.ranges = ranges
|
value.handler.ranges = ranges
|
||||||
return value.execute(args, editor, context, parent)
|
return value.execute(value.handler.name, args, editor, context, parent)
|
||||||
} else {
|
} else {
|
||||||
// todo more exceptions
|
// todo more exceptions
|
||||||
throw ExException("E15: Invalid expression")
|
throw ExException("E15: Invalid expression")
|
||||||
|
@ -25,10 +25,8 @@ data class FunctionCallExpression(val scope: Scope?, val functionName: String, v
|
|||||||
|
|
||||||
val funcref = VariableService.getNullableVariableValue(Variable(scope, functionName), editor, context, parent)
|
val funcref = VariableService.getNullableVariableValue(Variable(scope, functionName), editor, context, parent)
|
||||||
if (funcref is VimFuncref) {
|
if (funcref is VimFuncref) {
|
||||||
if (funcref.handler is DefinedFunctionHandler && funcref.handler.function.flags.contains(FunctionFlag.DICT) && funcref.handler.function.self == null) {
|
val name = (if (scope != null) scope.c + ":" else "") + functionName
|
||||||
throw ExException("E725: Calling dict function without Dictionary: ${(if (scope != null) scope.c + ":" else "") + functionName}")
|
return funcref.execute(name, arguments, editor, context, parent)
|
||||||
}
|
|
||||||
return funcref.execute(arguments, editor, context, parent)
|
|
||||||
}
|
}
|
||||||
throw ExException("E117: Unknown function: ${if (scope != null) scope.c + ":" else ""}$functionName")
|
throw ExException("E117: Unknown function: ${if (scope != null) scope.c + ":" else ""}$functionName")
|
||||||
}
|
}
|
||||||
|
@ -27,6 +27,6 @@ class LambdaFunctionCallExpression(val lambda: LambdaExpression, val arguments:
|
|||||||
|
|
||||||
override fun evaluate(editor: Editor, context: DataContext, parent: Executable): VimDataType {
|
override fun evaluate(editor: Editor, context: DataContext, parent: Executable): VimDataType {
|
||||||
val funcref = lambda.evaluate(editor, context, parent)
|
val funcref = lambda.evaluate(editor, context, parent)
|
||||||
return funcref.execute(arguments, editor, context, parent)
|
return funcref.execute("", arguments, editor, context, parent)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,7 +71,11 @@ object FunctionFunctionHandler : FunctionHandler() {
|
|||||||
if (arg3 != null && arg3 !is VimDictionary) {
|
if (arg3 != null && arg3 !is VimDictionary) {
|
||||||
throw ExException("E922: expected a dict")
|
throw ExException("E922: expected a dict")
|
||||||
}
|
}
|
||||||
return VimFuncref(function, arglist ?: VimList(mutableListOf()), dictionary ?: VimDictionary(LinkedHashMap()), VimFuncref.Type.FUNCTION)
|
val funcref = VimFuncref(function, arglist ?: VimList(mutableListOf()), dictionary, VimFuncref.Type.FUNCTION)
|
||||||
|
if (dictionary != null) {
|
||||||
|
funcref.isSelfFixed = true
|
||||||
|
}
|
||||||
|
return funcref
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,7 +119,7 @@ object FuncrefFunctionHandler : FunctionHandler() {
|
|||||||
if (arg3 != null && arg3 !is VimDictionary) {
|
if (arg3 != null && arg3 !is VimDictionary) {
|
||||||
throw ExException("E922: expected a dict")
|
throw ExException("E922: expected a dict")
|
||||||
}
|
}
|
||||||
return VimFuncref(handler, arglist ?: VimList(mutableListOf()), dictionary ?: VimDictionary(LinkedHashMap()), VimFuncref.Type.FUNCREF)
|
return VimFuncref(handler, arglist ?: VimList(mutableListOf()), dictionary, VimFuncref.Type.FUNCREF)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,7 +20,6 @@ data class FunctionDeclaration(
|
|||||||
) : Executable {
|
) : Executable {
|
||||||
override lateinit var parent: Executable
|
override lateinit var parent: Executable
|
||||||
var isDeleted = false
|
var isDeleted = false
|
||||||
var self: VimDataType? = null
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* we store the "a:" and "l:" scope variables here
|
* we store the "a:" and "l:" scope variables here
|
||||||
|
@ -0,0 +1,222 @@
|
|||||||
|
/*
|
||||||
|
* 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 DictionaryFunctionTest : VimTestCase() {
|
||||||
|
|
||||||
|
fun `test self in dictionary function with assignment via function function`() {
|
||||||
|
configureByText("\n")
|
||||||
|
typeText(
|
||||||
|
commandToKeys(
|
||||||
|
"""
|
||||||
|
function Print() dict |
|
||||||
|
echo self.data |
|
||||||
|
endfunction
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
typeText(commandToKeys("let dict = {'data': [], 'print': function('Print')}"))
|
||||||
|
typeText(commandToKeys("call dict.print()"))
|
||||||
|
assertExOutput("[]\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("delfunction! Print"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test self in dictionary function with assignment via let command`() {
|
||||||
|
configureByText("\n")
|
||||||
|
typeText(
|
||||||
|
commandToKeys(
|
||||||
|
"""
|
||||||
|
function Print() dict |
|
||||||
|
echo self.name |
|
||||||
|
endfunction
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
typeText(commandToKeys("let dict = {'name': 'dict_name'}"))
|
||||||
|
typeText(commandToKeys("let PrintFr = function('Print')"))
|
||||||
|
typeText(commandToKeys("let dict.print = PrintFr"))
|
||||||
|
typeText(commandToKeys("call dict.print()"))
|
||||||
|
assertExOutput("dict_name\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("delfunction! Print"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||||
|
fun `test dictionary function without dict`() {
|
||||||
|
configureByText("\n")
|
||||||
|
typeText(
|
||||||
|
commandToKeys(
|
||||||
|
"""
|
||||||
|
function Print() dict |
|
||||||
|
echo self |
|
||||||
|
endfunction
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
typeText(commandToKeys("call Print()"))
|
||||||
|
assertPluginError(true)
|
||||||
|
assertPluginErrorMessageContains("E725: Calling dict function without Dictionary: Print")
|
||||||
|
|
||||||
|
typeText(commandToKeys("delfunction! Print"))
|
||||||
|
}
|
||||||
|
|
||||||
|
// todo big brain logic
|
||||||
|
// fun `test assigned dictionary function to another dictionary`() {
|
||||||
|
// configureByText("\n")
|
||||||
|
// typeText(
|
||||||
|
// commandToKeys(
|
||||||
|
// """
|
||||||
|
// function Print() dict |
|
||||||
|
// echo self.name |
|
||||||
|
// endfunction
|
||||||
|
// """.trimIndent()
|
||||||
|
// )
|
||||||
|
// )
|
||||||
|
// typeText(commandToKeys("let dict = {'name': 'dict', 'print': function('Print')}"))
|
||||||
|
// typeText(commandToKeys("echo dict.print"))
|
||||||
|
// assertExOutput("function('Print', {'name': 'dict', 'print': function('Print')}")
|
||||||
|
// typeText(commandToKeys("echo dict"))
|
||||||
|
// assertExOutput("{'name': 'dict', 'print': function('Print')}")
|
||||||
|
// typeText(commandToKeys("call dict.print()"))
|
||||||
|
// assertExOutput("dict\n")
|
||||||
|
//
|
||||||
|
// typeText(commandToKeys("let dict2 = {'name': 'dict2', 'print': dict.print}"))
|
||||||
|
// typeText(commandToKeys("echo dict2.print"))
|
||||||
|
// assertExOutput("function('Print', {'name': 'dict2', 'print': function('Print', {name: 'dict', 'print': function('Print')})}")
|
||||||
|
// typeText(commandToKeys("echo dict2"))
|
||||||
|
// assertExOutput("{'name': 'dict2', 'print': function('Print', {name: 'dict', 'print': function('Print')})}")
|
||||||
|
// typeText(commandToKeys("call dict2.print()"))
|
||||||
|
// assertExOutput("dict2\n")
|
||||||
|
//
|
||||||
|
// typeText(commandToKeys("delfunction! Print"))
|
||||||
|
// }
|
||||||
|
|
||||||
|
fun `test self is not changed after let assignment`() {
|
||||||
|
configureByText("\n")
|
||||||
|
typeText(
|
||||||
|
commandToKeys(
|
||||||
|
"""
|
||||||
|
function Print() dict |
|
||||||
|
echo self.name |
|
||||||
|
endfunction
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
typeText(commandToKeys("let dict = {'name': 'dict', 'print': function('Print')}"))
|
||||||
|
typeText(commandToKeys("let dict2 = {'name': 'dict2'}"))
|
||||||
|
typeText(commandToKeys("let dict2.print = dict.print"))
|
||||||
|
|
||||||
|
typeText(commandToKeys("call dict2.print()"))
|
||||||
|
assertExOutput("dict2\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("call dict.print()"))
|
||||||
|
assertExOutput("dict\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("delfunction! Print"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test self is not changed after in-dictionary assignment`() {
|
||||||
|
configureByText("\n")
|
||||||
|
typeText(
|
||||||
|
commandToKeys(
|
||||||
|
"""
|
||||||
|
function Print() dict |
|
||||||
|
echo self.name |
|
||||||
|
endfunction
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
typeText(commandToKeys("let dict = {'name': 'dict', 'print': function('Print')}"))
|
||||||
|
typeText(commandToKeys("let dict2 = {'name': 'dict2', 'print': dict.print}"))
|
||||||
|
|
||||||
|
typeText(commandToKeys("call dict2.print()"))
|
||||||
|
assertExOutput("dict2\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("call dict.print()"))
|
||||||
|
assertExOutput("dict\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("delfunction! Print"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test assigned partial to another dictionary`() {
|
||||||
|
configureByText("\n")
|
||||||
|
typeText(
|
||||||
|
commandToKeys(
|
||||||
|
"""
|
||||||
|
function Print() dict |
|
||||||
|
echo self.name |
|
||||||
|
endfunction
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
typeText(commandToKeys("let dict = {'name': 'dict'}"))
|
||||||
|
typeText(commandToKeys("let dict.print = function('Print', dict)"))
|
||||||
|
typeText(commandToKeys("call dict.print()"))
|
||||||
|
assertExOutput("dict\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("let dict2 = {'name': 'dict2', 'print': dict.print}"))
|
||||||
|
typeText(commandToKeys("call dict2.print()"))
|
||||||
|
assertExOutput("dict\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("delfunction! Print"))
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.PLUGIN_ERROR)
|
||||||
|
fun `test self is read-only`() {
|
||||||
|
configureByText("\n")
|
||||||
|
typeText(
|
||||||
|
commandToKeys(
|
||||||
|
"""
|
||||||
|
function Print() dict |
|
||||||
|
let self = [] |
|
||||||
|
endfunction
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
typeText(commandToKeys("let dict = {'name': 'dict', 'print': function('Print')}"))
|
||||||
|
typeText(commandToKeys("call dict.print()"))
|
||||||
|
assertPluginError(true)
|
||||||
|
assertPluginErrorMessageContains("E46: Cannot change read-only variable \"self\"")
|
||||||
|
|
||||||
|
typeText(commandToKeys("delfunction! Print"))
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test self in inner dictionary`() {
|
||||||
|
configureByText("\n")
|
||||||
|
typeText(
|
||||||
|
commandToKeys(
|
||||||
|
"""
|
||||||
|
function Print() dict |
|
||||||
|
echo self.name |
|
||||||
|
endfunction
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
)
|
||||||
|
typeText(commandToKeys("let dict = {'name': 'dict', 'innerDict': {'name': 'innerDict', 'print': function('Print')}}"))
|
||||||
|
typeText(commandToKeys("call dict.innerDict.print()"))
|
||||||
|
assertExOutput("innerDict\n")
|
||||||
|
|
||||||
|
typeText(commandToKeys("delfunction! Print"))
|
||||||
|
}
|
||||||
|
}
|
@ -27,9 +27,8 @@
|
|||||||
- [x] function as method
|
- [x] function as method
|
||||||
- [x] `function` function
|
- [x] `function` function
|
||||||
- [x] `funcref` function
|
- [x] `funcref` function
|
||||||
- [ ] dictionary functions
|
- [x] `dict` function flag
|
||||||
- [ ] anonymous functions
|
- [ ] anonymous functions
|
||||||
- [ ] `dict` function flag
|
|
||||||
- [ ] default value in functions e.g. `function F1(a, b = 10)`
|
- [ ] default value in functions e.g. `function F1(a, b = 10)`
|
||||||
- [ ] delayed parsing of if/for/while etc.
|
- [ ] delayed parsing of if/for/while etc.
|
||||||
- [ ] `has("ide")` or "ide" option
|
- [ ] `has("ide")` or "ide" option
|
||||||
|
Loading…
Reference in New Issue
Block a user