1
0
mirror of https://github.com/chylex/IntelliJ-IdeaVim.git synced 2025-08-18 10:31:44 +02:00

Compare commits

..

58 Commits

Author SHA1 Message Date
Alex Plate
c656da5c75 Prepare to 0.64 release 2020-12-23 09:49:45 +03:00
Alex Plate
dcedf6abca Mute another broken test 2020-12-18 15:03:25 +03:00
Alex Plate
849a71bdac Update changes 2020-12-18 13:18:08 +03:00
Alex Plate
534cc1d1fe Disable broken test 2020-12-18 12:26:10 +03:00
Alex Plate
40ec6c53fa Revert "Add statistic collection for some options"
Classes of the collector are incompatible with 202

This reverts commit b7cb3c09
2020-12-18 11:57:06 +03:00
Alex Plate
b7cb3c0945 Add statistic collection for some options 2020-12-17 23:13:54 +03:00
Alex Plate
69d3c7b754 resetCaset function should not change the shape of other editors
This commit fixes the following issues:
1) Windows splitting
- Start insert mode in editor
- Split editor
- Go back to the previous editor. The caret has a block shape, but insert mode

2) VCS updates
In 2021.1 VCS creates a diff window right after the file was changed.
So, the case described above happens here as well.
2020-12-17 10:53:43 +03:00
Alex Plate
542f11804e Update detekt baseline 2020-12-17 10:14:11 +03:00
Alex Plate
8526054aa8 Update changes 2020-12-17 10:05:04 +03:00
Alex Plate
93700bddc7 Update deprecated methods according to the new minimal IJ requirements 2020-12-17 10:04:52 +03:00
Matt Ellis
494500041b Rearrange and document the public search API
No code changes, just moved everything
2020-12-17 10:02:16 +03:00
Matt Ellis
011a5a3b23 Remove unnecessary UNSET direction enum value 2020-12-17 10:02:16 +03:00
Matt Ellis
03726858f0 Move find methods to SearchHelper 2020-12-17 10:02:16 +03:00
Alex Plate
c8c42cc4b2 Update plugin verifier versions 2020-12-16 13:00:32 +03:00
Alex Plate
0b22b454e6 Prepare to 0.63 release 2020-12-16 12:56:25 +03:00
vladimir.petrenko
f4fe03c582 CWM-927 disable vim for client's hidden editor on host
to provide compatibility with Code With Me plugin
2020-12-16 12:27:34 +03:00
Alex Plate
964e87fd6a Update minimap IJ version to 202 2020-12-16 11:39:49 +03:00
Alex Plate
ec4c0a0d0d Update teamcity configurations to deprecate 201 branch 2020-12-16 11:38:52 +03:00
Alex Plate
f9cf62472c Prepare to 0.62 release 2020-12-15 10:12:31 +03:00
Alex Plate
ace584d294 Fix settings saving issues because of NPE 2020-12-15 09:35:35 +03:00
Alex Plate
5cd669202b Remove time calculation for isIdeavimDisabledHere 2020-12-10 10:06:29 +03:00
Alex Plate
4a09848720 Revert incorrect update 2020-12-10 10:03:51 +03:00
Alex Plate
f998f1be9f Update teamcity ide version for pull requests builds 2020-12-10 09:52:07 +03:00
Alex Plate
3352bdfabb Remove some deprecations in code 2020-12-10 09:50:05 +03:00
Alex Plate
ce43a9648f Update profile settings 2020-12-10 09:40:57 +03:00
Alex Plate
440a0bf393 Remove incorrect link in package-info.java 2020-12-10 09:36:59 +03:00
Alex Plate
64a7555f42 [VIM-2188] Remove deprecated configuration store 2020-12-10 09:35:07 +03:00
Alex Plate
3aa6fe3dc0 Update algorithm of number generation 2020-12-08 12:11:41 +03:00
Alex Plate
3522228d45 Add new line at the end of test 2020-12-08 11:36:23 +03:00
Alex Plate
9b42d9a5c6 Add test for incrementing fancy number 2020-12-08 11:35:11 +03:00
Alex Plate
4e8d98f956 Add Shaun Patterson to contributors list 2020-12-08 10:54:15 +03:00
Alex Plate
f6c3d27bbc Reset caret shape after <C-O> command 2020-12-08 10:50:06 +03:00
Alex Plate
21daf83fbd Include caret shape assertions into checks 2020-12-08 10:50:05 +03:00
Shaun Patterson
7f1203c207 VIM-1756: startSel works in insert mode 2020-12-08 10:49:19 +03:00
Alex Plate
89b1f90973 Fix detekt issues 2020-12-04 11:21:40 +03:00
Alex Plate
8002a5497f [VIM-1913] Update changes 2020-12-04 11:07:11 +03:00
Alex Plate
770d12d79b [VIM-1913] Enable enter for AppCode templates 2020-12-04 11:05:32 +03:00
Alex Plate
7e4ac22d23 [VIM-1913] Enable tab for AppCode templates 2020-12-04 10:45:56 +03:00
Alex Plate
4f4b26d3e1 Update CHANGES.md 2020-12-04 09:54:58 +03:00
Matt Ellis
4ea7c421a8 Extract and use common Direction enum 2020-12-04 09:53:58 +03:00
Matt Ellis
3c8b7e2de4 Convert SearchHighlightsHelper to Kotlin 2020-12-04 09:53:58 +03:00
Matt Ellis
b13acaf823 Rename .java to .kt 2020-12-04 09:53:58 +03:00
Matt Ellis
709cd6ad6e Extract SearchHighlightsHelper 2020-12-04 09:53:58 +03:00
Matt Ellis
1316ccc56f Update default for history to match Vim 2020-12-04 09:53:58 +03:00
Matt Ellis
881ddd0e11 Refactor setting special registers 2020-12-04 09:53:58 +03:00
Matt Ellis
49611ee6b9 Show the correct handler class in :map 2020-12-04 09:33:14 +03:00
Alex Plate
539465bb56 Update property based test 2020-12-03 10:50:57 +03:00
Alex Plate
bc54a73d69 Add suggested options to README.md 2020-12-03 10:13:28 +03:00
Alex Plate
5eb12f5d14 Update mappings in .ideavimrc example 2020-12-03 10:09:05 +03:00
Alex Plate
557e47650f Disable octal for nrformats 2020-12-03 10:07:27 +03:00
Alex Plate
f50753bfd7 Add tests for 2020.3 on TeamCity 2020-12-03 10:02:21 +03:00
Alex Plate
7a164d6d5f Updates to block caret in insert mode 2020-12-02 10:58:04 +03:00
Alex Plate
60bc936cd9 Take back: VIM-1475: Respect the "use block caret" when in insert mode 2020-12-02 10:31:01 +03:00
Alex Plate
d097e636ea Add test for double exiting visual mode 2020-12-02 10:30:37 +03:00
Alex Plate
3ce2bbb624 Rename test for visual exit 2020-12-02 10:27:28 +03:00
Alex Plate
4926d2554e Revert "VIM-1475: Respect the "use block caret" when in insert mode"
Reverting this commit due to VIM-2182

This reverts commit 62c828d7
2020-12-02 09:45:08 +03:00
Alex Plate
eae135acba Fix detekt issues 2020-12-01 12:19:08 +03:00
Alex Plate
8ce3801b87 [VIM-1913] Improve interaction with AppCode templates 2020-12-01 11:55:47 +03:00
72 changed files with 1897 additions and 1359 deletions

View File

