1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-05-07 05:34:02 +02:00
This commit is contained in:
lippfi 2021-10-01 01:35:43 +03:00
parent 9cf922ae80
commit d93fb1fdfc
7 changed files with 148 additions and 22 deletions
src/com/maddyhome/idea/vim/vimscript
vimscript-info

View File

@ -20,10 +20,14 @@ package com.maddyhome.idea.vim.vimscript.model.commands
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.vimscript.model.ExecutionResult
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
import com.maddyhome.idea.vim.vimscript.model.expressions.FunctionCallExpression
import com.maddyhome.idea.vim.vimscript.model.expressions.Variable
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
import com.maddyhome.idea.vim.vimscript.services.VariableService
/**
* see "h :call"
@ -33,9 +37,19 @@ class CallCommand(val ranges: Ranges, val functionCall: FunctionCallExpression)
override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED)
override fun processCommand(editor: Editor, context: DataContext): ExecutionResult {
val function = FunctionStorage.getFunctionHandler(functionCall.scope, functionCall.functionName, parent)
function.ranges = ranges
function.executeFunction(functionCall, editor, context, this)
return ExecutionResult.Success
val function = FunctionStorage.getFunctionHandlerOrNull(functionCall.scope, functionCall.functionName, parent)
if (function != null) {
function.ranges = ranges
function.executeFunction(functionCall.functionName, functionCall.arguments, editor, context, this)
return ExecutionResult.Success
}
val funcref = VariableService.getNullableVariableValue(Variable(functionCall.scope, functionCall.functionName), editor, context, parent)
if (funcref is VimFuncref) {
funcref.execute(functionCall.arguments, editor, context, parent)
return ExecutionResult.Success
}
throw ExException("E117: Unknown function: ${if (functionCall.scope != null) functionCall.scope.c + ":" else ""}${functionCall.functionName}")
}
}

View File

@ -0,0 +1,84 @@
/*
* 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.datatypes
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.expressions.Expression
import com.maddyhome.idea.vim.vimscript.model.expressions.SimpleExpression
import com.maddyhome.idea.vim.vimscript.model.functions.DefinedFunctionHandler
import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
data class VimFuncref(
private val definition: FunctionDeclaration,
val arguments: VimList,
val dictionary: VimDictionary, // todo notice me senpai :(
val type: Type,
val isDeleted: Boolean,
) : VimDataType() {
companion object {
var lambdaCounter = 0
}
override fun asDouble(): Double {
throw ExException("E703: using Funcref as a Number")
}
override fun asString(): String {
throw ExException("E729: using Funcref as a String")
}
override fun toString(): String {
return when (type) {
Type.LAMBDA -> "function('<lambda>${this.definition.name}')"
Type.FUNCREF -> "function('${this.definition.name}')"
Type.FUNCTION -> this.definition.name
}
}
override fun toVimNumber(): VimInt {
throw ExException("E703: using Funcref as a Number")
}
fun execute(args: List<Expression>, editor: Editor, context: DataContext, parent: Executable): VimDataType {
val allArguments = listOf(this.arguments.values.map { SimpleExpression(it) }, args).flatten()
if (isDeleted) {
throw ExException("E933: Function was deleted: ${this.definition.name}")
}
val definition = when (type) {
Type.LAMBDA, Type.FUNCREF -> this.definition
Type.FUNCTION -> {
FunctionStorage.getUserDefinedFunction(definition.scope, definition.name, parent)
?: throw ExException("E117: Unknown function: ${this.definition.name}")
}
}
return DefinedFunctionHandler(definition).executeFunction(definition.name, allArguments, editor, context, parent)
}
enum class Type {
LAMBDA,
FUNCREF,
FUNCTION,
}
}

View File

@ -2,15 +2,26 @@ package com.maddyhome.idea.vim.vimscript.model.expressions
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.VimDataType
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
import com.maddyhome.idea.vim.vimscript.services.VariableService
data class FunctionCallExpression(val scope: Scope?, val functionName: String, val arguments: List<Expression>) :
data class FunctionCallExpression(val scope: Scope?, val functionName: String, val arguments: MutableList<Expression>) :
Expression() {
override fun evaluate(editor: Editor, context: DataContext, parent: Executable): VimDataType {
val handler = FunctionStorage.getFunctionHandler(scope, functionName, parent)
return handler.executeFunction(this, editor, context, parent)
val handler = FunctionStorage.getFunctionHandlerOrNull(scope, functionName, parent)
if (handler != null) {
return handler.executeFunction(this.functionName, this.arguments, editor, context, parent)
}
val funcref = VariableService.getNullableVariableValue(Variable(scope, functionName), editor, context, parent)
if (funcref is VimFuncref) {
return funcref.execute(arguments, editor, context, parent)
}
throw ExException("E117: Unknown function: ${if (scope != null) scope.c + ":" else ""}$functionName")
}
}

View File

@ -25,7 +25,6 @@ import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.vimscript.model.Executable
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType
import com.maddyhome.idea.vim.vimscript.model.expressions.Expression
import com.maddyhome.idea.vim.vimscript.model.expressions.FunctionCallExpression
abstract class FunctionHandler {
@ -35,19 +34,19 @@ abstract class FunctionHandler {
protected abstract fun doFunction(argumentValues: List<Expression>, editor: Editor, context: DataContext, parent: Executable): VimDataType
fun executeFunction(functionCall: FunctionCallExpression, editor: Editor, context: DataContext, parent: Executable): VimDataType {
checkFunctionCall(functionCall)
val result = doFunction(functionCall.arguments, editor, context, parent)
fun executeFunction(name: String, arguments: List<Expression>, editor: Editor, context: DataContext, parent: Executable): VimDataType {
checkFunctionCall(name, arguments)
val result = doFunction(arguments, editor, context, parent)
ranges = null
return result
}
private fun checkFunctionCall(functionCall: FunctionCallExpression) {
if (minimumNumberOfArguments != null && functionCall.arguments.size < minimumNumberOfArguments!!) {
throw ExException("E119: Not enough arguments for function: ${functionCall.functionName}")
private fun checkFunctionCall(name: String, arguments: List<Expression>) {
if (minimumNumberOfArguments != null && arguments.size < minimumNumberOfArguments!!) {
throw ExException("E119: Not enough arguments for function: $name")
}
if (maximumNumberOfArguments != null && functionCall.arguments.size > maximumNumberOfArguments!!) {
throw ExException("E118: Too many arguments for function: ${functionCall.functionName}")
if (maximumNumberOfArguments != null && arguments.size > maximumNumberOfArguments!!) {
throw ExException("E118: Too many arguments for function: $name")
}
}
}

View File

@ -26,6 +26,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimBlob
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.VimFloat
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.VimList
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
@ -53,6 +54,7 @@ object EmptyFunctionHandler : FunctionHandler() {
is VimString -> argument.value.isEmpty()
is VimInt -> argument.value == 0
is VimFloat -> argument.value == 0.0
is VimFuncref -> false
is VimBlob -> TODO("Not yet implemented")
}
return isEmpty.asVimInt()

View File

@ -25,10 +25,12 @@ import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.ex.vimscript.VimScriptGlobalEnvironment
import com.maddyhome.idea.vim.vimscript.model.Executable
import com.maddyhome.idea.vim.vimscript.model.ExecutableContext
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.VimDataType
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFloat
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.VimList
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
@ -142,7 +144,12 @@ object VariableService {
break
}
}
node = node.parent
// todo better parent logic
node = if (node is Script) {
null
} else {
node.parent
}
}
visibleVariables.reverse()
@ -163,7 +170,12 @@ object VariableService {
break
}
}
node = node.parent
// todo better parent logic
node = if (node is Script) {
null
} else {
node.parent
}
}
visibleVariables.reverse()
@ -225,7 +237,8 @@ object VariableService {
is VimFloat -> this.value
is VimList -> this.values
is VimDictionary -> this.dictionary
is VimBlob -> throw NotImplementedError("Blobs are not implemented yet :(")
is VimBlob -> "blob"
is VimFuncref -> "funcref"
}
}
}

View File

@ -21,14 +21,16 @@
- [x] `abort` function flag
- [x] `range` function flag
- [x] `call` command
- [ ] function as method
- [x] optional arguments `...`
- [ ] funcref type
- [x] funcref type
- [ ] lambdas
- [ ] default value in functions e.g. `function F1(a, b = 10)`
- [ ] function as method
- [ ] `function` function
- [ ] `funcref` function
- [ ] dictionary functions
- [ ] anonymous functions
- [ ] `dict` function flag
- [ ] default value in functions e.g. `function F1(a, b = 10)`
- [ ] pass Lists and Dictionaries by reference
- [ ] variable locking (`lock`, `unlock`, `const`)
- [ ] rewrite OptionManager to vim data types
@ -50,6 +52,7 @@
- [ ] delayed parsing of if/for/while etc.
- [ ] `has("ide")` or "ide" option
- [ ] `normal` command
- [ ] `finish` statement
- [ ] context dependent parsing e.g. `dict.key`
- [ ] improve `w:` and `t:` scopes
- [ ] `v:` scope