From c34a7f123df9304355d2bd82cff24fefdc93e04a Mon Sep 17 00:00:00 2001 From: Alex Plate Date: Sun, 10 Apr 2022 00:15:21 +0000 Subject: [PATCH 1/2] Update formatting --- .../idea/vim/extension/matchit/Matchit.kt | 28 ++-- .../extension/matchit/MatchitCMakeTest.kt | 1 - .../ideavim/extension/matchit/MatchitCTest.kt | 129 +++++++++--------- .../extension/matchit/MatchitGNUMakeTest.kt | 3 +- .../extension/matchit/MatchitRubyTest.kt | 3 +- 5 files changed, 80 insertions(+), 84 deletions(-) diff --git a/src/main/java/com/maddyhome/idea/vim/extension/matchit/Matchit.kt b/src/main/java/com/maddyhome/idea/vim/extension/matchit/Matchit.kt index 96a0c92e9f9..324680d8068 100644 --- a/src/main/java/com/maddyhome/idea/vim/extension/matchit/Matchit.kt +++ b/src/main/java/com/maddyhome/idea/vim/extension/matchit/Matchit.kt @@ -156,7 +156,7 @@ private data class LanguagePatterns( val reversedClosings: PatternsTable, ) { // Helper constructor for languages that don't need reversed patterns. - constructor(openings: PatternsTable, closings: PatternsTable): this(openings, closings, openings, closings) + constructor(openings: PatternsTable, closings: PatternsTable) : this(openings, closings, openings, closings) operator fun plus(newLanguagePatterns: LanguagePatterns): LanguagePatterns { return LanguagePatterns( @@ -270,8 +270,8 @@ private object FileTypePatterns { return ( LanguagePatterns("<", ">") + - LanguagePatterns(mapOf(openingTagPattern to htmlSearchPair), mapOf(closingTagPattern to htmlSearchPair)) - ) + LanguagePatterns(mapOf(openingTagPattern to htmlSearchPair), mapOf(closingTagPattern to htmlSearchPair)) + ) } private fun createRubyPatterns(): LanguagePatterns { @@ -291,8 +291,8 @@ private object FileTypePatterns { return ( LanguagePatterns(blockCommentStart, blockCommentEnd) + - LanguagePatterns(openingKeywords, middleKeywords, endKeyword) - ) + LanguagePatterns(openingKeywords, middleKeywords, endKeyword) + ) } private fun createCPatterns(): LanguagePatterns { @@ -304,20 +304,19 @@ private object FileTypePatterns { // Original patterns: https://github.com/vim/vim/blob/master/runtime/ftplugin/make.vim return ( LanguagePatterns("\\bdefine\\b", "\\bendef\\b") + - LanguagePatterns("(? Date: Sun, 10 Apr 2022 15:57:46 +0600 Subject: [PATCH 2/2] Move some classes from vimscript package to engine --- .../change/insert/InsertRegisterAction.kt | 4 +- .../action/macro/PlaybackRegisterAction.kt | 2 +- .../vim/extension/VimExtensionRegistrar.kt | 2 +- .../idea/vim/group/IjStatisticsService.kt | 68 + .../idea/vim/group/ProcessGroup.java | 2 +- .../maddyhome/idea/vim/group/SearchGroup.java | 24 +- .../idea/vim/helper/IjEditorHelper.kt | 5 + .../idea/vim/helper/IjVimStringParser.kt | 8 + .../com/maddyhome/idea/vim/helper/Msg.java | 75 - .../idea/vim/helper/SearchHelper.java | 8 +- .../com/maddyhome/idea/vim/key/MappingInfo.kt | 2 +- .../idea/vim/newapi/IjVimApplication.kt | 9 + .../maddyhome/idea/vim/newapi/IjVimCaret.kt | 5 + .../maddyhome/idea/vim/newapi/IjVimEditor.kt | 8 + .../idea/vim/newapi/IjVimInjector.kt | 22 + .../idea/vim/newapi/IjVimMessages.kt | 2 +- .../idea/vim/regexp/CharPointer.java | 300 - .../idea/vim/regexp/CharacterClasses.java | 159 - .../com/maddyhome/idea/vim/regexp/Magic.java | 117 - .../com/maddyhome/idea/vim/regexp/RegExp.java | 4917 ----------------- .../com/maddyhome/idea/vim/ui/ReloadVimRc.kt | 7 +- .../idea/vim/ui/ex/ExEntryPanel.java | 3 +- .../maddyhome/idea/vim/vimscript/Executor.kt | 30 +- .../vimscript/model/commands/ActionCommand.kt | 10 +- .../model/commands/ActionListCommand.kt | 9 +- .../vimscript/model/commands/AsciiCommand.kt | 9 +- .../model/commands/BufferCloseCommand.kt | 11 +- .../vimscript/model/commands/BufferCommand.kt | 24 +- .../model/commands/BufferListCommand.kt | 22 +- .../vimscript/model/commands/CallCommand.kt | 6 +- .../model/commands/CmdClearCommand.kt | 6 +- .../vimscript/model/commands/CmdCommand.kt | 13 +- .../model/commands/CmdFilterCommand.kt | 21 +- .../model/commands/CopyTextCommand.kt | 19 +- .../vimscript/model/commands/DelCmdCommand.kt | 6 +- .../model/commands/DeleteLinesCommand.kt | 12 +- .../model/commands/DeleteMarksCommand.kt | 11 +- .../model/commands/DelfunctionCommand.kt | 6 +- .../model/commands/DigraphCommand.kt | 9 +- .../model/commands/DumpLineCommand.kt | 15 +- .../vimscript/model/commands/EchoCommand.kt | 9 +- .../model/commands/EditFileCommand.kt | 17 +- .../model/commands/ExecuteCommand.kt | 10 +- .../vimscript/model/commands/ExitCommand.kt | 9 +- .../vimscript/model/commands/FileCommand.kt | 9 +- .../model/commands/FindClassCommand.kt | 13 +- .../model/commands/FindFileCommand.kt | 13 +- .../model/commands/FindSymbolCommand.kt | 9 +- .../vimscript/model/commands/GlobalCommand.kt | 42 +- .../model/commands/GoToLineCommand.kt | 24 +- .../model/commands/GotoCharacterCommand.kt | 14 +- .../vimscript/model/commands/HelpCommand.kt | 6 +- .../model/commands/HistoryCommand.kt | 9 +- .../model/commands/JoinLinesCommand.kt | 12 +- .../vimscript/model/commands/JumpsCommand.kt | 13 +- .../model/commands/LockVarCommand.kt | 8 +- .../vimscript/model/commands/MarkCommand.kt | 12 +- .../vimscript/model/commands/MarksCommand.kt | 15 +- .../model/commands/MoveTextCommand.kt | 34 +- .../model/commands/NextFileCommand.kt | 12 +- .../model/commands/NextTabCommand.kt | 9 +- .../model/commands/NoHLSearchCommand.kt | 6 +- .../vimscript/model/commands/NormalCommand.kt | 36 +- .../vimscript/model/commands/OnlyCommand.kt | 9 +- .../model/commands/PackaddCommand.kt | 6 +- .../vimscript/model/commands/PlugCommand.kt | 6 +- .../model/commands/PreviousFileCommand.kt | 12 +- .../model/commands/PreviousTabCommand.kt | 9 +- .../vimscript/model/commands/PrintCommand.kt | 15 +- .../model/commands/PromptFindCommand.kt | 9 +- .../model/commands/PromptReplaceCommand.kt | 9 +- .../model/commands/PutLinesCommand.kt | 11 +- .../vimscript/model/commands/QuitCommand.kt | 9 +- .../vimscript/model/commands/RedoCommand.kt | 9 +- .../model/commands/RegistersCommand.kt | 9 +- .../vimscript/model/commands/RepeatCommand.kt | 21 +- .../model/commands/SelectFileCommand.kt | 12 +- .../model/commands/SelectFirstFileCommand.kt | 12 +- .../model/commands/SelectLastFileCommand.kt | 12 +- .../vimscript/model/commands/SetCommand.kt | 26 +- .../model/commands/SetHandlerCommand.kt | 6 +- .../vimscript/model/commands/ShellCommand.kt | 9 +- .../model/commands/ShiftLeftCommand.kt | 13 +- .../model/commands/ShiftRightCommand.kt | 13 +- .../vimscript/model/commands/SortCommand.kt | 28 +- .../vimscript/model/commands/SourceCommand.kt | 6 +- .../vimscript/model/commands/SplitCommand.kt | 11 +- .../model/commands/SubstituteCommand.kt | 12 +- .../model/commands/TabCloseCommand.kt | 9 +- .../model/commands/TabMoveCommand.kt | 13 +- .../model/commands/TabOnlyCommand.kt | 9 +- .../vimscript/model/commands/UndoCommand.kt | 9 +- .../model/commands/UnknownCommand.kt | 11 +- .../model/commands/WriteAllCommand.kt | 9 +- .../vimscript/model/commands/WriteCommand.kt | 9 +- .../model/commands/WriteNextFileCommand.kt | 14 +- .../commands/WritePreviousFileCommand.kt | 14 +- .../model/commands/WriteQuitCommand.kt | 11 +- .../model/commands/YankLinesCommand.kt | 16 +- .../model/commands/mapping/MapClearCommand.kt | 6 +- .../model/commands/mapping/MapCommand.kt | 11 +- .../model/commands/mapping/UnMapCommand.kt | 6 +- .../functions/handlers/AbsFunctionHandler.kt | 8 +- .../handlers/ColLineFunctionHandler.kt | 50 +- .../handlers/EmptyFunctionHandler.kt | 8 +- .../handlers/ExistsFunctionHandler.kt | 10 +- .../handlers/FunctionFunctionHandler.kt | 12 +- .../functions/handlers/HasFunctionHandler.kt | 8 +- .../functions/handlers/LenFunctionHandler.kt | 8 +- .../functions/handlers/SinFunctionHandler.kt | 8 +- .../handlers/SubmatchFunctionHandler.kt | 8 +- .../vim/vimscript/parser/VimscriptParser.kt | 14 +- .../vim/vimscript/services/FunctionStorage.kt | 20 +- .../vimscript/services/VariableServiceImpl.kt | 35 +- .../META-INF/includes/ApplicationServices.xml | 2 + .../plugins/ideavim/ex/CommandParserTest.kt | 3 +- .../plugins/ideavim/ex/ExpressionTest.kt | 3 +- .../implementation/commands/MapCommandTest.kt | 3 +- .../ideavim/extension/CommonExtensionTests.kt | 6 +- .../plugins/ideavim/mock/MockTestCase.kt | 6 +- .../mock/vimscript/commands/TabmoveTest.kt | 57 +- .../idea/vim/api/EngineEditorHelper.kt | 2 + .../maddyhome/idea/vim/api/VimApplication.kt | 3 + .../com/maddyhome/idea/vim/api/VimCaret.kt | 1 + .../com/maddyhome/idea/vim/api/VimEditor.kt | 2 + .../com/maddyhome/idea/vim/api/VimInjector.kt | 9 +- .../com/maddyhome/idea/vim/api/VimMessages.kt | 2 +- .../idea/vim/api/VimScriptExecutorBase.kt | 4 + .../maddyhome/idea/vim/api/VimSearchGroup.kt | 4 + .../maddyhome/idea/vim/api/VimStatistics.kt | 10 + .../maddyhome/idea/vim/api/VimStringParser.kt | 2 + .../maddyhome/idea/vim/api/VimrcFileState.kt | 7 + .../idea/vim/api/VimscriptExecutor.kt | 18 + .../idea/vim/api/VimscriptFunctionService.kt | 18 + .../maddyhome/idea/vim/api/VimscriptParser.kt | 12 + .../com/maddyhome/idea/vim/ex/ExExceptions.kt | 7 +- .../maddyhome/idea/vim/ex/ranges/ExRanges.kt | 65 +- .../maddyhome/idea/vim/ex/ranges/Ranges.kt | 59 +- .../com/maddyhome/idea/vim/helper/Msg.kt | 76 + .../maddyhome/idea/vim/regexp/CharPointer.kt | 257 + .../idea/vim/regexp/CharacterClasses.kt | 135 + .../com/maddyhome/idea/vim/regexp/Flags.kt | 84 +- .../com/maddyhome/idea/vim/regexp/Magic.kt | 114 + .../com/maddyhome/idea/vim/regexp/RegExp.kt | 4065 ++++++++++++++ .../idea/vim/vimscript/model/Executable.kt | 6 +- .../vim/vimscript/model/ExecutionResult.kt | 0 .../idea/vim/vimscript/model/Script.kt | 6 +- .../idea/vim/vimscript/model/VimLContext.kt | 0 .../vim/vimscript/model/commands/Command.kt | 62 +- .../vimscript/model/commands/LetCommand.kt | 28 +- .../vim/vimscript/model/datatypes/VimBlob.kt | 0 .../vim/vimscript/model/datatypes/VimFloat.kt | 0 .../vimscript/model/datatypes/VimFuncref.kt | 13 +- .../model/expressions/BinExpression.kt | 6 +- .../model/expressions/CurlyBracesName.kt | 6 +- .../model/expressions/DictionaryExpression.kt | 6 +- .../expressions/EnvVariableExpression.kt | 6 +- .../vimscript/model/expressions/Expression.kt | 6 +- .../model/expressions/FalsyExpression.kt | 6 +- .../expressions/FuncrefCallExpression.kt | 8 +- .../expressions/FunctionCallExpression.kt | 16 +- .../model/expressions/LambdaExpression.kt | 9 +- .../LambdaFunctionCallExpression.kt | 6 +- .../model/expressions/ListExpression.kt | 6 +- .../OneElementSublistExpression.kt | 6 +- .../model/expressions/OptionExpression.kt | 13 +- .../vimscript/model/expressions/Register.kt | 13 +- .../vim/vimscript/model/expressions/Scope.kt | 0 .../model/expressions/ScopeExpression.kt | 6 +- .../model/expressions/SimpleExpression.kt | 6 +- .../model/expressions/SublistExpression.kt | 6 +- .../model/expressions/TernaryExpression.kt | 6 +- .../model/expressions/UnaryExpression.kt | 6 +- .../vimscript/model/expressions/Variable.kt | 12 +- .../operators/AssignmentOperator.kt | 0 .../expressions/operators/BinaryOperator.kt | 0 .../expressions/operators/UnaryOperator.kt | 0 .../handlers/binary/AdditionHandler.kt | 0 .../handlers/binary/BinaryOperatorHandler.kt | 0 .../BinaryOperatorWithIgnoreCaseOption.kt | 4 +- .../handlers/binary/ConcatenationHandler.kt | 0 .../handlers/binary/DivisionHandler.kt | 0 .../binary/DoesntMatchCaseSensitiveHandler.kt | 0 .../handlers/binary/DoesntMatchHandler.kt | 0 .../binary/DoesntMatchIgnoreCaseHandler.kt | 0 .../binary/EqualsCaseSensitiveHandler.kt | 0 .../handlers/binary/EqualsHandler.kt | 0 .../binary/EqualsIgnoreCaseHandler.kt | 0 .../binary/GreaterCaseSensitiveHandler.kt | 0 .../handlers/binary/GreaterHandler.kt | 0 .../binary/GreaterIgnoreCaseHandler.kt | 0 .../GreaterOrEqualsCaseSensitiveHandler.kt | 0 .../handlers/binary/GreaterOrEqualsHandler.kt | 0 .../GreaterOrEqualsIgnoreCaseHandler.kt | 0 .../handlers/binary/IsCaseSensitiveHandler.kt | 0 .../operators/handlers/binary/IsHandler.kt | 0 .../handlers/binary/IsIgnoreCaseHandler.kt | 0 .../binary/IsNotCaseSensitiveHandler.kt | 0 .../operators/handlers/binary/IsNotHandler.kt | 0 .../handlers/binary/IsNotIgnoreCaseHandler.kt | 0 .../binary/LessCaseSensitiveHandler.kt | 0 .../operators/handlers/binary/LessHandler.kt | 0 .../handlers/binary/LessIgnoreCaseHandler.kt | 0 .../LessOrEqualsCaseSensitiveHandler.kt | 0 .../handlers/binary/LessOrEqualsHandler.kt | 0 .../binary/LessOrEqualsIgnoreCaseHandler.kt | 0 .../handlers/binary/LogicalAndHandler.kt | 0 .../handlers/binary/LogicalOrHandler.kt | 0 .../binary/MatchesCaseSensitiveHandler.kt | 0 .../handlers/binary/MatchesHandler.kt | 0 .../binary/MatchesIgnoreCaseHandler.kt | 0 .../handlers/binary/ModulusHandler.kt | 0 .../handlers/binary/MultiplicationHandler.kt | 0 .../handlers/binary/SubtractionHandler.kt | 0 .../binary/UnequalsCaseSensitiveHandler.kt | 0 .../handlers/binary/UnequalsHandler.kt | 0 .../binary/UnequalsIgnoreCaseHandler.kt | 0 .../handlers/unary/MinusOperatorHandler.kt | 0 .../handlers/unary/NotOperatorHandler.kt | 0 .../handlers/unary/PlusOperatorHandler.kt | 0 .../handlers/unary/UnaryOperatorHandler.kt | 0 .../model/functions/DefinedFunctionHandler.kt | 46 +- .../model/functions/FunctionHandler.kt | 8 +- .../AnonymousFunctionDeclaration.kt | 6 +- .../model/statements/FinishStatement.kt | 6 +- .../model/statements/FunctionDeclaration.kt | 13 +- .../vimscript/model/statements/IfStatement.kt | 10 +- .../model/statements/ReturnStatement.kt | 6 +- .../model/statements/ThrowStatement.kt | 6 +- .../model/statements/TryStatement.kt | 21 +- .../model/statements/loops/BreakStatement.kt | 6 +- .../statements/loops/ContinueStatement.kt | 6 +- .../model/statements/loops/ForLoop.kt | 24 +- .../model/statements/loops/WhileLoop.kt | 10 +- .../vim/vimscript/services/PatternService.kt | 0 .../vim/vimscript/services/VariableService.kt | 16 +- .../vim/vimscript/services/VimRcService.kt | 17 +- 237 files changed, 5896 insertions(+), 6574 deletions(-) create mode 100644 src/main/java/com/maddyhome/idea/vim/group/IjStatisticsService.kt delete mode 100644 src/main/java/com/maddyhome/idea/vim/helper/Msg.java delete mode 100644 src/main/java/com/maddyhome/idea/vim/regexp/CharPointer.java delete mode 100644 src/main/java/com/maddyhome/idea/vim/regexp/CharacterClasses.java delete mode 100644 src/main/java/com/maddyhome/idea/vim/regexp/Magic.java delete mode 100644 src/main/java/com/maddyhome/idea/vim/regexp/RegExp.java create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimScriptExecutorBase.kt create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStatistics.kt create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimrcFileState.kt create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptExecutor.kt create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptFunctionService.kt create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptParser.kt rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/ex/ExExceptions.kt (80%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/ex/ranges/ExRanges.kt (83%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/ex/ranges/Ranges.kt (73%) create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/helper/Msg.kt create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/CharPointer.kt create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/CharacterClasses.kt rename src/main/java/com/maddyhome/idea/vim/regexp/Flags.java => vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/Flags.kt (52%) create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/Magic.kt create mode 100644 vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/RegExp.kt rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/Executable.kt (84%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/ExecutionResult.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/Script.kt (90%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/VimLContext.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/commands/Command.kt (72%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt (88%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/datatypes/VimBlob.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFloat.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt (88%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/BinExpression.kt (86%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/CurlyBracesName.kt (84%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt (90%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/EnvVariableExpression.kt (83%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/Expression.kt (83%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/FalsyExpression.kt (88%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt (82%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/FunctionCallExpression.kt (77%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaExpression.kt (88%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt (85%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/ListExpression.kt (85%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/OneElementSublistExpression.kt (91%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/OptionExpression.kt (69%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/Register.kt (71%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/Scope.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/ScopeExpression.kt (85%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/SimpleExpression.kt (89%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/SublistExpression.kt (92%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/TernaryExpression.kt (86%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/UnaryExpression.kt (85%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/Variable.kt (73%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/AssignmentOperator.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/BinaryOperator.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/UnaryOperator.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/AdditionHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorWithIgnoreCaseOption.kt (91%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ConcatenationHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DivisionHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalAndHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalOrHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ModulusHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MultiplicationHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/SubtractionHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsCaseSensitiveHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsIgnoreCaseHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/MinusOperatorHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/NotOperatorHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/PlusOperatorHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/UnaryOperatorHandler.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/functions/DefinedFunctionHandler.kt (79%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/functions/FunctionHandler.kt (86%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/AnonymousFunctionDeclaration.kt (94%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/FinishStatement.kt (86%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt (86%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/IfStatement.kt (88%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/ReturnStatement.kt (87%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/ThrowStatement.kt (87%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/TryStatement.kt (84%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/loops/BreakStatement.kt (86%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/loops/ContinueStatement.kt (86%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/loops/ForLoop.kt (84%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/model/statements/loops/WhileLoop.kt (87%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/services/PatternService.kt (100%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/services/VariableService.kt (60%) rename {src/main/java => vim-engine/src/main/kotlin}/com/maddyhome/idea/vim/vimscript/services/VimRcService.kt (88%) diff --git a/src/main/java/com/maddyhome/idea/vim/action/change/insert/InsertRegisterAction.kt b/src/main/java/com/maddyhome/idea/vim/action/change/insert/InsertRegisterAction.kt index a10a627dad0..210c9dadf9d 100644 --- a/src/main/java/com/maddyhome/idea/vim/action/change/insert/InsertRegisterAction.kt +++ b/src/main/java/com/maddyhome/idea/vim/action/change/insert/InsertRegisterAction.kt @@ -29,8 +29,6 @@ import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.handler.VimActionHandler import com.maddyhome.idea.vim.helper.CommandLineHelper -import com.maddyhome.idea.vim.newapi.IjExecutionContext -import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.Script import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser @@ -49,7 +47,7 @@ class InsertRegisterAction : VimActionHandler.SingleExecution() { val expression = readExpression(editor.ij) if (expression != null) { if (expression.isNotEmpty()) { - val expressionValue = VimscriptParser.parseExpression(expression)?.evaluate((editor as IjVimEditor).editor, (context as IjExecutionContext).context, Script(listOf())) + val expressionValue = VimscriptParser.parseExpression(expression)?.evaluate(editor, context, Script(listOf())) ?: throw ExException("E15: Invalid expression: $expression") val textToStore = expressionValue.toInsertableString() VimPlugin.getRegister().storeTextSpecial('=', textToStore) diff --git a/src/main/java/com/maddyhome/idea/vim/action/macro/PlaybackRegisterAction.kt b/src/main/java/com/maddyhome/idea/vim/action/macro/PlaybackRegisterAction.kt index a74e4e048d9..4d9d749be68 100644 --- a/src/main/java/com/maddyhome/idea/vim/action/macro/PlaybackRegisterAction.kt +++ b/src/main/java/com/maddyhome/idea/vim/action/macro/PlaybackRegisterAction.kt @@ -48,7 +48,7 @@ class PlaybackRegisterAction : VimActionHandler.SingleExecution() { try { var i = 0 while (i < cmd.count) { - res.set(Executor.executeLastCommand(editor.ij, context.ij)) + res.set(Executor.executeLastCommand(editor, context)) if (!res.get()) { break } diff --git a/src/main/java/com/maddyhome/idea/vim/extension/VimExtensionRegistrar.kt b/src/main/java/com/maddyhome/idea/vim/extension/VimExtensionRegistrar.kt index 6d83a54fc68..dd998bc5ff6 100644 --- a/src/main/java/com/maddyhome/idea/vim/extension/VimExtensionRegistrar.kt +++ b/src/main/java/com/maddyhome/idea/vim/extension/VimExtensionRegistrar.kt @@ -89,7 +89,7 @@ object VimExtensionRegistrar { } private fun initExtension(extensionBean: ExtensionBeanClass, name: String) { - if (Executor.executingVimScript) { + if (Executor.executingVimscript) { delayedExtensionEnabling += extensionBean } else { extensionBean.instance.init() diff --git a/src/main/java/com/maddyhome/idea/vim/group/IjStatisticsService.kt b/src/main/java/com/maddyhome/idea/vim/group/IjStatisticsService.kt new file mode 100644 index 00000000000..da9a607014d --- /dev/null +++ b/src/main/java/com/maddyhome/idea/vim/group/IjStatisticsService.kt @@ -0,0 +1,68 @@ +/* + * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform + * Copyright (C) 2003-2022 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 . + */ + +/* + * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform + * Copyright (C) 2003-2022 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 . + */ + +package com.maddyhome.idea.vim.group + +import com.maddyhome.idea.vim.api.VimStatistics +import com.maddyhome.idea.vim.statistic.ActionTracker +import com.maddyhome.idea.vim.statistic.VimscriptState + +class IjStatisticsService : VimStatistics { + + override fun logTrackedAction(actionId: String) { + ActionTracker.logTrackedAction(actionId) + } + + override fun logCopiedAction(actionId: String) { + ActionTracker.logCopiedAction(actionId) + } + + override fun setIfLoopUsed(value: Boolean) { + VimscriptState.isLoopUsed = value + } + + override fun setIfFunctionCallUsed(value: Boolean) { + VimscriptState.isFunctionCallUsed = value + } + + override fun setIfFunctionDeclarationUsed(value: Boolean) { + VimscriptState.isFunctionDeclarationUsed = value + } + + override fun setIfIfUsed(value: Boolean) { + VimscriptState.isIfUsed = value + } +} diff --git a/src/main/java/com/maddyhome/idea/vim/group/ProcessGroup.java b/src/main/java/com/maddyhome/idea/vim/group/ProcessGroup.java index 340fc923d68..ce910d8bf6a 100644 --- a/src/main/java/com/maddyhome/idea/vim/group/ProcessGroup.java +++ b/src/main/java/com/maddyhome/idea/vim/group/ProcessGroup.java @@ -135,7 +135,7 @@ public boolean processExEntry(final @NotNull Editor editor, final @NotNull DataC if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread()); - Executor.INSTANCE.execute(text, editor, context, false, true, CommandLineVimLContext.INSTANCE); + Executor.INSTANCE.execute(text, new IjVimEditor(editor), new IjExecutionContext(context), false, true, CommandLineVimLContext.INSTANCE); } catch (ExException e) { VimPlugin.showMessage(e.getMessage()); diff --git a/src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java b/src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java index 9a1a6496afa..3d24bac73c7 100644 --- a/src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java +++ b/src/main/java/com/maddyhome/idea/vim/group/SearchGroup.java @@ -47,6 +47,7 @@ import com.maddyhome.idea.vim.ex.ranges.LineRange; import com.maddyhome.idea.vim.helper.*; import com.maddyhome.idea.vim.history.HistoryConstants; +import com.maddyhome.idea.vim.newapi.IjExecutionContext; import com.maddyhome.idea.vim.newapi.IjVimCaret; import com.maddyhome.idea.vim.newapi.IjVimEditor; import com.maddyhome.idea.vim.options.OptionChangeListener; @@ -754,7 +755,7 @@ else if (do_ic == 'I') { Expression expression = null; for (int lnum = line1; lnum <= line2 && !got_quit; ) { CharacterPosition newpos = null; - int nmatch = sp.vim_regexec_multi(regmatch, ((IjVimEditor) editor).getEditor(), lcount, lnum, searchcol); + int nmatch = sp.vim_regexec_multi(regmatch, editor, lcount, lnum, searchcol); if (nmatch > 0) { if (firstMatch) { VimPlugin.getMark().saveJumpLocation(editor); @@ -813,7 +814,7 @@ else if (do_ic == 'I') { if (expression != null) { try { match = expression - .evaluate(((IjVimEditor) editor).getEditor(), EditorDataContext.init(((IjVimEditor) editor).getEditor(), null), parent) + .evaluate(editor, new IjExecutionContext(EditorDataContext.init(((IjVimEditor) editor).getEditor(), null)), parent) .toInsertableString(); } catch (Exception e) { exceptions.add((ExException) e); @@ -879,6 +880,25 @@ else if (do_ic == 'I') { return true; } + @Override + public void setLastSearchPattern(@Nullable String lastSearchPattern) { + this.lastSearch = lastSearchPattern; + } + + @Override + public void setLastSubstitutePattern(@Nullable String lastSubstitutePattern) { + this.lastSubstitute = lastSubstitutePattern; + } + + @Override + public int processSearchRange(@NotNull VimEditor editor, + @NotNull String pattern, + int patternOffset, + int startOffset, + @NotNull Direction direction) { + return processSearchRange(((IjVimEditor) editor).getEditor(), pattern, patternOffset, startOffset, direction); + } + public Pair> search_regcomp(CharPointer pat, int which_pat, int patSave) { diff --git a/src/main/java/com/maddyhome/idea/vim/helper/IjEditorHelper.kt b/src/main/java/com/maddyhome/idea/vim/helper/IjEditorHelper.kt index eab2e30a0e3..08ecf372927 100644 --- a/src/main/java/com/maddyhome/idea/vim/helper/IjEditorHelper.kt +++ b/src/main/java/com/maddyhome/idea/vim/helper/IjEditorHelper.kt @@ -12,6 +12,7 @@ import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.newapi.IjVimCaret import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.newapi.ij +import java.nio.CharBuffer @Service class IjEditorHelper : EngineEditorHelper { @@ -102,4 +103,8 @@ class IjEditorHelper : EngineEditorHelper { .getReadonlyFragmentModificationHandler(editor.ij.document) .handle(exception as ReadOnlyFragmentModificationException?) } + + override fun getLineBuffer(editor: VimEditor, line: Int): CharBuffer { + return EditorHelper.getLineBuffer(editor.ij, line) + } } diff --git a/src/main/java/com/maddyhome/idea/vim/helper/IjVimStringParser.kt b/src/main/java/com/maddyhome/idea/vim/helper/IjVimStringParser.kt index 12908136b36..ccc1f46c1ad 100644 --- a/src/main/java/com/maddyhome/idea/vim/helper/IjVimStringParser.kt +++ b/src/main/java/com/maddyhome/idea/vim/helper/IjVimStringParser.kt @@ -16,4 +16,12 @@ class IjVimStringParser : VimStringParser { override fun stringToKeys(string: String): List { return StringHelper.stringToKeys(string) } + + override fun toKeyNotation(keyStroke: KeyStroke): String { + return StringHelper.toKeyNotation(keyStroke) + } + + override fun toKeyNotation(keyStrokes: List): String { + return StringHelper.toKeyNotation(keyStrokes) + } } diff --git a/src/main/java/com/maddyhome/idea/vim/helper/Msg.java b/src/main/java/com/maddyhome/idea/vim/helper/Msg.java deleted file mode 100644 index 45d5ea32c50..00000000000 --- a/src/main/java/com/maddyhome/idea/vim/helper/Msg.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform - * Copyright (C) 2003-2022 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 . - */ - -package com.maddyhome.idea.vim.helper; - -public interface Msg { - String NOT_EX_CMD = "notexcmd"; - String INT_BAD_CMD = "intbadcmd"; - String e_backslash = "e_backslash"; - String e_badrange = "e_badrange"; - String e_norange = "e_norange"; - String e_rangereq = "e_rangereq"; - String e_argreq = "e_argreq"; - String e_argforb = "e_argforb"; - String e_noprev = "e_noprev"; - String e_nopresub = "e_nopresub"; - String E191 = "E191"; - String e_backrange = "e_backrange"; - String E146 = "E146"; - String e_zerocount = "e_zerocount"; - String e_trailing = "e_trailing"; - String e_invcmd = "e_invcmd"; - String e_null = "e_null"; - String E50 = "E50"; - String E51 = "E51"; - String E52 = "E52"; - String E53 = "E53"; - String E54 = "E54"; - String E55 = "E55"; - String E56 = "E56"; - String E57 = "E57"; - String E58 = "E58"; - String E59 = "E59"; - String E60 = "E60"; - String E61 = "E61"; - String E62 = "E62"; - String E63 = "E63"; - String E64 = "E64"; - String E65 = "E65"; - String E66 = "E66"; - String E67 = "E67"; - String E68 = "E68"; - String E69 = "E69"; - String E70 = "E70"; - String E71 = "E71"; - String e_invrange = "e_invrange"; - String e_toomsbra = "e_toomsbra"; - String e_internal = "e_internal"; - String synerror = "synerror"; - String E363 = "E363"; - String e_re_corr = "e_re_corr"; - String e_re_damg = "e_re_damg"; - String E369 = "E369"; - String E384 = "E384"; - String E385 = "E385"; - String e_patnotf2 = "e_patnotf2"; - String unkopt = "unkopt"; - String e_invarg = "e_invarg"; - String E475 = "E475"; -} diff --git a/src/main/java/com/maddyhome/idea/vim/helper/SearchHelper.java b/src/main/java/com/maddyhome/idea/vim/helper/SearchHelper.java index 44eb1173355..751442ba94c 100644 --- a/src/main/java/com/maddyhome/idea/vim/helper/SearchHelper.java +++ b/src/main/java/com/maddyhome/idea/vim/helper/SearchHelper.java @@ -168,7 +168,7 @@ public static TextRange findPattern(@NotNull Editor editor, /* * Look for a match somewhere in the line. */ - nmatched = sp.vim_regexec_multi(regmatch, editor, lcount, lnum, 0); + nmatched = sp.vim_regexec_multi(regmatch, new IjVimEditor(editor), lcount, lnum, 0); if (nmatched > 0) { /* match may actually be in another line when using \zs */ matchpos = new RegExp.lpos_T(regmatch.startpos[0]); @@ -204,7 +204,7 @@ public static TextRange findPattern(@NotNull Editor editor, ++matchcol; } if (ptr.charAt(matchcol) == '\u0000' || - (nmatched = sp.vim_regexec_multi(regmatch, editor, lcount, lnum, matchcol)) == 0) { + (nmatched = sp.vim_regexec_multi(regmatch, new IjVimEditor(editor), lcount, lnum, matchcol)) == 0) { match_ok = false; break; } @@ -259,7 +259,7 @@ public static TextRange findPattern(@NotNull Editor editor, ++matchcol; } if (ptr.charAt(matchcol) == '\u0000' || - (nmatched = sp.vim_regexec_multi(regmatch, editor, lcount, lnum + matchpos.lnum, matchcol)) == 0) { + (nmatched = sp.vim_regexec_multi(regmatch, new IjVimEditor(editor), lcount, lnum + matchpos.lnum, matchcol)) == 0) { break; } @@ -383,7 +383,7 @@ else if (lnum <= 0) { int col = 0; for (int line = startLine; line <= actualEndLine; ) { - int matchedLines = regExp.vim_regexec_multi(regMatch, editor, lineCount, line, col); + int matchedLines = regExp.vim_regexec_multi(regMatch, new IjVimEditor(editor), lineCount, line, col); if (matchedLines > 0) { final CharacterPosition startPos = new CharacterPosition(line + regMatch.startpos[0].lnum, regMatch.startpos[0].col); diff --git a/src/main/java/com/maddyhome/idea/vim/key/MappingInfo.kt b/src/main/java/com/maddyhome/idea/vim/key/MappingInfo.kt index 84c16935c5c..ef376144ba3 100644 --- a/src/main/java/com/maddyhome/idea/vim/key/MappingInfo.kt +++ b/src/main/java/com/maddyhome/idea/vim/key/MappingInfo.kt @@ -130,7 +130,7 @@ class ToExpressionMappingInfo( override fun execute(editor: VimEditor, context: ExecutionContext) { LOG.debug("Executing 'ToExpression' mapping info...") val editorDataContext = injector.executionContextManager.onEditor(editor, context) - val toKeys = parseKeys(toExpression.evaluate(editor.ij, context.ij, CommandLineVimLContext).toString()) + val toKeys = parseKeys(toExpression.evaluate(editor, context, CommandLineVimLContext).toString()) val fromIsPrefix = KeyHandler.isPrefix(fromKeys, toKeys) var first = true for (keyStroke in toKeys) { diff --git a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimApplication.kt b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimApplication.kt index 52a9a422901..2d32e340add 100644 --- a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimApplication.kt +++ b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimApplication.kt @@ -21,6 +21,7 @@ package com.maddyhome.idea.vim.newapi import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.ModalityState import com.intellij.openapi.components.Service +import com.intellij.openapi.util.Computable import com.maddyhome.idea.vim.api.VimApplication import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.diagnostic.vimLogger @@ -70,6 +71,14 @@ class IjVimApplication : VimApplication { RunnableHelper.runReadCommand((editor as IjVimEditor).editor.project, command, name, groupId) } + override fun runWriteAction(action: () -> T): T { + return ApplicationManager.getApplication().runWriteAction(Computable(action)) + } + + override fun runReadAction(action: () -> T): T { + return ApplicationManager.getApplication().runReadAction(Computable(action)) + } + private fun createKeyEvent(stroke: KeyStroke, component: Component): KeyEvent { return KeyEvent( component, diff --git a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimCaret.kt b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimCaret.kt index b7863d97961..b4a74843c29 100644 --- a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimCaret.kt +++ b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimCaret.kt @@ -19,6 +19,7 @@ package com.maddyhome.idea.vim.newapi import com.intellij.openapi.editor.Caret +import com.intellij.openapi.editor.LogicalPosition import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.api.VimCaret import com.maddyhome.idea.vim.api.VimEditor @@ -68,6 +69,10 @@ class IjVimCaret(val caret: Caret) : VimCaret { MotionGroup.moveCaret(caret.editor, caret, offset) } + override fun moveToLogicalPosition(logicalPosition: VimLogicalPosition) { + this.caret.moveToLogicalPosition(LogicalPosition(logicalPosition.line, logicalPosition.column, logicalPosition.leansForward)) + } + override fun offsetForLineStartSkipLeading(line: Int): Int { return VimPlugin.getMotion().moveCaretToLineStartSkipLeading(editor, line) } diff --git a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt index a5b94342493..f815c909007 100644 --- a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt +++ b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimEditor.kt @@ -183,6 +183,10 @@ class IjVimEditor(editor: Editor) : MutableLinearEditor() { return modificationAllowed && writeRequested } + override fun isDocumentWritable(): Boolean { + return editor.document.isWritable + } + override fun isOneLineMode(): Boolean { return editor.isOneLineMode } @@ -263,6 +267,10 @@ class IjVimEditor(editor: Editor) : MutableLinearEditor() { editor.selectionModel.vimSetSystemBlockSelectionSilently(startPosition, endPosition) } + override fun getLineStartOffset(line: Int): Int { + return EditorHelper.getLineStartOffset(editor, line) + } + override fun getLineEndOffset(line: Int, allowEnd: Boolean): Int { return EditorHelper.getLineEndOffset(editor, line, allowEnd) } diff --git a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimInjector.kt b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimInjector.kt index a46c4aa4989..58e605aa8e1 100644 --- a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimInjector.kt +++ b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimInjector.kt @@ -23,9 +23,14 @@ import com.maddyhome.idea.vim.api.VimMotionGroup import com.maddyhome.idea.vim.api.VimProcessGroup import com.maddyhome.idea.vim.api.VimSearchGroup import com.maddyhome.idea.vim.api.VimSearchHelper +import com.maddyhome.idea.vim.api.VimStatistics import com.maddyhome.idea.vim.api.VimStringParser import com.maddyhome.idea.vim.api.VimTemplateManager import com.maddyhome.idea.vim.api.VimVisualMotionGroup +import com.maddyhome.idea.vim.api.VimrcFileState +import com.maddyhome.idea.vim.api.VimscriptExecutor +import com.maddyhome.idea.vim.api.VimscriptFunctionService +import com.maddyhome.idea.vim.api.VimscriptParser import com.maddyhome.idea.vim.command.CommandState import com.maddyhome.idea.vim.common.VimMachine import com.maddyhome.idea.vim.diagnostic.VimLogger @@ -42,6 +47,10 @@ import com.maddyhome.idea.vim.mark.VimMarkGroup import com.maddyhome.idea.vim.options.OptionService import com.maddyhome.idea.vim.put.VimPut import com.maddyhome.idea.vim.register.VimRegisterGroup +import com.maddyhome.idea.vim.ui.VimRcFileState +import com.maddyhome.idea.vim.vimscript.Executor +import com.maddyhome.idea.vim.vimscript.services.FunctionStorage +import com.maddyhome.idea.vim.vimscript.services.VariableService class IjVimInjector : VimInjector { override fun getLogger(clazz: Class): VimLogger = IjVimLogger(Logger.getInstance(clazz::class.java)) @@ -92,6 +101,19 @@ class IjVimInjector : VimInjector { get() = service() override val visualMotionGroup: VimVisualMotionGroup get() = service() + override val statisticsService: VimStatistics + get() = service() + + override val functionService: VimscriptFunctionService + get() = FunctionStorage + override val variableService: VariableService + get() = service() + override val vimrcFileState: VimrcFileState + get() = VimRcFileState + override val vimscriptExecutor: VimscriptExecutor + get() = Executor + override val vimscriptParser: VimscriptParser + get() = com.maddyhome.idea.vim.vimscript.parser.VimscriptParser override val optionService: OptionService get() = service() diff --git a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimMessages.kt b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimMessages.kt index 3a299e8c782..03ca67f9e75 100644 --- a/src/main/java/com/maddyhome/idea/vim/newapi/IjVimMessages.kt +++ b/src/main/java/com/maddyhome/idea/vim/newapi/IjVimMessages.kt @@ -83,7 +83,7 @@ class IjVimMessages : VimMessages { override fun isError(): Boolean = error - override fun message(key: String): String = MessageHelper.message(key) + override fun message(key: String, vararg params: Any): String = MessageHelper.message(key, *params) override fun updateStatusBar() { ShowCmd.update() } diff --git a/src/main/java/com/maddyhome/idea/vim/regexp/CharPointer.java b/src/main/java/com/maddyhome/idea/vim/regexp/CharPointer.java deleted file mode 100644 index d9a77c17d99..00000000000 --- a/src/main/java/com/maddyhome/idea/vim/regexp/CharPointer.java +++ /dev/null @@ -1,300 +0,0 @@ -/* - * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform - * Copyright (C) 2003-2022 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 . - */ - -package com.maddyhome.idea.vim.regexp; - -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.nio.CharBuffer; -import java.util.Objects; - - -public class CharPointer { - private @NotNull CharSequence seq; - private int pointer; - private boolean readonly; - - public CharPointer(@NotNull String text) { - seq = text; - readonly = true; - } - - public CharPointer(@NotNull CharBuffer text) { - seq = text; - readonly = true; - } - - public CharPointer(@NotNull StringBuffer text) { - seq = text; - readonly = false; - } - - private CharPointer(@NotNull CharPointer ptr, int offset) { - seq = ptr.seq; - readonly = ptr.readonly; - pointer = ptr.pointer + offset; - } - - public int pointer() { - return pointer; - } - - public @NotNull CharPointer set(char ch) { - return set(ch, 0); - } - - public @NotNull CharPointer set(char ch, int offset) { - if (readonly) { - throw new IllegalStateException("readonly string"); - } - - StringBuffer data = (StringBuffer)seq; - while (pointer + offset >= data.length()) { - data.append('\u0000'); - } - data.setCharAt(pointer + offset, ch); - - return this; - } - - public char charAtInc() { - char res = charAt(0); - inc(); - - return res; - } - - public char charAt() { - return charAt(0); - } - - public char charAt(int offset) { - if (end(offset)) { - return '\u0000'; - } - - return seq.charAt(pointer + offset); - } - - public @NotNull CharPointer inc() { - return inc(1); - } - - public @NotNull CharPointer inc(int cnt) { - pointer += cnt; - - return this; - } - - public @NotNull CharPointer dec() { - return dec(1); - } - - public @NotNull CharPointer dec(int cnt) { - pointer -= cnt; - - return this; - } - - public @NotNull CharPointer assign(@NotNull CharPointer ptr) { - seq = ptr.seq; - pointer = ptr.pointer; - readonly = ptr.readonly; - - return this; - } - - public @NotNull CharPointer ref(int offset) { - return new CharPointer(this, offset); - } - - public @NotNull String substring(int len) { - if (end()) return ""; - - int start = pointer; - int end = normalize(pointer + len); - return CharBuffer.wrap(seq, start, end).toString(); - } - - public int strlen() { - if (end()) return 0; - - for (int i = pointer; i < seq.length(); i++) { - if (seq.charAt(i) == '\u0000') { - return i - pointer; - } - } - - return seq.length() - pointer; - } - - public int strncmp(@NotNull String str, int len) { - if (end()) return -1; - - String s = CharBuffer.wrap(seq, pointer, normalize(pointer + len)).toString(); - - if (len > str.length()) { - len = str.length(); - } - - return s.compareTo(str.substring(0, len)); - } - - public int strncmp(@NotNull CharPointer str, int len, boolean ignoreCase) { - if (end()) return -1; - - CharSequence cs1 = CharBuffer.wrap(seq, pointer, normalize(pointer + len)); - CharSequence cs2 = CharBuffer.wrap(str.seq, str.pointer, str.normalize(str.pointer + len)); - - int l = cs1.length(); - if (l != cs2.length()) { - return 1; - } - - for (int i = 0; i < l; i++) { - char c1 = cs1.charAt(i); - char c2 = cs2.charAt(i); - - final boolean notEqual = ignoreCase ? Character.toLowerCase(c1) != Character.toLowerCase(c2) && - Character.toUpperCase(c1) != Character.toUpperCase(c2) : c1 != c2; - if (notEqual) return 1; - } - - return 0; - } - - public @Nullable CharPointer strchr(char c) { - if (end()) { - return null; - } - - final int len = seq.length(); - for (int i = pointer; i < len; i++) { - final char ch = seq.charAt(i); - if (ch == '\u0000') { - return null; - } - if (ch == c) { - return ref(i - pointer); - } - } - - return null; - } - - public @Nullable CharPointer istrchr(char c) { - if (end()) { - return null; - } - - final int len = seq.length(); - final char cc = Character.toUpperCase(c); - c = Character.toLowerCase(c); - - for (int i = pointer; i < len; i++) { - final char ch = seq.charAt(i); - if (ch == '\u0000') { - return null; - } - if (ch == c || ch == cc) { - return ref(i - pointer); - } - } - - return null; - } - - public boolean isNul() { - return charAt() == '\u0000'; - } - - public boolean end() { - return end(0); - } - - public boolean end(int offset) { - return pointer + offset >= seq.length(); - } - - public int OP() { - return charAt(); - } - - public @NotNull CharPointer OPERAND() { - return ref(3); - } - - public int NEXT() { - return ((((int)seq.charAt(pointer + 1) & 0xff) << 8) + ((int)seq.charAt(pointer + 2) & 0xff)); - } - - public int OPERAND_MIN() { - return (((int)seq.charAt(pointer + 3) << 24) + - ((int)seq.charAt(pointer + 4) << 16) + - ((int)seq.charAt(pointer + 5) << 8) + - ((int)seq.charAt(pointer + 6))); - } - - public int OPERAND_MAX() { - return (((int)seq.charAt(pointer + 7) << 24) + - ((int)seq.charAt(pointer + 8) << 16) + - ((int)seq.charAt(pointer + 9) << 8) + - ((int)seq.charAt(pointer + 10))); - } - - public char OPERAND_CMP() { - return seq.charAt(pointer + 7); - } - - public boolean equals(Object obj) { - if (obj instanceof CharPointer) { - CharPointer ptr = (CharPointer)obj; - return ptr.seq == seq && ptr.pointer == pointer; - } - - return false; - } - - @Override - public int hashCode() { - return Objects.hash(seq, pointer); - } - - public void skipWhitespaces() { - while (CharacterClasses.isWhite(charAt())) inc(); - } - - public int getDigits() { - int res = 0; - while (Character.isDigit(charAt())) { - res = res * 10 + (charAt() - '0'); - inc(); - } - - return res; - } - - private int normalize(int pos) { - return Math.min(seq.length(), pos); - } - - public @NotNull String toString() { - return substring(strlen()); - } -} diff --git a/src/main/java/com/maddyhome/idea/vim/regexp/CharacterClasses.java b/src/main/java/com/maddyhome/idea/vim/regexp/CharacterClasses.java deleted file mode 100644 index 11c5f1ef2d3..00000000000 --- a/src/main/java/com/maddyhome/idea/vim/regexp/CharacterClasses.java +++ /dev/null @@ -1,159 +0,0 @@ -/* - * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform - * Copyright (C) 2003-2022 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 . - */ - -package com.maddyhome.idea.vim.regexp; - -import org.jetbrains.annotations.NonNls; - -public final class CharacterClasses { - private CharacterClasses() { - } - - public static final String @NonNls [] CLASS_NAMES = new String[]{ - "alnum:]", - "alpha:]", - "blank:]", - "cntrl:]", - "digit:]", - "graph:]", - "lower:]", - "print:]", - "punct:]", - "space:]", - "upper:]", - "xdigit:]", - "tab:]", - "return:]", - "backspace:]", - "escape:]" - }; - - public static final int RI_DIGIT = 0x01; - public static final int RI_HEX = 0x02; - public static final int RI_OCTAL = 0x04; - public static final int RI_WORD = 0x08; - public static final int RI_HEAD = 0x10; - public static final int RI_ALPHA = 0x20; - public static final int RI_LOWER = 0x40; - public static final int RI_UPPER = 0x80; - public static final int RI_WHITE = 0x100; - - public static final int CLASS_ALNUM = 0; - public static final int CLASS_ALPHA = 1; - public static final int CLASS_BLANK = 2; - public static final int CLASS_CNTRL = 3; - public static final int CLASS_DIGIT = 4; - public static final int CLASS_GRAPH = 5; - public static final int CLASS_LOWER = 6; - public static final int CLASS_PRINT = 7; - public static final int CLASS_PUNCT = 8; - public static final int CLASS_SPACE = 9; - public static final int CLASS_UPPER = 10; - public static final int CLASS_XDIGIT = 11; - public static final int CLASS_TAB = 12; - public static final int CLASS_RETURN = 13; - public static final int CLASS_BACKSPACE = 14; - public static final int CLASS_ESCAPE = 15; - public static final int CLASS_NONE = 99; - - public static boolean isMask(char ch, int mask, int test) { - boolean res = false; - switch (mask) { - case RI_DIGIT: - res = Character.isDigit(ch); - break; - case RI_HEX: - res = isHex(ch); - break; - case RI_OCTAL: - res = isOctal(ch); - break; - case RI_WORD: - res = isWord(ch); - break; - case RI_HEAD: - res = isHead(ch); - break; - case RI_ALPHA: - res = isAlpha(ch); - break; - case RI_LOWER: - res = isLower(ch); - break; - case RI_UPPER: - res = isUpper(ch); - break; - case RI_WHITE: - res = isWhite(ch); - break; - } - - return (res == (test > 0)); - } - - public static boolean isHex(char ch) { - return Character.digit(ch, 16) != -1; - } - - public static boolean isOctal(char ch) { - return Character.digit(ch, 8) != -1; - } - - public static boolean isWord(char ch) { - return Character.isLetterOrDigit(ch) || ch == '_'; - } - - public static boolean isHead(char ch) { - return Character.isLetter(ch) || ch == '_'; - } - - public static boolean isAlpha(char ch) { - return Character.isLetter(ch); - } - - public static boolean isLower(char ch) { - return Character.isLowerCase(ch); - } - - public static boolean isUpper(char ch) { - return Character.isUpperCase(ch); - } - - public static boolean isWhite(char ch) { - return Character.isWhitespace(ch); - } - - public static boolean isGraph(char ch) { - return (ch >= '!' && ch <= '~'); - } - - public static boolean isPrint(char ch) { - return ((ch >= ' ' && ch <= '~') || ch > 0xff); - } - - public static boolean isPunct(char ch) { - return ((ch >= '!' && ch <= '/') || - (ch >= ':' && ch <= '@') || - (ch >= '[' && ch <= '`') || - (ch >= '{' && ch <= '~')); - } - - public static boolean isFile(char ch) { - return (isWord(ch) || "/.-+,#$%~=".indexOf(ch) != -1); - } -} diff --git a/src/main/java/com/maddyhome/idea/vim/regexp/Magic.java b/src/main/java/com/maddyhome/idea/vim/regexp/Magic.java deleted file mode 100644 index 223936551bb..00000000000 --- a/src/main/java/com/maddyhome/idea/vim/regexp/Magic.java +++ /dev/null @@ -1,117 +0,0 @@ -/* - * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform - * Copyright (C) 2003-2022 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 . - */ - -package com.maddyhome.idea.vim.regexp; - -public class Magic { - public static final int AMP = '&' - 256; - public static final int AT = '@' - 256; - public static final int DOLLAR = '$' - 256; - public static final int DOT = '.' - 256; - public static final int EQUAL = '=' - 256; - public static final int GREATER = '>' - 256; - public static final int HAT = '^' - 256; - public static final int LBRACE = '[' - 256; - public static final int LCURLY = '{' - 256; - public static final int LESS = '<' - 256; - public static final int LPAREN = '(' - 256; - public static final int PERCENT = '%' - 256; - public static final int PIPE = '|' - 256; - public static final int PLUS = '+' - 256; - public static final int QUESTION = '?' - 256; - public static final int RPAREN = ')' - 256; - public static final int STAR = '*' - 256; - public static final int TILDE = '~' - 256; - public static final int UNDER = '_' - 256; - public static final int N0 = '0' - 256; - public static final int N1 = '1' - 256; - public static final int N2 = '2' - 256; - public static final int N3 = '3' - 256; - public static final int N4 = '4' - 256; - public static final int N5 = '5' - 256; - public static final int N6 = '6' - 256; - public static final int N7 = '7' - 256; - public static final int N8 = '8' - 256; - public static final int N9 = '9' - 256; - public static final int a = 'a' - 256; - public static final int A = 'A' - 256; - public static final int c = 'c' - 256; - public static final int C = 'C' - 256; - public static final int d = 'd' - 256; - public static final int D = 'D' - 256; - public static final int f = 'f' - 256; - public static final int F = 'F' - 256; - public static final int h = 'h' - 256; - public static final int H = 'H' - 256; - public static final int i = 'i' - 256; - public static final int I = 'I' - 256; - public static final int k = 'k' - 256; - public static final int K = 'K' - 256; - public static final int l = 'l' - 256; - public static final int L = 'L' - 256; - public static final int m = 'm' - 256; - public static final int M = 'M' - 256; - public static final int n = 'n' - 256; - public static final int N = 'N' - 256; - public static final int o = 'o' - 256; - public static final int O = 'O' - 256; - public static final int p = 'p' - 256; - public static final int P = 'P' - 256; - public static final int s = 's' - 256; - public static final int S = 'S' - 256; - public static final int u = 'u' - 256; - public static final int U = 'U' - 256; - public static final int v = 'v' - 256; - public static final int V = 'V' - 256; - public static final int w = 'w' - 256; - public static final int W = 'W' - 256; - public static final int x = 'x' - 256; - public static final int X = 'X' - 256; - public static final int z = 'z' - 256; - - /* - * Magic characters have a special meaning, they don't match literally. - * Magic characters are negative. This separates them from literal characters - * (possibly multi-byte). Only ASCII characters can be Magic. - */ - public static int magic(int x) { - return (x - 256); - } - - public static int un_Magic(int x) { - return (x + 256); - } - - public static boolean is_Magic(int x) { - return (x < 0); - } - - public static int no_Magic(int x) { - if (is_Magic(x)) { - return un_Magic(x); - } - return x; - } - - public static int toggle_Magic(int x) { - if (is_Magic(x)) { - return un_Magic(x); - } - return magic(x); - } -} diff --git a/src/main/java/com/maddyhome/idea/vim/regexp/RegExp.java b/src/main/java/com/maddyhome/idea/vim/regexp/RegExp.java deleted file mode 100644 index 0b79f642a3d..00000000000 --- a/src/main/java/com/maddyhome/idea/vim/regexp/RegExp.java +++ /dev/null @@ -1,4917 +0,0 @@ -/* - * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform - * Copyright (C) 2003-2022 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 . - */ - -package com.maddyhome.idea.vim.regexp; - -import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.editor.Editor; -import com.intellij.openapi.editor.LogicalPosition; -import com.maddyhome.idea.vim.VimPlugin; -import com.maddyhome.idea.vim.helper.EditorHelper; -import com.maddyhome.idea.vim.helper.MessageHelper; -import com.maddyhome.idea.vim.helper.Msg; -import org.jetbrains.annotations.NonNls; -import org.jetbrains.annotations.NotNull; -import org.jetbrains.annotations.Nullable; - -import java.util.Arrays; - -public class RegExp { - public static @Nullable reg_extmatch_T re_extmatch_out = null; - public static @Nullable reg_extmatch_T re_extmatch_in = null; - - /* - * The opcodes are: - */ - - /* definition number opnd? meaning */ - private static final int END = 0; /* End of program or NOMATCH operand. */ - private static final int BOL = 1; /* Match "" at beginning of line. */ - private static final int EOL = 2; /* Match "" at end of line. */ - private static final int BRANCH = 3; /* node Match this alternative, or the next... */ - private static final int BACK = 4; /* Match "", "next" ptr points backward. */ - private static final int EXACTLY = 5; /* str Match this string. */ - private static final int NOTHING = 6; /* Match empty string. */ - private static final int STAR = 7; /* node Match this (simple) thing 0 or more times. */ - private static final int PLUS = 8; /* node Match this (simple) thing 1 or more times. */ - private static final int MATCH = 9; /* node match the operand zero-width */ - private static final int NOMATCH = 10; /* node check for no match with operand */ - private static final int BEHIND = 11; /* node look behind for a match with operand */ - private static final int NOBEHIND = 12; /* node look behind for no match with operand */ - private static final int SUBPAT = 13; /* node match the operand here */ - private static final int BRACE_SIMPLE = 14; /* node Match this (simple) thing between m and - * n times (\{m,n\}). */ - private static final int BOW = 15; /* Match "" after [^a-zA-Z0-9_] */ - private static final int EOW = 16; /* Match "" at [^a-zA-Z0-9_] */ - private static final int BRACE_LIMITS = 17; /* nr nr define the min & max for BRACE_SIMPLE - * and BRACE_COMPLEX. */ - private static final int NEWL = 18; /* Match line-break */ - private static final int BHPOS = 19; /* End position for BEHIND or NOBEHIND */ - - - /* character classes: 20-48 normal, 50-78 include a line-break */ - private static final int ADD_NL = 30; - private static final int ANY = 20; /* Match any one character. */ - private static final int FIRST_NL = ANY + ADD_NL; - private static final int ANYOF = 21; /* str Match any character in this string. */ - private static final int ANYBUT = 22; /* str Match any character not in this - * string. */ - private static final int IDENT = 23; /* Match identifier char */ - private static final int SIDENT = 24; /* Match identifier char but no digit */ - private static final int KWORD = 25; /* Match keyword char */ - private static final int SKWORD = 26; /* Match word char but no digit */ - private static final int FNAME = 27; /* Match file name char */ - private static final int SFNAME = 28; /* Match file name char but no digit */ - private static final int PRINT = 29; /* Match printable char */ - private static final int SPRINT = 30; /* Match printable char but no digit */ - private static final int WHITE = 31; /* Match whitespace char */ - private static final int NWHITE = 32; /* Match non-whitespace char */ - private static final int DIGIT = 33; /* Match digit char */ - private static final int NDIGIT = 34; /* Match non-digit char */ - private static final int HEX = 35; /* Match hex char */ - private static final int NHEX = 36; /* Match non-hex char */ - private static final int OCTAL = 37; /* Match octal char */ - private static final int NOCTAL = 38; /* Match non-octal char */ - private static final int WORD = 39; /* Match word char */ - private static final int NWORD = 40; /* Match non-word char */ - private static final int HEAD = 41; /* Match head char */ - private static final int NHEAD = 42; /* Match non-head char */ - private static final int ALPHA = 43; /* Match alpha char */ - private static final int NALPHA = 44; /* Match non-alpha char */ - private static final int LOWER = 45; /* Match lowercase char */ - private static final int NLOWER = 46; /* Match non-lowercase char */ - private static final int UPPER = 47; /* Match uppercase char */ - private static final int NUPPER = 48; /* Match non-uppercase char */ - private static final int LAST_NL = NUPPER + ADD_NL; - private static final int MOPEN = 80; /* -89 Mark this point in input as start of - * \( subexpr. MOPEN + 0 marks start of - * match. */ - private static final int MCLOSE = 90; /* -99 Analogous to MOPEN. MCLOSE + 0 marks - * end of match. */ - private static final int BACKREF = 100; /* -109 node Match same string again \1-\9 */ - - private static final int ZOPEN = 110; /* -119 Mark this point in input as start of - * \z( subexpr. */ - private static final int ZCLOSE = 120; /* -129 Analogous to ZOPEN. */ - private static final int ZREF = 130; /* -139 node Match external submatch \z1-\z9 */ - - private static final int BRACE_COMPLEX = 140; /* -149 node Match nodes between m & n times */ - - private static final int NOPEN = 150; /* Mark this point in input as start of - \%( subexpr. */ - private static final int NCLOSE = 151; /* Analogous to NOPEN. */ - - private static final int RE_BOF = 201; /* Match "" at beginning of file. */ - private static final int RE_EOF = 202; /* Match "" at end of file. */ - private static final int CURSOR = 203; /* Match location of cursor. */ - - private static final int RE_LNUM = 204; /* nr cmp Match line number */ - private static final int RE_COL = 205; /* nr cmp Match column number */ - private static final int RE_VCOL = 206; /* nr cmp Match virtual column number */ - - @SuppressWarnings("OctalInteger") - private static final int REGMAGIC = 0234; - - private static final int REX_SET = 1; - private static final int REX_USE = 2; - - private static final int MAX_LIMIT = Integer.MAX_VALUE; - - private static final int NOT_MULTI = 0; - private static final int MULTI_ONE = 1; - private static final int MULTI_MULT = 2; - - /* - * Flags to be passed up and down. - */ - private static final int HASWIDTH = 0x1; /* Known never to match null string. */ - private static final int SIMPLE = 0x2; /* Simple enough to be STAR/PLUS operand. */ - private static final int SPSTART = 0x4; /* Starts with * or +. */ - private static final int HASNL = 0x8; /* Contains some \n. */ - private static final int WORST = 0; /* Worst case. */ - - /* - * REGEXP_INRANGE contains all characters which are always special in a [] - * range after '\'. - * REGEXP_ABBR contains all characters which act as abbreviations after '\'. - * These are: - * \n - New line (NL). - * \r - Carriage Return (CR). - * \t - Tab (TAB). - * \e - Escape (ESC). - * \b - Backspace (Ctrl_H). - */ - private static final String REGEXP_INRANGE = "]^-n\\"; - private static final String REGEXP_ABBR = "nrteb"; - - /* flags for regflags */ - private static final int RF_ICASE = 1; /* ignore case */ - private static final int RF_NOICASE = 2; /* don't ignore case */ - private static final int RF_HASNL = 4; /* can match a NL */ - - /* - * Global work variables for vim_regcomp(). - */ - private static final int NSUBEXP = 10; - - private static final int MAGIC_NONE = 1; /* "\V" very unmagic */ - private static final int MAGIC_OFF = 2; /* "\M" or 'magic' off */ - private static final int MAGIC_ON = 3; /* "\m" or 'magic' */ - private static final int MAGIC_ALL = 4; /* "\v" very magic */ - - /* - * META contains all characters that may be magic, except '^' and '$'. - */ - - /* META[] is used often enough to justify turning it into a table. */ - private static final int[] META_flags = { - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - /* % & ( ) * + . */ - 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, - /* 1 2 3 4 5 6 7 8 9 < = > ? */ - 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, - /* @ A C D F H I K L M O */ - 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, - /* P S U V W X [ _ */ - 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, - /* a c d f h i k l m n o */ - 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, - /* p s u v w x z { | ~ */ - 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1 - }; - - /* arguments for reg() */ - private static final int REG_NOPAREN = 0; /* toplevel reg() */ - private static final int REG_PAREN = 1; /* \(\) */ - private static final int REG_ZPAREN = 2; /* \z(\) */ - private static final int REG_NPAREN = 3; /* \%(\) */ - - private static boolean WITH_NL(int op) { - return op >= FIRST_NL && op <= LAST_NL; - } - - /* - * The first byte of the regexp internal "program" is actually this magic - * number; the start node begins in the second byte. It's used to catch the - * most severe mutilation of the program by the caller. - */ - - /* - * Opcode notes: - * - * BRANCH The set of branches constituting a single choice are hooked - * together with their "next" pointers, since precedence prevents - * anything being concatenated to any individual branch. The - * "next" pointer of the last BRANCH in a choice points to the - * thing following the whole choice. This is also where the - * final "next" pointer of each individual branch points; each - * branch starts with the operand node of a BRANCH node. - * - * BACK Normal "next" pointers all implicitly point forward; BACK - * exists to make loop structures possible. - * - * STAR,PLUS '=', and complex '*' and '+', are implemented as circular - * BRANCH structures using BACK. Simple cases (one character - * per match) are implemented with STAR and PLUS for speed - * and to minimize recursive plunges. - * - * BRACE_LIMITS This is always followed by a BRACE_SIMPLE or BRACE_COMPLEX - * node, and defines the min and max limits to be used for that - * node. - * - * MOPEN,MCLOSE ...are numbered at compile time. - * ZOPEN,ZCLOSE ...ditto - */ - - /* - * A node is one char of opcode followed by two chars of "next" pointer. - * "Next" pointers are stored as two 8-bit bytes, high order first. The - * value is a positive offset from the opcode of the node containing it. - * An operand, if any, simply follows the node. (Note that much of the - * code generation knows about this implicit relationship.) - * - * Using two bytes for the "next" pointer is vast overkill for most things, - * but allows patterns to get big without disasters. - */ -// #define OP(p) ((int)*(p)) -// #define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377)) -// #define OPERAND(p) ((p) + 3) -/* Obtain an operand that was stored as four bytes, MSB first. */ -// #define OPERAND_MIN(p) (((long)(p)[3] << 24) + ((long)(p)[4] << 16) \ -// + ((long)(p)[5] << 8) + (long)(p)[6]) -/* Obtain a second operand stored as four bytes. */ -// #define OPERAND_MAX(p) OPERAND_MIN((p) + 4) -/* Obtain a second single-byte operand stored after a four bytes operand. */ -// #define OPERAND_CMP(p) (p)[7] - - /* - * Utility definitions. - */ - // #define UCHARAT(p) ((int)*(char_u *)(p)) - - /* Used for an error (down from) vim_regcomp(): give the error message, set rc_did_emsg and return null */ - /* - #define EMSG_RET_null(m) - { - EMSG(_(m)); - rc_did_emsg = true; - return null; - } - #define EMSG_M_RET_null(m, c) - { - EMSG2(_(m), c ? "" : "\\"); - rc_did_emsg = true; - return null; - } - #define EMSG_RET_FAIL(m) - { - EMSG(_(m)); - rc_did_emsg = true; - return FAIL; - } - #define EMSG_ONE_RET_null - */ - - //EMSG_M_RET_null("E369: invalid item in %s%%[]", reg_magic == MAGIC_ALL) - - private void EMSG_RET_null(@NotNull String key) { - VimPlugin.showMessage(MessageHelper.message(key)); - } - - private void EMSG_M_RET_null(@NotNull String key, boolean isMagic) { - String val = isMagic ? "" : "\\"; - VimPlugin.showMessage(MessageHelper.message(key, val)); - } - - private void EMSG_ONE_RET_null() { - EMSG_M_RET_null(Msg.E369, reg_magic == MAGIC_ALL); - } - - /* - * Return NOT_MULTI if c is not a "multi" operator. - * Return MULTI_ONE if c is a single "multi" operator. - * Return MULTI_MULT if c is a multi "multi" operator. - */ - private int re_multi_type(int c) { - if (c == Magic.AT || c == Magic.EQUAL || c == Magic.QUESTION) { - return MULTI_ONE; - } - if (c == Magic.STAR || c == Magic.PLUS || c == Magic.LCURLY) { - return MULTI_MULT; - } - return NOT_MULTI; - } - - /* - * Translate '\x' to its control character, except "\n", which is Magic. - */ - private int backslash_trans(int c) { - switch (c) { - case 'r': - return '\r'; - case 't': - return '\t'; - case 'e': - return 0x1b; - case 'b': - return '\b'; - } - return c; - } - - /* - * Check for a character class name. "pp" points to the '['. - * Returns one of the CLASS_ items. CLASS_NONE means that no item was - * recognized. Otherwise "pp" is advanced to after the item. - */ - private static int skip_class_name(@NotNull CharPointer pp) { - int i; - - if (pp.charAt(1) == ':') { - for (i = 0; i < CharacterClasses.CLASS_NAMES.length; ++i) { - if (pp.ref(2).strncmp(CharacterClasses.CLASS_NAMES[i], CharacterClasses.CLASS_NAMES[i].length()) == 0) { - pp.inc(CharacterClasses.CLASS_NAMES[i].length() + 2); - return i; - } - } - } - - return CharacterClasses.CLASS_NONE; - } - - /* - * Skip over a "[]" range. - * "p" must point to the character after the '['. - * The returned pointer is on the matching ']', or the terminating NUL. - */ - private static @NotNull CharPointer skip_anyof(@NotNull CharPointer p) { - if (p.charAt() == '^') /* Complement of range. */ { - p.inc(); - } - if (p.charAt() == ']' || p.charAt() == '-') { - p.inc(); - } - while (!p.end() && p.charAt() != ']') { - if (p.charAt() == '-') { - p.inc(); - if (!p.end() && p.charAt() != ']') { - p.inc(); - } - } - else if (p.charAt() == '\\' && - (REGEXP_INRANGE.indexOf(p.charAt(1)) != -1 || REGEXP_ABBR.indexOf(p.charAt(1)) != -1)) { - p.inc(2); - } - else if (p.charAt() == '[') { - if (skip_class_name(p) == CharacterClasses.CLASS_NONE) { - p.inc(); /* It was not a class name */ - } - } - else { - p.inc(); - } - } - - return p; - } - - /* - * Return true if compiled regular expression "prog" can match a line break. - */ - public int re_multiline(@NotNull regprog_T prog) { - return (prog.regflags & RF_HASNL); - } - - /* - * Skip past regular expression. - * Stop at end of 'p' of where 'dirc' is found ('/', '?', etc). - * Take care of characters with a backslash in front of it. - * Skip strings inside [ and ]. - */ - public static @NotNull CharPointer skip_regexp(@NotNull CharPointer p, char dirc, boolean magic) { - int mymagic; - - if (magic) { - mymagic = MAGIC_ON; - } - else { - mymagic = MAGIC_OFF; - } - - for (; !p.end(); p.inc()) { - if (p.charAt() == dirc) /* found end of regexp */ { - break; - } - if ((p.charAt() == '[' && mymagic >= MAGIC_ON) || - (p.charAt() == '\\' && p.charAt(1) == '[' && mymagic <= MAGIC_OFF)) { - p = skip_anyof(p.ref(1)); - if (p.end()) { - break; - } - } - else if (p.charAt() == '\\' && p.charAt(1) != '\u0000') { - p.inc(); /* skip next character */ - if (p.charAt() == 'v') { - mymagic = MAGIC_ALL; - } - else if (p.charAt() == 'V') { - mymagic = MAGIC_NONE; - } - } - } - - return p; - } - - /* - * vim_regcomp - compile a regular expression into internal code - * - * We can't allocate space until we know how big the compiled form will be, - * but we can't compile it (and thus know how big it is) until we've got a - * place to put the code. So we cheat: we compile it twice, once with code - * generation turned off and size counting turned on, and once "for real". - * This also means that we don't allocate space until we are sure that the - * thing really will compile successfully, and we never have to move the - * code and thus invalidate pointers into it. (Note that it has to be in - * one piece because vim_free() must be able to free it all.) - * - * Whether upper/lower case is to be ignored is decided when executing the - * program, it does not matter here. - * - * Beware that the optimization-preparation code in here knows about some - * of the structure of the compiled regexp. - */ - public @Nullable regprog_T vim_regcomp(@Nullable String expr, int magic) { - regprog_T r; - CharPointer scan; - CharPointer longest; - int len; - Flags flags = new Flags(); - - if (expr == null) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_null)); - return null; - } - - r = new regprog_T(); - - /* - * Second pass: emit code. - */ - regcomp_start(expr, magic); - regcode = new CharPointer(r.program); - regc(REGMAGIC); - if (reg(REG_NOPAREN, flags) == null) { - return null; - } - - /* Dig out information for optimizations. */ - r.regstart = 0; /* Worst-case defaults. */ - r.reganch = 0; - r.regmust = null; - r.regmlen = 0; - r.regflags = regflags; - if (flags.isSet(HASNL)) { - r.regflags |= RF_HASNL; - } - /* Remember whether this pattern has any \z specials in it. */ - r.reghasz = re_has_z; - scan = (new CharPointer(r.program)).ref(1); /* First BRANCH. */ - if (regnext(scan).OP() == END) /* Only one top-level choice. */ { - scan = scan.OPERAND(); - - /* Starting-point info. */ - if (scan.OP() == BOL || scan.OP() == RE_BOF) { - r.reganch++; - scan = regnext(scan); - } - - if (scan.OP() == EXACTLY) { - r.regstart = scan.OPERAND().charAt(); - } - else if ((scan.OP() == BOW - || scan.OP() == EOW - || scan.OP() == NOTHING - || scan.OP() == MOPEN || scan.OP() == NOPEN - || scan.OP() == MCLOSE || scan.OP() == NCLOSE) - && regnext(scan).OP() == EXACTLY) { - r.regstart = regnext(scan).OPERAND().charAt(); - } - - /* - * If there's something expensive in the r.e., find the longest - * literal string that must appear and make it the regmust. Resolve - * ties in favor of later strings, since the regstart check works - * with the beginning of the r.e. and avoiding duplication - * strengthens checking. Not a strong reason, but sufficient in the - * absence of others. - */ - /* - * When the r.e. starts with BOW, it is faster to look for a regmust - * first. Used a lot for "#" and "*" commands. (Added by mool). - */ - if ((flags.isSet(SPSTART) || scan.OP() == BOW || scan.OP() == EOW) - && !(flags.isSet(HASNL))) { - longest = null; - len = 0; - for (; scan != null; scan = regnext(scan)) { - CharPointer so = scan.OPERAND(); - if (scan.OP() == EXACTLY && so.strlen() >= len) { - longest = so.ref(0); - len = so.strlen(); - } - } - if (longest != null) { - r.regmust = longest.ref(0); - } - r.regmlen = len; - } - } - - if (logger.isDebugEnabled()) logger.debug(regdump(expr, r)); - - return r; - } - - /* - * Setup to parse the regexp. Used once to get the length and once to do it. - */ - private void regcomp_start(@NotNull String expr, int magic) { - initchr(expr); - if (magic != 0) { - reg_magic = MAGIC_ON; - } - else { - reg_magic = MAGIC_OFF; - } - num_complex_braces = 0; - regnpar = 1; - Arrays.fill(had_endbrace, false); - regnzpar = 1; - re_has_z = 0; - regflags = 0; - had_eol = false; - } - - /* - * Check if during the previous call to vim_regcomp the EOL item "$" has been - * found. This is messy, but it works fine. - */ - public boolean vim_regcomp_had_eol() { - return had_eol; - } - - /* - * reg - regular expression, i.e. main body or parenthesized thing - * - * Caller must absorb opening parenthesis. - * - * Combining parenthesis handling with the base level of regular expression - * is a trifle forced, but the need to tie the tails of the branches to what - * follows makes it hard to avoid. - */ - private @Nullable CharPointer reg(int paren, @NotNull Flags flagp) { - CharPointer ret; - CharPointer br; - CharPointer ender; - int parno = 0; - Flags flags = new Flags(); - - flagp.init(HASWIDTH); /* Tentatively. */ - - if (paren == REG_ZPAREN) { - /* Make a ZOPEN node. */ - if (regnzpar >= NSUBEXP) { - VimPlugin.showMessage(MessageHelper.message(Msg.E50)); - return null; - } - parno = regnzpar; - regnzpar++; - ret = regnode(ZOPEN + parno); - } - else if (paren == REG_PAREN) { - /* Make a MOPEN node. */ - if (regnpar >= NSUBEXP) { - EMSG_M_RET_null(Msg.E51, reg_magic == MAGIC_ALL); - return null; - } - parno = regnpar; - ++regnpar; - ret = regnode(MOPEN + parno); - } - else if (paren == REG_NPAREN) { - /* Make a NOPEN node. */ - ret = regnode(NOPEN); - } - else { - ret = null; - } - - /* Pick up the branches, linking them together. */ - br = regbranch(flags); - if (br == null) { - return null; - } - if (ret != null) { - regtail(ret, br); /* [MZ]OPEN -> first. */ - } - else { - ret = br.ref(0); - } - /* If one of the branches can be zero-width, the whole thing can. - * If one of the branches has * at start or matches a line-break, the - * whole thing can. */ - if (!flags.isSet(HASWIDTH)) { - flagp.unset(HASWIDTH); - } - flagp.set(flags.get() & (SPSTART | HASNL)); - while (peekchr() == Magic.PIPE) { - skipchr(); - br = regbranch(flags); - if (br == null) { - return null; - } - regtail(ret, br); /* BRANCH -> BRANCH. */ - if (!flags.isSet(HASWIDTH)) { - flagp.unset(HASWIDTH); - } - flagp.set(flags.get() & (SPSTART | HASNL)); - } - - /* Make a closing node, and hook it on the end. */ - ender = regnode(paren == REG_ZPAREN ? ZCLOSE + parno : paren == REG_PAREN ? MCLOSE + parno : - paren == REG_NPAREN ? NCLOSE : END); - regtail(ret, ender); - - /* Hook the tails of the branches to the closing node. */ - for (br = ret.ref(0); br != null; br = regnext(br)) { - regoptail(br, ender); - } - - /* Check for proper termination. */ - if (paren != REG_NOPAREN && getchr() != Magic.RPAREN) { - if (paren == REG_ZPAREN) { - VimPlugin.showMessage(MessageHelper.message(Msg.E52)); - return null; - } - else if (paren == REG_NPAREN) { - EMSG_M_RET_null(Msg.E53, reg_magic == MAGIC_ALL); - return null; - } - else { - EMSG_M_RET_null(Msg.E54, reg_magic == MAGIC_ALL); - return null; - } - } - else if (paren == REG_NOPAREN && peekchr() != '\u0000') { - if (curchr == Magic.LPAREN) { - EMSG_M_RET_null(Msg.E55, reg_magic == MAGIC_ALL); - return null; - } - else { - VimPlugin.showMessage(MessageHelper.message(Msg.e_trailing)); - return null; - } - /* NOTREACHED */ - } - /* - * Here we set the flag allowing back references to this set of - * parentheses. - */ - if (paren == REG_PAREN) { - had_endbrace[parno] = true; /* have seen the close paren */ - } - - return ret; - } - - /* - * regbranch - one alternative of an | operator - * - * Implements the & operator. - */ - private @Nullable CharPointer regbranch(@NotNull Flags flagp) { - CharPointer ret; - CharPointer chain = null; - CharPointer latest; - Flags flags = new Flags(); - - flagp.init(WORST | HASNL); /* Tentatively. */ - - ret = regnode(BRANCH); - for (; ; ) { - latest = regconcat(flags); - if (latest == null) { - return null; - } - - /* If one of the branches has width, the whole thing has. If one of - * the branches anchors at start-of-line, the whole thing does. */ - flagp.set(flags.get() & (HASWIDTH | SPSTART)); - /* If one of the branches doesn't match a line-break, the whole thing - * doesn't. */ - flagp.set(flagp.get() & (~HASNL | (flags.get() & HASNL))); - if (chain != null) { - regtail(chain, latest); - } - if (peekchr() != Magic.AMP) { - break; - } - skipchr(); - regtail(latest, regnode(END)); /* operand ends */ - reginsert(MATCH, latest.ref(0)); - chain = latest.ref(0); - } - - return ret; - } - - /* - * regbranch - one alternative of an | or & operator - * - * Implements the concatenation operator. - */ - private @Nullable CharPointer regconcat(@NotNull Flags flagp) { - CharPointer first = null; - CharPointer chain = null; - CharPointer latest; - Flags flags = new Flags(); - boolean cont = true; - - flagp.init(WORST); /* Tentatively. */ - - while (cont) { - switch (peekchr()) { - case '\u0000': - case Magic.PIPE: - case Magic.AMP: - case Magic.RPAREN: - cont = false; - break; - case Magic.c: - regflags |= RF_ICASE; - skipchr_keepstart(); - break; - case Magic.C: - regflags |= RF_NOICASE; - skipchr_keepstart(); - break; - case Magic.v: - reg_magic = MAGIC_ALL; - skipchr_keepstart(); - curchr = -1; - break; - case Magic.m: - reg_magic = MAGIC_ON; - skipchr_keepstart(); - curchr = -1; - break; - case Magic.M: - reg_magic = MAGIC_OFF; - skipchr_keepstart(); - curchr = -1; - break; - case Magic.V: - reg_magic = MAGIC_NONE; - skipchr_keepstart(); - curchr = -1; - break; - default: - latest = regpiece(flags); - if (latest == null) { - return null; - } - flagp.set(flags.get() & (HASWIDTH | HASNL)); - if (chain == null) /* First piece. */ { - flagp.set(flags.get() & SPSTART); - } - else { - regtail(chain, latest); - } - chain = latest.ref(0); - if (first == null) { - first = latest.ref(0); - } - break; - } - } - if (first == null) /* Loop ran zero times. */ { - first = regnode(NOTHING); - } - - return first; - } - - /* - * regpiece - something followed by possible [*+=] - * - * Note that the branching code sequences used for = and the general cases - * of * and + are somewhat optimized: they use the same NOTHING node as - * both the endmarker for their branch list and the body of the last branch. - * It might seem that this node could be dispensed with entirely, but the - * endmarker role is not redundant. - */ - private @Nullable CharPointer regpiece(@NotNull Flags flagp) { - CharPointer ret; - int op; - CharPointer next; - Flags flags = new Flags(); - - ret = regatom(flags); - if (ret == null) { - return null; - } - - op = peekchr(); - if (re_multi_type(op) == NOT_MULTI) { - flagp.init(flags.get()); - return ret; - } - if (!(flags.isSet(HASWIDTH)) && re_multi_type(op) == MULTI_MULT) { - if (op == Magic.STAR) { - EMSG_M_RET_null(Msg.E56, reg_magic >= MAGIC_ON); - return null; - } - if (op == Magic.PLUS) { - EMSG_M_RET_null(Msg.E57, reg_magic == MAGIC_ALL); - return null; - } - /* "\{}" is checked below, it's allowed when there is an upper limit */ - } - flagp.init((WORST | SPSTART | (flags.get() & HASNL))); /* default flags */ - - skipchr(); - switch (op) { - case Magic.STAR: - if (flags.isSet(SIMPLE)) { - reginsert(STAR, ret.ref(0)); - } - else { - /* Emit x* as (x&|), where & means "self". */ - reginsert(BRANCH, ret.ref(0)); /* Either x */ - regoptail(ret, regnode(BACK)); /* and loop */ - regoptail(ret, ret); /* back */ - regtail(ret, regnode(BRANCH)); /* or */ - regtail(ret, regnode(NOTHING)); /* null. */ - } - break; - - case Magic.PLUS: - if (flags.isSet(SIMPLE)) { - reginsert(PLUS, ret.ref(0)); - } - else { - /* Emit x+ as x(&|), where & means "self". */ - next = regnode(BRANCH); /* Either */ - regtail(ret, next); - regtail(regnode(BACK), ret); /* loop back */ - regtail(next, regnode(BRANCH)); /* or */ - regtail(ret, regnode(NOTHING)); /* null. */ - } - flagp.init((WORST | HASWIDTH | (flags.get() & HASNL))); - break; - - case Magic.AT: { - int lop = END; - - switch (Magic.no_Magic(getchr())) { - case '=': - lop = MATCH; - break; /* \@= */ - case '!': - lop = NOMATCH; - break; /* \@! */ - case '>': - lop = SUBPAT; - break; /* \@> */ - case '<': - switch (Magic.no_Magic(getchr())) { - case '=': - lop = BEHIND; - break; /* \@<= */ - case '!': - lop = NOBEHIND; - break; /* \@ minval ? maxval >= MAX_LIMIT : minval >= MAX_LIMIT)) { - EMSG_M_RET_null(Msg.E58, reg_magic == MAGIC_ALL); - return null; - } - if (flags.isSet(SIMPLE)) { - reginsert(BRACE_SIMPLE, ret.ref(0)); - reginsert_limits(BRACE_LIMITS, minval, maxval, ret.ref(0)); - } - else { - if (num_complex_braces >= 10) { - EMSG_M_RET_null(Msg.E60, reg_magic == MAGIC_ALL); - return null; - } - reginsert(BRACE_COMPLEX + num_complex_braces, ret.ref(0)); - regoptail(ret, regnode(BACK)); - regoptail(ret, ret); - reginsert_limits(BRACE_LIMITS, minval, maxval, ret.ref(0)); - ++num_complex_braces; - } - if (minval > 0 && maxval > 0) { - flagp.init((HASWIDTH | (flags.get() & HASNL))); - } - break; - } - if (re_multi_type(peekchr()) != NOT_MULTI) { - /* Can't have a multi follow a multi. */ - if (peekchr() == Magic.STAR) { - String val = reg_magic >= MAGIC_ON ? "" : "\\"; - VimPlugin.showMessage(MessageHelper.message(Msg.E61, val)); - } - else { - String val = reg_magic >= MAGIC_ON ? "" : "\\"; - VimPlugin.showMessage(MessageHelper.message(Msg.E62, val, Character.toString((char)Magic.no_Magic(peekchr())))); - } - return null; - } - - return ret; - } - - /* - * regatom - the lowest level - * - * Optimization: gobbles an entire sequence of ordinary characters so that - * it can turn them into a single node, which is smaller to store and - * faster to run. Don't do this when one_exactly is set. - */ - private @Nullable CharPointer regatom(@NotNull Flags flagp) { - CharPointer ret = null; - Flags flags = new Flags(); - boolean cpo_lit = false; /* 'cpoptions' contains 'l' flag */ - int c; - String classchars = ".iIkKfFpPsSdDxXoOwWhHaAlLuU"; - int[] classcodes = {ANY, IDENT, SIDENT, KWORD, SKWORD, - FNAME, SFNAME, PRINT, SPRINT, - WHITE, NWHITE, DIGIT, NDIGIT, - HEX, NHEX, OCTAL, NOCTAL, - WORD, NWORD, HEAD, NHEAD, - ALPHA, NALPHA, LOWER, NLOWER, - UPPER, NUPPER - }; - CharPointer p; - int extra = 0; - - flagp.init(WORST); /* Tentatively. */ - - c = getchr(); - boolean doCollection = false; - boolean doDefault = false; - switch (c) { - case Magic.HAT: - ret = regnode(BOL); - break; - - case Magic.DOLLAR: - ret = regnode(EOL); - had_eol = true; - break; - - case Magic.LESS: - ret = regnode(BOW); - break; - - case Magic.GREATER: - ret = regnode(EOW); - break; - - case Magic.UNDER: - c = Magic.no_Magic(getchr()); - if (c == '^') /* "\_^" is start-of-line */ { - ret = regnode(BOL); - break; - } - if (c == '$') /* "\_$" is end-of-line */ { - ret = regnode(EOL); - had_eol = true; - break; - } - - extra = ADD_NL; - flagp.set(HASNL); - - /* "\_[" is character range plus newline */ - if (c == '[') { - //goto collection; - doCollection = true; - } - - /* "\_x" is character class plus newline */ - /*FALLTHROUGH*/ - - /* - * Character classes. - */ - case Magic.DOT: - case Magic.i: - case Magic.I: - case Magic.k: - case Magic.K: - case Magic.f: - case Magic.F: - case Magic.p: - case Magic.P: - case Magic.s: - case Magic.S: - case Magic.d: - case Magic.D: - case Magic.x: - case Magic.X: - case Magic.o: - case Magic.O: - case Magic.w: - case Magic.W: - case Magic.h: - case Magic.H: - case Magic.a: - case Magic.A: - case Magic.l: - case Magic.L: - case Magic.u: - case Magic.U: - int i = classchars.indexOf(Magic.no_Magic(c)); - if (i == -1) { - VimPlugin.showMessage(MessageHelper.message(Msg.E63)); - return null; - } - ret = regnode(classcodes[i] + extra); - flagp.set(HASWIDTH | SIMPLE); - break; - - case Magic.n: - ret = regnode(NEWL); - flagp.set(HASWIDTH | HASNL); - break; - - case Magic.LPAREN: - if (one_exactly) { - EMSG_ONE_RET_null(); - return null; - } - ret = reg(REG_PAREN, flags); - if (ret == null) { - return null; - } - flagp.set(flags.get() & (HASWIDTH | SPSTART | HASNL)); - break; - - case '\u0000': - case Magic.PIPE: - case Magic.AMP: - case Magic.RPAREN: - EMSG_RET_null(Msg.e_internal); /* Supposed to be caught earlier. */ - return null; - /* NOTREACHED */ - - case Magic.EQUAL: - case Magic.QUESTION: - case Magic.PLUS: - case Magic.AT: - case Magic.LCURLY: - case Magic.STAR: - c = Magic.no_Magic(c); - String val = (c == '*' ? reg_magic >= MAGIC_ON : reg_magic == MAGIC_ALL) ? "" : "\\"; - VimPlugin.showMessage(MessageHelper.message(Msg.E64, val, Character.toString((char)c))); - return null; - /* NOTREACHED */ - - case Magic.TILDE: /* previous substitute pattern */ - if (reg_prev_sub != null) { - CharPointer lp; - - ret = regnode(EXACTLY); - lp = reg_prev_sub.ref(0); - while (!lp.isNul()) { - regc(lp.charAt()); - } - lp.inc(); - regc('\u0000'); - if (!reg_prev_sub.isNul()) { - flagp.set(HASWIDTH); - if ((lp.pointer() - reg_prev_sub.pointer()) == 1) { - flagp.set(SIMPLE); - } - } - } - else { - VimPlugin.showMessage(MessageHelper.message(Msg.e_nopresub)); - return null; - } - break; - - case Magic.N1: - case Magic.N2: - case Magic.N3: - case Magic.N4: - case Magic.N5: - case Magic.N6: - case Magic.N7: - case Magic.N8: - case Magic.N9: { - int refnum; - - refnum = c - Magic.N0; - /* - * Check if the back reference is legal. We must have seen the - * close brace. - * TODO: Should also check that we don't refer to something - * that is repeated (+*=): what instance of the repetition - * should we match? - */ - if (!had_endbrace[refnum]) { - /* Trick: check if "@<=" or "@') { - int n = 0; - int cmp; - - cmp = c; - if (cmp == '<' || cmp == '>') { - c = getchr(); - } - while (Character.isDigit((char)c)) { - n = n * 10 + (c - '0'); - c = getchr(); - } - if (c == 'l' || c == 'c' || c == 'v') { - if (c == 'l') { - ret = regnode(RE_LNUM); - } - else if (c == 'c') { - ret = regnode(RE_COL); - } - else { - ret = regnode(RE_VCOL); - } - - /* put the number and the optional - * comparator after the opcode */ - regcode = re_put_long(regcode.ref(0), n); - regcode.set((char)cmp).inc(); - break; - } - } - - EMSG_M_RET_null(Msg.E71, reg_magic == MAGIC_ALL); - return null; - } - } - break; - case Magic.LBRACE: - doCollection = true; - break; - default: - doDefault = true; - break; - } - - if (doCollection) { - CharPointer lp; - - /* - * If there is no matching ']', we assume the '[' is a normal - * character. This makes 'incsearch' and ":help [" work. - */ - lp = skip_anyof(regparse.ref(0)); - if (lp.charAt() == ']') /* there is a matching ']' */ { - int startc = -1; /* > 0 when next '-' is a range */ - int endc; - - /* - * In a character class, different parsing rules apply. - * Not even \ is special anymore, nothing is. - */ - if (regparse.charAt() == '^') /* Complement of range. */ { - ret = regnode(ANYBUT + extra); - regparse.inc(); - } - else { - ret = regnode(ANYOF + extra); - } - - /* At the start ']' and '-' mean the literal character. */ - if (regparse.charAt() == ']' || regparse.charAt() == '-') { - regc(regparse.charAt()); - regparse.inc(); - } - - while (!regparse.isNul() && regparse.charAt() != ']') { - if (regparse.charAt() == '-') { - regparse.inc(); - /* The '-' is not used for a range at the end and - * after or before a '\n'. */ - if (regparse.isNul() || regparse.charAt() == ']' || startc == -1 || - (regparse.charAt(0) == '\\' && regparse.charAt(1) == 'n')) { - regc('-'); - startc = '-'; /* [--x] is a range */ - } - else { - //endc = *regparse++; - endc = regparse.charAt(); - regparse.inc(); - if (startc > endc) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_invrange)); - return null; - } - while (++startc <= endc) { - regc(startc); - } - startc = -1; - } - } - /* - * Only "\]", "\^", "\]" and "\\" are special in Vi. Vim - * accepts "\t", "\e", etc., but only when the 'l' flag in - * 'cpoptions' is not included. - */ - else if (regparse.charAt() == '\\' && - (REGEXP_INRANGE.indexOf(regparse.charAt(1)) != -1 || (!cpo_lit && - REGEXP_ABBR.indexOf(regparse.charAt(1)) != -1))) { - regparse.inc(); - if (regparse.charAt() == 'n') { - /* '\n' in range: also match NL */ - if (ret.charAt() == ANYBUT) { - ret.set((char)(ANYBUT + ADD_NL)); - } - else if (ret.charAt() == ANYOF) { - ret.set((char)(ANYOF + ADD_NL)); - } - /* else: must have had a \n already */ - flagp.set(HASNL); - regparse.inc(); - startc = -1; - } - else { - startc = backslash_trans(regparse.charAt()); - regparse.inc(); - regc(startc); - } - } - else if (regparse.charAt() == '[') { - int c_class; - int cu; - - c_class = skip_class_name(regparse); - startc = -1; - /* Characters assumed to be 8 bits! */ - switch (c_class) { - case CharacterClasses.CLASS_NONE: - /* literal '[', allow [[-x] as a range */ - startc = regparse.charAt(); - regparse.inc(); - regc(startc); - break; - case CharacterClasses.CLASS_ALNUM: - for (cu = 1; cu <= 255; cu++) { - if (Character.isLetterOrDigit((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_ALPHA: - for (cu = 1; cu <= 255; cu++) { - if (Character.isLetter((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_BLANK: - regc(' '); - regc('\t'); - break; - case CharacterClasses.CLASS_CNTRL: - for (cu = 1; cu <= 255; cu++) { - if (Character.isISOControl((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_DIGIT: - for (cu = 1; cu <= 255; cu++) { - if (Character.isDigit((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_GRAPH: - for (cu = 1; cu <= 255; cu++) { - if (CharacterClasses.isGraph((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_LOWER: - for (cu = 1; cu <= 255; cu++) { - if (Character.isLowerCase((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_PRINT: - for (cu = 1; cu <= 255; cu++) { - if (CharacterClasses.isPrint((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_PUNCT: - for (cu = 1; cu <= 255; cu++) { - if (CharacterClasses.isPunct((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_SPACE: - for (cu = 9; cu <= 13; cu++) { - regc(cu); - } - regc(' '); - break; - case CharacterClasses.CLASS_UPPER: - for (cu = 1; cu <= 255; cu++) { - if (Character.isUpperCase((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_XDIGIT: - for (cu = 1; cu <= 255; cu++) { - if (CharacterClasses.isHex((char)cu)) { - regc(cu); - } - } - break; - case CharacterClasses.CLASS_TAB: - regc('\t'); - break; - case CharacterClasses.CLASS_RETURN: - regc('\r'); - break; - case CharacterClasses.CLASS_BACKSPACE: - regc('\b'); - break; - case CharacterClasses.CLASS_ESCAPE: - regc('\033'); - break; - } - } - else { - startc = regparse.charAt(); - regparse.inc(); - regc(startc); - } - } - regc('\u0000'); - prevchr_len = 1; /* last char was the ']' */ - if (regparse.charAt() != ']') { - VimPlugin.showMessage(MessageHelper.message(Msg.e_toomsbra)); - return null; - } - skipchr(); /* let's be friends with the lexer again */ - flagp.set(HASWIDTH | SIMPLE); - } - else { - doDefault = true; - } - } - /* FALLTHROUGH */ - - if (doDefault) { - int len; - - ret = regnode(EXACTLY); - - /* - * Append characters as long as: - * - there is no following multi, we then need the character in - * front of it as a single character operand - * - not running into a Magic character - * - "one_exactly" is not set - * But always emit at least one character. Might be a Multi, - * e.g., a "[" without matching "]". - */ - for (len = 0; c != '\u0000' && (len == 0 || (re_multi_type(peekchr()) == NOT_MULTI && - !one_exactly && !Magic.is_Magic(c))); ++len) { - c = Magic.no_Magic(c); - regc(c); - c = getchr(); - } - ungetchr(); - - regc('\u0000'); - flagp.set(HASWIDTH); - if (len == 1) { - flagp.set(SIMPLE); - } - } - - return ret; - } - - /* - * emit a node - * Return pointer to generated code. - */ - private CharPointer regnode(int op) { - CharPointer ret; - - ret = regcode.ref(0); - regcode.set((char)op).inc(); - regcode.set('\u0000').inc(); /* Null "next" pointer. */ - regcode.set('\u0000').inc(); - return ret; - } - - /* - * Emit (if appropriate) a byte of code - */ - private void regc(int b) { - regcode.set((char)b).inc(); - } - - /* - * reginsert - insert an operator in front of already-emitted operand - * - * Means relocating the operand. - */ - private void reginsert(int op, @NotNull CharPointer opnd) { - CharPointer src; - CharPointer dst; - CharPointer place; - - src = regcode.ref(0); - regcode.inc(3); - dst = regcode.ref(0); - while (src.pointer() > opnd.pointer()) { - //*--dst = *--src; - dst.dec().set(src.dec().charAt()); - } - - place = opnd.ref(0); /* Op node, where operand used to be. */ - place.set((char)op).inc(); - place.set('\u0000').inc(); - place.set('\u0000'); - } - - /* - * reginsert_limits - insert an operator in front of already-emitted operand. - * The operator has the given limit values as operands. Also set next pointer. - * - * Means relocating the operand. - */ - private void reginsert_limits(int op, int minval, int maxval, @NotNull CharPointer opnd) { - CharPointer src; - CharPointer dst; - CharPointer place; - - src = regcode.ref(0); - regcode.inc(11); - dst = regcode.ref(0); - while (src.pointer() > opnd.pointer()) { - //*--dst = *--src; - dst.dec().set(src.dec().charAt()); - } - - place = opnd.ref(0); /* Op node, where operand used to be. */ - place.set((char)op).inc(); - place.set('\u0000').inc(); - place.set('\u0000').inc(); - place = re_put_long(place.ref(0), minval); - place = re_put_long(place.ref(0), maxval); - regtail(opnd, place); - } - - /* - * Write a long as four bytes at "p" and return pointer to the next char. - */ - private @NotNull CharPointer re_put_long(@NotNull CharPointer p, int val) { - p.set((char)((val >> 24) & 0xff)).inc(); - p.set((char)((val >> 16) & 0xff)).inc(); - p.set((char)((val >> 8) & 0xff)).inc(); - p.set((char)(val & 0xff)).inc(); - return p; - } - - /* - * regtail - set the next-pointer at the end of a node chain - */ - private void regtail(@NotNull CharPointer p, @NotNull CharPointer val) { - CharPointer scan; - int offset; - - /* Find last node. */ - scan = p.ref(0); - for (; ; ) { - CharPointer temp = regnext(scan); - if (temp == null) { - break; - } - scan = temp; - } - - if (scan.OP() == BACK) { - offset = scan.pointer() - val.pointer(); - } - else { - offset = val.pointer() - scan.pointer(); - } - - scan.ref(1).set((char)(((char)offset >> 8) & 0xff)); - scan.ref(2).set((char)(offset & 0xff)); - } - - /* - * regoptail - regtail on item after a BRANCH; nop if none - */ - private void regoptail(@Nullable CharPointer p, @NotNull CharPointer val) { - /* When op is neither BRANCH nor BRACE_COMPLEX0-9, it is "operandless" */ - if (p == null || (p.OP() != BRANCH && (p.OP() < BRACE_COMPLEX || p.OP() > BRACE_COMPLEX + 9))) { - return; - } - - regtail(p.OPERAND(), val); - } - - private void initchr(@NotNull String str) { - regparse = new CharPointer(str); - prevchr_len = 0; - curchr = prevprevchr = prevchr = nextchr = -1; - at_start = true; - prev_at_start = false; - } - - private int peekchr() { - if (curchr == -1) { - switch (curchr = regparse.charAt(0)) { - case '.': - case '[': - case '~': - /* magic when 'magic' is on */ - if (reg_magic >= MAGIC_ON) { - curchr = Magic.magic(curchr); - } - break; - case '(': - case ')': - case '{': - case '%': - case '+': - case '=': - case '?': - case '@': - case '!': - case '&': - case '|': - case '<': - case '>': - case '#': /* future ext. */ - case '"': /* future ext. */ - case '\'': /* future ext. */ - case ',': /* future ext. */ - case '-': /* future ext. */ - case ':': /* future ext. */ - case ';': /* future ext. */ - case '`': /* future ext. */ - case '/': /* Can't be used in / command */ - /* magic only after "\v" */ - if (reg_magic == MAGIC_ALL) { - curchr = Magic.magic(curchr); - } - break; - case '*': - /* * is not magic as the very first character, eg "?*ptr" and when - * after '^', eg "/^*ptr" */ - if (reg_magic >= MAGIC_ON && !at_start && !(prev_at_start && prevchr == Magic.HAT)) { - curchr = Magic.STAR; - } - break; - case '^': - /* '^' is only magic as the very first character and if it's after - * "\(", "\|", "\&' or "\n" */ - if (reg_magic >= MAGIC_OFF && - (at_start || reg_magic == MAGIC_ALL || prevchr == Magic.LPAREN || prevchr == Magic.PIPE || - prevchr == Magic.AMP || prevchr == Magic.n || (Magic.no_Magic(prevchr) == '(' && - prevprevchr == Magic.PERCENT))) { - curchr = Magic.HAT; - at_start = true; - prev_at_start = false; - } - break; - case '$': - /* '$' is only magic as the very last char and if it's in front of - * either "\|", "\)", "\&", or "\n" */ - if (reg_magic >= MAGIC_OFF) { - CharPointer p = regparse.ref(1); - - /* ignore \c \C \m and \M after '$' */ - while (p.charAt(0) == '\\' && (p.charAt(1) == 'c' || p.charAt(1) == 'C' || - p.charAt(1) == 'm' || p.charAt(1) == 'M')) { - p.inc(2); - } - if (p.charAt(0) == '\u0000' || (p.charAt(0) == '\\' && - (p.charAt(1) == '|' || p.charAt(1) == '&' || p.charAt(1) == ')' || - p.charAt(1) == 'n')) || reg_magic == MAGIC_ALL) { - curchr = Magic.DOLLAR; - } - } - break; - case '\\': { - int c = regparse.charAt(1); - - if (c == '\u0000') { - curchr = '\\'; /* trailing '\' */ - } - else if (c <= '~' && META_flags[c] != 0) { - /* - * META contains everything that may be magic sometimes, - * except ^ and $ ("\^" and "\$" are only magic after - * "\v"). We now fetch the next character and toggle its - * magicness. Therefore, \ is so meta-magic that it is - * not in META. - */ - curchr = -1; - prev_at_start = at_start; - at_start = false; /* be able to say "/\*ptr" */ - regparse.inc(); - peekchr(); - regparse.dec(); - curchr = Magic.toggle_Magic(curchr); - } - else if (REGEXP_ABBR.indexOf(c) != -1) { - /* - * Handle abbreviations, like "\t" for TAB -- webb - */ - curchr = backslash_trans(c); - } - else if (reg_magic == MAGIC_NONE && (c == '$' || c == '^')) { - curchr = Magic.toggle_Magic(c); - } - else { - /* - * Next character can never be (made) magic? - * Then backslashing it won't do anything. - */ - curchr = c; - } - break; - } - } - } - - return curchr; - } - - /* - * Eat one lexed character. Do this in a way that we can undo it. - */ - private void skipchr() { - /* peekchr() eats a backslash, do the same here */ - if (regparse.charAt() == '\\') { - prevchr_len = 1; - } - else { - prevchr_len = 0; - } - if (regparse.charAt(prevchr_len) != '\u0000') { - ++prevchr_len; - } - regparse.inc(prevchr_len); - prev_at_start = at_start; - at_start = false; - prevprevchr = prevchr; - prevchr = curchr; - curchr = nextchr; /* use previously unget char, or -1 */ - nextchr = -1; - } - - /* - * Skip a character while keeping the value of prev_at_start for at_start. - * prevchr and prevprevchr are also kept. - */ - private void skipchr_keepstart() { - boolean as = prev_at_start; - int pr = prevchr; - int prpr = prevprevchr; - - skipchr(); - at_start = as; - prevchr = pr; - prevprevchr = prpr; - } - - private int getchr() { - int chr = peekchr(); - - skipchr(); - return chr; - } - - /* - * put character back. Works only once! - */ - private void ungetchr() { - nextchr = curchr; - curchr = prevchr; - prevchr = prevprevchr; - at_start = prev_at_start; - prev_at_start = false; - - /* Backup regparse, so that it's at the same position as before the - * getchr(). */ - regparse.dec(prevchr_len); - } - - /* - * read_limits - Read two integers to be taken as a minimum and maximum. - * If the first character is '-', then the range is reversed. - * Should end with 'end'. If minval is missing, zero is default, if maxval is - * missing, a very big number is the default. - */ - private @Nullable MinMax read_limits() { - boolean reverse = false; - CharPointer first_char; - int minval; - int maxval; - - if (regparse.charAt() == '-') { - /* Starts with '-', so reverse the range later */ - regparse.inc(); - reverse = true; - } - - first_char = regparse.ref(0); - minval = getdigits(regparse); - if (regparse.charAt() == ',') /* There is a comma */ { - if (Character.isDigit(regparse.inc().charAt())) { - maxval = getdigits(regparse); - } - else { - maxval = MAX_LIMIT; - } - } - else if (Character.isDigit(first_char.charAt())) { - maxval = minval; /* It was \{n} or \{-n} */ - } - else { - maxval = MAX_LIMIT; /* It was \{} or \{-} */ - } - - if (regparse.charAt() == '\\') { - regparse.inc(); /* Allow either \{...} or \{...\} */ - } - if (regparse.charAt() != '}' || (maxval == 0 && minval == 0)) { - String val = reg_magic == MAGIC_ALL ? "" : "\\"; - VimPlugin.showMessage(MessageHelper.message(Msg.synerror, val)); - return null; - } - - /* - * Reverse the range if there was a '-', or make sure it is in the right - * order otherwise. - */ - if ((!reverse && minval > maxval) || (reverse && minval < maxval)) { - int tmp = minval; - minval = maxval; - maxval = tmp; - } - skipchr(); /* let's be friends with the lexer again */ - - MinMax res = new MinMax(); - res.maxvalue = maxval; - res.minvalue = minval; - - return res; - } - - private int getdigits(@NotNull CharPointer p) { - int res = 0; - boolean neg = false; - - if (p.charAt() == '-') { - neg = true; - p.inc(); - } - while (Character.isDigit(p.charAt())) { - res = res * 10 + Character.digit(p.charAt(), 10); - p.inc(); - } - if (neg) { - res = -res; - } - - return res; - } - - /* - * vim_regexec and friends - */ - - /* - * Get pointer to the line "lnum", which is relative to "reg_firstlnum". - */ - private @Nullable CharPointer reg_getline(int lnum) { - /* when looking behind for a match/no-match lnum is negative. But we - * can't go before line 1 */ - if (reg_firstlnum + lnum < 0) { - return null; - } - - //return ml_get_buf(reg_buf, reg_firstlnum + lnum, false); - return new CharPointer(EditorHelper.getLineBuffer(reg_buf, reg_firstlnum + lnum)); - } - - /* - * Match a regexp against a string. - * "rmp->regprog" is a compiled regexp as returned by vim_regcomp(). - * Uses curbuf for line count and 'iskeyword'. - * - * Return true if there is a match, false if not. - */ - public boolean vim_regexec(@NotNull regmatch_T rmp, CharPointer line, int col) { - reg_match = rmp; - reg_mmatch = null; - reg_maxline = 0; - //reg_win = null; - ireg_ic = rmp.rm_ic; - - return (vim_regexec_both(line, col) != 0); - } - - /* - * Match a regexp against multiple lines. - * "rmp->regprog" is a compiled regexp as returned by vim_regcomp(). - * Uses curbuf for line count and 'iskeyword'. - * - * Return zero if there is no match. Return number of lines contained in the - * match otherwise. - */ - public int vim_regexec_multi(@NotNull regmmatch_T rmp, /*win_T win,*/ Editor buf, int lcount, int lnum, int col) - - /* window in which to search or null */ - /* buffer in which to search */ - /* nr of line to start looking for match */ - /* column to start looking for match */ { - int r; - //Editor save_curbuf = curbuf; - - reg_match = null; - reg_mmatch = rmp; - reg_buf = buf; - //reg_win = win; - reg_firstlnum = lnum; - reg_maxline = lcount - lnum; - ireg_ic = rmp.rmm_ic; - - /* Need to switch to buffer "buf" to make vim_iswordc() work. */ - //curbuf = buf; - r = vim_regexec_both(null, col); - //curbuf = save_curbuf; - - return r; - } - - public boolean vim_string_contains_regexp(@NotNull regmmatch_T rmp, @NotNull String string) { - reg_match = null; - reg_mmatch = rmp; - ireg_ic = rmp.rmm_ic; - - regprog_T prog; - CharPointer s; - int retval = 0; - reg_tofree = null; - - prog = reg_mmatch.regprog; - CharPointer line = new CharPointer(string); - reg_startpos = reg_mmatch.startpos; - reg_endpos = reg_mmatch.endpos; - - /* Be paranoid... */ - if (prog == null) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_null)); - return false; - } - - /* Check validity of program. */ - if (prog_magic_wrong()) { - return false; - } - - /* If pattern contains "\c" or "\C": overrule value of ireg_ic */ - if ((prog.regflags & RF_ICASE) != 0) { - ireg_ic = true; - } - else if ((prog.regflags & RF_NOICASE) != 0) { - ireg_ic = false; - } - - /* If there is a "must appear" string, look for it. */ - if (prog.regmust != null) { - char c; - - c = prog.regmust.charAt(); - s = line; - while ((s = cstrchr(s, c)) != null) { - if (cstrncmp(s, prog.regmust, prog.regmlen) == 0) { - break; /* Found it. */ - } - s.inc(); - } - if (s == null) /* Not present. */ { - // goto the end; - return false; - } - } - - regline = line.ref(0); - reglnum = 0; - out_of_stack = false; - - int col = 0; - /* Simplest case: Anchored match need be tried only once. */ - char c; - - c = regline.charAt(col); - if (prog.regstart == '\u0000' || - prog.regstart == c || - (ireg_ic && Character.toLowerCase(prog.regstart) == Character.toLowerCase(c))) { - retval = regtry(prog, col); - } - - if (out_of_stack) { - VimPlugin.showMessage(MessageHelper.message(Msg.E363)); - } - - return retval > 0; - } - - /* - * Match a regexp against a string ("line" points to the string) or multiple - * lines ("line" is null, use reg_getline()). - */ - private int vim_regexec_both(CharPointer line, int col) - /* column to start looking for match */ { - regprog_T prog; - CharPointer s; - int retval; - reg_tofree = null; - retval = 0; - - if (reg_match == null) { - prog = reg_mmatch.regprog; - line = reg_getline(0); - reg_startpos = reg_mmatch.startpos; - reg_endpos = reg_mmatch.endpos; - } - else { - prog = reg_match.regprog; - reg_startp = reg_match.startp; - reg_endp = reg_match.endp; - } - - /* Be paranoid... */ - if (prog == null || line == null) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_null)); - return retval; - } - - /* Check validity of program. */ - if (prog_magic_wrong()) { - return retval; - } - - /* If pattern contains "\c" or "\C": overrule value of ireg_ic */ - if ((prog.regflags & RF_ICASE) != 0) { - ireg_ic = true; - } - else if ((prog.regflags & RF_NOICASE) != 0) { - ireg_ic = false; - } - - /* If there is a "must appear" string, look for it. */ - if (prog.regmust != null) { - char c; - - c = prog.regmust.charAt(); - s = line.ref(col); - while ((s = cstrchr(s, c)) != null) { - if (cstrncmp(s, prog.regmust, prog.regmlen) == 0) { - break; /* Found it. */ - } - s.inc(); - } - if (s == null) /* Not present. */ { - // goto theend; - return retval; - } - } - - regline = line.ref(0); - reglnum = 0; - out_of_stack = false; - - /* Simplest case: Anchored match need be tried only once. */ - if (prog.reganch != 0) { - char c; - - c = regline.charAt(col); - if (prog.regstart == '\u0000' || prog.regstart == c || - (ireg_ic && Character.toLowerCase(prog.regstart) == Character.toLowerCase(c))) { - retval = regtry(prog, col); - } - else { - retval = 0; - } - } - else { - /* Messy cases: unanchored match. */ - while (!got_int && !out_of_stack) { - if (prog.regstart != '\u0000') { - /* Skip until the char we know it must start with. */ - s = cstrchr(regline.ref(col), prog.regstart); - if (s == null) { - retval = 0; - break; - } - col = s.pointer() - regline.pointer(); - } - - retval = regtry(prog, col); - if (retval > 0) { - break; - } - - /* if not currently on the first line, get it again */ - if (reglnum != 0) { - regline = reg_getline(0); - reglnum = 0; - } - if (regline.charAt(col) == '\u0000') { - break; - } - ++col; - } - } - - if (out_of_stack) { - VimPlugin.showMessage(MessageHelper.message(Msg.E363)); - } - - /* Didn't find a match. */ - //vim_free(reg_tofree); - return retval; - } - - private static class reg_extmatch_T { - @NotNull String[] matches = new String[NSUBEXP]; - } - - /* - * Create a new extmatch and mark it as referenced once. - */ - private @NotNull reg_extmatch_T make_extmatch() { - return new reg_extmatch_T(); - } - - /* - * Add a reference to an extmatch. - */ - /* - private reg_extmatch_T ref_extmatch(reg_extmatch_T em) - { - return em; - } - */ - - /* - * Remove a reference to an extmatch. If there are no references left, free - * the info. - */ - /* - private void unref_extmatch(reg_extmatch_T em) - { - } - */ - - /* - * regtry - try match of "prog" with at regline["col"]. - * Returns 0 for failure, number of lines contained in the match otherwise. - */ - private int regtry(@NotNull regprog_T prog, int col) { - reginput = regline.ref(col); - need_clear_subexpr = true; - /* Clear the external match subpointers if necessary. */ - if (prog.reghasz == REX_SET) { - need_clear_zsubexpr = true; - } - - if (regmatch((new CharPointer(prog.program)).ref(1))) { - cleanup_subexpr(); - if (reg_match == null) { - if (reg_startpos[0].lnum < 0) { - reg_startpos[0].lnum = 0; - reg_startpos[0].col = col; - } - if (reg_endpos[0].lnum < 0) { - reg_endpos[0].lnum = reglnum; - reg_endpos[0].col = reginput.pointer() - regline.pointer(); - } - } - else { - if (reg_startp[0] == null) { - reg_startp[0] = regline.ref(col); - } - if (reg_endp[0] == null) { - reg_endp[0] = reginput; - } - } - /* Package any found \z(...\) matches for export. Default is none. */ - //unref_extmatch(re_extmatch_out); - re_extmatch_out = null; - - if (prog.reghasz == REX_SET) { - int i; - - cleanup_zsubexpr(); - re_extmatch_out = make_extmatch(); - for (i = 0; i < NSUBEXP; i++) { - if (reg_match == null) { - /* Only accept single line matches. */ - if (reg_startzpos[i].lnum >= 0 && reg_endzpos[i].lnum == reg_startzpos[i].lnum) { - re_extmatch_out.matches[i] = - reg_getline(reg_startzpos[i].lnum).ref(reg_startzpos[i].col).substring( - reg_endzpos[i].col - reg_startzpos[i].col); - } - } - else { - if (reg_startzp[i] != null && reg_endzp[i] != null) { - re_extmatch_out.matches[i] = - reg_startzp[i].substring(reg_endzp[i].pointer() - reg_startzp[i].pointer()); - } - } - } - } - return 1 + reglnum; - } - return 0; - } - - /* - * regmatch - main matching routine - * - * Conceptually the strategy is simple: Check to see whether the current - * node matches, call self recursively to see whether the rest matches, - * and then act accordingly. In practice we make some effort to avoid - * recursion, in particular by going through "ordinary" nodes (that don't - * need to know whether the rest of the match failed) by a loop instead of - * by recursion. - * - * Returns true when there is a match. Leaves reginput and reglnum just after - * the last matched character. - * Returns false when there is no match. Leaves reginput and reglnum in an - * undefined state! - */ - private boolean regmatch(@Nullable CharPointer scan) { - CharPointer next; /* Next node. */ - int op; - char c; - - /* Some patterns my cause a long time to match, even though they are not - * illegal. E.g., "\([a-z]\+\)\+Q". Allow breaking them with CTRL-C. */ - //fast_breakcheck(); - TODO - - while (scan != null) { - if (got_int || out_of_stack) { - return false; - } - next = regnext(scan); - - op = scan.OP(); - /* Check for character class with NL added. */ - if (WITH_NL(op) && reginput.isNul() && reglnum < reg_maxline) { - reg_nextline(); - } - else { - if (WITH_NL(op)) { - op -= ADD_NL; - } - c = reginput.charAt(); - switch (op) { - case BOL: - if (!reginput.equals(regline)) { - return false; - } - break; - - case EOL: - if (c != '\u0000') { - return false; - } - break; - - case RE_BOF: - /* Passing -1 to the getline() function provided for the search - * should always return null if the current line is the first - * line of the file. */ - if (reglnum != 0 || !reginput.equals(regline) || (reg_match == null && reg_getline(-1) != null)) { - return false; - } - break; - - case RE_EOF: - if (reglnum != reg_maxline || c != '\u0000') { - return false; - } - break; - - case CURSOR: - /* Check if the buffer is in a window and compare the - * reg_win->w_cursor position to the match position. */ - LogicalPosition curpos = reg_buf.getCaretModel().getLogicalPosition(); - if (reglnum + reg_firstlnum != curpos.line || - reginput.pointer() - regline.pointer() != curpos.column) { - return false; - } - break; - - case RE_LNUM: - if (reg_match != null || !re_num_cmp((reglnum + reg_firstlnum), scan)) { - return false; - } - break; - - case RE_COL: - if (!re_num_cmp((reginput.pointer() - regline.pointer()) + 1, scan)) { - return false; - } - break; - - case RE_VCOL: - /* TODO - if (!re_num_cmp(win_linetabsize(reg_win == null ? curwin : reg_win, - regline, (int)(reginput - regline)) + 1, scan)) - { - return false; - } - */ - break; - - case BOW: /* \ regline.pointer() && - CharacterClasses.isWord(reginput.charAt(-1)))) { - return false; - } - } - break; - - case EOW: /* word\>; reginput points after d */ - if (reginput.equals(regline)) /* Can't match at start of line */ { - return false; - } - if (!CharacterClasses.isWord(reginput.charAt(-1))) { - return false; - } - if (!reginput.isNul() && CharacterClasses.isWord(c)) { - return false; - } - break; /* Matched with EOW */ - - case ANY: - if (c == '\u0000') { - return false; - } - reginput.inc(); - break; - - case IDENT: - if (!Character.isJavaIdentifierPart(c)) { - return false; - } - reginput.inc(); - break; - - case SIDENT: - if (Character.isDigit(reginput.charAt()) || !Character.isJavaIdentifierPart(c)) { - return false; - } - reginput.inc(); - break; - - case KWORD: - if (!CharacterClasses.isWord(reginput.charAt())) { - return false; - } - reginput.inc(); - break; - - case SKWORD: - if (Character.isDigit(reginput.charAt()) || !CharacterClasses.isWord(reginput.charAt())) { - return false; - } - reginput.inc(); - break; - - case FNAME: - if (!CharacterClasses.isFile(c)) { - return false; - } - reginput.inc(); - break; - - case SFNAME: - if (Character.isDigit(reginput.charAt()) || !CharacterClasses.isFile(c)) { - return false; - } - reginput.inc(); - break; - - case PRINT: - if (!CharacterClasses.isPrint(reginput.charAt())) { - return false; - } - reginput.inc(); - break; - - case SPRINT: - if (Character.isDigit(reginput.charAt()) || !CharacterClasses.isPrint(reginput.charAt())) { - return false; - } - reginput.inc(); - break; - - case WHITE: - if (!CharacterClasses.isWhite(c)) { - return false; - } - reginput.inc(); - break; - - case NWHITE: - if (c == '\u0000' || CharacterClasses.isWhite(c)) { - return false; - } - reginput.inc(); - break; - - case DIGIT: - if (!Character.isDigit(c)) { - return false; - } - reginput.inc(); - break; - - case NDIGIT: - if (c == '\u0000' || Character.isDigit(c)) { - return false; - } - reginput.inc(); - break; - - case HEX: - if (!CharacterClasses.isHex(c)) { - return false; - } - reginput.inc(); - break; - - case NHEX: - if (c == '\u0000' || CharacterClasses.isHex(c)) { - return false; - } - reginput.inc(); - break; - - case OCTAL: - if (!CharacterClasses.isOctal(c)) { - return false; - } - reginput.inc(); - break; - - case NOCTAL: - if (c == '\u0000' || CharacterClasses.isOctal(c)) { - return false; - } - reginput.inc(); - break; - - case WORD: - if (!CharacterClasses.isWord(c)) { - return false; - } - reginput.inc(); - break; - - case NWORD: - if (c == '\u0000' || CharacterClasses.isWord(c)) { - return false; - } - reginput.inc(); - break; - - case HEAD: - if (!CharacterClasses.isHead(c)) { - return false; - } - reginput.inc(); - break; - - case NHEAD: - if (c == '\u0000' || CharacterClasses.isHead(c)) { - return false; - } - reginput.inc(); - break; - - case ALPHA: - if (!CharacterClasses.isAlpha(c)) { - return false; - } - reginput.inc(); - break; - - case NALPHA: - if (c == '\u0000' || CharacterClasses.isAlpha(c)) { - return false; - } - reginput.inc(); - break; - - case LOWER: - if (!CharacterClasses.isLower(c)) { - return false; - } - reginput.inc(); - break; - - case NLOWER: - if (c == '\u0000' || CharacterClasses.isLower(c)) { - return false; - } - reginput.inc(); - break; - - case UPPER: - if (!CharacterClasses.isUpper(c)) { - return false; - } - reginput.inc(); - break; - - case NUPPER: - if (c == '\u0000' || CharacterClasses.isUpper(c)) { - return false; - } - reginput.inc(); - break; - - case EXACTLY: { - int len; - CharPointer opnd; - - opnd = scan.OPERAND(); - /* Inline the first byte, for speed. */ - if (opnd.charAt() != reginput.charAt() && (!ireg_ic || - Character.toLowerCase(opnd.charAt()) != Character.toLowerCase(reginput.charAt()))) { - return false; - } - if (opnd.charAt(1) == '\u0000') { - reginput.inc(); /* matched a single char */ - } - else { - len = opnd.strlen(); - /* Need to match first byte again for multi-byte. */ - if (cstrncmp(opnd, reginput, len) != 0) { - return false; - } - reginput.inc(len); - } - } - break; - - case ANYOF: - case ANYBUT: - if (c == '\u0000') { - return false; - } - if ((cstrchr(scan.OPERAND(), c) == null) == (op == ANYOF)) { - return false; - } - reginput.inc(); - break; - - - case NOTHING: - break; - - case BACK: - break; - - case MOPEN: /* Match start: \zs */ - case MOPEN + 1: /* \( */ - case MOPEN + 2: - case MOPEN + 3: - case MOPEN + 4: - case MOPEN + 5: - case MOPEN + 6: - case MOPEN + 7: - case MOPEN + 8: - case MOPEN + 9: { - int no; - save_se_T save = new save_se_T(); - - no = op - MOPEN; - cleanup_subexpr(); - save_se(save, reg_startpos[no], reg_startp[no]); - - if (regmatch(next)) { - return true; - } - - restore_se(save, reg_startpos[no], reg_startp[no]); - return false; - } - /* break; Not Reached */ - - case NOPEN: /* \%( */ - case NCLOSE: /* \) after \%( */ - return regmatch(next); - /* break; Not Reached */ - - case ZOPEN + 1: - case ZOPEN + 2: - case ZOPEN + 3: - case ZOPEN + 4: - case ZOPEN + 5: - case ZOPEN + 6: - case ZOPEN + 7: - case ZOPEN + 8: - case ZOPEN + 9: { - int no; - save_se_T save = new save_se_T(); - - no = op - ZOPEN; - cleanup_zsubexpr(); - save_se(save, reg_startzpos[no], reg_startzp[no]); - - if (regmatch(next)) { - return true; - } - - restore_se(save, reg_startzpos[no], reg_startzp[no]); - return false; - } - /* break; Not Reached */ - - case MCLOSE: /* Match end: \ze */ - case MCLOSE + 1: /* \) */ - case MCLOSE + 2: - case MCLOSE + 3: - case MCLOSE + 4: - case MCLOSE + 5: - case MCLOSE + 6: - case MCLOSE + 7: - case MCLOSE + 8: - case MCLOSE + 9: { - int no; - save_se_T save = new save_se_T(); - - no = op - MCLOSE; - cleanup_subexpr(); - save_se(save, reg_endpos[no], reg_endp[no]); - - if (regmatch(next)) { - return true; - } - - restore_se(save, reg_endpos[no], reg_endp[no]); - return false; - } - /* break; Not Reached */ - - case ZCLOSE + 1: /* \) after \z( */ - case ZCLOSE + 2: - case ZCLOSE + 3: - case ZCLOSE + 4: - case ZCLOSE + 5: - case ZCLOSE + 6: - case ZCLOSE + 7: - case ZCLOSE + 8: - case ZCLOSE + 9: { - int no; - save_se_T save = new save_se_T(); - - no = op - ZCLOSE; - cleanup_zsubexpr(); - save_se(save, reg_endzpos[no], reg_endzp[no]); - - if (regmatch(next)) { - return true; - } - - restore_se(save, reg_endzpos[no], reg_endzp[no]); - return false; - } - /* break; Not Reached */ - - case BACKREF + 1: - case BACKREF + 2: - case BACKREF + 3: - case BACKREF + 4: - case BACKREF + 5: - case BACKREF + 6: - case BACKREF + 7: - case BACKREF + 8: - case BACKREF + 9: { - int no; - int len; - int clnum; - int ccol; - CharPointer p; - - no = op - BACKREF; - cleanup_subexpr(); - if (reg_match != null) /* Single-line regexp */ { - if (reg_endp[no] == null) { - /* Backref was not set: Match an empty string. */ - len = 0; - } - else { - /* Compare current input with back-ref in the same - * line. */ - len = reg_endp[no].pointer() - reg_startp[no].pointer(); - if (cstrncmp(reg_startp[no], reginput, len) != 0) { - return false; - } - } - } - else /* Multi-line regexp */ { - if (reg_endpos[no].lnum < 0) { - /* Backref was not set: Match an empty string. */ - len = 0; - } - else { - if (reg_startpos[no].lnum == reglnum - && reg_endpos[no].lnum == reglnum) { - /* Compare back-ref within the current line. */ - len = reg_endpos[no].col - reg_startpos[no].col; - if (cstrncmp(regline.ref(reg_startpos[no].col), reginput, len) != 0) { - return false; - } - } - else { - /* Messy situation: Need to compare between two - * lines. */ - ccol = reg_startpos[no].col; - clnum = reg_startpos[no].lnum; - for (; ; ) { - /* Since getting one line may invalidate - * the other, need to make copy. Slow! */ - if (!regline.equals(reg_tofree)) { - reg_tofree = regline.ref(0); - reginput = reg_tofree.ref(reginput.pointer() - regline.pointer()); - regline = reg_tofree.ref(0); - } - - /* Get the line to compare with. */ - p = reg_getline(clnum); - if (clnum == reg_endpos[no].lnum) { - len = reg_endpos[no].col - ccol; - } - else { - len = p.ref(ccol).strlen(); - } - - if (cstrncmp(p.ref(ccol), reginput, len) != 0) { - return false; /* doesn't match */ - } - if (clnum == reg_endpos[no].lnum) { - break; /* match and at end! */ - } - if (reglnum == reg_maxline) { - return false; /* text too short */ - } - - /* Advance to next line. */ - reg_nextline(); - ++clnum; - ccol = 0; - if (got_int || out_of_stack) { - return false; - } - } - - /* found a match! Note that regline may now point - * to a copy of the line, that should not matter. */ - } - } - } - - /* Matched the backref, skip over it. */ - reginput.inc(len); - } - break; - - case ZREF + 1: - case ZREF + 2: - case ZREF + 3: - case ZREF + 4: - case ZREF + 5: - case ZREF + 6: - case ZREF + 7: - case ZREF + 8: - case ZREF + 9: { - int no; - int len; - - cleanup_zsubexpr(); - no = op - ZREF; - final String match = re_extmatch_in.matches[no]; - if (re_extmatch_in != null && match != null) { - len = match.length(); - if (cstrncmp(new CharPointer(match), reginput, len) != 0) { - return false; - } - reginput.inc(len); - } - else { - /* Backref was not set: Match an empty string. */ - } - } - break; - - case BRANCH: { - if (next.OP() != BRANCH) /* No choice. */ { - next = scan.OPERAND(); /* Avoid recursion. */ - } - else { - regsave_T save = new regsave_T(); - - do { - reg_save(save); - if (regmatch(scan.OPERAND())) { - return true; - } - reg_restore(save); - scan = regnext(scan); - } - while (scan != null && scan.OP() == BRANCH); - - return false; - /* NOTREACHED */ - } - } - break; - - case BRACE_LIMITS: { - int no; - - if (next.OP() == BRACE_SIMPLE) { - bl_minval = scan.OPERAND_MIN(); - bl_maxval = scan.OPERAND_MAX(); - } - else if (next.OP() >= BRACE_COMPLEX - && next.OP() < BRACE_COMPLEX + 10) { - no = next.OP() - BRACE_COMPLEX; - brace_min[no] = scan.OPERAND_MIN(); - brace_max[no] = scan.OPERAND_MAX(); - brace_count[no] = 0; - } - else { - VimPlugin.showMessage(MessageHelper.message(Msg.e_internal)); - return false; - } - } - break; - - case BRACE_COMPLEX: - case BRACE_COMPLEX + 1: - case BRACE_COMPLEX + 2: - case BRACE_COMPLEX + 3: - case BRACE_COMPLEX + 4: - case BRACE_COMPLEX + 5: - case BRACE_COMPLEX + 6: - case BRACE_COMPLEX + 7: - case BRACE_COMPLEX + 8: - case BRACE_COMPLEX + 9: { - int no; - regsave_T save = new regsave_T(); - - no = op - BRACE_COMPLEX; - ++brace_count[no]; - - /* If not matched enough times yet, try one more */ - if (brace_count[no] <= (brace_min[no] <= brace_max[no] - ? brace_min[no] : brace_max[no])) { - reg_save(save); - if (regmatch(scan.OPERAND())) { - return true; - } - reg_restore(save); - --brace_count[no]; /* failed, decrement match count */ - return false; - } - - /* If matched enough times, may try matching some more */ - if (brace_min[no] <= brace_max[no]) { - /* Range is the normal way around, use longest match */ - if (brace_count[no] <= brace_max[no]) { - reg_save(save); - if (regmatch(scan.OPERAND())) { - return true; /* matched some more times */ - } - reg_restore(save); - --brace_count[no]; /* matched just enough times */ - /* continue with the items after \{} */ - } - } - else { - /* Range is backwards, use shortest match first */ - if (brace_count[no] <= brace_min[no]) { - reg_save(save); - if (regmatch(next)) { - return true; - } - reg_restore(save); - next = scan.OPERAND(); - /* must try to match one more item */ - } - } - } - break; - - case BRACE_SIMPLE: - case STAR: - case PLUS: { - char nextb; /* next byte */ - char nextb_ic; /* next byte reverse case */ - int count; - regsave_T save = new regsave_T(); - int minval; - int maxval; - - /* - * Lookahead to avoid useless match attempts when we know - * what character comes next. - */ - if (next.OP() == EXACTLY) { - nextb = next.OPERAND().charAt(); - if (ireg_ic) { - if (Character.isUpperCase(nextb)) { - nextb_ic = Character.toLowerCase(nextb); - } - else { - nextb_ic = Character.toUpperCase(nextb); - } - } - else { - nextb_ic = nextb; - } - } - else { - nextb = '\u0000'; - nextb_ic = '\u0000'; - } - if (op != BRACE_SIMPLE) { - minval = (op == STAR) ? 0 : 1; - maxval = MAX_LIMIT; - } - else { - minval = bl_minval; - maxval = bl_maxval; - } - - /* - * When maxval > minval, try matching as much as possible, up - * to maxval. When maxval < minval, try matching at least the - * minimal number (since the range is backwards, that's also - * maxval!). - */ - count = regrepeat(scan.OPERAND(), maxval); - if (got_int) { - return false; - } - if (minval <= maxval) { - /* Range is the normal way around, use longest match */ - while (count >= minval) { - /* If it could match, try it. */ - if (nextb == '\u0000' || reginput.charAt() == nextb || - reginput.charAt() == nextb_ic) { - reg_save(save); - if (regmatch(next)) { - return true; - } - reg_restore(save); - } - /* Couldn't or didn't match -- back up one char. */ - if (--count < minval) { - break; - } - if (reginput.equals(regline)) { - /* backup to last char of previous line */ - --reglnum; - regline = reg_getline(reglnum); - /* Just in case regrepeat() didn't count right. */ - if (regline == null) { - return false; - } - reginput = regline.ref(regline.strlen()); - // fast_breakcheck(); - TOOD - if (got_int || out_of_stack) { - return false; - } - } - else { - reginput.dec(); - } - } - } - else { - /* Range is backwards, use shortest match first. - * Careful: maxval and minval are exchanged! */ - if (count < maxval) { - return false; - } - for (; ; ) { - /* If it could work, try it. */ - if (nextb == '\u0000' || reginput.charAt() == nextb || - reginput.charAt() == nextb_ic) { - reg_save(save); - if (regmatch(next)) { - return true; - } - reg_restore(save); - } - /* Couldn't or didn't match: try advancing one char. */ - if (count == minval || regrepeat(scan.OPERAND(), 1) == 0) { - break; - } - ++count; - if (got_int || out_of_stack) { - return false; - } - } - } - return false; - } - /* break; Not Reached */ - - case NOMATCH: { - regsave_T save = new regsave_T(); - - /* If the operand matches, we fail. Otherwise backup and - * continue with the next item. */ - reg_save(save); - if (regmatch(scan.OPERAND())) { - return false; - } - reg_restore(save); - } - break; - - case MATCH: - case SUBPAT: { - regsave_T save = new regsave_T(); - - /* If the operand doesn't match, we fail. Otherwise backup - * and continue with the next item. */ - reg_save(save); - if (!regmatch(scan.OPERAND())) { - return false; - } - if (op == MATCH) /* zero-width */ { - reg_restore(save); - } - } - break; - - case BEHIND: - case NOBEHIND: { - regsave_T save_after = new regsave_T(), save_start = new regsave_T(); - regsave_T save_behind_pos; - boolean needmatch = (op == BEHIND); - - /* - * Look back in the input of the operand matches or not. This - * must be done at every position in the input and checking if - * the match ends at the current position. - * First check if the next item matches, that's probably - * faster. - */ - reg_save(save_start); - if (regmatch(next)) { - /* save the position after the found match for next */ - reg_save(save_after); - - /* start looking for a match with operand at the current - * postion. Go back one character until we find the - * result, hitting the start of the line or the previous - * line (for multi-line matching). - * Set behind_pos to where the match should end, BHPOS - * will match it. */ - save_behind_pos = behind_pos == null ? null : new regsave_T(behind_pos); - behind_pos = new regsave_T(save_start); - while (true) { - reg_restore(save_start); - if (regmatch(scan.OPERAND()) && reg_save_equal(behind_pos)) { - behind_pos = save_behind_pos; - /* found a match that ends where "next" started */ - if (needmatch) { - reg_restore(save_after); - return true; - } - return false; - } - /* - * No match: Go back one character. May go to - * previous line once. - */ - if (reg_match == null) { - if (save_start.pos.col == 0) { - if (save_start.pos.lnum < behind_pos.pos.lnum || - reg_getline(--save_start.pos.lnum) == null) { - break; - } - reg_restore(save_start); - save_start.pos.col = regline.strlen(); - } - else { - --save_start.pos.col; - } - } - else { - if (save_start.ptr == regline) { - break; - } - save_start.ptr.dec(); - } - } - - /* NOBEHIND succeeds when no match was found */ - behind_pos = save_behind_pos; - if (!needmatch) { - reg_restore(save_after); - return true; - } - } - return false; - } - - case BHPOS: - if (reg_match == null) { - if (behind_pos.pos.col != reginput.pointer() - regline.pointer() || - behind_pos.pos.lnum != reglnum) { - return false; - } - } - else if (behind_pos.ptr != reginput) { - return false; - } - break; - - case NEWL: - if (c != '\u0000' || reglnum == reg_maxline) { - return false; - } - reg_nextline(); - break; - - case END: - return true; /* Success! */ - - default: - VimPlugin.showMessage(MessageHelper.message(Msg.e_re_corr)); - return false; - } - } - - scan = next; - } - - /* - * We get here only if there's trouble -- normally "case END" is the - * terminating point. - */ - VimPlugin.showMessage(MessageHelper.message(Msg.e_re_corr)); - return false; - } - - /* - * regrepeat - repeatedly match something simple, return how many. - * Advances reginput (and reglnum) to just after the matched chars. - */ - private int regrepeat(@NotNull CharPointer p, int maxcount) { - int count = 0; - CharPointer scan; - CharPointer opnd; - int mask = 0; - int testval = 0; - - scan = reginput.ref(0); /* Make local copy of reginput for speed. */ - opnd = p.OPERAND(); - switch (p.OP()) { - case ANY: - case ANY + ADD_NL: - while (count < maxcount) { - /* Matching anything means we continue until end-of-line (or - * end-of-file for ANY + ADD_NL), only limited by maxcount. */ - while (!scan.isNul() && count < maxcount) { - ++count; - scan.inc(); - } - if (!WITH_NL(p.OP()) || reglnum == reg_maxline || count == maxcount) { - break; - } - ++count; /* count the line-break */ - reg_nextline(); - scan = reginput.ref(0); - if (got_int) { - break; - } - } - break; - - case IDENT: - case IDENT + ADD_NL: - testval = 1; - /*FALLTHROUGH*/ - case SIDENT: - case SIDENT + ADD_NL: - while (count < maxcount) { - if (Character.isJavaIdentifierPart(scan.charAt()) && - (testval == 1 || !Character.isDigit(scan.charAt()))) { - scan.inc(); - } - else if (scan.isNul()) { - if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { - break; - } - reg_nextline(); - scan = reginput.ref(0); - if (got_int) { - break; - } - } - else { - break; - } - ++count; - } - break; - - case KWORD: - case KWORD + ADD_NL: - testval = 1; - /*FALLTHROUGH*/ - case SKWORD: - case SKWORD + ADD_NL: - while (count < maxcount) { - if (CharacterClasses.isWord(scan.charAt()) && (testval == 1 || !Character.isDigit(scan.charAt()))) { - scan.inc(); - } - else if (scan.isNul()) { - if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { - break; - } - reg_nextline(); - scan = reginput.ref(0); - if (got_int) { - break; - } - } - else { - break; - } - ++count; - } - break; - - case FNAME: - case FNAME + ADD_NL: - testval = 1; - /*FALLTHROUGH*/ - case SFNAME: - case SFNAME + ADD_NL: - while (count < maxcount) { - if (CharacterClasses.isFile(scan.charAt()) && (testval == 1 || !Character.isDigit(scan.charAt()))) { - scan.inc(); - } - else if (scan.isNul()) { - if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { - break; - } - reg_nextline(); - scan = reginput.ref(0); - if (got_int) { - break; - } - } - else { - break; - } - ++count; - } - break; - - case PRINT: - case PRINT + ADD_NL: - testval = 1; - /*FALLTHROUGH*/ - case SPRINT: - case SPRINT + ADD_NL: - while (count < maxcount) { - if (scan.isNul()) { - if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { - break; - } - reg_nextline(); - scan = reginput.ref(0); - if (got_int) { - break; - } - } - else if (CharacterClasses.isPrint(scan.charAt()) && - (testval == 1 || !Character.isDigit(scan.charAt()))) { - scan.inc(); - } - else { - break; - } - ++count; - } - break; - - case WHITE: - case WHITE + ADD_NL: - testval = mask = CharacterClasses.RI_WHITE; - break; - case NWHITE: - case NWHITE + ADD_NL: - mask = CharacterClasses.RI_WHITE; - break; - case DIGIT: - case DIGIT + ADD_NL: - testval = mask = CharacterClasses.RI_DIGIT; - break; - case NDIGIT: - case NDIGIT + ADD_NL: - mask = CharacterClasses.RI_DIGIT; - break; - case HEX: - case HEX + ADD_NL: - testval = mask = CharacterClasses.RI_HEX; - break; - case NHEX: - case NHEX + ADD_NL: - mask = CharacterClasses.RI_HEX; - break; - case OCTAL: - case OCTAL + ADD_NL: - testval = mask = CharacterClasses.RI_OCTAL; - break; - case NOCTAL: - case NOCTAL + ADD_NL: - mask = CharacterClasses.RI_OCTAL; - break; - case WORD: - case WORD + ADD_NL: - testval = mask = CharacterClasses.RI_WORD; - break; - case NWORD: - case NWORD + ADD_NL: - mask = CharacterClasses.RI_WORD; - break; - case HEAD: - case HEAD + ADD_NL: - testval = mask = CharacterClasses.RI_HEAD; - break; - case NHEAD: - case NHEAD + ADD_NL: - mask = CharacterClasses.RI_HEAD; - break; - case ALPHA: - case ALPHA + ADD_NL: - testval = mask = CharacterClasses.RI_ALPHA; - break; - case NALPHA: - case NALPHA + ADD_NL: - mask = CharacterClasses.RI_ALPHA; - break; - case LOWER: - case LOWER + ADD_NL: - testval = mask = CharacterClasses.RI_LOWER; - break; - case NLOWER: - case NLOWER + ADD_NL: - mask = CharacterClasses.RI_LOWER; - break; - case UPPER: - case UPPER + ADD_NL: - testval = mask = CharacterClasses.RI_UPPER; - break; - case NUPPER: - case NUPPER + ADD_NL: - mask = CharacterClasses.RI_UPPER; - break; - - case EXACTLY: { - char cu, cl; - - /* This doesn't do a multi-byte character, because a MULTIBYTECODE - * would have been used for it. */ - if (ireg_ic) { - cu = Character.toUpperCase(opnd.charAt()); - cl = Character.toLowerCase(opnd.charAt()); - while (count < maxcount && (scan.charAt() == cu || scan.charAt() == cl)) { - count++; - scan.inc(); - } - } - else { - cu = opnd.charAt(); - while (count < maxcount && scan.charAt() == cu) { - count++; - scan.inc(); - } - } - break; - } - - case ANYOF: - case ANYOF + ADD_NL: - testval = 1; - /*FALLTHROUGH*/ - - case ANYBUT: - case ANYBUT + ADD_NL: - while (count < maxcount) { - if (scan.isNul()) { - if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { - break; - } - reg_nextline(); - scan = reginput.ref(0); - if (got_int) { - break; - } - } - else { - if ((cstrchr(opnd, scan.charAt()) == null) == (testval == 1)) { - break; - } - scan.inc(); - } - ++count; - } - break; - - case NEWL: - while (count < maxcount && scan.isNul() && reglnum < reg_maxline) { - count++; - reg_nextline(); - scan = reginput.ref(0); - if (got_int) { - break; - } - } - break; - - default: /* Oh dear. Called inappropriately. */ - VimPlugin.showMessage(MessageHelper.message(Msg.e_re_corr)); - break; - } - - if (mask != 0) { - while (count < maxcount) { - if (scan.isNul()) { - if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { - break; - } - reg_nextline(); - scan = reginput.ref(0); - if (got_int) { - break; - } - } - else if (CharacterClasses.isMask(scan.charAt(), mask, testval)) { - scan.inc(); - } - else { - break; - } - ++count; - } - } - - reginput = scan.ref(0); - - return count; - } - - /* - * regnext - dig the "next" pointer out of a node - */ - private @Nullable CharPointer regnext(@NotNull CharPointer p) { - int offset; - - offset = p.NEXT(); - if (offset == 0) { - return null; - } - - if (p.OP() == BACK) { - return p.ref(-offset); - } - else { - return p.ref(offset); - } - } - - /* - * Check the regexp program for its magic number. - * Return true if it's wrong. - */ - private boolean prog_magic_wrong() { - if ((reg_match == null ? reg_mmatch.regprog.program : reg_match.regprog.program).charAt(0) != REGMAGIC) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_re_corr)); - return true; - } - return false; - } - - /* - * Cleanup the subexpressions, if this wasn't done yet. - * This construction is used to clear the subexpressions only when they are - * used (to increase speed). - */ - private void cleanup_subexpr() { - if (need_clear_subexpr) { - if (reg_match == null) { - /* Use 0xff to set lnum to -1 */ - for (int i = 0; i < NSUBEXP; i++) { - reg_startpos[i].col = -1; - reg_startpos[i].lnum = -1; - reg_endpos[i].col = -1; - reg_endpos[i].lnum = -1; - } - } - else { - for (int i = 0; i < NSUBEXP; i++) { - reg_startp[i] = null; - reg_endp[i] = null; - } - } - need_clear_subexpr = false; - } - } - - private void cleanup_zsubexpr() { - if (need_clear_zsubexpr) { - if (reg_match == null) { - /* Use 0xff to set lnum to -1 */ - for (int i = 0; i < NSUBEXP; i++) { - reg_startzpos[i].col = -1; - reg_startzpos[i].lnum = -1; - reg_endzpos[i].col = -1; - reg_endzpos[i].lnum = -1; - } - } - else { - for (int i = 0; i < NSUBEXP; i++) { - reg_startzp[i] = null; - reg_endzp[i] = null; - } - } - need_clear_zsubexpr = false; - } - } - - /* - * Advance reglnum, regline and reginput to the next line. - */ - private void reg_nextline() { - regline = reg_getline(++reglnum); - reginput = regline.ref(0); - // fast_breakcheck(); TODO - } - - /* - * Save the input line and position in a regsave_T. - */ - private void reg_save(@NotNull regsave_T save) { - if (reg_match == null) { - save.pos.col = reginput.pointer() - regline.pointer(); - save.pos.lnum = reglnum; - } - else { - save.ptr = reginput.ref(0); - } - } - - /* - * Restore the input line and position from a regsave_T. - */ - private void reg_restore(@NotNull regsave_T save) { - if (reg_match == null) { - if (reglnum != save.pos.lnum) { - /* only call reg_getline() when the line number changed to save - * a bit of time */ - reglnum = save.pos.lnum; - regline = reg_getline(reglnum); - } - reginput = regline.ref(save.pos.col); - } - else { - reginput = save.ptr.ref(0); - } - } - - /* - * Return true if current position is equal to saved position. - */ - private boolean reg_save_equal(@NotNull regsave_T save) { - if (reg_match == null) { - return reglnum == save.pos.lnum && reginput.equals(regline.ref(save.pos.col)); - } - return reginput.equals(save.ptr); - } - - /* - * Tentatively set the sub-expression start to the current position (after - * calling regmatch() they will have changed). Need to save the existing - * values for when there is no match. - * Use pointer or position, depending on reg_match == null. - */ - private void save_se(@NotNull save_se_T savep, @NotNull lpos_T posp, @Nullable CharPointer pp) { - if (reg_match == null) { - savep.pos.lnum = posp.lnum; - savep.pos.col = posp.col; - posp.lnum = reglnum; - posp.col = reginput.pointer() - regline.pointer(); - } - else if (pp != null) { - savep.ptr = pp.ref(0); - pp.assign(reginput); - } - } - - /* - * We were wrong, restore the sub-expressions. - */ - private void restore_se(@NotNull save_se_T savep, @NotNull lpos_T posp, @Nullable CharPointer pp) { - if (reg_match == null) { - posp.col = savep.pos.col; - posp.lnum = savep.pos.lnum; - } - else if (pp != null) { - pp.assign(savep.ptr); - } - } - - /* - * Compare a number with the operand of RE_LNUM, RE_COL or RE_VCOL. - */ - private boolean re_num_cmp(int val, @NotNull CharPointer scan) { - int n = scan.OPERAND_MIN(); - - if (scan.OPERAND_CMP() == '>') { - return val > n; - } - if (scan.OPERAND_CMP() == '<') { - return val < n; - } - return val == n; - } - - /* - * Compare two strings, ignore case if ireg_ic set. - * Return 0 if strings match, non-zero otherwise. - */ - private int cstrncmp(@NotNull CharPointer s1, @NotNull CharPointer s2, int n) { - return s1.strncmp(s2, n, ireg_ic); - } - - /* - * cstrchr: This function is used a lot for simple searches, keep it fast! - */ - private @Nullable CharPointer cstrchr(@NotNull CharPointer s, char c) { - if (!ireg_ic) { - return s.strchr(c); - } - else { - return s.istrchr(c); - } - - /* tolower() and toupper() can be slow, comparing twice should be a lot - * faster (esp. when using MS Visual C++!). - * For UTF-8 need to use folded case. */ - /* was 1,173ms - int cc; - if (CharacterClasses.isUpper(c)) - { - cc = Character.toLowerCase(c); - } - else if (CharacterClasses.isLower(c)) - { - cc = Character.toUpperCase(c); - } - else - { - return s.strchr(c); - } - */ - - /* Faster version for when there are no multi-byte characters. */ - /* - CharPointer p = s.ref(0); - char ch; - while ((ch = p.charAt()) != '\u0000') - { - if (ch == c || ch == cc) - { - return p; - } - - p.inc(); - } - */ - - /* was 2,053ms - for (p = s.ref(0); !p.isNul(); p.inc()) - { - char ch = p.charAt(); - if (ch == c || ch == cc) - { - return p; - } - } - */ - - //return null; - } - - /*************************************************************** - * regsub stuff * - ***************************************************************/ - - /* - * regtilde(): Replace tildes in the pattern by the old pattern. - * - * Short explanation of the tilde: It stands for the previous replacement - * pattern. If that previous pattern also contains a ~ we should go back a - * step further... But we insert the previous pattern into the current one - * and remember that. - * This still does not handle the case where "magic" changes. TODO? - * - * The tildes are parsed once before the first call to vim_regsub(). - */ - //public CharPointer regtilde(CharPointer source, boolean magic) - //{ - // CharPointer newsub = source.ref(0); - // CharPointer tmpsub; - // CharPointer p; - // int len; - // int prevlen; - // - // for (p = newsub.ref(0); !p.isNul(); p.inc()) - // { - // if ((p.charAt() == '~' && magic != 0) || (p.charAt() == '\\' && p.charAt(1) == '~' && magic == 0)) - // { - // if (reg_prev_sub != null) - // { - // /* length = len(newsub) - 1 + len(prev_sub) + 1 */ - // prevlen = reg_prev_sub.strlen(); - // tmpsub = alloc((unsigned)(STRLEN(newsub) + prevlen)); - // if (tmpsub != null) - // { - // /* copy prefix */ - // len = (int)(p - newsub); /* not including ~ */ - // mch_memmove(tmpsub, newsub, (size_t)len); - // /* interpretate tilde */ - // mch_memmove(tmpsub + len, reg_prev_sub, (size_t)prevlen); - // /* copy postfix */ - // if (!magic) - // ++p; /* back off \ */ - // STRCPY(tmpsub + len + prevlen, p + 1); - // - // if (newsub != source) /* already allocated newsub */ - // vim_free(newsub); - // newsub = tmpsub; - // p = newsub + len + prevlen; - // } - // } - // else if (magic) - // STRCPY(p, p + 1); /* remove '~' */ - // else - // STRCPY(p, p + 2); /* remove '\~' */ - // --p; - // } - // else if (*p == '\\' && p[1]) /* skip escaped characters */ - // ++p; - // } - // - // vim_free(reg_prev_sub); - // if (newsub != source) /* newsub was allocated, just keep it */ - // reg_prev_sub = newsub; - // else /* no ~ found, need to save newsub */ - // reg_prev_sub = vim_strsave(newsub); - // return newsub; - //} - - /** - * vim_regsub() - perform substitutions after a vim_regexec() or - * vim_regexec_multi() match. - *

- * If "copy" is true really copy into "dest". - * If "copy" is false nothing is copied, this is just to find out the length - * of the result. - *

- * If "backslash" is true, a backslash will be removed later, need to double - * them to keep them, and insert a backslash before a CR to avoid it being - * replaced with a line break later. - *

- * Note: The matched text must not change between the call of - * vim_regexec()/vim_regexec_multi() and vim_regsub()! It would make the back - * references invalid! - *

- * Returns the size of the replacement, including terminating '\u0000'. - */ - public @Nullable String vim_regsub(regmatch_T rmp, CharPointer source, int magic, boolean backslash) { - reg_match = rmp; - reg_mmatch = null; - reg_maxline = 0; - - return vim_regsub_both(source, magic, backslash); - } - - public @Nullable String vim_regsub_multi(regmmatch_T rmp, int lnum, CharPointer source, int magic, boolean backslash) { - reg_match = null; - reg_mmatch = rmp; - //reg_buf = curbuf; /* always works on the current buffer! */ - reg_firstlnum = lnum; - reg_maxline = EditorHelper.getLineCount(reg_buf) - lnum; - - return vim_regsub_both(source, magic, backslash); - } - - private int subappend(int mode, @NotNull StringBuffer dst, char c) { - switch (mode) { - case 'u': - mode = 0; - // Fall through - case 'U': - dst.append(Character.toUpperCase(c)); - break; - case 'l': - mode = 0; - // Fall through - case 'L': - dst.append(Character.toLowerCase(c)); - break; - default: - dst.append(c); - break; - } - - return mode; - } - - private @Nullable String vim_regsub_both(@Nullable CharPointer source, int magic, boolean backslash) { - CharPointer src; - StringBuffer dst = new StringBuffer(); - CharPointer s; - char c; - int no = -1; - int clnum = 0; /* init for GCC */ - int len = 0; /* init for GCC */ - //CharPointer eval_result = null; - int mode = 0; - - /* Be paranoid... */ - if (source == null) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_null)); - return null; - } - if (prog_magic_wrong()) { - return null; - } - src = source.ref(0); - - /* - * When the substitute part starts with "\=" evaluate it as an expression. - */ - if (source.charAt(0) == '\\' && source.charAt(1) == '=') { - } - else { - while ((c = src.charAt()) != '\u0000') { - src.inc(); - if (c == '&' && magic != 0) { - no = 0; - } - else if (c == '\\' && !src.isNul()) { - if (src.charAt() == '&' && magic == 0) { - src.inc(); - no = 0; - } - else if ('0' <= src.charAt() && src.charAt() <= '9') { - no = src.charAt() - '0'; - src.inc(); - } - else if ("uUlLeE".indexOf(src.charAt()) != -1) { - switch (src.charAtInc()) { - case 'u': - mode = 'u'; - continue; - case 'U': - mode = 'U'; - continue; - case 'l': - mode = 'l'; - continue; - case 'L': - mode = 'L'; - continue; - case 'e': - case 'E': - mode = 0; - continue; - } - } - } - if (no < 0) /* Ordinary character. */ { - if (c == '\\' && !src.isNul()) { - /* Check for abbreviations -- webb */ - // In vim '\u0000' is represented in memory as '\n', and '\n' as '\r', see :help NL-used-for-Nul - switch (src.charAt()) { - case 'r': - c = '\n'; - src.inc(); - break; - case 'n': - c = '\u0000'; - src.inc(); - break; - case 't': - c = '\t'; - src.inc(); - break; - /* Oh no! \e already has meaning in subst pat :-( */ - /* case 'e': c = ESC; ++src; break; */ - case 'b': - c = '\b'; - src.inc(); - break; - - /* If "backslash" is true the backslash will be removed - * later. Used to insert a literal CR. */ - default: - if (backslash) { - dst.append('\\'); - } - c = src.charAt(); - src.inc(); - } - } - - /* Write to buffer, if copy is set. */ - mode = subappend(mode, dst, c); - } - else { - if (reg_match == null) { - clnum = reg_mmatch.startpos[no].lnum; - if (clnum < 0 || reg_mmatch.endpos[no].lnum < 0) { - s = null; - } - else { - s = reg_getline(clnum).ref(reg_mmatch.startpos[no].col); - if (reg_mmatch.endpos[no].lnum == clnum) { - len = reg_mmatch.endpos[no].col - reg_mmatch.startpos[no].col; - } - else { - len = s.strlen(); - } - } - } - else { - s = reg_match.startp[no]; - if (reg_match.endp[no] == null) { - s = null; - } - else { - len = reg_match.endp[no].pointer() - s.pointer(); - } - } - if (s != null) { - for (; ; ) { - if (len == 0) { - if (reg_match == null) { - if (reg_mmatch.endpos[no].lnum == clnum) { - break; - } - dst.append('\r'); - s = reg_getline(++clnum); - if (reg_mmatch.endpos[no].lnum == clnum) { - len = reg_mmatch.endpos[no].col; - } - else { - len = s.strlen(); - } - } - else { - break; - } - } - else if (s.isNul()) /* we hit '\u0000'. */ { - VimPlugin.showMessage(MessageHelper.message(Msg.e_re_damg)); - - return dst.toString(); - } - else { - if (backslash && (s.charAt() == '\r' || s.charAt() == '\\')) { - /* - * Insert a backslash in front of a CR, otherwise - * it will be replaced by a line break. - * Number of backslashes will be halved later, - * double them here. - */ - dst.append('\\'); - dst.append(s.charAt()); - } - else { - mode = subappend(mode, dst, s.charAt()); - } - s.inc(); - --len; - } - } - } - no = -1; - } - } - } - - return dst.toString(); - } - - /* - * Used for the submatch() function: get the string from tne n'th submatch in - * allocated memory. - * Returns null when not in a ":s" command and for a non-existing submatch. - */ - /* - public String reg_submatch(int no) - { - StringBuffer retval = null; - CharPointer s; - int len; - int round; - int lnum; - - if (!can_f_submatch) - return null; - - if (submatch_match == null) - { - // First round: compute the length and allocate memory. - // Second round: copy the text. - for (round = 1; round <= 2; ++round) - { - lnum = submatch_mmatch.startpos[no].lnum; - if (lnum < 0 || submatch_mmatch.endpos[no].lnum < 0) - { - return null; - } - - s = reg_getline(lnum).ref(submatch_mmatch.startpos[no].col); - if (s == null) // anti-crash check, cannot happen? - { - break; - } - if (submatch_mmatch.endpos[no].lnum == lnum) - { - // Within one line: take form start to end col. - len = submatch_mmatch.endpos[no].col - submatch_mmatch.startpos[no].col; - if (round == 2) - { - retval.append(s.substring(len)); - } - ++len; - } - else - { - // Multiple lines: take start line from start col, middle - // lines completely and end line up to end col. - len = s.strlen(); - if (round == 2) - { - retval.append(s.substring(len)); - } - ++len; - ++lnum; - while (lnum < submatch_mmatch.endpos[no].lnum) - { - s = reg_getline(lnum++); - if (round == 2) - { - retval.append(s.substring(s.strlen())); - } - len += s.strlen(); - if (round == 2) - { - retval.append('\n'); - } - ++len; - } - if (round == 2) - { - retval.append(reg_getline(lnum).substring(submatch_mmatch.endpos[no].col)); - } - len += submatch_mmatch.endpos[no].col; - if (round == 2) - { - //retval[len] = '\u0000'; - } - ++len; - } - - if (round == 1) - { - retval = new StringBuffer(); - if (s == null) - return null; - } - } - } - else - { - if (submatch_match.endp[no] == null) - { - retval = null; - } - else - { - s = submatch_match.startp[no]; - retval = new StringBuffer(s.substring(submatch_match.endp[no].pointer() - s.pointer())); - } - } - - return retval == null ? null : retval.toString(); - } - */ - - /* - * regdump - dump a regexp onto stdout in vaguely comprehensible form - */ - private @NotNull String regdump(String pattern, @NotNull regprog_T r) { - CharPointer start; - CharPointer s; - int op = EXACTLY; /* Arbitrary non-END op. */ - CharPointer next; - CharPointer end = null; - StringBuilder res = new StringBuilder(); - - res.append("\nregcomp(").append(pattern).append("):\n"); - - start = (new CharPointer(r.program)); - s = start.ref(1); - /* - * Loop until we find the END that isn't before a referred next (an END - * can also appear in a NOMATCH operand). - */ - while (op != END || !s.end()) { - op = s.OP(); - res.append(s.pointer() - start.pointer()); - res.append(regprop(s)); - next = regnext(s); - if (next == null) /* Next ptr. */ { - res.append("(0)"); - } - else { - res.append("(").append(s.pointer() - start.pointer() + (next.pointer() - s.pointer())).append(")"); - } - if (end == null || (next != null && end.pointer() < next.pointer())) { - end = next; - } - if (op == BRACE_LIMITS) { - /* Two short ints */ - res.append(" minval "); - res.append(s.OPERAND_MIN()); - res.append(", maxval "); - res.append(s.OPERAND_MAX()); - s.inc(8); - } - s.inc(3); - if (op == ANYOF || op == ANYOF + ADD_NL - || op == ANYBUT || op == ANYBUT + ADD_NL - || op == EXACTLY) { - /* Literal string, where present. */ - while (!s.isNul()) { - res.append(s.charAt()); - s.inc(); - } - s.inc(); - } - res.append("\n"); - } - - /* Header fields of interest. */ - if (r.regstart != '\u0000') { - res.append("start `"); - if (r.regstart < ' ') { - res.append("^").append((char)('@' + r.regstart)); - } - else { - res.append(r.regstart); - } - res.append("' "); - res.append(Integer.toString(r.regstart, 16)); - } - if (r.reganch != 0) { - res.append("anchored: "); - } - if (r.regmust != null) { - res.append("must have \"").append(r.regmust.substring(r.regmust.strlen())).append("\""); - } - res.append("\n"); - - return res.toString(); - } - - /* -* regprop - printable representation of opcode -*/ - private @NotNull @NonNls String regprop(@NotNull CharPointer op) { - @NonNls String p; - StringBuilder buf = new StringBuilder(); - - buf.append(':'); - - switch (op.OP()) { - case BOL: - p = "BOL"; - break; - case EOL: - p = "EOL"; - break; - case RE_BOF: - p = "BOF"; - break; - case RE_EOF: - p = "EOF"; - break; - case CURSOR: - p = "CURSOR"; - break; - case RE_LNUM: - p = "RE_LNUM"; - break; - case RE_COL: - p = "RE_COL"; - break; - case RE_VCOL: - p = "RE_VCOL"; - break; - case BOW: - p = "BOW"; - break; - case EOW: - p = "EOW"; - break; - case ANY: - p = "ANY"; - break; - case ANY + ADD_NL: - p = "ANY+NL"; - break; - case ANYOF: - p = "ANYOF"; - break; - case ANYOF + ADD_NL: - p = "ANYOF+NL"; - break; - case ANYBUT: - p = "ANYBUT"; - break; - case ANYBUT + ADD_NL: - p = "ANYBUT+NL"; - break; - case IDENT: - p = "IDENT"; - break; - case IDENT + ADD_NL: - p = "IDENT+NL"; - break; - case SIDENT: - p = "SIDENT"; - break; - case SIDENT + ADD_NL: - p = "SIDENT+NL"; - break; - case KWORD: - p = "KWORD"; - break; - case KWORD + ADD_NL: - p = "KWORD+NL"; - break; - case SKWORD: - p = "SKWORD"; - break; - case SKWORD + ADD_NL: - p = "SKWORD+NL"; - break; - case FNAME: - p = "FNAME"; - break; - case FNAME + ADD_NL: - p = "FNAME+NL"; - break; - case SFNAME: - p = "SFNAME"; - break; - case SFNAME + ADD_NL: - p = "SFNAME+NL"; - break; - case PRINT: - p = "PRINT"; - break; - case PRINT + ADD_NL: - p = "PRINT+NL"; - break; - case SPRINT: - p = "SPRINT"; - break; - case SPRINT + ADD_NL: - p = "SPRINT+NL"; - break; - case WHITE: - p = "WHITE"; - break; - case WHITE + ADD_NL: - p = "WHITE+NL"; - break; - case NWHITE: - p = "NWHITE"; - break; - case NWHITE + ADD_NL: - p = "NWHITE+NL"; - break; - case DIGIT: - p = "DIGIT"; - break; - case DIGIT + ADD_NL: - p = "DIGIT+NL"; - break; - case NDIGIT: - p = "NDIGIT"; - break; - case NDIGIT + ADD_NL: - p = "NDIGIT+NL"; - break; - case HEX: - p = "HEX"; - break; - case HEX + ADD_NL: - p = "HEX+NL"; - break; - case NHEX: - p = "NHEX"; - break; - case NHEX + ADD_NL: - p = "NHEX+NL"; - break; - case OCTAL: - p = "OCTAL"; - break; - case OCTAL + ADD_NL: - p = "OCTAL+NL"; - break; - case NOCTAL: - p = "NOCTAL"; - break; - case NOCTAL + ADD_NL: - p = "NOCTAL+NL"; - break; - case WORD: - p = "WORD"; - break; - case WORD + ADD_NL: - p = "WORD+NL"; - break; - case NWORD: - p = "NWORD"; - break; - case NWORD + ADD_NL: - p = "NWORD+NL"; - break; - case HEAD: - p = "HEAD"; - break; - case HEAD + ADD_NL: - p = "HEAD+NL"; - break; - case NHEAD: - p = "NHEAD"; - break; - case NHEAD + ADD_NL: - p = "NHEAD+NL"; - break; - case ALPHA: - p = "ALPHA"; - break; - case ALPHA + ADD_NL: - p = "ALPHA+NL"; - break; - case NALPHA: - p = "NALPHA"; - break; - case NALPHA + ADD_NL: - p = "NALPHA+NL"; - break; - case LOWER: - p = "LOWER"; - break; - case LOWER + ADD_NL: - p = "LOWER+NL"; - break; - case NLOWER: - p = "NLOWER"; - break; - case NLOWER + ADD_NL: - p = "NLOWER+NL"; - break; - case UPPER: - p = "UPPER"; - break; - case UPPER + ADD_NL: - p = "UPPER+NL"; - break; - case NUPPER: - p = "NUPPER"; - break; - case NUPPER + ADD_NL: - p = "NUPPER+NL"; - break; - case BRANCH: - p = "BRANCH"; - break; - case EXACTLY: - p = "EXACTLY"; - break; - case NOTHING: - p = "NOTHING"; - break; - case BACK: - p = "BACK"; - break; - case END: - p = "END"; - break; - case MOPEN: - p = "MATCH START"; - break; - case MOPEN + 1: - case MOPEN + 2: - case MOPEN + 3: - case MOPEN + 4: - case MOPEN + 5: - case MOPEN + 6: - case MOPEN + 7: - case MOPEN + 8: - case MOPEN + 9: - buf.append("MOPEN").append(op.OP() - MOPEN); - p = null; - break; - case MCLOSE: - p = "MATCH END"; - break; - case MCLOSE + 1: - case MCLOSE + 2: - case MCLOSE + 3: - case MCLOSE + 4: - case MCLOSE + 5: - case MCLOSE + 6: - case MCLOSE + 7: - case MCLOSE + 8: - case MCLOSE + 9: - buf.append("MCLOSE").append(op.OP() - MCLOSE); - p = null; - break; - case BACKREF + 1: - case BACKREF + 2: - case BACKREF + 3: - case BACKREF + 4: - case BACKREF + 5: - case BACKREF + 6: - case BACKREF + 7: - case BACKREF + 8: - case BACKREF + 9: - buf.append("BACKREF").append(op.OP() - BACKREF); - p = null; - break; - case NOPEN: - p = "NOPEN"; - break; - case NCLOSE: - p = "NCLOSE"; - break; - case ZOPEN + 1: - case ZOPEN + 2: - case ZOPEN + 3: - case ZOPEN + 4: - case ZOPEN + 5: - case ZOPEN + 6: - case ZOPEN + 7: - case ZOPEN + 8: - case ZOPEN + 9: - buf.append("ZOPEN").append(op.OP() - ZOPEN); - p = null; - break; - case ZCLOSE + 1: - case ZCLOSE + 2: - case ZCLOSE + 3: - case ZCLOSE + 4: - case ZCLOSE + 5: - case ZCLOSE + 6: - case ZCLOSE + 7: - case ZCLOSE + 8: - case ZCLOSE + 9: - buf.append("ZCLOSE").append(op.OP() - ZCLOSE); - p = null; - break; - case ZREF + 1: - case ZREF + 2: - case ZREF + 3: - case ZREF + 4: - case ZREF + 5: - case ZREF + 6: - case ZREF + 7: - case ZREF + 8: - case ZREF + 9: - buf.append("ZREF").append(op.OP() - ZREF); - p = null; - break; - case STAR: - p = "STAR"; - break; - case PLUS: - p = "PLUS"; - break; - case NOMATCH: - p = "NOMATCH"; - break; - case MATCH: - p = "MATCH"; - break; - case BEHIND: - p = "BEHIND"; - break; - case NOBEHIND: - p = "NOBEHIND"; - break; - case SUBPAT: - p = "SUBPAT"; - break; - case BRACE_LIMITS: - p = "BRACE_LIMITS"; - break; - case BRACE_SIMPLE: - p = "BRACE_SIMPLE"; - break; - case BRACE_COMPLEX: - case BRACE_COMPLEX + 1: - case BRACE_COMPLEX + 2: - case BRACE_COMPLEX + 3: - case BRACE_COMPLEX + 4: - case BRACE_COMPLEX + 5: - case BRACE_COMPLEX + 6: - case BRACE_COMPLEX + 7: - case BRACE_COMPLEX + 8: - case BRACE_COMPLEX + 9: - buf.append("BRACE_COMPLEX").append(op.OP() - BRACE_COMPLEX); - p = null; - break; - case NEWL: - p = "NEWL"; - break; - default: - buf.append("corrupt ").append(op.OP()); - p = null; - break; - } - if (p != null) { - buf.append(p); - } - - return buf.toString(); - } - - public static class regprog_T { - char regstart; - char reganch; - @Nullable CharPointer regmust; - int regmlen; - int regflags; - char reghasz; - @NotNull StringBuffer program = new StringBuffer(); - } - - private static class MinMax { - int minvalue; - int maxvalue; - } - - public static class lpos_T { - public lpos_T(@NotNull lpos_T pos) { - this.lnum = pos.lnum; - this.col = pos.col; - } - - public lpos_T() { - } - - public int lnum = 0; - public int col = 0; - - @Override - public String toString() { - return "lpos: (" + lnum + ", " + col + ")"; - } - } - - /* - * Structure used to save the current input state, when it needs to be - * restored after trying a match. Used by reg_save() and reg_restore(). - */ - private static class regsave_T { - CharPointer ptr; /* reginput pointer, for single-line regexp */ - @NotNull lpos_T pos = new lpos_T(); /* reginput pos, for multi-line regexp */ - - public regsave_T() { - } - - public regsave_T(regsave_T rhs) { - ptr = rhs.ptr == null ? null : new CharPointer("").assign(rhs.ptr); - pos = new lpos_T(rhs.pos); - } - } - - /* struct to save start/end pointer/position in for \(\) */ - private static class save_se_T { - CharPointer ptr; - @NotNull lpos_T pos = new lpos_T(); - } - - private static class regmatch_T { - regprog_T regprog; - @NotNull CharPointer[] startp = new CharPointer[NSUBEXP]; - @NotNull CharPointer[] endp = new CharPointer[NSUBEXP]; - boolean rm_ic; - } - - public static class regmmatch_T { - public regmmatch_T() { - for (int i = 0; i < NSUBEXP; i++) { - startpos[i] = new lpos_T(); - endpos[i] = new lpos_T(); - } - } - - public @Nullable regprog_T regprog; - public @NotNull lpos_T[] startpos = new lpos_T[NSUBEXP]; - public @NotNull lpos_T[] endpos = new lpos_T[NSUBEXP]; - public boolean rmm_ic; - } - - private int reg_do_extmatch = 0; - - private @Nullable CharPointer reg_prev_sub = null; - - private CharPointer regparse; /* Input-scan pointer. */ - private int prevchr_len; /* byte length of previous char */ - private int num_complex_braces; /* Complex \{...} count */ - private int regnpar; /* () count. */ - private int regnzpar; /* \z() count. */ - private char re_has_z; /* \z item detected */ - private CharPointer regcode; /* Code-emit pointer */ - private boolean[] had_endbrace = new boolean[NSUBEXP]; /* flags, true if end of () found */ - private int regflags; /* RF_ flags for prog */ - private int[] brace_min = new int[10]; /* Minimums for complex brace repeats */ - private int[] brace_max = new int[10]; /* Maximums for complex brace repeats */ - private int[] brace_count = new int[10]; /* Current counts for complex brace repeats */ - private boolean had_eol; /* true when EOL found by vim_regcomp() */ - private boolean one_exactly = false; /* only do one char for EXACTLY */ - - private int reg_magic; /* magicness of the pattern: */ - - private int curchr; - - /* - * getchr() - get the next character from the pattern. We know about - * magic and such, so therefore we need a lexical analyzer. - */ - - /* static int curchr; */ - private int prevprevchr; - private int prevchr; - private int nextchr; /* used for ungetchr() */ - /* - * Note: prevchr is sometimes -1 when we are not at the start, - * eg in /[ ^I]^ the pattern was never found even if it existed, because ^ was - * taken to be magic -- webb - */ - private boolean at_start; /* True when on the first character */ - private boolean prev_at_start; /* True when on the second character */ - - /* - * Global work variables for vim_regexec(). - */ - - /* The current match-position is remembered with these variables: */ - private int reglnum; /* line number, relative to first line */ - private @Nullable CharPointer regline; /* start of current line */ - private CharPointer reginput; /* current input, points into "regline" */ - - private boolean need_clear_subexpr; /* subexpressions still need to be - * cleared */ - private boolean need_clear_zsubexpr = false; /* extmatch subexpressions - * still need to be cleared */ - - private boolean out_of_stack; /* true when ran out of stack space */ - - /* - * Internal copy of 'ignorecase'. It is set at each call to vim_regexec(). - * Normally it gets the value of "rm_ic" or "rmm_ic", but when the pattern - * contains '\c' or '\C' the value is overruled. - */ - private boolean ireg_ic; - - /* - * Sometimes need to save a copy of a line. Since alloc()/free() is very - * slow, we keep one allocated piece of memory and only re-allocate it when - * it's too small. It's freed in vim_regexec_both() when finished. - */ - private @Nullable CharPointer reg_tofree; - //private int reg_tofreelen; - - /* - * These variables are set when executing a regexp to speed up the execution. - * Which ones are set depends on whethere a single-line or multi-line match is - * done: - * single-line multi-line - * reg_match ®match_T null - * reg_mmatch null ®mmatch_T - * reg_startp reg_match->startp - * reg_endp reg_match->endp - * reg_startpos reg_mmatch->startpos - * reg_endpos reg_mmatch->endpos - * reg_win null window in which to search - * reg_buf buffer in which to search - * reg_firstlnum first line in which to search - * reg_maxline 0 last line nr - */ - private @Nullable regmatch_T reg_match; - private @Nullable regmmatch_T reg_mmatch; - private @NotNull CharPointer[] reg_startp = new CharPointer[NSUBEXP]; - private @NotNull CharPointer[] reg_endp = new CharPointer[NSUBEXP]; - private @NotNull lpos_T[] reg_startpos = new lpos_T[NSUBEXP]; - private @NotNull lpos_T[] reg_endpos = new lpos_T[NSUBEXP]; - //static win_T *reg_win; - private Editor reg_buf; - private int reg_firstlnum; - private int reg_maxline; - - private regsave_T behind_pos; - - private @NotNull CharPointer[] reg_startzp = new CharPointer[NSUBEXP]; /* Workspace to mark beginning */ - private @NotNull CharPointer[] reg_endzp = new CharPointer[NSUBEXP]; /* and end of \z(...\) matches */ - private @NotNull lpos_T[] reg_startzpos = new lpos_T[NSUBEXP]; /* idem, beginning pos */ - private @NotNull lpos_T[] reg_endzpos = new lpos_T[NSUBEXP]; /* idem, end pos */ - - private boolean got_int = false; - - /* - * The arguments from BRACE_LIMITS are stored here. They are actually local - * to regmatch(), but they are here to reduce the amount of stack space used - * (it can be called recursively many times). - */ - private int bl_minval; - private int bl_maxval; - - //private boolean can_f_submatch = false; /* true when submatch() can be used */ - - /* These pointers are used instead of reg_match and reg_mmatch for - * reg_submatch(). Needed for when the substitution string is an expression - * that contains a call to substitute() and submatch(). */ - //private regmatch_T submatch_match; - //private regmmatch_T submatch_mmatch; - - private static Logger logger = Logger.getInstance(RegExp.class.getName()); -} diff --git a/src/main/java/com/maddyhome/idea/vim/ui/ReloadVimRc.kt b/src/main/java/com/maddyhome/idea/vim/ui/ReloadVimRc.kt index 61e1cb9873d..0d241b220f5 100644 --- a/src/main/java/com/maddyhome/idea/vim/ui/ReloadVimRc.kt +++ b/src/main/java/com/maddyhome/idea/vim/ui/ReloadVimRc.kt @@ -30,6 +30,7 @@ import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.io.FileUtil +import com.maddyhome.idea.vim.api.VimrcFileState import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.icons.VimIcons import com.maddyhome.idea.vim.ui.ReloadFloatingToolbarActionGroup.Companion.ACTION_GROUP @@ -49,14 +50,14 @@ import org.jetbrains.annotations.TestOnly * - Action / action group */ -object VimRcFileState { +object VimRcFileState : VimrcFileState { // Hash of .ideavimrc parsed to Script class private var state: Int? = null // ModificationStamp. Can be taken only from document. Doesn't play a big role, but can help speed up [equalTo] private var modificationStamp = 0L - var filePath: String? = null + override var filePath: String? = null private val saveStateListeners = ArrayList<() -> Unit>() @@ -67,7 +68,7 @@ object VimRcFileState { saveStateListeners.forEach { it() } } - fun saveFileState(filePath: String) { + override fun saveFileState(filePath: String) { val vimRcFile = VimRcService.findIdeaVimRc() val ideaVimRcText = vimRcFile?.readText() ?: "" saveFileState(filePath, ideaVimRcText) diff --git a/src/main/java/com/maddyhome/idea/vim/ui/ex/ExEntryPanel.java b/src/main/java/com/maddyhome/idea/vim/ui/ex/ExEntryPanel.java index 3e89da91b39..5ecae861244 100644 --- a/src/main/java/com/maddyhome/idea/vim/ui/ex/ExEntryPanel.java +++ b/src/main/java/com/maddyhome/idea/vim/ui/ex/ExEntryPanel.java @@ -33,6 +33,7 @@ import com.maddyhome.idea.vim.group.MotionGroup; import com.maddyhome.idea.vim.helper.SearchHighlightsHelper; import com.maddyhome.idea.vim.helper.UiHelper; +import com.maddyhome.idea.vim.newapi.IjVimEditor; import com.maddyhome.idea.vim.regexp.CharPointer; import com.maddyhome.idea.vim.regexp.RegExp; import com.maddyhome.idea.vim.ui.ExPanelBorder; @@ -288,7 +289,7 @@ protected void textChanged(@NotNull DocumentEvent e) { VimPlugin.getSearch().resetIncsearchHighlights(); return; } - searchRange = command.getLineRange(editor); + searchRange = command.getLineRange(new IjVimEditor(editor)); } final String labelText = label.getText(); diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/Executor.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/Executor.kt index e272dfc8e7a..26e5bca092d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/Executor.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/Executor.kt @@ -20,12 +20,16 @@ package com.maddyhome.idea.vim.vimscript import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.diagnostic.logger -import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.textarea.TextComponentEditorImpl import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.VimScriptExecutorBase +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.FinishException import com.maddyhome.idea.vim.history.HistoryConstants +import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.register.RegisterConstants.LAST_COMMAND_REGISTER import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -37,12 +41,12 @@ import java.io.File import java.io.IOException import javax.swing.JTextArea -object Executor { +object Executor : VimScriptExecutorBase() { private val logger = logger() - var executingVimScript = false + override var executingVimscript = false @Throws(ExException::class) - fun execute(scriptString: String, editor: Editor, context: DataContext, skipHistory: Boolean, indicateErrors: Boolean = true, vimContext: VimLContext? = null): ExecutionResult { + override fun execute(scriptString: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean, vimContext: VimLContext?): ExecutionResult { var finalResult: ExecutionResult = ExecutionResult.Success val script = VimscriptParser.parse(scriptString) @@ -76,6 +80,9 @@ object Executor { } catch (e: Exception) { logger.warn("Caught: ${e.message}") logger.warn(e.stackTrace.toString()) + if (injector.application.isUnitTest()) { + throw e + } } } @@ -88,23 +95,22 @@ object Executor { return finalResult } - fun execute(scriptString: String, skipHistory: Boolean = true) { - val editor = TextComponentEditorImpl(null, JTextArea()) - val context = DataContext.EMPTY_CONTEXT + override fun execute(scriptString: String, skipHistory: Boolean) { + val editor = TextComponentEditorImpl(null, JTextArea()).vim + val context = DataContext.EMPTY_CONTEXT.vim execute(scriptString, editor, context, skipHistory, indicateErrors = true, CommandLineVimLContext) } - @JvmStatic - fun executeFile(file: File, indicateErrors: Boolean = false) { - val editor = TextComponentEditorImpl(null, JTextArea()) - val context = DataContext.EMPTY_CONTEXT + override fun executeFile(file: File, indicateErrors: Boolean) { + val editor = TextComponentEditorImpl(null, JTextArea()).vim + val context = DataContext.EMPTY_CONTEXT.vim try { execute(file.readText(), editor, context, skipHistory = true, indicateErrors) } catch (ignored: IOException) { } } @Throws(ExException::class) - fun executeLastCommand(editor: Editor, context: DataContext): Boolean { + override fun executeLastCommand(editor: VimEditor, context: ExecutionContext): Boolean { val reg = VimPlugin.getRegister().getRegister(':') ?: return false val text = reg.text ?: return false execute(text, editor, context, skipHistory = false, indicateErrors = true, CommandLineVimLContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ActionCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ActionCommand.kt index 3a290d1b989..d4c96fad5f3 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ActionCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ActionCommand.kt @@ -20,9 +20,9 @@ package com.maddyhome.idea.vim.vimscript.model.commands import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.AnAction -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges @@ -38,7 +38,7 @@ data class ActionCommand(val ranges: Ranges, val argument: String) : Command.Sin override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY, Flag.SAVE_VISUAL) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val actionName = argument.trim() val action = ActionManager.getInstance().getAction(actionName) ?: throw ExException(MessageHelper.message("action.not.found.0", actionName)) val application = ApplicationManager.getApplication() @@ -50,7 +50,7 @@ data class ActionCommand(val ranges: Ranges, val argument: String) : Command.Sin return ExecutionResult.Success } - private fun executeAction(action: AnAction, context: DataContext) { - injector.actionExecutor.executeAction(action.vim, context.vim) + private fun executeAction(action: AnAction, context: ExecutionContext) { + injector.actionExecutor.executeAction(action.vim, context) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ActionListCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ActionListCommand.kt index 851844aa517..8300c3d9686 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ActionListCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ActionListCommand.kt @@ -19,13 +19,14 @@ package com.maddyhome.idea.vim.vimscript.model.commands import com.intellij.openapi.actionSystem.ActionManager -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.KeyboardShortcut -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.StringHelper +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import java.util.* @@ -35,7 +36,7 @@ import java.util.* data class ActionListCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val lineSeparator = "\n" val searchPattern = argument.trim().lowercase(Locale.getDefault()).split("*") val actionManager = ActionManager.getInstance() @@ -51,7 +52,7 @@ data class ActionListCommand(val ranges: Ranges, val argument: String) : Command .filter { line -> searchPattern.all { it in line.lowercase(Locale.getDefault()) } } .joinToString(lineSeparator) - ExOutputModel.getInstance(editor).output(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions)) + ExOutputModel.getInstance(editor.ij).output(MessageHelper.message("ex.show.all.actions.0.1", lineSeparator, actions)) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/AsciiCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/AsciiCommand.kt index de38d2af926..6fcd123ee04 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/AsciiCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/AsciiCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,8 +31,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class AsciiCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getDigraph().displayAsciiInfo(editor) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getDigraph().displayAsciiInfo(editor.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferCloseCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferCloseCommand.kt index d526759f313..a4781ec20f8 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferCloseCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferCloseCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,13 +31,13 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class BufferCloseCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val arg = argument.trim() val bufNum = arg.toIntOrNull() if (bufNum != null) { - VimPlugin.getFile().closeFile(bufNum - 1, context) + VimPlugin.getFile().closeFile(bufNum - 1, context.ij) } else { - VimPlugin.getFile().closeFile(editor, context) + VimPlugin.getFile().closeFile(editor.ij, context.ij) } return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferCommand.kt index 8e9395df2a5..fe83bf8502a 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferCommand.kt @@ -18,14 +18,16 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.PlatformDataKeys -import com.intellij.openapi.editor.Editor import com.intellij.openapi.fileEditor.FileEditorManager import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.MessageHelper +import com.maddyhome.idea.vim.newapi.ij +import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -36,7 +38,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class BufferCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val arg = argument.trim() val overrideModified = arg.startsWith('!') val buffer = if (overrideModified) arg.replace(Regex("^!\\s*"), "") else arg @@ -46,12 +48,12 @@ data class BufferCommand(val ranges: Ranges, val argument: String) : Command.Sin if (buffer.matches(Regex("^\\d+$"))) { val bufNum = buffer.toInt() - 1 - if (!VimPlugin.getFile().selectFile(bufNum, context)) { + if (!VimPlugin.getFile().selectFile(bufNum, context.ij)) { VimPlugin.showMessage(MessageHelper.message("buffer.0.does.not.exist", bufNum)) result = false } } else if (buffer == "#") { - VimPlugin.getFile().selectPreviousTab(context) + VimPlugin.getFile().selectPreviousTab(context.ij) } else { val editors = findPartialMatch(context, buffer) @@ -61,11 +63,11 @@ data class BufferCommand(val ranges: Ranges, val argument: String) : Command.Sin result = false } 1 -> { - if (EditorHelper.hasUnsavedChanges(editor) && !overrideModified) { + if (EditorHelper.hasUnsavedChanges(editor.ij) && !overrideModified) { VimPlugin.showMessage(MessageHelper.message("no.write.since.last.change.add.to.override")) result = false } else { - VimPlugin.getFile().openFile(EditorHelper.getVirtualFile(editors[0])!!.name, context) + VimPlugin.getFile().openFile(EditorHelper.getVirtualFile(editors[0].ij)!!.name, context.ij) } } else -> { @@ -79,14 +81,14 @@ data class BufferCommand(val ranges: Ranges, val argument: String) : Command.Sin return if (result) ExecutionResult.Success else ExecutionResult.Error } - private fun findPartialMatch(context: DataContext, fileName: String): List { - val matchedFiles = mutableListOf() - val project = PlatformDataKeys.PROJECT.getData(context) ?: return matchedFiles + private fun findPartialMatch(context: ExecutionContext, fileName: String): List { + val matchedFiles = mutableListOf() + val project = PlatformDataKeys.PROJECT.getData(context.ij) ?: return matchedFiles for (file in FileEditorManager.getInstance(project).openFiles) { if (file.name.contains(fileName)) { val editor = EditorHelper.getEditor(file) ?: continue - matchedFiles.add(editor) + matchedFiles.add(editor.vim) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferListCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferListCommand.kt index 16650679abf..27e20d69ffc 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferListCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/BufferListCommand.kt @@ -18,18 +18,20 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.PlatformDataKeys import com.intellij.openapi.editor.Document -import com.intellij.openapi.editor.Editor import com.intellij.openapi.fileEditor.FileEditorManager import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.VirtualFile import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.vimLine +import com.maddyhome.idea.vim.newapi.ij +import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import org.jetbrains.annotations.NonNls @@ -46,34 +48,34 @@ data class BufferListCommand(val ranges: Ranges, val argument: String) : Command val SUPPORTED_FILTERS = setOf('+', '=', 'a', '%', '#') } - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val arg = argument.trim() val filter = pruneUnsupportedFilters(arg) val bufferList = getBufferList(context, filter) - ExOutputModel.getInstance(editor).output(bufferList.joinToString(separator = "\n")) + ExOutputModel.getInstance(editor.ij).output(bufferList.joinToString(separator = "\n")) return ExecutionResult.Success } private fun pruneUnsupportedFilters(filter: String) = filter.filter { it in SUPPORTED_FILTERS } - private fun getBufferList(context: DataContext, filter: String): List { + private fun getBufferList(context: ExecutionContext, filter: String): List { val bufferList = mutableListOf() - val project = PlatformDataKeys.PROJECT.getData(context) ?: return emptyList() + val project = PlatformDataKeys.PROJECT.getData(context.ij) ?: return emptyList() val fem = FileEditorManager.getInstance(project) val openFiles = fem.openFiles val bufNumPad = openFiles.size.toString().length val currentFile = fem.selectedFiles[0] - val previousFile = VimPlugin.getFile().getPreviousTab(context) + val previousFile = VimPlugin.getFile().getPreviousTab(context.ij) val virtualFileDisplayMap = buildVirtualFileDisplayMap(project) var index = 1 for ((file, displayFileName) in virtualFileDisplayMap) { val editor = EditorHelper.getEditor(file) ?: continue - val bufStatus = getBufferStatus(editor, file, currentFile, previousFile) + val bufStatus = getBufferStatus(editor.vim, file, currentFile, previousFile) if (bufStatusMatchesFilter(filter, bufStatus)) { val lineNum = editor.vimLine @@ -118,7 +120,7 @@ data class BufferListCommand(val ranges: Ranges, val argument: String) : Command } private fun getBufferStatus( - editor: Editor, + editor: VimEditor, file: VirtualFile, currentFile: VirtualFile, previousFile: VirtualFile?, @@ -135,7 +137,7 @@ private fun getBufferStatus( bufStatus.setCharAt(2, '=') } - if (isDocumentDirty(editor.document)) { + if (isDocumentDirty(editor.ij.document)) { bufStatus.setCharAt(3, '+') } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CallCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CallCommand.kt index ccdd8e5f5e0..c85c6613aba 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CallCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CallCommand.kt @@ -18,9 +18,9 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -40,7 +40,7 @@ class CallCommand(val ranges: Ranges, val functionCall: Expression) : Command.Si override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { if (functionCall is FunctionCallExpression) { val function = FunctionStorage.getFunctionHandlerOrNull( functionCall.scope, diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdClearCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdClearCommand.kt index 1ca1c350658..72c23a43bfa 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdClearCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdClearCommand.kt @@ -18,9 +18,9 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -30,7 +30,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class CmdClearCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { VimPlugin.getCommand().resetAliases() return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdCommand.kt index d2bcdf8383a..a2af6a29ba9 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdCommand.kt @@ -18,15 +18,16 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor import com.intellij.openapi.util.NlsSafe import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.common.CommandAlias import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.group.CommandGroup.Companion.BLACKLISTED_ALIASES import com.maddyhome.idea.vim.helper.MessageHelper +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -47,7 +48,7 @@ data class CmdCommand(val ranges: Ranges, val argument: String) : Command.Single const val zeroOrOneArguments = "?" const val moreThanZeroArguments = "+" } - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val result: Boolean = if (argument.trim().isEmpty()) { this.listAlias(editor, "") } else { @@ -56,7 +57,7 @@ data class CmdCommand(val ranges: Ranges, val argument: String) : Command.Single return if (result) ExecutionResult.Success else ExecutionResult.Error } - private fun listAlias(editor: Editor, filter: String): Boolean { + private fun listAlias(editor: VimEditor, filter: String): Boolean { val lineSeparator = "\n" val allAliases = VimPlugin.getCommand().listAliases() val aliases = allAliases.filter { @@ -64,11 +65,11 @@ data class CmdCommand(val ranges: Ranges, val argument: String) : Command.Single }.map { "${it.key.padEnd(12)}${it.value.numberOfArguments.padEnd(11)}${it.value.printValue()}" }.sortedWith(String.CASE_INSENSITIVE_ORDER).joinToString(lineSeparator) - ExOutputModel.getInstance(editor).output("Name Args Definition$lineSeparator$aliases") + ExOutputModel.getInstance(editor.ij).output("Name Args Definition$lineSeparator$aliases") return true } - private fun addAlias(editor: Editor?): Boolean { + private fun addAlias(editor: VimEditor?): Boolean { var argument = argument.trim() // Handle overwriting of aliases diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdFilterCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdFilterCommand.kt index 5cae593043b..0469ab4e4ca 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdFilterCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CmdFilterCommand.kt @@ -18,17 +18,18 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.editor.Editor import com.intellij.openapi.progress.ProcessCanceledException import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.MessageHelper +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -37,7 +38,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class CmdFilterCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { logger.debug("execute") val command = buildString { var inBackslash = false @@ -52,7 +53,7 @@ data class CmdFilterCommand(val ranges: Ranges, val argument: String) : Command. append(last) } !inBackslash && c == '%' -> { - val virtualFile = EditorHelper.getVirtualFile(editor) + val virtualFile = EditorHelper.getVirtualFile(editor.ij) if (virtualFile == null) { // Note that we use a slightly different error message to Vim, because we don't support alternate files or file // name modifiers. (I also don't know what the :p:h means) @@ -74,23 +75,23 @@ data class CmdFilterCommand(val ranges: Ranges, val argument: String) : Command. return ExecutionResult.Error } - val workingDirectory = editor.project?.basePath + val workingDirectory = editor.ij.project?.basePath return try { if (ranges.size() == 0) { // Show command output in a window - VimPlugin.getProcess().executeCommand(editor, command, null, workingDirectory)?.let { - ExOutputModel.getInstance(editor).output(it) + VimPlugin.getProcess().executeCommand(editor.ij, command, null, workingDirectory)?.let { + ExOutputModel.getInstance(editor.ij).output(it) } ExecutionResult.Success } else { // Filter val range = this.getTextRange(editor, false) - val input = editor.document.charsSequence.subSequence(range.startOffset, range.endOffset) - VimPlugin.getProcess().executeCommand(editor, command, input, workingDirectory)?.let { + val input = editor.ij.document.charsSequence.subSequence(range.startOffset, range.endOffset) + VimPlugin.getProcess().executeCommand(editor.ij, command, input, workingDirectory)?.let { ApplicationManager.getApplication().runWriteAction { val start = editor.offsetToLogicalPosition(range.startOffset) val end = editor.offsetToLogicalPosition(range.endOffset) - editor.document.replaceString(range.startOffset, range.endOffset, it) + editor.ij.document.replaceString(range.startOffset, range.endOffset, it) val linesFiltered = end.line - start.line if (linesFiltered > 2) { VimPlugin.showMessage("$linesFiltered lines filtered") diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CopyTextCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CopyTextCommand.kt index c7c2c8ce7ad..b8730b67632 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CopyTextCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/CopyTextCommand.kt @@ -18,15 +18,16 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.group.copy.PutData import com.maddyhome.idea.vim.helper.EditorHelper +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser @@ -37,16 +38,16 @@ import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser data class CopyTextCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_REQUIRED, Access.WRITABLE) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - val carets = EditorHelper.getOrderedCaretsList(editor) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + val carets = EditorHelper.getOrderedCaretsList(editor.ij) for (caret in carets) { - val range = getTextRange(editor, caret, false) - val text = EditorHelper.getText(editor, range.startOffset, range.endOffset) + val range = getTextRange(editor, caret.vim, false) + val text = EditorHelper.getText(editor.ij, range.startOffset, range.endOffset) val goToLineCommand = VimscriptParser.parseCommand(argument) ?: throw ExException("E16: Invalid range") - val line = goToLineCommand.commandRanges.getFirstLine(editor, caret) + val line = goToLineCommand.commandRanges.getFirstLine(editor, caret.vim) - val transferableData = injector.clipboardManager.getTransferableData(editor.vim, range, text) + val transferableData = injector.clipboardManager.getTransferableData(editor, range, text) val textData = PutData.TextData(text, SelectionType.LINE_WISE, transferableData) val putData = PutData( textData, @@ -57,7 +58,7 @@ data class CopyTextCommand(val ranges: Ranges, val argument: String) : Command.S caretAfterInsertedText = false, putToLine = line ) - VimPlugin.getPut().putTextForCaret(editor, caret, context, putData) + VimPlugin.getPut().putTextForCaret(editor.ij, caret, context.ij, putData) } return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DelCmdCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DelCmdCommand.kt index a982cbfefbc..bc66382e3ec 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DelCmdCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DelCmdCommand.kt @@ -18,9 +18,9 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -30,7 +30,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class DelCmdCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_REQUIRED, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { if (!VimPlugin.getCommand().hasAlias(argument)) { VimPlugin.showMessage(MessageHelper.message("e184.no.such.user.defined.command.0", argument)) return ExecutionResult.Error diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DeleteLinesCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DeleteLinesCommand.kt index ef0a5c3f40b..10b8055aab6 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DeleteLinesCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DeleteLinesCommand.kt @@ -18,14 +18,12 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.IjVimCaret -import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -34,7 +32,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class DeleteLinesCommand(val ranges: Ranges, var argument: String) : Command.ForEachCaret(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.WRITABLE) - override fun processCommand(editor: Editor, caret: Caret, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, caret: VimCaret, context: ExecutionContext): ExecutionResult { val argument = this.argument val register = if (argument.isNotEmpty() && !argument[0].isDigit()) { this.argument = argument.substring(1) @@ -47,7 +45,7 @@ data class DeleteLinesCommand(val ranges: Ranges, var argument: String) : Comman val textRange = getTextRange(editor, caret, true) return if (VimPlugin.getChange() - .deleteRange(IjVimEditor(editor), IjVimCaret(caret), textRange, SelectionType.LINE_WISE, false) + .deleteRange(editor, caret, textRange, SelectionType.LINE_WISE, false) ) ExecutionResult.Success else ExecutionResult.Error } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DeleteMarksCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DeleteMarksCommand.kt index 5358e9790b7..ec2c250ce8d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DeleteMarksCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/DeleteMarksCommand.kt @@ -18,9 +18,9 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.Msg @@ -29,7 +29,6 @@ import com.maddyhome.idea.vim.mark.VimMarkConstants.DEL_MARKS import com.maddyhome.idea.vim.mark.VimMarkConstants.RO_GLOBAL_MARKS import com.maddyhome.idea.vim.mark.VimMarkConstants.WR_GLOBAL_MARKS import com.maddyhome.idea.vim.mark.VimMarkConstants.WR_REGULAR_FILE_MARKS -import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult private val VIML_COMMENT = Regex("(?) : Command override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult.Success { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult.Success { val text = args.joinToString(separator = " ", postfix = "\n") { it.evaluate(editor, context, this).toString() } - ExOutputModel.getInstance(editor).output(text) + ExOutputModel.getInstance(editor.ij).output(text) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/EditFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/EditFileCommand.kt index d408358ff9f..6a1118d9d4a 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/EditFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/EditFileCommand.kt @@ -18,13 +18,14 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.EditorDataContext +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -33,23 +34,23 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class EditFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val arg = argument if (arg == "#") { - VimPlugin.getMark().saveJumpLocation(editor.vim) - VimPlugin.getFile().selectPreviousTab(context) + VimPlugin.getMark().saveJumpLocation(editor) + VimPlugin.getFile().selectPreviousTab(context.ij) return ExecutionResult.Success } else if (arg.isNotEmpty()) { - val res = VimPlugin.getFile().openFile(arg, context) + val res = VimPlugin.getFile().openFile(arg, context.ij) if (res) { - VimPlugin.getMark().saveJumpLocation(editor.vim) + VimPlugin.getMark().saveJumpLocation(editor) } return if (res) ExecutionResult.Success else ExecutionResult.Error } // Don't open a choose file dialog under a write action ApplicationManager.getApplication().invokeLater { - injector.actionExecutor.executeAction("OpenFile", EditorDataContext.init(editor, context).vim) + injector.actionExecutor.executeAction("OpenFile", EditorDataContext.init(editor.ij, context.ij).vim) } return ExecutionResult.Success diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ExecuteCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ExecuteCommand.kt index c7cd3fb13da..a14316c157d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ExecuteCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ExecuteCommand.kt @@ -18,10 +18,10 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.vimscript.Executor import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.expressions.Expression @@ -31,8 +31,8 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.Expression data class ExecuteCommand(val ranges: Ranges, val expressions: List) : Command.SingleExecution(ranges) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val command = expressions.joinToString(separator = " ") { it.evaluate(editor, context, this).asString() } - return Executor.execute(command, editor, context, skipHistory = true, indicateErrors = true, this.vimContext) + return injector.vimscriptExecutor.execute(command, editor, context, skipHistory = true, indicateErrors = true, this.vimContext) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ExitCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ExitCommand.kt index 8770f54a43a..9c54480dc16 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ExitCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/ExitCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,8 +31,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class ExitCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getWindow().closeAll(context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getWindow().closeAll(context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FileCommand.kt index b49e074258e..268e70aa102 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FileCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,9 +31,9 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class FileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_IS_COUNT, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val count = getCount(editor, 0, false) - VimPlugin.getFile().displayFileInfo(editor, count > 0) + VimPlugin.getFile().displayFileInfo(editor.ij, count > 0) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindClassCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindClassCommand.kt index 2bda04692f5..19dc6c97c1f 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindClassCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindClassCommand.kt @@ -18,12 +18,13 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -32,18 +33,18 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class FindClassCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val arg = argument if (arg.isNotEmpty()) { - val res = VimPlugin.getFile().openFile("$arg.java", context) + val res = VimPlugin.getFile().openFile("$arg.java", context.ij) if (res) { - VimPlugin.getMark().saveJumpLocation(editor.vim) + VimPlugin.getMark().saveJumpLocation(editor) } return if (res) ExecutionResult.Success else ExecutionResult.Error } - ApplicationManager.getApplication().invokeLater { injector.actionExecutor.executeAction("GotoClass", context.vim) } + ApplicationManager.getApplication().invokeLater { injector.actionExecutor.executeAction("GotoClass", context) } return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindFileCommand.kt index 63b26e436c9..e5af35adc91 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindFileCommand.kt @@ -18,12 +18,13 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -32,18 +33,18 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class FindFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val arg = argument if (arg.isNotEmpty()) { - val res = VimPlugin.getFile().openFile(arg, context) + val res = VimPlugin.getFile().openFile(arg, context.ij) if (res) { - VimPlugin.getMark().saveJumpLocation(editor.vim) + VimPlugin.getMark().saveJumpLocation(editor) } return if (res) ExecutionResult.Success else ExecutionResult.Error } - ApplicationManager.getApplication().invokeLater { injector.actionExecutor.executeAction("GotoFile", context.vim) } + ApplicationManager.getApplication().invokeLater { injector.actionExecutor.executeAction("GotoFile", context) } return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindSymbolCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindSymbolCommand.kt index 6460de64322..31692a5ca3f 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindSymbolCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/FindSymbolCommand.kt @@ -18,12 +18,11 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -31,9 +30,9 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class FindSymbolCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { // TODO: Check the command argument and jump to a specific symbol - ApplicationManager.getApplication().invokeLater { injector.actionExecutor.executeAction("GotoSymbol", context.vim) } + ApplicationManager.getApplication().invokeLater { injector.actionExecutor.executeAction("GotoSymbol", context) } return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GlobalCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GlobalCommand.kt index a7fa1f788fa..49f2591203d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GlobalCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GlobalCommand.kt @@ -18,22 +18,22 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.RangeMarker import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.LineRange import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.group.SearchGroup.RE_BOTH import com.maddyhome.idea.vim.group.SearchGroup.RE_LAST import com.maddyhome.idea.vim.group.SearchGroup.RE_SEARCH import com.maddyhome.idea.vim.group.SearchGroup.RE_SUBST -import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.MessageHelper.message import com.maddyhome.idea.vim.helper.Msg +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.regexp.CharPointer import com.maddyhome.idea.vim.regexp.RegExp -import com.maddyhome.idea.vim.vimscript.Executor import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -42,14 +42,14 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class GlobalCommand(val ranges: Ranges, val argument: String, val invert: Boolean) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.SELF_SYNCHRONIZED) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { var result: ExecutionResult = ExecutionResult.Success - editor.caretModel.removeSecondaryCarets() - val caret = editor.caretModel.currentCaret + editor.removeSecondaryCarets() + val caret = editor.currentCaret() // For :g command the default range is % val lineRange: LineRange = if (ranges.size() == 0) { - LineRange(0, editor.document.lineCount - 1) + LineRange(0, editor.lineCount() - 1) } else { getLineRange(editor, caret) } @@ -60,13 +60,13 @@ data class GlobalCommand(val ranges: Ranges, val argument: String, val invert: B } private fun processGlobalCommand( - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, range: LineRange, ): Boolean { // When nesting the command works on one line. This allows for // ":g/found/v/notfound/command". - if (globalBusy && (range.startLine != 0 || range.endLine != editor.document.lineCount - 1)) { + if (globalBusy && (range.startLine != 0 || range.endLine != editor.lineCount() - 1)) { VimPlugin.showMessage(message("E147")) VimPlugin.indicateError() return false @@ -115,11 +115,11 @@ data class GlobalCommand(val ranges: Ranges, val argument: String, val invert: B val sp = second.getThird() var match: Int - val lcount = EditorHelper.getLineCount(editor) + val lcount = editor.lineCount() val searchcol = 0 if (globalBusy) { - val offset = editor.caretModel.currentCaret.offset - val lineStartOffset = editor.document.getLineStartOffset(editor.document.getLineNumber(offset)) + val offset = editor.currentCaret().offset + val lineStartOffset = editor.lineStartForOffset(offset.point) match = sp.vim_regexec_multi(regmatch, editor, lcount, lineStartOffset, searchcol) if ((!invert && match > 0) || (invert && match <= 0)) { globalExecuteOne(editor, context, lineStartOffset, cmd.toString()) @@ -144,8 +144,8 @@ data class GlobalCommand(val ranges: Ranges, val argument: String, val invert: B // a match on this line? match = sp.vim_regexec_multi(regmatch, editor, lcount, lnum, searchcol) if ((!invert && match > 0) || (invert && match <= 0)) { - val lineStartOffset = editor.document.getLineStartOffset(lnum) - marks += editor.document.createRangeMarker(lineStartOffset, lineStartOffset) + val lineStartOffset = editor.getLineStartOffset(lnum) + marks += editor.ij.document.createRangeMarker(lineStartOffset, lineStartOffset) ndone += 1 } // TODO: 25.05.2021 Check break @@ -167,7 +167,7 @@ data class GlobalCommand(val ranges: Ranges, val argument: String, val invert: B return true } - private fun globalExe(editor: Editor, context: DataContext, marks: List, cmd: String) { + private fun globalExe(editor: VimEditor, context: ExecutionContext, marks: List, cmd: String) { globalBusy = true try { for (mark in marks) { @@ -186,13 +186,13 @@ data class GlobalCommand(val ranges: Ranges, val argument: String, val invert: B // TODO: 26.05.2021 Add other staff } - private fun globalExecuteOne(editor: Editor, context: DataContext, lineStartOffset: Int, cmd: String?) { + private fun globalExecuteOne(editor: VimEditor, context: ExecutionContext, lineStartOffset: Int, cmd: String?) { // TODO: 26.05.2021 What about folds? - editor.caretModel.moveToOffset(lineStartOffset) + editor.currentCaret().moveToOffset(lineStartOffset) if (cmd == null || cmd.isEmpty() || (cmd.length == 1 && cmd[0] == '\n')) { - Executor.execute("p", editor, context, skipHistory = true, indicateErrors = true, this.vimContext) + injector.vimscriptExecutor.execute("p", editor, context, skipHistory = true, indicateErrors = true, this.vimContext) } else { - Executor.execute(cmd, editor, context, skipHistory = true, indicateErrors = true, this.vimContext) + injector.vimscriptExecutor.execute(cmd, editor, context, skipHistory = true, indicateErrors = true, this.vimContext) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GoToLineCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GoToLineCommand.kt index 8328861e26e..a0ac9f8b8e6 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GoToLineCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GoToLineCommand.kt @@ -18,14 +18,12 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.group.MotionGroup -import com.maddyhome.idea.vim.helper.EditorHelper -import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import java.lang.Integer.min @@ -38,19 +36,19 @@ data class GoToLineCommand(val ranges: Ranges) : override val argFlags = flags(RangeFlag.RANGE_REQUIRED, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) override fun processCommand( - editor: Editor, - caret: Caret, - context: DataContext, + editor: VimEditor, + caret: VimCaret, + context: ExecutionContext, ): ExecutionResult { - val line = min(this.getLine(editor, caret), EditorHelper.getLineCount(editor) - 1) + val line = min(this.getLine(editor, caret), editor.lineCount() - 1) if (line >= 0) { - val offset = VimPlugin.getMotion().moveCaretToLineWithStartOfLineOption(editor.vim, line, caret.vim) - MotionGroup.moveCaret(editor, caret, offset) + val offset = VimPlugin.getMotion().moveCaretToLineWithStartOfLineOption(editor, line, caret) + injector.motion.moveCaret(editor, caret, offset) return ExecutionResult.Success } - MotionGroup.moveCaret(editor, caret, 0) + injector.motion.moveCaret(editor, caret, 0) return ExecutionResult.Error } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GotoCharacterCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GotoCharacterCommand.kt index 2e71cea2756..9bf80d54c8a 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GotoCharacterCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/GotoCharacterCommand.kt @@ -18,11 +18,11 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.group.MotionGroup import com.maddyhome.idea.vim.helper.fileSize import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import kotlin.math.max @@ -34,14 +34,14 @@ import kotlin.math.min data class GotoCharacterCommand(val ranges: Ranges, val argument: String) : Command.ForEachCaret(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_IS_COUNT, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, caret: Caret, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, caret: VimCaret, context: ExecutionContext): ExecutionResult { val count = getCount(editor, caret, 1, true) if (count <= 0) return ExecutionResult.Error - val offset = max(0, min(count - 1, editor.fileSize - 1)) + val offset = max(0, min(count - 1, editor.fileSize().toInt() - 1)) if (offset == -1) return ExecutionResult.Error - MotionGroup.moveCaret(editor, caret, offset) + injector.motion.moveCaret(editor, caret, offset) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/HelpCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/HelpCommand.kt index 415da09eabd..f32051604e5 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/HelpCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/HelpCommand.kt @@ -19,8 +19,8 @@ package com.maddyhome.idea.vim.vimscript.model.commands import com.intellij.ide.BrowserUtil -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import org.jetbrains.annotations.NonNls @@ -33,7 +33,7 @@ import java.net.URLEncoder */ data class HelpCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { BrowserUtil.browse(helpTopicUrl(argument)) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/HistoryCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/HistoryCommand.kt index a3f70abf295..8a720a68bb8 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/HistoryCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/HistoryCommand.kt @@ -18,17 +18,18 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.diagnostic.debug -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.history.HistoryConstants.COMMAND import com.maddyhome.idea.vim.history.HistoryConstants.EXPRESSION import com.maddyhome.idea.vim.history.HistoryConstants.INPUT import com.maddyhome.idea.vim.history.HistoryConstants.SEARCH +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -36,7 +37,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class HistoryCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { logger.debug("execute") var arg = argument.trim().ifEmpty { "cmd" } @@ -110,7 +111,7 @@ data class HistoryCommand(val ranges: Ranges, val argument: String) : Command.Si else -> "" } - ExOutputModel.getInstance(editor).output(res) + ExOutputModel.getInstance(editor.ij).output(res) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/JoinLinesCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/JoinLinesCommand.kt index abce7e56cd8..82d878da10b 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/JoinLinesCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/JoinLinesCommand.kt @@ -18,14 +18,12 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.IjVimCaret -import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -34,14 +32,14 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class JoinLinesCommand(val ranges: Ranges, val argument: String) : Command.ForEachCaret(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.WRITABLE) - override fun processCommand(editor: Editor, caret: Caret, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, caret: VimCaret, context: ExecutionContext): ExecutionResult { val arg = argument val spaces = arg.isEmpty() || arg[0] != '!' val textRange = getTextRange(editor, caret, true) return if (VimPlugin.getChange().deleteJoinRange( - IjVimEditor(editor), IjVimCaret(caret), + editor, caret, TextRange( textRange.startOffset, textRange.endOffset - 1 diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/JumpsCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/JumpsCommand.kt index adb457ddec5..839c4c9a8b0 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/JumpsCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/JumpsCommand.kt @@ -18,14 +18,15 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.StringHelper.stringToKeys import com.maddyhome.idea.vim.helper.StringHelper.toPrintableCharacters +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import kotlin.math.absoluteValue @@ -34,7 +35,7 @@ import kotlin.math.absoluteValue */ data class JumpsCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val jumps = VimPlugin.getMark().getJumps() val spot = VimPlugin.getMark().getJumpSpot() @@ -50,9 +51,9 @@ data class JumpsCommand(val ranges: Ranges, val argument: String) : Command.Sing text.append(jump.col.toString().padStart(3)) text.append(" ") - val vf = EditorHelper.getVirtualFile(editor) + val vf = EditorHelper.getVirtualFile(editor.ij) if (vf != null && vf.path == jump.filepath) { - val line = EditorHelper.getLineText(editor, jump.logicalLine).trim().take(200) + val line = EditorHelper.getLineText(editor.ij, jump.logicalLine).trim().take(200) val keys = stringToKeys(line) text.append(toPrintableCharacters(keys).take(200)) } else { @@ -66,7 +67,7 @@ data class JumpsCommand(val ranges: Ranges, val argument: String) : Command.Sing text.append(">\n") } - ExOutputModel.getInstance(editor).output(text.toString()) + ExOutputModel.getInstance(editor.ij).output(text.toString()) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/LockVarCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/LockVarCommand.kt index b6e7880ab5a..5b3b4318096 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/LockVarCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/LockVarCommand.kt @@ -18,9 +18,9 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -34,7 +34,7 @@ class LockVarCommand(val ranges: Ranges, val argument: String) : Command.SingleE override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) // todo doesn't throw proper vim exceptions in case of wrong arguments - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val variableAndDepth = parseVariableAndDepth(argument) VimPlugin.getVariableService().lockVariable(variableAndDepth.first, variableAndDepth.second, editor, context, vimContext) return ExecutionResult.Success @@ -48,7 +48,7 @@ class UnlockVarCommand(val ranges: Ranges, val argument: String) : Command.Singl override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) // todo doesn't throw proper vim exceptions in case of wrong arguments - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val variableAndDepth = parseVariableAndDepth(argument) VimPlugin.getVariableService().unlockVariable(variableAndDepth.first, variableAndDepth.second, editor, context, vimContext) return ExecutionResult.Success diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MarkCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MarkCommand.kt index ca539fb2902..d42e400b99b 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MarkCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MarkCommand.kt @@ -18,14 +18,12 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.Msg -import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -34,13 +32,13 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class MarkCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_REQUIRED, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val mark = argument[0] val line = getLine(editor) - val offset = EditorHelper.getLineStartOffset(editor, line) + val offset = editor.getLineStartOffset(line) val result = if (mark.isLetter() || mark in "'`") { - VimPlugin.getMark().setMark(editor.vim, mark, offset) + VimPlugin.getMark().setMark(editor, mark, offset) } else { VimPlugin.showMessage(MessageHelper.message(Msg.E191)) false diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MarksCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MarksCommand.kt index 269d1a420ba..7d668441857 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MarksCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MarksCommand.kt @@ -18,14 +18,15 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.StringHelper.stringToKeys import com.maddyhome.idea.vim.helper.StringHelper.toPrintableCharacters +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -35,19 +36,19 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class MarksCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { // Yeah, lower case. Vim uses lower case here, but Title Case in :registers. Go figure. - val res = VimPlugin.getMark().getMarks(editor.vim) + val res = VimPlugin.getMark().getMarks(editor) .filter { argument.isEmpty() || argument.contains(it.key) } .joinToString("\n", prefix = "mark line col file/text\n") { mark -> // Lines are 1 based, columns zero based. See :help :marks val line = (mark.logicalLine + 1).toString().padStart(5) val column = mark.col.toString().padStart(3) - val vf = EditorHelper.getVirtualFile(editor) + val vf = EditorHelper.getVirtualFile(editor.ij) val text = if (vf != null && vf.path == mark.filename) { - val lineText = EditorHelper.getLineText(editor, mark.logicalLine).trim().take(200) + val lineText = EditorHelper.getLineText(editor.ij, mark.logicalLine).trim().take(200) toPrintableCharacters(stringToKeys(lineText)).take(200) } else { mark.filename @@ -56,7 +57,7 @@ data class MarksCommand(val ranges: Ranges, val argument: String) : Command.Sing " ${mark.key} $line $column $text" } - ExOutputModel.getInstance(editor).output(res) + ExOutputModel.getInstance(editor.ij).output(res) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MoveTextCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MoveTextCommand.kt index 0c18a2f9a93..4077fa2ff38 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MoveTextCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/MoveTextCommand.kt @@ -18,10 +18,10 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.ex.ExException @@ -32,7 +32,8 @@ import com.maddyhome.idea.vim.group.copy.PutData import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.Msg -import com.maddyhome.idea.vim.helper.fileSize +import com.maddyhome.idea.vim.newapi.ij +import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser import kotlin.math.min @@ -44,23 +45,22 @@ data class MoveTextCommand(val ranges: Ranges, val argument: String) : Command.S override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_REQUIRED, Access.WRITABLE) @Throws(ExException::class) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - val carets = EditorHelper.getOrderedCaretsList(editor) - val caretModel = editor.caretModel - val caretCount = caretModel.caretCount + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + val carets = EditorHelper.getOrderedCaretsList(editor.ij) + val caretCount = editor.nativeCarets().size val texts = ArrayList(caretCount) val ranges = ArrayList(caretCount) - var line = editor.fileSize + var line = editor.fileSize().toInt() val goToLineCommand = VimscriptParser.parseCommand(argument) ?: throw ExException("E16: Invalid range") var lastRange: TextRange? = null for (caret in carets) { - val range = getTextRange(editor, caret, false) - val lineRange = getLineRange(editor, caret) + val range = getTextRange(editor, caret.vim, false) + val lineRange = getLineRange(editor, caret.vim) - line = min(line, normalizeLine(editor, caret, goToLineCommand, lineRange)) - texts.add(EditorHelper.getText(editor, range.startOffset, range.endOffset)) + line = min(line, normalizeLine(editor, caret.vim, goToLineCommand, lineRange)) + texts.add(EditorHelper.getText(editor.ij, range.startOffset, range.endOffset)) if (lastRange == null || lastRange.startOffset != range.startOffset && lastRange.endOffset != range.endOffset) { ranges.add(range) @@ -68,7 +68,7 @@ data class MoveTextCommand(val ranges: Ranges, val argument: String) : Command.S } } - ranges.forEach { editor.document.deleteString(it.startOffset, it.endOffset) } + ranges.forEach { editor.ij.document.deleteString(it.startOffset, it.endOffset) } for (i in 0 until caretCount) { val caret = carets[i] @@ -84,7 +84,7 @@ data class MoveTextCommand(val ranges: Ranges, val argument: String) : Command.S caretAfterInsertedText = false, putToLine = line ) - VimPlugin.getPut().putTextForCaret(editor, caret, context, putData) + VimPlugin.getPut().putTextForCaret(editor.ij, caret, context.ij, putData) } return ExecutionResult.Success @@ -92,8 +92,8 @@ data class MoveTextCommand(val ranges: Ranges, val argument: String) : Command.S @Throws private fun normalizeLine( - editor: Editor, - caret: Caret, + editor: VimEditor, + caret: VimCaret, command: Command, lineRange: LineRange, ): Int { diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NextFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NextFileCommand.kt index cf2f180bbd1..3df7c27f4c3 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NextFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NextFileCommand.kt @@ -18,11 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -31,10 +31,10 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class NextFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_IS_COUNT, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val count = getCount(editor, 1, true) - VimPlugin.getMark().saveJumpLocation(editor.vim) - VimPlugin.getFile().selectNextFile(count, context) + VimPlugin.getMark().saveJumpLocation(editor) + VimPlugin.getFile().selectNextFile(count, context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NextTabCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NextTabCommand.kt index 4508bd91d46..c1a5d7a85a7 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NextTabCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NextTabCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -29,8 +30,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class NextTabCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getMotion().moveCaretGotoNextTab(editor, context, argument.toIntOrNull() ?: 0) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getMotion().moveCaretGotoNextTab(editor.ij, context.ij, argument.toIntOrNull() ?: 0) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NoHLSearchCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NoHLSearchCommand.kt index 832394370a0..6c9728d8a1e 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NoHLSearchCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NoHLSearchCommand.kt @@ -17,9 +17,9 @@ */ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -28,7 +28,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class NoHLSearchCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { VimPlugin.getSearch().clearSearchHighlight() return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NormalCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NormalCommand.kt index 16d0a6e4def..6e52984613e 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NormalCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/NormalCommand.kt @@ -18,22 +18,20 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.editor.LogicalPosition import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.VimLogicalPosition import com.maddyhome.idea.vim.command.CommandState import com.maddyhome.idea.vim.command.OperatorArguments import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.StringHelper.stringToKeys import com.maddyhome.idea.vim.helper.commandState import com.maddyhome.idea.vim.helper.exitInsertMode import com.maddyhome.idea.vim.helper.exitSelectMode -import com.maddyhome.idea.vim.helper.exitVisualMode -import com.maddyhome.idea.vim.helper.getTopLevelEditor import com.maddyhome.idea.vim.helper.mode +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionScope @@ -42,7 +40,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class NormalCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.WRITABLE, Flag.SAVE_VISUAL) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.ideadelaymacroName)) { return ExecutionResult.Success } @@ -54,45 +52,45 @@ data class NormalCommand(val ranges: Ranges, val argument: String) : Command.Sin argument = argument.substring(1) } - val commandState = editor.vim.commandState + val commandState = editor.commandState val rangeUsed = ranges.size() != 0 when (editor.mode) { CommandState.Mode.VISUAL -> { - editor.getTopLevelEditor().exitVisualMode() + editor.exitVisualModeNative() if (!rangeUsed) { - val selectionStart = VimPlugin.getMark().getMark(editor.vim, '<')!! - editor.caretModel.moveToLogicalPosition(LogicalPosition(selectionStart.logicalLine, selectionStart.col)) + val selectionStart = VimPlugin.getMark().getMark(editor, '<')!! + editor.currentCaret().moveToLogicalPosition(VimLogicalPosition(selectionStart.logicalLine, selectionStart.col)) } } - CommandState.Mode.CMD_LINE -> VimPlugin.getProcess().cancelExEntry(editor, false) + CommandState.Mode.CMD_LINE -> VimPlugin.getProcess().cancelExEntry(editor.ij, false) CommandState.Mode.INSERT, CommandState.Mode.REPLACE -> editor.exitInsertMode(context, OperatorArguments(false, 1, commandState.mode, commandState.subMode)) CommandState.Mode.SELECT -> editor.exitSelectMode(false) CommandState.Mode.OP_PENDING, CommandState.Mode.COMMAND -> Unit } - val range = getLineRange(editor, editor.caretModel.primaryCaret) + val range = getLineRange(editor, editor.primaryCaret()) for (line in range.startLine..range.endLine) { if (rangeUsed) { // Move caret to the first position on line - if (editor.document.lineCount < line) { + if (editor.lineCount() < line) { break } - val startOffset = EditorHelper.getLineStartOffset(editor, line) - editor.caretModel.moveToOffset(startOffset) + val startOffset = editor.getLineStartOffset(line) + editor.currentCaret().moveToOffset(startOffset) } // Perform operations val keys = stringToKeys(argument) val keyHandler = KeyHandler.getInstance() - keyHandler.reset(editor.vim) + keyHandler.reset(editor) for (key in keys) { - keyHandler.handleKey(editor.vim, key, context.vim, useMappings, true) + keyHandler.handleKey(editor, key, context, useMappings, true) } // Exit if state leaves as insert or cmd_line val mode = commandState.mode if (mode == CommandState.Mode.CMD_LINE) { - VimPlugin.getProcess().cancelExEntry(editor, false) + VimPlugin.getProcess().cancelExEntry(editor.ij, false) } if (mode == CommandState.Mode.INSERT || mode == CommandState.Mode.REPLACE) { editor.exitInsertMode(context, OperatorArguments(false, 1, commandState.mode, commandState.subMode)) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/OnlyCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/OnlyCommand.kt index 2451658f107..73a12d35aab 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/OnlyCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/OnlyCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,8 +31,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class OnlyCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getWindow().closeAllExceptCurrent(context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getWindow().closeAllExceptCurrent(context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PackaddCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PackaddCommand.kt index 208fcdfd3bd..bced04ed270 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PackaddCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PackaddCommand.kt @@ -18,9 +18,9 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -29,7 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult class PackaddCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_REQUIRED, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { if (argument == "matchit" || (argument.startsWith("!") && argument.drop(1).trim() == "matchit")) { VimPlugin.getOptionService().setOption(OptionScope.GLOBAL, "matchit") } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PlugCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PlugCommand.kt index 22cfa61837a..6e347e45172 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PlugCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PlugCommand.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.extension.VimExtensionRegistrar import com.maddyhome.idea.vim.statistic.VimscriptState @@ -31,7 +31,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class PlugCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_REQUIRED, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val argument = argument val firstChar = argument[0] if (firstChar != '"' && firstChar != '\'') return ExecutionResult.Error diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PreviousFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PreviousFileCommand.kt index 70e873121b9..a2a5db50717 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PreviousFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PreviousFileCommand.kt @@ -18,11 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,11 +30,11 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class PreviousFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_IS_COUNT, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val count = getCount(editor, 1, true) - VimPlugin.getMark().saveJumpLocation(editor.vim) - VimPlugin.getFile().selectNextFile(-count, context) + VimPlugin.getMark().saveJumpLocation(editor) + VimPlugin.getFile().selectNextFile(-count, context.ij) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PreviousTabCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PreviousTabCommand.kt index 5059b0ab60d..9fc9f3826cd 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PreviousTabCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PreviousTabCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -29,8 +30,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class PreviousTabCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getMotion().moveCaretGotoPreviousTab(editor, context, argument.toIntOrNull() ?: 0) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getMotion().moveCaretGotoPreviousTab(editor.ij, context.ij, argument.toIntOrNull() ?: 0) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PrintCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PrintCommand.kt index 9fe37711bb4..d564cdaef70 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PrintCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PrintCommand.kt @@ -18,11 +18,12 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor import com.intellij.openapi.util.TextRange +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -31,14 +32,14 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class PrintCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - editor.caretModel.removeSecondaryCarets() - val caret = editor.caretModel.currentCaret + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + editor.removeSecondaryCarets() + val caret = editor.currentCaret() val textRange = getTextRange(editor, caret, checkCount = true) - val text = editor.document.getText(TextRange(textRange.startOffset, textRange.endOffset)) + val text = editor.ij.document.getText(TextRange(textRange.startOffset, textRange.endOffset)) - val exOutputModel = ExOutputModel.getInstance(editor) + val exOutputModel = ExOutputModel.getInstance(editor.ij) exOutputModel.output((exOutputModel.text ?: "") + text) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PromptFindCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PromptFindCommand.kt index f7496593d54..983acaaff53 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PromptFindCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PromptFindCommand.kt @@ -18,11 +18,10 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,7 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class PromptFindCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - return if (injector.actionExecutor.executeAction("Find", context.vim)) ExecutionResult.Success else ExecutionResult.Error + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + return if (injector.actionExecutor.executeAction("Find", context)) ExecutionResult.Success else ExecutionResult.Error } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PromptReplaceCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PromptReplaceCommand.kt index e2e6246c601..26d9a36cdf7 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PromptReplaceCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PromptReplaceCommand.kt @@ -18,11 +18,10 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,7 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class PromptReplaceCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - return if (injector.actionExecutor.executeAction("Replace", context.vim)) ExecutionResult.Success else ExecutionResult.Error + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + return if (injector.actionExecutor.executeAction("Replace", context)) ExecutionResult.Success else ExecutionResult.Error } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PutLinesCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PutLinesCommand.kt index 7e9f9dd5230..e7e58283099 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PutLinesCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/PutLinesCommand.kt @@ -18,13 +18,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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.group.copy.PutData import com.maddyhome.idea.vim.helper.StringHelper +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -33,8 +34,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class PutLinesCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - if (editor.isOneLineMode) return ExecutionResult.Error + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + if (editor.isOneLineMode()) return ExecutionResult.Error val registerGroup = VimPlugin.getRegister() val arg = argument @@ -62,6 +63,6 @@ data class PutLinesCommand(val ranges: Ranges, val argument: String) : Command.S caretAfterInsertedText = false, putToLine = line ) - return if (VimPlugin.getPut().putText(editor, context, putData)) ExecutionResult.Success else ExecutionResult.Error + return if (VimPlugin.getPut().putText(editor.ij, context.ij, putData)) ExecutionResult.Success else ExecutionResult.Error } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/QuitCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/QuitCommand.kt index 1df62db0828..bdd7c2eb3ef 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/QuitCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/QuitCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -29,8 +30,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class QuitCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getFile().closeFile(editor, context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getFile().closeFile(editor.ij, context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RedoCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RedoCommand.kt index 82991cf1d25..0ef1b2fe2fb 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RedoCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RedoCommand.kt @@ -18,10 +18,11 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.UndoRedoHelper +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -29,7 +30,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class RedoCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.WRITABLE) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - return if (UndoRedoHelper.redo(context)) ExecutionResult.Success else ExecutionResult.Error + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + return if (UndoRedoHelper.redo(context.ij)) ExecutionResult.Success else ExecutionResult.Error } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RegistersCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RegistersCommand.kt index 51841713acc..0e774b8a80d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RegistersCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RegistersCommand.kt @@ -18,14 +18,15 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.StringHelper import com.maddyhome.idea.vim.helper.StringHelper.parseKeys +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -33,7 +34,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class RegistersCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val registerGroup = VimPlugin.getRegister() val regs = registerGroup.getRegisters() @@ -48,7 +49,7 @@ data class RegistersCommand(val ranges: Ranges, val argument: String) : Command. " $type \"${reg.name} ${StringHelper.toPrintableCharacters(text).take(200)}" } - ExOutputModel.getInstance(editor).output(regs) + ExOutputModel.getInstance(editor.ij).output(regs) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RepeatCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RepeatCommand.kt index c38bb75b5df..3eb8992632d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RepeatCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/RepeatCommand.kt @@ -18,16 +18,13 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.group.MotionGroup -import com.maddyhome.idea.vim.newapi.IjVimCaret -import com.maddyhome.idea.vim.newapi.IjVimEditor -import com.maddyhome.idea.vim.vimscript.Executor import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -39,26 +36,26 @@ data class RepeatCommand(val ranges: Ranges, val argument: String) : Command.For private var lastArg = ':' @Throws(ExException::class) - override fun processCommand(editor: Editor, caret: Caret, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, caret: VimCaret, context: ExecutionContext): ExecutionResult { var arg = argument[0] if (arg == '@') arg = lastArg lastArg = arg val line = getLine(editor, caret) - MotionGroup.moveCaret( + injector.motion.moveCaret( editor, caret, - VimPlugin.getMotion().moveCaretToLineWithSameColumn(IjVimEditor(editor), line, IjVimCaret(editor.caretModel.primaryCaret)) + VimPlugin.getMotion().moveCaretToLineWithSameColumn(editor, line, editor.primaryCaret()) ) if (arg == ':') { - return if (Executor.executeLastCommand(editor, context)) ExecutionResult.Success else ExecutionResult.Error + return if (injector.vimscriptExecutor.executeLastCommand(editor, context)) ExecutionResult.Success else ExecutionResult.Error } val reg = VimPlugin.getRegister().getPlaybackRegister(arg) ?: return ExecutionResult.Error val text = reg.text ?: return ExecutionResult.Error - Executor.execute(text, editor, context, skipHistory = false, indicateErrors = true, this.vimContext) + injector.vimscriptExecutor.execute(text, editor, context, skipHistory = false, indicateErrors = true, this.vimContext) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectFileCommand.kt index 858e2da99f0..b8184a26f32 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectFileCommand.kt @@ -18,11 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -31,13 +31,13 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class SelectFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_IS_COUNT, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val count = getCount(editor, 0, true) if (count > 0) { - val res = VimPlugin.getFile().selectFile(count - 1, context) + val res = VimPlugin.getFile().selectFile(count - 1, context.ij) if (res) { - VimPlugin.getMark().saveJumpLocation(editor.vim) + VimPlugin.getMark().saveJumpLocation(editor) } return if (res) ExecutionResult.Success else ExecutionResult.Error diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectFirstFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectFirstFileCommand.kt index 31c9e8dd30b..ac5ccd353af 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectFirstFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectFirstFileCommand.kt @@ -18,11 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,10 +30,10 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class SelectFirstFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - val res = VimPlugin.getFile().selectFile(0, context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + val res = VimPlugin.getFile().selectFile(0, context.ij) if (res) { - VimPlugin.getMark().saveJumpLocation(editor.vim) + VimPlugin.getMark().saveJumpLocation(editor) } return if (res) ExecutionResult.Success else ExecutionResult.Error } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectLastFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectLastFileCommand.kt index 39b77716ad8..a06bf2aef08 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectLastFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SelectLastFileCommand.kt @@ -18,11 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,10 +30,10 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class SelectLastFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - val res = VimPlugin.getFile().selectFile(999, context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + val res = VimPlugin.getFile().selectFile(999, context.ij) if (res) { - VimPlugin.getMark().saveJumpLocation(editor.vim) + VimPlugin.getMark().saveJumpLocation(editor) } return if (res) ExecutionResult.Success else ExecutionResult.Error } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SetCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SetCommand.kt index 86c5266dfd7..4141edde729 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SetCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/SetCommand.kt @@ -18,16 +18,16 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ExOutputModel import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.Msg -import com.maddyhome.idea.vim.newapi.IjVimEditor +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.option.OptionsManager import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -46,10 +46,10 @@ data class SetCommand(val ranges: Ranges, val argument: String) : Command.Single internal var isExecutingCommand = false } - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { isExecutingCommand = true try { - OptionsManager.parseOptionLine(editor, argument, true) + OptionsManager.parseOptionLine(editor.ij, argument, true) } catch (e: ExException) { // same exceptions will be thrown later, so we ignore them for now } @@ -65,8 +65,8 @@ data class SetCommand(val ranges: Ranges, val argument: String) : Command.Single data class SetLocalCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - return if (parseOptionLine(editor, argument, OptionScope.LOCAL(IjVimEditor(editor)), failOnBad = true)) { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + return if (parseOptionLine(editor, argument, OptionScope.LOCAL(editor), failOnBad = true)) { ExecutionResult.Success } else { ExecutionResult.Error @@ -99,7 +99,7 @@ data class SetLocalCommand(val ranges: Ranges, val argument: String) : Command.S * @return True if no errors were found, false if there were any errors */ // todo is failOnBad used anywhere? -fun parseOptionLine(editor: Editor, args: String, scope: OptionScope, failOnBad: Boolean): Boolean { +fun parseOptionLine(editor: VimEditor, args: String, scope: OptionScope, failOnBad: Boolean): Boolean { // No arguments so we show changed values val optionService = (VimPlugin.getOptionService() as OptionServiceImpl) when { @@ -196,7 +196,7 @@ fun parseOptionLine(editor: Editor, args: String, scope: OptionScope, failOnBad: return true } -private fun showOptions(editor: Editor, nameAndToken: Collection>, scope: OptionScope, showIntro: Boolean) { +private fun showOptions(editor: VimEditor, nameAndToken: Collection>, scope: OptionScope, showIntro: Boolean) { val optionService = VimPlugin.getOptionService() val optionsToShow = mutableListOf() var unknownOption: Pair? = null @@ -220,7 +220,7 @@ private fun showOptions(editor: Editor, nameAndToken: Collection= tabCount) { throw ExException("E474: Invalid argument") } - tabService.moveCurrentTabToIndex(index, context) + tabService.moveCurrentTabToIndex(index, context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/TabOnlyCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/TabOnlyCommand.kt index 5c04ea8a12e..ba90f356dbe 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/TabOnlyCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/TabOnlyCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -29,8 +30,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class TabOnlyCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_IS_COUNT, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getWindow().closeAllExceptCurrentTab(context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getWindow().closeAllExceptCurrentTab(context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/UndoCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/UndoCommand.kt index 869a2e7fe1b..9a0b2d91281 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/UndoCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/UndoCommand.kt @@ -18,10 +18,11 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.UndoRedoHelper +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,7 +31,7 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult data class UndoCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.WRITABLE) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - return if (UndoRedoHelper.undo(context)) ExecutionResult.Success else ExecutionResult.Error + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + return if (UndoRedoHelper.undo(context.ij)) ExecutionResult.Success else ExecutionResult.Error } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/UnknownCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/UnknownCommand.kt index 31216bec7a6..7ae90e18d55 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/UnknownCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/UnknownCommand.kt @@ -18,15 +18,16 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.common.GoalCommand import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.InvalidCommandException import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.Msg +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.commands.UnknownCommand.Constants.MAX_RECURSION import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser @@ -42,11 +43,11 @@ data class UnknownCommand(val ranges: Ranges, val name: String, val argument: St const val MAX_RECURSION = 100 } - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { return processPossiblyAliasCommand("$name $argument", editor, context, MAX_RECURSION) } - private fun processPossiblyAliasCommand(name: String, editor: Editor, context: DataContext, aliasCountdown: Int): ExecutionResult { + private fun processPossiblyAliasCommand(name: String, editor: VimEditor, context: ExecutionContext, aliasCountdown: Int): ExecutionResult { if (VimPlugin.getCommand().isAlias(name)) { if (aliasCountdown > 0) { val commandAlias = VimPlugin.getCommand().getAliasCommand(name, 1) @@ -66,7 +67,7 @@ data class UnknownCommand(val ranges: Ranges, val name: String, val argument: St } } is GoalCommand.Call -> { - commandAlias.handler.execute(editor, context) + commandAlias.handler.execute(editor.ij, context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteAllCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteAllCommand.kt index a66be5f6132..02be976b403 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteAllCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteAllCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -29,8 +30,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class WriteAllCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getFile().saveFiles(context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getFile().saveFiles(context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteCommand.kt index 13d4f9e4636..c8c7dbbb3fb 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -29,8 +30,8 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class WriteCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getFile().saveFile(context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getFile().saveFile(context.ij) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteNextFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteNextFileCommand.kt index e71801b5c96..53ed32eeca7 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteNextFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteNextFileCommand.kt @@ -18,11 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,12 +30,12 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class WriteNextFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_IS_COUNT, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val count = getCount(editor, 1, true) - VimPlugin.getFile().saveFile(context) - VimPlugin.getMark().saveJumpLocation(editor.vim) - VimPlugin.getFile().selectNextFile(count, context) + VimPlugin.getFile().saveFile(context.ij) + VimPlugin.getMark().saveJumpLocation(editor) + VimPlugin.getFile().selectNextFile(count, context.ij) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WritePreviousFileCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WritePreviousFileCommand.kt index 29d11297704..c60d8dbd1ce 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WritePreviousFileCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WritePreviousFileCommand.kt @@ -18,11 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.vim +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -30,12 +30,12 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class WritePreviousFileCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val count = getCount(editor, 1, true) - VimPlugin.getFile().saveFile(context) - VimPlugin.getMark().saveJumpLocation(editor.vim) - VimPlugin.getFile().selectNextFile(-count, context) + VimPlugin.getFile().saveFile(context.ij) + VimPlugin.getMark().saveJumpLocation(editor) + VimPlugin.getFile().selectNextFile(-count, context.ij) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteQuitCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteQuitCommand.kt index 7b9c748e92a..8db3ea02e62 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteQuitCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/WriteQuitCommand.kt @@ -18,10 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -29,9 +30,9 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult */ data class WriteQuitCommand(val ranges: Ranges, val argument: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { - VimPlugin.getFile().saveFile(context) - VimPlugin.getFile().closeFile(editor, context) + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { + VimPlugin.getFile().saveFile(context.ij) + VimPlugin.getFile().closeFile(editor.ij, context.ij) return ExecutionResult.Success } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/YankLinesCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/YankLinesCommand.kt index 57bbc48fcec..1ba3214f554 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/YankLinesCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/YankLinesCommand.kt @@ -18,13 +18,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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutionResult /** @@ -34,7 +35,7 @@ data class YankLinesCommand(val ranges: Ranges, var argument: String) : Command. override val argFlags = flags(RangeFlag.RANGE_OPTIONAL, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) @Throws(ExException::class) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { val argument = this.argument val registerGroup = VimPlugin.getRegister() val register = if (argument.isNotEmpty() && !argument[0].isDigit()) { @@ -46,17 +47,16 @@ data class YankLinesCommand(val ranges: Ranges, var argument: String) : Command. if (!registerGroup.selectRegister(register)) return ExecutionResult.Error - val caretModel = editor.caretModel - val starts = ArrayList(caretModel.caretCount) - val ends = ArrayList(caretModel.caretCount) - for (caret in caretModel.allCarets) { + val starts = ArrayList(editor.nativeCarets().size) + val ends = ArrayList(editor.nativeCarets().size) + for (caret in editor.nativeCarets()) { val range = getTextRange(editor, caret, true) starts.add(range.startOffset) ends.add(range.endOffset) } return if (VimPlugin.getYank().yankRange( - editor, + editor.ij, TextRange(starts.toIntArray(), ends.toIntArray()), SelectionType.LINE_WISE, false ) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/MapClearCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/MapClearCommand.kt index 2bfd7a88394..7e57d175d8f 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/MapClearCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/MapClearCommand.kt @@ -18,9 +18,9 @@ package com.maddyhome.idea.vim.vimscript.model.commands.mapping -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.common.MappingMode import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -29,7 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.commands.Command data class MapClearCommand(val ranges: Ranges, val argument: String, val cmd: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_FORBIDDEN, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { return if (executeCommand()) ExecutionResult.Success else ExecutionResult.Error } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/MapCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/MapCommand.kt index c4a6941d5fa..36313828129 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/MapCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/MapCommand.kt @@ -18,14 +18,15 @@ package com.maddyhome.idea.vim.vimscript.model.commands.mapping -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.common.MappingMode import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.StringHelper.parseKeys import com.maddyhome.idea.vim.key.MappingOwner +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.statistic.VimscriptState import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.commands.Command @@ -45,16 +46,16 @@ data class MapCommand(val ranges: Ranges, val argument: String, val cmd: String) override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) @Throws(ExException::class) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { return if (executeCommand(editor)) ExecutionResult.Success else ExecutionResult.Error } @Throws(ExException::class) - private fun executeCommand(editor: Editor?): Boolean { + private fun executeCommand(editor: VimEditor?): Boolean { val commandInfo = COMMAND_INFOS.find { cmd.startsWith(it.prefix) } ?: return false val modes = commandInfo.mappingModes - if (argument.isEmpty()) return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor) + if (argument.isEmpty()) return editor != null && VimPlugin.getKey().showKeyMappings(modes, editor.ij) val arguments = try { parseCommandArguments(argument) ?: return false diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/UnMapCommand.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/UnMapCommand.kt index 96cb74b2bec..53e7d4c6b22 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/UnMapCommand.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/mapping/UnMapCommand.kt @@ -18,9 +18,9 @@ package com.maddyhome.idea.vim.vimscript.model.commands.mapping -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.common.MappingMode import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.helper.StringHelper.parseKeys @@ -30,7 +30,7 @@ import com.maddyhome.idea.vim.vimscript.model.commands.Command data class UnMapCommand(val ranges: Ranges, val argument: String, val cmd: String) : Command.SingleExecution(ranges, argument) { override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_REQUIRED, Access.READ_ONLY) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { return if (executeCommand()) ExecutionResult.Success else ExecutionResult.Error } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/AbsFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/AbsFunctionHandler.kt index 1b26d38a597..88d5f6c9cca 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/AbsFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/AbsFunctionHandler.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFloat @@ -36,8 +36,8 @@ object AbsFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimDataType { val argument = argumentValues[0].evaluate(editor, context, vimContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/ColLineFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/ColLineFunctionHandler.kt index e43e91917a8..7b5fd247ebb 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/ColLineFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/ColLineFunctionHandler.kt @@ -18,14 +18,14 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.inVisualMode import com.maddyhome.idea.vim.helper.vimLine import com.maddyhome.idea.vim.helper.vimSelectionStart -import com.maddyhome.idea.vim.newapi.IjVimEditor +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionScope @@ -47,8 +47,8 @@ object LineFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimInt { val argument = argumentValues[0].evaluate(editor, context, vimContext) @@ -64,8 +64,8 @@ object ColFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimDataType { val argument = argumentValues[0].evaluate(editor, context, vimContext) @@ -73,13 +73,13 @@ object ColFunctionHandler : FunctionHandler() { } } -private fun currentCol(editor: Editor): VimInt { - val logicalPosition = editor.caretModel.currentCaret.logicalPosition - var lineLength = EditorHelper.getLineLength(editor, logicalPosition.line) +private fun currentCol(editor: VimEditor): VimInt { + val logicalPosition = editor.currentCaret().getLogicalPosition() + var lineLength = editor.lineLength(logicalPosition.line) // If virtualedit is set, the col is one more // XXX Should we also check the current mode? - if ((VimPlugin.getOptionService().getOptionValue(OptionScope.LOCAL(IjVimEditor(editor)), OptionConstants.virtualeditName) as VimString).value.isNotEmpty()) { + if ((VimPlugin.getOptionService().getOptionValue(OptionScope.LOCAL(editor), OptionConstants.virtualeditName) as VimString).value.isNotEmpty()) { lineLength += 1 } @@ -88,17 +88,17 @@ private fun currentCol(editor: Editor): VimInt { // Analog of var2fpos function // Translate variable to position -private fun variableToPosition(editor: Editor, variable: VimDataType, dollarForLine: Boolean): Pair? { +private fun variableToPosition(editor: VimEditor, variable: VimDataType, dollarForLine: Boolean): Pair? { if (variable is VimList) { if (variable.values.size < 2) return null val line = indexAsNumber(variable, 0) ?: return null - if (line <= 0 || line > editor.document.lineCount) { + if (line <= 0 || line > editor.lineCount()) { return null } var column = indexAsNumber(variable, 1) ?: return null - val lineLength = EditorHelper.getLineLength(editor, line.value - 1) + val lineLength = editor.lineLength(line.value - 1) if (variable[1].asString() == "$") { column = (lineLength + 1).asVimInt() @@ -115,15 +115,15 @@ private fun variableToPosition(editor: Editor, variable: VimDataType, dollarForL if (name.isEmpty()) return null // Current caret line - if (name[0] == '.') return editor.vimLine.asVimInt() to currentCol(editor) + if (name[0] == '.') return editor.ij.vimLine.asVimInt() to currentCol(editor) // Visual start if (name == "v") { if (editor.inVisualMode) { - return editor.vimLine.asVimInt() to currentCol(editor) + return editor.ij.vimLine.asVimInt() to currentCol(editor) } - val vimStart = editor.caretModel.currentCaret.vimSelectionStart + val vimStart = editor.currentCaret().vimSelectionStart val visualLine = (editor.offsetToLogicalPosition(vimStart).line + 1).asVimInt() val visualCol = (editor.offsetToLogicalPosition(vimStart).column + 1).asVimInt() @@ -132,7 +132,7 @@ private fun variableToPosition(editor: Editor, variable: VimDataType, dollarForL // Mark if (name.length >= 2 && name[0] == '\'') { - val mark = VimPlugin.getMark().getMark(editor.vim, name[1]) ?: return null + val mark = VimPlugin.getMark().getMark(editor, name[1]) ?: return null val markLogicalLine = (mark.logicalLine + 1).asVimInt() val markLogicalCol = (mark.col + 1).asVimInt() return markLogicalLine to markLogicalCol @@ -141,26 +141,26 @@ private fun variableToPosition(editor: Editor, variable: VimDataType, dollarForL // First visual line if (name.length >= 2 && name[0] == 'w' && name[1] == '0') { if (!dollarForLine) return null - val actualVisualTop = EditorHelper.getVisualLineAtTopOfScreen(editor) - val actualLogicalTop = EditorHelper.visualLineToLogicalLine(editor, actualVisualTop) + val actualVisualTop = EditorHelper.getVisualLineAtTopOfScreen(editor.ij) + val actualLogicalTop = EditorHelper.visualLineToLogicalLine(editor.ij, actualVisualTop) return (actualLogicalTop + 1).asVimInt() to currentCol(editor) } // Last visual line if (name.length >= 2 && name[0] == 'w' && name[1] == '$') { if (!dollarForLine) return null - val actualVisualBottom = EditorHelper.getVisualLineAtBottomOfScreen(editor) - val actualLogicalBottom = EditorHelper.visualLineToLogicalLine(editor, actualVisualBottom) + val actualVisualBottom = EditorHelper.getVisualLineAtBottomOfScreen(editor.ij) + val actualLogicalBottom = EditorHelper.visualLineToLogicalLine(editor.ij, actualVisualBottom) return (actualLogicalBottom + 1).asVimInt() to currentCol(editor) } // Last column or line if (name[0] == '$') { return if (dollarForLine) { - editor.document.lineCount.asVimInt() to VimInt.ZERO + editor.lineCount().asVimInt() to VimInt.ZERO } else { - val line = editor.caretModel.currentCaret.logicalPosition.line - val lineLength = EditorHelper.getLineLength(editor, line) + val line = editor.currentCaret().getLogicalPosition().line + val lineLength = editor.lineLength(line) (line + 1).asVimInt() to lineLength.asVimInt() } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/EmptyFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/EmptyFunctionHandler.kt index f31767d4186..54e8ee74427 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/EmptyFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/EmptyFunctionHandler.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimBlob import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -41,8 +41,8 @@ object EmptyFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimDataType { val argument = argumentValues[0].evaluate(editor, context, vimContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/ExistsFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/ExistsFunctionHandler.kt index 7e164b79af6..78065a1dcda 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/ExistsFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/ExistsFunctionHandler.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.option.OptionsManager import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -39,13 +39,13 @@ object ExistsFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimDataType { val expression = argumentValues[0] return if (expression is SimpleExpression && expression.data is VimString) { - val parsedValue = VimscriptParser.parseExpression(expression.data.value) + val parsedValue = VimscriptParser.parseExpression((expression.data as VimString).value) if (parsedValue is OptionExpression) { if (OptionsManager.getOption(parsedValue.optionName) != null) { VimInt.ONE diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/FunctionFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/FunctionFunctionHandler.kt index 1aaf1d8d199..075894fc7d5 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/FunctionFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/FunctionFunctionHandler.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary @@ -39,8 +39,8 @@ object FunctionFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimFuncref { val arg1 = argumentValues[0].evaluate(editor, context, vimContext) @@ -86,8 +86,8 @@ object FuncrefFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimFuncref { val arg1 = argumentValues[0].evaluate(editor, context, vimContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/HasFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/HasFunctionHandler.kt index 73ca9077a26..fecd484f860 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/HasFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/HasFunctionHandler.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.statistic.VimscriptState import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -36,8 +36,8 @@ object HasFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimDataType { val feature = argumentValues[0].evaluate(editor, context, vimContext).asString() diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/LenFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/LenFunctionHandler.kt index 06f2e988f46..ea0e0977b83 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/LenFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/LenFunctionHandler.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimBlob @@ -39,8 +39,8 @@ object LenFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimDataType { val argument = argumentValues[0].evaluate(editor, context, vimContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/SinFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/SinFunctionHandler.kt index 3103f94a076..ceeb8f87ccf 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/SinFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/SinFunctionHandler.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFloat @@ -35,8 +35,8 @@ object SinFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimDataType { val argument = argumentValues[0].evaluate(editor, context, vimContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/SubmatchFunctionHandler.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/SubmatchFunctionHandler.kt index 306731b1c19..ae51a815a1f 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/SubmatchFunctionHandler.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/handlers/SubmatchFunctionHandler.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -36,8 +36,8 @@ object SubmatchFunctionHandler : FunctionHandler() { override fun doFunction( argumentValues: List, - editor: Editor, - context: DataContext, + editor: VimEditor, + context: ExecutionContext, vimContext: VimLContext, ): VimDataType { val firstArgValue = argumentValues[0].evaluate(editor, context, vimContext).toVimNumber() diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/parser/VimscriptParser.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/parser/VimscriptParser.kt index 7abef7067e3..0404577b3b2 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/parser/VimscriptParser.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/parser/VimscriptParser.kt @@ -33,15 +33,15 @@ import org.antlr.v4.runtime.CharStreams import org.antlr.v4.runtime.CommonTokenStream import org.antlr.v4.runtime.tree.ParseTree -object VimscriptParser { +object VimscriptParser : com.maddyhome.idea.vim.api.VimscriptParser { private val logger = logger() val linesWithErrors = mutableListOf() private const val MAX_NUMBER_OF_TRIES = 5 var tries = 0 - fun parse(text: String): Script { - val preprocessedText = uncommentIdeaVimIgnore(getTextWithoutErrors(text)) + override fun parse(script: String): Script { + val preprocessedText = uncommentIdeaVimIgnore(getTextWithoutErrors(script)) linesWithErrors.clear() val parser = getParser(preprocessedText + "\n", true) // grammar expects that any script ends with a newline character @@ -63,8 +63,8 @@ object VimscriptParser { } } - fun parseExpression(text: String): Expression? { - val parser = getParser(text, true) + override fun parseExpression(expression: String): Expression? { + val parser = getParser(expression, true) val AST: ParseTree = parser.expr() if (linesWithErrors.isNotEmpty()) { linesWithErrors.clear() @@ -73,8 +73,8 @@ object VimscriptParser { return ExpressionVisitor.visit(AST) } - fun parseCommand(text: String): Command? { - val textToParse = text.replace("\n", "") + "\n" // grammar expects that any command ends with a newline character + override fun parseCommand(command: String): Command? { + val textToParse = command.replace("\n", "") + "\n" // grammar expects that any command ends with a newline character val parser = getParser(textToParse, true) val AST: ParseTree = parser.command() if (linesWithErrors.isNotEmpty()) { diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/services/FunctionStorage.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/services/FunctionStorage.kt index 03fea51699c..0954b33dc52 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/services/FunctionStorage.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/services/FunctionStorage.kt @@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.vimscript.services import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.extensions.ExtensionPointName +import com.maddyhome.idea.vim.api.VimscriptFunctionService import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext import com.maddyhome.idea.vim.vimscript.model.Script @@ -30,7 +31,7 @@ import com.maddyhome.idea.vim.vimscript.model.functions.FunctionBeanClass import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration -object FunctionStorage { +object FunctionStorage : VimscriptFunctionService { private val logger = logger() @@ -39,7 +40,7 @@ object FunctionStorage { private val extensionPoint = ExtensionPointName.create("IdeaVIM.vimLibraryFunction") private val builtInFunctions: MutableMap = mutableMapOf() - fun deleteFunction(name: String, scope: Scope? = null, vimContext: VimLContext) { + override fun deleteFunction(name: String, scope: Scope?, vimContext: VimLContext) { if (name[0].isLowerCase() && scope != Scope.SCRIPT_VARIABLE) { throw ExException("E128: Function name must start with a capital or \"s:\": $name") } @@ -84,7 +85,7 @@ object FunctionStorage { throw ExException("E130: Unknown function: $name") } - fun storeFunction(declaration: FunctionDeclaration) { + override fun storeFunction(declaration: FunctionDeclaration) { val scope: Scope = declaration.scope ?: getDefaultFunctionScope() when (scope) { Scope.GLOBAL_VARIABLE -> { @@ -109,12 +110,12 @@ object FunctionStorage { } } - fun getFunctionHandler(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler { + override fun getFunctionHandler(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler { return getFunctionHandlerOrNull(scope, name, vimContext) ?: throw ExException("E117: Unknown function: ${scope?.toString() ?: ""}$name") } - fun getFunctionHandlerOrNull(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler? { + override fun getFunctionHandlerOrNull(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler? { if (scope == null) { val builtInFunction = getBuiltInFunction(name) if (builtInFunction != null) { @@ -129,7 +130,7 @@ object FunctionStorage { return null } - fun getUserDefinedFunction(scope: Scope?, name: String, vimContext: VimLContext): FunctionDeclaration? { + override fun getUserDefinedFunction(scope: Scope?, name: String, vimContext: VimLContext): FunctionDeclaration? { return when (scope) { Scope.GLOBAL_VARIABLE -> globalFunctions[name] Scope.SCRIPT_VARIABLE -> getScriptFunction(name, vimContext) @@ -145,7 +146,7 @@ object FunctionStorage { } } - fun getBuiltInFunction(name: String): FunctionHandler? { + override fun getBuiltInFunction(name: String): FunctionHandler? { return builtInFunctions[name] } @@ -171,11 +172,12 @@ object FunctionStorage { return Scope.GLOBAL_VARIABLE } - fun registerHandlers() { + override fun registerHandlers() { extensionPoint.extensions().forEach(FunctionBeanClass::register) } - fun addHandler(handlerHolder: FunctionBeanClass) { + override fun addHandler(handlerHolder: Any) { + handlerHolder as FunctionBeanClass if (handlerHolder.name != null) { builtInFunctions[handlerHolder.name!!] = handlerHolder.instance } else { diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/services/VariableServiceImpl.kt b/src/main/java/com/maddyhome/idea/vim/vimscript/services/VariableServiceImpl.kt index be4af4c0f5c..c1b6c90a51c 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/services/VariableServiceImpl.kt +++ b/src/main/java/com/maddyhome/idea/vim/vimscript/services/VariableServiceImpl.kt @@ -18,11 +18,12 @@ package com.maddyhome.idea.vim.vimscript.services -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor import com.intellij.openapi.util.Key +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.vimscript.VimScriptGlobalEnvironment +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.model.ExecutableContext import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimBlob @@ -51,22 +52,22 @@ internal class VariableServiceImpl : VariableService { } } - override fun isVariableLocked(variable: Variable, editor: Editor, context: DataContext, vimContext: VimLContext): Boolean { + override fun isVariableLocked(variable: Variable, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): Boolean { return getNullableVariableValue(variable, editor, context, vimContext)?.isLocked ?: false } - override fun lockVariable(variable: Variable, depth: Int, editor: Editor, context: DataContext, vimContext: VimLContext) { + override fun lockVariable(variable: Variable, depth: Int, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) { val value = getNullableVariableValue(variable, editor, context, vimContext) ?: return value.lockOwner = variable value.lockVar(depth) } - override fun unlockVariable(variable: Variable, depth: Int, editor: Editor, context: DataContext, vimContext: VimLContext) { + override fun unlockVariable(variable: Variable, depth: Int, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) { val value = getNullableVariableValue(variable, editor, context, vimContext) ?: return value.unlockVar(depth) } - override fun storeVariable(variable: Variable, value: VimDataType, editor: Editor, context: DataContext, vimContext: VimLContext) { + override fun storeVariable(variable: Variable, value: VimDataType, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) { val scope = variable.scope ?: getDefaultVariableScope(vimContext) when (scope) { Scope.GLOBAL_VARIABLE -> { @@ -78,48 +79,48 @@ internal class VariableServiceImpl : VariableService { Scope.SCRIPT_VARIABLE -> storeScriptVariable(variable.name.evaluate(editor, context, vimContext).value, value, vimContext) Scope.WINDOW_VARIABLE, Scope.TABPAGE_VARIABLE -> { val variableKey = scope.c + ":" + variable.name - if (editor.getUserData(tabAndWindowVariablesKey) == null) { - editor.putUserData(tabAndWindowVariablesKey, mutableMapOf(variableKey to value)) + if (editor.ij.getUserData(tabAndWindowVariablesKey) == null) { + editor.ij.putUserData(tabAndWindowVariablesKey, mutableMapOf(variableKey to value)) } else { - editor.getUserData(tabAndWindowVariablesKey)!![variableKey] = value + editor.ij.getUserData(tabAndWindowVariablesKey)!![variableKey] = value } } Scope.FUNCTION_VARIABLE -> storeFunctionVariable(variable.name.evaluate(editor, context, vimContext).value, value, vimContext) Scope.LOCAL_VARIABLE -> storeLocalVariable(variable.name.evaluate(editor, context, vimContext).value, value, vimContext) Scope.BUFFER_VARIABLE -> { - if (editor.document.getUserData(bufferVariablesKey) == null) { - editor.document.putUserData(bufferVariablesKey, mutableMapOf(variable.name.evaluate(editor, context, vimContext).value to value)) + if (editor.ij.document.getUserData(bufferVariablesKey) == null) { + editor.ij.document.putUserData(bufferVariablesKey, mutableMapOf(variable.name.evaluate(editor, context, vimContext).value to value)) } else { - editor.document.getUserData(bufferVariablesKey)!![variable.name.evaluate(editor, context, vimContext).value] = value + editor.ij.document.getUserData(bufferVariablesKey)!![variable.name.evaluate(editor, context, vimContext).value] = value } } Scope.VIM_VARIABLE -> throw ExException("The 'v:' scope is not implemented yet :(") } } - override fun getNullableVariableValue(variable: Variable, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType? { + override fun getNullableVariableValue(variable: Variable, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType? { val scope = variable.scope ?: getDefaultVariableScope(vimContext) return when (scope) { Scope.GLOBAL_VARIABLE -> getGlobalVariableValue(variable.name.evaluate(editor, context, vimContext).value) Scope.SCRIPT_VARIABLE -> getScriptVariable(variable.name.evaluate(editor, context, vimContext).value, vimContext) Scope.WINDOW_VARIABLE, Scope.TABPAGE_VARIABLE -> { val variableKey = scope.c + ":" + variable.name - editor.getUserData(tabAndWindowVariablesKey)?.get(variableKey) + editor.ij.getUserData(tabAndWindowVariablesKey)?.get(variableKey) } Scope.FUNCTION_VARIABLE -> getFunctionVariable(variable.name.evaluate(editor, context, vimContext).value, vimContext) Scope.LOCAL_VARIABLE -> getLocalVariable(variable.name.evaluate(editor, context, vimContext).value, vimContext) Scope.BUFFER_VARIABLE -> { - editor.document.getUserData(bufferVariablesKey)?.get(variable.name.evaluate(editor, context, vimContext).value) + editor.ij.document.getUserData(bufferVariablesKey)?.get(variable.name.evaluate(editor, context, vimContext).value) } Scope.VIM_VARIABLE -> throw ExException("The 'v:' scope is not implemented yet :(") } } - override fun getNonNullVariableValue(variable: Variable, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun getNonNullVariableValue(variable: Variable, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { return getNullableVariableValue(variable, editor, context, vimContext) ?: throw ExException( "E121: Undefined variable: " + - (if (variable.scope != null) variable.scope.c + ":" else "") + + (if (variable.scope != null) variable.scope!!.c + ":" else "") + variable.name.evaluate(editor, context, vimContext).value ) } diff --git a/src/main/resources/META-INF/includes/ApplicationServices.xml b/src/main/resources/META-INF/includes/ApplicationServices.xml index 2600b4e0f1f..78c8dd91f77 100644 --- a/src/main/resources/META-INF/includes/ApplicationServices.xml +++ b/src/main/resources/META-INF/includes/ApplicationServices.xml @@ -27,6 +27,8 @@ + diff --git a/src/test/java/org/jetbrains/plugins/ideavim/ex/CommandParserTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/ex/CommandParserTest.kt index 0be079276b9..b6b782d80b6 100644 --- a/src/test/java/org/jetbrains/plugins/ideavim/ex/CommandParserTest.kt +++ b/src/test/java/org/jetbrains/plugins/ideavim/ex/CommandParserTest.kt @@ -22,6 +22,7 @@ import com.intellij.openapi.actionSystem.DataContext import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.command.CommandState import com.maddyhome.idea.vim.helper.StringHelper +import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.Executor import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext import com.maddyhome.idea.vim.vimscript.model.commands.EchoCommand @@ -319,7 +320,7 @@ class CommandParserTest : VimTestCase() { nnoremap Y y${'$'} """.trimIndent().replace("\n", "\r\n"), - myFixture.editor, DataContext.EMPTY_CONTEXT, skipHistory = true, indicateErrors = true, CommandLineVimLContext + myFixture.editor.vim, DataContext.EMPTY_CONTEXT.vim, skipHistory = true, indicateErrors = true, CommandLineVimLContext ) typeText(StringHelper.parseKeys("Yp")) assertState("----------\n1234556789${c}067890\n----------\n") diff --git a/src/test/java/org/jetbrains/plugins/ideavim/ex/ExpressionTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/ex/ExpressionTest.kt index b95529486fa..08937a57218 100644 --- a/src/test/java/org/jetbrains/plugins/ideavim/ex/ExpressionTest.kt +++ b/src/test/java/org/jetbrains/plugins/ideavim/ex/ExpressionTest.kt @@ -20,6 +20,7 @@ package org.jetbrains.plugins.ideavim.ex import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.editor.textarea.TextComponentEditorImpl +import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.model.CommandLineVimLContext import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -29,5 +30,5 @@ import javax.swing.JTextArea fun Expression.evaluate(vimContext: VimLContext = CommandLineVimLContext): VimDataType { val editor = TextComponentEditorImpl(null, JTextArea()) val context = DataContext.EMPTY_CONTEXT - return this.evaluate(editor, context, vimContext) + return this.evaluate(editor.vim, context.vim, vimContext) } diff --git a/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/MapCommandTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/MapCommandTest.kt index 0d3926e90ac..c736c89f798 100644 --- a/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/MapCommandTest.kt +++ b/src/test/java/org/jetbrains/plugins/ideavim/ex/implementation/commands/MapCommandTest.kt @@ -23,6 +23,7 @@ import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.command.CommandState import com.maddyhome.idea.vim.helper.StringHelper import com.maddyhome.idea.vim.helper.StringHelper.parseKeys +import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.vimscript.Executor import junit.framework.TestCase import org.jetbrains.plugins.ideavim.SkipNeovimReason @@ -779,7 +780,7 @@ n ,f Foo let s:mapping = '^f8a' nnoremap t s:mapping """.trimIndent(), - editor, context, skipHistory = false, indicateErrors = true, null + editor.vim, context.vim, skipHistory = false, indicateErrors = true, null ) typeText(parseKeys("t")) assertPluginError(true) diff --git a/src/test/java/org/jetbrains/plugins/ideavim/extension/CommonExtensionTests.kt b/src/test/java/org/jetbrains/plugins/ideavim/extension/CommonExtensionTests.kt index 60434c9ed93..9f0ce74fda5 100644 --- a/src/test/java/org/jetbrains/plugins/ideavim/extension/CommonExtensionTests.kt +++ b/src/test/java/org/jetbrains/plugins/ideavim/extension/CommonExtensionTests.kt @@ -41,7 +41,7 @@ import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.option.OptionsManager import com.maddyhome.idea.vim.option.ToggleOption import com.maddyhome.idea.vim.vimscript.Executor -import com.maddyhome.idea.vim.vimscript.Executor.executingVimScript +import com.maddyhome.idea.vim.vimscript.Executor.executingVimscript import junit.framework.TestCase import org.jetbrains.plugins.ideavim.SkipNeovimReason import org.jetbrains.plugins.ideavim.TestWithoutNeovim @@ -316,9 +316,9 @@ class PlugMissingKeysTest : VimTestCase() { } private fun executeLikeVimrc(vararg text: String) { - executingVimScript = true + executingVimscript = true Executor.execute(text.joinToString("\n"), false) - executingVimScript = false + executingVimscript = false VimExtensionRegistrar.enableDelayedExtensions() } } diff --git a/src/test/java/org/jetbrains/plugins/ideavim/mock/MockTestCase.kt b/src/test/java/org/jetbrains/plugins/ideavim/mock/MockTestCase.kt index d1c434ccfa6..97bc3031bc6 100644 --- a/src/test/java/org/jetbrains/plugins/ideavim/mock/MockTestCase.kt +++ b/src/test/java/org/jetbrains/plugins/ideavim/mock/MockTestCase.kt @@ -22,14 +22,16 @@ import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.editor.textarea.TextComponentEditorImpl import com.intellij.testFramework.replaceService +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.newapi.vim import org.jetbrains.plugins.ideavim.VimTestCase import org.mockito.Mockito import javax.swing.JTextArea open class MockTestCase : VimTestCase() { - val editorStub = TextComponentEditorImpl(null, JTextArea()) - val contextStub: DataContext = DataContext.EMPTY_CONTEXT + val editorStub = TextComponentEditorImpl(null, JTextArea()).vim + val contextStub: ExecutionContext = DataContext.EMPTY_CONTEXT.vim fun mockService(service: Class): T { val mock = Mockito.mock(service) diff --git a/src/test/java/org/jetbrains/plugins/ideavim/mock/vimscript/commands/TabmoveTest.kt b/src/test/java/org/jetbrains/plugins/ideavim/mock/vimscript/commands/TabmoveTest.kt index 97449360f0f..10a8d2faf9a 100644 --- a/src/test/java/org/jetbrains/plugins/ideavim/mock/vimscript/commands/TabmoveTest.kt +++ b/src/test/java/org/jetbrains/plugins/ideavim/mock/vimscript/commands/TabmoveTest.kt @@ -19,6 +19,7 @@ package org.jetbrains.plugins.ideavim.mock.vimscript.commands import com.maddyhome.idea.vim.group.TabService +import com.maddyhome.idea.vim.newapi.ij import com.maddyhome.idea.vim.vimscript.Executor import org.jetbrains.plugins.ideavim.mock.MockTestCase import org.mockito.Mockito @@ -30,44 +31,44 @@ class TabmoveTest : MockTestCase() { fun `test move to the first index`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(2) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(2) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove 0", editorStub, contextStub, skipHistory = false) - verify(tabService).moveCurrentTabToIndex(0, contextStub) + verify(tabService).moveCurrentTabToIndex(0, contextStub.ij) } fun `test move to the last index`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(2) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(2) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove $", editorStub, contextStub, skipHistory = false) - verify(tabService).moveCurrentTabToIndex(4, contextStub) + verify(tabService).moveCurrentTabToIndex(4, contextStub.ij) } fun `test move to index that is greater than current`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(4) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(4) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove 2", editorStub, contextStub, skipHistory = false) - verify(tabService).moveCurrentTabToIndex(2, contextStub) + verify(tabService).moveCurrentTabToIndex(2, contextStub.ij) } fun `test move to index that is less than current`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(1) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(1) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove 3", editorStub, contextStub, skipHistory = false) - verify(tabService).moveCurrentTabToIndex(2, contextStub) + verify(tabService).moveCurrentTabToIndex(2, contextStub.ij) } fun `test move to nonexistent index`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(2) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(2) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove 7", editorStub, contextStub, skipHistory = false) assertPluginError(true) @@ -77,26 +78,26 @@ class TabmoveTest : MockTestCase() { fun `test move to positive relative index`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(2) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(2) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove +2", editorStub, contextStub, skipHistory = false) - verify(tabService).moveCurrentTabToIndex(4, contextStub) + verify(tabService).moveCurrentTabToIndex(4, contextStub.ij) } fun `test move to negative relative index`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(4) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(4) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove -2", editorStub, contextStub, skipHistory = false) - verify(tabService).moveCurrentTabToIndex(2, contextStub) + verify(tabService).moveCurrentTabToIndex(2, contextStub.ij) } fun `test move to nonexistent positive relative index`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(2) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(2) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove +10", editorStub, contextStub, skipHistory = false) assertPluginError(true) @@ -106,8 +107,8 @@ class TabmoveTest : MockTestCase() { fun `test move to nonexistent negative relative index`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(2) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(2) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove -10", editorStub, contextStub, skipHistory = false) assertPluginError(true) @@ -117,8 +118,8 @@ class TabmoveTest : MockTestCase() { fun `test move to plus zero`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(2) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(2) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove +0", editorStub, contextStub, skipHistory = false) assertPluginError(true) @@ -128,8 +129,8 @@ class TabmoveTest : MockTestCase() { fun `test move to minus zero`() { val tabService = mockService(TabService::class.java) - Mockito.`when`(tabService.getCurrentTabIndex(contextStub)).thenReturn(2) - Mockito.`when`(tabService.getTabCount(contextStub)).thenReturn(5) + Mockito.`when`(tabService.getCurrentTabIndex(contextStub.ij)).thenReturn(2) + Mockito.`when`(tabService.getTabCount(contextStub.ij)).thenReturn(5) Executor.execute("tabmove +0", editorStub, contextStub, skipHistory = false) assertPluginError(true) diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/EngineEditorHelper.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/EngineEditorHelper.kt index 23309f93d40..8db761a33b1 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/EngineEditorHelper.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/EngineEditorHelper.kt @@ -1,6 +1,7 @@ package com.maddyhome.idea.vim.api import com.maddyhome.idea.vim.common.TextRange +import java.nio.CharBuffer interface EngineEditorHelper { fun normalizeOffset(editor: VimEditor, offset: Int, allowEnd: Boolean): Int @@ -23,4 +24,5 @@ interface EngineEditorHelper { fun getVisualLineAtTopOfScreen(editor: VimEditor): Int fun getApproximateScreenWidth(editor: VimEditor): Int fun handleWithReadonlyFragmentModificationHandler(editor: VimEditor, exception: java.lang.Exception) + fun getLineBuffer(editor: VimEditor, line: Int): CharBuffer } \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimApplication.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimApplication.kt index ffc20e82da8..57b7a33f032 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimApplication.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimApplication.kt @@ -30,4 +30,7 @@ interface VimApplication { fun runWriteCommand(editor: VimEditor, name: String?, groupId: Any?, command: Runnable) fun runReadCommand(editor: VimEditor, name: String?, groupId: Any?, command: Runnable) + + fun runWriteAction(action: () -> T): T + fun runReadAction(action: () -> T): T } diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimCaret.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimCaret.kt index 86915b6b377..70ccfc6b8aa 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimCaret.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimCaret.kt @@ -15,6 +15,7 @@ interface VimCaret { val vimLeadSelectionOffset: Int var vimLastVisualOperatorRange: VisualChange? fun moveToOffset(offset: Int) + fun moveToLogicalPosition(logicalPosition: VimLogicalPosition) fun offsetForLineStartSkipLeading(line: Int): Int fun getLine(): EditorLine.Pointer fun hasSelection(): Boolean diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimEditor.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimEditor.kt index 0df4a55c6ba..9244ec91a10 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimEditor.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimEditor.kt @@ -162,6 +162,7 @@ interface VimEditor { fun currentCaret(): VimCaret fun isWritable(): Boolean + fun isDocumentWritable(): Boolean fun isOneLineMode(): Boolean /** * Function for refactoring, get rid of it @@ -186,6 +187,7 @@ interface VimEditor { fun removeSecondaryCarets() fun vimSetSystemBlockSelectionSilently(start: VimLogicalPosition, end: VimLogicalPosition) + fun getLineStartOffset(line: Int): Int fun getLineEndOffset(line: Int, allowEnd: Boolean): Int fun addCaretListener(listener: VimCaretListener) diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimInjector.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimInjector.kt index 1e3fcee96b4..4f0e532f68f 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimInjector.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimInjector.kt @@ -7,6 +7,7 @@ import com.maddyhome.idea.vim.mark.VimMarkGroup import com.maddyhome.idea.vim.options.OptionService import com.maddyhome.idea.vim.put.VimPut import com.maddyhome.idea.vim.register.VimRegisterGroup +import com.maddyhome.idea.vim.vimscript.services.VariableService interface VimInjector { val parser: VimStringParser @@ -39,9 +40,15 @@ interface VimInjector { val lookupManager: VimLookupManager val templateManager: VimTemplateManager val searchGroup: VimSearchGroup -// val statisticsService: VimStatistics + val statisticsService: VimStatistics val put: VimPut + val vimscriptExecutor: VimscriptExecutor + val vimscriptParser: VimscriptParser + val variableService: VariableService + val functionService: VimscriptFunctionService + val vimrcFileState: VimrcFileState + /** * Please use vimLogger() function */ diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMessages.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMessages.kt index a2e5d3b64ce..1ee3b1553fd 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMessages.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimMessages.kt @@ -24,7 +24,7 @@ interface VimMessages { fun indicateError() fun clearError() fun isError(): Boolean - fun message(key: String): String + fun message(key: String, vararg params: Any): String fun updateStatusBar() diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimScriptExecutorBase.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimScriptExecutorBase.kt new file mode 100644 index 00000000000..7eda27cf3b4 --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimScriptExecutorBase.kt @@ -0,0 +1,4 @@ +package com.maddyhome.idea.vim.api + +abstract class VimScriptExecutorBase: VimscriptExecutor { +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimSearchGroup.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimSearchGroup.kt index 7358fa8533e..c234d062dc7 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimSearchGroup.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimSearchGroup.kt @@ -1,9 +1,13 @@ package com.maddyhome.idea.vim.api +import com.maddyhome.idea.vim.common.Direction import com.maddyhome.idea.vim.common.TextRange interface VimSearchGroup { + var lastSearchPattern: String? + var lastSubstitutePattern: String? fun findUnderCaret(editor: VimEditor): TextRange? fun searchBackward(editor: VimEditor, offset: Int, count: Int): TextRange? fun getNextSearchRange(editor: VimEditor, count: Int, forwards: Boolean): TextRange? + fun processSearchRange(editor: VimEditor, pattern: String, patternOffset: Int, startOffset: Int, direction: Direction): Int } \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStatistics.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStatistics.kt new file mode 100644 index 00000000000..97b7cd9cbf5 --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStatistics.kt @@ -0,0 +1,10 @@ +package com.maddyhome.idea.vim.api + +interface VimStatistics { + fun logTrackedAction(actionId: String) + fun logCopiedAction(actionId: String) + fun setIfIfUsed(value: Boolean) + fun setIfFunctionCallUsed(value: Boolean) + fun setIfFunctionDeclarationUsed(value: Boolean) + fun setIfLoopUsed(value: Boolean) +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStringParser.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStringParser.kt index 76d548dfd58..a26fdf3a45d 100644 --- a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStringParser.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimStringParser.kt @@ -6,4 +6,6 @@ interface VimStringParser { val plugKeyStroke: KeyStroke fun parseKeys(vararg strings: String): List fun stringToKeys(string: String): List + fun toKeyNotation(keyStroke: KeyStroke): String + fun toKeyNotation(keyStrokes: List): String } diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimrcFileState.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimrcFileState.kt new file mode 100644 index 00000000000..245c62d57d6 --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimrcFileState.kt @@ -0,0 +1,7 @@ +package com.maddyhome.idea.vim.api + +interface VimrcFileState { + var filePath: String? + + fun saveFileState(filePath: String) +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptExecutor.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptExecutor.kt new file mode 100644 index 00000000000..7ee3b27c512 --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptExecutor.kt @@ -0,0 +1,18 @@ +package com.maddyhome.idea.vim.api + +import com.maddyhome.idea.vim.vimscript.model.ExecutionResult +import com.maddyhome.idea.vim.vimscript.model.VimLContext +import java.io.File + +interface VimscriptExecutor { + + var executingVimscript: Boolean + + fun execute(script: String, editor: VimEditor, context: ExecutionContext, skipHistory: Boolean, indicateErrors: Boolean = true, vimContext: VimLContext? = null): ExecutionResult + + fun execute(script: String, skipHistory: Boolean = true) + + fun executeFile(file: File, indicateErrors: Boolean = false) + + fun executeLastCommand(editor: VimEditor, context: ExecutionContext): Boolean +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptFunctionService.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptFunctionService.kt new file mode 100644 index 00000000000..b865d984e44 --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptFunctionService.kt @@ -0,0 +1,18 @@ +package com.maddyhome.idea.vim.api + +import com.maddyhome.idea.vim.vimscript.model.VimLContext +import com.maddyhome.idea.vim.vimscript.model.expressions.Scope +import com.maddyhome.idea.vim.vimscript.model.functions.FunctionHandler +import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration + +interface VimscriptFunctionService { + + fun deleteFunction(name: String, scope: Scope? = null, vimContext: VimLContext) + fun storeFunction(declaration: FunctionDeclaration) + fun getFunctionHandler(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler + fun getFunctionHandlerOrNull(scope: Scope?, name: String, vimContext: VimLContext): FunctionHandler? + fun getUserDefinedFunction(scope: Scope?, name: String, vimContext: VimLContext): FunctionDeclaration? + fun getBuiltInFunction(name: String): FunctionHandler? + fun registerHandlers() + fun addHandler(handlerHolder: Any) +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptParser.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptParser.kt new file mode 100644 index 00000000000..d1a75962255 --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/api/VimscriptParser.kt @@ -0,0 +1,12 @@ +package com.maddyhome.idea.vim.api + +import com.maddyhome.idea.vim.vimscript.model.Script +import com.maddyhome.idea.vim.vimscript.model.commands.Command +import com.maddyhome.idea.vim.vimscript.model.expressions.Expression + +interface VimscriptParser { + + fun parse(script: String): Script + fun parseCommand(command: String): Command? + fun parseExpression(expression: String): Expression? +} \ No newline at end of file diff --git a/src/main/java/com/maddyhome/idea/vim/ex/ExExceptions.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ExExceptions.kt similarity index 80% rename from src/main/java/com/maddyhome/idea/vim/ex/ExExceptions.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ExExceptions.kt index a305b27f85c..b44d31cffb4 100644 --- a/src/main/java/com/maddyhome/idea/vim/ex/ExExceptions.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ExExceptions.kt @@ -17,8 +17,7 @@ */ package com.maddyhome.idea.vim.ex -import com.maddyhome.idea.vim.helper.MessageHelper -import org.jetbrains.annotations.PropertyKey +import com.maddyhome.idea.vim.api.injector class InvalidCommandException(message: String, cmd: String?) : ExException(message + if (cmd != null) " | $cmd" else "") @@ -34,5 +33,5 @@ class NoRangeAllowedException : ExException() class FinishException : ExException() -fun exExceptionMessage(@PropertyKey(resourceBundle = MessageHelper.BUNDLE) code: String, vararg params: Any) = - ExException(MessageHelper.message(code, *params)).apply { this.code = code } +fun exExceptionMessage(code: String, vararg params: Any) = + ExException(injector.messages.message(code, *params)).apply { this.code = code } diff --git a/src/main/java/com/maddyhome/idea/vim/ex/ranges/ExRanges.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ranges/ExRanges.kt similarity index 83% rename from src/main/java/com/maddyhome/idea/vim/ex/ranges/ExRanges.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ranges/ExRanges.kt index 5258448877e..ec0fab2a7ce 100644 --- a/src/main/java/com/maddyhome/idea/vim/ex/ranges/ExRanges.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ranges/ExRanges.kt @@ -17,14 +17,13 @@ */ package com.maddyhome.idea.vim.ex.ranges -import com.intellij.openapi.diagnostic.debug -import com.intellij.openapi.diagnostic.logger -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor -import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.common.Direction -import com.maddyhome.idea.vim.helper.EditorHelper -import com.maddyhome.idea.vim.newapi.vim +import com.maddyhome.idea.vim.diagnostic.VimLogger +import com.maddyhome.idea.vim.diagnostic.debug +import com.maddyhome.idea.vim.diagnostic.vimLogger import java.util.* /** @@ -42,12 +41,12 @@ sealed class Range( * @param lastZero True if last line was set to start of file * @return The zero based line number, -1 if unable to get the line number */ - fun getLine(editor: Editor, lastZero: Boolean): Int { + fun getLine(editor: VimEditor, lastZero: Boolean): Int { val line = getRangeLine(editor, lastZero) return line + offset } - fun getLine(editor: Editor, caret: Caret, lastZero: Boolean): Int { + fun getLine(editor: VimEditor, caret: VimCaret, lastZero: Boolean): Int { return if (offset == 0) getRangeLine(editor, lastZero) else getRangeLine(editor, caret, lastZero) + offset } @@ -60,9 +59,9 @@ sealed class Range( * @param lastZero True if last line was set to start of file * @return The zero based line number, -1 if inable to get the line number */ - protected abstract fun getRangeLine(editor: Editor, lastZero: Boolean): Int + protected abstract fun getRangeLine(editor: VimEditor, lastZero: Boolean): Int - protected abstract fun getRangeLine(editor: Editor, caret: Caret, lastZero: Boolean): Int + protected abstract fun getRangeLine(editor: VimEditor, caret: VimCaret, lastZero: Boolean): Int override fun equals(other: Any?): Boolean { if (this === other) return true @@ -151,21 +150,21 @@ class LineNumberRange : Range { * @param lastZero True if last line was set to start of file * @return The zero based line number, -1 for start of file */ - override fun getRangeLine(editor: Editor, lastZero: Boolean): Int { + override fun getRangeLine(editor: VimEditor, lastZero: Boolean): Int { if (line == CURRENT_LINE) { - line = editor.caretModel.logicalPosition.line + line = editor.currentCaret().getLogicalPosition().line } else if (line == LAST_LINE) { - line = EditorHelper.getLineCount(editor) - 1 + line = editor.lineCount() - 1 } return line } override fun getRangeLine( - editor: Editor, - caret: Caret, + editor: VimEditor, + caret: VimCaret, lastZero: Boolean, ): Int { - line = if (line == LAST_LINE) EditorHelper.getLineCount(editor) - 1 else caret.logicalPosition.line + line = if (line == LAST_LINE) editor.lineCount() - 1 else caret.getLogicalPosition().line return line } @@ -207,12 +206,12 @@ class MarkRange(private val mark: Char, offset: Int, move: Boolean) : Range(offs * @param lastZero True if last line was set to start of file * @return The zero based line number, -1 if there is no such mark set in the file */ - override fun getRangeLine(editor: Editor, lastZero: Boolean): Int { - val mark = VimPlugin.getMark().getFileMark(editor.vim, mark) + override fun getRangeLine(editor: VimEditor, lastZero: Boolean): Int { + val mark = injector.markGroup.getFileMark(editor, mark) return mark?.logicalLine ?: -1 } - override fun getRangeLine(editor: Editor, caret: Caret, lastZero: Boolean): Int = getRangeLine(editor, lastZero) + override fun getRangeLine(editor: VimEditor, caret: VimCaret, lastZero: Boolean): Int = getRangeLine(editor, lastZero) override fun toString(): String = "MarkRange[mark=$mark, ${super.toString()}]" override fun equals(other: Any?): Boolean { @@ -253,15 +252,15 @@ class SearchRange(pattern: String, offset: Int, move: Boolean) : Range(offset, m var pat = tok.nextToken() when (pat) { "\\/" -> { - patterns.add(VimPlugin.getSearch().lastSearchPattern) + patterns.add(injector.searchGroup.lastSearchPattern) directions.add(Direction.FORWARDS) } "\\?" -> { - patterns.add(VimPlugin.getSearch().lastSearchPattern) + patterns.add(injector.searchGroup.lastSearchPattern) directions.add(Direction.BACKWARDS) } "\\&" -> { - patterns.add(VimPlugin.getSearch().lastSubstitutePattern) + patterns.add(injector.searchGroup.lastSubstitutePattern) directions.add(Direction.FORWARDS) } else -> { @@ -289,18 +288,18 @@ class SearchRange(pattern: String, offset: Int, move: Boolean) : Range(offset, m * @return The zero based line number, -1 if the text was not found */ override fun getRangeLine( - editor: Editor, + editor: VimEditor, lastZero: Boolean, ): Int { // Each subsequent pattern is searched for starting in the line after the previous search match - return getRangeLine(editor, editor.caretModel.currentCaret, lastZero) + return getRangeLine(editor, editor.currentCaret(), lastZero) } override fun getRangeLine( - editor: Editor, - caret: Caret, + editor: VimEditor, + caret: VimCaret, lastZero: Boolean, ): Int { - var line = caret.logicalPosition.line + var line = caret.getLogicalPosition().line var searchOffset = -1 for (i in patterns.indices) { val pattern = patterns[i] @@ -313,18 +312,18 @@ class SearchRange(pattern: String, offset: Int, move: Boolean) : Range(offset, m val patternOffset = if (i == patterns.size - 1) offset else 0 searchOffset = getSearchOffset(editor, line, direction, lastZero) - searchOffset = VimPlugin.getSearch().processSearchRange(editor, pattern!!, patternOffset, searchOffset, direction) + searchOffset = injector.searchGroup.processSearchRange(editor, pattern!!, patternOffset, searchOffset, direction) if (searchOffset == -1) break line = editor.offsetToLogicalPosition(searchOffset).line } return if (searchOffset != -1) line else -1 } - private fun getSearchOffset(editor: Editor, line: Int, direction: Direction, lastZero: Boolean): Int { + private fun getSearchOffset(editor: VimEditor, line: Int, direction: Direction, lastZero: Boolean): Int { return if (direction == Direction.FORWARDS && !lastZero) { - VimPlugin.getMotion().moveCaretToLineEnd(editor.vim, line, true) + injector.motion.moveCaretToLineEnd(editor, line, true) } else { - VimPlugin.getMotion().moveCaretToLineStart(editor.vim, line) + injector.motion.moveCaretToLineStart(editor, line) } } @@ -356,7 +355,7 @@ class SearchRange(pattern: String, offset: Int, move: Boolean) : Range(offset, m private val directions: MutableList = mutableListOf() companion object { - private val logger = logger() + private val logger = vimLogger() } init { diff --git a/src/main/java/com/maddyhome/idea/vim/ex/ranges/Ranges.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ranges/Ranges.kt similarity index 73% rename from src/main/java/com/maddyhome/idea/vim/ex/ranges/Ranges.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ranges/Ranges.kt index c594ceba205..d6cb7133422 100644 --- a/src/main/java/com/maddyhome/idea/vim/ex/ranges/Ranges.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/ex/ranges/Ranges.kt @@ -17,15 +17,10 @@ */ package com.maddyhome.idea.vim.ex.ranges -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor -import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.common.TextRange -import com.maddyhome.idea.vim.group.MotionGroup -import com.maddyhome.idea.vim.helper.EditorHelper -import com.maddyhome.idea.vim.helper.fileSize -import com.maddyhome.idea.vim.newapi.IjVimCaret -import com.maddyhome.idea.vim.newapi.IjVimEditor import org.jetbrains.annotations.NonNls import kotlin.math.min @@ -57,17 +52,17 @@ class Ranges { * @param editor The editor to get the line for * @return The line number represented by the range */ - fun getLine(editor: Editor): Int { + fun getLine(editor: VimEditor): Int { processRange(editor) return endLine } - fun getLine(editor: Editor, caret: Caret): Int { + fun getLine(editor: VimEditor, caret: VimCaret): Int { processRange(editor, caret) return endLine } - fun getFirstLine(editor: Editor, caret: Caret): Int { + fun getFirstLine(editor: VimEditor, caret: VimCaret): Int { processRange(editor, caret) return startLine } @@ -80,9 +75,9 @@ class Ranges { * @param count The count given at the end of the command or -1 if no such count (use end line) * @return count if count != -1, else return end line of range */ - fun getCount(editor: Editor, count: Int): Int = if (count == -1) getLine(editor) else count + fun getCount(editor: VimEditor, count: Int): Int = if (count == -1) getLine(editor) else count - fun getCount(editor: Editor, caret: Caret, count: Int): Int { + fun getCount(editor: VimEditor, caret: VimCaret, count: Int): Int { return if (count == -1) getLine(editor, caret) else count } @@ -94,7 +89,7 @@ class Ranges { * @param count The count given at the end of the command or -1 if no such count * @return The line range */ - fun getLineRange(editor: Editor, count: Int): LineRange { + fun getLineRange(editor: VimEditor, count: Int): LineRange { processRange(editor) val end: Int val start: Int @@ -108,7 +103,7 @@ class Ranges { return LineRange(start, end) } - fun getLineRange(editor: Editor, caret: Caret, count: Int): LineRange { + fun getLineRange(editor: VimEditor, caret: VimCaret, count: Int): LineRange { processRange(editor, caret) return if (count == -1) LineRange(startLine, endLine) else LineRange(endLine, endLine + count - 1) } @@ -122,18 +117,18 @@ class Ranges { * @param count The count given at the end of the command or -1 if no such count * @return The text range */ - fun getTextRange(editor: Editor, count: Int): TextRange { + fun getTextRange(editor: VimEditor, count: Int): TextRange { val lr = getLineRange(editor, count) - val start = EditorHelper.getLineStartOffset(editor, lr.startLine) - val end = EditorHelper.getLineEndOffset(editor, lr.endLine, true) + 1 - return TextRange(start, min(end, editor.fileSize)) + val start = injector.engineEditorHelper.getLineStartOffset(editor, lr.startLine) + val end = injector.engineEditorHelper.getLineEndOffset(editor, lr.endLine, true) + 1 + return TextRange(start, min(end, editor.fileSize().toInt())) } - fun getTextRange(editor: Editor, caret: Caret, count: Int): TextRange { + fun getTextRange(editor: VimEditor, caret: VimCaret, count: Int): TextRange { val lineRange = getLineRange(editor, caret, count) - val start = EditorHelper.getLineStartOffset(editor, lineRange.startLine) - val end = EditorHelper.getLineEndOffset(editor, lineRange.endLine, true) + 1 - return TextRange(start, min(end, editor.fileSize)) + val start = injector.engineEditorHelper.getLineStartOffset(editor, lineRange.startLine) + val end = injector.engineEditorHelper.getLineEndOffset(editor, lineRange.endLine, true) + 1 + return TextRange(start, min(end, editor.fileSize().toInt())) } /** @@ -141,11 +136,11 @@ class Ranges { * * @param editor The editor to get the lines for */ - private fun processRange(editor: Editor) { + private fun processRange(editor: VimEditor) { // Already done if (done) return // Start with the range being the current line - startLine = if (defaultLine == -1) editor.caretModel.logicalPosition.line else defaultLine + startLine = if (defaultLine == -1) editor.currentCaret().getLogicalPosition().line else defaultLine endLine = startLine var lastZero = false // Now process each range, moving the cursor if appropriate @@ -153,9 +148,9 @@ class Ranges { startLine = endLine endLine = range.getLine(editor, lastZero) if (range.isMove) { - MotionGroup.moveCaret( - editor, editor.caretModel.primaryCaret, - VimPlugin.getMotion().moveCaretToLineWithSameColumn(IjVimEditor(editor), endLine, IjVimCaret(editor.caretModel.primaryCaret)) + injector.motion.moveCaret( + editor, editor.primaryCaret(), + injector.motion.moveCaretToLineWithSameColumn(editor, endLine, editor.primaryCaret()) ) } // Did that last range represent the start of the file? @@ -169,17 +164,17 @@ class Ranges { done = true } - private fun processRange(editor: Editor, caret: Caret) { - startLine = if (defaultLine == -1) caret.logicalPosition.line else defaultLine + private fun processRange(editor: VimEditor, caret: VimCaret) { + startLine = if (defaultLine == -1) caret.getLogicalPosition().line else defaultLine endLine = startLine var lastZero = false for (range in ranges) { startLine = endLine endLine = range.getLine(editor, caret, lastZero) - if (range.isMove) MotionGroup.moveCaret( + if (range.isMove) injector.motion.moveCaret( editor, caret, - VimPlugin.getMotion().moveCaretToLineWithSameColumn(IjVimEditor(editor), endLine, IjVimCaret(editor.caretModel.primaryCaret)) + injector.motion.moveCaretToLineWithSameColumn(editor, endLine, editor.primaryCaret()) ) lastZero = endLine < 0 ++count diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/helper/Msg.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/helper/Msg.kt new file mode 100644 index 00000000000..de96f9e87f7 --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/helper/Msg.kt @@ -0,0 +1,76 @@ +/* + * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform + * Copyright (C) 2003-2022 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 . + */ +package com.maddyhome.idea.vim.helper + +interface Msg { + companion object { + const val NOT_EX_CMD = "notexcmd" + const val INT_BAD_CMD = "intbadcmd" + const val e_backslash = "e_backslash" + const val e_badrange = "e_badrange" + const val e_norange = "e_norange" + const val e_rangereq = "e_rangereq" + const val e_argreq = "e_argreq" + const val e_argforb = "e_argforb" + const val e_noprev = "e_noprev" + const val e_nopresub = "e_nopresub" + const val E191 = "E191" + const val e_backrange = "e_backrange" + const val E146 = "E146" + const val e_zerocount = "e_zerocount" + const val e_trailing = "e_trailing" + const val e_invcmd = "e_invcmd" + const val e_null = "e_null" + const val E50 = "E50" + const val E51 = "E51" + const val E52 = "E52" + const val E53 = "E53" + const val E54 = "E54" + const val E55 = "E55" + const val E56 = "E56" + const val E57 = "E57" + const val E58 = "E58" + const val E59 = "E59" + const val E60 = "E60" + const val E61 = "E61" + const val E62 = "E62" + const val E63 = "E63" + const val E64 = "E64" + const val E65 = "E65" + const val E66 = "E66" + const val E67 = "E67" + const val E68 = "E68" + const val E69 = "E69" + const val E70 = "E70" + const val E71 = "E71" + const val e_invrange = "e_invrange" + const val e_toomsbra = "e_toomsbra" + const val e_internal = "e_internal" + const val synerror = "synerror" + const val E363 = "E363" + const val e_re_corr = "e_re_corr" + const val e_re_damg = "e_re_damg" + const val E369 = "E369" + const val E384 = "E384" + const val E385 = "E385" + const val e_patnotf2 = "e_patnotf2" + const val unkopt = "unkopt" + const val e_invarg = "e_invarg" + const val E475 = "E475" + } +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/CharPointer.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/CharPointer.kt new file mode 100644 index 00000000000..de53d83eb8a --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/CharPointer.kt @@ -0,0 +1,257 @@ +/* + * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform + * Copyright (C) 2003-2022 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 . + */ +package com.maddyhome.idea.vim.regexp + +import java.lang.StringBuffer +import com.maddyhome.idea.vim.regexp.CharPointer +import java.lang.IllegalStateException +import com.maddyhome.idea.vim.regexp.CharacterClasses +import java.nio.CharBuffer +import java.util.* + +class CharPointer { + private var seq: CharSequence + private var pointer = 0 + private var readonly: Boolean + + constructor(text: String) { + seq = text + readonly = true + } + + constructor(text: CharBuffer) { + seq = text + readonly = true + } + + constructor(text: StringBuffer) { + seq = text + readonly = false + } + + private constructor(ptr: CharPointer, offset: Int) { + seq = ptr.seq + readonly = ptr.readonly + pointer = ptr.pointer + offset + } + + fun pointer(): Int { + return pointer + } + + @JvmOverloads + fun set(ch: Char, offset: Int = 0): CharPointer { + check(!readonly) { "readonly string" } + val data = seq as StringBuffer + while (pointer + offset >= data.length) { + data.append('\u0000') + } + data.setCharAt(pointer + offset, ch) + return this + } + + fun charAtInc(): Char { + val res = charAt(0) + inc() + return res + } + + @JvmOverloads + fun charAt(offset: Int = 0): Char { + return if (end(offset)) { + '\u0000' + } else seq[pointer + offset] + } + + @JvmOverloads + operator fun inc(cnt: Int = 1): CharPointer { + pointer += cnt + return this + } + + @JvmOverloads + operator fun dec(cnt: Int = 1): CharPointer { + pointer -= cnt + return this + } + + fun assign(ptr: CharPointer): CharPointer { + seq = ptr.seq + pointer = ptr.pointer + readonly = ptr.readonly + return this + } + + fun ref(offset: Int): CharPointer { + return CharPointer(this, offset) + } + + fun substring(len: Int): String { + if (end()) return "" + val start = pointer + val end = normalize(pointer + len) + return CharBuffer.wrap(seq, start, end).toString() + } + + fun strlen(): Int { + if (end()) return 0 + for (i in pointer until seq.length) { + if (seq[i] == '\u0000') { + return i - pointer + } + } + return seq.length - pointer + } + + fun strncmp(str: String, len: Int): Int { + var len = len + if (end()) return -1 + val s = CharBuffer.wrap(seq, pointer, normalize(pointer + len)).toString() + if (len > str.length) { + len = str.length + } + return s.compareTo(str.substring(0, len)) + } + + fun strncmp(str: CharPointer, len: Int, ignoreCase: Boolean): Int { + if (end()) return -1 + val cs1: CharSequence = CharBuffer.wrap(seq, pointer, normalize(pointer + len)) + val cs2: CharSequence = CharBuffer.wrap(str.seq, str.pointer, str.normalize(str.pointer + len)) + val l = cs1.length + if (l != cs2.length) { + return 1 + } + for (i in 0 until l) { + val c1 = cs1[i] + val c2 = cs2[i] + val notEqual = if (ignoreCase) c1.lowercaseChar() != c2.lowercaseChar() && + c1.uppercaseChar() != c2.uppercaseChar() else c1 != c2 + if (notEqual) return 1 + } + return 0 + } + + fun strchr(c: Char): CharPointer? { + if (end()) { + return null + } + val len = seq.length + for (i in pointer until len) { + val ch = seq[i] + if (ch == '\u0000') { + return null + } + if (ch == c) { + return ref(i - pointer) + } + } + return null + } + + fun istrchr(c: Char): CharPointer? { + var c = c + if (end()) { + return null + } + val len = seq.length + val cc = c.uppercaseChar() + c = c.lowercaseChar() + for (i in pointer until len) { + val ch = seq[i] + if (ch == '\u0000') { + return null + } + if (ch == c || ch == cc) { + return ref(i - pointer) + } + } + return null + } + + val isNul: Boolean + get() = charAt() == '\u0000' + + @JvmOverloads + fun end(offset: Int = 0): Boolean { + return pointer + offset >= seq.length + } + + fun OP(): Int { + return charAt().toInt() + } + + fun OPERAND(): CharPointer { + return ref(3) + } + + fun NEXT(): Int { + return (seq[pointer + 1].code and 0xff shl 8) + (seq[pointer + 2].code and 0xff) + } + + fun OPERAND_MIN(): Int { + return (seq[pointer + 3].code shl 24) + + (seq[pointer + 4].code shl 16) + + (seq[pointer + 5].code shl 8) + + seq[pointer + 6].code + } + + fun OPERAND_MAX(): Int { + return (seq[pointer + 7].code shl 24) + + (seq[pointer + 8].code shl 16) + + (seq[pointer + 9].code shl 8) + + seq[pointer + 10].code + } + + fun OPERAND_CMP(): Char { + return seq[pointer + 7] + } + + override fun equals(obj: Any?): Boolean { + if (obj is CharPointer) { + val ptr = obj + return ptr.seq === seq && ptr.pointer == pointer + } + return false + } + + override fun hashCode(): Int { + return Objects.hash(seq, pointer) + } + + fun skipWhitespaces() { + while (CharacterClasses.isWhite(charAt())) inc() + } + + val digits: Int + get() { + var res = 0 + while (Character.isDigit(charAt())) { + res = res * 10 + (charAt() - '0') + inc() + } + return res + } + + private fun normalize(pos: Int): Int { + return Math.min(seq.length, pos) + } + + override fun toString(): String { + return substring(strlen()) + } +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/CharacterClasses.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/CharacterClasses.kt new file mode 100644 index 00000000000..64aa3a8a8dd --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/CharacterClasses.kt @@ -0,0 +1,135 @@ +/* + * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform + * Copyright (C) 2003-2022 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 . + */ +package com.maddyhome.idea.vim.regexp + +import com.maddyhome.idea.vim.regexp.CharacterClasses +import org.jetbrains.annotations.NonNls + +object CharacterClasses { + val CLASS_NAMES: @NonNls Array? = arrayOf( + "alnum:]", + "alpha:]", + "blank:]", + "cntrl:]", + "digit:]", + "graph:]", + "lower:]", + "print:]", + "punct:]", + "space:]", + "upper:]", + "xdigit:]", + "tab:]", + "return:]", + "backspace:]", + "escape:]" + ) + const val RI_DIGIT = 0x01 + const val RI_HEX = 0x02 + const val RI_OCTAL = 0x04 + const val RI_WORD = 0x08 + const val RI_HEAD = 0x10 + const val RI_ALPHA = 0x20 + const val RI_LOWER = 0x40 + const val RI_UPPER = 0x80 + const val RI_WHITE = 0x100 + const val CLASS_ALNUM = 0 + const val CLASS_ALPHA = 1 + const val CLASS_BLANK = 2 + const val CLASS_CNTRL = 3 + const val CLASS_DIGIT = 4 + const val CLASS_GRAPH = 5 + const val CLASS_LOWER = 6 + const val CLASS_PRINT = 7 + const val CLASS_PUNCT = 8 + const val CLASS_SPACE = 9 + const val CLASS_UPPER = 10 + const val CLASS_XDIGIT = 11 + const val CLASS_TAB = 12 + const val CLASS_RETURN = 13 + const val CLASS_BACKSPACE = 14 + const val CLASS_ESCAPE = 15 + const val CLASS_NONE = 99 + fun isMask(ch: Char, mask: Int, test: Int): Boolean { + var res = false + when (mask) { + RI_DIGIT -> res = Character.isDigit(ch) + RI_HEX -> res = isHex(ch) + RI_OCTAL -> res = isOctal(ch) + RI_WORD -> res = isWord(ch) + RI_HEAD -> res = isHead(ch) + RI_ALPHA -> res = isAlpha(ch) + RI_LOWER -> res = isLower(ch) + RI_UPPER -> res = isUpper(ch) + RI_WHITE -> res = isWhite(ch) + } + return res == test > 0 + } + + fun isHex(ch: Char): Boolean { + return ch.digitToIntOrNull(16) ?: -1 != -1 + } + + fun isOctal(ch: Char): Boolean { + return ch.digitToIntOrNull(8) ?: -1 != -1 + } + + fun isWord(ch: Char): Boolean { + return Character.isLetterOrDigit(ch) || ch == '_' + } + + fun isHead(ch: Char): Boolean { + return Character.isLetter(ch) || ch == '_' + } + + @JvmStatic + fun isAlpha(ch: Char): Boolean { + return Character.isLetter(ch) + } + + fun isLower(ch: Char): Boolean { + return Character.isLowerCase(ch) + } + + fun isUpper(ch: Char): Boolean { + return Character.isUpperCase(ch) + } + + fun isWhite(ch: Char): Boolean { + return Character.isWhitespace(ch) + } + + fun isGraph(ch: Char): Boolean { + return ch >= '!' && ch <= '~' + } + + fun isPrint(ch: Char): Boolean { + return ch >= ' ' && ch <= '~' || ch.code > 0xff + } + + fun isPunct(ch: Char): Boolean { + return ch in '!'..'/' || + ch in ':'..'@' || + ch in '['..'`' || + ch in '{'..'~' + } + + fun isFile(ch: Char): Boolean { + return isWord(ch) || "/.-+,#$%~=".indexOf(ch) != -1 + } +} \ No newline at end of file diff --git a/src/main/java/com/maddyhome/idea/vim/regexp/Flags.java b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/Flags.kt similarity index 52% rename from src/main/java/com/maddyhome/idea/vim/regexp/Flags.java rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/Flags.kt index 532d841adb6..e7b94c2db5a 100644 --- a/src/main/java/com/maddyhome/idea/vim/regexp/Flags.java +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/Flags.kt @@ -15,47 +15,43 @@ * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ - -package com.maddyhome.idea.vim.regexp; - -public class Flags { - private int flags; - - public Flags() { - flags = 0; - } - - public Flags(int flags) { - this.flags = flags; - } - - public int get() { - return flags; - } - - public boolean isSet(int flag) { - return ((this.flags & flag) != 0); - } - - public boolean allSet(int flags) { - return ((this.flags & flags) == flags); - } - - public int init(int flags) { - this.flags = flags; - - return this.flags; - } - - public int set(int flags) { - this.flags |= flags; - - return this.flags; - } - - public int unset(int flags) { - this.flags &= ~flags; - - return this.flags; - } -} +package com.maddyhome.idea.vim.regexp + +class Flags { + private var flags: Int + + constructor() { + flags = 0 + } + + constructor(flags: Int) { + this.flags = flags + } + + fun get(): Int { + return flags + } + + fun isSet(flag: Int): Boolean { + return flags and flag != 0 + } + + fun allSet(flags: Int): Boolean { + return this.flags and flags == flags + } + + fun init(flags: Int): Int { + this.flags = flags + return this.flags + } + + fun set(flags: Int): Int { + this.flags = this.flags or flags + return this.flags + } + + fun unset(flags: Int): Int { + this.flags = this.flags and flags.inv() + return this.flags + } +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/Magic.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/Magic.kt new file mode 100644 index 00000000000..eb2a3dadae1 --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/Magic.kt @@ -0,0 +1,114 @@ +/* + * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform + * Copyright (C) 2003-2022 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 . + */ +package com.maddyhome.idea.vim.regexp + +object Magic { + const val AMP = '&'.code - 256 + const val AT = '@'.code - 256 + const val DOLLAR = '$'.code - 256 + const val DOT = '.'.code - 256 + const val EQUAL = '='.code - 256 + const val GREATER = '>'.code - 256 + const val HAT = '^'.code - 256 + const val LBRACE = '['.code - 256 + const val LCURLY = '{'.code - 256 + const val LESS = '<'.code - 256 + const val LPAREN = '('.code - 256 + const val PERCENT = '%'.code - 256 + const val PIPE = '|'.code - 256 + const val PLUS = '+'.code - 256 + const val QUESTION = '?'.code - 256 + const val RPAREN = ')'.code - 256 + const val STAR = '*'.code - 256 + const val TILDE = '~'.code - 256 + const val UNDER = '_'.code - 256 + const val N0 = '0'.code - 256 + const val N1 = '1'.code - 256 + const val N2 = '2'.code - 256 + const val N3 = '3'.code - 256 + const val N4 = '4'.code - 256 + const val N5 = '5'.code - 256 + const val N6 = '6'.code - 256 + const val N7 = '7'.code - 256 + const val N8 = '8'.code - 256 + const val N9 = '9'.code - 256 + const val a = 'a'.code - 256 + const val A = 'A'.code - 256 + const val c = 'c'.code - 256 + const val C = 'C'.code - 256 + const val d = 'd'.code - 256 + const val D = 'D'.code - 256 + const val f = 'f'.code - 256 + const val F = 'F'.code - 256 + const val h = 'h'.code - 256 + const val H = 'H'.code - 256 + const val i = 'i'.code - 256 + const val I = 'I'.code - 256 + const val k = 'k'.code - 256 + const val K = 'K'.code - 256 + const val l = 'l'.code - 256 + const val L = 'L'.code - 256 + const val m = 'm'.code - 256 + const val M = 'M'.code - 256 + const val n = 'n'.code - 256 + const val N = 'N'.code - 256 + const val o = 'o'.code - 256 + const val O = 'O'.code - 256 + const val p = 'p'.code - 256 + const val P = 'P'.code - 256 + const val s = 's'.code - 256 + const val S = 'S'.code - 256 + const val u = 'u'.code - 256 + const val U = 'U'.code - 256 + const val v = 'v'.code - 256 + const val V = 'V'.code - 256 + const val w = 'w'.code - 256 + const val W = 'W'.code - 256 + const val x = 'x'.code - 256 + const val X = 'X'.code - 256 + const val z = 'z'.code - 256 + + /* + * Magic characters have a special meaning, they don't match literally. + * Magic characters are negative. This separates them from literal characters + * (possibly multi-byte). Only ASCII characters can be Magic. + */ + fun magic(x: Int): Int { + return x - 256 + } + + fun un_Magic(x: Int): Int { + return x + 256 + } + + fun is_Magic(x: Int): Boolean { + return x < 0 + } + + fun no_Magic(x: Int): Int { + return if (is_Magic(x)) { + un_Magic(x) + } else x + } + + fun toggle_Magic(x: Int): Int { + return if (is_Magic(x)) { + un_Magic(x) + } else magic(x) + } +} \ No newline at end of file diff --git a/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/RegExp.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/RegExp.kt new file mode 100644 index 00000000000..a08926539bd --- /dev/null +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/regexp/RegExp.kt @@ -0,0 +1,4065 @@ +/* + * IdeaVim - Vim emulator for IDEs based on the IntelliJ platform + * Copyright (C) 2003-2022 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 . + */ +package com.maddyhome.idea.vim.regexp + +import com.maddyhome.idea.vim.helper.Msg +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector +import java.lang.StringBuffer +import com.maddyhome.idea.vim.diagnostic.VimLogger +import org.jetbrains.annotations.NonNls +import java.lang.StringBuilder +import java.util.* + +class RegExp { + /* + * The first byte of the regexp internal "program" is actually this magic + * number; the start node begins in the second byte. It's used to catch the + * most severe mutilation of the program by the caller. + */ + /* + * Opcode notes: + * + * BRANCH The set of branches constituting a single choice are hooked + * together with their "next" pointers, since precedence prevents + * anything being concatenated to any individual branch. The + * "next" pointer of the last BRANCH in a choice points to the + * thing following the whole choice. This is also where the + * final "next" pointer of each individual branch points; each + * branch starts with the operand node of a BRANCH node. + * + * BACK Normal "next" pointers all implicitly point forward; BACK + * exists to make loop structures possible. + * + * STAR,PLUS '=', and complex '*' and '+', are implemented as circular + * BRANCH structures using BACK. Simple cases (one character + * per match) are implemented with STAR and PLUS for speed + * and to minimize recursive plunges. + * + * BRACE_LIMITS This is always followed by a BRACE_SIMPLE or BRACE_COMPLEX + * node, and defines the min and max limits to be used for that + * node. + * + * MOPEN,MCLOSE ...are numbered at compile time. + * ZOPEN,ZCLOSE ...ditto + */ + /* + * A node is one char of opcode followed by two chars of "next" pointer. + * "Next" pointers are stored as two 8-bit bytes, high order first. The + * value is a positive offset from the opcode of the node containing it. + * An operand, if any, simply follows the node. (Note that much of the + * code generation knows about this implicit relationship.) + * + * Using two bytes for the "next" pointer is vast overkill for most things, + * but allows patterns to get big without disasters. + */ + // #define OP(p) ((int)*(p)) + // #define NEXT(p) (((*((p) + 1) & 0377) << 8) + (*((p) + 2) & 0377)) + // #define OPERAND(p) ((p) + 3) + /* Obtain an operand that was stored as four bytes, MSB first. */ // #define OPERAND_MIN(p) (((long)(p)[3] << 24) + ((long)(p)[4] << 16) \ + // + ((long)(p)[5] << 8) + (long)(p)[6]) + /* Obtain a second operand stored as four bytes. */ // #define OPERAND_MAX(p) OPERAND_MIN((p) + 4) + /* Obtain a second single-byte operand stored after a four bytes operand. */ // #define OPERAND_CMP(p) (p)[7] + /* + * Utility definitions. + */ + // #define UCHARAT(p) ((int)*(char_u *)(p)) + /* Used for an error (down from) vim_regcomp(): give the error message, set rc_did_emsg and return null */ /* + #define EMSG_RET_null(m) + { + EMSG(_(m)); + rc_did_emsg = true; + return null; + } + #define EMSG_M_RET_null(m, c) + { + EMSG2(_(m), c ? "" : "\\"); + rc_did_emsg = true; + return null; + } + #define EMSG_RET_FAIL(m) + { + EMSG(_(m)); + rc_did_emsg = true; + return FAIL; + } + #define EMSG_ONE_RET_null + */ + //EMSG_M_RET_null("E369: invalid item in %s%%[]", reg_magic == MAGIC_ALL) + private fun EMSG_RET_null(key: String) { + injector.messages.showStatusBarMessage(injector.messages.message(key)) + } + + private fun EMSG_M_RET_null(key: String, isMagic: Boolean) { + val `val` = if (isMagic) "" else "\\" + injector.messages.showStatusBarMessage(injector.messages.message(key, `val`)) + } + + private fun EMSG_ONE_RET_null() { + EMSG_M_RET_null(Msg.E369, reg_magic == MAGIC_ALL) + } + + /* + * Return NOT_MULTI if c is not a "multi" operator. + * Return MULTI_ONE if c is a single "multi" operator. + * Return MULTI_MULT if c is a multi "multi" operator. + */ + private fun re_multi_type(c: Int): Int { + if (c == Magic.AT || c == Magic.EQUAL || c == Magic.QUESTION) { + return MULTI_ONE + } + return if (c == Magic.STAR || c == Magic.PLUS || c == Magic.LCURLY) { + MULTI_MULT + } else NOT_MULTI + } + + /* + * Translate '\x' to its control character, except "\n", which is Magic. + */ + private fun backslash_trans(c: Int): Int { + when (c) { + 'r'.code -> return '\r'.code + 't'.code -> return '\t'.code + 'e'.code -> return 0x1b + 'b'.code -> return '\b'.code + } + return c + } + + /* + * Return true if compiled regular expression "prog" can match a line break. + */ + fun re_multiline(prog: regprog_T): Int { + return prog.regflags and RF_HASNL + } + + /* + * vim_regcomp - compile a regular expression into internal code + * + * We can't allocate space until we know how big the compiled form will be, + * but we can't compile it (and thus know how big it is) until we've got a + * place to put the code. So we cheat: we compile it twice, once with code + * generation turned off and size counting turned on, and once "for real". + * This also means that we don't allocate space until we are sure that the + * thing really will compile successfully, and we never have to move the + * code and thus invalidate pointers into it. (Note that it has to be in + * one piece because vim_free() must be able to free it all.) + * + * Whether upper/lower case is to be ignored is decided when executing the + * program, it does not matter here. + * + * Beware that the optimization-preparation code in here knows about some + * of the structure of the compiled regexp. + */ + fun vim_regcomp(expr: String?, magic: Int): regprog_T? { + val r: regprog_T + var scan: CharPointer + var longest: CharPointer? + var len: Int + val flags = Flags() + if (expr == null) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_null)) + return null + } + r = regprog_T() + + /* + * Second pass: emit code. + */regcomp_start(expr, magic) + regcode = CharPointer(r.program) + regc(REGMAGIC) + if (reg(REG_NOPAREN, flags) == null) { + return null + } + + /* Dig out information for optimizations. */r.regstart = 0.toChar() /* Worst-case defaults. */ + r.reganch = 0.toChar() + r.regmust = null + r.regmlen = 0 + r.regflags = regflags + if (flags.isSet(HASNL)) { + r.regflags = r.regflags or RF_HASNL + } + /* Remember whether this pattern has any \z specials in it. */r.reghasz = re_has_z + scan = CharPointer(r.program).ref(1) /* First BRANCH. */ + if (regnext(scan)!!.OP() == END) /* Only one top-level choice. */ { + scan = scan.OPERAND() + + /* Starting-point info. */if (scan.OP() == BOL || scan.OP() == RE_BOF) { + r.reganch++ + scan = regnext(scan)!! + } + if (scan.OP() == EXACTLY) { + r.regstart = scan.OPERAND().charAt() + } else if ((scan.OP() == BOW || scan.OP() == EOW || scan.OP() == NOTHING || scan.OP() == MOPEN || scan.OP() == NOPEN || scan.OP() == MCLOSE || scan.OP() == NCLOSE) + && regnext(scan)!!.OP() == EXACTLY + ) { + r.regstart = regnext(scan)!!.OPERAND().charAt() + } + + /* + * If there's something expensive in the r.e., find the longest + * literal string that must appear and make it the regmust. Resolve + * ties in favor of later strings, since the regstart check works + * with the beginning of the r.e. and avoiding duplication + * strengthens checking. Not a strong reason, but sufficient in the + * absence of others. + */ + /* + * When the r.e. starts with BOW, it is faster to look for a regmust + * first. Used a lot for "#" and "*" commands. (Added by mool). + */if ((flags.isSet(SPSTART) || scan.OP() == BOW || scan.OP() == EOW) + && !flags.isSet(HASNL) + ) { + longest = null + len = 0 + while (scan != null) { + val so = scan.OPERAND() + if (scan.OP() == EXACTLY && so.strlen() >= len) { + longest = so.ref(0) + len = so.strlen() + } + scan = regnext(scan)!! + } + if (longest != null) { + r.regmust = longest.ref(0) + } + r.regmlen = len + } + } + if (logger.isDebug()) logger.debug(regdump(expr, r)) + return r + } + + /* + * Setup to parse the regexp. Used once to get the length and once to do it. + */ + private fun regcomp_start(expr: String, magic: Int) { + initchr(expr) + reg_magic = if (magic != 0) { + MAGIC_ON + } else { + MAGIC_OFF + } + num_complex_braces = 0 + regnpar = 1 + Arrays.fill(had_endbrace, false) + regnzpar = 1 + re_has_z = 0.toChar() + regflags = 0 + had_eol = false + } + + /* + * Check if during the previous call to vim_regcomp the EOL item "$" has been + * found. This is messy, but it works fine. + */ + fun vim_regcomp_had_eol(): Boolean { + return had_eol + } + + /* + * reg - regular expression, i.e. main body or parenthesized thing + * + * Caller must absorb opening parenthesis. + * + * Combining parenthesis handling with the base level of regular expression + * is a trifle forced, but the need to tie the tails of the branches to what + * follows makes it hard to avoid. + */ + private fun reg(paren: Int, flagp: Flags): CharPointer? { + var ret: CharPointer? + var br: CharPointer? + val ender: CharPointer + var parno = 0 + val flags = Flags() + flagp.init(HASWIDTH) /* Tentatively. */ + if (paren == REG_ZPAREN) { + /* Make a ZOPEN node. */ + if (regnzpar >= NSUBEXP) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E50)) + return null + } + parno = regnzpar + regnzpar++ + ret = regnode(ZOPEN + parno) + } else if (paren == REG_PAREN) { + /* Make a MOPEN node. */ + if (regnpar >= NSUBEXP) { + EMSG_M_RET_null(Msg.E51, reg_magic == MAGIC_ALL) + return null + } + parno = regnpar + ++regnpar + ret = regnode(MOPEN + parno) + } else if (paren == REG_NPAREN) { + /* Make a NOPEN node. */ + ret = regnode(NOPEN) + } else { + ret = null + } + + /* Pick up the branches, linking them together. */br = regbranch(flags) + if (br == null) { + return null + } + if (ret != null) { + regtail(ret, br) /* [MZ]OPEN -> first. */ + } else { + ret = br.ref(0) + } + /* If one of the branches can be zero-width, the whole thing can. + * If one of the branches has * at start or matches a line-break, the + * whole thing can. */if (!flags.isSet(HASWIDTH)) { + flagp.unset(HASWIDTH) + } + flagp.set(flags.get() and (SPSTART or HASNL)) + while (peekchr() == Magic.PIPE) { + skipchr() + br = regbranch(flags) + if (br == null) { + return null + } + regtail(ret, br) /* BRANCH -> BRANCH. */ + if (!flags.isSet(HASWIDTH)) { + flagp.unset(HASWIDTH) + } + flagp.set(flags.get() and (SPSTART or HASNL)) + } + + /* Make a closing node, and hook it on the end. */ender = + regnode(if (paren == REG_ZPAREN) ZCLOSE + parno else if (paren == REG_PAREN) MCLOSE + parno else if (paren == REG_NPAREN) NCLOSE else END) + regtail(ret, ender) + + /* Hook the tails of the branches to the closing node. */br = ret.ref(0) + while (br != null) { + regoptail(br, ender) + br = regnext(br) + } + + /* Check for proper termination. */if (paren != REG_NOPAREN && getchr() != Magic.RPAREN) { + return if (paren == REG_ZPAREN) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E52)) + null + } else if (paren == REG_NPAREN) { + EMSG_M_RET_null(Msg.E53, reg_magic == MAGIC_ALL) + null + } else { + EMSG_M_RET_null(Msg.E54, reg_magic == MAGIC_ALL) + null + } + } else if (paren == REG_NOPAREN && peekchr() != '\u0000'.code) { + return if (curchr == Magic.LPAREN) { + EMSG_M_RET_null(Msg.E55, reg_magic == MAGIC_ALL) + null + } else { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_trailing)) + null + } + /* NOTREACHED */ + } + /* + * Here we set the flag allowing back references to this set of + * parentheses. + */if (paren == REG_PAREN) { + had_endbrace[parno] = true /* have seen the close paren */ + } + return ret + } + + /* + * regbranch - one alternative of an | operator + * + * Implements the & operator. + */ + private fun regbranch(flagp: Flags): CharPointer? { + val ret: CharPointer + var chain: CharPointer? = null + var latest: CharPointer? + val flags = Flags() + flagp.init(WORST or HASNL) /* Tentatively. */ + ret = regnode(BRANCH) + while (true) { + latest = regconcat(flags) + if (latest == null) { + return null + } + + /* If one of the branches has width, the whole thing has. If one of + * the branches anchors at start-of-line, the whole thing does. */flagp.set(flags.get() and (HASWIDTH or SPSTART)) + /* If one of the branches doesn't match a line-break, the whole thing + * doesn't. */flagp.set(flagp.get() and (HASNL.inv() or (flags.get() and HASNL))) + chain?.let { regtail(it, latest) } + if (peekchr() != Magic.AMP) { + break + } + skipchr() + regtail(latest, regnode(END)) /* operand ends */ + reginsert(MATCH, latest.ref(0)) + chain = latest.ref(0) + } + return ret + } + + /* + * regbranch - one alternative of an | or & operator + * + * Implements the concatenation operator. + */ + private fun regconcat(flagp: Flags): CharPointer? { + var first: CharPointer? = null + var chain: CharPointer? = null + var latest: CharPointer? + val flags = Flags() + var cont = true + flagp.init(WORST) /* Tentatively. */ + while (cont) { + when (peekchr()) { + '\u0000'.code, Magic.PIPE, Magic.AMP, Magic.RPAREN -> cont = false + Magic.c -> { + regflags = regflags or RF_ICASE + skipchr_keepstart() + } + Magic.C -> { + regflags = regflags or RF_NOICASE + skipchr_keepstart() + } + Magic.v -> { + reg_magic = MAGIC_ALL + skipchr_keepstart() + curchr = -1 + } + Magic.m -> { + reg_magic = MAGIC_ON + skipchr_keepstart() + curchr = -1 + } + Magic.M -> { + reg_magic = MAGIC_OFF + skipchr_keepstart() + curchr = -1 + } + Magic.V -> { + reg_magic = MAGIC_NONE + skipchr_keepstart() + curchr = -1 + } + else -> { + latest = regpiece(flags) + if (latest == null) { + return null + } + flagp.set(flags.get() and (HASWIDTH or HASNL)) + chain /* First piece. */?.let { regtail(it, latest) } + ?: flagp.set(flags.get() and SPSTART) + chain = latest.ref(0) + if (first == null) { + first = latest.ref(0) + } + } + } + } + if (first == null) /* Loop ran zero times. */ { + first = regnode(NOTHING) + } + return first + } + + /* + * regpiece - something followed by possible [*+=] + * + * Note that the branching code sequences used for = and the general cases + * of * and + are somewhat optimized: they use the same NOTHING node as + * both the endmarker for their branch list and the body of the last branch. + * It might seem that this node could be dispensed with entirely, but the + * endmarker role is not redundant. + */ + private fun regpiece(flagp: Flags): CharPointer? { + val ret: CharPointer? + val op: Int + val next: CharPointer + val flags = Flags() + ret = regatom(flags) + if (ret == null) { + return null + } + op = peekchr() + if (re_multi_type(op) == NOT_MULTI) { + flagp.init(flags.get()) + return ret + } + if (!flags.isSet(HASWIDTH) && re_multi_type(op) == MULTI_MULT) { + if (op == Magic.STAR) { + EMSG_M_RET_null(Msg.E56, reg_magic >= MAGIC_ON) + return null + } + if (op == Magic.PLUS) { + EMSG_M_RET_null(Msg.E57, reg_magic == MAGIC_ALL) + return null + } + /* "\{}" is checked below, it's allowed when there is an upper limit */ + } + flagp.init(WORST or SPSTART or (flags.get() and HASNL)) /* default flags */ + skipchr() + when (op) { + Magic.STAR -> if (flags.isSet(SIMPLE)) { + reginsert(STAR, ret.ref(0)) + } else { + /* Emit x* as (x&|), where & means "self". */ + reginsert(BRANCH, ret.ref(0)) /* Either x */ + regoptail(ret, regnode(BACK)) /* and loop */ + regoptail(ret, ret) /* back */ + regtail(ret, regnode(BRANCH)) /* or */ + regtail(ret, regnode(NOTHING)) /* null. */ + } + Magic.PLUS -> { + if (flags.isSet(SIMPLE)) { + reginsert(PLUS, ret.ref(0)) + } else { + /* Emit x+ as x(&|), where & means "self". */ + next = regnode(BRANCH) /* Either */ + regtail(ret, next) + regtail(regnode(BACK), ret) /* loop back */ + regtail(next, regnode(BRANCH)) /* or */ + regtail(ret, regnode(NOTHING)) /* null. */ + } + flagp.init(WORST or HASWIDTH or (flags.get() and HASNL)) + } + Magic.AT -> { + var lop = END + when (Magic.no_Magic(getchr())) { + '='.code -> lop = MATCH + '!'.code -> lop = NOMATCH + '>'.code -> lop = SUBPAT + '<'.code -> when (Magic.no_Magic(getchr())) { + '='.code -> lop = BEHIND + '!'.code -> lop = NOBEHIND + } + } + if (lop == END) { + EMSG_M_RET_null(Msg.E59, reg_magic == MAGIC_ALL) + return null + } + /* Look behind must match with behind_pos. */if (lop == BEHIND || lop == NOBEHIND) { + regtail(ret, regnode(BHPOS)) + } + regtail(ret, regnode(END)) /* operand ends */ + reginsert(lop, ret.ref(0)) + } + Magic.QUESTION, Magic.EQUAL -> { + /* Emit x= as (x|) */reginsert(BRANCH, ret.ref(0)) /* Either x */ + regtail(ret, regnode(BRANCH)) /* or */ + next = regnode(NOTHING) /* null. */ + regtail(ret, next) + regoptail(ret, next) + } + Magic.LCURLY -> { + val limits = read_limits() ?: return null + val maxval = limits.maxvalue + val minval = limits.minvalue + if (!flags.isSet(HASWIDTH) && (if (maxval > minval) maxval >= MAX_LIMIT else minval >= MAX_LIMIT)) { + EMSG_M_RET_null(Msg.E58, reg_magic == MAGIC_ALL) + return null + } + if (flags.isSet(SIMPLE)) { + reginsert(BRACE_SIMPLE, ret.ref(0)) + reginsert_limits(BRACE_LIMITS, minval, maxval, ret.ref(0)) + } else { + if (num_complex_braces >= 10) { + EMSG_M_RET_null(Msg.E60, reg_magic == MAGIC_ALL) + return null + } + reginsert(BRACE_COMPLEX + num_complex_braces, ret.ref(0)) + regoptail(ret, regnode(BACK)) + regoptail(ret, ret) + reginsert_limits(BRACE_LIMITS, minval, maxval, ret.ref(0)) + ++num_complex_braces + } + if (minval > 0 && maxval > 0) { + flagp.init(HASWIDTH or (flags.get() and HASNL)) + } + } + } + if (re_multi_type(peekchr()) != NOT_MULTI) { + /* Can't have a multi follow a multi. */ + if (peekchr() == Magic.STAR) { + val `val` = if (reg_magic >= MAGIC_ON) "" else "\\" + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E61, `val`)) + } else { + val `val` = if (reg_magic >= MAGIC_ON) "" else "\\" + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E62, + `val`, + Character.toString(Magic.no_Magic(peekchr()).toChar()))) + } + return null + } + return ret + } + + /* + * regatom - the lowest level + * + * Optimization: gobbles an entire sequence of ordinary characters so that + * it can turn them into a single node, which is smaller to store and + * faster to run. Don't do this when one_exactly is set. + */ + private fun regatom(flagp: Flags): CharPointer? { + var ret: CharPointer? = null + val flags = Flags() + val cpo_lit = false /* 'cpoptions' contains 'l' flag */ + var c: Int + val classchars = ".iIkKfFpPsSdDxXoOwWhHaAlLuU" + val classcodes = intArrayOf(ANY, IDENT, SIDENT, KWORD, SKWORD, + FNAME, SFNAME, PRINT, SPRINT, + WHITE, NWHITE, DIGIT, NDIGIT, + HEX, NHEX, OCTAL, NOCTAL, + WORD, NWORD, HEAD, NHEAD, + ALPHA, NALPHA, LOWER, NLOWER, + UPPER, NUPPER + ) + val p: CharPointer + var extra = 0 + flagp.init(WORST) /* Tentatively. */ + c = getchr() + var doCollection = false + var doDefault = false + when (c) { + Magic.HAT -> ret = regnode(BOL) + Magic.DOLLAR -> { + ret = regnode(EOL) + had_eol = true + } + Magic.LESS -> ret = regnode(BOW) + Magic.GREATER -> ret = regnode(EOW) + Magic.UNDER -> { + c = Magic.no_Magic(getchr()) + if (c == '^'.code) /* "\_^" is start-of-line */ { + ret = regnode(BOL) + } + if (c == '$'.code) /* "\_$" is end-of-line */ { + ret = regnode(EOL) + had_eol = true + } + extra = ADD_NL + flagp.set(HASNL) + + /* "\_[" is character range plus newline */if (c == '['.code) { + //goto collection; + doCollection = true + } + val i = classchars.indexOf(Magic.no_Magic(c).toChar()) + if (i == -1) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E63)) + return null + } + ret = regnode(classcodes[i] + extra) + flagp.set(HASWIDTH or SIMPLE) + } + Magic.DOT, Magic.i, Magic.I, Magic.k, Magic.K, Magic.f, Magic.F, Magic.p, Magic.P, Magic.s, Magic.S, Magic.d, Magic.D, Magic.x, Magic.X, Magic.o, Magic.O, Magic.w, Magic.W, Magic.h, Magic.H, Magic.a, Magic.A, Magic.l, Magic.L, Magic.u, Magic.U -> { + val i = classchars.indexOf(Magic.no_Magic(c).toChar()) + if (i == -1) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E63)) + return null + } + ret = regnode(classcodes[i] + extra) + flagp.set(HASWIDTH or SIMPLE) + } + Magic.n -> { + ret = regnode(NEWL) + flagp.set(HASWIDTH or HASNL) + } + Magic.LPAREN -> { + if (one_exactly) { + EMSG_ONE_RET_null() + return null + } + ret = reg(REG_PAREN, flags) + if (ret == null) { + return null + } + flagp.set(flags.get() and (HASWIDTH or SPSTART or HASNL)) + } + '\u0000'.code, Magic.PIPE, Magic.AMP, Magic.RPAREN -> { + EMSG_RET_null(Msg.e_internal) /* Supposed to be caught earlier. */ + return null + } + Magic.EQUAL, Magic.QUESTION, Magic.PLUS, Magic.AT, Magic.LCURLY, Magic.STAR -> { + c = Magic.no_Magic(c) + val `val` = if (if (c == '*'.code) reg_magic >= MAGIC_ON else reg_magic == MAGIC_ALL) "" else "\\" + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E64, + `val`, + Character.toString(c.toChar()))) + return null + } + Magic.TILDE -> if (reg_prev_sub != null) { + val lp: CharPointer + ret = regnode(EXACTLY) + lp = reg_prev_sub.ref(0) + while (!lp.isNul) { + regc(lp.charAt().code) + } + lp.inc() + regc('\u0000'.code) + if (!reg_prev_sub.isNul) { + flagp.set(HASWIDTH) + if (lp.pointer() - reg_prev_sub.pointer() == 1) { + flagp.set(SIMPLE) + } + } + } else { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_nopresub)) + return null + } + Magic.N1, Magic.N2, Magic.N3, Magic.N4, Magic.N5, Magic.N6, Magic.N7, Magic.N8, Magic.N9 -> { + val refnum: Int + refnum = c - Magic.N0 + /* + * Check if the back reference is legal. We must have seen the + * close brace. + * TODO: Should also check that we don't refer to something + * that is repeated (+*=): what instance of the repetition + * should we match? + */if (!had_endbrace[refnum]) { + /* Trick: check if "@<=" or "@ { + c = Magic.no_Magic(getchr()) + when (c) { + '('.code -> { + if (reg_do_extmatch != REX_SET) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E66)) + return null + } + if (one_exactly) { + EMSG_ONE_RET_null() + return null + } + ret = reg(REG_ZPAREN, flags) + if (ret == null) { + return null + } + flagp.set(flags.get() and (HASWIDTH or SPSTART or HASNL)) + re_has_z = REX_SET.toChar() + } + '1'.code, '2'.code, '3'.code, '4'.code, '5'.code, '6'.code, '7'.code, '8'.code, '9'.code -> { + if (reg_do_extmatch != REX_USE) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E67)) + return null + } + ret = regnode(ZREF + c - '0'.code) + re_has_z = REX_USE.toChar() + } + 's'.code -> ret = regnode(MOPEN) + 'e'.code -> ret = regnode(MCLOSE) + else -> { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E68)) + return null + } + } + } + Magic.PERCENT -> { + c = Magic.no_Magic(getchr()) + when (c) { + '('.code -> { + if (one_exactly) { + EMSG_ONE_RET_null() + return null + } + ret = reg(REG_NPAREN, flags) + if (ret == null) { + return null + } + flagp.set(flags.get() and (HASWIDTH or SPSTART or HASNL)) + } + '^'.code -> ret = regnode(RE_BOF) + '$'.code -> ret = regnode(RE_EOF) + '#'.code -> ret = regnode(CURSOR) + '['.code -> if (one_exactly) /* doesn't nest */ { + EMSG_ONE_RET_null() + return null + } else { + val lastbranch: CharPointer + var lastnode: CharPointer? = null + var br: CharPointer? + ret = null + while (getchr().also { c = it } != ']'.code) { + if (c == '\u0000'.code) { + EMSG_M_RET_null(Msg.E69, reg_magic == MAGIC_ALL) + return null + } + br = regnode(BRANCH) + if (ret == null) { + ret = br.ref(0) + } else { + regtail(lastnode!!, br) + } + ungetchr() + one_exactly = true + lastnode = regatom(flagp) + one_exactly = false + if (lastnode == null) { + return null + } + } + if (ret == null) { + EMSG_M_RET_null(Msg.E70, reg_magic == MAGIC_ALL) + return null + } + lastbranch = regnode(BRANCH) + br = regnode(NOTHING) + regtail(lastnode!!, br) + regtail(lastbranch, br) + /* connect all branches to the NOTHING + * branch at the end */br = ret.ref(0) + while (br !== lastnode) { + br = if (br!!.OP() == BRANCH) { + regtail(br, lastbranch) + br.OPERAND() + } else { + regnext(br) + } + } + flagp.unset(HASWIDTH) + } + else -> { + if (Character.isDigit(c.toChar()) || c == '<'.code || c == '>'.code) { + var n = 0 + val cmp: Int + cmp = c + if (cmp == '<'.code || cmp == '>'.code) { + c = getchr() + } + while (Character.isDigit(c.toChar())) { + n = n * 10 + (c - '0'.code) + c = getchr() + } + if (c == 'l'.code || c == 'c'.code || c == 'v'.code) { + ret = if (c == 'l'.code) { + regnode(RE_LNUM) + } else if (c == 'c'.code) { + regnode(RE_COL) + } else { + regnode(RE_VCOL) + } + + /* put the number and the optional + * comparator after the opcode */regcode = re_put_long(regcode!!.ref(0), n) + regcode!!.set(cmp.toChar()).inc() + } + } + EMSG_M_RET_null(Msg.E71, reg_magic == MAGIC_ALL) + return null + } + } + } + Magic.LBRACE -> doCollection = true + else -> doDefault = true + } + if (doCollection) { + val lp: CharPointer + + /* + * If there is no matching ']', we assume the '[' is a normal + * character. This makes 'incsearch' and ":help [" work. + */lp = skip_anyof(regparse!!.ref(0)) + if (lp.charAt() == ']') /* there is a matching ']' */ { + var startc = -1 /* > 0 when next '-' is a range */ + var endc: Int + + /* + * In a character class, different parsing rules apply. + * Not even \ is special anymore, nothing is. + */if (regparse!!.charAt() == '^') /* Complement of range. */ { + ret = regnode(ANYBUT + extra) + regparse!!.inc() + } else { + ret = regnode(ANYOF + extra) + } + + /* At the start ']' and '-' mean the literal character. */if (regparse!!.charAt() == ']' || regparse!!.charAt() == '-') { + regc(regparse!!.charAt().code) + regparse!!.inc() + } + while (!regparse!!.isNul && regparse!!.charAt() != ']') { + if (regparse!!.charAt() == '-') { + regparse!!.inc() + /* The '-' is not used for a range at the end and + * after or before a '\n'. */if (regparse!!.isNul || regparse!!.charAt() == ']' || startc == -1 || + regparse!!.charAt(0) == '\\' && regparse!!.charAt(1) == 'n' + ) { + regc('-'.code) + startc = '-'.code /* [--x] is a range */ + } else { + //endc = *regparse++; + endc = regparse!!.charAt().code + regparse!!.inc() + if (startc > endc) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_invrange)) + return null + } + while (++startc <= endc) { + regc(startc) + } + startc = -1 + } + } else if (regparse!!.charAt() == '\\' && + (REGEXP_INRANGE.indexOf(regparse!!.charAt(1)) != -1 || !cpo_lit && + REGEXP_ABBR.indexOf(regparse!!.charAt(1)) != -1) + ) { + regparse!!.inc() + if (regparse!!.charAt() == 'n') { + /* '\n' in range: also match NL */ + if (ret.charAt().code == ANYBUT) { + ret.set((ANYBUT + ADD_NL).toChar()) + } else if (ret.charAt().code == ANYOF) { + ret.set((ANYOF + ADD_NL).toChar()) + } + /* else: must have had a \n already */flagp.set(HASNL) + regparse!!.inc() + startc = -1 + } else { + startc = backslash_trans(regparse!!.charAt().code) + regparse!!.inc() + regc(startc) + } + } else if (regparse!!.charAt() == '[') { + var c_class: Int + var cu: Int + c_class = skip_class_name(regparse!!) + startc = -1 + when (c_class) { + CharacterClasses.CLASS_NONE -> { + /* literal '[', allow [[-x] as a range */startc = regparse!!.charAt().code + regparse!!.inc() + regc(startc) + } + CharacterClasses.CLASS_ALNUM -> { + cu = 1 + while (cu <= 255) { + if (Character.isLetterOrDigit(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_ALPHA -> { + cu = 1 + while (cu <= 255) { + if (Character.isLetter(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_BLANK -> { + regc(' '.code) + regc('\t'.code) + } + CharacterClasses.CLASS_CNTRL -> { + cu = 1 + while (cu <= 255) { + if (Character.isISOControl(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_DIGIT -> { + cu = 1 + while (cu <= 255) { + if (Character.isDigit(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_GRAPH -> { + cu = 1 + while (cu <= 255) { + if (CharacterClasses.isGraph(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_LOWER -> { + cu = 1 + while (cu <= 255) { + if (Character.isLowerCase(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_PRINT -> { + cu = 1 + while (cu <= 255) { + if (CharacterClasses.isPrint(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_PUNCT -> { + cu = 1 + while (cu <= 255) { + if (CharacterClasses.isPunct(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_SPACE -> { + cu = 9 + while (cu <= 13) { + regc(cu) + cu++ + } + regc(' '.code) + } + CharacterClasses.CLASS_UPPER -> { + cu = 1 + while (cu <= 255) { + if (Character.isUpperCase(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_XDIGIT -> { + cu = 1 + while (cu <= 255) { + if (CharacterClasses.isHex(cu.toChar())) { + regc(cu) + } + cu++ + } + } + CharacterClasses.CLASS_TAB -> regc('\t'.code) + CharacterClasses.CLASS_RETURN -> regc('\r'.code) + CharacterClasses.CLASS_BACKSPACE -> regc('\b'.code) + CharacterClasses.CLASS_ESCAPE -> regc('\u001b'.code) + } + } else { + startc = regparse!!.charAt().code + regparse!!.inc() + regc(startc) + } + } + regc('\u0000'.code) + prevchr_len = 1 /* last char was the ']' */ + if (regparse!!.charAt() != ']') { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_toomsbra)) + return null + } + skipchr() /* let's be friends with the lexer again */ + flagp.set(HASWIDTH or SIMPLE) + } else { + doDefault = true + } + } + /* FALLTHROUGH */if (doDefault) { + var len: Int + ret = regnode(EXACTLY) + + /* + * Append characters as long as: + * - there is no following multi, we then need the character in + * front of it as a single character operand + * - not running into a Magic character + * - "one_exactly" is not set + * But always emit at least one character. Might be a Multi, + * e.g., a "[" without matching "]". + */len = 0 + while (c != '\u0000'.code && (len == 0 || re_multi_type(peekchr()) == NOT_MULTI && + !one_exactly && !Magic.is_Magic(c)) + ) { + c = Magic.no_Magic(c) + regc(c) + c = getchr() + ++len + } + ungetchr() + regc('\u0000'.code) + flagp.set(HASWIDTH) + if (len == 1) { + flagp.set(SIMPLE) + } + } + return ret + } + + /* + * emit a node + * Return pointer to generated code. + */ + private fun regnode(op: Int): CharPointer { + val ret: CharPointer + ret = regcode!!.ref(0) + regcode!!.set(op.toChar()).inc() + regcode!!.set('\u0000').inc() /* Null "next" pointer. */ + regcode!!.set('\u0000').inc() + return ret + } + + /* + * Emit (if appropriate) a byte of code + */ + private fun regc(b: Int) { + regcode!!.set(b.toChar()).inc() + } + + /* + * reginsert - insert an operator in front of already-emitted operand + * + * Means relocating the operand. + */ + private fun reginsert(op: Int, opnd: CharPointer) { + val src: CharPointer + val dst: CharPointer + val place: CharPointer + src = regcode!!.ref(0) + regcode!!.inc(3) + dst = regcode!!.ref(0) + while (src.pointer() > opnd.pointer()) { + //*--dst = *--src; + dst.dec().set(src.dec().charAt()) + } + place = opnd.ref(0) /* Op node, where operand used to be. */ + place.set(op.toChar()).inc() + place.set('\u0000').inc() + place.set('\u0000') + } + + /* + * reginsert_limits - insert an operator in front of already-emitted operand. + * The operator has the given limit values as operands. Also set next pointer. + * + * Means relocating the operand. + */ + private fun reginsert_limits(op: Int, minval: Int, maxval: Int, opnd: CharPointer) { + val src: CharPointer + val dst: CharPointer + var place: CharPointer + src = regcode!!.ref(0) + regcode!!.inc(11) + dst = regcode!!.ref(0) + while (src.pointer() > opnd.pointer()) { + //*--dst = *--src; + dst.dec().set(src.dec().charAt()) + } + place = opnd.ref(0) /* Op node, where operand used to be. */ + place.set(op.toChar()).inc() + place.set('\u0000').inc() + place.set('\u0000').inc() + place = re_put_long(place.ref(0), minval) + place = re_put_long(place.ref(0), maxval) + regtail(opnd, place) + } + + /* + * Write a long as four bytes at "p" and return pointer to the next char. + */ + private fun re_put_long(p: CharPointer, `val`: Int): CharPointer { + p.set((`val` shr 24 and 0xff).toChar()).inc() + p.set((`val` shr 16 and 0xff).toChar()).inc() + p.set((`val` shr 8 and 0xff).toChar()).inc() + p.set((`val` and 0xff).toChar()).inc() + return p + } + + /* + * regtail - set the next-pointer at the end of a node chain + */ + private fun regtail(p: CharPointer, `val`: CharPointer) { + var scan: CharPointer + val offset: Int + + /* Find last node. */scan = p.ref(0) + while (true) { + val temp = regnext(scan) ?: break + scan = temp + } + offset = if (scan.OP() == BACK) { + scan.pointer() - `val`.pointer() + } else { + `val`.pointer() - scan.pointer() + } + scan.ref(1).set((offset.toChar().code shr 8 and 0xff).toChar()) + scan.ref(2).set((offset and 0xff).toChar()) + } + + /* + * regoptail - regtail on item after a BRANCH; nop if none + */ + private fun regoptail(p: CharPointer?, `val`: CharPointer) { + /* When op is neither BRANCH nor BRACE_COMPLEX0-9, it is "operandless" */ + if (p == null || p.OP() != BRANCH && (p.OP() < BRACE_COMPLEX || p.OP() > BRACE_COMPLEX + 9)) { + return + } + regtail(p.OPERAND(), `val`) + } + + private fun initchr(str: String) { + regparse = CharPointer(str) + prevchr_len = 0 + nextchr = -1 + prevchr = nextchr + prevprevchr = prevchr + curchr = prevprevchr + at_start = true + prev_at_start = false + } + + private fun peekchr(): Int { + if (curchr == -1) { + when (regparse!!.charAt(0).also { curchr = it.toInt() }) { + '.', '[', '~' -> /* magic when 'magic' is on */if (reg_magic >= MAGIC_ON) { + curchr = Magic.magic(curchr) + } + '(', ')', '{', '%', '+', '=', '?', '@', '!', '&', '|', '<', '>', '#', '"', '\'', ',', '-', ':', ';', '`', '/' -> /* magic only after "\v" */if (reg_magic == MAGIC_ALL) { + curchr = Magic.magic(curchr) + } + '*' -> /* * is not magic as the very first character, eg "?*ptr" and when + * after '^', eg "/^*ptr" */if (reg_magic >= MAGIC_ON && !at_start && !(prev_at_start && prevchr == Magic.HAT)) { + curchr = Magic.STAR + } + '^' -> /* '^' is only magic as the very first character and if it's after + * "\(", "\|", "\&' or "\n" */if (reg_magic >= MAGIC_OFF && + (at_start || reg_magic == MAGIC_ALL || prevchr == Magic.LPAREN || prevchr == Magic.PIPE || prevchr == Magic.AMP || prevchr == Magic.n || Magic.no_Magic( + prevchr) == '('.code && + prevprevchr == Magic.PERCENT) + ) { + curchr = Magic.HAT + at_start = true + prev_at_start = false + } + '$' -> /* '$' is only magic as the very last char and if it's in front of + * either "\|", "\)", "\&", or "\n" */if (reg_magic >= MAGIC_OFF) { + val p = regparse!!.ref(1) + + /* ignore \c \C \m and \M after '$' */while (p.charAt(0) == '\\' && (p.charAt(1) == 'c' || p.charAt( + 1) == 'C' || p.charAt(1) == 'm' || p.charAt(1) == 'M') + ) { + p.inc(2) + } + if (p.charAt(0) == '\u0000' || p.charAt(0) == '\\' && + (p.charAt(1) == '|' || p.charAt(1) == '&' || p.charAt(1) == ')' || p.charAt(1) == 'n') || reg_magic == MAGIC_ALL + ) { + curchr = Magic.DOLLAR + } + } + '\\' -> { + val c = regparse!!.charAt(1).code + if (c == '\u0000'.code) { + curchr = '\\'.code /* trailing '\' */ + } else if (c <= '~'.code && META_flags[c] != 0) { + /* + * META contains everything that may be magic sometimes, + * except ^ and $ ("\^" and "\$" are only magic after + * "\v"). We now fetch the next character and toggle its + * magicness. Therefore, \ is so meta-magic that it is + * not in META. + */ + curchr = -1 + prev_at_start = at_start + at_start = false /* be able to say "/\*ptr" */ + regparse!!.inc() + peekchr() + regparse!!.dec() + curchr = Magic.toggle_Magic(curchr) + } else if (REGEXP_ABBR.indexOf(c.toChar()) != -1) { + /* + * Handle abbreviations, like "\t" for TAB -- webb + */ + curchr = backslash_trans(c) + } else if (reg_magic == MAGIC_NONE && (c == '$'.code || c == '^'.code)) { + curchr = Magic.toggle_Magic(c) + } else { + /* + * Next character can never be (made) magic? + * Then backslashing it won't do anything. + */ + curchr = c + } + } + } + } + return curchr + } + + /* + * Eat one lexed character. Do this in a way that we can undo it. + */ + private fun skipchr() { + /* peekchr() eats a backslash, do the same here */ + prevchr_len = if (regparse!!.charAt() == '\\') { + 1 + } else { + 0 + } + if (regparse!!.charAt(prevchr_len) != '\u0000') { + ++prevchr_len + } + regparse!!.inc(prevchr_len) + prev_at_start = at_start + at_start = false + prevprevchr = prevchr + prevchr = curchr + curchr = nextchr /* use previously unget char, or -1 */ + nextchr = -1 + } + + /* + * Skip a character while keeping the value of prev_at_start for at_start. + * prevchr and prevprevchr are also kept. + */ + private fun skipchr_keepstart() { + val `as` = prev_at_start + val pr = prevchr + val prpr = prevprevchr + skipchr() + at_start = `as` + prevchr = pr + prevprevchr = prpr + } + + private fun getchr(): Int { + val chr = peekchr() + skipchr() + return chr + } + + /* + * put character back. Works only once! + */ + private fun ungetchr() { + nextchr = curchr + curchr = prevchr + prevchr = prevprevchr + at_start = prev_at_start + prev_at_start = false + + /* Backup regparse, so that it's at the same position as before the + * getchr(). */regparse!!.dec(prevchr_len) + } + + /* + * read_limits - Read two integers to be taken as a minimum and maximum. + * If the first character is '-', then the range is reversed. + * Should end with 'end'. If minval is missing, zero is default, if maxval is + * missing, a very big number is the default. + */ + private fun read_limits(): MinMax? { + var reverse = false + val first_char: CharPointer + var minval: Int + var maxval: Int + if (regparse!!.charAt() == '-') { + /* Starts with '-', so reverse the range later */ + regparse!!.inc() + reverse = true + } + first_char = regparse!!.ref(0) + minval = getdigits(regparse!!) + maxval = if (regparse!!.charAt() == ',') /* There is a comma */ { + if (Character.isDigit(regparse!!.inc().charAt())) { + getdigits(regparse!!) + } else { + MAX_LIMIT + } + } else if (Character.isDigit(first_char.charAt())) { + minval /* It was \{n} or \{-n} */ + } else { + MAX_LIMIT /* It was \{} or \{-} */ + } + if (regparse!!.charAt() == '\\') { + regparse!!.inc() /* Allow either \{...} or \{...\} */ + } + if (regparse!!.charAt() != '}' || maxval == 0 && minval == 0) { + val `val` = if (reg_magic == MAGIC_ALL) "" else "\\" + injector.messages.showStatusBarMessage(injector.messages.message(Msg.synerror, `val`)) + return null + } + + /* + * Reverse the range if there was a '-', or make sure it is in the right + * order otherwise. + */if (!reverse && minval > maxval || reverse && minval < maxval) { + val tmp = minval + minval = maxval + maxval = tmp + } + skipchr() /* let's be friends with the lexer again */ + val res = MinMax() + res.maxvalue = maxval + res.minvalue = minval + return res + } + + private fun getdigits(p: CharPointer): Int { + var res = 0 + var neg = false + if (p.charAt() == '-') { + neg = true + p.inc() + } + while (Character.isDigit(p.charAt())) { + res = res * 10 + p.charAt().digitToIntOrNull()!! ?: -1 + p.inc() + } + if (neg) { + res = -res + } + return res + } + + /* + * vim_regexec and friends + */ + /* + * Get pointer to the line "lnum", which is relative to "reg_firstlnum". + */ + private fun reg_getline(lnum: Int): CharPointer? { + /* when looking behind for a match/no-match lnum is negative. But we + * can't go before line 1 */ + return if (reg_firstlnum + lnum < 0) { + null + } else CharPointer(injector.engineEditorHelper.getLineBuffer(reg_buf!!, + reg_firstlnum + lnum)) + + //return ml_get_buf(reg_buf, reg_firstlnum + lnum, false); + } + + /* + * Match a regexp against a string. + * "rmp->regprog" is a compiled regexp as returned by vim_regcomp(). + * Uses curbuf for line count and 'iskeyword'. + * + * Return true if there is a match, false if not. + */ + fun vim_regexec(rmp: regmatch_T, line: CharPointer?, col: Int): Boolean { + reg_match = rmp + reg_mmatch = null + reg_maxline = 0 + //reg_win = null; + ireg_ic = rmp.rm_ic + return vim_regexec_both(line, col) != 0 + } + + /* + * Match a regexp against multiple lines. + * "rmp->regprog" is a compiled regexp as returned by vim_regcomp(). + * Uses curbuf for line count and 'iskeyword'. + * + * Return zero if there is no match. Return number of lines contained in the + * match otherwise. + */ + fun vim_regexec_multi( + rmp: regmmatch_T, /*win_T win,*/ + buf: VimEditor?, lcount: Int, lnum: Int, col: Int + ): Int /* window in which to search or null */ /* buffer in which to search */ /* nr of line to start looking for match */ /* column to start looking for match */ { + val r: Int + //VimEditor save_curbuf = curbuf; + reg_match = null + reg_mmatch = rmp + reg_buf = buf + //reg_win = win; + reg_firstlnum = lnum + reg_maxline = lcount - lnum + ireg_ic = rmp.rmm_ic + + /* Need to switch to buffer "buf" to make vim_iswordc() work. */ + //curbuf = buf; + r = vim_regexec_both(null, col) + //curbuf = save_curbuf; + return r + } + + fun vim_string_contains_regexp(rmp: regmmatch_T, string: String): Boolean { + reg_match = null + reg_mmatch = rmp + ireg_ic = rmp.rmm_ic + val prog: regprog_T? + var s: CharPointer + var retval = 0 + reg_tofree = null + prog = reg_mmatch!!.regprog + val line = CharPointer(string) + reg_startpos = reg_mmatch!!.startpos + reg_endpos = reg_mmatch!!.endpos + + /* Be paranoid... */if (prog == null) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_null)) + return false + } + + /* Check validity of program. */if (prog_magic_wrong()) { + return false + } + + /* If pattern contains "\c" or "\C": overrule value of ireg_ic */if (prog.regflags and RF_ICASE != 0) { + ireg_ic = true + } else if (prog.regflags and RF_NOICASE != 0) { + ireg_ic = false + } + + /* If there is a "must appear" string, look for it. */if (prog.regmust != null) { + val c: Char + c = prog.regmust!!.charAt() + s = line + while (cstrchr(s, c).also { s = it!! } != null) { + if (cstrncmp(s, prog.regmust!!, prog.regmlen) == 0) { + break /* Found it. */ + } + s.inc() + } + if (s == null) /* Not present. */ { + // goto the end; + return false + } + } + regline = line.ref(0) + reglnum = 0 + out_of_stack = false + val col = 0 + /* Simplest case: Anchored match need be tried only once. */ + val c: Char + c = regline!!.charAt(col) + if (prog.regstart == '\u0000' || prog.regstart == c || + ireg_ic && prog.regstart.lowercaseChar() == c.lowercaseChar() + ) { + retval = regtry(prog, col) + } + if (out_of_stack) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E363)) + } + return retval > 0 + } + + /* + * Match a regexp against a string ("line" points to the string) or multiple + * lines ("line" is null, use reg_getline()). + */ + private fun vim_regexec_both(line: CharPointer?, col: Int): Int /* column to start looking for match */ { + var line = line + var col = col + val prog: regprog_T? + var s: CharPointer? + var retval: Int + reg_tofree = null + retval = 0 + if (reg_match == null) { + prog = reg_mmatch!!.regprog + line = reg_getline(0) + reg_startpos = reg_mmatch!!.startpos + reg_endpos = reg_mmatch!!.endpos + } else { + prog = reg_match!!.regprog + reg_startp = reg_match!!.startp + reg_endp = reg_match!!.endp + } + + /* Be paranoid... */if (prog == null || line == null) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_null)) + return retval + } + + /* Check validity of program. */if (prog_magic_wrong()) { + return retval + } + + /* If pattern contains "\c" or "\C": overrule value of ireg_ic */if (prog.regflags and RF_ICASE != 0) { + ireg_ic = true + } else if (prog.regflags and RF_NOICASE != 0) { + ireg_ic = false + } + + /* If there is a "must appear" string, look for it. */if (prog.regmust != null) { + val c: Char + c = prog.regmust!!.charAt() + s = line.ref(col) + while (cstrchr(s!!, c).also { s = it } != null) { + if (cstrncmp(s!!, prog.regmust!!, prog.regmlen) == 0) { + break /* Found it. */ + } + s!!.inc() + } + if (s == null) /* Not present. */ { + // goto theend; + return retval + } + } + regline = line.ref(0) + reglnum = 0 + out_of_stack = false + + /* Simplest case: Anchored match need be tried only once. */if (prog.reganch.code != 0) { + val c: Char + c = regline!!.charAt(col) + retval = if (prog.regstart == '\u0000' || prog.regstart == c || + ireg_ic && prog.regstart.lowercaseChar() == c.lowercaseChar() + ) { + regtry(prog, col) + } else { + 0 + } + } else { + /* Messy cases: unanchored match. */ + while (!got_int && !out_of_stack) { + if (prog.regstart != '\u0000') { + /* Skip until the char we know it must start with. */ + s = cstrchr(regline!!.ref(col), prog.regstart) + if (s == null) { + retval = 0 + break + } + col = s!!.pointer() - regline!!.pointer() + } + retval = regtry(prog, col) + if (retval > 0) { + break + } + + /* if not currently on the first line, get it again */if (reglnum != 0) { + regline = reg_getline(0) + reglnum = 0 + } + if (regline!!.charAt(col) == '\u0000') { + break + } + ++col + } + } + if (out_of_stack) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.E363)) + } + + /* Didn't find a match. */ + //vim_free(reg_tofree); + return retval + } + + class reg_extmatch_T { + var matches = arrayOfNulls(NSUBEXP) + } + + /* + * Create a new extmatch and mark it as referenced once. + */ + private fun make_extmatch(): reg_extmatch_T { + return reg_extmatch_T() + } + + /* + * Add a reference to an extmatch. + */ + /* + private reg_extmatch_T ref_extmatch(reg_extmatch_T em) + { + return em; + } + */ + /* + * Remove a reference to an extmatch. If there are no references left, free + * the info. + */ + /* + private void unref_extmatch(reg_extmatch_T em) + { + } + */ + /* + * regtry - try match of "prog" with at regline["col"]. + * Returns 0 for failure, number of lines contained in the match otherwise. + */ + private fun regtry(prog: regprog_T, col: Int): Int { + reginput = regline!!.ref(col) + need_clear_subexpr = true + /* Clear the external match subpointers if necessary. */if (prog.reghasz.code == REX_SET) { + need_clear_zsubexpr = true + } + if (regmatch(CharPointer(prog.program).ref(1))) { + cleanup_subexpr() + if (reg_match == null) { + if (reg_startpos[0]!!.lnum < 0) { + reg_startpos[0]!!.lnum = 0 + reg_startpos[0]!!.col = col + } + if (reg_endpos[0]!!.lnum < 0) { + reg_endpos[0]!!.lnum = reglnum + reg_endpos[0]!!.col = reginput!!.pointer() - regline!!.pointer() + } + } else { + if (reg_startp[0] == null) { + reg_startp[0] = regline!!.ref(col) + } + if (reg_endp[0] == null) { + reg_endp[0] = reginput + } + } + /* Package any found \z(...\) matches for export. Default is none. */ + //unref_extmatch(re_extmatch_out); + re_extmatch_out = null + if (prog.reghasz.code == REX_SET) { + var i: Int + cleanup_zsubexpr() + re_extmatch_out = make_extmatch() + i = 0 + while (i < NSUBEXP) { + if (reg_match == null) { + /* Only accept single line matches. */ + if (reg_startzpos[i]!!.lnum >= 0 && reg_endzpos[i]!!.lnum == reg_startzpos[i]!!.lnum) { + re_extmatch_out!!.matches[i] = reg_getline( + reg_startzpos[i]!!.lnum)!!.ref(reg_startzpos[i]!!.col).substring( + reg_endzpos[i]!!.col - reg_startzpos[i]!!.col) + } + } else { + if (reg_startzp[i] != null && reg_endzp[i] != null) { + re_extmatch_out!!.matches[i] = reg_startzp[i]!! + .substring(reg_endzp[i]!!.pointer() - reg_startzp[i]!!.pointer()) + } + } + i++ + } + } + return 1 + reglnum + } + return 0 + } + + /* + * regmatch - main matching routine + * + * Conceptually the strategy is simple: Check to see whether the current + * node matches, call self recursively to see whether the rest matches, + * and then act accordingly. In practice we make some effort to avoid + * recursion, in particular by going through "ordinary" nodes (that don't + * need to know whether the rest of the match failed) by a loop instead of + * by recursion. + * + * Returns true when there is a match. Leaves reginput and reglnum just after + * the last matched character. + * Returns false when there is no match. Leaves reginput and reglnum in an + * undefined state! + */ + private fun regmatch(scan: CharPointer?): Boolean { + var scan = scan + var next: CharPointer? /* Next node. */ + var op: Int + var c: Char + + /* Some patterns my cause a long time to match, even though they are not + * illegal. E.g., "\([a-z]\+\)\+Q". Allow breaking them with CTRL-C. */ + //fast_breakcheck(); - TODO + while (scan != null) { + if (got_int || out_of_stack) { + return false + } + next = regnext(scan) + op = scan.OP() + /* Check for character class with NL added. */if (WITH_NL(op) && reginput!!.isNul && reglnum < reg_maxline) { + reg_nextline() + } else { + if (WITH_NL(op)) { + op -= ADD_NL + } + c = reginput!!.charAt() + when (op) { + BOL -> if (!reginput!!.equals(regline)) { + return false + } + EOL -> if (c != '\u0000') { + return false + } + RE_BOF -> /* Passing -1 to the getline() function provided for the search + * should always return null if the current line is the first + * line of the file. */if (reglnum != 0 || !reginput!!.equals(regline) || reg_match == null && reg_getline( + -1) != null + ) { + return false + } + RE_EOF -> if (reglnum != reg_maxline || c != '\u0000') { + return false + } + CURSOR -> { + /* Check if the buffer is in a window and compare the + * reg_win->w_cursor position to the match position. */ + val curpos = reg_buf!!.currentCaret().getLogicalPosition() + if (reglnum + reg_firstlnum != curpos.line || + reginput!!.pointer() - regline!!.pointer() != curpos.column + ) { + return false + } + } + RE_LNUM -> if (reg_match != null || !re_num_cmp( + reglnum + reg_firstlnum, scan) + ) { + return false + } + RE_COL -> if (!re_num_cmp(reginput!!.pointer() - regline!!.pointer() + 1, scan)) { + return false + } + RE_VCOL -> {} + BOW -> if (c == '\u0000') /* Can't match at end of line */ { + return false + } else { + if (!CharacterClasses.isWord(c) || reginput!!.pointer() > regline!!.pointer() && + CharacterClasses.isWord(reginput!!.charAt(-1)) + ) { + return false + } + } + EOW -> { + if (reginput!!.equals(regline)) /* Can't match at start of line */ { + return false + } + if (!CharacterClasses.isWord(reginput!!.charAt(-1))) { + return false + } + if (!reginput!!.isNul && CharacterClasses.isWord(c)) { + return false + } + } + ANY -> { + if (c == '\u0000') { + return false + } + reginput!!.inc() + } + IDENT -> { + if (!Character.isJavaIdentifierPart(c)) { + return false + } + reginput!!.inc() + } + SIDENT -> { + if (Character.isDigit(reginput!!.charAt()) || !Character.isJavaIdentifierPart(c)) { + return false + } + reginput!!.inc() + } + KWORD -> { + if (!CharacterClasses.isWord(reginput!!.charAt())) { + return false + } + reginput!!.inc() + } + SKWORD -> { + if (Character.isDigit(reginput!!.charAt()) || !CharacterClasses.isWord(reginput!!.charAt())) { + return false + } + reginput!!.inc() + } + FNAME -> { + if (!CharacterClasses.isFile(c)) { + return false + } + reginput!!.inc() + } + SFNAME -> { + if (Character.isDigit(reginput!!.charAt()) || !CharacterClasses.isFile(c)) { + return false + } + reginput!!.inc() + } + PRINT -> { + if (!CharacterClasses.isPrint(reginput!!.charAt())) { + return false + } + reginput!!.inc() + } + SPRINT -> { + if (Character.isDigit(reginput!!.charAt()) || !CharacterClasses.isPrint(reginput!!.charAt())) { + return false + } + reginput!!.inc() + } + WHITE -> { + if (!CharacterClasses.isWhite(c)) { + return false + } + reginput!!.inc() + } + NWHITE -> { + if (c == '\u0000' || CharacterClasses.isWhite(c)) { + return false + } + reginput!!.inc() + } + DIGIT -> { + if (!Character.isDigit(c)) { + return false + } + reginput!!.inc() + } + NDIGIT -> { + if (c == '\u0000' || Character.isDigit(c)) { + return false + } + reginput!!.inc() + } + HEX -> { + if (!CharacterClasses.isHex(c)) { + return false + } + reginput!!.inc() + } + NHEX -> { + if (c == '\u0000' || CharacterClasses.isHex(c)) { + return false + } + reginput!!.inc() + } + OCTAL -> { + if (!CharacterClasses.isOctal(c)) { + return false + } + reginput!!.inc() + } + NOCTAL -> { + if (c == '\u0000' || CharacterClasses.isOctal(c)) { + return false + } + reginput!!.inc() + } + WORD -> { + if (!CharacterClasses.isWord(c)) { + return false + } + reginput!!.inc() + } + NWORD -> { + if (c == '\u0000' || CharacterClasses.isWord(c)) { + return false + } + reginput!!.inc() + } + HEAD -> { + if (!CharacterClasses.isHead(c)) { + return false + } + reginput!!.inc() + } + NHEAD -> { + if (c == '\u0000' || CharacterClasses.isHead(c)) { + return false + } + reginput!!.inc() + } + ALPHA -> { + if (!CharacterClasses.isAlpha(c)) { + return false + } + reginput!!.inc() + } + NALPHA -> { + if (c == '\u0000' || CharacterClasses.isAlpha(c)) { + return false + } + reginput!!.inc() + } + LOWER -> { + if (!CharacterClasses.isLower(c)) { + return false + } + reginput!!.inc() + } + NLOWER -> { + if (c == '\u0000' || CharacterClasses.isLower(c)) { + return false + } + reginput!!.inc() + } + UPPER -> { + if (!CharacterClasses.isUpper(c)) { + return false + } + reginput!!.inc() + } + NUPPER -> { + if (c == '\u0000' || CharacterClasses.isUpper(c)) { + return false + } + reginput!!.inc() + } + EXACTLY -> { + var len: Int + var opnd: CharPointer + opnd = scan.OPERAND() + /* Inline the first byte, for speed. */if (opnd.charAt() != reginput!!.charAt() && (!ireg_ic || + opnd.charAt().lowercaseChar() != reginput!!.charAt().lowercaseChar()) + ) { + return false + } + if (opnd.charAt(1) == '\u0000') { + reginput!!.inc() /* matched a single char */ + } else { + len = opnd.strlen() + /* Need to match first byte again for multi-byte. */if (cstrncmp(opnd, + reginput!!, + len) != 0 + ) { + return false + } + reginput!!.inc(len) + } + } + ANYOF, ANYBUT -> { + if (c == '\u0000') { + return false + } + if (cstrchr(scan.OPERAND(), c) == null == (op == ANYOF)) { + return false + } + reginput!!.inc() + } + NOTHING -> {} + BACK -> {} + MOPEN, MOPEN + 1, MOPEN + 2, MOPEN + 3, MOPEN + 4, MOPEN + 5, MOPEN + 6, MOPEN + 7, MOPEN + 8, MOPEN + 9 -> { + val no: Int + val save = save_se_T() + no = op - MOPEN + cleanup_subexpr() + save_se(save, reg_startpos[no]!!, reg_startp[no]) + if (regmatch(next)) { + return true + } + restore_se(save, reg_startpos[no]!!, reg_startp[no]) + return false + } + NOPEN, NCLOSE -> return regmatch(next) + ZOPEN + 1, ZOPEN + 2, ZOPEN + 3, ZOPEN + 4, ZOPEN + 5, ZOPEN + 6, ZOPEN + 7, ZOPEN + 8, ZOPEN + 9 -> { + val no: Int + val save = save_se_T() + no = op - ZOPEN + cleanup_zsubexpr() + save_se(save, reg_startzpos[no]!!, reg_startzp[no]) + if (regmatch(next)) { + return true + } + restore_se(save, reg_startzpos[no]!!, reg_startzp[no]) + return false + } + MCLOSE, MCLOSE + 1, MCLOSE + 2, MCLOSE + 3, MCLOSE + 4, MCLOSE + 5, MCLOSE + 6, MCLOSE + 7, MCLOSE + 8, MCLOSE + 9 -> { + val no: Int + val save = save_se_T() + no = op - MCLOSE + cleanup_subexpr() + save_se(save, reg_endpos[no]!!, reg_endp[no]) + if (regmatch(next)) { + return true + } + restore_se(save, reg_endpos[no]!!, reg_endp[no]) + return false + } + ZCLOSE + 1, ZCLOSE + 2, ZCLOSE + 3, ZCLOSE + 4, ZCLOSE + 5, ZCLOSE + 6, ZCLOSE + 7, ZCLOSE + 8, ZCLOSE + 9 -> { + val no: Int + val save = save_se_T() + no = op - ZCLOSE + cleanup_zsubexpr() + save_se(save, reg_endzpos[no]!!, reg_endzp[no]) + if (regmatch(next)) { + return true + } + restore_se(save, reg_endzpos[no]!!, reg_endzp[no]) + return false + } + BACKREF + 1, BACKREF + 2, BACKREF + 3, BACKREF + 4, BACKREF + 5, BACKREF + 6, BACKREF + 7, BACKREF + 8, BACKREF + 9 -> { + var no: Int + var len: Int + var clnum: Int + var ccol: Int + var p: CharPointer? + no = op - BACKREF + cleanup_subexpr() + if (reg_match != null) /* Single-line regexp */ { + if (reg_endp[no] == null) { + /* Backref was not set: Match an empty string. */ + len = 0 + } else { + /* Compare current input with back-ref in the same + * line. */ + len = reg_endp[no]!!.pointer() - reg_startp[no]!!.pointer() + if (cstrncmp(reg_startp[no]!!, reginput!!, len) != 0) { + return false + } + } + } else /* Multi-line regexp */ { + if (reg_endpos[no]!!.lnum < 0) { + /* Backref was not set: Match an empty string. */ + len = 0 + } else { + if (reg_startpos[no]!!.lnum == reglnum + && reg_endpos[no]!!.lnum == reglnum + ) { + /* Compare back-ref within the current line. */ + len = reg_endpos[no]!!.col - reg_startpos[no]!!.col + if (cstrncmp(regline!!.ref(reg_startpos[no]!!.col), reginput!!, len) != 0) { + return false + } + } else { + /* Messy situation: Need to compare between two + * lines. */ + ccol = reg_startpos[no]!!.col + clnum = reg_startpos[no]!!.lnum + while (true) { + + /* Since getting one line may invalidate + * the other, need to make copy. Slow! */if (!regline!!.equals(reg_tofree)) { + reg_tofree = regline!!.ref(0) + reginput = reg_tofree!!.ref(reginput!!.pointer() - regline!!.pointer()) + regline = reg_tofree!!.ref(0) + } + + /* Get the line to compare with. */p = reg_getline(clnum) + len = if (clnum == reg_endpos[no]!!.lnum) { + reg_endpos[no]!!.col - ccol + } else { + p!!.ref(ccol).strlen() + } + if (cstrncmp(p!!.ref(ccol), reginput!!, len) != 0) { + return false /* doesn't match */ + } + if (clnum == reg_endpos[no]!!.lnum) { + break /* match and at end! */ + } + if (reglnum == reg_maxline) { + return false /* text too short */ + } + + /* Advance to next line. */reg_nextline() + ++clnum + ccol = 0 + if (got_int || out_of_stack) { + return false + } + } + + /* found a match! Note that regline may now point + * to a copy of the line, that should not matter. */ + } + } + } + + /* Matched the backref, skip over it. */reginput!!.inc(len) + } + ZREF + 1, ZREF + 2, ZREF + 3, ZREF + 4, ZREF + 5, ZREF + 6, ZREF + 7, ZREF + 8, ZREF + 9 -> { + var no: Int + var len: Int + cleanup_zsubexpr() + no = op - ZREF + val match = re_extmatch_in!!.matches[no] + if (re_extmatch_in != null && match != null) { + len = match.length + if (cstrncmp(CharPointer(match), reginput!!, len) != 0) { + return false + } + reginput!!.inc(len) + } else { + /* Backref was not set: Match an empty string. */ + } + } + BRANCH -> { + if (next!!.OP() != BRANCH) /* No choice. */ { + next = scan.OPERAND() /* Avoid recursion. */ + } else { + val save = regsave_T() + do { + reg_save(save) + if (regmatch(scan!!.OPERAND())) { + return true + } + reg_restore(save) + scan = regnext(scan) + } while (scan != null && scan.OP() == BRANCH) + return false + /* NOTREACHED */ + } + } + BRACE_LIMITS -> { + var no: Int + if (next!!.OP() == BRACE_SIMPLE) { + bl_minval = scan.OPERAND_MIN() + bl_maxval = scan.OPERAND_MAX() + } else if (next.OP() >= BRACE_COMPLEX + && next.OP() < BRACE_COMPLEX + 10 + ) { + no = next.OP() - BRACE_COMPLEX + brace_min[no] = scan.OPERAND_MIN() + brace_max[no] = scan.OPERAND_MAX() + brace_count[no] = 0 + } else { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_internal)) + return false + } + } + BRACE_COMPLEX, BRACE_COMPLEX + 1, BRACE_COMPLEX + 2, BRACE_COMPLEX + 3, BRACE_COMPLEX + 4, BRACE_COMPLEX + 5, BRACE_COMPLEX + 6, BRACE_COMPLEX + 7, BRACE_COMPLEX + 8, BRACE_COMPLEX + 9 -> { + var no: Int + val save = regsave_T() + no = op - BRACE_COMPLEX + ++brace_count[no] + + /* If not matched enough times yet, try one more */if (brace_count[no] <= (if (brace_min[no] <= brace_max[no]) brace_min[no] else brace_max[no])) { + reg_save(save) + if (regmatch(scan.OPERAND())) { + return true + } + reg_restore(save) + --brace_count[no] /* failed, decrement match count */ + return false + } + + /* If matched enough times, may try matching some more */if (brace_min[no] <= brace_max[no]) { + /* Range is the normal way around, use longest match */ + if (brace_count[no] <= brace_max[no]) { + reg_save(save) + if (regmatch(scan.OPERAND())) { + return true /* matched some more times */ + } + reg_restore(save) + --brace_count[no] /* matched just enough times */ + /* continue with the items after \{} */ + } + } else { + /* Range is backwards, use shortest match first */ + if (brace_count[no] <= brace_min[no]) { + reg_save(save) + if (regmatch(next)) { + return true + } + reg_restore(save) + next = scan.OPERAND() + /* must try to match one more item */ + } + } + } + BRACE_SIMPLE, STAR, PLUS -> { + val nextb: Char /* next byte */ + val nextb_ic: Char /* next byte reverse case */ + var count: Int + val save = regsave_T() + val minval: Int + val maxval: Int + + /* + * Lookahead to avoid useless match attempts when we know + * what character comes next. + */if (next!!.OP() == EXACTLY) { + nextb = next.OPERAND().charAt() + nextb_ic = if (ireg_ic) { + if (Character.isUpperCase(nextb)) { + nextb.lowercaseChar() + } else { + nextb.uppercaseChar() + } + } else { + nextb + } + } else { + nextb = '\u0000' + nextb_ic = '\u0000' + } + if (op != BRACE_SIMPLE) { + minval = if (op == STAR) 0 else 1 + maxval = MAX_LIMIT + } else { + minval = bl_minval + maxval = bl_maxval + } + + /* + * When maxval > minval, try matching as much as possible, up + * to maxval. When maxval < minval, try matching at least the + * minimal number (since the range is backwards, that's also + * maxval!). + */count = regrepeat(scan.OPERAND(), maxval) + if (got_int) { + return false + } + if (minval <= maxval) { + /* Range is the normal way around, use longest match */ + while (count >= minval) { + /* If it could match, try it. */ + if (nextb == '\u0000' || reginput!!.charAt() == nextb || reginput!!.charAt() == nextb_ic) { + reg_save(save) + if (regmatch(next)) { + return true + } + reg_restore(save) + } + /* Couldn't or didn't match -- back up one char. */if (--count < minval) { + break + } + if (reginput!!.equals(regline)) { + /* backup to last char of previous line */ + --reglnum + regline = reg_getline(reglnum) + /* Just in case regrepeat() didn't count right. */if (regline == null) { + return false + } + reginput = regline!!.ref(regline!!.strlen()) + // fast_breakcheck(); - TOOD + if (got_int || out_of_stack) { + return false + } + } else { + reginput!!.dec() + } + } + } else { + /* Range is backwards, use shortest match first. + * Careful: maxval and minval are exchanged! */ + if (count < maxval) { + return false + } + while (true) { + + /* If it could work, try it. */if (nextb == '\u0000' || reginput!!.charAt() == nextb || reginput!!.charAt() == nextb_ic) { + reg_save(save) + if (regmatch(next)) { + return true + } + reg_restore(save) + } + /* Couldn't or didn't match: try advancing one char. */if (count == minval || regrepeat( + scan.OPERAND(), + 1) == 0 + ) { + break + } + ++count + if (got_int || out_of_stack) { + return false + } + } + } + return false + } + NOMATCH -> { + val save = regsave_T() + + /* If the operand matches, we fail. Otherwise backup and + * continue with the next item. */reg_save(save) + if (regmatch(scan.OPERAND())) { + return false + } + reg_restore(save) + } + MATCH, SUBPAT -> { + val save = regsave_T() + + /* If the operand doesn't match, we fail. Otherwise backup + * and continue with the next item. */reg_save(save) + if (!regmatch(scan.OPERAND())) { + return false + } + if (op == MATCH) /* zero-width */ { + reg_restore(save) + } + } + BEHIND, NOBEHIND -> { + val save_after = regsave_T() + val save_start = regsave_T() + val save_behind_pos: regsave_T? + val needmatch = op == BEHIND + + /* + * Look back in the input of the operand matches or not. This + * must be done at every position in the input and checking if + * the match ends at the current position. + * First check if the next item matches, that's probably + * faster. + */reg_save(save_start) + if (regmatch(next)) { + /* save the position after the found match for next */ + reg_save(save_after) + + /* start looking for a match with operand at the current + * postion. Go back one character until we find the + * result, hitting the start of the line or the previous + * line (for multi-line matching). + * Set behind_pos to where the match should end, BHPOS + * will match it. */save_behind_pos = if (behind_pos == null) null else regsave_T( + behind_pos!!) + behind_pos = regsave_T(save_start) + while (true) { + reg_restore(save_start) + if (regmatch(scan.OPERAND()) && reg_save_equal(behind_pos!!)) { + behind_pos = save_behind_pos + /* found a match that ends where "next" started */if (needmatch) { + reg_restore(save_after) + return true + } + return false + } + /* + * No match: Go back one character. May go to + * previous line once. + */if (reg_match == null) { + if (save_start.pos.col == 0) { + if (save_start.pos.lnum < behind_pos!!.pos.lnum || + reg_getline(--save_start.pos.lnum) == null + ) { + break + } + reg_restore(save_start) + save_start.pos.col = regline!!.strlen() + } else { + --save_start.pos.col + } + } else { + if (save_start.ptr === regline) { + break + } + save_start.ptr!!.dec() + } + } + + /* NOBEHIND succeeds when no match was found */behind_pos = save_behind_pos + if (!needmatch) { + reg_restore(save_after) + return true + } + } + return false + } + BHPOS -> if (reg_match == null) { + if (behind_pos!!.pos.col != reginput!!.pointer() - regline!!.pointer() || + behind_pos!!.pos.lnum != reglnum + ) { + return false + } + } else if (behind_pos!!.ptr !== reginput) { + return false + } + NEWL -> { + if (c != '\u0000' || reglnum == reg_maxline) { + return false + } + reg_nextline() + } + END -> return true /* Success! */ + else -> { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_re_corr)) + return false + } + } + } + scan = next + } + + /* + * We get here only if there's trouble -- normally "case END" is the + * terminating point. + */injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_re_corr)) + return false + } + + /* + * regrepeat - repeatedly match something simple, return how many. + * Advances reginput (and reglnum) to just after the matched chars. + */ + private fun regrepeat(p: CharPointer, maxcount: Int): Int { + var count = 0 + var scan: CharPointer + val opnd: CharPointer + var mask = 0 + var testval = 0 + scan = reginput!!.ref(0) /* Make local copy of reginput for speed. */ + opnd = p.OPERAND() + when (p.OP()) { + ANY, ANY + ADD_NL -> while (count < maxcount) { + /* Matching anything means we continue until end-of-line (or + * end-of-file for ANY + ADD_NL), only limited by maxcount. */ + while (!scan.isNul && count < maxcount) { + ++count + scan.inc() + } + if (!WITH_NL(p.OP()) || reglnum == reg_maxline || count == maxcount) { + break + } + ++count /* count the line-break */ + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } + IDENT, IDENT + ADD_NL -> { + testval = 1 + while (count < maxcount) { + if (Character.isJavaIdentifierPart(scan.charAt()) && + (testval == 1 || !Character.isDigit(scan.charAt())) + ) { + scan.inc() + } else if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else { + break + } + ++count + } + } + SIDENT, SIDENT + ADD_NL -> while (count < maxcount) { + if (Character.isJavaIdentifierPart(scan.charAt()) && + (testval == 1 || !Character.isDigit(scan.charAt())) + ) { + scan.inc() + } else if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else { + break + } + ++count + } + KWORD, KWORD + ADD_NL -> { + testval = 1 + while (count < maxcount) { + if (CharacterClasses.isWord(scan.charAt()) && (testval == 1 || !Character.isDigit(scan.charAt()))) { + scan.inc() + } else if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else { + break + } + ++count + } + } + SKWORD, SKWORD + ADD_NL -> while (count < maxcount) { + if (CharacterClasses.isWord(scan.charAt()) && (testval == 1 || !Character.isDigit(scan.charAt()))) { + scan.inc() + } else if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else { + break + } + ++count + } + FNAME, FNAME + ADD_NL -> { + testval = 1 + while (count < maxcount) { + if (CharacterClasses.isFile(scan.charAt()) && (testval == 1 || !Character.isDigit(scan.charAt()))) { + scan.inc() + } else if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else { + break + } + ++count + } + } + SFNAME, SFNAME + ADD_NL -> while (count < maxcount) { + if (CharacterClasses.isFile(scan.charAt()) && (testval == 1 || !Character.isDigit(scan.charAt()))) { + scan.inc() + } else if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else { + break + } + ++count + } + PRINT, PRINT + ADD_NL -> { + testval = 1 + while (count < maxcount) { + if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else if (CharacterClasses.isPrint(scan.charAt()) && + (testval == 1 || !Character.isDigit(scan.charAt())) + ) { + scan.inc() + } else { + break + } + ++count + } + } + SPRINT, SPRINT + ADD_NL -> while (count < maxcount) { + if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else if (CharacterClasses.isPrint(scan.charAt()) && + (testval == 1 || !Character.isDigit(scan.charAt())) + ) { + scan.inc() + } else { + break + } + ++count + } + WHITE, WHITE + ADD_NL -> { + mask = CharacterClasses.RI_WHITE + testval = mask + } + NWHITE, NWHITE + ADD_NL -> mask = CharacterClasses.RI_WHITE + DIGIT, DIGIT + ADD_NL -> { + mask = CharacterClasses.RI_DIGIT + testval = mask + } + NDIGIT, NDIGIT + ADD_NL -> mask = CharacterClasses.RI_DIGIT + HEX, HEX + ADD_NL -> { + mask = CharacterClasses.RI_HEX + testval = mask + } + NHEX, NHEX + ADD_NL -> mask = CharacterClasses.RI_HEX + OCTAL, OCTAL + ADD_NL -> { + mask = CharacterClasses.RI_OCTAL + testval = mask + } + NOCTAL, NOCTAL + ADD_NL -> mask = CharacterClasses.RI_OCTAL + WORD, WORD + ADD_NL -> { + mask = CharacterClasses.RI_WORD + testval = mask + } + NWORD, NWORD + ADD_NL -> mask = CharacterClasses.RI_WORD + HEAD, HEAD + ADD_NL -> { + mask = CharacterClasses.RI_HEAD + testval = mask + } + NHEAD, NHEAD + ADD_NL -> mask = CharacterClasses.RI_HEAD + ALPHA, ALPHA + ADD_NL -> { + mask = CharacterClasses.RI_ALPHA + testval = mask + } + NALPHA, NALPHA + ADD_NL -> mask = CharacterClasses.RI_ALPHA + LOWER, LOWER + ADD_NL -> { + mask = CharacterClasses.RI_LOWER + testval = mask + } + NLOWER, NLOWER + ADD_NL -> mask = CharacterClasses.RI_LOWER + UPPER, UPPER + ADD_NL -> { + mask = CharacterClasses.RI_UPPER + testval = mask + } + NUPPER, NUPPER + ADD_NL -> mask = CharacterClasses.RI_UPPER + EXACTLY -> { + val cu: Char + val cl: Char + + /* This doesn't do a multi-byte character, because a MULTIBYTECODE + * would have been used for it. */if (ireg_ic) { + cu = opnd.charAt().uppercaseChar() + cl = opnd.charAt().lowercaseChar() + while (count < maxcount && (scan.charAt() == cu || scan.charAt() == cl)) { + count++ + scan.inc() + } + } else { + cu = opnd.charAt() + while (count < maxcount && scan.charAt() == cu) { + count++ + scan.inc() + } + } + } + ANYOF, ANYOF + ADD_NL -> { + testval = 1 + while (count < maxcount) { + if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else { + if (cstrchr(opnd, scan.charAt()) == null == (testval == 1)) { + break + } + scan.inc() + } + ++count + } + } + ANYBUT, ANYBUT + ADD_NL -> while (count < maxcount) { + if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else { + if (cstrchr(opnd, scan.charAt()) == null == (testval == 1)) { + break + } + scan.inc() + } + ++count + } + NEWL -> while (count < maxcount && scan.isNul && reglnum < reg_maxline) { + count++ + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } + else -> injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_re_corr)) + } + if (mask != 0) { + while (count < maxcount) { + if (scan.isNul) { + if (!WITH_NL(p.OP()) || reglnum == reg_maxline) { + break + } + reg_nextline() + scan = reginput!!.ref(0) + if (got_int) { + break + } + } else if (CharacterClasses.isMask(scan.charAt(), mask, testval)) { + scan.inc() + } else { + break + } + ++count + } + } + reginput = scan.ref(0) + return count + } + + /* + * regnext - dig the "next" pointer out of a node + */ + private fun regnext(p: CharPointer): CharPointer? { + val offset: Int + offset = p.NEXT() + if (offset == 0) { + return null + } + return if (p.OP() == BACK) { + p.ref(-offset) + } else { + p.ref(offset) + } + } + + /* + * Check the regexp program for its magic number. + * Return true if it's wrong. + */ + private fun prog_magic_wrong(): Boolean { + if ((if (reg_match == null) reg_mmatch!!.regprog!!.program else reg_match!!.regprog!!.program)[0].code != REGMAGIC) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_re_corr)) + return true + } + return false + } + + /* + * Cleanup the subexpressions, if this wasn't done yet. + * This construction is used to clear the subexpressions only when they are + * used (to increase speed). + */ + private fun cleanup_subexpr() { + if (need_clear_subexpr) { + if (reg_match == null) { + /* Use 0xff to set lnum to -1 */ + for (i in 0 until NSUBEXP) { + reg_startpos[i]!!.col = -1 + reg_startpos[i]!!.lnum = -1 + reg_endpos[i]!!.col = -1 + reg_endpos[i]!!.lnum = -1 + } + } else { + for (i in 0 until NSUBEXP) { + reg_startp[i] = null + reg_endp[i] = null + } + } + need_clear_subexpr = false + } + } + + private fun cleanup_zsubexpr() { + if (need_clear_zsubexpr) { + if (reg_match == null) { + /* Use 0xff to set lnum to -1 */ + for (i in 0 until NSUBEXP) { + reg_startzpos[i]!!.col = -1 + reg_startzpos[i]!!.lnum = -1 + reg_endzpos[i]!!.col = -1 + reg_endzpos[i]!!.lnum = -1 + } + } else { + for (i in 0 until NSUBEXP) { + reg_startzp[i] = null + reg_endzp[i] = null + } + } + need_clear_zsubexpr = false + } + } + + /* + * Advance reglnum, regline and reginput to the next line. + */ + private fun reg_nextline() { + regline = reg_getline(++reglnum) + reginput = regline!!.ref(0) + // fast_breakcheck(); TODO + } + + /* + * Save the input line and position in a regsave_T. + */ + private fun reg_save(save: regsave_T) { + if (reg_match == null) { + save.pos.col = reginput!!.pointer() - regline!!.pointer() + save.pos.lnum = reglnum + } else { + save.ptr = reginput!!.ref(0) + } + } + + /* + * Restore the input line and position from a regsave_T. + */ + private fun reg_restore(save: regsave_T) { + if (reg_match == null) { + if (reglnum != save.pos.lnum) { + /* only call reg_getline() when the line number changed to save + * a bit of time */ + reglnum = save.pos.lnum + regline = reg_getline(reglnum) + } + reginput = regline!!.ref(save.pos.col) + } else { + reginput = save.ptr!!.ref(0) + } + } + + /* + * Return true if current position is equal to saved position. + */ + private fun reg_save_equal(save: regsave_T): Boolean { + return if (reg_match == null) { + reglnum == save.pos.lnum && reginput!!.equals(regline!!.ref(save.pos.col)) + } else reginput!!.equals(save.ptr) + } + + /* + * Tentatively set the sub-expression start to the current position (after + * calling regmatch() they will have changed). Need to save the existing + * values for when there is no match. + * Use pointer or position, depending on reg_match == null. + */ + private fun save_se(savep: save_se_T, posp: lpos_T, pp: CharPointer?) { + if (reg_match == null) { + savep.pos.lnum = posp.lnum + savep.pos.col = posp.col + posp.lnum = reglnum + posp.col = reginput!!.pointer() - regline!!.pointer() + } else if (pp != null) { + savep.ptr = pp.ref(0) + pp.assign(reginput!!) + } + } + + /* + * We were wrong, restore the sub-expressions. + */ + private fun restore_se(savep: save_se_T, posp: lpos_T, pp: CharPointer?) { + if (reg_match == null) { + posp.col = savep.pos.col + posp.lnum = savep.pos.lnum + } else pp?.assign(savep.ptr!!) + } + + /* + * Compare a number with the operand of RE_LNUM, RE_COL or RE_VCOL. + */ + private fun re_num_cmp(`val`: Int, scan: CharPointer): Boolean { + val n = scan.OPERAND_MIN() + if (scan.OPERAND_CMP() == '>') { + return `val` > n + } + return if (scan.OPERAND_CMP() == '<') { + `val` < n + } else `val` == n + } + + /* + * Compare two strings, ignore case if ireg_ic set. + * Return 0 if strings match, non-zero otherwise. + */ + private fun cstrncmp(s1: CharPointer, s2: CharPointer, n: Int): Int { + return s1.strncmp(s2, n, ireg_ic) + } + + /* + * cstrchr: This function is used a lot for simple searches, keep it fast! + */ + private fun cstrchr(s: CharPointer, c: Char): CharPointer? { + return if (!ireg_ic) { + s.strchr(c) + } else { + s.istrchr(c) + } + + /* tolower() and toupper() can be slow, comparing twice should be a lot + * faster (esp. when using MS Visual C++!). + * For UTF-8 need to use folded case. */ + /* was 1,173ms + int cc; + if (CharacterClasses.isUpper(c)) + { + cc = Character.toLowerCase(c); + } + else if (CharacterClasses.isLower(c)) + { + cc = Character.toUpperCase(c); + } + else + { + return s.strchr(c); + } + */ + + /* Faster version for when there are no multi-byte characters. */ + /* + CharPointer p = s.ref(0); + char ch; + while ((ch = p.charAt()) != '\u0000') + { + if (ch == c || ch == cc) + { + return p; + } + + p.inc(); + } + */ + + /* was 2,053ms + for (p = s.ref(0); !p.isNul(); p.inc()) + { + char ch = p.charAt(); + if (ch == c || ch == cc) + { + return p; + } + } + */ + + //return null; + } + /*************************************************************** + * regsub stuff * + */ + /* + * regtilde(): Replace tildes in the pattern by the old pattern. + * + * Short explanation of the tilde: It stands for the previous replacement + * pattern. If that previous pattern also contains a ~ we should go back a + * step further... But we insert the previous pattern into the current one + * and remember that. + * This still does not handle the case where "magic" changes. TODO? + * + * The tildes are parsed once before the first call to vim_regsub(). + */ + //public CharPointer regtilde(CharPointer source, boolean magic) + //{ + // CharPointer newsub = source.ref(0); + // CharPointer tmpsub; + // CharPointer p; + // int len; + // int prevlen; + // + // for (p = newsub.ref(0); !p.isNul(); p.inc()) + // { + // if ((p.charAt() == '~' && magic != 0) || (p.charAt() == '\\' && p.charAt(1) == '~' && magic == 0)) + // { + // if (reg_prev_sub != null) + // { + // /* length = len(newsub) - 1 + len(prev_sub) + 1 */ + // prevlen = reg_prev_sub.strlen(); + // tmpsub = alloc((unsigned)(STRLEN(newsub) + prevlen)); + // if (tmpsub != null) + // { + // /* copy prefix */ + // len = (int)(p - newsub); /* not including ~ */ + // mch_memmove(tmpsub, newsub, (size_t)len); + // /* interpretate tilde */ + // mch_memmove(tmpsub + len, reg_prev_sub, (size_t)prevlen); + // /* copy postfix */ + // if (!magic) + // ++p; /* back off \ */ + // STRCPY(tmpsub + len + prevlen, p + 1); + // + // if (newsub != source) /* already allocated newsub */ + // vim_free(newsub); + // newsub = tmpsub; + // p = newsub + len + prevlen; + // } + // } + // else if (magic) + // STRCPY(p, p + 1); /* remove '~' */ + // else + // STRCPY(p, p + 2); /* remove '\~' */ + // --p; + // } + // else if (*p == '\\' && p[1]) /* skip escaped characters */ + // ++p; + // } + // + // vim_free(reg_prev_sub); + // if (newsub != source) /* newsub was allocated, just keep it */ + // reg_prev_sub = newsub; + // else /* no ~ found, need to save newsub */ + // reg_prev_sub = vim_strsave(newsub); + // return newsub; + //} + /** + * vim_regsub() - perform substitutions after a vim_regexec() or + * vim_regexec_multi() match. + * + * + * If "copy" is true really copy into "dest". + * If "copy" is false nothing is copied, this is just to find out the length + * of the result. + * + * + * If "backslash" is true, a backslash will be removed later, need to double + * them to keep them, and insert a backslash before a CR to avoid it being + * replaced with a line break later. + * + * + * Note: The matched text must not change between the call of + * vim_regexec()/vim_regexec_multi() and vim_regsub()! It would make the back + * references invalid! + * + * + * Returns the size of the replacement, including terminating '\u0000'. + */ + fun vim_regsub(rmp: regmatch_T?, source: CharPointer?, magic: Int, backslash: Boolean): String? { + reg_match = rmp + reg_mmatch = null + reg_maxline = 0 + return vim_regsub_both(source, magic, backslash) + } + + fun vim_regsub_multi(rmp: regmmatch_T?, lnum: Int, source: CharPointer?, magic: Int, backslash: Boolean): String? { + reg_match = null + reg_mmatch = rmp + //reg_buf = curbuf; /* always works on the current buffer! */ + reg_firstlnum = lnum + reg_maxline = reg_buf!!.lineCount() - lnum + return vim_regsub_both(source, magic, backslash) + } + + private fun subappend(mode: Int, dst: StringBuffer, c: Char): Int { + var mode = mode + when (mode) { + 'u'.code -> { + mode = 0 + dst.append(c.uppercaseChar()) + } + 'U'.code -> dst.append(c.uppercaseChar()) + 'l'.code -> { + mode = 0 + dst.append(c.lowercaseChar()) + } + 'L'.code -> dst.append(c.lowercaseChar()) + else -> dst.append(c) + } + return mode + } + + private fun vim_regsub_both(source: CharPointer?, magic: Int, backslash: Boolean): String? { + val src: CharPointer + val dst = StringBuffer() + var s: CharPointer? + var c: Char + var no = -1 + var clnum = 0 /* init for GCC */ + var len = 0 /* init for GCC */ + //CharPointer eval_result = null; + var mode = 0 + + /* Be paranoid... */if (source == null) { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_null)) + return null + } + if (prog_magic_wrong()) { + return null + } + src = source.ref(0) + + /* + * When the substitute part starts with "\=" evaluate it as an expression. + */if (source.charAt(0) == '\\' && source.charAt(1) == '=') { + } else { + while (src.charAt().also { c = it } != '\u0000') { + src.inc() + if (c == '&' && magic != 0) { + no = 0 + } else if (c == '\\' && !src.isNul) { + if (src.charAt() == '&' && magic == 0) { + src.inc() + no = 0 + } else if ('0' <= src.charAt() && src.charAt() <= '9') { + no = src.charAt() - '0' + src.inc() + } else if ("uUlLeE".indexOf(src.charAt()) != -1) { + when (src.charAtInc()) { + 'u' -> { + mode = 'u'.code + continue + } + 'U' -> { + mode = 'U'.code + continue + } + 'l' -> { + mode = 'l'.code + continue + } + 'L' -> { + mode = 'L'.code + continue + } + 'e', 'E' -> { + mode = 0 + continue + } + } + } + } + if (no < 0) /* Ordinary character. */ { + if (c == '\\' && !src.isNul) { + /* Check for abbreviations -- webb */ + // In vim '\u0000' is represented in memory as '\n', and '\n' as '\r', see :help NL-used-for-Nul + when (src.charAt()) { + 'r' -> { + c = '\n' + src.inc() + } + 'n' -> { + c = '\u0000' + src.inc() + } + 't' -> { + c = '\t' + src.inc() + } + 'b' -> { + c = '\b' + src.inc() + } + else -> { + if (backslash) { + dst.append('\\') + } + c = src.charAt() + src.inc() + } + } + } + + /* Write to buffer, if copy is set. */mode = subappend(mode, dst, c) + } else { + if (reg_match == null) { + clnum = reg_mmatch!!.startpos[no]!!.lnum + if (clnum < 0 || reg_mmatch!!.endpos[no]!!.lnum < 0) { + s = null + } else { + s = reg_getline(clnum)!!.ref(reg_mmatch!!.startpos[no]!!.col) + len = if (reg_mmatch!!.endpos[no]!!.lnum == clnum) { + reg_mmatch!!.endpos[no]!!.col - reg_mmatch!!.startpos[no]!!.col + } else { + s.strlen() + } + } + } else { + s = reg_match!!.startp[no] + if (reg_match!!.endp[no] == null) { + s = null + } else { + len = reg_match!!.endp[no]!!.pointer() - s!!.pointer() + } + } + if (s != null) { + while (true) { + if (len == 0) { + if (reg_match == null) { + if (reg_mmatch!!.endpos[no]!!.lnum == clnum) { + break + } + dst.append('\r') + s = reg_getline(++clnum) + len = if (reg_mmatch!!.endpos[no]!!.lnum == clnum) { + reg_mmatch!!.endpos[no]!!.col + } else { + s!!.strlen() + } + } else { + break + } + } else if (s!!.isNul) /* we hit '\u0000'. */ { + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_re_damg)) + return dst.toString() + } else { + if (backslash && (s.charAt() == '\r' || s.charAt() == '\\')) { + /* + * Insert a backslash in front of a CR, otherwise + * it will be replaced by a line break. + * Number of backslashes will be halved later, + * double them here. + */ + dst.append('\\') + dst.append(s.charAt()) + } else { + mode = subappend(mode, dst, s.charAt()) + } + s.inc() + --len + } + } + } + no = -1 + } + } + } + return dst.toString() + } + + /* + * Used for the submatch() function: get the string from tne n'th submatch in + * allocated memory. + * Returns null when not in a ":s" command and for a non-existing submatch. + */ + /* + public String reg_submatch(int no) + { + StringBuffer retval = null; + CharPointer s; + int len; + int round; + int lnum; + + if (!can_f_submatch) + return null; + + if (submatch_match == null) + { + // First round: compute the length and allocate memory. + // Second round: copy the text. + for (round = 1; round <= 2; ++round) + { + lnum = submatch_mmatch.startpos[no].lnum; + if (lnum < 0 || submatch_mmatch.endpos[no].lnum < 0) + { + return null; + } + + s = reg_getline(lnum).ref(submatch_mmatch.startpos[no].col); + if (s == null) // anti-crash check, cannot happen? + { + break; + } + if (submatch_mmatch.endpos[no].lnum == lnum) + { + // Within one line: take form start to end col. + len = submatch_mmatch.endpos[no].col - submatch_mmatch.startpos[no].col; + if (round == 2) + { + retval.append(s.substring(len)); + } + ++len; + } + else + { + // Multiple lines: take start line from start col, middle + // lines completely and end line up to end col. + len = s.strlen(); + if (round == 2) + { + retval.append(s.substring(len)); + } + ++len; + ++lnum; + while (lnum < submatch_mmatch.endpos[no].lnum) + { + s = reg_getline(lnum++); + if (round == 2) + { + retval.append(s.substring(s.strlen())); + } + len += s.strlen(); + if (round == 2) + { + retval.append('\n'); + } + ++len; + } + if (round == 2) + { + retval.append(reg_getline(lnum).substring(submatch_mmatch.endpos[no].col)); + } + len += submatch_mmatch.endpos[no].col; + if (round == 2) + { + //retval[len] = '\u0000'; + } + ++len; + } + + if (round == 1) + { + retval = new StringBuffer(); + if (s == null) + return null; + } + } + } + else + { + if (submatch_match.endp[no] == null) + { + retval = null; + } + else + { + s = submatch_match.startp[no]; + retval = new StringBuffer(s.substring(submatch_match.endp[no].pointer() - s.pointer())); + } + } + + return retval == null ? null : retval.toString(); + } + */ + /* + * regdump - dump a regexp onto stdout in vaguely comprehensible form + */ + private fun regdump(pattern: String, r: regprog_T): String { + val start: CharPointer + val s: CharPointer + var op = EXACTLY /* Arbitrary non-END op. */ + var next: CharPointer? + var end: CharPointer? = null + val res = StringBuilder() + res.append("\nregcomp(").append(pattern).append("):\n") + start = CharPointer(r.program) + s = start.ref(1) + /* + * Loop until we find the END that isn't before a referred next (an END + * can also appear in a NOMATCH operand). + */while (op != END || !s.end()) { + op = s.OP() + res.append(s.pointer() - start.pointer()) + res.append(regprop(s)) + next = regnext(s) + if (next == null) /* Next ptr. */ { + res.append("(0)") + } else { + res.append("(").append(s.pointer() - start.pointer() + (next.pointer() - s.pointer())).append(")") + } + if (end == null || next != null && end.pointer() < next.pointer()) { + end = next + } + if (op == BRACE_LIMITS) { + /* Two short ints */ + res.append(" minval ") + res.append(s.OPERAND_MIN()) + res.append(", maxval ") + res.append(s.OPERAND_MAX()) + s.inc(8) + } + s.inc(3) + if (op == ANYOF || op == ANYOF + ADD_NL || op == ANYBUT || op == ANYBUT + ADD_NL || op == EXACTLY) { + /* Literal string, where present. */ + while (!s.isNul) { + res.append(s.charAt()) + s.inc() + } + s.inc() + } + res.append("\n") + } + + /* Header fields of interest. */if (r.regstart != '\u0000') { + res.append("start `") + if (r.regstart < ' ') { + res.append("^").append('@' + r.regstart.toInt()) + } else { + res.append(r.regstart) + } + res.append("' ") + res.append(Integer.toString(r.regstart.code, 16)) + } + if (r.reganch.code != 0) { + res.append("anchored: ") + } + if (r.regmust != null) { + res.append("must have \"").append(r.regmust!!.substring(r.regmust!!.strlen())).append("\"") + } + res.append("\n") + return res.toString() + } + + /* +* regprop - printable representation of opcode +*/ + private fun regprop(op: CharPointer): @NonNls String { + val p: @NonNls String? + val buf = StringBuilder() + buf.append(':') + p = when (op.OP()) { + BOL -> "BOL" + EOL -> "EOL" + RE_BOF -> "BOF" + RE_EOF -> "EOF" + CURSOR -> "CURSOR" + RE_LNUM -> "RE_LNUM" + RE_COL -> "RE_COL" + RE_VCOL -> "RE_VCOL" + BOW -> "BOW" + EOW -> "EOW" + ANY -> "ANY" + ANY + ADD_NL -> "ANY+NL" + ANYOF -> "ANYOF" + ANYOF + ADD_NL -> "ANYOF+NL" + ANYBUT -> "ANYBUT" + ANYBUT + ADD_NL -> "ANYBUT+NL" + IDENT -> "IDENT" + IDENT + ADD_NL -> "IDENT+NL" + SIDENT -> "SIDENT" + SIDENT + ADD_NL -> "SIDENT+NL" + KWORD -> "KWORD" + KWORD + ADD_NL -> "KWORD+NL" + SKWORD -> "SKWORD" + SKWORD + ADD_NL -> "SKWORD+NL" + FNAME -> "FNAME" + FNAME + ADD_NL -> "FNAME+NL" + SFNAME -> "SFNAME" + SFNAME + ADD_NL -> "SFNAME+NL" + PRINT -> "PRINT" + PRINT + ADD_NL -> "PRINT+NL" + SPRINT -> "SPRINT" + SPRINT + ADD_NL -> "SPRINT+NL" + WHITE -> "WHITE" + WHITE + ADD_NL -> "WHITE+NL" + NWHITE -> "NWHITE" + NWHITE + ADD_NL -> "NWHITE+NL" + DIGIT -> "DIGIT" + DIGIT + ADD_NL -> "DIGIT+NL" + NDIGIT -> "NDIGIT" + NDIGIT + ADD_NL -> "NDIGIT+NL" + HEX -> "HEX" + HEX + ADD_NL -> "HEX+NL" + NHEX -> "NHEX" + NHEX + ADD_NL -> "NHEX+NL" + OCTAL -> "OCTAL" + OCTAL + ADD_NL -> "OCTAL+NL" + NOCTAL -> "NOCTAL" + NOCTAL + ADD_NL -> "NOCTAL+NL" + WORD -> "WORD" + WORD + ADD_NL -> "WORD+NL" + NWORD -> "NWORD" + NWORD + ADD_NL -> "NWORD+NL" + HEAD -> "HEAD" + HEAD + ADD_NL -> "HEAD+NL" + NHEAD -> "NHEAD" + NHEAD + ADD_NL -> "NHEAD+NL" + ALPHA -> "ALPHA" + ALPHA + ADD_NL -> "ALPHA+NL" + NALPHA -> "NALPHA" + NALPHA + ADD_NL -> "NALPHA+NL" + LOWER -> "LOWER" + LOWER + ADD_NL -> "LOWER+NL" + NLOWER -> "NLOWER" + NLOWER + ADD_NL -> "NLOWER+NL" + UPPER -> "UPPER" + UPPER + ADD_NL -> "UPPER+NL" + NUPPER -> "NUPPER" + NUPPER + ADD_NL -> "NUPPER+NL" + BRANCH -> "BRANCH" + EXACTLY -> "EXACTLY" + NOTHING -> "NOTHING" + BACK -> "BACK" + END -> "END" + MOPEN -> "MATCH START" + MOPEN + 1, MOPEN + 2, MOPEN + 3, MOPEN + 4, MOPEN + 5, MOPEN + 6, MOPEN + 7, MOPEN + 8, MOPEN + 9 -> { + buf.append("MOPEN").append(op.OP() - MOPEN) + null + } + MCLOSE -> "MATCH END" + MCLOSE + 1, MCLOSE + 2, MCLOSE + 3, MCLOSE + 4, MCLOSE + 5, MCLOSE + 6, MCLOSE + 7, MCLOSE + 8, MCLOSE + 9 -> { + buf.append("MCLOSE").append(op.OP() - MCLOSE) + null + } + BACKREF + 1, BACKREF + 2, BACKREF + 3, BACKREF + 4, BACKREF + 5, BACKREF + 6, BACKREF + 7, BACKREF + 8, BACKREF + 9 -> { + buf.append("BACKREF").append(op.OP() - BACKREF) + null + } + NOPEN -> "NOPEN" + NCLOSE -> "NCLOSE" + ZOPEN + 1, ZOPEN + 2, ZOPEN + 3, ZOPEN + 4, ZOPEN + 5, ZOPEN + 6, ZOPEN + 7, ZOPEN + 8, ZOPEN + 9 -> { + buf.append("ZOPEN").append(op.OP() - ZOPEN) + null + } + ZCLOSE + 1, ZCLOSE + 2, ZCLOSE + 3, ZCLOSE + 4, ZCLOSE + 5, ZCLOSE + 6, ZCLOSE + 7, ZCLOSE + 8, ZCLOSE + 9 -> { + buf.append("ZCLOSE").append(op.OP() - ZCLOSE) + null + } + ZREF + 1, ZREF + 2, ZREF + 3, ZREF + 4, ZREF + 5, ZREF + 6, ZREF + 7, ZREF + 8, ZREF + 9 -> { + buf.append("ZREF").append(op.OP() - ZREF) + null + } + STAR -> "STAR" + PLUS -> "PLUS" + NOMATCH -> "NOMATCH" + MATCH -> "MATCH" + BEHIND -> "BEHIND" + NOBEHIND -> "NOBEHIND" + SUBPAT -> "SUBPAT" + BRACE_LIMITS -> "BRACE_LIMITS" + BRACE_SIMPLE -> "BRACE_SIMPLE" + BRACE_COMPLEX, BRACE_COMPLEX + 1, BRACE_COMPLEX + 2, BRACE_COMPLEX + 3, BRACE_COMPLEX + 4, BRACE_COMPLEX + 5, BRACE_COMPLEX + 6, BRACE_COMPLEX + 7, BRACE_COMPLEX + 8, BRACE_COMPLEX + 9 -> { + buf.append("BRACE_COMPLEX").append(op.OP() - BRACE_COMPLEX) + null + } + NEWL -> "NEWL" + else -> { + buf.append("corrupt ").append(op.OP()) + null + } + } + if (p != null) { + buf.append(p) + } + return buf.toString() + } + + class regprog_T { + var regstart = 0.toChar() + var reganch = 0.toChar() + var regmust: CharPointer? = null + var regmlen = 0 + var regflags = 0 + var reghasz = 0.toChar() + var program = StringBuffer() + } + + private class MinMax { + var minvalue = 0 + var maxvalue = 0 + } + + class lpos_T { + constructor(pos: lpos_T) { + lnum = pos.lnum + col = pos.col + } + + constructor() {} + + @JvmField + var lnum = 0 + @JvmField + var col = 0 + override fun toString(): String { + return "lpos: ($lnum, $col)" + } + } + + /* + * Structure used to save the current input state, when it needs to be + * restored after trying a match. Used by reg_save() and reg_restore(). + */ + private class regsave_T { + var ptr /* reginput pointer, for single-line regexp */: CharPointer? = null + var pos = lpos_T() /* reginput pos, for multi-line regexp */ + + constructor() {} + constructor(rhs: regsave_T) { + ptr = if (rhs.ptr == null) null else CharPointer("").assign(rhs.ptr!!) + pos = lpos_T(rhs.pos) + } + } + + /* struct to save start/end pointer/position in for \(\) */ + private class save_se_T { + var ptr: CharPointer? = null + var pos = lpos_T() + } + + class regmatch_T { + var regprog: regprog_T? = null + var startp = arrayOfNulls(NSUBEXP) + var endp = arrayOfNulls(NSUBEXP) + var rm_ic = false + } + + class regmmatch_T { + @JvmField + var regprog: regprog_T? = null + @JvmField + var startpos = arrayOfNulls(NSUBEXP) + @JvmField + var endpos = arrayOfNulls(NSUBEXP) + @JvmField + var rmm_ic = false + + init { + for (i in 0 until NSUBEXP) { + startpos[i] = lpos_T() + endpos[i] = lpos_T() + } + } + } + + private val reg_do_extmatch = 0 + private val reg_prev_sub: CharPointer? = null + private var regparse /* Input-scan pointer. */: CharPointer? = null + private var prevchr_len /* byte length of previous char */ = 0 + private var num_complex_braces /* Complex \{...} count */ = 0 + private var regnpar /* () count. */ = 0 + private var regnzpar /* \z() count. */ = 0 + private var re_has_z /* \z item detected */ = 0.toChar() + private var regcode /* Code-emit pointer */: CharPointer? = null + private val had_endbrace = BooleanArray(NSUBEXP) /* flags, true if end of () found */ + private var regflags /* RF_ flags for prog */ = 0 + private val brace_min = IntArray(10) /* Minimums for complex brace repeats */ + private val brace_max = IntArray(10) /* Maximums for complex brace repeats */ + private val brace_count = IntArray(10) /* Current counts for complex brace repeats */ + private var had_eol /* true when EOL found by vim_regcomp() */ = false + private var one_exactly = false /* only do one char for EXACTLY */ + private var reg_magic /* magicness of the pattern: */ = 0 + private var curchr = 0 + + /* + * getchr() - get the next character from the pattern. We know about + * magic and such, so therefore we need a lexical analyzer. + */ + /* static int curchr; */ + private var prevprevchr = 0 + private var prevchr = 0 + private var nextchr /* used for ungetchr() */ = 0 + + /* + * Note: prevchr is sometimes -1 when we are not at the start, + * eg in /[ ^I]^ the pattern was never found even if it existed, because ^ was + * taken to be magic -- webb + */ + private var at_start /* True when on the first character */ = false + private var prev_at_start /* True when on the second character */ = false + + /* + * Global work variables for vim_regexec(). + */ + /* The current match-position is remembered with these variables: */ + private var reglnum /* line number, relative to first line */ = 0 + private var regline /* start of current line */: CharPointer? = null + private var reginput /* current input, points into "regline" */: CharPointer? = null + private var need_clear_subexpr /* subexpressions still need to be + * cleared */ = false + private var need_clear_zsubexpr = false /* extmatch subexpressions + * still need to be cleared */ + private var out_of_stack /* true when ran out of stack space */ = false + + /* + * Internal copy of 'ignorecase'. It is set at each call to vim_regexec(). + * Normally it gets the value of "rm_ic" or "rmm_ic", but when the pattern + * contains '\c' or '\C' the value is overruled. + */ + private var ireg_ic = false + + /* + * Sometimes need to save a copy of a line. Since alloc()/free() is very + * slow, we keep one allocated piece of memory and only re-allocate it when + * it's too small. It's freed in vim_regexec_both() when finished. + */ + private var reg_tofree: CharPointer? = null + + //private int reg_tofreelen; + /* + * These variables are set when executing a regexp to speed up the execution. + * Which ones are set depends on whethere a single-line or multi-line match is + * done: + * single-line multi-line + * reg_match ®match_T null + * reg_mmatch null ®mmatch_T + * reg_startp reg_match->startp + * reg_endp reg_match->endp + * reg_startpos reg_mmatch->startpos + * reg_endpos reg_mmatch->endpos + * reg_win null window in which to search + * reg_buf buffer in which to search + * reg_firstlnum first line in which to search + * reg_maxline 0 last line nr + */ + private var reg_match: regmatch_T? = null + private var reg_mmatch: regmmatch_T? = null + private var reg_startp = arrayOfNulls(NSUBEXP) + private var reg_endp = arrayOfNulls(NSUBEXP) + private var reg_startpos = arrayOfNulls(NSUBEXP) + private var reg_endpos = arrayOfNulls(NSUBEXP) + + //static win_T *reg_win; + private var reg_buf: VimEditor? = null + private var reg_firstlnum = 0 + private var reg_maxline = 0 + private var behind_pos: regsave_T? = null + private val reg_startzp = arrayOfNulls(NSUBEXP) /* Workspace to mark beginning */ + private val reg_endzp = arrayOfNulls(NSUBEXP) /* and end of \z(...\) matches */ + private val reg_startzpos = arrayOfNulls(NSUBEXP) /* idem, beginning pos */ + private val reg_endzpos = arrayOfNulls(NSUBEXP) /* idem, end pos */ + private val got_int = false + + /* + * The arguments from BRACE_LIMITS are stored here. They are actually local + * to regmatch(), but they are here to reduce the amount of stack space used + * (it can be called recursively many times). + */ + private var bl_minval = 0 + private var bl_maxval = 0 + + companion object { + var re_extmatch_out: reg_extmatch_T? = null + var re_extmatch_in: reg_extmatch_T? = null + + /* + * The opcodes are: + */ + /* definition number opnd? meaning */ + private const val END = 0 /* End of program or NOMATCH operand. */ + private const val BOL = 1 /* Match "" at beginning of line. */ + private const val EOL = 2 /* Match "" at end of line. */ + private const val BRANCH = 3 /* node Match this alternative, or the next... */ + private const val BACK = 4 /* Match "", "next" ptr points backward. */ + private const val EXACTLY = 5 /* str Match this string. */ + private const val NOTHING = 6 /* Match empty string. */ + private const val STAR = 7 /* node Match this (simple) thing 0 or more times. */ + private const val PLUS = 8 /* node Match this (simple) thing 1 or more times. */ + private const val MATCH = 9 /* node match the operand zero-width */ + private const val NOMATCH = 10 /* node check for no match with operand */ + private const val BEHIND = 11 /* node look behind for a match with operand */ + private const val NOBEHIND = 12 /* node look behind for no match with operand */ + private const val SUBPAT = 13 /* node match the operand here */ + private const val BRACE_SIMPLE = 14 /* node Match this (simple) thing between m and + * n times (\{m,n\}). */ + private const val BOW = 15 /* Match "" after [^a-zA-Z0-9_] */ + private const val EOW = 16 /* Match "" at [^a-zA-Z0-9_] */ + private const val BRACE_LIMITS = 17 /* nr nr define the min & max for BRACE_SIMPLE + * and BRACE_COMPLEX. */ + private const val NEWL = 18 /* Match line-break */ + private const val BHPOS = 19 /* End position for BEHIND or NOBEHIND */ + + /* character classes: 20-48 normal, 50-78 include a line-break */ + private const val ADD_NL = 30 + private const val ANY = 20 /* Match any one character. */ + private const val FIRST_NL = ANY + ADD_NL + private const val ANYOF = 21 /* str Match any character in this string. */ + private const val ANYBUT = 22 /* str Match any character not in this + * string. */ + private const val IDENT = 23 /* Match identifier char */ + private const val SIDENT = 24 /* Match identifier char but no digit */ + private const val KWORD = 25 /* Match keyword char */ + private const val SKWORD = 26 /* Match word char but no digit */ + private const val FNAME = 27 /* Match file name char */ + private const val SFNAME = 28 /* Match file name char but no digit */ + private const val PRINT = 29 /* Match printable char */ + private const val SPRINT = 30 /* Match printable char but no digit */ + private const val WHITE = 31 /* Match whitespace char */ + private const val NWHITE = 32 /* Match non-whitespace char */ + private const val DIGIT = 33 /* Match digit char */ + private const val NDIGIT = 34 /* Match non-digit char */ + private const val HEX = 35 /* Match hex char */ + private const val NHEX = 36 /* Match non-hex char */ + private const val OCTAL = 37 /* Match octal char */ + private const val NOCTAL = 38 /* Match non-octal char */ + private const val WORD = 39 /* Match word char */ + private const val NWORD = 40 /* Match non-word char */ + private const val HEAD = 41 /* Match head char */ + private const val NHEAD = 42 /* Match non-head char */ + private const val ALPHA = 43 /* Match alpha char */ + private const val NALPHA = 44 /* Match non-alpha char */ + private const val LOWER = 45 /* Match lowercase char */ + private const val NLOWER = 46 /* Match non-lowercase char */ + private const val UPPER = 47 /* Match uppercase char */ + private const val NUPPER = 48 /* Match non-uppercase char */ + private const val LAST_NL = NUPPER + ADD_NL + private const val MOPEN = 80 /* -89 Mark this point in input as start of + * \( subexpr. MOPEN + 0 marks start of + * match. */ + private const val MCLOSE = 90 /* -99 Analogous to MOPEN. MCLOSE + 0 marks + * end of match. */ + private const val BACKREF = 100 /* -109 node Match same string again \1-\9 */ + private const val ZOPEN = 110 /* -119 Mark this point in input as start of + * \z( subexpr. */ + private const val ZCLOSE = 120 /* -129 Analogous to ZOPEN. */ + private const val ZREF = 130 /* -139 node Match external submatch \z1-\z9 */ + private const val BRACE_COMPLEX = 140 /* -149 node Match nodes between m & n times */ + private const val NOPEN = 150 /* Mark this point in input as start of + \%( subexpr. */ + private const val NCLOSE = 151 /* Analogous to NOPEN. */ + private const val RE_BOF = 201 /* Match "" at beginning of file. */ + private const val RE_EOF = 202 /* Match "" at end of file. */ + private const val CURSOR = 203 /* Match location of cursor. */ + private const val RE_LNUM = 204 /* nr cmp Match line number */ + private const val RE_COL = 205 /* nr cmp Match column number */ + private const val RE_VCOL = 206 /* nr cmp Match virtual column number */ + private const val REGMAGIC = 156 + private const val REX_SET = 1 + private const val REX_USE = 2 + private const val MAX_LIMIT = Int.MAX_VALUE + private const val NOT_MULTI = 0 + private const val MULTI_ONE = 1 + private const val MULTI_MULT = 2 + + /* + * Flags to be passed up and down. + */ + private const val HASWIDTH = 0x1 /* Known never to match null string. */ + private const val SIMPLE = 0x2 /* Simple enough to be STAR/PLUS operand. */ + private const val SPSTART = 0x4 /* Starts with * or +. */ + private const val HASNL = 0x8 /* Contains some \n. */ + private const val WORST = 0 /* Worst case. */ + + /* + * REGEXP_INRANGE contains all characters which are always special in a [] + * range after '\'. + * REGEXP_ABBR contains all characters which act as abbreviations after '\'. + * These are: + * \n - New line (NL). + * \r - Carriage Return (CR). + * \t - Tab (TAB). + * \e - Escape (ESC). + * \b - Backspace (Ctrl_H). + */ + private const val REGEXP_INRANGE = "]^-n\\" + private const val REGEXP_ABBR = "nrteb" + + /* flags for regflags */ + private const val RF_ICASE = 1 /* ignore case */ + private const val RF_NOICASE = 2 /* don't ignore case */ + private const val RF_HASNL = 4 /* can match a NL */ + + /* + * Global work variables for vim_regcomp(). + */ + private const val NSUBEXP = 10 + private const val MAGIC_NONE = 1 /* "\V" very unmagic */ + private const val MAGIC_OFF = 2 /* "\M" or 'magic' off */ + private const val MAGIC_ON = 3 /* "\m" or 'magic' */ + private const val MAGIC_ALL = 4 /* "\v" very magic */ + + /* + * META contains all characters that may be magic, except '^' and '$'. + */ + /* META[] is used often enough to justify turning it into a table. */ + private val META_flags = intArrayOf( + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* % & ( ) * + . */ + 0, 0, 0, 0, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, /* 1 2 3 4 5 6 7 8 9 < = > ? */ + 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, /* @ A C D F H I K L M O */ + 1, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 0, 1, /* P S U V W X [ _ */ + 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 0, 0, 1, /* a c d f h i k l m n o */ + 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 1, /* p s u v w x z { | ~ */ + 1, 0, 0, 1, 0, 1, 1, 1, 1, 0, 1, 1, 1, 0, 1 + ) + + /* arguments for reg() */ + private const val REG_NOPAREN = 0 /* toplevel reg() */ + private const val REG_PAREN = 1 /* \(\) */ + private const val REG_ZPAREN = 2 /* \z(\) */ + private const val REG_NPAREN = 3 /* \%(\) */ + private fun WITH_NL(op: Int): Boolean { + return op >= FIRST_NL && op <= LAST_NL + } + + /* + * Check for a character class name. "pp" points to the '['. + * Returns one of the CLASS_ items. CLASS_NONE means that no item was + * recognized. Otherwise "pp" is advanced to after the item. + */ + private fun skip_class_name(pp: CharPointer): Int { + var i: Int + if (pp.charAt(1) == ':') { + i = 0 + while (i < (CharacterClasses.CLASS_NAMES?.size ?: 0)) { + if (pp.ref(2) + .strncmp(CharacterClasses.CLASS_NAMES!![i], CharacterClasses.CLASS_NAMES[i].length) == 0 + ) { + pp.inc(CharacterClasses.CLASS_NAMES[i].length + 2) + return i + } + ++i + } + } + return CharacterClasses.CLASS_NONE + } + + /* + * Skip over a "[]" range. + * "p" must point to the character after the '['. + * The returned pointer is on the matching ']', or the terminating NUL. + */ + private fun skip_anyof(p: CharPointer): CharPointer { + if (p.charAt() == '^') /* Complement of range. */ { + p.inc() + } + if (p.charAt() == ']' || p.charAt() == '-') { + p.inc() + } + while (!p.end() && p.charAt() != ']') { + if (p.charAt() == '-') { + p.inc() + if (!p.end() && p.charAt() != ']') { + p.inc() + } + } else if (p.charAt() == '\\' && + (REGEXP_INRANGE.indexOf(p.charAt(1)) != -1 || REGEXP_ABBR.indexOf(p.charAt(1)) != -1) + ) { + p.inc(2) + } else if (p.charAt() == '[') { + if (skip_class_name(p) == CharacterClasses.CLASS_NONE) { + p.inc() /* It was not a class name */ + } + } else { + p.inc() + } + } + return p + } + + /* + * Skip past regular expression. + * Stop at end of 'p' of where 'dirc' is found ('/', '?', etc). + * Take care of characters with a backslash in front of it. + * Skip strings inside [ and ]. + */ + @JvmStatic + fun skip_regexp(p: CharPointer, dirc: Char, magic: Boolean): CharPointer { + var p = p + var mymagic: Int + mymagic = if (magic) { + MAGIC_ON + } else { + MAGIC_OFF + } + while (!p.end()) { + if (p.charAt() == dirc) /* found end of regexp */ { + break + } + if (p.charAt() == '[' && mymagic >= MAGIC_ON || + p.charAt() == '\\' && p.charAt(1) == '[' && mymagic <= MAGIC_OFF + ) { + p = skip_anyof(p.ref(1)) + if (p.end()) { + break + } + } else if (p.charAt() == '\\' && p.charAt(1) != '\u0000') { + p.inc() /* skip next character */ + if (p.charAt() == 'v') { + mymagic = MAGIC_ALL + } else if (p.charAt() == 'V') { + mymagic = MAGIC_NONE + } + } + p.inc() + } + return p + } + + //private boolean can_f_submatch = false; /* true when submatch() can be used */ + /* These pointers are used instead of reg_match and reg_mmatch for + * reg_submatch(). Needed for when the substitution string is an expression + * that contains a call to substitute() and submatch(). */ + //private regmatch_T submatch_match; + //private regmmatch_T submatch_mmatch; + private val logger: VimLogger = injector.getLogger(RegExp::class.java) + } +} \ No newline at end of file diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/Executable.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/Executable.kt similarity index 84% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/Executable.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/Executable.kt index 14b00a3eea1..3a10911a246 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/Executable.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/Executable.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor interface Executable : VimLContext { @@ -29,5 +29,5 @@ interface Executable : VimLContext { return vimContext } - fun execute(editor: Editor, context: DataContext): ExecutionResult + fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/ExecutionResult.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/ExecutionResult.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/ExecutionResult.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/ExecutionResult.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/Script.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/Script.kt similarity index 90% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/Script.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/Script.kt index 0e83a50995b..fe2f357735e 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/Script.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/Script.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.statements.FunctionDeclaration @@ -37,7 +37,7 @@ data class Script(val units: List = ArrayList()) : Executable { throw RuntimeException("Script has no parent context") } - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { var latestResult: ExecutionResult = ExecutionResult.Success for (unit in units) { unit.vimContext = this diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/VimLContext.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/VimLContext.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/VimLContext.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/VimLContext.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/Command.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/Command.kt similarity index 72% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/Command.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/Command.kt index 5177befdc1a..4fa770f03ca 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/Command.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/Command.kt @@ -18,15 +18,13 @@ package com.maddyhome.idea.vim.vimscript.model.commands -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.application.ApplicationManager -import com.intellij.openapi.diagnostic.logger -import com.intellij.openapi.editor.Caret -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.util.ThrowableComputable -import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.VimCaret +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.common.TextRange +import com.maddyhome.idea.vim.diagnostic.vimLogger import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.MissingArgumentException import com.maddyhome.idea.vim.ex.MissingRangeException @@ -34,9 +32,7 @@ import com.maddyhome.idea.vim.ex.NoArgumentAllowedException import com.maddyhome.idea.vim.ex.NoRangeAllowedException import com.maddyhome.idea.vim.ex.ranges.LineRange import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.Msg -import com.maddyhome.idea.vim.helper.exitVisualMode import com.maddyhome.idea.vim.helper.inVisualMode import com.maddyhome.idea.vim.helper.noneOfEnum import com.maddyhome.idea.vim.vimscript.model.Executable @@ -49,41 +45,41 @@ sealed class Command(var commandRanges: Ranges, val commandArgument: String) : E abstract val argFlags: CommandHandlerFlags protected open val optFlags: EnumSet = noneOfEnum() - private val logger = logger() + private val logger = vimLogger() abstract class ForEachCaret(ranges: Ranges, argument: String = "") : Command(ranges, argument) { - abstract fun processCommand(editor: Editor, caret: Caret, context: DataContext): ExecutionResult + abstract fun processCommand(editor: VimEditor, caret: VimCaret, context: ExecutionContext): ExecutionResult } abstract class SingleExecution(ranges: Ranges, argument: String = "") : Command(ranges, argument) { - abstract fun processCommand(editor: Editor, context: DataContext): ExecutionResult + abstract fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult } @Throws(ExException::class) - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { checkRanges() checkArgument() if (editor.inVisualMode && Flag.SAVE_VISUAL !in argFlags.flags) { - editor.exitVisualMode() + editor.exitVisualModeNative() } - if (argFlags.access == Access.WRITABLE && !editor.document.isWritable) { + if (argFlags.access == Access.WRITABLE && !editor.isDocumentWritable()) { logger.info("Trying to modify readonly document") return ExecutionResult.Error } - val runCommand = ThrowableComputable { runCommand(editor, context) } + val runCommand = { runCommand(editor, context) } return when (argFlags.access) { - Access.WRITABLE -> ApplicationManager.getApplication().runWriteAction(runCommand) - Access.READ_ONLY -> ApplicationManager.getApplication().runReadAction(runCommand) - Access.SELF_SYNCHRONIZED -> runCommand.compute() + Access.WRITABLE -> injector.application.runWriteAction(runCommand) + Access.READ_ONLY -> injector.application.runReadAction(runCommand) + Access.SELF_SYNCHRONIZED -> runCommand.invoke() } } - private fun runCommand(editor: Editor, context: DataContext): ExecutionResult { + private fun runCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { var result: ExecutionResult = ExecutionResult.Success when (this) { is ForEachCaret -> { - editor.caretModel.runForEachCaret( + editor.forEachNativeCaret( { caret -> if (result is ExecutionResult.Success) { result = processCommand(editor, caret, context) @@ -99,12 +95,12 @@ sealed class Command(var commandRanges: Ranges, val commandArgument: String) : E private fun checkRanges() { if (RangeFlag.RANGE_FORBIDDEN == argFlags.rangeFlag && commandRanges.size() != 0) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_norange)) + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_norange)) throw NoRangeAllowedException() } if (RangeFlag.RANGE_REQUIRED == argFlags.rangeFlag && commandRanges.size() == 0) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_rangereq)) + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_rangereq)) throw MissingRangeException() } @@ -115,12 +111,12 @@ sealed class Command(var commandRanges: Ranges, val commandArgument: String) : E private fun checkArgument() { if (ArgumentFlag.ARGUMENT_FORBIDDEN == argFlags.argumentFlag && commandArgument.isNotBlank()) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_argforb)) + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_argforb)) throw NoArgumentAllowedException() } if (ArgumentFlag.ARGUMENT_REQUIRED == argFlags.argumentFlag && commandArgument.isBlank()) { - VimPlugin.showMessage(MessageHelper.message(Msg.e_argreq)) + injector.messages.showStatusBarMessage(injector.messages.message(Msg.e_argreq)) throw MissingArgumentException() } } @@ -202,34 +198,34 @@ sealed class Command(var commandRanges: Ranges, val commandArgument: String) : E fun flags(rangeFlag: RangeFlag, argumentFlag: ArgumentFlag, access: Access, vararg flags: Flag) = CommandHandlerFlags(rangeFlag, argumentFlag, access, flags.toSet()) - fun getLine(editor: Editor): Int = commandRanges.getLine(editor) + fun getLine(editor: VimEditor): Int = commandRanges.getLine(editor) - fun getLine(editor: Editor, caret: Caret): Int = commandRanges.getLine(editor, caret) + fun getLine(editor: VimEditor, caret: VimCaret): Int = commandRanges.getLine(editor, caret) - fun getCount(editor: Editor, defaultCount: Int, checkCount: Boolean): Int { + fun getCount(editor: VimEditor, defaultCount: Int, checkCount: Boolean): Int { val count = if (checkCount) countArgument else -1 val res = commandRanges.getCount(editor, count) return if (res == -1) defaultCount else res } - fun getCount(editor: Editor, caret: Caret, defaultCount: Int, checkCount: Boolean): Int { + fun getCount(editor: VimEditor, caret: VimCaret, defaultCount: Int, checkCount: Boolean): Int { val count = commandRanges.getCount(editor, caret, if (checkCount) countArgument else -1) return if (count == -1) defaultCount else count } - fun getLineRange(editor: Editor): LineRange = commandRanges.getLineRange(editor, -1) + fun getLineRange(editor: VimEditor): LineRange = commandRanges.getLineRange(editor, -1) - fun getLineRange(editor: Editor, caret: Caret, checkCount: Boolean = false): LineRange { + fun getLineRange(editor: VimEditor, caret: VimCaret, checkCount: Boolean = false): LineRange { return commandRanges.getLineRange(editor, caret, if (checkCount) countArgument else -1) } - fun getTextRange(editor: Editor, checkCount: Boolean): TextRange { + fun getTextRange(editor: VimEditor, checkCount: Boolean): TextRange { val count = if (checkCount) countArgument else -1 return commandRanges.getTextRange(editor, count) } - fun getTextRange(editor: Editor, caret: Caret, checkCount: Boolean): TextRange { + fun getTextRange(editor: VimEditor, caret: VimCaret, checkCount: Boolean): TextRange { return commandRanges.getTextRange(editor, caret, if (checkCount) countArgument else -1) } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt similarity index 88% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt index d5b82875842..55565f58296 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/commands/LetCommand.kt @@ -18,13 +18,11 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges -import com.maddyhome.idea.vim.newapi.IjVimEditor -import com.maddyhome.idea.vim.newapi.vim import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.Script @@ -61,7 +59,7 @@ data class LetCommand( override val argFlags = flags(RangeFlag.RANGE_FORBIDDEN, ArgumentFlag.ARGUMENT_OPTIONAL, Access.READ_ONLY) @Throws(ExException::class) - override fun processCommand(editor: Editor, context: DataContext): ExecutionResult { + override fun processCommand(editor: VimEditor, context: ExecutionContext): ExecutionResult { if (!isSyntaxSupported) return ExecutionResult.Error when (variable) { is Variable -> { @@ -75,12 +73,12 @@ data class LetCommand( throw ExException("E46: Cannot change read-only variable \"${variable.toString(editor, context, vimContext)}\"") } - val leftValue = VimPlugin.getVariableService().getNullableVariableValue(variable, editor, context, vimContext) + val leftValue = injector.variableService.getNullableVariableValue(variable, editor, context, vimContext) if (leftValue?.isLocked == true && (leftValue.lockOwner as? Variable)?.name == variable.name) { throw ExException("E741: Value is locked: ${variable.toString(editor, context, vimContext)}") } val rightValue = expression.evaluate(editor, context, vimContext) - VimPlugin.getVariableService().storeVariable(variable, operator.getNewValue(leftValue, rightValue), editor, context, this) + injector.variableService.storeVariable(variable, operator.getNewValue(leftValue, rightValue), editor, context, this) } is OneElementSublistExpression -> { @@ -132,7 +130,7 @@ data class LetCommand( is SublistExpression -> { if (variable.expression is Variable) { - val variableValue = VimPlugin.getVariableService().getNonNullVariableValue(variable.expression, editor, context, this) + val variableValue = injector.variableService.getNonNullVariableValue(variable.expression, editor, context, this) if (variableValue is VimList) { // we use Integer.parseInt(........asString()) because in case if index's type is Float, List, Dictionary etc // vim throws the same error as the asString() method @@ -184,8 +182,8 @@ data class LetCommand( ) { val newValue = operator.getNewValue(optionValue, expression.evaluate(editor, context, this)) when (variable.scope) { - Scope.GLOBAL_VARIABLE -> VimPlugin.getOptionService().setOptionValue(OptionScope.GLOBAL, variable.optionName, newValue, variable.originalString) - Scope.LOCAL_VARIABLE -> VimPlugin.getOptionService().setOptionValue(OptionScope.LOCAL(IjVimEditor(editor)), variable.optionName, newValue, variable.originalString) + Scope.GLOBAL_VARIABLE -> injector.optionService.setOptionValue(OptionScope.GLOBAL, variable.optionName, newValue, variable.originalString) + Scope.LOCAL_VARIABLE -> injector.optionService.setOptionValue(OptionScope.LOCAL(editor), variable.optionName, newValue, variable.originalString) else -> throw ExException("Invalid option scope") } } else { @@ -200,9 +198,9 @@ data class LetCommand( throw ExException("Let command supports only 0-9a-zA-Z\" registers at the moment") } - VimPlugin.getRegister().startRecording(editor.vim, variable.char) - VimPlugin.getRegister().recordText(expression.evaluate(editor, context, vimContext).asString()) - VimPlugin.getRegister().finishRecording(editor.vim) + injector.registerGroup.startRecording(editor, variable.char) + injector.registerGroup.recordText(expression.evaluate(editor, context, vimContext).asString()) + injector.registerGroup.finishRecording(editor) } else -> throw ExException("E121: Undefined variable") @@ -222,7 +220,7 @@ data class LetCommand( return isInsideFunction } - private fun isReadOnlyVariable(variable: Variable, editor: Editor, context: DataContext): Boolean { + private fun isReadOnlyVariable(variable: Variable, editor: VimEditor, context: ExecutionContext): Boolean { if (variable.scope == Scope.FUNCTION_VARIABLE) return true if (variable.scope == null && variable.name.evaluate(editor, context, vimContext).value == "self" && isInsideDictionaryFunction()) return true return false diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/datatypes/VimBlob.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/datatypes/VimBlob.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/datatypes/VimBlob.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/datatypes/VimBlob.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFloat.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFloat.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFloat.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFloat.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt similarity index 88% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt index 966e74fcbfe..af134c71f6e 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/datatypes/VimFuncref.kt @@ -18,9 +18,9 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.expressions.Expression @@ -30,7 +30,6 @@ 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.FunctionHandler import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag -import com.maddyhome.idea.vim.vimscript.services.FunctionStorage data class VimFuncref( val handler: FunctionHandler, @@ -75,12 +74,12 @@ data class VimFuncref( throw ExException("E703: using Funcref as a Number") } - fun execute(name: String, args: List, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + fun execute(name: String, args: List, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { if (handler is DefinedFunctionHandler && handler.function.flags.contains(FunctionFlag.DICT)) { if (dictionary == null) { throw ExException("E725: Calling dict function without Dictionary: $name") } else { - VimPlugin.getVariableService().storeVariable( + injector.variableService.storeVariable( Variable(Scope.LOCAL_VARIABLE, "self"), dictionary!!, editor, @@ -97,7 +96,7 @@ data class VimFuncref( val handler = when (type) { Type.LAMBDA, Type.FUNCREF -> this.handler Type.FUNCTION -> { - FunctionStorage.getFunctionHandlerOrNull(handler.scope, handler.name, vimContext) + injector.functionService.getFunctionHandlerOrNull(handler.scope, handler.name, vimContext) ?: throw ExException("E117: Unknown function: ${handler.name}") } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/BinExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/BinExpression.kt similarity index 86% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/BinExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/BinExpression.kt index bc47d64ba1c..01c3014b2f5 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/BinExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/BinExpression.kt @@ -18,15 +18,15 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.expressions.operators.BinaryOperator data class BinExpression(val left: Expression, val right: Expression, val operator: BinaryOperator) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { return operator.handler.performOperation( left.evaluate(editor, context, vimContext), right.evaluate(editor, context, vimContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/CurlyBracesName.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/CurlyBracesName.kt similarity index 84% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/CurlyBracesName.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/CurlyBracesName.kt index 708150324e4..ed698e9d5ef 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/CurlyBracesName.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/CurlyBracesName.kt @@ -18,14 +18,14 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString data class CurlyBracesName(val parts: List) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimString { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimString { return VimString(parts.joinToString(separator = "") { it.evaluate(editor, context, vimContext).asString() }) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt similarity index 90% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt index ef6d0f02c40..0fd3b02a3ce 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/DictionaryExpression.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary @@ -29,7 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.functions.DefinedFunctionHandler data class DictionaryExpression(val dictionary: LinkedHashMap) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { val dict = VimDictionary(linkedMapOf()) for ((key, value) in dictionary) { val evaluatedVal = value.evaluate(editor, context, vimContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/EnvVariableExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/EnvVariableExpression.kt similarity index 83% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/EnvVariableExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/EnvVariableExpression.kt index 4917eeb9fa3..b5e0238e974 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/EnvVariableExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/EnvVariableExpression.kt @@ -18,14 +18,14 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType data class EnvVariableExpression(val variableName: String) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { TODO("Not yet implemented") } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Expression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Expression.kt similarity index 83% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Expression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Expression.kt index 031f4543978..4eb06ad5840 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Expression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Expression.kt @@ -18,13 +18,13 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType abstract class Expression { lateinit var originalString: String - abstract fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType + abstract fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/FalsyExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/FalsyExpression.kt similarity index 88% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/FalsyExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/FalsyExpression.kt index db18e70142a..4e6616f9197 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/FalsyExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/FalsyExpression.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary @@ -27,7 +27,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimList class FalsyExpression(val left: Expression, val right: Expression) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { val leftValue = left.evaluate(editor, context, vimContext) val isLeftTrue = when (leftValue) { is VimList -> leftValue.values.isNotEmpty() diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt similarity index 82% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt index 225f33e37a4..b3b31beddc1 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/FuncrefCallExpression.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -28,7 +28,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref data class FuncrefCallExpression(val expression: Expression, val args: List) : Expression() { - fun evaluateWithRange(ranges: Ranges?, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + fun evaluateWithRange(ranges: Ranges?, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { val value = expression.evaluate(editor, context, vimContext) if (value is VimFuncref) { value.handler.ranges = ranges @@ -39,7 +39,7 @@ data class FuncrefCallExpression(val expression: Expression, val args: List) : Expression() { constructor(scope: Scope?, functionName: String, arguments: MutableList) : this(scope, CurlyBracesName(listOf(SimpleExpression(functionName))), arguments) - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { - VimscriptState.isFunctionCallUsed = true - val handler = FunctionStorage.getFunctionHandlerOrNull(scope, functionName.evaluate(editor, context, vimContext).value, vimContext) + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { + injector.statisticsService.setIfFunctionCallUsed(true) + val handler = injector.functionService.getFunctionHandlerOrNull(scope, functionName.evaluate(editor, context, vimContext).value, vimContext) if (handler != null) { if (handler is DefinedFunctionHandler && handler.function.flags.contains(FunctionFlag.DICT)) { throw ExException( @@ -48,7 +46,7 @@ data class FunctionCallExpression(val scope: Scope?, val functionName: CurlyBrac return handler.executeFunction(this.arguments, editor, context, vimContext) } - val funcref = VimPlugin.getVariableService().getNullableVariableValue(Variable(scope, functionName), editor, context, vimContext) + val funcref = injector.variableService.getNullableVariableValue(Variable(scope, functionName), editor, context, vimContext) if (funcref is VimFuncref) { val name = (if (scope != null) scope.c + ":" else "") + functionName return funcref.execute(name, arguments, editor, context, vimContext) diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaExpression.kt similarity index 88% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaExpression.kt index cda9f1ac2ea..5a2a112725d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaExpression.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -34,7 +34,7 @@ import com.maddyhome.idea.vim.vimscript.model.statements.ReturnStatement data class LambdaExpression(val args: List, val expr: Expression) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimFuncref { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimFuncref { val function = FunctionDeclaration(null, getFunctionName(), args, listOf(), buildBody(), false, setOf(FunctionFlag.CLOSURE), true) function.vimContext = vimContext return VimFuncref(DefinedFunctionHandler(function), VimList(mutableListOf()), null, VimFuncref.Type.LAMBDA) @@ -47,7 +47,8 @@ data class LambdaExpression(val args: List, val expr: Expression) : Expr private fun buildBody(): List { val body = mutableListOf() for (argument in args) { - body.add(LetCommand(Ranges(), Variable(Scope.LOCAL_VARIABLE, argument), AssignmentOperator.ASSIGNMENT, Variable(Scope.FUNCTION_VARIABLE, argument), true)) + body.add(LetCommand(Ranges(), Variable(Scope.LOCAL_VARIABLE, argument), AssignmentOperator.ASSIGNMENT, Variable( + Scope.FUNCTION_VARIABLE, argument), true)) } body.add(ReturnStatement(expr)) return body diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt similarity index 85% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt index 741e0ef6642..1da1de72364 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/LambdaFunctionCallExpression.kt @@ -18,14 +18,14 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType class LambdaFunctionCallExpression(val lambda: LambdaExpression, val arguments: List) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { val funcref = lambda.evaluate(editor, context, vimContext) return funcref.execute("", arguments, editor, context, vimContext) } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/ListExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/ListExpression.kt similarity index 85% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/ListExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/ListExpression.kt index 7e38cf5c082..1b97c6b4519 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/ListExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/ListExpression.kt @@ -18,15 +18,15 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimList data class ListExpression(val list: MutableList) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { val evaluatedList = list.map { it.evaluate(editor, context, vimContext) }.toMutableList() return VimList(evaluatedList) } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/OneElementSublistExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/OneElementSublistExpression.kt similarity index 91% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/OneElementSublistExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/OneElementSublistExpression.kt index 39cb9e91bbd..48ab60befec 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/OneElementSublistExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/OneElementSublistExpression.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -29,7 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString data class OneElementSublistExpression(val index: Expression, val expression: Expression) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { val expressionValue = expression.evaluate(editor, context, vimContext) if (expressionValue is VimDictionary) { return expressionValue.dictionary[VimString(index.evaluate(editor, context, vimContext).asString())] diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/OptionExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/OptionExpression.kt similarity index 69% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/OptionExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/OptionExpression.kt index 9be13c2612a..42339de34c3 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/OptionExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/OptionExpression.kt @@ -18,21 +18,20 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException -import com.maddyhome.idea.vim.newapi.IjVimEditor import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType data class OptionExpression(val scope: Scope, val optionName: String) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { return when (scope) { - Scope.GLOBAL_VARIABLE -> VimPlugin.getOptionService().getOptionValue(OptionScope.GLOBAL, optionName, originalString) - Scope.LOCAL_VARIABLE -> VimPlugin.getOptionService().getOptionValue(OptionScope.LOCAL(IjVimEditor(editor)), optionName, originalString) + Scope.GLOBAL_VARIABLE -> injector.optionService.getOptionValue(OptionScope.GLOBAL, optionName, originalString) + Scope.LOCAL_VARIABLE -> injector.optionService.getOptionValue(OptionScope.LOCAL(editor), optionName, originalString) else -> throw ExException("Invalid option scope") } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Register.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Register.kt similarity index 71% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Register.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Register.kt index 85e761d38cf..2232de1f736 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Register.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Register.kt @@ -18,20 +18,19 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException -import com.maddyhome.idea.vim.helper.StringHelper import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString data class Register(val char: Char) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { - val register = VimPlugin.getRegister().getRegister(char) ?: throw ExException("Register is not supported yet") + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { + val register = injector.registerGroup.getRegister(char) ?: throw ExException("Register is not supported yet") // todo Esc like keys should be one char - return VimString(StringHelper.toKeyNotation(register.keys)) + return VimString(injector.parser.toKeyNotation(register.keys)) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Scope.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Scope.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Scope.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Scope.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/ScopeExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/ScopeExpression.kt similarity index 85% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/ScopeExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/ScopeExpression.kt index cea1da0ff95..2d6c163028c 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/ScopeExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/ScopeExpression.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -27,7 +27,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType data class ScopeExpression(val scope: Scope) : Expression() { // this expression should never have been evaluated and only be used as a function argument - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { throw ExException("Cannot evaluate scope expression: $scope") } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/SimpleExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/SimpleExpression.kt similarity index 89% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/SimpleExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/SimpleExpression.kt index 4689ef56401..542f7ed088f 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/SimpleExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/SimpleExpression.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDictionary @@ -35,7 +35,7 @@ data class SimpleExpression(val data: VimDataType) : Expression() { constructor(value: MutableList) : this(VimList(value)) constructor(value: LinkedHashMap) : this(VimDictionary(value)) - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { return data } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/SublistExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/SublistExpression.kt similarity index 92% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/SublistExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/SublistExpression.kt index e02676b7d5f..93d5e2dfbeb 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/SublistExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/SublistExpression.kt @@ -18,8 +18,8 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -29,7 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString data class SublistExpression(val from: Expression?, val to: Expression?, val expression: Expression) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { val expressionValue = expression.evaluate(editor, context, vimContext) val arraySize = when (expressionValue) { is VimDictionary -> throw ExException("E719: Cannot slice a Dictionary") diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/TernaryExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/TernaryExpression.kt similarity index 86% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/TernaryExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/TernaryExpression.kt index 49556c4b2d1..4e8e20a2fb4 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/TernaryExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/TernaryExpression.kt @@ -18,14 +18,14 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType data class TernaryExpression(val condition: Expression, val then: Expression, val otherwise: Expression) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { return if (condition.evaluate(editor, context, vimContext).asDouble() != 0.0) { then.evaluate(editor, context, vimContext) } else { diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/UnaryExpression.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/UnaryExpression.kt similarity index 85% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/UnaryExpression.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/UnaryExpression.kt index 15c124d8562..86942cc796d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/UnaryExpression.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/UnaryExpression.kt @@ -18,15 +18,15 @@ 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.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.expressions.operators.UnaryOperator data class UnaryExpression(val operator: UnaryOperator, val expression: Expression) : Expression() { - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { return operator.handler.performOperation(expression.evaluate(editor, context, vimContext)) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Variable.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Variable.kt similarity index 73% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Variable.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Variable.kt index e0d5e8e94be..e789b64de59 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/Variable.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/Variable.kt @@ -18,20 +18,20 @@ 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.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType data class Variable(val scope: Scope?, val name: CurlyBracesName) : Expression() { constructor(scope: Scope?, name: String) : this(scope, CurlyBracesName(listOf(SimpleExpression(name)))) - override fun evaluate(editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { - return VimPlugin.getVariableService().getNonNullVariableValue(this, editor, context, vimContext) + override fun evaluate(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { + return injector.variableService.getNonNullVariableValue(this, editor, context, vimContext) } - fun toString(editor: Editor, context: DataContext, vimContext: VimLContext): String { + fun toString(editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): String { return (scope?.toString() ?: "") + name.evaluate(editor, context, vimContext) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/AssignmentOperator.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/AssignmentOperator.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/AssignmentOperator.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/AssignmentOperator.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/BinaryOperator.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/BinaryOperator.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/BinaryOperator.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/BinaryOperator.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/UnaryOperator.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/UnaryOperator.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/UnaryOperator.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/UnaryOperator.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/AdditionHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/AdditionHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/AdditionHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/AdditionHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorWithIgnoreCaseOption.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorWithIgnoreCaseOption.kt similarity index 91% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorWithIgnoreCaseOption.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorWithIgnoreCaseOption.kt index e5f1794561a..783154ce24b 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorWithIgnoreCaseOption.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/BinaryOperatorWithIgnoreCaseOption.kt @@ -18,7 +18,7 @@ package com.maddyhome.idea.vim.vimscript.model.expressions.operators.handlers.binary -import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.options.OptionConstants import com.maddyhome.idea.vim.options.OptionScope import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType @@ -29,7 +29,7 @@ abstract class BinaryOperatorWithIgnoreCaseOption( ) : BinaryOperatorHandler() { private fun shouldIgnoreCase(): Boolean { - return VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.ignorecaseName) + return injector.optionService.isSet(OptionScope.GLOBAL, OptionConstants.ignorecaseName) } override fun performOperation(left: VimDataType, right: VimDataType): VimDataType { diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ConcatenationHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ConcatenationHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ConcatenationHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ConcatenationHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DivisionHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DivisionHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DivisionHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DivisionHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/DoesntMatchIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/EqualsIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/GreaterOrEqualsIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/IsNotIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LessOrEqualsIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalAndHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalAndHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalAndHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalAndHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalOrHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalOrHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalOrHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/LogicalOrHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MatchesIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ModulusHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ModulusHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ModulusHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/ModulusHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MultiplicationHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MultiplicationHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MultiplicationHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/MultiplicationHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/SubtractionHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/SubtractionHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/SubtractionHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/SubtractionHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsCaseSensitiveHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsCaseSensitiveHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsCaseSensitiveHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsCaseSensitiveHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsIgnoreCaseHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsIgnoreCaseHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsIgnoreCaseHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/binary/UnequalsIgnoreCaseHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/MinusOperatorHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/MinusOperatorHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/MinusOperatorHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/MinusOperatorHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/NotOperatorHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/NotOperatorHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/NotOperatorHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/NotOperatorHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/PlusOperatorHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/PlusOperatorHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/PlusOperatorHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/PlusOperatorHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/UnaryOperatorHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/UnaryOperatorHandler.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/UnaryOperatorHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/expressions/operators/handlers/unary/UnaryOperatorHandler.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/DefinedFunctionHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/functions/DefinedFunctionHandler.kt similarity index 79% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/DefinedFunctionHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/functions/DefinedFunctionHandler.kt index c2d6dbd6e25..9ef207d63c4 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/DefinedFunctionHandler.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/functions/DefinedFunctionHandler.kt @@ -18,11 +18,11 @@ package com.maddyhome.idea.vim.vimscript.model.functions -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.diagnostic.logger -import com.intellij.openapi.editor.Editor -import com.intellij.openapi.editor.LogicalPosition -import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.VimLogicalPosition +import com.maddyhome.idea.vim.api.injector +import com.maddyhome.idea.vim.diagnostic.vimLogger import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.FinishException import com.maddyhome.idea.vim.ex.ranges.LineNumberRange @@ -40,19 +40,19 @@ import com.maddyhome.idea.vim.vimscript.model.statements.FunctionFlag data class DefinedFunctionHandler(val function: FunctionDeclaration) : FunctionHandler() { - private val logger = logger() + private val logger = vimLogger() override val name = function.name override val scope = function.scope override val minimumNumberOfArguments = function.args.size override val maximumNumberOfArguments get() = if (function.hasOptionalArguments) null else function.args.size + function.defaultArgs.size - override fun doFunction(argumentValues: List, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + override fun doFunction(argumentValues: List, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { var returnValue: VimDataType? = null val exceptionsCaught = mutableListOf() val isRangeGiven = (ranges?.size() ?: 0) > 0 if (!isRangeGiven) { - val currentLine = editor.caretModel.currentCaret.logicalPosition.line + val currentLine = editor.currentCaret().getLogicalPosition().line ranges = Ranges() ranges!!.addRange( arrayOf( @@ -64,27 +64,27 @@ data class DefinedFunctionHandler(val function: FunctionDeclaration) : FunctionH initializeFunctionVariables(argumentValues, editor, context) if (function.flags.contains(FunctionFlag.RANGE)) { - val line = (VimPlugin.getVariableService().getNonNullVariableValue(Variable(Scope.FUNCTION_VARIABLE, "firstline"), editor, context, function) as VimInt).value + val line = (injector.variableService.getNonNullVariableValue(Variable(Scope.FUNCTION_VARIABLE, "firstline"), editor, context, function) as VimInt).value returnValue = executeBodyForLine(line, isRangeGiven, exceptionsCaught, editor, context) } else { - val firstLine = (VimPlugin.getVariableService().getNonNullVariableValue(Variable(Scope.FUNCTION_VARIABLE, "firstline"), editor, context, function) as VimInt).value - val lastLine = (VimPlugin.getVariableService().getNonNullVariableValue(Variable(Scope.FUNCTION_VARIABLE, "lastline"), editor, context, function) as VimInt).value + val firstLine = (injector.variableService.getNonNullVariableValue(Variable(Scope.FUNCTION_VARIABLE, "firstline"), editor, context, function) as VimInt).value + val lastLine = (injector.variableService.getNonNullVariableValue(Variable(Scope.FUNCTION_VARIABLE, "lastline"), editor, context, function) as VimInt).value for (line in firstLine..lastLine) { returnValue = executeBodyForLine(line, isRangeGiven, exceptionsCaught, editor, context) } } if (exceptionsCaught.isNotEmpty()) { - VimPlugin.indicateError() - VimPlugin.showMessage(exceptionsCaught.last().message) + injector.messages.indicateError() + injector.messages.showStatusBarMessage(exceptionsCaught.last().message) } return returnValue ?: VimInt(0) } - private fun executeBodyForLine(line: Int, isRangeGiven: Boolean, exceptionsCaught: MutableList, editor: Editor, context: DataContext): VimDataType? { + private fun executeBodyForLine(line: Int, isRangeGiven: Boolean, exceptionsCaught: MutableList, editor: VimEditor, context: ExecutionContext): VimDataType? { var returnValue: VimDataType? = null if (isRangeGiven) { - editor.caretModel.moveToLogicalPosition(LogicalPosition(line - 1, 0)) + editor.currentCaret().moveToLogicalPosition(VimLogicalPosition(line - 1, 0)) } var result: ExecutionResult = ExecutionResult.Success if (function.flags.contains(FunctionFlag.ABORT)) { @@ -131,10 +131,10 @@ data class DefinedFunctionHandler(val function: FunctionDeclaration) : FunctionH return returnValue } - private fun initializeFunctionVariables(argumentValues: List, editor: Editor, context: DataContext) { + private fun initializeFunctionVariables(argumentValues: List, editor: VimEditor, context: ExecutionContext) { // non-optional function arguments for ((index, name) in function.args.withIndex()) { - VimPlugin.getVariableService().storeVariable( + injector.variableService.storeVariable( Variable(Scope.FUNCTION_VARIABLE, name), argumentValues[index].evaluate(editor, context, function.vimContext), editor, @@ -145,7 +145,7 @@ data class DefinedFunctionHandler(val function: FunctionDeclaration) : FunctionH // optional function arguments with default values for (index in 0 until function.defaultArgs.size) { val expressionToStore = if (index + function.args.size < argumentValues.size) argumentValues[index + function.args.size] else function.defaultArgs[index].second - VimPlugin.getVariableService().storeVariable( + injector.variableService.storeVariable( Variable(Scope.FUNCTION_VARIABLE, function.defaultArgs[index].first), expressionToStore.evaluate(editor, context, function.vimContext), editor, @@ -163,7 +163,7 @@ data class DefinedFunctionHandler(val function: FunctionDeclaration) : FunctionH } else { VimList(mutableListOf()) } - VimPlugin.getVariableService().storeVariable( + injector.variableService.storeVariable( Variable(Scope.FUNCTION_VARIABLE, "000"), remainingArgs, editor, @@ -171,13 +171,13 @@ data class DefinedFunctionHandler(val function: FunctionDeclaration) : FunctionH function ) } - VimPlugin.getVariableService().storeVariable( + injector.variableService.storeVariable( Variable(Scope.FUNCTION_VARIABLE, "firstline"), - VimInt(ranges!!.getFirstLine(editor, editor.caretModel.currentCaret) + 1), editor, context, function + VimInt(ranges!!.getFirstLine(editor, editor.currentCaret()) + 1), editor, context, function ) - VimPlugin.getVariableService().storeVariable( + injector.variableService.storeVariable( Variable(Scope.FUNCTION_VARIABLE, "lastline"), - VimInt(ranges!!.getLine(editor, editor.caretModel.currentCaret) + 1), editor, context, function + VimInt(ranges!!.getLine(editor, editor.currentCaret()) + 1), editor, context, function ) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/FunctionHandler.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/functions/FunctionHandler.kt similarity index 86% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/FunctionHandler.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/functions/FunctionHandler.kt index 39d68219174..529e9ab4be5 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/functions/FunctionHandler.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/functions/FunctionHandler.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model.functions -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ranges.Ranges import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -35,9 +35,9 @@ abstract class FunctionHandler { abstract val maximumNumberOfArguments: Int? var ranges: Ranges? = null - protected abstract fun doFunction(argumentValues: List, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType + protected abstract fun doFunction(argumentValues: List, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType - fun executeFunction(arguments: List, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType { + fun executeFunction(arguments: List, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType { checkFunctionCall(arguments) val result = doFunction(arguments, editor, context, vimContext) ranges = null diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/AnonymousFunctionDeclaration.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/AnonymousFunctionDeclaration.kt similarity index 94% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/AnonymousFunctionDeclaration.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/AnonymousFunctionDeclaration.kt index 9eee1500814..f5d3e8cb79d 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/AnonymousFunctionDeclaration.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/AnonymousFunctionDeclaration.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model.statements -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -45,7 +45,7 @@ data class AnonymousFunctionDeclaration( override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { val container = sublist.expression.evaluate(editor, context, vimContext) if (container !is VimDictionary) { throw ExException("E1203: Dot can only be used on a dictionary") diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/FinishStatement.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/FinishStatement.kt similarity index 86% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/FinishStatement.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/FinishStatement.kt index 622f5b95d44..4c736bd9a19 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/FinishStatement.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/FinishStatement.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model.statements -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.FinishException import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -28,7 +28,7 @@ import com.maddyhome.idea.vim.vimscript.model.VimLContext object FinishStatement : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { throw FinishException() } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt similarity index 86% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt index 52ca4bbf77f..7d1fd4ee851 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/FunctionDeclaration.kt @@ -18,17 +18,16 @@ package com.maddyhome.idea.vim.vimscript.model.statements -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException -import com.maddyhome.idea.vim.statistic.VimscriptState import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.VimLContext 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.Scope -import com.maddyhome.idea.vim.vimscript.services.FunctionStorage data class FunctionDeclaration( val scope: Scope?, @@ -50,8 +49,8 @@ data class FunctionDeclaration( val functionVariables: MutableMap = mutableMapOf() val localVariables: MutableMap = mutableMapOf() - override fun execute(editor: Editor, context: DataContext): ExecutionResult { - VimscriptState.isFunctionDeclarationUsed = true + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { + injector.statisticsService.setIfFunctionDeclarationUsed(true) val forbiddenArgumentNames = setOf("firstline", "lastline") val forbiddenArgument = args.firstOrNull { forbiddenArgumentNames.contains(it) } if (forbiddenArgument != null) { @@ -59,7 +58,7 @@ data class FunctionDeclaration( } body.forEach { it.vimContext = this } - FunctionStorage.storeFunction(this) + injector.functionService.storeFunction(this) return ExecutionResult.Success } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/IfStatement.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/IfStatement.kt similarity index 88% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/IfStatement.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/IfStatement.kt index c4c5344ee43..b774e2547fa 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/IfStatement.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/IfStatement.kt @@ -18,9 +18,9 @@ package com.maddyhome.idea.vim.vimscript.model.statements -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor -import com.maddyhome.idea.vim.statistic.VimscriptState +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -29,8 +29,8 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.Expression data class IfStatement(val conditionToBody: List>>) : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { - VimscriptState.isIfUsed = true + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { + injector.statisticsService.setIfIfUsed(true) var result: ExecutionResult = ExecutionResult.Success var statementsToExecute: List? = null for ((condition, statements) in conditionToBody) { diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/ReturnStatement.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/ReturnStatement.kt similarity index 87% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/ReturnStatement.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/ReturnStatement.kt index 1d2e353fd13..8189a276e1c 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/ReturnStatement.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/ReturnStatement.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model.statements -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -28,7 +28,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.Expression data class ReturnStatement(val expression: Expression) : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { return ExecutionResult.Return(expression.evaluate(editor, context, this)) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/ThrowStatement.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/ThrowStatement.kt similarity index 87% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/ThrowStatement.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/ThrowStatement.kt index 5c0b5273877..31ede81ad96 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/ThrowStatement.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/ThrowStatement.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model.statements -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult @@ -29,7 +29,7 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.Expression data class ThrowStatement(val expression: Expression) : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { throw ExException(expression.evaluate(editor, context, this).toString()) } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/TryStatement.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/TryStatement.kt similarity index 84% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/TryStatement.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/TryStatement.kt index cd21508096b..69bf8634be0 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/TryStatement.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/TryStatement.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model.statements -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.FinishException import com.maddyhome.idea.vim.vimscript.model.Executable @@ -27,10 +27,11 @@ import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.services.PatternService -data class TryStatement(val tryBlock: TryBlock, val catchBlocks: List, val finallyBlock: FinallyBlock?) : Executable { +data class TryStatement(val tryBlock: TryBlock, val catchBlocks: List, val finallyBlock: FinallyBlock?) : + Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { var uncaughtException: ExException? = null var result: ExecutionResult = ExecutionResult.Success try { @@ -77,7 +78,7 @@ data class TryStatement(val tryBlock: TryBlock, val catchBlocks: List) : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { body.forEach { it.vimContext = this.vimContext } return executeBody(body, editor, context) } @@ -85,7 +86,7 @@ data class TryBlock(val body: List) : Executable { data class CatchBlock(val pattern: String, val body: List) : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { body.forEach { it.vimContext = this.vimContext } return executeBody(body, editor, context) } @@ -93,16 +94,16 @@ data class CatchBlock(val pattern: String, val body: List) : Executa data class FinallyBlock(val body: List) : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { body.forEach { it.vimContext = this.vimContext } return executeBody(body, editor, context) } } fun executeBody( - body: List, - editor: Editor, - context: DataContext, + body: List, + editor: VimEditor, + context: ExecutionContext, ): ExecutionResult { var result: ExecutionResult = ExecutionResult.Success for (statement in body) { diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/BreakStatement.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/BreakStatement.kt similarity index 86% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/BreakStatement.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/BreakStatement.kt index 0af2de4d16e..a5845f523f0 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/BreakStatement.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/BreakStatement.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model.statements.loops -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -27,7 +27,7 @@ import com.maddyhome.idea.vim.vimscript.model.VimLContext object BreakStatement : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { return ExecutionResult.Break } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/ContinueStatement.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/ContinueStatement.kt similarity index 86% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/ContinueStatement.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/ContinueStatement.kt index bf13c609805..31daa6867fd 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/ContinueStatement.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/ContinueStatement.kt @@ -18,8 +18,8 @@ package com.maddyhome.idea.vim.vimscript.model.statements.loops -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -27,7 +27,7 @@ import com.maddyhome.idea.vim.vimscript.model.VimLContext object ContinueStatement : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { return ExecutionResult.Continue } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/ForLoop.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/ForLoop.kt similarity index 84% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/ForLoop.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/ForLoop.kt index 0713a18141a..98b0df77660 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/ForLoop.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/ForLoop.kt @@ -18,11 +18,10 @@ package com.maddyhome.idea.vim.vimscript.model.statements.loops -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor -import com.maddyhome.idea.vim.VimPlugin +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.ex.ExException -import com.maddyhome.idea.vim.statistic.VimscriptState import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -37,15 +36,15 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.Variable data class ForLoop(val variable: Variable, val iterable: Expression, val body: List) : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { - VimscriptState.isLoopUsed = true + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { + injector.statisticsService.setIfLoopUsed(true) var result: ExecutionResult = ExecutionResult.Success body.forEach { it.vimContext = this } var iterableValue = iterable.evaluate(editor, context, this) if (iterableValue is VimString) { for (i in iterableValue.value) { - VimPlugin.getVariableService().storeVariable(variable, VimString(i.toString()), editor, context, this) + injector.variableService.storeVariable(variable, VimString(i.toString()), editor, context, this) for (statement in body) { if (result is ExecutionResult.Success) { result = statement.execute(editor, context) @@ -66,7 +65,7 @@ data class ForLoop(val variable: Variable, val iterable: Expression, val body: L } else if (iterableValue is VimList) { var index = 0 while (index < (iterableValue as VimList).values.size) { - VimPlugin.getVariableService().storeVariable(variable, iterableValue.values[index], editor, context, this) + injector.variableService.storeVariable(variable, iterableValue.values[index], editor, context, this) for (statement in body) { if (result is ExecutionResult.Success) { result = statement.execute(editor, context) @@ -95,10 +94,11 @@ data class ForLoop(val variable: Variable, val iterable: Expression, val body: L } } -data class ForLoopWithList(val variables: List, val iterable: Expression, val body: List) : Executable { +data class ForLoopWithList(val variables: List, val iterable: Expression, val body: List) : + Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { var result: ExecutionResult = ExecutionResult.Success body.forEach { it.vimContext = this } @@ -132,7 +132,7 @@ data class ForLoopWithList(val variables: List, val iterable: Expression return result } - private fun storeListVariables(list: VimDataType, editor: Editor, context: DataContext) { + private fun storeListVariables(list: VimDataType, editor: VimEditor, context: ExecutionContext) { if (list !is VimList) { throw ExException("E714: List required") } @@ -145,7 +145,7 @@ data class ForLoopWithList(val variables: List, val iterable: Expression } for (item in list.values.withIndex()) { - VimPlugin.getVariableService().storeVariable(Variable(null, variables[item.index]), item.value, editor, context, this) + injector.variableService.storeVariable(Variable(null, variables[item.index]), item.value, editor, context, this) } } } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/WhileLoop.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/WhileLoop.kt similarity index 87% rename from src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/WhileLoop.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/WhileLoop.kt index 30046d3bc15..f49dd548d67 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/model/statements/loops/WhileLoop.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/model/statements/loops/WhileLoop.kt @@ -18,9 +18,9 @@ package com.maddyhome.idea.vim.vimscript.model.statements.loops -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor -import com.maddyhome.idea.vim.statistic.VimscriptState +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor +import com.maddyhome.idea.vim.api.injector import com.maddyhome.idea.vim.vimscript.model.Executable import com.maddyhome.idea.vim.vimscript.model.ExecutionResult import com.maddyhome.idea.vim.vimscript.model.VimLContext @@ -29,8 +29,8 @@ import com.maddyhome.idea.vim.vimscript.model.expressions.Expression data class WhileLoop(val condition: Expression, val body: List) : Executable { override lateinit var vimContext: VimLContext - override fun execute(editor: Editor, context: DataContext): ExecutionResult { - VimscriptState.isLoopUsed = true + override fun execute(editor: VimEditor, context: ExecutionContext): ExecutionResult { + injector.statisticsService.setIfLoopUsed(true) var result: ExecutionResult = ExecutionResult.Success body.forEach { it.vimContext = this } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/services/PatternService.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/services/PatternService.kt similarity index 100% rename from src/main/java/com/maddyhome/idea/vim/vimscript/services/PatternService.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/services/PatternService.kt diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/services/VariableService.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/services/VariableService.kt similarity index 60% rename from src/main/java/com/maddyhome/idea/vim/vimscript/services/VariableService.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/services/VariableService.kt index 19ba37fc530..b4a87296880 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/services/VariableService.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/services/VariableService.kt @@ -18,24 +18,24 @@ package com.maddyhome.idea.vim.vimscript.services -import com.intellij.openapi.actionSystem.DataContext -import com.intellij.openapi.editor.Editor +import com.maddyhome.idea.vim.api.ExecutionContext +import com.maddyhome.idea.vim.api.VimEditor import com.maddyhome.idea.vim.vimscript.model.VimLContext import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType import com.maddyhome.idea.vim.vimscript.model.expressions.Variable interface VariableService { - fun isVariableLocked(variable: Variable, editor: Editor, context: DataContext, vimContext: VimLContext): Boolean + fun isVariableLocked(variable: Variable, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): Boolean - fun lockVariable(variable: Variable, depth: Int, editor: Editor, context: DataContext, vimContext: VimLContext) + fun lockVariable(variable: Variable, depth: Int, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) - fun unlockVariable(variable: Variable, depth: Int, editor: Editor, context: DataContext, vimContext: VimLContext) + fun unlockVariable(variable: Variable, depth: Int, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) - fun storeVariable(variable: Variable, value: VimDataType, editor: Editor, context: DataContext, vimContext: VimLContext) + fun storeVariable(variable: Variable, value: VimDataType, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext) // todo replace with one method after Result class fun getGlobalVariableValue(name: String): VimDataType? - fun getNullableVariableValue(variable: Variable, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType? - fun getNonNullVariableValue(variable: Variable, editor: Editor, context: DataContext, vimContext: VimLContext): VimDataType + fun getNullableVariableValue(variable: Variable, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType? + fun getNonNullVariableValue(variable: Variable, editor: VimEditor, context: ExecutionContext, vimContext: VimLContext): VimDataType } diff --git a/src/main/java/com/maddyhome/idea/vim/vimscript/services/VimRcService.kt b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/services/VimRcService.kt similarity index 88% rename from src/main/java/com/maddyhome/idea/vim/vimscript/services/VimRcService.kt rename to vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/services/VimRcService.kt index 92193a5ba4e..f9e367380fe 100644 --- a/src/main/java/com/maddyhome/idea/vim/vimscript/services/VimRcService.kt +++ b/vim-engine/src/main/kotlin/com/maddyhome/idea/vim/vimscript/services/VimRcService.kt @@ -18,16 +18,15 @@ package com.maddyhome.idea.vim.vimscript.services -import com.intellij.openapi.diagnostic.logger -import com.maddyhome.idea.vim.ui.VimRcFileState -import com.maddyhome.idea.vim.vimscript.Executor +import com.maddyhome.idea.vim.api.injector +import com.maddyhome.idea.vim.diagnostic.vimLogger import org.jetbrains.annotations.NonNls import java.io.File import java.io.IOException import java.nio.file.Paths object VimRcService { - private val logger = logger() + private val logger = vimLogger() @NonNls const val VIMRC_FILE_NAME = "ideavimrc" @@ -103,7 +102,7 @@ object VimRcService { val file = File(homeDirName, fileName) file.createNewFile() file.writeText(newIdeaVimRcTemplate) - VimRcFileState.filePath = file.absolutePath + injector.vimrcFileState.filePath = file.absolutePath return file } catch (ignored: IOException) { // Try to create one of two files @@ -116,17 +115,17 @@ object VimRcService { @JvmStatic fun executeIdeaVimRc() { try { - Executor.executingVimScript = true + injector.vimscriptExecutor.executingVimscript = true val ideaVimRc = findIdeaVimRc() if (ideaVimRc != null) { logger.info("Execute ideavimrc file: " + ideaVimRc.absolutePath) - Executor.executeFile(ideaVimRc) - VimRcFileState.saveFileState(ideaVimRc.absolutePath) + injector.vimscriptExecutor.executeFile(ideaVimRc) + injector.vimrcFileState.saveFileState(ideaVimRc.absolutePath) } else { logger.info("ideavimrc file isn't found") } } finally { - Executor.executingVimScript = false + injector.vimscriptExecutor.executingVimscript = false } } }