@@ -9,6 +9,7 @@
<ID>ComplexMethod:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID> <ID>ComplexMethod:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID>
<ID>ComplexMethod:PutGroup.kt$PutGroup$private fun prepareDocumentAndGetStartOffsets(editor: Editor, caret: Caret, typeInRegister: SelectionType, data: PutData, additionalData: Map&lt;String, Any&gt;): List&lt;Int&gt;</ID> <ID>ComplexMethod:PutGroup.kt$PutGroup$private fun prepareDocumentAndGetStartOffsets(editor: Editor, caret: Caret, typeInRegister: SelectionType, data: PutData, additionalData: Map&lt;String, Any&gt;): List&lt;Int&gt;</ID>
<ID>ComplexMethod:SearchHelperKt.kt$// bounds are considered inside corresponding quotes fun checkInString(chars: CharSequence, currentPos: Int, str: Boolean): Boolean</ID> <ID>ComplexMethod:SearchHelperKt.kt$// bounds are considered inside corresponding quotes fun checkInString(chars: CharSequence, currentPos: Int, str: Boolean): Boolean</ID>
<ID>ComplexMethod:SearchHighlightsHelper.kt$ private fun updateSearchHighlights( pattern: String?, shouldIgnoreSmartCase: Boolean, showHighlights: Boolean, initialOffset: Int, searchRange: LineRange?, forwards: Boolean, forceUpdate: Boolean ): Int</ID>
<ID>ComplexMethod:TabCloseHandler.kt$TabCloseHandler$ private fun getTabIndexToClose(arg: String, current: Int, last: Int): Int?</ID> <ID>ComplexMethod:TabCloseHandler.kt$TabCloseHandler$ private fun getTabIndexToClose(arg: String, current: Int, last: Int): Int?</ID>
<ID>ComplexMethod:VimExchangeExtension.kt$VimExchangeExtension.Operator$private fun compareExchanges(x: Exchange, y: Exchange): ExchangeCompareResult</ID> <ID>ComplexMethod:VimExchangeExtension.kt$VimExchangeExtension.Operator$private fun compareExchanges(x: Exchange, y: Exchange): ExchangeCompareResult</ID>
<ID>ComplexMethod:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID> <ID>ComplexMethod:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID>
@@ -16,6 +17,8 @@
<ID>LongMethod:CmdHandler.kt$CmdHandler$private fun addAlias(cmd: ExCommand, editor: Editor?): Boolean</ID> <ID>LongMethod:CmdHandler.kt$CmdHandler$private fun addAlias(cmd: ExCommand, editor: Editor?): Boolean</ID>
<ID>LongMethod:HistoryHandler.kt$HistoryHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID> <ID>LongMethod:HistoryHandler.kt$HistoryHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>LongMethod:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID> <ID>LongMethod:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID>
<ID>LongMethod:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID>
<ID>LoopWithTooManyJumpStatements:SearchHighlightsHelper.kt$for (project in projectManager.openProjects) { val current = FileEditorManager.getInstance(project).selectedTextEditor ?: continue // [VERSION UPDATE] 202+ Use editors val editors = EditorFactory.getInstance().getEditors(current.document, project) ?: continue for (editor in editors) { // Try to keep existing highlights if possible. Update if hlsearch has changed or if the pattern has changed. // Force update for the situations where the text is the same, but the ignore case values have changed. // E.g. Use `*` to search for a word (which ignores smartcase), then use `/&lt;Up&gt;` to search for the same pattern, // which will match smartcase. Or changing the smartcase/ignorecase settings if (shouldRemoveSearchHighlights(editor, pattern, showHighlights) || forceUpdate) { removeSearchHighlights(editor) } if (pattern == null) continue if (shouldAddAllSearchHighlights(editor, pattern, showHighlights)) { // hlsearch (+ incsearch/noincsearch) val startLine = searchRange?.startLine ?: 0 val endLine = searchRange?.endLine ?: -1 val results = SearchHelper.findAll(editor, pattern, startLine, endLine, shouldIgnoreCase(pattern, shouldIgnoreSmartCase)) if (results.isNotEmpty()) { currentMatchOffset = findClosestMatch(editor, results, initialOffset, forwards) highlightSearchResults(editor, pattern, results, currentMatchOffset) } editor.vimLastSearch = pattern } else if (shouldAddCurrentMatchSearchHighlight(pattern, showHighlights, initialOffset)) { // nohlsearch + incsearch val searchOptions = EnumSet.of(SearchOptions.WHOLE_FILE) if (wrapscan.isSet) searchOptions.add(SearchOptions.WRAP) if (shouldIgnoreSmartCase) searchOptions.add(SearchOptions.IGNORE_SMARTCASE) if (!forwards) searchOptions.add(SearchOptions.BACKWARDS) val result = SearchHelper.findPattern(editor, pattern, initialOffset, 1, searchOptions) if (result != null) { currentMatchOffset = result.startOffset val results = listOf(result) highlightSearchResults(editor, pattern, results, currentMatchOffset) } } else if (shouldMaintainCurrentMatchOffset(pattern, initialOffset)) { // incsearch. If nothing has changed (e.g. we've edited offset values in `/foo/e+2`) make sure we return the // current match offset so the caret remains at the current incsarch match val offset = editor.vimIncsearchCurrentMatchOffset if (offset != null) { currentMatchOffset = offset } } } }</ID>
<ID>MagicNumber:ActionListHandler.kt$ActionListHandler$50</ID> <ID>MagicNumber:ActionListHandler.kt$ActionListHandler$50</ID>
<ID>MagicNumber:AddBlockInlaysAction.kt$AddBlockInlaysAction$0.9f</ID> <ID>MagicNumber:AddBlockInlaysAction.kt$AddBlockInlaysAction$0.9f</ID>
<ID>MagicNumber:AddBlockInlaysAction.kt$AddBlockInlaysAction$1.75f</ID> <ID>MagicNumber:AddBlockInlaysAction.kt$AddBlockInlaysAction$1.75f</ID>
@@ -35,7 +38,6 @@
<ID>MagicNumber:CommandBuilder.kt$CommandBuilder$999999999</ID> <ID>MagicNumber:CommandBuilder.kt$CommandBuilder$999999999</ID>
<ID>MagicNumber:ConfigurationMigrators.kt$Version 6 to 7 config migration$6</ID> <ID>MagicNumber:ConfigurationMigrators.kt$Version 6 to 7 config migration$6</ID>
<ID>MagicNumber:ConfigurationMigrators.kt$Version 6 to 7 config migration$7</ID> <ID>MagicNumber:ConfigurationMigrators.kt$Version 6 to 7 config migration$7</ID>
<ID>MagicNumber:EditorHelper.kt$10</ID>
<ID>MagicNumber:ExKeyBindings.kt$ExKeyBindings$0x05</ID> <ID>MagicNumber:ExKeyBindings.kt$ExKeyBindings$0x05</ID>
<ID>MagicNumber:ExKeyBindings.kt$ExKeyBindings$0x08</ID> <ID>MagicNumber:ExKeyBindings.kt$ExKeyBindings$0x08</ID>
<ID>MagicNumber:HistoryHandler.kt$HistoryHandler$7</ID> <ID>MagicNumber:HistoryHandler.kt$HistoryHandler$7</ID>
@@ -50,6 +52,7 @@
<ID>MagicNumber:OptionsManager.kt$OptionsManager$19</ID> <ID>MagicNumber:OptionsManager.kt$OptionsManager$19</ID>
<ID>MagicNumber:OptionsManager.kt$OptionsManager$20</ID> <ID>MagicNumber:OptionsManager.kt$OptionsManager$20</ID>
<ID>MagicNumber:OptionsManager.kt$OptionsManager$3</ID> <ID>MagicNumber:OptionsManager.kt$OptionsManager$3</ID>
<ID>MagicNumber:OptionsManager.kt$OptionsManager$50</ID>
<ID>MagicNumber:OptionsManager.kt$OptionsManager$80</ID> <ID>MagicNumber:OptionsManager.kt$OptionsManager$80</ID>
<ID>MagicNumber:ProcessExEntryAction.kt$ProcessExEntryAction$0x0a</ID> <ID>MagicNumber:ProcessExEntryAction.kt$ProcessExEntryAction$0x0a</ID>
<ID>MagicNumber:RegistersHandler.kt$RegistersHandler$200</ID> <ID>MagicNumber:RegistersHandler.kt$RegistersHandler$200</ID>
@@ -61,7 +64,7 @@
<ID>MagicNumber:VimHighlightedYank.kt$VimHighlightedYank.HighlightHandler$3</ID> <ID>MagicNumber:VimHighlightedYank.kt$VimHighlightedYank.HighlightHandler$3</ID>
<ID>MagicNumber:VimHighlightedYank.kt$VimHighlightedYank.HighlightHandler$4</ID> <ID>MagicNumber:VimHighlightedYank.kt$VimHighlightedYank.HighlightHandler$4</ID>
<ID>MatchingDeclarationName:CommandDefinition.kt$CommandName</ID> <ID>MatchingDeclarationName:CommandDefinition.kt$CommandName</ID>
<ID>MaxLineLength:ExBeanClass.kt$ExBeanClass$logger&lt;ExBeanClass&gt;().error("IdeaVim doesn't accept contributions to `vimActions` extension points. Please create a plugin using `VimExtension`. Plugin to blame: $pluginId")</ID> <ID>MaxLineLength:ExBeanClass.kt$ExBeanClass$logger&lt;ExBeanClass&gt;().error("IdeaVim doesn't accept contributions to `vimActions` extension points. Please create a plugin using `VimExtension`. Plugin to blame: ${this.pluginDescriptor.pluginId}")</ID>
<ID>MaxLineLength:ExRanges.kt$SearchRange$override</ID> <ID>MaxLineLength:ExRanges.kt$SearchRange$override</ID>
<ID>MaxLineLength:NotificationService.kt$NotificationService$notification.addAction(AppendToIdeaVimRcAction(notification, "set clipboard+=ideaput", "ideaput") { OptionsManager.clipboard.append(ClipboardOptionsData.ideaput) })</ID> <ID>MaxLineLength:NotificationService.kt$NotificationService$notification.addAction(AppendToIdeaVimRcAction(notification, "set clipboard+=ideaput", "ideaput") { OptionsManager.clipboard.append(ClipboardOptionsData.ideaput) })</ID>
<ID>MaxLineLength:NotificationService.kt$NotificationService.AppendToIdeaVimRcAction$private inner</ID> <ID>MaxLineLength:NotificationService.kt$NotificationService.AppendToIdeaVimRcAction$private inner</ID>
@@ -79,67 +82,18 @@
<ID>MaxLineLength:VimShortcutKeyAction.kt$VimShortcutKeyAction.Companion$ImmutableSet.builder&lt;KeyStroke&gt;().addAll(getKeyStrokes(KeyEvent.VK_ENTER, 0)).addAll(getKeyStrokes(KeyEvent.VK_ESCAPE, 0)) .addAll(getKeyStrokes(KeyEvent.VK_TAB, 0)).addAll(getKeyStrokes(KeyEvent.VK_BACK_SPACE, 0, InputEvent.CTRL_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_INSERT, 0)).addAll(getKeyStrokes(KeyEvent.VK_DELETE, 0, InputEvent.CTRL_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_UP, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK)).addAll(getKeyStrokes(KeyEvent.VK_DOWN, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_LEFT, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK, InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_RIGHT, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK, InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_HOME, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK, InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK))</ID> <ID>MaxLineLength:VimShortcutKeyAction.kt$VimShortcutKeyAction.Companion$ImmutableSet.builder&lt;KeyStroke&gt;().addAll(getKeyStrokes(KeyEvent.VK_ENTER, 0)).addAll(getKeyStrokes(KeyEvent.VK_ESCAPE, 0)) .addAll(getKeyStrokes(KeyEvent.VK_TAB, 0)).addAll(getKeyStrokes(KeyEvent.VK_BACK_SPACE, 0, InputEvent.CTRL_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_INSERT, 0)).addAll(getKeyStrokes(KeyEvent.VK_DELETE, 0, InputEvent.CTRL_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_UP, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK)).addAll(getKeyStrokes(KeyEvent.VK_DOWN, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_LEFT, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK, InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_RIGHT, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK, InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK)) .addAll(getKeyStrokes(KeyEvent.VK_HOME, 0, InputEvent.CTRL_DOWN_MASK, InputEvent.SHIFT_DOWN_MASK, InputEvent.CTRL_DOWN_MASK or InputEvent.SHIFT_DOWN_MASK))</ID>
<ID>MemberNameEqualsClassName:Ranges.kt$Ranges$private val ranges: MutableList&lt;Range&gt; = mutableListOf()</ID> <ID>MemberNameEqualsClassName:Ranges.kt$Ranges$private val ranges: MutableList&lt;Range&gt; = mutableListOf()</ID>
<ID>NestedBlockDepth:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID> <ID>NestedBlockDepth:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID>
<ID>ReturnCount:ActionBeanClass.kt$ActionBeanClass$fun getParsedModes(): Set&lt;MappingMode&gt;?</ID>
<ID>ReturnCount:Alias.kt$Alias$fun getCommand(input: String, count: Int): String</ID>
<ID>ReturnCount:CmdFilterHandler.kt$CmdFilterHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>ReturnCount:CmdHandler.kt$CmdHandler$private fun addAlias(cmd: ExCommand, editor: Editor?): Boolean</ID> <ID>ReturnCount:CmdHandler.kt$CmdHandler$private fun addAlias(cmd: ExCommand, editor: Editor?): Boolean</ID>
<ID>ReturnCount:CommandGroup.kt$CommandGroup$fun isAlias(command: String): Boolean</ID>
<ID>ReturnCount:DeleteJoinLinesAction.kt$DeleteJoinLinesAction$override fun execute(editor: Editor, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Boolean</ID>
<ID>ReturnCount:DeleteJoinLinesSpacesAction.kt$DeleteJoinLinesSpacesAction$override fun execute(editor: Editor, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Boolean</ID>
<ID>ReturnCount:DeleteJoinVisualLinesAction.kt$DeleteJoinVisualLinesAction$override fun executeForAllCarets(editor: Editor, context: DataContext, cmd: Command, caretsAndSelections: Map&lt;Caret, VimSelection&gt;): Boolean</ID>
<ID>ReturnCount:DeleteJoinVisualLinesSpacesAction.kt$DeleteJoinVisualLinesSpacesAction$override fun executeForAllCarets(editor: Editor, context: DataContext, cmd: Command, caretsAndSelections: Map&lt;Caret, VimSelection&gt;): Boolean</ID>
<ID>ReturnCount:DeleteMotionAction.kt$DeleteMotionAction$override fun execute(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Boolean</ID>
<ID>ReturnCount:EditFileHandler.kt$EditFileHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>ReturnCount:EditorHelper.kt$ fun Editor.isPrimaryEditor(): Boolean</ID>
<ID>ReturnCount:ExRanges.kt$Range.Companion$ @JvmStatic fun createRange(str: String, offset: Int, move: Boolean): Array&lt;Range&gt;?</ID> <ID>ReturnCount:ExRanges.kt$Range.Companion$ @JvmStatic fun createRange(str: String, offset: Int, move: Boolean): Array&lt;Range&gt;?</ID>
<ID>ReturnCount:FilterMotionAction.kt$FilterMotionAction$override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean</ID>
<ID>ReturnCount:GotoCharacterHandler.kt$GotoCharacterHandler$override fun execute(editor: Editor, caret: Caret, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>ReturnCount:Helper.kt$@Suppress("IncorrectParentDisposable") fun Editor.isTemplateActive(): Boolean</ID>
<ID>ReturnCount:HistoryHandler.kt$HistoryHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>ReturnCount:IdeaSelectionControl.kt$IdeaSelectionControl$ fun predictMode(editor: Editor, selectionSource: VimListenerManager.SelectionSource): CommandState.Mode</ID>
<ID>ReturnCount:MapHandler.kt$MapHandler$@Throws(ExException::class) private fun executeCommand(cmd: ExCommand, editor: Editor?): Boolean</ID>
<ID>ReturnCount:Marks.kt$IntellijMark$private fun getProject(): Project?</ID>
<ID>ReturnCount:Marks.kt$VimMark.Companion$@JvmStatic fun create(key: Char?, logicalLine: Int?, col: Int?, filename: String?, protocol: String?): VimMark?</ID>
<ID>ReturnCount:ModalEntry.kt$ModalEntry.&lt;no name provided&gt;$override fun dispatchKeyEvent(e: KeyEvent): Boolean</ID>
<ID>ReturnCount:MotionScrollLastScreenLinePageStartAction.kt$MotionScrollLastScreenLinePageStartAction$override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean</ID>
<ID>ReturnCount:OperatorAction.kt$OperatorAction$override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean</ID>
<ID>ReturnCount:OptionsManager.kt$OptionsManager$ fun parseOptionLine(editor: Editor?, args: String, failOnBad: Boolean): Boolean</ID>
<ID>ReturnCount:PutGroup.kt$PutGroup$private fun getProviderForPasteViaIde(context: DataContext, typeInRegister: SelectionType, data: PutData): PasteProvider?</ID>
<ID>ReturnCount:PutGroup.kt$PutGroup$private fun prepareDocumentAndGetStartOffsets(editor: Editor, caret: Caret, typeInRegister: SelectionType, data: PutData, additionalData: Map&lt;String, Any&gt;): List&lt;Int&gt;</ID>
<ID>ReturnCount:PutLinesHandler.kt$PutLinesHandler$override fun execute(editor: Editor, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>ReturnCount:ReloadVimRc.kt$VimRcFileState$fun equalTo(document: Document): Boolean</ID>
<ID>ReturnCount:RepeatHandler.kt$RepeatHandler$@Throws(ExException::class) override fun execute(editor: Editor, caret: Caret, context: DataContext, cmd: ExCommand): Boolean</ID>
<ID>ReturnCount:SelectMotionRightAction.kt$SelectMotionRightAction$override fun getOffset(editor: Editor, caret: Caret, context: DataContext, count: Int, rawCount: Int, argument: Argument?): Int</ID>
<ID>ReturnCount:ShowCmd.kt$ShowCmd$fun getFullText(editor: Editor?): String</ID>
<ID>ReturnCount:TabCloseHandler.kt$TabCloseHandler$ private fun getTabIndexToClose(arg: String, current: Int, last: Int): Int?</ID>
<ID>ReturnCount:TextObjectActionHandler.kt$TextObjectActionHandler$ final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean</ID>
<ID>ReturnCount:UndoRedoHelper.kt$UndoRedoHelper$fun redo(context: DataContext): Boolean</ID>
<ID>ReturnCount:UndoRedoHelper.kt$UndoRedoHelper$fun undo(context: DataContext): Boolean</ID>
<ID>ReturnCount:VimExchangeExtension.kt$VimExchangeExtension.Operator$override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean</ID>
<ID>ReturnCount:VimExtensionFacade.kt$VimExtensionFacade$ @JvmStatic fun inputString(editor: Editor, prompt: String, finishOn: Char?): String</ID>
<ID>ReturnCount:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.AllOccurrencesHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID> <ID>ReturnCount:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.AllOccurrencesHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID>
<ID>ReturnCount:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID> <ID>ReturnCount:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.NextOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID>
<ID>ReturnCount:VimMultipleCursorsExtension.kt$VimMultipleCursorsExtension.SkipOccurrenceHandler$override fun executeInWriteAction(editor: Editor, context: DataContext)</ID>
<ID>ReturnCount:VimScriptParser.kt$VimScriptParser$@Throws(ExException::class) fun evaluate(expression: String, globals: Map&lt;String?, Any?&gt;): Any</ID>
<ID>ReturnCount:VimScriptParser.kt$VimScriptParser$fun findOrCreateIdeaVimRc(): File?</ID>
<ID>ReturnCount:VimShortcutKeyAction.kt$VimShortcutKeyAction$private fun getKeyStroke(e: AnActionEvent): KeyStroke?</ID>
<ID>ReturnCount:VimShortcutKeyAction.kt$VimShortcutKeyAction$private fun isEnabled(e: AnActionEvent): Boolean</ID> <ID>ReturnCount:VimShortcutKeyAction.kt$VimShortcutKeyAction$private fun isEnabled(e: AnActionEvent): Boolean</ID>
<ID>ReturnCount:VimSurroundExtension.kt$VimSurroundExtension.CSurroundHandler$override fun execute(editor: Editor, context: DataContext)</ID>
<ID>ReturnCount:VimSurroundExtension.kt$VimSurroundExtension.Operator$override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean</ID>
<ID>ReturnCount:VisualBlockAppendAction.kt$VisualBlockAppendAction$override fun executeForAllCarets(editor: Editor, context: DataContext, cmd: Command, caretsAndSelections: Map&lt;Caret, VimSelection&gt;): Boolean</ID>
<ID>ReturnCount:VisualBlockInsertAction.kt$VisualBlockInsertAction$override fun executeForAllCarets(editor: Editor, context: DataContext, cmd: Command, caretsAndSelections: Map&lt;Caret, VimSelection&gt;): Boolean</ID>
<ID>ReturnCount:VisualMotionGroup.kt$VisualMotionGroup$ fun toggleVisual(editor: Editor, count: Int, rawCount: Int, subMode: CommandState.SubMode): Boolean</ID>
<ID>ReturnCount:VisualMotionGroup.kt$VisualMotionGroup$fun autodetectVisualSubmode(editor: Editor): CommandState.SubMode</ID>
<ID>ReturnCount:VisualMotionGroup.kt$VisualMotionGroup$fun selectPreviousVisualMode(editor: Editor): Boolean</ID>
<ID>ReturnCount:VisualMotionGroup.kt$VisualMotionGroup$fun swapVisualSelections(editor: Editor): Boolean</ID>
<ID>ReturnCount:VisualMotionGroup.kt$VisualMotionGroup$private fun seemsLikeBlockMode(editor: Editor): Boolean</ID> <ID>ReturnCount:VisualMotionGroup.kt$VisualMotionGroup$private fun seemsLikeBlockMode(editor: Editor): Boolean</ID>
<ID>ReturnCount:VisualOperatorActionHandler.kt$VisualOperatorActionHandler$final override fun baseExecute(editor: Editor, caret: Caret, context: DataContext, cmd: Command): Boolean</ID>
<ID>ReturnCount:YankGroup.kt$YankGroup$ fun yankMotion(editor: Editor, context: DataContext, count: Int, rawCount: Int, argument: Argument): Boolean</ID>
<ID>ThrowsCount:CommandHandler.kt$CommandHandler$private fun checkArgs(cmd: ExCommand)</ID> <ID>ThrowsCount:CommandHandler.kt$CommandHandler$private fun checkArgs(cmd: ExCommand)</ID>
<ID>TooManyFunctions:CommandBuilder.kt$CommandBuilder</ID> <ID>TooManyFunctions:CommandBuilder.kt$CommandBuilder</ID>
<ID>TooManyFunctions:CommandState.kt$CommandState</ID> <ID>TooManyFunctions:CommandState.kt$CommandState</ID>
<ID>TooManyFunctions:PutGroup.kt$PutGroup</ID> <ID>TooManyFunctions:PutGroup.kt$PutGroup</ID>
<ID>TooManyFunctions:Ranges.kt$Ranges</ID> <ID>TooManyFunctions:Ranges.kt$Ranges</ID>
<ID>TooManyFunctions:SearchHighlightsHelper.kt$com.maddyhome.idea.vim.helper.SearchHighlightsHelper.kt</ID>
<ID>TooManyFunctions:VisualGroup.kt$com.maddyhome.idea.vim.group.visual.VisualGroup.kt</ID> <ID>TooManyFunctions:VisualGroup.kt$com.maddyhome.idea.vim.group.visual.VisualGroup.kt</ID>
<ID>TooManyFunctions:VisualMotionGroup.kt$VisualMotionGroup</ID> <ID>TooManyFunctions:VisualMotionGroup.kt$VisualMotionGroup</ID>
</CurrentIssues> </CurrentIssues>

View File

@@ -29,7 +29,6 @@
<option name="m_requireAnnotationsFirst" value="true" /> <option name="m_requireAnnotationsFirst" value="true" />
</inspection_tool> </inspection_tool>
<inspection_tool class="PluginXmlI18n" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="PluginXmlI18n" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" />
</profile> </profile>
</component> </component>

View File

@@ -41,7 +41,6 @@
<option name="processLiterals" value="true" /> <option name="processLiterals" value="true" />
<option name="processComments" value="true" /> <option name="processComments" value="true" />
</inspection_tool> </inspection_tool>
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="SuperTearDownInFinally" enabled="true" level="WARNING" enabled_by_default="true" /> <inspection_tool class="SuperTearDownInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
<inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" /> <inspection_tool class="UnstableApiUsage" enabled="false" level="WARNING" enabled_by_default="false" />
</profile> </profile>

View File

@@ -13,10 +13,12 @@ import _Self.buildTypes.TestsForIntelliJ20192
import _Self.buildTypes.TestsForIntelliJ20193 import _Self.buildTypes.TestsForIntelliJ20193
import _Self.buildTypes.TestsForIntelliJ20201 import _Self.buildTypes.TestsForIntelliJ20201
import _Self.buildTypes.TestsForIntelliJ20202 import _Self.buildTypes.TestsForIntelliJ20202
import _Self.buildTypes.TestsForIntelliJ20203
import _Self.buildTypes.TestsForIntelliJEAP import _Self.buildTypes.TestsForIntelliJEAP
import _Self.vcsRoots.Branch_181 import _Self.vcsRoots.Branch_181
import _Self.vcsRoots.Branch_183 import _Self.vcsRoots.Branch_183
import _Self.vcsRoots.Branch_191_193 import _Self.vcsRoots.Branch_191_193
import _Self.vcsRoots.Branch_201
import _Self.vcsRoots.GitHubPullRequest import _Self.vcsRoots.GitHubPullRequest
import jetbrains.buildServer.configs.kotlin.v2019_2.Project import jetbrains.buildServer.configs.kotlin.v2019_2.Project
@@ -25,11 +27,22 @@ object Project : Project({
vcsRoot(Branch_183) vcsRoot(Branch_183)
vcsRoot(Branch_181) vcsRoot(Branch_181)
vcsRoot(GitHubPullRequest)
vcsRoot(Branch_191_193) vcsRoot(Branch_191_193)
vcsRoot(Branch_201)
vcsRoot(GitHubPullRequest)
buildType(GitHubPullRequests) buildType(GitHubPullRequests)
buildType(Release) buildType(Release)
buildType(ReleaseEap)
buildType(TestsForIntelliJ20202)
buildType(TestsForIntelliJ20203)
buildType(TestsForIntelliJEAP)
buildType(Nvim)
buildType(PluginVerifier)
buildType(TestsForIntelliJ20201) buildType(TestsForIntelliJ20201)
buildType(TestsForIntelliJ20191) buildType(TestsForIntelliJ20191)
buildType(TestsForIntelliJ20181) buildType(TestsForIntelliJ20181)
@@ -37,11 +50,6 @@ object Project : Project({
buildType(TestsForIntelliJ20182) buildType(TestsForIntelliJ20182)
buildType(TestsForIntelliJ20193) buildType(TestsForIntelliJ20193)
buildType(TestsForIntelliJ20183) buildType(TestsForIntelliJ20183)
buildType(Nvim)
buildType(ReleaseEap)
buildType(TestsForIntelliJ20202)
buildType(TestsForIntelliJEAP)
buildType(PluginVerifier)
features { features {
feature { feature {

View File

@@ -41,5 +41,5 @@ sealed class ActiveTests(buildName: String, ijVersion: String) : BuildType({
}) })
object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT") object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT")
object TestsForIntelliJ20203 : ActiveTests("Tests for IntelliJ 2020.3", "2020.3")
object TestsForIntelliJ20202 : ActiveTests("Tests for IntelliJ 2020.2", "2020.2") object TestsForIntelliJ20202 : ActiveTests("Tests for IntelliJ 2020.2", "2020.2")
object TestsForIntelliJ20201 : ActiveTests("Tests for IntelliJ 2020.1", "2020.1")

View File

@@ -16,7 +16,7 @@ object GitHubPullRequests : BuildType({
params { params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false") param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.1") param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.3")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false") param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
} }

View File

@@ -10,7 +10,7 @@ object Release : BuildType({
description = "Build and publish IdeaVim plugin" description = "Build and publish IdeaVim plugin"
artifactRules = "build/distributions/*" artifactRules = "build/distributions/*"
buildNumberPattern = "0.61" buildNumberPattern = "0.64"
params { params {
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2") param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")

View File

@@ -13,7 +13,7 @@ object ReleaseEap : BuildType({
description = "Build and publish EAP of IdeaVim plugin" description = "Build and publish EAP of IdeaVim plugin"
artifactRules = "build/distributions/*" artifactRules = "build/distributions/*"
buildNumberPattern = "0.61.%build.counter%" buildNumberPattern = "0.64.%build.counter%"
params { params {
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2") param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")

View File

@@ -0,0 +1,46 @@
@file:Suppress("ClassName")
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
sealed class TestsForIntelliJ_201_branch(private val version: String) : BuildType({
name = "Tests for IntelliJ $version"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_ideaVersion", "IC-$version")
param("env.ORG_GRADLE_PROJECT_instrumentPluginCode", "false")
param("env.ORG_GRADLE_PROJECT_javaVersion", "1.8")
}
vcs {
root(_Self.vcsRoots.Branch_201)
checkoutMode = CheckoutMode.ON_SERVER
}
steps {
gradle {
tasks = "clean test"
buildFile = ""
enableStacktrace = true
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
triggers {
vcs {
branchFilter = ""
}
}
requirements {
noLessThanVer("teamcity.agent.jvm.version", "1.8")
}
})
object TestsForIntelliJ20201 : TestsForIntelliJ_201_branch("2020.1")

12
.teamcity/_Self/vcsRoots/Branch_201.kt vendored Normal file
View File

@@ -0,0 +1,12 @@
@file:Suppress("ClassName")
package _Self.vcsRoots
import jetbrains.buildServer.configs.kotlin.v2019_2.vcs.GitVcsRoot
object Branch_201 : GitVcsRoot({
name = "https://github.com/JetBrains/ideavim (branch 201)"
url = "https://github.com/JetBrains/ideavim.git"
branch = "201"
useMirrors = false
})

View File

@@ -331,6 +331,14 @@ Contributors:
[![icon][github]](https://github.com/antekone) [![icon][github]](https://github.com/antekone)
&nbsp; &nbsp;
Grzegorz Antoniak Grzegorz Antoniak
* [![icon][mail]](mailto:shaunpatterson@gmail.com)
[![icon][github]](https://github.com/shaunpatterson)
&nbsp;
Shaun Patterson
* [![icon][mail]](mailto:vladimir.petrenko@jetbrains.com)
[![icon][github]](https://github.com/vladimir-petrenko)
&nbsp;
Vladimir Petrenko
If you are a contributor and your name is not listed here, feel free to If you are a contributor and your name is not listed here, feel free to
contact the maintainers. contact the maintainers.

View File

@@ -22,18 +22,42 @@ It is important to distinguish EAP from traditional pre-release software.
Please note that the quality of EAP versions may at times be way below even Please note that the quality of EAP versions may at times be way below even
usual beta standards. usual beta standards.
## To Be Released ## 0.64, 2020-12-23
### Merged PRs:
* [260](https://github.com/JetBrains/ideavim/pull/260) by [Matt Ellis](https://github.com/citizenmatt): Refactor SearchGroup
### Fixes:
* [VIM-2194](https://youtrack.jetbrains.com/issue/VIM-2194) Fix caret shape during editing a new file
## 0.63, 2020-12-16
### Changes:
* Update the minimal required IJ version: 2020.2+
### Fixes:
* [CWM-927](https://youtrack.jetbrains.com/issue/CWM-927) Fix typing for CodeWithMe and IdeaVim
### Merged PRs:
* [259](https://github.com/JetBrains/ideavim/pull/259) by [Vladimir Petrenko](https://github.com/vladimir-petrenko): CWM-927 disable vim for client's hidden editor on host
## 0.62, 2020-12-15
### Features: ### Features:
* Support `unmap` and `mapclear` commands [VIM-1491](https://youtrack.jetbrains.com/issue/VIM-1491) * Support `unmap` and `mapclear` commands [VIM-1491](https://youtrack.jetbrains.com/issue/VIM-1491)
* Support mappings in ex panel (`cmap`) [VIM-1227](https://youtrack.jetbrains.com/issue/VIM-1227) * Support mappings in ex panel (`cmap`) [VIM-1227](https://youtrack.jetbrains.com/issue/VIM-1227)
### Changes:
* `octal` is now disabled by default for `nrformats`. [VIM-2181](https://youtrack.jetbrains.com/issue/VIM-2181)
### Fixes: ### Fixes:
* [VIM-2113](https://youtrack.jetbrains.com/issue/VIM-2113) Fix `cit` for empty tags * [VIM-2113](https://youtrack.jetbrains.com/issue/VIM-2113) Fix `cit` for empty tags
* [VIM-2114](https://youtrack.jetbrains.com/issue/VIM-2114) Unnamed register isn't changed after deleting empty tag * [VIM-2114](https://youtrack.jetbrains.com/issue/VIM-2114) Unnamed register isn't changed after deleting empty tag
* [VIM-1475](https://youtrack.jetbrains.com/issue/VIM-1475) Enable block caret to be used in insert mode. * [VIM-1475](https://youtrack.jetbrains.com/issue/VIM-1475) Enable block caret to be used in insert mode.
* [VIM-2170](https://youtrack.jetbrains.com/issue/VIM-2170) Fix an alternative range format for `s` command * [VIM-2170](https://youtrack.jetbrains.com/issue/VIM-2170) Fix an alternative range format for `s` command
* [VIM-1913](https://youtrack.jetbrains.com/issue/VIM-1913)
[VIM-2154](https://youtrack.jetbrains.com/issue/VIM-2154) Several fixes for AppCode templates
* [VIM-1756](https://youtrack.jetbrains.com/issue/VIM-1756) Fix startsel from insert mode
### Merged PRs: ### Merged PRs:
* [249](https://github.com/JetBrains/ideavim/pull/249) by [Jan Palus](https://github.com/jpalus): VIM-2113 Increase tag range only in visual mode * [249](https://github.com/JetBrains/ideavim/pull/249) by [Jan Palus](https://github.com/jpalus): VIM-2113 Increase tag range only in visual mode
@@ -41,6 +65,9 @@ usual beta standards.
* [256](https://github.com/JetBrains/ideavim/pull/256) by [Brandon Conway](https://github.com/brandoncc): Fix typo * [256](https://github.com/JetBrains/ideavim/pull/256) by [Brandon Conway](https://github.com/brandoncc): Fix typo
* [254](https://github.com/JetBrains/ideavim/pull/254) by [Grzegorz Antoniak](https://github.com/antekone): VIM-1475: Add an option to use block caret in insert mode * [254](https://github.com/JetBrains/ideavim/pull/254) by [Grzegorz Antoniak](https://github.com/antekone): VIM-1475: Add an option to use block caret in insert mode
* [225](https://github.com/JetBrains/ideavim/pull/225) by [sumoooru2](https://github.com/sumoooru2): Implement cmap * [225](https://github.com/JetBrains/ideavim/pull/225) by [sumoooru2](https://github.com/sumoooru2): Implement cmap
* [258](https://github.com/JetBrains/ideavim/pull/258) by [Matt Ellis](https://github.com/citizenmatt): Show the correct handler class in :map
* [257](https://github.com/JetBrains/ideavim/pull/257) by [Matt Ellis](https://github.com/citizenmatt): Extract SearchHighlightsHelper from SearchGroup
* [251](https://github.com/JetBrains/ideavim/pull/251) by [Shaun Patterson](https://github.com/shaunpatterson): VIM-1756: startSel works in insert mode
## 0.61, 2020-11-12 ## 0.61, 2020-11-12

View File

@@ -144,21 +144,38 @@ set idearefactormode=keep
map <leader>f <Plug>(easymotion-s) map <leader>f <Plug>(easymotion-s)
map <leader>e <Plug>(easymotion-f) map <leader>e <Plug>(easymotion-f)
map <leader>d :action Debug<CR> map <leader>d <Action>(Debug)
map <leader>r :action RenameElement<CR> map <leader>r <Action>(RenameElement)
map <leader>c :action Stop<CR> map <leader>c <Action>(Stop)
map <leader>z :action ToggleDistractionFreeMode<CR> map <leader>z <Action>(ToggleDistractionFreeMode)
map <leader>s :action SelectInProjectView<CR> map <leader>s <Action>(SelectInProjectView)
map <leader>a :action Annotate<CR> map <leader>a <Action>(Annotate)
map <leader>h :action Vcs.ShowTabbedFileHistory<CR> map <leader>h <Action>(Vcs.ShowTabbedFileHistory)
map <S-Space> :action GotoNextError<CR> map <S-Space> <Action>(GotoNextError)
map <leader>b :action ToggleLineBreakpoint<CR> map <leader>b <Action>(ToggleLineBreakpoint)
map <leader>o :action FileStructurePopup<CR> map <leader>o <Action>(FileStructurePopup)
``` ```
</details> </details>
<details>
<summary><strong>Suggested options</strong> (click to see)</summary>
Here is also a list of the suggested options from [defaults.vim](https://github.com/vim/vim/blob/master/runtime/defaults.vim)
```vim
" Show a few lines of context around the cursor. Note that this makes the
" text scroll if you mouse-click near the start or end of the window.
set scrolloff=5
" Do incremental searching
set incsearch
" Don't use Ex mode, use Q for formatting.
map Q gq
```
</details>
You can read your `~/.vimrc` file from `~/.ideavimrc` with this command: You can read your `~/.vimrc` file from `~/.ideavimrc` with this command:

View File

@@ -59,7 +59,7 @@ runIdeForUiTests {
} }
runPluginVerifier { runPluginVerifier {
ideVersions = ["IC-2020.1.4", "IC-2020.2.3"] ideVersions = ["IC-2020.2.3", "IC-2020.3"]
downloadDirectory = "${project.buildDir}/pluginVerifier/ides" downloadDirectory = "${project.buildDir}/pluginVerifier/ides"
teamCityOutputFormat = true teamCityOutputFormat = true
} }

View File

@@ -28,9 +28,9 @@
<vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionRightMatchCharAction" mappingModes="NXO" keys="f"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionRightMatchCharAction" mappingModes="NXO" keys="f"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionRightTillMatchCharAction" mappingModes="NXO" keys="t"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionRightTillMatchCharAction" mappingModes="NXO" keys="t"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionHomeAction" mappingModes="NV" keys="«Home»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionHomeAction" mappingModes="NV" keys="«Home»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionShiftHomeAction" mappingModes="NV" keys="«S-Home»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionShiftHomeAction" mappingModes="INV" keys="«S-Home»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionEndAction" mappingModes="NVO" keys="«End»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionEndAction" mappingModes="NVO" keys="«End»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionShiftEndAction" mappingModes="NV" keys="«S-End»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionShiftEndAction" mappingModes="INV" keys="«S-End»"/>
<!-- Up/Down --> <!-- Up/Down -->
<vimAction implementation="com.maddyhome.idea.vim.action.motion.updown.MotionDownAction" mappingModes="NXO" keys="j"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.updown.MotionDownAction" mappingModes="NXO" keys="j"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.updown.MotionDownCtrlNAction" mappingModes="NXO" keys="«C-N»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.updown.MotionDownCtrlNAction" mappingModes="NXO" keys="«C-N»"/>
@@ -152,10 +152,10 @@
<vimAction implementation="com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction" mappingModes="NXO" keys="zh,z«Left»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.scroll.MotionScrollColumnRightAction" mappingModes="NXO" keys="zh,z«Left»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthLeftAction" mappingModes="NXO" keys="zL"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthLeftAction" mappingModes="NXO" keys="zL"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthRightAction" mappingModes="NXO" keys="zH"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.scroll.MotionScrollHalfWidthRightAction" mappingModes="NXO" keys="zH"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction" mappingModes="NV" keys="«S-Down»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.updown.MotionShiftDownAction" mappingModes="INV" keys="«S-Down»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction" mappingModes="NV" keys="«S-Up»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.updown.MotionShiftUpAction" mappingModes="INV" keys="«S-Up»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction" mappingModes="NV" keys="«S-Right»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionShiftRightAction" mappingModes="INV" keys="«S-Right»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction" mappingModes="NV" keys="«S-Left»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.leftright.MotionShiftLeftAction" mappingModes="INV" keys="«S-Left»"/>
<!-- Visual --> <!-- Visual -->
<vimAction implementation="com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction" mappingModes="X" keys="«Esc»,«C-[»,«C-C»"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.visual.VisualExitModeAction" mappingModes="X" keys="«Esc»,«C-[»,«C-C»"/>
<vimAction implementation="com.maddyhome.idea.vim.action.motion.visual.VisualToggleCharacterModeAction" mappingModes="NX" keys="v"/> <vimAction implementation="com.maddyhome.idea.vim.action.motion.visual.VisualToggleCharacterModeAction" mappingModes="NX" keys="v"/>

View File

@@ -2,62 +2,21 @@
<name>IdeaVim</name> <name>IdeaVim</name>
<id>IdeaVIM</id> <id>IdeaVIM</id>
<change-notes><![CDATA[ <change-notes><![CDATA[
<h3>Features:</h3> <h3>Merged PRs:</h3>
<ul> <ul>
<li>Support <code>unmap</code> and <code>mapclear</code> commands <li>
<a href="https://youtrack.jetbrains.com/issue/VIM-1491">VIM-1491</a> <a href="https://github.com/JetBrains/ideavim/pull/260">260</a>
</li> by <a href="https://github.com/citizenmatt">Matt Ellis</a>: Refactor SearchGroup
<li>Support mappings in ex panel (<code>cmap</code>)
<a href="https://youtrack.jetbrains.com/issue/VIM-1227">VIM-1227</a>
</li> </li>
</ul> </ul>
<h3>Fixes:</h3> <h3>Fixes:</h3>
<ul> <ul>
<li> <li>
<a href="https://youtrack.jetbrains.com/issue/VIM-2113">VIM-2113</a> <a href="https://youtrack.jetbrains.com/issue/VIM-2194">VIM-2194</a>
Fix <code>cit</code> for empty tags Fix caret shape during editing a new file
</li>
<li>
<a href="https://youtrack.jetbrains.com/issue/VIM-2114">VIM-2114</a>
Unnamed register isn't changed after deleting empty tag
</li>
<li>
<a href="https://youtrack.jetbrains.com/issue/VIM-1475">VIM-1475</a>
Enable block caret to be used in insert mode.
</li>
<li>
<a href="https://youtrack.jetbrains.com/issue/VIM-2170">VIM-2170</a>
Fix an alternative range format for <code>s</code> command
</li> </li>
</ul> </ul>
<h3>Merged PRs:</h3>
<ul>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/249">249</a>
by <a href="https://github.com/jpalus">Jan Palus</a>: VIM-2113 Increase tag range only in visual mode
</li>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/250">250</a>
by <a href="https://github.com/jpalus">Jan Palus</a>: VIM-2114 Do not override registers when deleting empty range
</li>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/256">256</a>
by <a href="https://github.com/brandoncc">Brandon Conway</a>: Fix typo
</li>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/254">254</a>
by <a href="https://github.com/antekone">Grzegorz Antoniak</a>: VIM-1475: Add an option to use block caret in insert
mode
</li>
<li>
<a href="https://github.com/JetBrains/ideavim/pull/225">225</a>
by <a href="https://github.com/sumoooru2">sumoooru2</a>: Implement cmap
</li>
</ul>
<br/>
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
]]> ]]>
</change-notes> </change-notes>
<description><![CDATA[ <description><![CDATA[
@@ -77,7 +36,7 @@
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version --> <!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
<!-- Check for [Version Update] tag in YouTrack as well --> <!-- Check for [Version Update] tag in YouTrack as well -->
<idea-version since-build="201.5985.41"/> <idea-version since-build="202.5103.13"/>
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform --> <!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform -->
<depends>com.intellij.modules.lang</depends> <depends>com.intellij.modules.lang</depends>
@@ -111,7 +70,6 @@
<statusBarWidgetFactory implementation="com.maddyhome.idea.vim.ui.StatusBarIconFactory"/> <statusBarWidgetFactory implementation="com.maddyhome.idea.vim.ui.StatusBarIconFactory"/>
<statusBarWidgetFactory implementation="com.maddyhome.idea.vim.ui.ShowCmdStatusBarWidgetFactory" order="first"/> <statusBarWidgetFactory implementation="com.maddyhome.idea.vim.ui.ShowCmdStatusBarWidgetFactory" order="first"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.config.VimLocalConfig"/>
<applicationService serviceImplementation="com.maddyhome.idea.vim.VimPlugin"/> <applicationService serviceImplementation="com.maddyhome.idea.vim.VimPlugin"/>
<!-- Initialise as early as possible so that we're ready to edit quickly. This is especially important for Rider, <!-- Initialise as early as possible so that we're ready to edit quickly. This is especially important for Rider,

View File

@@ -140,6 +140,6 @@ public class EventFacade {
} }
private @NotNull TypedAction getTypedAction() { private @NotNull TypedAction getTypedAction() {
return EditorActionManager.getInstance().getTypedAction(); return TypedAction.getInstance();
} }
} }

View File

@@ -45,8 +45,8 @@ import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
import com.maddyhome.idea.vim.helper.*; import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.key.*; import com.maddyhome.idea.vim.key.*;
import com.maddyhome.idea.vim.option.OptionsManager; import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.ui.ShowCmd; import com.maddyhome.idea.vim.ui.ShowCmd;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NonNls; import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -319,7 +319,7 @@ public class KeyHandler {
} }
} }
reset(editor); reset(editor);
ChangeGroup.resetCaret(editor, VimPlugin.getEditor().isBarCursor()); ChangeGroup.resetCaret(editor, false);
} }
private boolean handleKeyMapping(final @NotNull Editor editor, private boolean handleKeyMapping(final @NotNull Editor editor,
@@ -692,7 +692,7 @@ public class KeyHandler {
@NotNull CommandNode node, @NotNull CommandNode node,
CommandState editorState) { CommandState editorState) {
// The user entered a valid command. Create the command and add it to the stack. // The user entered a valid command. Create the command and add it to the stack.
final EditorActionHandlerBase action = node.getActionHolder().getAction(); final EditorActionHandlerBase action = node.getActionHolder().getInstance();
final CommandBuilder commandBuilder = editorState.getCommandBuilder(); final CommandBuilder commandBuilder = editorState.getCommandBuilder();
final Argument.Type expectedArgumentType = commandBuilder.getExpectedArgumentType(); final Argument.Type expectedArgumentType = commandBuilder.getExpectedArgumentType();
@@ -739,7 +739,7 @@ public class KeyHandler {
} }
private boolean stopMacroRecord(CommandNode node, @NotNull CommandState editorState) { private boolean stopMacroRecord(CommandNode node, @NotNull CommandState editorState) {
return editorState.isRecording() && node.getActionHolder().getAction() instanceof ToggleRecordingAction; return editorState.isRecording() && node.getActionHolder().getInstance() instanceof ToggleRecordingAction;
} }
private void startWaitingForArgument(Editor editor, private void startWaitingForArgument(Editor editor,
@@ -934,6 +934,7 @@ public class KeyHandler {
if (editorState.getSubMode() == CommandState.SubMode.SINGLE_COMMAND && if (editorState.getSubMode() == CommandState.SubMode.SINGLE_COMMAND &&
(!cmd.getFlags().contains(CommandFlags.FLAG_EXPECT_MORE))) { (!cmd.getFlags().contains(CommandFlags.FLAG_EXPECT_MORE))) {
editorState.popModes(); editorState.popModes();
VisualGroupKt.resetShape(CommandStateHelper.getMode(editor), editor);
} }
if (editorState.getCommandBuilder().isDone()) { if (editorState.getCommandBuilder().isDone()) {

View File

@@ -53,7 +53,7 @@ public class RegisterActions {
public static @Nullable EditorActionHandlerBase findAction(@NotNull String id) { public static @Nullable EditorActionHandlerBase findAction(@NotNull String id) {
return VIM_ACTIONS_EP.extensions().filter(vimActionBean -> vimActionBean.getActionId().equals(id)).findFirst() return VIM_ACTIONS_EP.extensions().filter(vimActionBean -> vimActionBean.getActionId().equals(id)).findFirst()
.map(ActionBeanClass::getAction).orElse(null); .map(ActionBeanClass::getInstance).orElse(null);
} }
public static @NotNull EditorActionHandlerBase findActionOrDie(@NotNull String id) { public static @NotNull EditorActionHandlerBase findActionOrDie(@NotNull String id) {

View File

@@ -19,6 +19,7 @@ package com.maddyhome.idea.vim;
import com.intellij.ide.plugins.IdeaPluginDescriptor; import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManager; import com.intellij.ide.plugins.PluginManager;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.notification.Notification; import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener; import com.intellij.notification.NotificationListener;
import com.intellij.openapi.Disposable; import com.intellij.openapi.Disposable;
@@ -40,7 +41,6 @@ import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.SystemInfo;
import com.intellij.openapi.wm.StatusBar; import com.intellij.openapi.wm.StatusBar;
import com.intellij.openapi.wm.WindowManager; import com.intellij.openapi.wm.WindowManager;
import com.maddyhome.idea.vim.config.VimLocalConfig;
import com.maddyhome.idea.vim.config.VimState; import com.maddyhome.idea.vim.config.VimState;
import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator; import com.maddyhome.idea.vim.config.migration.ApplicationConfigurationMigrator;
import com.maddyhome.idea.vim.ex.CommandParser; import com.maddyhome.idea.vim.ex.CommandParser;
@@ -105,11 +105,6 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
public void initialize() { public void initialize() {
LOG.debug("initComponent"); LOG.debug("initComponent");
// Initialize a legacy local config.
if (previousStateVersion == 5) {
//noinspection deprecation
VimLocalConfig.Companion.initialize();
}
if (enabled) { if (enabled) {
Application application = ApplicationManager.getApplication(); Application application = ApplicationManager.getApplication();
if (application.isUnitTestMode()) { if (application.isUnitTestMode()) {
@@ -168,7 +163,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
} }
public static @Nullable RegisterGroup getRegisterIfCreated() { public static @Nullable RegisterGroup getRegisterIfCreated() {
return ServiceManager.getServiceIfCreated(RegisterGroup.class); return ApplicationManager.getApplication().getServiceIfCreated(RegisterGroup.class);
} }
public static @NotNull FileGroup getFile() { public static @NotNull FileGroup getFile() {
@@ -180,7 +175,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
} }
public static @Nullable SearchGroup getSearchIfCreated() { public static @Nullable SearchGroup getSearchIfCreated() {
return ServiceManager.getServiceIfCreated(SearchGroup.class); return ApplicationManager.getApplication().getServiceIfCreated(SearchGroup.class);
} }
public static @NotNull ProcessGroup getProcess() { public static @NotNull ProcessGroup getProcess() {
@@ -204,7 +199,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
} }
public static @Nullable KeyGroup getKeyIfCreated() { public static @Nullable KeyGroup getKeyIfCreated() {
return ServiceManager.getServiceIfCreated(KeyGroup.class); return ApplicationManager.getApplication().getServiceIfCreated(KeyGroup.class);
} }
public static @NotNull WindowGroup getWindow() { public static @NotNull WindowGroup getWindow() {
@@ -216,7 +211,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
} }
public static @Nullable EditorGroup getEditorIfCreated() { public static @Nullable EditorGroup getEditorIfCreated() {
return ServiceManager.getServiceIfCreated(EditorGroup.class); return ApplicationManager.getApplication().getServiceIfCreated(EditorGroup.class);
} }
public static @NotNull VisualMotionGroup getVisualMotion() { public static @NotNull VisualMotionGroup getVisualMotion() {
@@ -263,7 +258,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
} }
public static @NotNull String getVersion() { public static @NotNull String getVersion() {
final IdeaPluginDescriptor plugin = PluginManager.getPlugin(getPluginId()); final IdeaPluginDescriptor plugin = PluginManagerCore.getPlugin(getPluginId());
if (!ApplicationManager.getApplication().isInternal()) { if (!ApplicationManager.getApplication().isInternal()) {
return plugin != null ? plugin.getVersion() : "SNAPSHOT"; return plugin != null ? plugin.getVersion() : "SNAPSHOT";
} }

View File

@@ -41,6 +41,7 @@ import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
import com.maddyhome.idea.vim.helper.isPrimaryEditor import com.maddyhome.idea.vim.helper.isPrimaryEditor
import com.maddyhome.idea.vim.helper.isTemplateActive import com.maddyhome.idea.vim.helper.isTemplateActive
import com.maddyhome.idea.vim.key.ShortcutOwner import com.maddyhome.idea.vim.key.ShortcutOwner
import com.maddyhome.idea.vim.listener.IdeaSpecifics.AppCodeTemplates.appCodeTemplateCaptured
import com.maddyhome.idea.vim.listener.IdeaSpecifics.aceJumpActive import com.maddyhome.idea.vim.listener.IdeaSpecifics.aceJumpActive
import com.maddyhome.idea.vim.option.OptionsManager import com.maddyhome.idea.vim.option.OptionsManager
import java.awt.event.InputEvent import java.awt.event.InputEvent
@@ -99,6 +100,8 @@ class VimShortcutKeyAction : AnAction(), DumbAware {
if (keyCode == KeyEvent.VK_TAB && editor.isTemplateActive()) return false if (keyCode == KeyEvent.VK_TAB && editor.isTemplateActive()) return false
if ((keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ENTER) && editor.appCodeTemplateCaptured()) return false
if (editor.inInsertMode) { // XXX: <Tab> won't be recorded in macros if (editor.inInsertMode) { // XXX: <Tab> won't be recorded in macros
if (keyCode == KeyEvent.VK_TAB) { if (keyCode == KeyEvent.VK_TAB) {
VimPlugin.getChange().tabAction = true VimPlugin.getChange().tabAction = true

View File

@@ -27,6 +27,7 @@ import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.ex.CommandParser import com.maddyhome.idea.vim.ex.CommandParser
import com.maddyhome.idea.vim.ex.ExException import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.group.RegisterGroup
import com.maddyhome.idea.vim.handler.VimActionHandler import com.maddyhome.idea.vim.handler.VimActionHandler
class PlaybackRegisterAction : VimActionHandler.SingleExecution() { class PlaybackRegisterAction : VimActionHandler.SingleExecution() {
@@ -44,7 +45,7 @@ class PlaybackRegisterAction : VimActionHandler.SingleExecution() {
'@' -> { '@' -> {
application.runWriteAction { res.set(VimPlugin.getMacro().playbackLastRegister(editor, context, project, cmd.count)) } application.runWriteAction { res.set(VimPlugin.getMacro().playbackLastRegister(editor, context, project, cmd.count)) }
} }
':' -> { // No write action RegisterGroup.LAST_COMMAND_REGISTER -> { // No write action
try { try {
res.set(CommandParser.getInstance().processLastCommand(editor, context, cmd.count)) res.set(CommandParser.getInstance().processLastCommand(editor, context, cmd.count))
} catch (e: ExException) { } catch (e: ExException) {

View File

@@ -47,9 +47,7 @@ class MotionScrollPageDownAction : VimActionHandler.SingleExecution() {
class MotionScrollPageDownInsertModeAction : VimActionHandler.SingleExecution(), ComplicatedKeysAction { class MotionScrollPageDownInsertModeAction : VimActionHandler.SingleExecution(), ComplicatedKeysAction {
override val keyStrokesSet: Set<List<KeyStroke>> = setOf( override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0)), listOf(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_DOWN, 0))
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, KeyEvent.SHIFT_DOWN_MASK)),
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_KP_DOWN, KeyEvent.SHIFT_DOWN_MASK))
) )
override val type: Command.Type = Command.Type.OTHER_READONLY override val type: Command.Type = Command.Type.OTHER_READONLY

View File

@@ -47,9 +47,7 @@ class MotionScrollPageUpAction : VimActionHandler.SingleExecution() {
class MotionScrollPageUpInsertModeAction : VimActionHandler.SingleExecution(), ComplicatedKeysAction { class MotionScrollPageUpInsertModeAction : VimActionHandler.SingleExecution(), ComplicatedKeysAction {
override val keyStrokesSet: Set<List<KeyStroke>> = setOf( override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0)), listOf(KeyStroke.getKeyStroke(KeyEvent.VK_PAGE_UP, 0))
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_UP, KeyEvent.SHIFT_DOWN_MASK)),
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_KP_UP, KeyEvent.SHIFT_DOWN_MASK))
) )
override val type: Command.Type = Command.Type.OTHER_READONLY override val type: Command.Type = Command.Type.OTHER_READONLY

View File

@@ -25,6 +25,7 @@ import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MotionType import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.handler.MotionActionHandler import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.helper.Direction
import com.maddyhome.idea.vim.helper.enumSetOf import com.maddyhome.idea.vim.helper.enumSetOf
import java.util.* import java.util.*
@@ -37,7 +38,7 @@ class SearchWholeWordBackwardAction : MotionActionHandler.ForEachCaret() {
count: Int, count: Int,
rawCount: Int, rawCount: Int,
argument: Argument?): Int { argument: Argument?): Int {
return VimPlugin.getSearch().searchWord(editor, caret, count, true, -1) return VimPlugin.getSearch().searchWord(editor, caret, count, true, Direction.BACKWARDS)
} }
override val motionType: MotionType = MotionType.EXCLUSIVE override val motionType: MotionType = MotionType.EXCLUSIVE

View File

@@ -25,6 +25,7 @@ import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MotionType import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.handler.MotionActionHandler import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.helper.Direction
import com.maddyhome.idea.vim.helper.enumSetOf import com.maddyhome.idea.vim.helper.enumSetOf
import java.util.* import java.util.*
@@ -37,7 +38,7 @@ class SearchWholeWordForwardAction : MotionActionHandler.ForEachCaret() {
count: Int, count: Int,
rawCount: Int, rawCount: Int,
argument: Argument?): Int { argument: Argument?): Int {
return VimPlugin.getSearch().searchWord(editor, caret, count, true, 1) return VimPlugin.getSearch().searchWord(editor, caret, count, true, Direction.FORWARDS)
} }
override val motionType: MotionType = MotionType.EXCLUSIVE override val motionType: MotionType = MotionType.EXCLUSIVE

View File

@@ -25,6 +25,7 @@ import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MotionType import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.handler.MotionActionHandler import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.helper.Direction
import com.maddyhome.idea.vim.helper.enumSetOf import com.maddyhome.idea.vim.helper.enumSetOf
import java.util.* import java.util.*
@@ -37,7 +38,7 @@ class SearchWordBackwardAction : MotionActionHandler.ForEachCaret() {
count: Int, count: Int,
rawCount: Int, rawCount: Int,
argument: Argument?): Int { argument: Argument?): Int {
return VimPlugin.getSearch().searchWord(editor, caret, count, false, -1) return VimPlugin.getSearch().searchWord(editor, caret, count, false, Direction.BACKWARDS)
} }
override val motionType: MotionType = MotionType.EXCLUSIVE override val motionType: MotionType = MotionType.EXCLUSIVE

View File

@@ -25,6 +25,7 @@ import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.CommandFlags import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MotionType import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.handler.MotionActionHandler import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.helper.Direction
import com.maddyhome.idea.vim.helper.enumSetOf import com.maddyhome.idea.vim.helper.enumSetOf
import java.util.* import java.util.*
@@ -37,7 +38,7 @@ class SearchWordForwardAction : MotionActionHandler.ForEachCaret() {
count: Int, count: Int,
rawCount: Int, rawCount: Int,
argument: Argument?): Int { argument: Argument?): Int {
return VimPlugin.getSearch().searchWord(editor, caret, count, false, 1) return VimPlugin.getSearch().searchWord(editor, caret, count, false, Direction.FORWARDS)
} }
override val motionType: MotionType = MotionType.EXCLUSIVE override val motionType: MotionType = MotionType.EXCLUSIVE

View File

@@ -51,9 +51,7 @@ class MotionWordLeftInsertAction : MotionActionHandler.ForEachCaret(), Complicat
override val keyStrokesSet: Set<List<KeyStroke>> = setOf( override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK)), listOf(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.CTRL_DOWN_MASK)),
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, KeyEvent.CTRL_DOWN_MASK)), listOf(KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, KeyEvent.CTRL_DOWN_MASK))
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, KeyEvent.SHIFT_DOWN_MASK)),
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_KP_LEFT, KeyEvent.SHIFT_DOWN_MASK))
) )
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE) override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE)

View File

@@ -51,9 +51,7 @@ class MotionWordRightInsertAction : MotionActionHandler.ForEachCaret(), Complica
override val keyStrokesSet: Set<List<KeyStroke>> = setOf( override val keyStrokesSet: Set<List<KeyStroke>> = setOf(
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK)), listOf(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.CTRL_DOWN_MASK)),
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_KP_RIGHT, KeyEvent.CTRL_DOWN_MASK)), listOf(KeyStroke.getKeyStroke(KeyEvent.VK_KP_RIGHT, KeyEvent.CTRL_DOWN_MASK))
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, KeyEvent.SHIFT_DOWN_MASK)),
listOf(KeyStroke.getKeyStroke(KeyEvent.VK_KP_RIGHT, KeyEvent.SHIFT_DOWN_MASK))
) )
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE) override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_STROKE)

View File

@@ -1,57 +0,0 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.config
import com.intellij.openapi.components.PersistentStateComponent
import com.intellij.openapi.components.RoamingType
import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.maddyhome.idea.vim.VimPlugin
import org.jdom.Element
/**
* @author Alex Plate
*/
@State(name = "VimLocalSettings", storages = [
Storage("\$APP_CONFIG$$/vim_local_settings.xml", roamingType = RoamingType.DISABLED, deprecated = true),
Storage("\$APP_CONFIG$/vim_local_settings.xml", roamingType = RoamingType.DISABLED, deprecated = true)
])
@Deprecated("The data from this class will be stored in vim_settings")
class VimLocalConfig : PersistentStateComponent<Element> {
override fun getState(): Element? = null
override fun loadState(state: Element) {
// This is initialization of state from the legacy configuration structure.
// This code should be performed only once on settings migration.
// After the migration is done, the file with settings gets removed and this method won't be called again.
VimPlugin.getMark().readData(state)
VimPlugin.getRegister().readData(state)
VimPlugin.getSearch().readData(state)
VimPlugin.getHistory().readData(state)
}
companion object {
fun initialize() {
@Suppress("DEPRECATION")
ServiceManager.getService(VimLocalConfig::class.java)
}
}
}

View File

@@ -24,13 +24,12 @@ import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.extensions.ExtensionPointName; import com.intellij.openapi.extensions.ExtensionPointName;
import com.intellij.openapi.util.ThrowableComputable; import com.intellij.openapi.util.ThrowableComputable;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.SelectionType;
import com.maddyhome.idea.vim.common.Register; import com.maddyhome.idea.vim.common.Register;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.ex.handler.GotoLineHandler; import com.maddyhome.idea.vim.ex.handler.GotoLineHandler;
import com.maddyhome.idea.vim.ex.ranges.Range; import com.maddyhome.idea.vim.ex.ranges.Range;
import com.maddyhome.idea.vim.ex.ranges.Ranges; import com.maddyhome.idea.vim.ex.ranges.Ranges;
import com.maddyhome.idea.vim.group.HistoryGroup; import com.maddyhome.idea.vim.group.HistoryGroup;
import com.maddyhome.idea.vim.group.RegisterGroup;
import com.maddyhome.idea.vim.helper.MessageHelper; import com.maddyhome.idea.vim.helper.MessageHelper;
import com.maddyhome.idea.vim.helper.Msg; import com.maddyhome.idea.vim.helper.Msg;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -177,8 +176,7 @@ public class CommandParser {
ThrowableComputable<Object, ExException> runCommand = () -> { ThrowableComputable<Object, ExException> runCommand = () -> {
boolean ok = handler.process(editor, context, command, count); boolean ok = handler.process(editor, context, command, count);
if (ok && !handler.getArgFlags().getFlags().contains(CommandHandler.Flag.DONT_SAVE_LAST)) { if (ok && !handler.getArgFlags().getFlags().contains(CommandHandler.Flag.DONT_SAVE_LAST)) {
VimPlugin.getRegister().storeTextInternal(editor, new TextRange(-1, -1), cmd, VimPlugin.getRegister().storeTextSpecial(RegisterGroup.LAST_COMMAND_REGISTER, cmd);
SelectionType.CHARACTER_WISE, ':', false);
} }
return null; return null;
}; };
@@ -210,7 +208,7 @@ public class CommandParser {
} }
} }
final ExBeanClass handlerHolder = node.getCommandHandler(); final ExBeanClass handlerHolder = node.getCommandHandler();
return handlerHolder != null ? handlerHolder.getHandler() : null; return handlerHolder != null ? handlerHolder.getInstance() : null;
} }
/** /**
@@ -558,8 +556,8 @@ public class CommandParser {
if (handlerHolder.getNames() != null) { if (handlerHolder.getNames() != null) {
names = CommandDefinitionKt.commands(handlerHolder.getNames().split(",")); names = CommandDefinitionKt.commands(handlerHolder.getNames().split(","));
} }
else if (handlerHolder.getHandler() instanceof ComplicatedNameExCommand) { else if (handlerHolder.getInstance() instanceof ComplicatedNameExCommand) {
names = ((ComplicatedNameExCommand)handlerHolder.getHandler()).getNames(); names = ((ComplicatedNameExCommand)handlerHolder.getInstance()).getNames();
} }
else { else {
throw new RuntimeException("Cannot create an ex command: " + handlerHolder); throw new RuntimeException("Cannot create an ex command: " + handlerHolder);

View File

@@ -18,29 +18,23 @@
package com.maddyhome.idea.vim.ex package com.maddyhome.idea.vim.ex
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.diagnostic.logger
import com.intellij.openapi.extensions.AbstractExtensionPointBean import com.intellij.serviceContainer.BaseKeyedLazyInstance
import com.intellij.util.xmlb.annotations.Attribute import com.intellij.util.xmlb.annotations.Attribute
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
// [Version Update] 202+ class ExBeanClass : BaseKeyedLazyInstance<CommandHandler>() {
@Suppress("DEPRECATION")
class ExBeanClass : AbstractExtensionPointBean() {
@Attribute("implementation") @Attribute("implementation")
var implementation: String? = null var implementation: String? = null
@Attribute("names") @Attribute("names")
var names: String? = null var names: String? = null
val handler: CommandHandler by lazy { override fun getImplementationClassName(): String? = implementation
this.instantiateClass<CommandHandler>(
implementation ?: "", ApplicationManager.getApplication().picoContainer)
}
fun register() { fun register() {
if (pluginId != VimPlugin.getPluginId()) { if (this.pluginDescriptor.pluginId != VimPlugin.getPluginId()) {
logger<ExBeanClass>().error("IdeaVim doesn't accept contributions to `vimActions` extension points. Please create a plugin using `VimExtension`. Plugin to blame: $pluginId") logger<ExBeanClass>().error("IdeaVim doesn't accept contributions to `vimActions` extension points. Please create a plugin using `VimExtension`. Plugin to blame: ${this.pluginDescriptor.pluginId}")
return return
} }
CommandParser.getInstance().addHandler(this) CommandParser.getInstance().addHandler(this)

View File

@@ -18,19 +18,13 @@
package com.maddyhome.idea.vim.extension package com.maddyhome.idea.vim.extension
import com.intellij.openapi.application.ApplicationManager import com.intellij.serviceContainer.BaseKeyedLazyInstance
import com.intellij.openapi.extensions.AbstractExtensionPointBean
import com.intellij.util.xmlb.annotations.Attribute import com.intellij.util.xmlb.annotations.Attribute
import com.intellij.util.xmlb.annotations.Tag import com.intellij.util.xmlb.annotations.Tag
import com.intellij.util.xmlb.annotations.XCollection import com.intellij.util.xmlb.annotations.XCollection
import java.util.concurrent.atomic.AtomicBoolean
// [Version Update] 202+ class ExtensionBeanClass : BaseKeyedLazyInstance<VimExtension>() {
@Suppress("DEPRECATION")
class ExtensionBeanClass : AbstractExtensionPointBean() {
init {
println()
}
@Attribute("implementation") @Attribute("implementation")
var implementation: String? = null var implementation: String? = null
@@ -46,14 +40,7 @@ class ExtensionBeanClass : AbstractExtensionPointBean() {
@XCollection @XCollection
var aliases: List<Alias>? = null var aliases: List<Alias>? = null
var initialized = AtomicBoolean(false) override fun getImplementationClassName(): String? = implementation
val handler: VimExtension by lazy {
initialized.set(true)
this.instantiateClass<VimExtension>(
implementation ?: "", ApplicationManager.getApplication().picoContainer
)
}
} }
@Tag("alias") @Tag("alias")

View File

@@ -41,9 +41,7 @@ object VimExtensionRegistrar {
VimExtension.EP_NAME.extensions.forEach(this::registerExtension) VimExtension.EP_NAME.extensions.forEach(this::registerExtension)
// [VERSION UPDATE] 202+ VimExtension.EP_NAME.point.addExtensionPointListener(object : ExtensionPointListener<ExtensionBeanClass> {
@Suppress("DEPRECATION")
VimExtension.EP_NAME.getPoint(null).addExtensionPointListener(object : ExtensionPointListener<ExtensionBeanClass> {
override fun extensionAdded(extension: ExtensionBeanClass, pluginDescriptor: PluginDescriptor) { override fun extensionAdded(extension: ExtensionBeanClass, pluginDescriptor: PluginDescriptor) {
registerExtension(extension) registerExtension(extension)
} }
@@ -56,7 +54,7 @@ object VimExtensionRegistrar {
@Synchronized @Synchronized
private fun registerExtension(extensionBean: ExtensionBeanClass) { private fun registerExtension(extensionBean: ExtensionBeanClass) {
val name = extensionBean.name ?: extensionBean.handler.name val name = extensionBean.name ?: extensionBean.instance.name
if (name in registeredExtensions) return if (name in registeredExtensions) return
registeredExtensions.add(name) registeredExtensions.add(name)
@@ -64,10 +62,10 @@ object VimExtensionRegistrar {
val option = ToggleOption(name, name, false) val option = ToggleOption(name, name, false)
option.addOptionChangeListener { _, _ -> option.addOptionChangeListener { _, _ ->
if (isSet(name)) { if (isSet(name)) {
extensionBean.handler.init() extensionBean.instance.init()
logger.info("IdeaVim extension '$name' initialized") logger.info("IdeaVim extension '$name' initialized")
} else { } else {
extensionBean.handler.dispose() extensionBean.instance.dispose()
} }
} }
addOption(option) addOption(option)
@@ -75,13 +73,11 @@ object VimExtensionRegistrar {
@Synchronized @Synchronized
private fun unregisterExtension(extension: ExtensionBeanClass) { private fun unregisterExtension(extension: ExtensionBeanClass) {
val name = extension.name ?: extension.handler.name val name = extension.name ?: extension.instance.name
if (name !in registeredExtensions) return if (name !in registeredExtensions) return
registeredExtensions.remove(name) registeredExtensions.remove(name)
removeAliases(extension) removeAliases(extension)
if (extension.initialized.get()) { extension.instance.dispose()
extension.handler.dispose()
}
removeOption(name) removeOption(name)
remove(name) remove(name)
logger.info("IdeaVim extension '$name' disposed") logger.info("IdeaVim extension '$name' disposed")
@@ -95,7 +91,7 @@ object VimExtensionRegistrar {
private fun registerAliases(extension: ExtensionBeanClass) { private fun registerAliases(extension: ExtensionBeanClass) {
extension.aliases extension.aliases
?.mapNotNull { it.name } ?.mapNotNull { it.name }
?.forEach { alias -> extensionAliases[alias] = extension.name ?: extension.handler.name } ?.forEach { alias -> extensionAliases[alias] = extension.name ?: extension.instance.name }
} }
private fun removeAliases(extension: ExtensionBeanClass) { private fun removeAliases(extension: ExtensionBeanClass) {

View File

@@ -33,6 +33,7 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionHandler import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.group.MotionGroup import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.group.visual.vimSetSelection import com.maddyhome.idea.vim.group.visual.vimSetSelection
import com.maddyhome.idea.vim.helper.Direction
import com.maddyhome.idea.vim.helper.EditorHelper import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.SearchHelper.findWordUnderCursor import com.maddyhome.idea.vim.helper.SearchHelper.findWordUnderCursor
@@ -48,18 +49,23 @@ import java.util.*
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe // [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls @NonNls
private const val NEXT_WHOLE_OCCURRENCE = "<Plug>NextWholeOccurrence" private const val NEXT_WHOLE_OCCURRENCE = "<Plug>NextWholeOccurrence"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe // [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls @NonNls
private const val NEXT_OCCURRENCE = "<Plug>NextOccurrence" private const val NEXT_OCCURRENCE = "<Plug>NextOccurrence"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe // [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls @NonNls
private const val SKIP_OCCURRENCE = "<Plug>SkipOccurrence" private const val SKIP_OCCURRENCE = "<Plug>SkipOccurrence"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe // [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls @NonNls
private const val REMOVE_OCCURRENCE = "<Plug>RemoveOccurrence" private const val REMOVE_OCCURRENCE = "<Plug>RemoveOccurrence"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe // [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls @NonNls
private const val ALL_WHOLE_OCCURRENCES = "<Plug>AllWholeOccurrences" private const val ALL_WHOLE_OCCURRENCES = "<Plug>AllWholeOccurrences"
// [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe // [VERSION UPDATE] 203+ Annotation should be replaced with @NlsSafe
@NonNls @NonNls
private const val ALL_OCCURRENCES = "<Plug>AllOccurrences" private const val ALL_OCCURRENCES = "<Plug>AllOccurrences"
@@ -75,9 +81,21 @@ class VimMultipleCursorsExtension : VimExtension {
override fun init() { override fun init() {
putExtensionHandlerMapping(MappingMode.NXO, parseKeys(NEXT_WHOLE_OCCURRENCE), owner, NextOccurrenceHandler(), false) putExtensionHandlerMapping(MappingMode.NXO, parseKeys(NEXT_WHOLE_OCCURRENCE), owner, NextOccurrenceHandler(), false)
putExtensionHandlerMapping(MappingMode.NXO, parseKeys(NEXT_OCCURRENCE), owner, NextOccurrenceHandler(whole = false), false) putExtensionHandlerMapping(
MappingMode.NXO,
parseKeys(NEXT_OCCURRENCE),
owner,
NextOccurrenceHandler(whole = false),
false
)
putExtensionHandlerMapping(MappingMode.NXO, parseKeys(ALL_WHOLE_OCCURRENCES), owner, AllOccurrencesHandler(), false) putExtensionHandlerMapping(MappingMode.NXO, parseKeys(ALL_WHOLE_OCCURRENCES), owner, AllOccurrencesHandler(), false)
putExtensionHandlerMapping(MappingMode.NXO, parseKeys(ALL_OCCURRENCES), owner, AllOccurrencesHandler(whole = false), false ) putExtensionHandlerMapping(
MappingMode.NXO,
parseKeys(ALL_OCCURRENCES),
owner,
AllOccurrencesHandler(whole = false),
false
)
putExtensionHandlerMapping(MappingMode.X, parseKeys(SKIP_OCCURRENCE), owner, SkipOccurrenceHandler(), false) putExtensionHandlerMapping(MappingMode.X, parseKeys(SKIP_OCCURRENCE), owner, SkipOccurrenceHandler(), false)
putExtensionHandlerMapping(MappingMode.X, parseKeys(REMOVE_OCCURRENCE), owner, RemoveOccurrenceHandler(), false) putExtensionHandlerMapping(MappingMode.X, parseKeys(REMOVE_OCCURRENCE), owner, RemoveOccurrenceHandler(), false)
@@ -100,7 +118,8 @@ class VimMultipleCursorsExtension : VimExtension {
inner class NextOccurrenceHandler(val whole: Boolean = true) : WriteActionHandler() { inner class NextOccurrenceHandler(val whole: Boolean = true) : WriteActionHandler() {
override fun executeInWriteAction(editor: Editor, context: DataContext) { override fun executeInWriteAction(editor: Editor, context: DataContext) {
val caretModel = editor.caretModel val caretModel = editor.caretModel
val patternComparator = if (OptionsManager.ignorecase.isSet) String.CASE_INSENSITIVE_ORDER else Comparator(String::compareTo) val patternComparator =
if (OptionsManager.ignorecase.isSet) String.CASE_INSENSITIVE_ORDER else Comparator(String::compareTo)
if (!editor.inVisualMode) { if (!editor.inVisualMode) {
if (caretModel.caretCount > 1) return if (caretModel.caretCount > 1) return
@@ -138,10 +157,18 @@ class VimMultipleCursorsExtension : VimExtension {
val primaryCaret = editor.caretModel.primaryCaret val primaryCaret = editor.caretModel.primaryCaret
val nextOffset = VimPlugin.getSearch().searchNextFromOffset(editor, primaryCaret.offset + 1, 1) val nextOffset = VimPlugin.getSearch().searchNextFromOffset(editor, primaryCaret.offset + 1, 1)
val pattern = patterns.first() val pattern = patterns.first()
if (nextOffset == -1 || patternComparator.compare(EditorHelper.getText(editor, nextOffset, nextOffset + pattern.length), pattern) != 0) { if (nextOffset == -1 || patternComparator.compare(
EditorHelper.getText(
editor,
nextOffset,
nextOffset + pattern.length
), pattern
) != 0
) {
if (caretModel.caretCount > 1) return if (caretModel.caretCount > 1) return
val newNextOffset = VimPlugin.getSearch().search(editor, pattern, 1, EnumSet.of(CommandFlags.FLAG_SEARCH_FWD), false) val newNextOffset =
VimPlugin.getSearch().search(editor, pattern, 1, EnumSet.of(CommandFlags.FLAG_SEARCH_FWD), false)
if (newNextOffset != -1) { if (newNextOffset != -1) {
val caret = editor.caretModel.addCaret(editor.offsetToVisualPosition(newNextOffset)) ?: return val caret = editor.caretModel.addCaret(editor.offsetToVisualPosition(newNextOffset)) ?: return
@@ -172,7 +199,8 @@ class VimMultipleCursorsExtension : VimExtension {
val primaryCaret = caretModel.primaryCaret val primaryCaret = caretModel.primaryCaret
var nextOffset = if (editor.inVisualMode) { var nextOffset = if (editor.inVisualMode) {
val selectedText = primaryCaret.selectedText ?: return val selectedText = primaryCaret.selectedText ?: return
val nextOffset = VimPlugin.getSearch().search(editor, selectedText, 1, EnumSet.of(CommandFlags.FLAG_SEARCH_FWD), false) val nextOffset =
VimPlugin.getSearch().search(editor, selectedText, 1, EnumSet.of(CommandFlags.FLAG_SEARCH_FWD), false)
nextOffset nextOffset
} else { } else {
val range = findWordUnderCursor(editor, primaryCaret) ?: return val range = findWordUnderCursor(editor, primaryCaret) ?: return
@@ -242,7 +270,7 @@ class VimMultipleCursorsExtension : VimExtension {
val wordRange = VimPlugin.getMotion().getWordRange(editor, caret, 1, false, false) val wordRange = VimPlugin.getMotion().getWordRange(editor, caret, 1, false, false)
caret.vimSetSelection(wordRange.startOffset, wordRange.endOffsetInclusive, true) caret.vimSetSelection(wordRange.startOffset, wordRange.endOffsetInclusive, true)
val offset = VimPlugin.getSearch().searchWord(editor, caret, 1, whole, 1) val offset = VimPlugin.getSearch().searchWord(editor, caret, 1, whole, Direction.FORWARDS)
MotionGroup.moveCaret(editor, caret, range.endOffset - 1) MotionGroup.moveCaret(editor, caret, range.endOffset - 1)
return offset return offset

View File

@@ -1765,28 +1765,8 @@ public class ChangeGroup {
} }
public static void resetCaret(@NotNull Editor editor, boolean insert) { public static void resetCaret(@NotNull Editor editor, boolean insert) {
Document doc = editor.getDocument();
VirtualFile vf = FileDocumentManager.getInstance().getFile(doc);
if (vf != null) {
resetCaret(vf, editor.getProject(), insert);
}
else {
editor.getSettings().setBlockCursor(!insert); editor.getSettings().setBlockCursor(!insert);
} }
}
private static void resetCaret(@NotNull VirtualFile virtualFile, Project proj, boolean insert) {
logger.debug("Reset caret to a " + (insert ? "non-block" : "block") + " shape");
Document doc = FileDocumentManager.getInstance().getDocument(virtualFile);
if (doc == null) return; // Must be no text editor (such as image)
Editor[] editors = EditorFactory.getInstance().getEditors(doc, proj);
if (logger.isDebugEnabled()) {
logger.debug("There are " + editors.length + " editors for virtual file " + virtualFile.getName());
}
for (Editor editor : editors) {
editor.getSettings().setBlockCursor(!insert);
}
}
/** /**
* Sort range of text with a given comparator * Sort range of text with a given comparator

View File

@@ -27,9 +27,11 @@ import com.intellij.openapi.editor.*;
import com.intellij.openapi.editor.event.CaretEvent; import com.intellij.openapi.editor.event.CaretEvent;
import com.intellij.openapi.editor.event.CaretListener; import com.intellij.openapi.editor.event.CaretListener;
import com.intellij.openapi.editor.ex.EditorGutterComponentEx; import com.intellij.openapi.editor.ex.EditorGutterComponentEx;
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable;
import com.intellij.openapi.project.Project; import com.intellij.openapi.project.Project;
import com.maddyhome.idea.vim.KeyHandler; import com.maddyhome.idea.vim.KeyHandler;
import com.maddyhome.idea.vim.VimPlugin; import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.group.visual.VisualGroupKt;
import com.maddyhome.idea.vim.helper.*; import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.option.OptionChangeListener; import com.maddyhome.idea.vim.option.OptionChangeListener;
import com.maddyhome.idea.vim.option.OptionsManager; import com.maddyhome.idea.vim.option.OptionsManager;
@@ -204,8 +206,8 @@ public class EditorGroup implements PersistentStateComponent<Element> {
} }
} }
public boolean isBarCursor() { public boolean isBarCursorSettings() {
return !isBlockCursor; return !EditorSettingsExternalizable.getInstance().isBlockCursor();
} }
public void editorCreated(@NotNull Editor editor) { public void editorCreated(@NotNull Editor editor) {
@@ -222,7 +224,7 @@ public class EditorGroup implements PersistentStateComponent<Element> {
VimPlugin.getChange().insertBeforeCursor(editor, new EditorDataContext(editor, null)); VimPlugin.getChange().insertBeforeCursor(editor, new EditorDataContext(editor, null));
KeyHandler.getInstance().reset(editor); KeyHandler.getInstance().reset(editor);
} }
editor.getSettings().setBlockCursor(!CommandStateHelper.inInsertMode(editor) || isBlockCursor); VisualGroupKt.resetShape(CommandStateHelper.getMode(editor), editor);
editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE); editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
} }

View File

@@ -307,17 +307,17 @@ public class KeyGroup implements PersistentStateComponent<Element> {
public void registerCommandAction(@NotNull ActionBeanClass actionHolder) { public void registerCommandAction(@NotNull ActionBeanClass actionHolder) {
if (!VimPlugin.getPluginId().equals(actionHolder.getPluginId())) { if (!VimPlugin.getPluginId().equals(actionHolder.getPluginDescriptor().getPluginId())) {
logger.error("IdeaVim doesn't accept contributions to `vimActions` extension points. " + logger.error("IdeaVim doesn't accept contributions to `vimActions` extension points. " +
"Please create a plugin using `VimExtension`. " + "Please create a plugin using `VimExtension`. " +
"Plugin to blame: " + "Plugin to blame: " +
actionHolder.getPluginId()); actionHolder.getPluginDescriptor().getPluginId());
return; return;
} }
Set<List<KeyStroke>> actionKeys = actionHolder.getParsedKeys(); Set<List<KeyStroke>> actionKeys = actionHolder.getParsedKeys();
if (actionKeys == null) { if (actionKeys == null) {
final EditorActionHandlerBase action = actionHolder.getAction(); final EditorActionHandlerBase action = actionHolder.getInstance();
if (action instanceof ComplicatedKeysAction) { if (action instanceof ComplicatedKeysAction) {
actionKeys = ((ComplicatedKeysAction)action).getKeyStrokesSet(); actionKeys = ((ComplicatedKeysAction)action).getKeyStrokesSet();
} }
@@ -337,7 +337,7 @@ public class KeyGroup implements PersistentStateComponent<Element> {
prefixes = new HashMap<>(); prefixes = new HashMap<>();
} }
for (List<KeyStroke> keys : actionKeys) { for (List<KeyStroke> keys : actionKeys) {
checkCommand(actionModes, actionHolder.getAction(), keys); checkCommand(actionModes, actionHolder.getInstance(), keys);
} }
} }

View File

@@ -41,6 +41,7 @@ import com.maddyhome.idea.vim.group.visual.VisualGroupKt;
import com.maddyhome.idea.vim.handler.MotionActionHandler; import com.maddyhome.idea.vim.handler.MotionActionHandler;
import com.maddyhome.idea.vim.handler.TextObjectActionHandler; import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
import com.maddyhome.idea.vim.helper.*; import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.listener.IdeaSpecifics;
import com.maddyhome.idea.vim.option.NumberOption; import com.maddyhome.idea.vim.option.NumberOption;
import com.maddyhome.idea.vim.option.OptionChangeListener; import com.maddyhome.idea.vim.option.OptionChangeListener;
import com.maddyhome.idea.vim.option.OptionsManager; import com.maddyhome.idea.vim.option.OptionsManager;
@@ -318,6 +319,8 @@ public class MotionGroup {
else { else {
ModeHelper.exitVisualMode(editor); ModeHelper.exitVisualMode(editor);
} }
IdeaSpecifics.AppCodeTemplates.onMovement(editor, caret, oldOffset < offset);
} }
private @Nullable Editor selectEditor(@NotNull Editor editor, @NotNull Mark mark) { private @Nullable Editor selectEditor(@NotNull Editor editor, @NotNull Mark mark) {

View File

@@ -18,7 +18,6 @@
package com.maddyhome.idea.vim.group; package com.maddyhome.idea.vim.group;
import com.google.common.collect.ImmutableList;
import com.intellij.codeInsight.editorActions.CopyPastePostProcessor; import com.intellij.codeInsight.editorActions.CopyPastePostProcessor;
import com.intellij.codeInsight.editorActions.CopyPastePreProcessor; import com.intellij.codeInsight.editorActions.CopyPastePreProcessor;
import com.intellij.codeInsight.editorActions.TextBlockTransferable; import com.intellij.codeInsight.editorActions.TextBlockTransferable;
@@ -81,18 +80,33 @@ import java.util.stream.Collectors;
@Storage(value = "$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED) @Storage(value = "$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)
}) })
public class RegisterGroup implements PersistentStateComponent<Element> { public class RegisterGroup implements PersistentStateComponent<Element> {
private static final @NonNls String WRITABLE_REGISTERS = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-*+_/\""; public static final char UNNAMED_REGISTER = '"';
private static final String READONLY_REGISTERS = ":.%#=/"; public static final char LAST_SEARCH_REGISTER = '/'; // IdeaVim does not supporting writing to this register
private static final @NonNls String RECORDABLE_REGISTER = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"; public static final char LAST_COMMAND_REGISTER = ':';
private static final String PLAYBACK_REGISTER = RECORDABLE_REGISTER + "\".*+"; private static final char LAST_INSERTED_TEXT_REGISTER = '.';
public static final char SMALL_DELETION_REGISTER = '-';
private static final char BLACK_HOLE_REGISTER = '_';
private static final char ALTERNATE_BUFFER_REGISTER = '#'; // Not supported
private static final char EXPRESSION_BUFFER_REGISTER = '='; // Not supported
private static final char CURRENT_FILENAME_REGISTER = '%'; // Not supported
private static final @NonNls String CLIPBOARD_REGISTERS = "*+";
private static final @NonNls String NUMBERED_REGISTERS = "0123456789";
private static final @NonNls String NAMED_REGISTERS = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
private static final @NonNls String WRITABLE_REGISTERS = NUMBERED_REGISTERS + NAMED_REGISTERS + CLIPBOARD_REGISTERS
+ SMALL_DELETION_REGISTER + BLACK_HOLE_REGISTER + UNNAMED_REGISTER + LAST_SEARCH_REGISTER;
private static final String READONLY_REGISTERS = ""
+ CURRENT_FILENAME_REGISTER + LAST_COMMAND_REGISTER + LAST_INSERTED_TEXT_REGISTER + ALTERNATE_BUFFER_REGISTER
+ EXPRESSION_BUFFER_REGISTER; // Expression buffer is not actually readonly
private static final @NonNls String RECORDABLE_REGISTERS = NUMBERED_REGISTERS + NAMED_REGISTERS;
private static final String PLAYBACK_REGISTERS = RECORDABLE_REGISTERS + UNNAMED_REGISTER + CLIPBOARD_REGISTERS + LAST_INSERTED_TEXT_REGISTER;
private static final String VALID_REGISTERS = WRITABLE_REGISTERS + READONLY_REGISTERS; private static final String VALID_REGISTERS = WRITABLE_REGISTERS + READONLY_REGISTERS;
private static final List<Character> CLIPBOARD_REGISTERS = ImmutableList.of('*', '+');
private static final Logger logger = Logger.getInstance(RegisterGroup.class.getName()); private static final Logger logger = Logger.getInstance(RegisterGroup.class.getName());
public static final char UNNAMED_REGISTER = '"'; private final @NotNull HashMap<Character, Register> registers = new HashMap<>();
private char defaultRegister = UNNAMED_REGISTER; private char defaultRegister = UNNAMED_REGISTER;
private char lastRegister = defaultRegister; private char lastRegister = defaultRegister;
private final @NotNull HashMap<Character, Register> registers = new HashMap<>();
private char recordRegister = 0; private char recordRegister = 0;
private @Nullable List<KeyStroke> recordList = null; private @Nullable List<KeyStroke> recordList = null;
@@ -173,10 +187,35 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
return false; return false;
} }
public boolean storeTextInternal(@NotNull Editor editor, @NotNull TextRange range, @NotNull String text, /**
* Stores text, character wise, in the given special register
*
* <p>This method is intended to support writing to registers when the text cannot be yanked from an editor. This is
* expected to only be used to update the search and command registers. It will not update named registers.</p>
*
* <p>While this method allows setting the unnamed register, this should only be done from tests, and only when it's
* not possible to yank or cut from the fixture editor. This method will skip additional text processing, and won't
* update other registers such as the small delete register or reorder the numbered registers. It is much more
* preferable to yank from the fixture editor.</p>
*
* @param register The register to use for storing the text. Cannot be a normal text register
* @param text The text to store, without further processing
* @return True if the text is stored, false if the passed register is not supported
*/
public boolean storeTextSpecial(char register, @NotNull String text) {
if (READONLY_REGISTERS.indexOf(register) == -1 && register != LAST_SEARCH_REGISTER
&& register != UNNAMED_REGISTER) {
return false;
}
registers.put(register, new Register(register, SelectionType.CHARACTER_WISE, text, new ArrayList<>()));
if (logger.isDebugEnabled()) logger.debug("register '" + register + "' contains: \"" + text + "\"");
return true;
}
private boolean storeTextInternal(@NotNull Editor editor, @NotNull TextRange range, @NotNull String text,
@NotNull SelectionType type, char register, boolean isDelete) { @NotNull SelectionType type, char register, boolean isDelete) {
// Null register doesn't get saved // Null register doesn't get saved, but acts like it was
if (lastRegister == '_') return true; if (lastRegister == BLACK_HOLE_REGISTER) return true;
int start = range.getStartOffset(); int start = range.getStartOffset();
int end = range.getEndOffset(); int end = range.getEndOffset();
@@ -219,7 +258,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
if (logger.isDebugEnabled()) logger.debug("register '" + register + "' contains: \"" + processedText + "\""); if (logger.isDebugEnabled()) logger.debug("register '" + register + "' contains: \"" + processedText + "\"");
} }
if (CLIPBOARD_REGISTERS.contains(register)) { if (CLIPBOARD_REGISTERS.indexOf(register) >= 0) {
ClipboardHandler.setClipboardText(processedText, new ArrayList<>(transferableData), text); ClipboardHandler.setClipboardText(processedText, new ArrayList<>(transferableData), text);
} }
@@ -248,7 +287,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
// Deletes smaller than one line and without specified register go the the "-" register // Deletes smaller than one line and without specified register go the the "-" register
if (smallInlineDeletion && register == defaultRegister) { if (smallInlineDeletion && register == defaultRegister) {
registers.put('-', new Register('-', type, processedText, new ArrayList<>(transferableData))); registers.put(SMALL_DELETION_REGISTER, new Register(SMALL_DELETION_REGISTER, type, processedText, new ArrayList<>(transferableData)));
} }
} }
// Yanks also go to register 0 if the default register was used // Yanks also go to register 0 if the default register was used
@@ -338,7 +377,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
} }
public @Nullable Register getPlaybackRegister(char r) { public @Nullable Register getPlaybackRegister(char r) {
if (PLAYBACK_REGISTER.indexOf(r) != 0) { if (PLAYBACK_REGISTERS.indexOf(r) != 0) {
return getRegister(r); return getRegister(r);
} }
else { else {
@@ -351,7 +390,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
if (Character.isUpperCase(r)) { if (Character.isUpperCase(r)) {
r = Character.toLowerCase(r); r = Character.toLowerCase(r);
} }
return CLIPBOARD_REGISTERS.contains(r) ? refreshClipboardRegister(r) : registers.get(r); return CLIPBOARD_REGISTERS.indexOf(r) >= 0 ? refreshClipboardRegister(r) : registers.get(r);
} }
public void saveRegister(char r, Register register) { public void saveRegister(char r, Register register) {
@@ -359,7 +398,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
if (Character.isUpperCase(r)) { if (Character.isUpperCase(r)) {
r = Character.toLowerCase(r); r = Character.toLowerCase(r);
} }
if (CLIPBOARD_REGISTERS.contains(r)) { if (CLIPBOARD_REGISTERS.indexOf(r) >= 0) {
ClipboardHandler.setClipboardText(register.getText(), new ArrayList<>(register.getTransferableData()), register.getRawText()); ClipboardHandler.setClipboardText(register.getText(), new ArrayList<>(register.getTransferableData()), register.getRawText());
} }
registers.put(r, register); registers.put(r, register);
@@ -383,7 +422,8 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
public @NotNull List<Register> getRegisters() { public @NotNull List<Register> getRegisters() {
final List<Register> res = new ArrayList<>(registers.values()); final List<Register> res = new ArrayList<>(registers.values());
for (Character r : CLIPBOARD_REGISTERS) { for (int i = 0; i < CLIPBOARD_REGISTERS.length(); i++) {
final char r = CLIPBOARD_REGISTERS.charAt(i);
final Register register = refreshClipboardRegister(r); final Register register = refreshClipboardRegister(r);
if (register != null) { if (register != null) {
res.add(register); res.add(register);
@@ -394,7 +434,7 @@ public class RegisterGroup implements PersistentStateComponent<Element> {
} }
public boolean startRecording(Editor editor, char register) { public boolean startRecording(Editor editor, char register) {
if (RECORDABLE_REGISTER.indexOf(register) != -1) { if (RECORDABLE_REGISTERS.indexOf(register) != -1) {
CommandState.getInstance(editor).setRecording(true); CommandState.getInstance(editor).setRecording(true);
recordRegister = register; recordRegister = register;
recordList = new ArrayList<>(); recordList = new ArrayList<>();

File diff suppressed because it is too large Load Diff

View File

@@ -163,7 +163,7 @@ fun updateCaretState(editor: Editor) {
fun CommandState.Mode.resetShape(editor: Editor) = when (this) { fun CommandState.Mode.resetShape(editor: Editor) = when (this) {
CommandState.Mode.COMMAND, CommandState.Mode.VISUAL, CommandState.Mode.REPLACE -> ChangeGroup.resetCaret(editor, false) CommandState.Mode.COMMAND, CommandState.Mode.VISUAL, CommandState.Mode.REPLACE -> ChangeGroup.resetCaret(editor, false)
CommandState.Mode.SELECT, CommandState.Mode.INSERT -> ChangeGroup.resetCaret(editor, VimPlugin.getEditor().isBarCursor) CommandState.Mode.SELECT, CommandState.Mode.INSERT -> ChangeGroup.resetCaret(editor, VimPlugin.getEditor().isBarCursorSettings)
CommandState.Mode.CMD_LINE, CommandState.Mode.OP_PENDING -> Unit CommandState.Mode.CMD_LINE, CommandState.Mode.OP_PENDING -> Unit
} }

View File

@@ -18,8 +18,7 @@
package com.maddyhome.idea.vim.handler package com.maddyhome.idea.vim.handler
import com.intellij.openapi.application.ApplicationManager import com.intellij.serviceContainer.BaseKeyedLazyInstance
import com.intellij.openapi.extensions.AbstractExtensionPointBean
import com.intellij.util.SmartList import com.intellij.util.SmartList
import com.intellij.util.xmlb.annotations.Attribute import com.intellij.util.xmlb.annotations.Attribute
import com.maddyhome.idea.vim.command.MappingMode import com.maddyhome.idea.vim.command.MappingMode
@@ -47,9 +46,7 @@ import javax.swing.KeyStroke
* The reason is startup performance. Using the extension points you don't even have to load classes of actions. * The reason is startup performance. Using the extension points you don't even have to load classes of actions.
* So, all actions are loaded on demand, including classes in classloader. * So, all actions are loaded on demand, including classes in classloader.
*/ */
// [VERSION UPDATE] 202+ class ActionBeanClass : BaseKeyedLazyInstance<EditorActionHandlerBase>() {
@Suppress("DEPRECATION")
class ActionBeanClass : AbstractExtensionPointBean() {
@Attribute("implementation") @Attribute("implementation")
var implementation: String? = null var implementation: String? = null
@@ -61,17 +58,14 @@ class ActionBeanClass : AbstractExtensionPointBean() {
val actionId: String get() = implementation?.let { EditorActionHandlerBase.getActionId(it) } ?: "" val actionId: String get() = implementation?.let { EditorActionHandlerBase.getActionId(it) } ?: ""
val action: EditorActionHandlerBase by lazy {
this.instantiateClass<EditorActionHandlerBase>(
implementation ?: "", ApplicationManager.getApplication().picoContainer)
}
fun getParsedKeys(): Set<List<KeyStroke>>? { fun getParsedKeys(): Set<List<KeyStroke>>? {
val myKeys = keys ?: return null val myKeys = keys ?: return null
val escapedKeys = myKeys.splitByComma() val escapedKeys = myKeys.splitByComma()
return EditorActionHandlerBase.parseKeysSet(escapedKeys) return EditorActionHandlerBase.parseKeysSet(escapedKeys)
} }
override fun getImplementationClassName(): String? = implementation
fun getParsedModes(): Set<MappingMode>? { fun getParsedModes(): Set<MappingMode>? {
val myModes = modes ?: return null val myModes = modes ?: return null

View File

@@ -21,6 +21,7 @@
package com.maddyhome.idea.vim.helper package com.maddyhome.idea.vim.helper
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.option.OptionsManager import com.maddyhome.idea.vim.option.OptionsManager
@@ -40,12 +41,23 @@ val CommandState.Mode.isEndAllowedIgnoringOnemore: Boolean
CommandState.Mode.COMMAND, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.OP_PENDING -> false CommandState.Mode.COMMAND, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.OP_PENDING -> false
} }
val CommandState.Mode.isBlockCaret /**
* Should this caret behave like the block caret?
* Keep in mind that in insert mode the caret can have a block shape, but it doesn't behave like the block one
* If you're looking for a shape, check [isBlockCaretShape]
*/
val CommandState.Mode.isBlockCaretBehaviour
get() = when (this) { get() = when (this) {
CommandState.Mode.VISUAL, CommandState.Mode.COMMAND, CommandState.Mode.OP_PENDING -> true CommandState.Mode.VISUAL, CommandState.Mode.COMMAND, CommandState.Mode.OP_PENDING -> true
CommandState.Mode.INSERT, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.SELECT -> false CommandState.Mode.INSERT, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.SELECT -> false
} }
val CommandState.Mode.isBlockCaretShape
get() = when (this) {
CommandState.Mode.VISUAL, CommandState.Mode.COMMAND, CommandState.Mode.OP_PENDING -> true
CommandState.Mode.INSERT, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.SELECT -> !VimPlugin.getEditor().isBarCursorSettings
}
val CommandState.Mode.hasVisualSelection val CommandState.Mode.hasVisualSelection
get() = when (this) { get() = when (this) {
CommandState.Mode.VISUAL, CommandState.Mode.SELECT -> true CommandState.Mode.VISUAL, CommandState.Mode.SELECT -> true

View File

@@ -20,7 +20,7 @@
package com.maddyhome.idea.vim.helper package com.maddyhome.idea.vim.helper
import com.intellij.openapi.diagnostic.logger import com.intellij.codeWithMe.ClientId
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.util.EditorUtil import com.intellij.openapi.editor.ex.util.EditorUtil
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
@@ -29,7 +29,6 @@ import com.maddyhome.idea.vim.option.OptionsManager
import java.awt.Component import java.awt.Component
import javax.swing.JComponent import javax.swing.JComponent
import javax.swing.JTable import javax.swing.JTable
import kotlin.system.measureTimeMillis
val Editor.fileSize: Int val Editor.fileSize: Int
get() = document.textLength get() = document.textLength
@@ -40,31 +39,14 @@ val Editor.fileSize: Int
*/ */
val Editor.isIdeaVimDisabledHere: Boolean val Editor.isIdeaVimDisabledHere: Boolean
get() { get() {
var res = true return disabledInDialog
val start = System.currentTimeMillis() || (!ClientId.isCurrentlyUnderLocalId) // CWM-927
val times = mutableListOf<Pair<Long, String>>() || (!OptionsManager.ideavimsupport.contains("singleline") && isDatabaseCell())
val timeForCalculation = measureTimeMillis { || (!OptionsManager.ideavimsupport.contains("singleline") && isOneLineMode)
res = (disabledInDialog.apply { times += System.currentTimeMillis() to "Disabled in dialog" }
|| (!OptionsManager.ideavimsupport.contains("singleline")
.apply { times += System.currentTimeMillis() to "first single line check" }
&& isDatabaseCell(times).apply { times += System.currentTimeMillis() to "is db cell" })
|| (!OptionsManager.ideavimsupport.contains("singleline")
.apply { times += System.currentTimeMillis() to "second single line check" }
&& isOneLineMode.apply { times += System.currentTimeMillis() to "is one line" })
)
}
if (timeForCalculation > 10) {
val timeDiffs = times.map { it.second + ": " + (it.first - start) }
val message = "Time for calculation of 'isIdeaVimDisabledHere' took $timeForCalculation ms. Time diff: $timeDiffs"
logger<Editor>().error(message)
}
return res
} }
private fun Editor.isDatabaseCell(times: MutableList<Pair<Long, String>>): Boolean { private fun Editor.isDatabaseCell(): Boolean {
return isTableCellEditor(this.component, times) return isTableCellEditor(this.component)
} }
private val Editor.disabledInDialog: Boolean private val Editor.disabledInDialog: Boolean
@@ -81,15 +63,10 @@ fun Editor.isPrimaryEditor(): Boolean {
} }
// Optimized clone of com.intellij.ide.ui.laf.darcula.DarculaUIUtil.isTableCellEditor // Optimized clone of com.intellij.ide.ui.laf.darcula.DarculaUIUtil.isTableCellEditor
private fun isTableCellEditor(c: Component, times: MutableList<Pair<Long, String>>): Boolean { private fun isTableCellEditor(c: Component): Boolean {
return (java.lang.Boolean.TRUE == (c as JComponent).getClientProperty("JComboBox.isTableCellEditor")) return (java.lang.Boolean.TRUE == (c as JComponent).getClientProperty("JComboBox.isTableCellEditor")) ||
.apply { times += System.currentTimeMillis() to "is property tru" } || (findParentByCondition(c) { it is JTable } != null) &&
(findParentByCondition(c) { it is JTable } != null)
.apply { times += System.currentTimeMillis() to "is not null" } &&
(findParentByCondition(c) { it is JBTableRowEditor } == null) (findParentByCondition(c) { it is JBTableRowEditor } == null)
.apply { times += System.currentTimeMillis() to "is null" }
} }
private const val PARENT_BY_CONDITION_DEPTH = 10 private const val PARENT_BY_CONDITION_DEPTH = 10

View File

@@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.helper; package com.maddyhome.idea.vim.helper;
import com.google.common.collect.Lists;
import com.intellij.lang.CodeDocumentationAwareCommenter; import com.intellij.lang.CodeDocumentationAwareCommenter;
import com.intellij.lang.Commenter; import com.intellij.lang.Commenter;
import com.intellij.lang.Language; import com.intellij.lang.Language;
@@ -29,10 +30,14 @@ import com.intellij.psi.PsiComment;
import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil; import com.intellij.psi.util.PsiTreeUtil;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.CommandState; import com.maddyhome.idea.vim.command.CommandState;
import com.maddyhome.idea.vim.common.CharacterPosition;
import com.maddyhome.idea.vim.common.TextRange; import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.option.ListOption; import com.maddyhome.idea.vim.option.ListOption;
import com.maddyhome.idea.vim.option.OptionsManager; import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.regexp.CharPointer;
import com.maddyhome.idea.vim.regexp.RegExp;
import kotlin.Pair; import kotlin.Pair;
import org.jetbrains.annotations.Contract; import org.jetbrains.annotations.Contract;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
@@ -44,11 +49,357 @@ import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import static com.maddyhome.idea.vim.helper.SearchHelperKtKt.checkInString; import static com.maddyhome.idea.vim.helper.SearchHelperKtKt.checkInString;
import static com.maddyhome.idea.vim.helper.SearchHelperKtKt.shouldIgnoreCase;
/** /**
* Helper methods for searching text * Helper methods for searching text
*/ */
public class SearchHelper { public class SearchHelper {
/**
* Find text matching the given pattern.
*
* @param editor The editor to search in
* @param pattern The pattern to search for
* @param startOffset The offset to start searching from
* @param count Find the nth next occurrence of the pattern. Must be 1 or greater.
* @param searchOptions A set of options, such as direction and wrap
* @return A TextRange representing the result, or null
*/
@Nullable
public static TextRange findPattern(@NotNull Editor editor,
@Nullable String pattern,
int startOffset,
int count,
EnumSet<SearchOptions> searchOptions) {
if (pattern == null || pattern.length() == 0) {
logger.warn("Pattern is null or empty. Cannot perform search");
return null;
}
Direction dir = searchOptions.contains(SearchOptions.BACKWARDS) ? Direction.BACKWARDS : Direction.FORWARDS;
//RE sp;
RegExp sp;
RegExp.regmmatch_T regmatch = new RegExp.regmmatch_T();
regmatch.rmm_ic = shouldIgnoreCase(pattern, searchOptions.contains(SearchOptions.IGNORE_SMARTCASE));
sp = new RegExp();
regmatch.regprog = sp.vim_regcomp(pattern, 1);
if (regmatch.regprog == null) {
if (logger.isDebugEnabled()) logger.debug("bad pattern: " + pattern);
return null;
}
/*
int extra_col = 1;
int startcol = -1;
boolean found = false;
boolean match_ok = true;
LogicalPosition pos = editor.offsetToLogicalPosition(startOffset);
LogicalPosition endpos = null;
//REMatch match = null;
*/
CharacterPosition lpos = CharacterPosition.Companion.fromOffset(editor, startOffset);
RegExp.lpos_T pos = new RegExp.lpos_T();
pos.lnum = lpos.line;
pos.col = lpos.column;
int found;
int lnum; /* no init to shut up Apollo cc */
//RegExp.regmmatch_T regmatch;
CharPointer ptr;
int matchcol;
RegExp.lpos_T matchpos;
RegExp.lpos_T endpos = new RegExp.lpos_T();
int loop;
RegExp.lpos_T start_pos;
boolean at_first_line;
int extra_col = dir == Direction.FORWARDS ? 1 : 0;
boolean match_ok;
long nmatched;
//int submatch = 0;
boolean first_match = true;
int lineCount = EditorHelper.getLineCount(editor);
int startLine = 0;
int endLine = lineCount;
do /* loop for count */ {
start_pos = new RegExp.lpos_T(pos); /* remember start pos for detecting no match */
found = 0; /* default: not found */
at_first_line = true; /* default: start in first line */
if (pos.lnum == -1) /* correct lnum for when starting in line 0 */ {
pos.lnum = 0;
pos.col = 0;
at_first_line = false; /* not in first line now */
}
/*
* Start searching in current line, unless searching backwards and
* we're in column 0.
*/
if (dir == Direction.BACKWARDS && start_pos.col == 0) {
lnum = pos.lnum - 1;
at_first_line = false;
}
else {
lnum = pos.lnum;
}
int lcount = EditorHelper.getLineCount(editor);
for (loop = 0; loop <= 1; ++loop) /* loop twice if 'wrapscan' set */ {
if (!searchOptions.contains(SearchOptions.WHOLE_FILE)) {
startLine = lnum;
endLine = lnum + 1;
}
for (; lnum >= startLine && lnum < endLine; lnum += dir.toInt(), at_first_line = false) {
/*
* Look for a match somewhere in the line.
*/
nmatched = sp.vim_regexec_multi(regmatch, 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]);
endpos = new RegExp.lpos_T(regmatch.endpos[0]);
ptr = new CharPointer(EditorHelper.getLineBuffer(editor, lnum + matchpos.lnum));
/*
* Forward search in the first line: match should be after
* the start position. If not, continue at the end of the
* match (this is vi compatible) or on the next char.
*/
if (dir == Direction.FORWARDS && at_first_line) {
match_ok = true;
/*
* When match lands on a NUL the cursor will be put
* one back afterwards, compare with that position,
* otherwise "/$" will get stuck on end of line.
*/
while (matchpos.lnum == 0
&& (searchOptions.contains(SearchOptions.WANT_ENDPOS) && first_match
? (nmatched == 1 && endpos.col - 1 < start_pos.col + extra_col)
: (matchpos.col - (ptr.charAt(matchpos.col) == '\u0000' ? 1 : 0) < start_pos.col + extra_col))) {
if (nmatched > 1) {
/* end is in next line, thus no match in
* this line */
match_ok = false;
break;
}
matchcol = endpos.col;
/* for empty match: advance one char */
if (matchcol == matchpos.col && ptr.charAt(matchcol) != '\u0000') {
++matchcol;
}
if (ptr.charAt(matchcol) == '\u0000' ||
(nmatched = sp.vim_regexec_multi(regmatch, editor, lcount, lnum, matchcol)) == 0) {
match_ok = false;
break;
}
matchpos = new RegExp.lpos_T(regmatch.startpos[0]);
endpos = new RegExp.lpos_T(regmatch.endpos[0]);
/* Need to get the line pointer again, a
* multi-line search may have made it invalid. */
ptr = new CharPointer(EditorHelper.getLineBuffer(editor, lnum));
}
if (!match_ok) {
continue;
}
}
if (dir == Direction.BACKWARDS) {
/*
* Now, if there are multiple matches on this line,
* we have to get the last one. Or the last one before
* the cursor, if we're on that line.
* When putting the new cursor at the end, compare
* relative to the end of the match.
*/
match_ok = false;
for (;;) {
if (loop != 0 ||
(searchOptions.contains(SearchOptions.WANT_ENDPOS)
? (lnum + regmatch.endpos[0].lnum < start_pos.lnum || (lnum + regmatch.endpos[0].lnum == start_pos.lnum && regmatch.endpos[0].col - 1 < start_pos.col + extra_col))
: (lnum + regmatch.startpos[0].lnum < start_pos.lnum || (lnum + regmatch.startpos[0].lnum == start_pos.lnum && regmatch.startpos[0].col < start_pos.col + extra_col)))) {
/* Remember this position, we use it if it's
* the last match in the line. */
match_ok = true;
matchpos = new RegExp.lpos_T(regmatch.startpos[0]);
endpos = new RegExp.lpos_T(regmatch.endpos[0]);
}
else {
break;
}
/*
* We found a valid match, now check if there is
* another one after it.
* If vi-compatible searching, continue at the end
* of the match, otherwise continue one position
* forward.
*/
if (nmatched > 1) {
break;
}
matchcol = endpos.col;
/* for empty match: advance one char */
if (matchcol == matchpos.col && ptr.charAt(matchcol) != '\u0000') {
++matchcol;
}
if (ptr.charAt(matchcol) == '\u0000' ||
(nmatched = sp.vim_regexec_multi(regmatch, editor, lcount, lnum + matchpos.lnum, matchcol)) == 0) {
break;
}
/* Need to get the line pointer again, a
* multi-line search may have made it invalid. */
ptr = new CharPointer(EditorHelper.getLineBuffer(editor, lnum + matchpos.lnum));
}
/*
* If there is only a match after the cursor, skip
* this match.
*/
if (!match_ok) {
continue;
}
}
pos.lnum = lnum + matchpos.lnum;
pos.col = matchpos.col;
endpos.lnum = lnum + endpos.lnum;
found = 1;
first_match = false;
/* Set variables used for 'incsearch' highlighting. */
//search_match_lines = endpos.lnum - (lnum - first_lnum);
//search_match_endcol = endpos.col;
break;
}
//line_breakcheck(); /* stop if ctrl-C typed */
//if (got_int)
// break;
if (loop != 0 && lnum == start_pos.lnum) {
break; /* if second loop, stop where started */
}
}
at_first_line = false;
/*
* stop the search if wrapscan isn't set, after an interrupt and
* after a match
*/
if (!searchOptions.contains(SearchOptions.WRAP) || found != 0) {
break;
}
/*
* If 'wrapscan' is set we continue at the other end of the file.
* If 'shortmess' does not contain 's', we give a message.
* This message is also remembered in keep_msg for when the screen
* is redrawn. The keep_msg is cleared whenever another message is
* written.
*/
if (dir == Direction.BACKWARDS) /* start second loop at the other end */ {
lnum = lineCount - 1;
//if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
// give_warning((char_u *)_(top_bot_msg), TRUE);
}
else {
lnum = 0;
//if (!shortmess(SHM_SEARCH) && (options & SEARCH_MSG))
// give_warning((char_u *)_(bot_top_msg), TRUE);
}
}
//if (got_int || called_emsg || break_loop)
// break;
}
while (--count > 0 && found != 0); /* stop after count matches or no match */
if (found == 0) /* did not find it */ {
//if ((options & SEARCH_MSG) == SEARCH_MSG)
if (searchOptions.contains(SearchOptions.SHOW_MESSAGES)) {
if (searchOptions.contains(SearchOptions.WRAP)) {
VimPlugin.showMessage(MessageHelper.message(Msg.e_patnotf2, pattern));
}
else if (lnum <= 0) {
VimPlugin.showMessage(MessageHelper.message(Msg.E384, pattern));
}
else {
VimPlugin.showMessage(MessageHelper.message(Msg.E385, pattern));
}
}
return null;
}
//return new TextRange(editor.logicalPositionToOffset(new LogicalPosition(pos.lnum, pos.col)),
// editor.logicalPositionToOffset(new LogicalPosition(endpos.lnum, endpos.col)));
//return new TextRange(editor.logicalPositionToOffset(new LogicalPosition(pos.lnum, 0)) + pos.col,
// editor.logicalPositionToOffset(new LogicalPosition(endpos.lnum, 0)) + endpos.col);
return new TextRange(new CharacterPosition(pos.lnum, pos.col).toOffset(editor),
new CharacterPosition(endpos.lnum, endpos.col).toOffset(editor));
}
/**
* Find all occurrences of the pattern.
*
* @param editor The editor to search in
* @param pattern The pattern to search for
* @param startLine The start line of the range to search for, or -1 for the whole document
* @param endLine The end line of the range to search for, or -1 for the whole document
* @param ignoreCase Case sensitive or insensitive searching
* @return A list of TextRange objects representing the results
*/
public static @NotNull List<TextRange> findAll(@NotNull Editor editor,
@NotNull String pattern,
int startLine,
int endLine,
boolean ignoreCase) {
final List<TextRange> results = Lists.newArrayList();
final int lineCount = EditorHelper.getLineCount(editor);
final int actualEndLine = endLine == -1 ? lineCount : endLine;
final RegExp.regmmatch_T regMatch = new RegExp.regmmatch_T();
final RegExp regExp = new RegExp();
regMatch.regprog = regExp.vim_regcomp(pattern, 1);
if (regMatch.regprog == null) {
return results;
}
regMatch.rmm_ic = ignoreCase;
int col = 0;
for (int line = startLine; line <= actualEndLine; ) {
int matchedLines = regExp.vim_regexec_multi(regMatch, editor, lineCount, line, col);
if (matchedLines > 0) {
final CharacterPosition startPos = new CharacterPosition(line + regMatch.startpos[0].lnum,
regMatch.startpos[0].col);
final CharacterPosition endPos = new CharacterPosition(line + regMatch.endpos[0].lnum,
regMatch.endpos[0].col);
int start = startPos.toOffset(editor);
int end = endPos.toOffset(editor);
results.add(new TextRange(start, end));
if (start != end) {
line += matchedLines - 1;
col = endPos.column;
}
else {
line += matchedLines;
col = 0;
}
}
else {
line++;
col = 0;
}
}
return results;
}
public static boolean anyNonWhitespace(@NotNull Editor editor, int offset, int dir) { public static boolean anyNonWhitespace(@NotNull Editor editor, int offset, int dir) {
int start; int start;
int end; int end;
@@ -103,7 +454,7 @@ public class SearchHelper {
int pos = caret.getOffset(); int pos = caret.getOffset();
int loc = blockChars.indexOf(type); int loc = blockChars.indexOf(type);
// What direction should we go now (-1 is backward, 1 is forward) // What direction should we go now (-1 is backward, 1 is forward)
Direction dir = loc % 2 == 0 ? Direction.BACK : Direction.FORWARD; Direction dir = loc % 2 == 0 ? Direction.BACKWARDS : Direction.FORWARDS;
// Which character did we find and which should we now search for // Which character did we find and which should we now search for
char match = blockChars.charAt(loc); char match = blockChars.charAt(loc);
char found = blockChars.charAt(loc - dir.toInt()); char found = blockChars.charAt(loc - dir.toInt());
@@ -163,10 +514,10 @@ public class SearchHelper {
int endOffset = quoteRange.getEndOffset(); int endOffset = quoteRange.getEndOffset();
CharSequence subSequence = chars.subSequence(startOffset, endOffset); CharSequence subSequence = chars.subSequence(startOffset, endOffset);
int inQuotePos = pos - startOffset; int inQuotePos = pos - startOffset;
int inQuoteStart = findBlockLocation(subSequence, close, type, Direction.BACK, inQuotePos, count, false); int inQuoteStart = findBlockLocation(subSequence, close, type, Direction.BACKWARDS, inQuotePos, count, false);
if (inQuoteStart != -1) { if (inQuoteStart != -1) {
startPosInStringFound = true; startPosInStringFound = true;
int inQuoteEnd = findBlockLocation(subSequence, type, close, Direction.FORWARD, inQuoteStart, 1, false); int inQuoteEnd = findBlockLocation(subSequence, type, close, Direction.FORWARDS, inQuoteStart, 1, false);
if (inQuoteEnd != -1) { if (inQuoteEnd != -1) {
bstart = inQuoteStart + startOffset; bstart = inQuoteStart + startOffset;
bend = inQuoteEnd + startOffset; bend = inQuoteEnd + startOffset;
@@ -176,9 +527,9 @@ public class SearchHelper {
} }
if (!startPosInStringFound) { if (!startPosInStringFound) {
bstart = findBlockLocation(chars, close, type, Direction.BACK, pos, count, false); bstart = findBlockLocation(chars, close, type, Direction.BACKWARDS, pos, count, false);
if (bstart != -1) { if (bstart != -1) {
bend = findBlockLocation(chars, type, close, Direction.FORWARD, bstart, 1, false); bend = findBlockLocation(chars, type, close, Direction.FORWARDS, bstart, 1, false);
} }
} }
@@ -294,7 +645,7 @@ public class SearchHelper {
// If we found one ... // If we found one ...
if (loc >= 0) { if (loc >= 0) {
// What direction should we go now (-1 is backward, 1 is forward) // What direction should we go now (-1 is backward, 1 is forward)
Direction dir = loc % 2 == 0 ? Direction.FORWARD : Direction.BACK; Direction dir = loc % 2 == 0 ? Direction.FORWARDS : Direction.BACKWARDS;
// Which character did we find and which should we now search for // Which character did we find and which should we now search for
char found = getPairChars().charAt(loc); char found = getPairChars().charAt(loc);
char match = getPairChars().charAt(loc + dir.toInt()); char match = getPairChars().charAt(loc + dir.toInt());
@@ -327,7 +678,7 @@ public class SearchHelper {
boolean allowInString) { boolean allowInString) {
int res = -1; int res = -1;
int initialPos = pos; int initialPos = pos;
Function<Integer, Integer> inCheckPosF = x -> dir == Direction.BACK && x > 0 ? x - 1 : x + 1; Function<Integer, Integer> inCheckPosF = x -> dir == Direction.BACKWARDS && x > 0 ? x - 1 : x + 1;
final int inCheckPos = inCheckPosF.apply(pos); final int inCheckPos = inCheckPosF.apply(pos);
boolean inString = checkInString(chars, inCheckPos, true); boolean inString = checkInString(chars, inCheckPos, true);
boolean initialInString = inString; boolean initialInString = inString;
@@ -391,30 +742,16 @@ public class SearchHelper {
return backslashCounter % 2 == 0; return backslashCounter % 2 == 0;
} }
public enum Direction {
BACK(-1), FORWARD(1);
private final int value;
Direction(int i) {
value = i;
}
public int toInt() {
return value;
}
}
public enum NumberType { public enum NumberType {
BIN, OCT, DEC, HEX, ALPHA BIN, OCT, DEC, HEX, ALPHA
} }
private static int findNextQuoteInLine(@NotNull CharSequence chars, int pos, char quote) { private static int findNextQuoteInLine(@NotNull CharSequence chars, int pos, char quote) {
return findQuoteInLine(chars, pos, quote, Direction.FORWARD); return findQuoteInLine(chars, pos, quote, Direction.FORWARDS);
} }
private static int findPreviousQuoteInLine(@NotNull CharSequence chars, int pos, char quote) { private static int findPreviousQuoteInLine(@NotNull CharSequence chars, int pos, char quote) {
return findQuoteInLine(chars, pos, quote, Direction.BACK); return findQuoteInLine(chars, pos, quote, Direction.BACKWARDS);
} }
private static int findFirstQuoteInLine(@NotNull Editor editor, int pos, char quote) { private static int findFirstQuoteInLine(@NotNull Editor editor, int pos, char quote) {
@@ -428,8 +765,8 @@ public class SearchHelper {
private static int countCharactersInLine(@NotNull CharSequence chars, int pos, char c) { private static int countCharactersInLine(@NotNull CharSequence chars, int pos, char c) {
int cnt = 0; int cnt = 0;
while (pos > 0 && (chars.charAt(pos + Direction.BACK.toInt()) != '\n')) { while (pos > 0 && (chars.charAt(pos + Direction.BACKWARDS.toInt()) != '\n')) {
pos = findCharacterPosition(chars, pos + Direction.BACK.toInt(), c, false, true, Direction.BACK); pos = findCharacterPosition(chars, pos + Direction.BACKWARDS.toInt(), c, false, true, Direction.BACKWARDS);
if (pos != -1) { if (pos != -1) {
cnt++; cnt++;
} }

View File

@@ -18,14 +18,37 @@
package com.maddyhome.idea.vim.helper package com.maddyhome.idea.vim.helper
import com.maddyhome.idea.vim.helper.SearchHelper.Direction
import com.maddyhome.idea.vim.helper.SearchHelper.findPositionOfFirstCharacter import com.maddyhome.idea.vim.helper.SearchHelper.findPositionOfFirstCharacter
import com.maddyhome.idea.vim.option.OptionsManager.ignorecase
import com.maddyhome.idea.vim.option.OptionsManager.smartcase
enum class Direction(private val value: Int) {
BACKWARDS(-1), FORWARDS(1);
fun toInt(): Int = value
fun reverse(): Direction = when (this) {
BACKWARDS -> FORWARDS
FORWARDS -> BACKWARDS
}
companion object {
fun fromInt(value: Int) = when (value) {
BACKWARDS.value -> BACKWARDS
FORWARDS.value -> FORWARDS
else -> FORWARDS
}
}
}
enum class SearchOptions {
BACKWARDS, WANT_ENDPOS, WRAP, SHOW_MESSAGES, WHOLE_FILE, IGNORE_SMARTCASE
}
private data class State(val position: Int, val trigger: Char, val inQuote: Boolean?, val lastOpenSingleQuotePos: Int) private data class State(val position: Int, val trigger: Char, val inQuote: Boolean?, val lastOpenSingleQuotePos: Int)
// bounds are considered inside corresponding quotes // bounds are considered inside corresponding quotes
fun checkInString(chars: CharSequence, currentPos: Int, str: Boolean): Boolean { fun checkInString(chars: CharSequence, currentPos: Int, str: Boolean): Boolean {
val begin = findPositionOfFirstCharacter(chars, currentPos, setOf('\n'), false, Direction.BACK)?.second ?: 0 val begin = findPositionOfFirstCharacter(chars, currentPos, setOf('\n'), false, Direction.BACKWARDS)?.second ?: 0
val changes = quoteChanges(chars, begin) val changes = quoteChanges(chars, begin)
// TODO: here we need to keep only the latest element in beforePos (if any) and // TODO: here we need to keep only the latest element in beforePos (if any) and
// don't need atAndAfterPos to be eagerly collected // don't need atAndAfterPos to be eagerly collected
@@ -105,7 +128,7 @@ private fun quoteChanges(chars: CharSequence, begin: Int) = sequence {
// in that situation it may be double quote inside single quotes, so we cannot threat it as double quote pair open/close // in that situation it may be double quote inside single quotes, so we cannot threat it as double quote pair open/close
var inQuote: Boolean? = false var inQuote: Boolean? = false
val charsToSearch = setOf('\'', '"', '\n') val charsToSearch = setOf('\'', '"', '\n')
var found = findPositionOfFirstCharacter(chars, begin, charsToSearch, false, Direction.FORWARD) var found = findPositionOfFirstCharacter(chars, begin, charsToSearch, false, Direction.FORWARDS)
while (found != null && found.first != '\n') { while (found != null && found.first != '\n') {
val i = found.second val i = found.second
@@ -158,6 +181,23 @@ private fun quoteChanges(chars: CharSequence, begin: Int) = sequence {
} }
} }
yield(State(i, c, inQuote, lastOpenSingleQuotePos)) yield(State(i, c, inQuote, lastOpenSingleQuotePos))
found = findPositionOfFirstCharacter(chars, i + Direction.FORWARD.toInt(), charsToSearch, false, Direction.FORWARD) found = findPositionOfFirstCharacter(chars, i + Direction.FORWARDS.toInt(), charsToSearch, false, Direction.FORWARDS)
} }
} }
/**
* Check ignorecase and smartcase options to see if a case insensitive search should be performed with the given pattern.
*
* When ignorecase is not set, this will always return false - perform a case sensitive search.
*
* Otherwise, check smartcase. When set, the search will be case insensitive if the pattern contains only lowercase
* characters, and case sensitive (returns false) if the pattern contains any lowercase characters.
*
* The smartcase option can be ignored, e.g. when searching for the whole word under the cursor. This always performs a
* case insensitive search, so `\<Work\>` will match `Work` and `work`. But when choosing the same pattern from search
* history, the smartcase option is applied, and `\<Work\>` will only match `Work`.
*/
fun shouldIgnoreCase(pattern: String, ignoreSmartCaseOption: Boolean): Boolean {
val sc = smartcase.isSet && !ignoreSmartCaseOption
return ignorecase.isSet && !(sc && StringHelper.containsUpperCase(pattern))
}

View File

@@ -0,0 +1,266 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
@file:JvmName("SearchHighlightsHelper")
package com.maddyhome.idea.vim.helper
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorFactory
import com.intellij.openapi.editor.colors.EditorColors
import com.intellij.openapi.editor.colors.EditorColorsScheme
import com.intellij.openapi.editor.markup.EffectType
import com.intellij.openapi.editor.markup.HighlighterLayer
import com.intellij.openapi.editor.markup.HighlighterTargetArea
import com.intellij.openapi.editor.markup.RangeHighlighter
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapi.fileEditor.FileEditorManager
import com.intellij.openapi.project.ProjectManager
import com.intellij.ui.ColorUtil
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.ex.ranges.LineRange
import com.maddyhome.idea.vim.option.OptionsManager.hlsearch
import com.maddyhome.idea.vim.option.OptionsManager.wrapscan
import org.jetbrains.annotations.Contract
import java.awt.Color
import java.awt.Font
import java.util.*
fun updateSearchHighlights(
pattern: String?,
shouldIgnoreSmartCase: Boolean,
showHighlights: Boolean,
forceUpdate: Boolean
) {
updateSearchHighlights(pattern, shouldIgnoreSmartCase, showHighlights, -1, null, true, forceUpdate)
}
fun updateIncsearchHighlights(
editor: Editor,
pattern: String,
forwards: Boolean,
caretOffset: Int,
searchRange: LineRange?
): Int {
val searchStartOffset =
if (searchRange != null) EditorHelper.getLineStartOffset(editor, searchRange.startLine) else caretOffset
val showHighlights = hlsearch.isSet
return updateSearchHighlights(pattern, false, showHighlights, searchStartOffset, searchRange, forwards, false)
}
fun addSubstitutionConfirmationHighlight(editor: Editor, start: Int, end: Int): RangeHighlighter {
val color = TextAttributes(
editor.colorsScheme.getColor(EditorColors.SELECTION_FOREGROUND_COLOR),
editor.colorsScheme.getColor(EditorColors.SELECTION_BACKGROUND_COLOR),
editor.colorsScheme.getColor(EditorColors.CARET_COLOR),
EffectType.ROUNDED_BOX, Font.PLAIN
)
return editor.markupModel.addRangeHighlighter(
start, end, HighlighterLayer.SELECTION,
color, HighlighterTargetArea.EXACT_RANGE
)
}
/**
* Refreshes current search highlights for all editors of currently active text editor/document
*/
private fun updateSearchHighlights(
pattern: String?, shouldIgnoreSmartCase: Boolean, showHighlights: Boolean,
initialOffset: Int, searchRange: LineRange?, forwards: Boolean, forceUpdate: Boolean
): Int {
var currentMatchOffset = -1
val projectManager = ProjectManager.getInstanceIfCreated() ?: return currentMatchOffset
for (project in projectManager.openProjects) {
val current = FileEditorManager.getInstance(project).selectedTextEditor ?: continue
// [VERSION UPDATE] 202+ Use editors
val editors = EditorFactory.getInstance().getEditors(current.document, project) ?: continue
for (editor in editors) {
// Try to keep existing highlights if possible. Update if hlsearch has changed or if the pattern has changed.
// Force update for the situations where the text is the same, but the ignore case values have changed.
// E.g. Use `*` to search for a word (which ignores smartcase), then use `/<Up>` to search for the same pattern,
// which will match smartcase. Or changing the smartcase/ignorecase settings
if (shouldRemoveSearchHighlights(editor, pattern, showHighlights) || forceUpdate) {
removeSearchHighlights(editor)
}
if (pattern == null) continue
if (shouldAddAllSearchHighlights(editor, pattern, showHighlights)) {
// hlsearch (+ incsearch/noincsearch)
val startLine = searchRange?.startLine ?: 0
val endLine = searchRange?.endLine ?: -1
val results =
SearchHelper.findAll(editor, pattern, startLine, endLine, shouldIgnoreCase(pattern, shouldIgnoreSmartCase))
if (results.isNotEmpty()) {
currentMatchOffset = findClosestMatch(editor, results, initialOffset, forwards)
highlightSearchResults(editor, pattern, results, currentMatchOffset)
}
editor.vimLastSearch = pattern
} else if (shouldAddCurrentMatchSearchHighlight(pattern, showHighlights, initialOffset)) {
// nohlsearch + incsearch
val searchOptions = EnumSet.of(SearchOptions.WHOLE_FILE)
if (wrapscan.isSet) searchOptions.add(SearchOptions.WRAP)
if (shouldIgnoreSmartCase) searchOptions.add(SearchOptions.IGNORE_SMARTCASE)
if (!forwards) searchOptions.add(SearchOptions.BACKWARDS)
val result = SearchHelper.findPattern(editor, pattern, initialOffset, 1, searchOptions)
if (result != null) {
currentMatchOffset = result.startOffset
val results = listOf(result)
highlightSearchResults(editor, pattern, results, currentMatchOffset)
}
} else if (shouldMaintainCurrentMatchOffset(pattern, initialOffset)) {
// incsearch. If nothing has changed (e.g. we've edited offset values in `/foo/e+2`) make sure we return the
// current match offset so the caret remains at the current incsarch match
val offset = editor.vimIncsearchCurrentMatchOffset
if (offset != null) {
currentMatchOffset = offset
}
}
}
}
return currentMatchOffset
}
/**
* Remove current search highlights if hlSearch is false, or if the pattern is changed
*/
@Contract("_, _, false -> true; _, null, true -> false")
private fun shouldRemoveSearchHighlights(editor: Editor, newPattern: String?, hlSearch: Boolean): Boolean {
return !hlSearch || newPattern != null && newPattern != editor.vimLastSearch
}
private fun removeSearchHighlights(editor: Editor) {
editor.vimLastSearch = null
val ehl = editor.vimLastHighlighters ?: return
for (rh in ehl) {
editor.markupModel.removeHighlighter(rh)
}
editor.vimLastHighlighters = null
}
/**
* Add search highlights if hlSearch is true and the pattern is changed
*/
@Contract("_, _, false -> false; _, null, true -> false")
private fun shouldAddAllSearchHighlights(editor: Editor, newPattern: String?, hlSearch: Boolean): Boolean {
return hlSearch && newPattern != null && newPattern != editor.vimLastSearch && newPattern != ""
}
private fun findClosestMatch(editor: Editor, results: List<TextRange>, initialOffset: Int, forwards: Boolean): Int {
if (results.isEmpty() || initialOffset == -1) {
return -1
}
val size = editor.fileSize
val max = Collections.max(results) { r1: TextRange, r2: TextRange ->
val d1 = distance(r1, initialOffset, forwards, size)
val d2 = distance(r2, initialOffset, forwards, size)
if (d1 < 0 && d2 >= 0) {
return@max Int.MAX_VALUE
}
d2 - d1
}
if (!wrapscan.isSet) {
val start = max.startOffset
if (forwards && start < initialOffset) {
return -1
} else if (start >= initialOffset) {
return -1
}
}
return max.startOffset
}
private fun distance(range: TextRange, pos: Int, forwards: Boolean, size: Int): Int {
val start = range.startOffset
return if (start <= pos) {
if (forwards) size - pos + start else pos - start
} else {
if (forwards) start - pos else pos + size - start
}
}
fun highlightSearchResults(editor: Editor, pattern: String, results: List<TextRange>, currentMatchOffset: Int) {
var highlighters = editor.vimLastHighlighters
if (highlighters == null) {
highlighters = mutableListOf()
editor.vimLastHighlighters = highlighters
}
for (range in results) {
val current = range.startOffset == currentMatchOffset
val highlighter = highlightMatch(editor, range.startOffset, range.endOffset, current, pattern)
highlighters.add(highlighter)
}
editor.vimIncsearchCurrentMatchOffset = currentMatchOffset
}
private fun highlightMatch(editor: Editor, start: Int, end: Int, current: Boolean, tooltip: String): RangeHighlighter {
var attributes = editor.colorsScheme.getAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES)
if (current) {
// This mimics what IntelliJ does with the Find live preview
attributes = attributes.clone()
attributes.effectType = EffectType.ROUNDED_BOX
attributes.effectColor = editor.colorsScheme.getColor(EditorColors.CARET_COLOR)
}
if (attributes.errorStripeColor == null) {
attributes.errorStripeColor = getFallbackErrorStripeColor(attributes, editor.colorsScheme)
}
val highlighter = editor.markupModel.addRangeHighlighter(
start, end, HighlighterLayer.SELECTION - 1,
attributes, HighlighterTargetArea.EXACT_RANGE
)
highlighter.errorStripeTooltip = tooltip
return highlighter
}
/**
* Return a valid error stripe colour based on editor background
*
*
* Based on HighlightManager#addRangeHighlight behaviour, which we can't use because it will hide highlights
* when hitting Escape.
*/
private fun getFallbackErrorStripeColor(attributes: TextAttributes, colorsScheme: EditorColorsScheme): Color? {
if (attributes.backgroundColor != null) {
val isDark = ColorUtil.isDark(colorsScheme.defaultBackground)
return if (isDark) attributes.backgroundColor.brighter() else attributes.backgroundColor.darker()
}
return null
}
/**
* Add search highlight for current match if hlsearch is false and we're performing incsearch highlights
*/
@Contract("_, true, _ -> false")
private fun shouldAddCurrentMatchSearchHighlight(pattern: String?, hlSearch: Boolean, initialOffset: Int): Boolean {
return !hlSearch && isIncrementalSearchHighlights(initialOffset) && pattern != null && pattern.isNotEmpty()
}
/**
* Keep the current match offset if the pattern is still valid and we're performing incremental search highlights
* This will keep the caret position when editing the offset in e.g. `/foo/e+1`
*/
@Contract("null, _ -> false")
private fun shouldMaintainCurrentMatchOffset(pattern: String?, initialOffset: Int): Boolean {
return pattern != null && pattern.isNotEmpty() && isIncrementalSearchHighlights(initialOffset)
}
/**
* initialOffset is only valid if we're highlighting incsearch
*/
@Contract(pure = true)
private fun isIncrementalSearchHighlights(initialOffset: Int) = initialOffset != -1

View File

@@ -80,7 +80,7 @@ fun unInitializeEditor(editor: Editor) {
} }
var Editor.vimLastSearch: String? by userData() var Editor.vimLastSearch: String? by userData()
var Editor.vimLastHighlighters: Collection<RangeHighlighter>? by userData() var Editor.vimLastHighlighters: MutableCollection<RangeHighlighter>? by userData()
var Editor.vimIncsearchCurrentMatchOffset: Int? by userData() var Editor.vimIncsearchCurrentMatchOffset: Int? by userData()
/*** /***
* @see :help visualmode() * @see :help visualmode()

View File

@@ -107,7 +107,7 @@ class ToHandlerMappingInfo(
isRecursive: Boolean, isRecursive: Boolean,
owner: MappingOwner owner: MappingOwner
) : MappingInfo(fromKeys, isRecursive, owner) { ) : MappingInfo(fromKeys, isRecursive, owner) {
override fun getPresentableString(): String = "call ${this.javaClass.canonicalName}" override fun getPresentableString(): String = "call ${extensionHandler.javaClass.canonicalName}"
override fun execute(editor: Editor, context: DataContext) { override fun execute(editor: Editor, context: DataContext) {
val processor = CommandProcessor.getInstance() val processor = CommandProcessor.getInstance()

View File

@@ -32,12 +32,14 @@ import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.ex.AnActionListener import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.actionSystem.EditorActionManager import com.intellij.openapi.editor.actionSystem.EditorActionManager
import com.intellij.openapi.editor.event.CaretEvent import com.intellij.openapi.editor.event.CaretEvent
import com.intellij.openapi.editor.event.CaretListener import com.intellij.openapi.editor.event.CaretListener
import com.intellij.openapi.project.DumbAwareToggleAction import com.intellij.openapi.project.DumbAwareToggleAction
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key
import com.intellij.util.PlatformUtils import com.intellij.util.PlatformUtils
import com.maddyhome.idea.vim.EventFacade import com.maddyhome.idea.vim.EventFacade
import com.maddyhome.idea.vim.KeyHandler import com.maddyhome.idea.vim.KeyHandler
@@ -47,10 +49,12 @@ import com.maddyhome.idea.vim.group.visual.IdeaSelectionControl
import com.maddyhome.idea.vim.group.visual.moveCaretOneCharLeftFromSelectionEnd import com.maddyhome.idea.vim.group.visual.moveCaretOneCharLeftFromSelectionEnd
import com.maddyhome.idea.vim.helper.EditorDataContext import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.commandState import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.getTopLevelEditor import com.maddyhome.idea.vim.helper.getTopLevelEditor
import com.maddyhome.idea.vim.helper.inNormalMode import com.maddyhome.idea.vim.helper.inNormalMode
import com.maddyhome.idea.vim.option.IdeaRefactorMode import com.maddyhome.idea.vim.option.IdeaRefactorMode
import org.jetbrains.annotations.NonNls import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.NotNull
import java.beans.PropertyChangeEvent import java.beans.PropertyChangeEvent
import java.beans.PropertyChangeListener import java.beans.PropertyChangeListener
@@ -191,6 +195,92 @@ object IdeaSpecifics {
.javaClass.name.startsWith("org.acejump.") .javaClass.name.startsWith("org.acejump.")
} }
//endregion //endregion
//region AppCode templates
/**
* A collection of hacks to improve the interaction with fancy AppCode templates
*/
object AppCodeTemplates {
private val facedAppCodeTemplate = Key.create<IntRange>("FacedAppCodeTemplate")
private const val TEMPLATE_START = "<#T##"
private const val TEMPLATE_END = "#>"
@JvmStatic
fun onMovement(
editor: @NotNull Editor,
caret: @NotNull Caret,
toRight: Boolean
) {
if (!PlatformUtils.isAppCode()) return
val offset = caret.offset
val offsetRightEnd = offset + TEMPLATE_START.length
val offsetLeftEnd = offset - 1
val templateRange = caret.getUserData(facedAppCodeTemplate)
if (templateRange == null) {
if (offsetRightEnd < editor.fileSize
&& editor.document.charsSequence.subSequence(offset, offsetRightEnd).toString() == TEMPLATE_START) {
caret.shake()
val templateEnd = editor.findTemplateEnd(offset) ?: return
caret.putUserData(facedAppCodeTemplate, offset..templateEnd)
}
if (offsetLeftEnd >= 0
&& editor.document.charsSequence.subSequence(offsetLeftEnd, offset + 1).toString() == TEMPLATE_END) {
caret.shake()
val templateStart = editor.findTemplateStart(offsetLeftEnd) ?: return
caret.putUserData(facedAppCodeTemplate, templateStart..offset)
}
} else {
if (offset in templateRange) {
if (toRight) {
caret.moveToOffset(templateRange.last + 1)
} else {
caret.moveToOffset(templateRange.first)
}
}
caret.putUserData(facedAppCodeTemplate, null)
caret.shake()
}
}
fun Editor.appCodeTemplateCaptured(): Boolean {
if (!PlatformUtils.isAppCode()) return false
return this.caretModel.allCarets.any { it.getUserData(facedAppCodeTemplate) != null }
}
private fun Caret.shake() {
moveCaretRelatively(1, 0, false, false)
moveCaretRelatively(-1, 0, false, false)
}
private fun Editor.findTemplateEnd(start: Int): Int? {
val charSequence = this.document.charsSequence
val length = charSequence.length
for (i in start until length - 1) {
if (charSequence[i] == TEMPLATE_END[0] && charSequence[i+1] == TEMPLATE_END[1]) {
return i + 1
}
}
return null
}
private fun Editor.findTemplateStart(start: Int): Int? {
val charSequence = this.document.charsSequence
val templateLastIndex = TEMPLATE_START.length
for (i in start downTo templateLastIndex) {
if (charSequence.subSequence(i - templateLastIndex, i + 1).toString() == TEMPLATE_START) {
return i - templateLastIndex
}
}
return null
}
}
//endregion
} }
//region Find action ID //region Find action ID

View File

@@ -253,11 +253,11 @@ object VimListenerManager {
if (onLineEnd(caret)) { if (onLineEnd(caret)) {
// UX protection for case when user performs a small dragging while putting caret on line end // UX protection for case when user performs a small dragging while putting caret on line end
caret.removeSelection() caret.removeSelection()
ChangeGroup.resetCaret(e.editor, VimPlugin.getEditor().isBarCursor) ChangeGroup.resetCaret(e.editor, true)
} }
} }
if (mouseDragging && e.editor.caretModel.primaryCaret.hasSelection()) { if (mouseDragging && e.editor.caretModel.primaryCaret.hasSelection()) {
ChangeGroup.resetCaret(e.editor, VimPlugin.getEditor().isBarCursor) ChangeGroup.resetCaret(e.editor, true)
if (!cutOffFixed && ComponentMouseListener.cutOffEnd) { if (!cutOffFixed && ComponentMouseListener.cutOffEnd) {
cutOffFixed = true cutOffFixed = true

View File

@@ -32,7 +32,7 @@ import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.Msg import com.maddyhome.idea.vim.helper.Msg
import com.maddyhome.idea.vim.helper.hasVisualSelection import com.maddyhome.idea.vim.helper.hasVisualSelection
import com.maddyhome.idea.vim.helper.isBlockCaret import com.maddyhome.idea.vim.helper.isBlockCaretBehaviour
import com.maddyhome.idea.vim.helper.mode import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.subMode import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
@@ -52,7 +52,7 @@ object OptionsManager {
val clipboard = addOption(ListOption(ClipboardOptionsData.name, ClipboardOptionsData.abbr, arrayOf(ClipboardOptionsData.ideaput, "autoselect,exclude:cons\\|linux"), null)) val clipboard = addOption(ListOption(ClipboardOptionsData.name, ClipboardOptionsData.abbr, arrayOf(ClipboardOptionsData.ideaput, "autoselect,exclude:cons\\|linux"), null))
val digraph = addOption(ToggleOption("digraph", "dg", false)) val digraph = addOption(ToggleOption("digraph", "dg", false))
val gdefault = addOption(ToggleOption("gdefault", "gd", false)) val gdefault = addOption(ToggleOption("gdefault", "gd", false))
val history = addOption(NumberOption("history", "hi", 20, 1, Int.MAX_VALUE)) val history = addOption(NumberOption("history", "hi", 50, 1, Int.MAX_VALUE))
val hlsearch = addOption(ToggleOption("hlsearch", "hls", false)) val hlsearch = addOption(ToggleOption("hlsearch", "hls", false))
val ideamarks = addOption(IdeaMarkskOptionsData.option) val ideamarks = addOption(IdeaMarkskOptionsData.option)
val ignorecase = addOption(ToggleOption(IgnoreCaseOptionsData.name, IgnoreCaseOptionsData.abbr, false)) val ignorecase = addOption(ToggleOption(IgnoreCaseOptionsData.name, IgnoreCaseOptionsData.abbr, false))
@@ -62,7 +62,7 @@ object OptionsManager {
val lookupKeys = addOption(ListOption(LookupKeysData.name, LookupKeysData.name, LookupKeysData.defaultValues, null)) val lookupKeys = addOption(ListOption(LookupKeysData.name, LookupKeysData.name, LookupKeysData.defaultValues, null))
val matchpairs = addOption(ListOption("matchpairs", "mps", arrayOf("(:)", "{:}", "[:]"), ".:.")) val matchpairs = addOption(ListOption("matchpairs", "mps", arrayOf("(:)", "{:}", "[:]"), ".:."))
val more = addOption(ToggleOption("more", "more", true)) val more = addOption(ToggleOption("more", "more", true))
val nrformats = addOption(BoundListOption("nrformats", "nf", arrayOf("octal", "hex"), arrayOf("octal", "hex", "alpha"))) val nrformats = addOption(BoundListOption("nrformats", "nf", arrayOf("hex"), arrayOf("octal", "hex", "alpha"))) // Octal is disabled as in neovim
val number = addOption(ToggleOption("number", "nu", false)) val number = addOption(ToggleOption("number", "nu", false))
val relativenumber = addOption(ToggleOption("relativenumber", "rnu", false)) val relativenumber = addOption(ToggleOption("relativenumber", "rnu", false))
val scroll = addOption(NumberOption("scroll", "scr", 0)) val scroll = addOption(NumberOption("scroll", "scr", 0))
@@ -491,7 +491,7 @@ object IdeaRefactorMode {
} }
} }
if (editor.mode.isBlockCaret) { if (editor.mode.isBlockCaretBehaviour) {
TemplateManagerImpl.getTemplateState(editor)?.currentVariableRange?.let { segmentRange -> TemplateManagerImpl.getTemplateState(editor)?.currentVariableRange?.let { segmentRange ->
if (!segmentRange.isEmpty && segmentRange.endOffset == editor.caretModel.offset && editor.caretModel.offset != 0) { if (!segmentRange.isEmpty && segmentRange.endOffset == editor.caretModel.offset && editor.caretModel.offset != 0) {
editor.caretModel.moveToOffset(editor.caretModel.offset - 1) editor.caretModel.moveToOffset(editor.caretModel.offset - 1)

View File

@@ -669,7 +669,7 @@
* |c_<S-Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction} * |c_<S-Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpAction}
* |c_<Tab>| TO BE IMPLEMENTED * |c_<Tab>| TO BE IMPLEMENTED
* |c_<Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpFilterAction} * |c_<Up>| {@link com.maddyhome.idea.vim.ui.ex.HistoryUpFilterAction}
* |c_digraph| {char1} <BS> {char2} {@link com.maddyhome.idea.vim.ui.ex.StartDigraphAction} * |c_digraph| {char1} <BS> {char2}
* |c_wildchar| TO BE IMPLEMENTED * |c_wildchar| TO BE IMPLEMENTED
* |'cedit'| TO BE IMPLEMENTED * |'cedit'| TO BE IMPLEMENTED
* *

View File

@@ -28,12 +28,12 @@ import com.intellij.openapi.editor.toolbar.floating.FloatingToolbarComponent
import com.intellij.openapi.fileEditor.FileDocumentManager import com.intellij.openapi.fileEditor.FileDocumentManager
import com.intellij.openapi.project.DumbAwareAction import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.util.io.FileUtil import com.intellij.openapi.util.io.FileUtil
import com.intellij.util.containers.IntArrayList
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.ex.vimscript.VimScriptParser import com.maddyhome.idea.vim.ex.vimscript.VimScriptParser
import com.maddyhome.idea.vim.helper.MessageHelper import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.ui.ReloadFloatingToolbarActionGroup.Companion.ACTION_GROUP import com.maddyhome.idea.vim.ui.ReloadFloatingToolbarActionGroup.Companion.ACTION_GROUP
import icons.VimIcons import icons.VimIcons
import it.unimi.dsi.fastutil.ints.IntArrayList
import org.jetbrains.annotations.TestOnly import org.jetbrains.annotations.TestOnly
import java.util.regex.Pattern import java.util.regex.Pattern
@@ -49,8 +49,6 @@ import java.util.regex.Pattern
object VimRcFileState { object VimRcFileState {
// List of hashes of non-empty trimmed lines // List of hashes of non-empty trimmed lines
// [VERSION UPDATE] 202+
@Suppress("DEPRECATION")
private val state = IntArrayList() private val state = IntArrayList()
// ModificationStamp. Can be taken only from document. Doesn't play a big role, but can help speed up [equalTo] // ModificationStamp. Can be taken only from document. Doesn't play a big role, but can help speed up [equalTo]
@@ -74,11 +72,11 @@ object VimRcFileState {
val fileModificationStamp = document.modificationStamp val fileModificationStamp = document.modificationStamp
if (fileModificationStamp == modificationStamp) return true if (fileModificationStamp == modificationStamp) return true
val stateSize = state.size() val stateSize = state.size
var i = 0 var i = 0
VimScriptParser.readText(document.charsSequence).forEach { line -> VimScriptParser.readText(document.charsSequence).forEach { line ->
if (i >= stateSize) return false if (i >= stateSize) return false
if (state.get(i) != line.hashCode()) return false if (state.getInt(i) != line.hashCode()) return false
i++ i++
} }
if (i < stateSize) return false if (i < stateSize) return false

View File

@@ -33,6 +33,7 @@ import com.maddyhome.idea.vim.ex.CommandParser;
import com.maddyhome.idea.vim.ex.ExCommand; import com.maddyhome.idea.vim.ex.ExCommand;
import com.maddyhome.idea.vim.ex.ranges.LineRange; import com.maddyhome.idea.vim.ex.ranges.LineRange;
import com.maddyhome.idea.vim.group.MotionGroup; 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.helper.UiHelper;
import com.maddyhome.idea.vim.option.OptionsManager; import com.maddyhome.idea.vim.option.OptionsManager;
import com.maddyhome.idea.vim.regexp.CharPointer; import com.maddyhome.idea.vim.regexp.CharPointer;
@@ -279,6 +280,9 @@ public class ExEntryPanel extends JPanel {
searchText = argument.substring(1); searchText = argument.substring(1);
} }
if (searchText.length() == 0) { if (searchText.length() == 0) {
// Reset back to the original search highlights after deleting a search from a substitution command.
// E.g. Highlight `whatever`, type `:%s/foo` + highlight `foo`, delete back to `:%s/` and reset highlights
// back to `whatever`
VimPlugin.getSearch().resetIncsearchHighlights(); VimPlugin.getSearch().resetIncsearchHighlights();
return; return;
} }
@@ -294,7 +298,7 @@ public class ExEntryPanel extends JPanel {
pattern = p.substring(end.pointer() - p.pointer()); pattern = p.substring(end.pointer() - p.pointer());
VimPlugin.getEditor().closeEditorSearchSession(editor); VimPlugin.getEditor().closeEditorSearchSession(editor);
final int matchOffset = VimPlugin.getSearch().updateIncsearchHighlights(editor, pattern, forwards, caretOffset, searchRange); final int matchOffset = SearchHighlightsHelper.updateIncsearchHighlights(editor, pattern, forwards, caretOffset, searchRange);
if (matchOffset != -1) { if (matchOffset != -1) {
MotionGroup.moveCaret(editor, editor.getCaretModel().getPrimaryCaret(), matchOffset); MotionGroup.moveCaret(editor, editor.getCaretModel().getPrimaryCaret(), matchOffset);
} }

View File

@@ -37,6 +37,9 @@ class RegisterActionsTest : VimTestCase() {
} }
fun `test action in disabled plugin`() { fun `test action in disabled plugin`() {
setupChecks {
caretShape = false
}
val keys = StringHelper.parseKeys("jklwB") // just random keys val keys = StringHelper.parseKeys("jklwB") // just random keys
val before = "I ${c}found it in a legendary land" val before = "I ${c}found it in a legendary land"
val after = "I ${c}found it in a legendary land" val after = "I ${c}found it in a legendary land"

View File

@@ -55,6 +55,9 @@ import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import com.maddyhome.idea.vim.helper.StringHelper.stringToKeys import com.maddyhome.idea.vim.helper.StringHelper.stringToKeys
import com.maddyhome.idea.vim.helper.TestInputModel import com.maddyhome.idea.vim.helper.TestInputModel
import com.maddyhome.idea.vim.helper.inBlockSubMode import com.maddyhome.idea.vim.helper.inBlockSubMode
import com.maddyhome.idea.vim.helper.isBlockCaretBehaviour
import com.maddyhome.idea.vim.helper.isBlockCaretShape
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.key.MappingOwner import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.key.ToKeysMappingInfo import com.maddyhome.idea.vim.key.ToKeysMappingInfo
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
@@ -65,7 +68,6 @@ import com.maddyhome.idea.vim.option.OptionsManager.resetAllOptions
import com.maddyhome.idea.vim.option.ToggleOption import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel import com.maddyhome.idea.vim.ui.ex.ExEntryPanel
import org.junit.Assert import org.junit.Assert
import java.util.*
import java.util.function.Consumer import java.util.function.Consumer
import javax.swing.KeyStroke import javax.swing.KeyStroke
@@ -93,6 +95,7 @@ abstract class VimTestCase : UsefulTestCase() {
VimPlugin.getSearch().resetState() VimPlugin.getSearch().resetState()
if (!VimPlugin.isEnabled()) VimPlugin.setEnabled(true) if (!VimPlugin.isEnabled()) VimPlugin.setEnabled(true)
ideastrictmode.set() ideastrictmode.set()
Checks.reset()
// Make sure the entry text field gets a bounds, or we won't be able to work out caret location // Make sure the entry text field gets a bounds, or we won't be able to work out caret location
ExEntryPanel.getInstance().entry.setBounds(0, 0, 100, 25) ExEntryPanel.getInstance().entry.setBounds(0, 0, 100, 25)
@@ -427,6 +430,7 @@ abstract class VimTestCase : UsefulTestCase() {
assertCaretsColour() assertCaretsColour()
assertMode(modeAfter) assertMode(modeAfter)
assertSubMode(subModeAfter) assertSubMode(subModeAfter)
if (Checks.caretShape) assertEquals(myFixture.editor.mode.isBlockCaretShape, myFixture.editor.settings.isBlockCursor)
} }
protected val fileManager: FileEditorManagerEx protected val fileManager: FileEditorManagerEx
@@ -440,6 +444,11 @@ abstract class VimTestCase : UsefulTestCase() {
return EditorTestUtil.addInlay(myFixture.editor, offset, relatesToPrecedingText, widthInColumns * columnWidth)!! return EditorTestUtil.addInlay(myFixture.editor, offset, relatesToPrecedingText, widthInColumns * columnWidth)!!
} }
// Disable or enable checks for the particular test
protected inline fun setupChecks(setup: Checks.() -> Unit) {
Checks.setup()
}
companion object { companion object {
const val c = EditorTestUtil.CARET_TAG const val c = EditorTestUtil.CARET_TAG
const val s = EditorTestUtil.SELECTION_START_TAG const val s = EditorTestUtil.SELECTION_START_TAG
@@ -480,4 +489,12 @@ abstract class VimTestCase : UsefulTestCase() {
fun String.dotToTab(): String = replace('.', '\t') fun String.dotToTab(): String = replace('.', '\t')
} }
object Checks {
var caretShape: Boolean = true
fun reset() {
caretShape = true
}
}
} }

View File

@@ -25,7 +25,7 @@ import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
public class ReformatCodeTest extends VimTestCase { public class ReformatCodeTest extends VimTestCase {
/* /*
[VERSION UPDATE] 2020.2+ [VERSION UPDATE] 203+
public void testEmpty() { public void testEmpty() {
configureByJavaText("<caret>"); configureByJavaText("<caret>");
typeText(parseKeys("gqq")); typeText(parseKeys("gqq"));

View File

@@ -40,7 +40,7 @@ public class SpecialRegistersTest extends VimTestCase {
final RegisterGroup registerGroup = VimPlugin.getRegister(); final RegisterGroup registerGroup = VimPlugin.getRegister();
registerGroup.setKeys('a', stringToKeys(DUMMY_TEXT)); registerGroup.setKeys('a', stringToKeys(DUMMY_TEXT));
registerGroup.setKeys('-', stringToKeys(DUMMY_TEXT)); registerGroup.setKeys(RegisterGroup.SMALL_DELETION_REGISTER, stringToKeys(DUMMY_TEXT));
for (char c = '0'; c <= '9'; c++) { for (char c = '0'; c <= '9'; c++) {
registerGroup.setKeys(c, stringToKeys(DUMMY_TEXT)); registerGroup.setKeys(c, stringToKeys(DUMMY_TEXT));
} }
@@ -50,7 +50,7 @@ public class SpecialRegistersTest extends VimTestCase {
public void testSmallDelete() { public void testSmallDelete() {
typeTextInFile(parseKeys("de"), "one <caret>two three\n"); typeTextInFile(parseKeys("de"), "one <caret>two three\n");
assertEquals("two", getRegisterText('-')); assertEquals("two", getRegisterText(RegisterGroup.SMALL_DELETION_REGISTER));
// Text smaller than line doesn't go to numbered registers (except special cases) // Text smaller than line doesn't go to numbered registers (except special cases)
assertRegisterNotChanged('1'); assertRegisterNotChanged('1');
} }
@@ -60,7 +60,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("d%"), "(one<caret> two) three\n"); typeTextInFile(parseKeys("d%"), "(one<caret> two) three\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |(| Special case for small delete // |d| |(| Special case for small delete
@@ -68,7 +68,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("d("), "One. Two<caret>. Three.\n"); typeTextInFile(parseKeys("d("), "One. Two<caret>. Three.\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |)| Special case for small delete // |d| |)| Special case for small delete
@@ -76,7 +76,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("d)"), "One. <caret>Two. Three.\n"); typeTextInFile(parseKeys("d)"), "One. <caret>Two. Three.\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |`| Special case for small delete // |d| |`| Special case for small delete
@@ -84,7 +84,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("ma", "b", "d`a"), "one two<caret> three\n"); typeTextInFile(parseKeys("ma", "b", "d`a"), "one two<caret> three\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |/| Special case for small delete // |d| |/| Special case for small delete
@@ -92,7 +92,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("d/", "o", "<Enter>"), "one <caret>two three\n"); typeTextInFile(parseKeys("d/", "o", "<Enter>"), "one <caret>two three\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |?| Special case for small delete // |d| |?| Special case for small delete
@@ -100,7 +100,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("d?", "t", "<Enter>"), "one two<caret> three\n"); typeTextInFile(parseKeys("d?", "t", "<Enter>"), "one two<caret> three\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |n| Special case for small delete // |d| |n| Special case for small delete
@@ -108,7 +108,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("/", "t", "<Enter>", "dn"), "<caret>one two three\n"); typeTextInFile(parseKeys("/", "t", "<Enter>", "dn"), "<caret>one two three\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |N| Special case for small delete // |d| |N| Special case for small delete
@@ -116,7 +116,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("/", "t", "<Enter>", "dN"), "one tw<caret>o three\n"); typeTextInFile(parseKeys("/", "t", "<Enter>", "dN"), "one tw<caret>o three\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |{| Special case for small delete // |d| |{| Special case for small delete
@@ -124,7 +124,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("d{"), "one<caret> two three"); typeTextInFile(parseKeys("d{"), "one<caret> two three");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
// |d| |}| Special case for small delete // |d| |}| Special case for small delete
@@ -132,7 +132,7 @@ public class SpecialRegistersTest extends VimTestCase {
typeTextInFile(parseKeys("d}"), "one<caret> two three"); typeTextInFile(parseKeys("d}"), "one<caret> two three");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterChanged('-'); assertRegisterChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
public void testSmallDeleteInRegister() { public void testSmallDeleteInRegister() {
@@ -141,14 +141,14 @@ public class SpecialRegistersTest extends VimTestCase {
// Small deletes (less than a line) with register specified go to that register and to numbered registers // Small deletes (less than a line) with register specified go to that register and to numbered registers
assertRegisterChanged('a'); assertRegisterChanged('a');
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterNotChanged('-'); assertRegisterNotChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
public void testLineDelete() { public void testLineDelete() {
typeTextInFile(parseKeys("dd"), "one <caret>two three\n"); typeTextInFile(parseKeys("dd"), "one <caret>two three\n");
assertRegisterChanged('1'); assertRegisterChanged('1');
assertRegisterNotChanged('-'); assertRegisterNotChanged(RegisterGroup.SMALL_DELETION_REGISTER);
} }
public void testLineDeleteInRegister() { public void testLineDeleteInRegister() {
@@ -190,5 +190,4 @@ public class SpecialRegistersTest extends VimTestCase {
return register.getText(); return register.getText();
} }
} }

View File

@@ -0,0 +1,30 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jetbrains.plugins.ideavim.action.change.change.number
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase
class ChangeNumberIncActionTest : VimTestCase() {
@VimBehaviorDiffers(originalVimAfter = "11X0")
fun `test inc fancy number`() {
doTest("<C-A>", "1${c}0X0", "10X1", CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
}
}

View File

@@ -0,0 +1,40 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jetbrains.plugins.ideavim.action.change.insert
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
import com.maddyhome.idea.vim.command.CommandState
import org.jetbrains.plugins.ideavim.VimTestCase
class InsertBeforeCursorActionTest : VimTestCase() {
fun `test check caret shape`() {
doTest("i", "123", "123", CommandState.Mode.INSERT, CommandState.SubMode.NONE)
assertFalse(myFixture.editor.settings.isBlockCursor)
}
fun `test check caret shape for block caret`() {
EditorSettingsExternalizable.getInstance().isBlockCursor = true
try {
doTest("i", "123", "123", CommandState.Mode.INSERT, CommandState.SubMode.NONE)
assertTrue(myFixture.editor.settings.isBlockCursor)
} finally {
EditorSettingsExternalizable.getInstance().isBlockCursor = false
}
}
}

View File

@@ -0,0 +1,34 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2020 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package org.jetbrains.plugins.ideavim.action.change.insert
import com.maddyhome.idea.vim.command.CommandState
import org.jetbrains.plugins.ideavim.VimTestCase
class InsertSingleCommandActionTest : VimTestCase() {
fun `test enter visual`() {
doTest(
listOf("i", "<C-O>", "vlll", "<Esc>"),
"I found ${c}it in a legendary land",
"I found it ${c}in a legendary land",
CommandState.Mode.INSERT,
CommandState.SubMode.NONE
)
}
}

View File

@@ -21,8 +21,13 @@ package org.jetbrains.plugins.ideavim.action.motion.visual
import com.maddyhome.idea.vim.command.CommandState import com.maddyhome.idea.vim.command.CommandState
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
class VisualExitModeAction : VimTestCase() { class VisualExitModeActionTest : VimTestCase() {
fun `test exit visual mode after line end`() { fun `test exit visual mode after line end`() {
doTest("vl<Esc>", "12${c}3", "12${c}3", CommandState.Mode.COMMAND, CommandState.SubMode.NONE) doTest("vl<Esc>", "12${c}3", "12${c}3", CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
} }
fun `test double exit`() {
doTest("vl<Esc><Esc>", "12${c}3", "12${c}3", CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
assertTrue(myFixture.editor.settings.isBlockCursor)
}
} }

View File

@@ -90,7 +90,7 @@ class VisualToggleBlockModeActionTest : VimTestCase() {
} }
/* /*
[VERSION UPDATE] 2020.2+ [VERSION UPDATE] 203+
fun `test on empty file`() { fun `test on empty file`() {
doTest("<C-V>", "", "", doTest("<C-V>", "", "",
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_BLOCK) CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_BLOCK)

View File

@@ -65,6 +65,9 @@ class CommandParserTest : VimTestCase() {
} }
fun `test execute in disabled state`() { fun `test execute in disabled state`() {
setupChecks {
caretShape = false
}
val keys = commandToKeys(">>") val keys = commandToKeys(">>")
val before = "I ${c}found it in a legendary land" val before = "I ${c}found it in a legendary land"
val after = "I ${c}found it in a legendary land" val after = "I ${c}found it in a legendary land"

View File

@@ -21,8 +21,11 @@ package org.jetbrains.plugins.ideavim.ex.handler;
import com.intellij.openapi.actionSystem.ActionManager; import com.intellij.openapi.actionSystem.ActionManager;
import com.intellij.util.ArrayUtil; import com.intellij.util.ArrayUtil;
import com.maddyhome.idea.vim.ex.ExOutputModel; import com.maddyhome.idea.vim.ex.ExOutputModel;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.plugins.ideavim.VimTestCase; import org.jetbrains.plugins.ideavim.VimTestCase;
import java.util.List;
/** /**
* @author Naoto Ikeno * @author Naoto Ikeno
*/ */

View File

@@ -18,6 +18,7 @@
package org.jetbrains.plugins.ideavim.extension package org.jetbrains.plugins.ideavim.extension
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.actionSystem.DataContext import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin import com.maddyhome.idea.vim.VimPlugin
@@ -50,15 +51,14 @@ class OpMappingTest : VimTestCase() {
extension = TestExtension.createBean() extension = TestExtension.createBean()
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ VimExtension.EP_NAME.point.registerExtension(extension, VimPlugin.getInstance())
VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
enableExtensions("TestExtension") enableExtensions("TestExtension")
} }
} }
override fun tearDown() { override fun tearDown() {
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ @Suppress("DEPRECATION")
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension) VimExtension.EP_NAME.point.unregisterExtension(extension)
super.tearDown() super.tearDown()
} }
@@ -137,15 +137,14 @@ class OpMappingTest : VimTestCase() {
typeText(parseKeys("Q")) typeText(parseKeys("Q"))
myFixture.checkResult("I${c} found it in a legendary land") myFixture.checkResult("I${c} found it in a legendary land")
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ @Suppress("DEPRECATION")
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension) VimExtension.EP_NAME.point.unregisterExtension(extension)
assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.handler.owner)) assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.instance.owner))
typeText(parseKeys("Q")) typeText(parseKeys("Q"))
myFixture.checkResult("I${c} found it in a legendary land") myFixture.checkResult("I${c} found it in a legendary land")
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ VimExtension.EP_NAME.point.registerExtension(extension, VimPlugin.getInstance())
VimExtension.EP_NAME.getPoint(null).registerExtension(extension) assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.instance.owner))
assertEmpty(VimPlugin.getKey().getKeyMappingByOwner(extension.handler.owner))
enableExtensions("TestExtension") enableExtensions("TestExtension")
typeText(parseKeys("Q")) typeText(parseKeys("Q"))
myFixture.checkResult("I ${c}found it in a legendary land") myFixture.checkResult("I ${c}found it in a legendary land")
@@ -157,13 +156,12 @@ class OpMappingTest : VimTestCase() {
myFixture.checkResult("I${c} found it in a legendary land") myFixture.checkResult("I${c} found it in a legendary land")
enterCommand("set noTestExtension") enterCommand("set noTestExtension")
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ @Suppress("DEPRECATION")
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension) VimExtension.EP_NAME.point.unregisterExtension(extension)
typeText(parseKeys("Q")) typeText(parseKeys("Q"))
myFixture.checkResult("I${c} found it in a legendary land") myFixture.checkResult("I${c} found it in a legendary land")
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ VimExtension.EP_NAME.point.registerExtension(extension, VimPlugin.getInstance())
VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
enableExtensions("TestExtension") enableExtensions("TestExtension")
typeText(parseKeys("Q")) typeText(parseKeys("Q"))
myFixture.checkResult("I ${c}found it in a legendary land") myFixture.checkResult("I ${c}found it in a legendary land")
@@ -178,13 +176,12 @@ class PlugExtensionsTest : VimTestCase() {
super.setUp() super.setUp()
extension = TestExtension.createBean() extension = TestExtension.createBean()
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ VimExtension.EP_NAME.point.registerExtension(extension, VimPlugin.getInstance())
VimExtension.EP_NAME.getPoint(null).registerExtension(extension)
} }
override fun tearDown() { override fun tearDown() {
@Suppress("DEPRECATION") // [VERSION UPDATE] 202+ @Suppress("DEPRECATION")
VimExtension.EP_NAME.getPoint(null).unregisterExtension(extension) VimExtension.EP_NAME.point.unregisterExtension(extension)
super.tearDown() super.tearDown()
} }
@@ -212,7 +209,7 @@ class PlugExtensionsTest : VimTestCase() {
} }
private val ExtensionBeanClass.ext: TestExtension private val ExtensionBeanClass.ext: TestExtension
get() = this.handler as TestExtension get() = this.instance as TestExtension
private class TestExtension : VimExtension { private class TestExtension : VimExtension {
@@ -296,6 +293,7 @@ private class TestExtension : VimExtension {
val beanClass = ExtensionBeanClass() val beanClass = ExtensionBeanClass()
beanClass.implementation = TestExtension::class.java.canonicalName beanClass.implementation = TestExtension::class.java.canonicalName
beanClass.aliases = listOf(Alias().also { it.name = "MyTest" }) beanClass.aliases = listOf(Alias().also { it.name = "MyTest" })
beanClass.pluginDescriptor = PluginManagerCore.getPlugin(VimPlugin.getPluginId())!!
return beanClass return beanClass
} }
} }

View File

@@ -22,6 +22,7 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.SelectionType import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.group.RegisterGroup
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
@@ -57,7 +58,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
val text = "" val text = ""
configureByText(text) configureByText(text)
VimPlugin.getRegister().storeTextInternal(myFixture.editor, TextRange(0, 0), "one", SelectionType.CHARACTER_WISE, '"', false) VimPlugin.getRegister().storeTextSpecial(RegisterGroup.UNNAMED_REGISTER, "one")
typeText(parseKeys("griw")) typeText(parseKeys("griw"))
myFixture.checkResult("on${c}e") myFixture.checkResult("on${c}e")
} }
@@ -66,7 +67,7 @@ class ReplaceWithRegisterTest : VimTestCase() {
val text = "${c}one" val text = "${c}one"
configureByText(text) configureByText(text)
VimPlugin.getRegister().storeText(myFixture.editor, "" rangeOf "", SelectionType.CHARACTER_WISE, false) VimPlugin.getRegister().storeTextSpecial(RegisterGroup.UNNAMED_REGISTER, "")
typeText(parseKeys("griw")) typeText(parseKeys("griw"))
myFixture.checkResult(c) myFixture.checkResult(c)
} }

View File

@@ -41,6 +41,6 @@ class InfoFileTest : VimTestCase() {
} }
private inline fun forEachAction(supply: (action: EditorActionHandlerBase) -> Unit) { private inline fun forEachAction(supply: (action: EditorActionHandlerBase) -> Unit) {
VIM_ACTIONS_EP.extensions.map { it.action }.forEach { supply(it) } VIM_ACTIONS_EP.extensions.map { it.instance }.forEach { supply(it) }
} }
} }

View File

@@ -23,6 +23,7 @@ import com.intellij.openapi.editor.Editor
import com.intellij.testFramework.PlatformTestUtil import com.intellij.testFramework.PlatformTestUtil
import com.maddyhome.idea.vim.helper.StringHelper import com.maddyhome.idea.vim.helper.StringHelper
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
import com.maddyhome.idea.vim.option.OptionsManager
import org.jetbrains.jetCheck.Generator import org.jetbrains.jetCheck.Generator
import org.jetbrains.jetCheck.ImperativeCommand import org.jetbrains.jetCheck.ImperativeCommand
import org.jetbrains.jetCheck.PropertyChecker import org.jetbrains.jetCheck.PropertyChecker
@@ -30,6 +31,8 @@ import org.jetbrains.plugins.ideavim.NeovimTesting
import org.jetbrains.plugins.ideavim.SkipNeovimReason import org.jetbrains.plugins.ideavim.SkipNeovimReason
import org.jetbrains.plugins.ideavim.TestWithoutNeovim import org.jetbrains.plugins.ideavim.TestWithoutNeovim
import org.jetbrains.plugins.ideavim.VimTestCase import org.jetbrains.plugins.ideavim.VimTestCase
import kotlin.math.absoluteValue
import kotlin.math.sign
class IncrementDecrementTest : VimPropertyTest() { class IncrementDecrementTest : VimPropertyTest() {
@TestWithoutNeovim(SkipNeovimReason.DIFFERENT) @TestWithoutNeovim(SkipNeovimReason.DIFFERENT)
@@ -48,6 +51,7 @@ class IncrementDecrementTest : VimPropertyTest() {
} }
fun testPlayingWithNumbersGenerateNumber() { fun testPlayingWithNumbersGenerateNumber() {
OptionsManager.nrformats.append("octal")
PropertyChecker.checkScenarios { PropertyChecker.checkScenarios {
ImperativeCommand { env -> ImperativeCommand { env ->
val number = env.generateValue(testNumberGenerator, "Generate %s number") val number = env.generateValue(testNumberGenerator, "Generate %s number")
@@ -85,15 +89,10 @@ private class IncrementDecrementActions(private val editor: Editor, val test: Vi
val differentFormNumberGenerator = Generator.from { env -> val differentFormNumberGenerator = Generator.from { env ->
val form = env.generate(Generator.sampledFrom(/*2,*/ 8, 10, 16)) val form = env.generate(Generator.sampledFrom(/*2,*/ 8, 10, 16))
env.generate(Generator.integers().map { env.generate(Generator.integers().suchThat { it != Int.MIN_VALUE }.map {
val str = it.toString(form) val sign = it.sign
val prefix = when (form) { val stringNumber = it.absoluteValue.toString(form)
2 -> "0b" if (sign < 0) "-$stringNumber" else stringNumber
8 -> "0"
16 -> "0x"
else -> ""
}
if (str[0] == '-') "-$prefix${str.substring(1)}" else "$prefix$str"
}) })
} }