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

Compare commits

..

221 Commits

Author SHA1 Message Date
9f469d0eb2 Set plugin version to chylex-13 2022-10-24 02:18:35 +02:00
f59d2f769c Stop IdeaVIM blocking editor scrolling 2022-10-24 02:18:35 +02:00
dc00b59733 Change matchit plugin to use HTML patterns in unrecognized files 2022-10-24 02:11:31 +02:00
bc20e6af9c Fix vim-surround not working with multiple cursors
Fixes multiple cursors with vim-surround commands `cs, ds, S` (but not `ys`).

 Conflicts:
	src/main/java/com/maddyhome/idea/vim/extension/surround/VimSurroundExtension.kt
2022-10-24 02:09:43 +02:00
c40f07714a Add VimScript 'renaming()' function 2022-10-24 02:04:59 +02:00
fa68842c2d Add support for repeatable actions with ':raction' 2022-10-24 02:04:59 +02:00
eca9258607 Disable taking over arrow keys and Home/End 2022-10-24 02:04:26 +02:00
46fb030977 Set custom plugin version 2022-10-24 02:04:25 +02:00
Alex Plate
da3d83ecc6 Update formatting 2022-10-23 00:26:59 +00:00
filipp
4af8e574c4 Log keystrokes only in ASCII 2022-10-19 14:59:09 +03:00
Alex Plate
bdcb5c4f33 Update colors 2022-10-18 16:56:43 +03:00
Alex Plate
013f7a42c2 [VIM-2774] Move visual toggle mode to another handler 2022-10-18 16:38:40 +03:00
Alex Plate
d03398f3e8 [VIM-2774] Move reset mode to another handler 2022-10-18 16:38:40 +03:00
Alex Plate
7a26307a2b [VIM-2774] Move caret swap to runForEachCaret 2022-10-18 16:38:40 +03:00
Alex Plate
fa6a0369b8 [VIM-2774] Remove runforEachCaret for other method 2022-10-18 16:38:40 +03:00
Alex Plate
ad8cb0ba09 [VIM-2774] Add conditional multicaret handler 2022-10-18 16:38:39 +03:00
Alex Plate
8125ce5072 Update changelog 2022-10-18 08:34:00 +00:00
Alex Plate
6c0cc7285f Fix(VIM-2766): Move NERDTree update to background thread 2022-10-18 11:31:15 +03:00
Alex Plate
d3424021c8 Fix(VIM-2768): Refactor listeners 2022-10-17 17:39:40 +03:00
Alex Plate
623aa40acd Update to java 17 2022-10-17 15:45:15 +03:00
Alex Plate
c131cb338e Update description in plugin.xml 2022-10-17 15:45:14 +03:00
filipp
14d242a233 Disable logging undefined handlers 2022-10-17 14:56:16 +03:00
Alex Plate
a131b7d29a Update IdeaVim motto 2022-10-17 12:35:05 +03:00
Alex Plate
85a1fbe89e Update links to github accounts 2022-10-11 09:23:07 +03:00
Alex Plate
142550a1f8 Use 2022.2.2 version of IJ by default 2022-10-04 09:48:35 +03:00
Alex Plate
e3d3b73903 Fix incompatiility with futur versions of IJ 2022-10-04 09:48:18 +03:00
Alex Plate
45f18ff91c Update formatting 2022-10-02 00:26:29 +00:00
Alex Pláte
2103163207 Update AUTHORS information 2022-09-29 09:10:19 +03:00
filipp
19dd49670c Statistic 2022-09-26 11:51:56 +03:00
Alex Plate
e738a1a821 Update formatting 2022-09-25 00:20:49 +00:00
filipp
6e0f301fb8 Fix(VIM-2757) Wrong gv behavior 2022-09-22 04:08:39 +03:00
filipp
c76b8db293 Fix(VIM-2718) Copied value is not inserted 2022-09-21 03:00:53 +03:00
Alex Plate
9fa4ca8fb3 Update formatting 2022-09-18 00:20:25 +00:00
Alex Plate
871b60fe8d Revert "[New Typing Handler]: Switch j command to new typing handler"
This reverts commit 43a79dba
2022-09-12 09:30:22 +03:00
Alex Plate
6715a5b61f Revert "[New Typing Handler]: Support d"
This reverts commit c32c62ea
2022-09-12 09:29:46 +03:00
Alex Plate
d7d91f1cc5 Add some tests for dd 2022-09-12 09:28:27 +03:00
Alex Plate
9f00dbd6f4 Update formatting 2022-09-11 00:19:01 +00:00
Alex Plate
f95cf3d671 Update changelog 2022-09-10 21:26:01 +00:00
filipp
7fbc17624f Fix(VIM-2718): Fixed case where the primary caret was changed 2022-09-11 00:24:06 +03:00
Alex Plate
b9c2ea37cb Update changelog 2022-09-09 14:21:51 +00:00
Alex Plate
ca0db15e01 Fix(VIM-2749): Fix :tabn and :tabN commands 2022-09-09 17:20:09 +03:00
Alex Plate
c32c62eacc [New Typing Handler]: Support d 2022-09-06 13:13:31 +03:00
Alex Plate
43a79dbad4 [New Typing Handler]: Switch j command to new typing handler 2022-09-05 15:22:10 +03:00
Alex Plate
2829a13187 Update gradle plugin 2022-09-05 12:32:08 +03:00
Alex Plate
efc8c9207d Update changelog 2022-08-29 06:37:12 +00:00
Alex Plate
183ed10592 Fix(VIM-2744): Fix undo from ex line 2022-08-29 09:31:55 +03:00
Alex Plate
926b47a31e Update gradle plugin 2022-08-29 09:31:34 +03:00
Alex Plate
d272c919ea Fill missing authors 2022-08-25 11:59:16 +03:00
Alex Plate
f6e7d04fd5 Fix accessing bookmarks
Tests were failing because IdeaVim group is created by default by project name
2022-08-25 11:59:05 +03:00
Alex Plate
ccdff4f087 TC: Fix missing import 2022-08-25 11:23:22 +03:00
Alex Plate
ff14303e88 TC: add tests for stable version of idea 2022-08-25 11:12:50 +03:00
Alex Plate
48a592340b Update test fixture 2022-08-23 15:27:00 +03:00
Alex Plate
da8f5f3231 Fix handler call from put command 2022-08-23 15:26:58 +03:00
Alex Plate
f8fa8b73fa Move some methods to vim engine 2022-08-23 15:26:55 +03:00
Alex Plate
aee126b625 Formatting 2022-08-23 15:26:53 +03:00
Alex Plate
396ac86939 Fix strange issue on ideavimrc reload 2022-08-23 15:26:50 +03:00
Alex Plate
81816f903f Update formatting 2022-08-21 00:17:52 +00:00
Alex Plate
06a85b784b Update changelog 2022-08-17 07:14:42 +00:00
Alex Plate
7f1e3bb155 Fix(VIM-1758): Commentary plugin in rider 2022-08-17 10:13:04 +03:00
Alex Plate
241f554133 Fix(VIM-1903): Autoindent now works in rider 2022-08-17 10:11:19 +03:00
Alex Plate
9498d0779c Revert "Refactoring IdeaVim to use editor actions instead of registering shortcuts in the editor"
This reverts commit b12fd5100f.
2022-08-15 18:59:35 +03:00
Alex Plate
b12fd5100f Refactoring IdeaVim to use editor actions instead of registering shortcuts in the editor 2022-08-15 18:42:32 +03:00
Alex Plate
92f622430d Revert "Add a hidden gem"
This reverts commit 362b9a5c3a.
2022-08-15 17:22:31 +03:00
Alex Plate
ef518f5b23 Revert "Rename hidden gem to neovim"
This reverts commit 4fd1a25557.
2022-08-15 17:22:31 +03:00
Alex Plate
7acb17ebdb Small update 2022-08-15 17:22:31 +03:00
Alex Plate
479a7dbbaf Update formatting 2022-08-14 00:17:52 +00:00
Alex Plate
4fd1a25557 Rename hidden gem to neovim 2022-08-12 12:14:17 +03:00
Alex Plate
f32d42e625 Nice knowledge popup 2022-08-12 12:10:57 +03:00
Alex Plate
362b9a5c3a Add a hidden gem 2022-08-12 10:49:55 +03:00
Alex Plate
e42b4d0ea3 Fix regex for changelog plugin 2022-08-12 10:14:31 +03:00
Alex Plate
43767b8500 Print error 2022-08-12 09:55:29 +03:00
Alex Plate
d05098c870 Update changelog 2022-08-12 06:47:15 +00:00
Alex Plate
505f485568 Update release version 2022-08-12 09:45:30 +03:00
Alex Plate
86f512fb91 Update for slack notification 2022-08-12 09:45:08 +03:00
Alex Plate
12903066b9 Workaround for VIM-2487 2022-08-12 09:45:07 +03:00
Alex Plate
118d0433cb Fix(VIM-2728): Give access to global variables 2022-08-12 09:45:07 +03:00
filipp
eb781c3679 An attempt to avoid "No tests found" emails 2022-08-11 03:50:07 +03:00
filipp
3c6bffba03 Fix(VIM-749) 2022-08-11 03:27:19 +03:00
Alex Plate
89623b04d6 Update changelog 2022-08-09 10:25:14 +03:00
Alex Plate
444a96132c Comment out test 2022-08-09 10:10:17 +03:00
Alex Plate
c008553127 Update TC constants 2022-08-09 09:51:25 +03:00
Alex Plate
162d7b021f Update reference to changes 2022-08-09 09:50:02 +03:00
Alex Plate
c82364c1dd Update changelog 2022-08-09 09:49:29 +03:00
Alex Plate
977402c6b0 Update changelog 2022-08-09 09:49:28 +03:00
Alex Plate
b14e59ab5b Disable removing selection after undo 2022-08-09 09:49:28 +03:00
Alex Plate
47dcefcfbf Update formatting 2022-08-07 00:20:00 +00:00
Alex Plate
2b299cb422 Cut white edges on the gif 2022-08-05 08:47:50 +03:00
Alex Plate
d0ccbb4620 Use correct git for dark mode 2022-08-05 08:44:21 +03:00
Alex Plate
187b207271 Use gif instead of mp4 2022-08-05 08:37:05 +03:00
Alex Plate
a3e22c844c Different gif in readme 2022-08-05 08:34:59 +03:00
Alex Plate
f8384b2732 Create dark screenshot for contributing 2022-08-05 08:16:38 +03:00
Alex Plate
2dae43258c Skip unsupported arguments in command
VIM-2720
2022-08-04 20:08:13 +03:00
Alex Plate
48033ecb85 Update changelog 2022-08-04 19:45:52 +03:00
Alex Plate
ad8df027ac Skip neovim check in extensions and multicaret tests 2022-08-04 19:44:58 +03:00
Alex Plate
91f580771d Fix test with closing buffer 2022-08-04 19:18:26 +03:00
Matt Ellis
9c6f0981f5 Consolidate doTest methods 2022-08-04 19:17:59 +03:00
Alex Plate
2212569688 Update changelog 2022-08-02 15:07:49 +00:00
Alex Plate
6711f1dbab Specify update thread for actions 2022-08-01 13:09:23 +03:00
Alex Plate
0b7a883efb Fix(VIM-2723): Move focus to editor after :q 2022-08-01 09:29:44 +03:00
Alex Plate
8ae84c62c0 Update changelog 2022-07-26 09:39:51 +03:00
Alex Plate
0d168c8115 Update formatting 2022-07-24 00:20:23 +00:00
c7b51b7fa5 Implement partial code completion support in macros
Works ok with insertions (Enter, Ctrl+Enter) but not with replacements (Tab)
2022-07-22 10:02:23 +03:00
aleksei.plate
86bf723791 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Qodana checks' build configuration were updated 2022-07-20 11:36:12 +00:00
Alex Plate
71f2e9de4a Update changelog 2022-07-20 08:20:43 +00:00
Alex Plate
33d3f270a3 Fix(VIM-2710): Show options value on set opt 2022-07-20 09:56:23 +03:00
filipp
da94edd386 Fix(VIM-2703) 2022-07-20 02:51:45 +06:00
Alex Plate
90dfaefd11 Update formatting 2022-07-17 00:17:41 +00:00
Alex Plate
8bc616cc55 New vim behaviour: ci( searches for brackets
Change in vim:
b9115da4be
https://github.com/vim/vim/pull/8670

VIM-2699
2022-07-14 12:08:26 +03:00
aleksei.plate
a9e79d62c5 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Qodana checks' build configuration were updated 2022-07-13 11:55:31 +00:00
Alex Plate
1998221a0b Remove useless @NotNull annotations 2022-07-13 10:26:57 +03:00
Alex Plate
a9b1625749 Update deprecated action listeners 2022-07-13 10:26:16 +03:00
Alex Plate
b411836570 Hide macos notification during UI testing 2022-07-13 09:23:35 +03:00
Alex Plate
df7e0221a8 Update qodana baseline 2022-07-11 14:10:08 +03:00
aleksei.plate
8ff8f2b685 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Qodana checks' build configuration were updated 2022-07-11 10:00:37 +00:00
aleksei.plate
65dea7e3f7 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Qodana checks' build configuration were updated 2022-07-11 09:45:28 +00:00
aleksei.plate
1942f86633 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim / IdeaVim releases' project: build features of 'Publish EAP Build' build configuration were updated 2022-07-11 08:29:56 +00:00
Alex Plate
ee4ce5033a Fix tests 2022-07-11 11:09:43 +03:00
Alex Plate
040fe806c8 Update release versions of IJ 2022-07-11 09:28:39 +03:00
Alex Plate
97f5c9225e Cleanup the sources 2022-07-08 11:24:10 +03:00
Alex Plate
09b86c15f9 Fix missing space 2022-07-08 10:59:02 +03:00
Alex Plate
8f34285d8c Fix issues with notations 2022-07-08 10:55:21 +03:00
Alex Plate
d3c3b71e3e Remove unnecessary libraries from the distribution 2022-07-08 10:29:51 +03:00
Alex Plate
aa6f49c9b1 Reformat code 2022-07-08 10:00:00 +03:00
Alex Plate
c011628420 Reformat code 2022-07-08 09:14:43 +03:00
Alex Plate
1c9fa9d662 Skip one test in multicaret 2022-07-07 16:32:14 +03:00
Alex Plate
7b9bc64364 Fix multicaret insert 2022-07-07 14:54:41 +03:00
Alex Plate
729062bfdd Turn on ideadelaymacro by default 2022-07-07 14:36:04 +03:00
Alex Plate
bc6c726a45 Fix macro with count execution 2022-07-07 14:35:49 +03:00
Alex Plate
dfc3df713e Update changelog 2022-07-07 12:22:46 +03:00
Alex Plate
42eca1d5f2 Apply TC patches 2022-07-07 11:20:10 +03:00
Alex Plate
66245e2730 Change secret for the merge PR action 2022-07-07 10:42:27 +03:00
aleksei.plate
d44b82c1d1 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'Plugin verification' build configuration settings were updated 2022-07-07 07:12:38 +00:00
aleksei.plate
5440e48fa3 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'Tests for IntelliJ 2021.3' build configuration was moved to 'IntelliJ IDEA plugins / IdeaVim / Old IdeaVim tests' project 2022-07-07 07:11:51 +00:00
aleksei.plate
1c513cf8aa TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: VCS roots of 'Tests for IntelliJ 2021.3' build configuration were updated 2022-07-07 07:11:26 +00:00
aleksei.plate
a17c4b8d43 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: VCS roots of 'Tests for IntelliJ 2021.3' build configuration were updated 2022-07-07 07:11:07 +00:00
aleksei.plate
15eb4ac278 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'https://github.com/JetBrains/ideavim (branch 213-221)' VCS root was created 2022-07-07 07:06:47 +00:00
Alex Plate
0d9b81eab3 Update minimal version of IJ 2022-07-07 10:02:14 +03:00
Alex Plate
f02e1a20c7 Create test update job 2022-07-06 21:23:48 +03:00
Alex Plate
a11991dad7 Create test token 2022-07-06 21:21:51 +03:00
Alex Plate
1238828bfd Update token name 2022-07-06 21:18:27 +03:00
Alex Plate
ba409cb24c Add some logging to update after PR job 2022-07-06 21:06:00 +03:00
Alex Plate
d597670275 Update changelog after merging PR 2022-07-06 17:58:16 +00:00
Alex Pláte
d8540e95f8 Create gradle.properties 2022-07-06 20:56:49 +03:00
Alex Plate
d35ebf00dd Add qodana baseline to the project (I guess) 2022-07-06 20:43:40 +03:00
Alex Plate
2b32cb26b1 Set since version in config 2022-07-06 20:39:30 +03:00
aleksei.plate
ca95fcb658 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Tests with nvim' build configuration were updated 2022-07-06 17:32:40 +00:00
aleksei.plate
cc18bbd168 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'Tests with nvim' build configuration settings were updated 2022-07-06 17:09:16 +00:00
Alex Plate
8c8ea800cb Update neovim tests 2022-07-06 20:06:02 +03:00
Alex Plate
0746dcc686 Fix some neovim tests 2022-07-06 19:41:05 +03:00
Alex Plate
930650be9d Add lippfi to contributors list 2022-07-06 07:36:26 +00:00
Alex Plate
4e3a9ffa40 Add unchecked email 2022-07-06 10:34:31 +03:00
filipp
3bf68a2bb8 Update formatting 2022-07-06 13:11:11 +06:00
Alex Plate
a80f6feab0 Update changelog 2022-07-06 09:30:25 +03:00
Alex Plate
3cf8ae52ed Add link to the docs 2022-07-06 09:30:25 +03:00
Matt Ellis
62632a4514 Improve handling of fractional width fonts 2022-07-06 09:29:36 +03:00
Alex Plate
249bd3778a Add a note about refactoring 2022-07-06 09:14:52 +03:00
filipp
ab9e5d7a4a Fix selection issue with oldundo set 2022-07-06 12:12:55 +06:00
filipp
083b7dc952 Fix(VIM-2698) Undo causes confirmation dialog to reappear forever 2022-07-06 11:35:29 +06:00
Alex Plate
1791692d92 Use java boolean 2022-07-05 12:26:16 +03:00
Alex Plate
ba23c9ab5e Rename variable service 2022-07-05 11:27:53 +03:00
Alex Plate
f96ab37bcb Rename Scope 2022-07-05 11:04:08 +03:00
Alex Plate
0da34bbb34 Compatibility of toggleOption 2022-07-05 10:56:45 +03:00
Alex Plate
51e7c745ea Move number option to a different package 2022-07-05 10:26:14 +03:00
aleksei.plate
8347251572 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: triggers of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-05 07:13:58 +00:00
aleksei.plate
ce8512f4e0 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: triggers of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-05 07:13:22 +00:00
aleksei.plate
a724a19d00 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: triggers of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-05 07:13:00 +00:00
Alex Plate
7eae7a98e8 Command state compatibility 2022-07-05 10:05:02 +03:00
Alex Plate
fe9566eebd Convert helper to kt 2022-07-04 10:59:24 +03:00
Alex Plate
b69756730f Rename .java to .kt 2022-07-04 10:59:23 +03:00
Alex Plate
6cd1a60b53 More compatibility 2022-07-04 10:33:31 +03:00
Alex Plate
9d935e47b5 Move compatibility 2022-07-04 09:49:50 +03:00
Alex Plate
a7d5372d06 Move classes to a different package 2022-07-04 09:49:50 +03:00
Alex Plate
a575942c81 Compatibility 2022-07-04 09:49:50 +03:00
aleksei.plate
3cf6c53a8e TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:40:47 +00:00
aleksei.plate
91d86680de TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:22:54 +00:00
aleksei.plate
d1d082fb99 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:15:19 +00:00
aleksei.plate
2c634d1bf0 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:06:43 +00:00
aleksei.plate
02a6fe4dc9 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:03:46 +00:00
aleksei.plate
223d681526 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: VCS roots of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:03:33 +00:00
aleksei.plate
f42ef1c2fc TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: VCS roots of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-07-04 06:03:27 +00:00
Alex Plate
f4817b2111 Add compatibility verifier to the repo 2022-07-04 08:59:31 +03:00
Alex Plate
6f5def0abf Update formatting 2022-07-03 00:19:25 +00:00
filipp
f0fcd7f133 Better offset for multiple carets with surround 2022-07-02 18:59:21 +06:00
filipp
6115adb72e Add registers to carets 2022-07-02 18:51:10 +06:00
filipp
bfd0b5fd91 Merge remote-tracking branch 'origin/master' 2022-07-02 11:21:33 +06:00
Alex Plate
6c0a52155b Add compatibility method 2022-07-01 16:36:30 +03:00
Alex Plate
c7ebce39bf Make options compatible 2022-07-01 16:10:13 +03:00
Alex Plate
a0dc7a792f Add more compatibility methods 2022-07-01 15:55:07 +03:00
Alex Plate
fdb09a8f1f Use vim-engine kotlin settings 2022-07-01 12:18:53 +03:00
Alex Plate
4ac2aa2339 Apply kotlin options to all projects 2022-07-01 11:29:15 +03:00
Alex Plate
ebbc20692a Add JVM compatibility option to the compiler 2022-07-01 10:58:32 +03:00
Alex Plate
5c82d112c9 More compatibility methods 2022-07-01 10:05:13 +03:00
Alex Plate
40fd50d7f1 Add midding import 2022-07-01 09:27:07 +03:00
Alex Plate
f7b948fee2 Add CommandState compatibility layer and rename our main CommandState to VimStateMachine 2022-07-01 09:04:27 +03:00
Alex Plate
6cdcf133bb Use snapshot version of gradle plugin 2022-06-30 09:14:29 +03:00
filipp
f3025757b6 Merge remote-tracking branch 'origin/master' 2022-06-30 11:02:41 +06:00
nikita.koshcheev
a49811a3f9 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: Updated cloud profile 'amazon-48' in project 'project55' 2022-06-29 15:16:26 +00:00
Alex Plate
2ac4b265d1 Add compatibility method 2022-06-29 16:30:26 +03:00
Alex Plate
46e994b563 Fix incorrect inheritance 2022-06-29 11:42:21 +03:00
Alex Plate
81482bd298 Add more compatibility changes 2022-06-29 11:25:11 +03:00
Alex Plate
f1a239c085 Make compatibility function public 2022-06-29 10:42:04 +03:00
Alex Plate
a48e38de7b Make function static 2022-06-29 10:25:41 +03:00
Alex Plate
0aaacee117 Add more classes for compatibility 2022-06-29 09:54:50 +03:00
Alex Plate
b8373af69f Move MappingMode to a different package 2022-06-29 09:54:49 +03:00
Alex Plate
e99b2ee73d Add new method for compatibility 2022-06-29 09:54:49 +03:00
aleksei.plate
705022331a TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: general settings of 'IdeaVim compatibility with external plugins' build configuration were updated 2022-06-28 08:48:58 +00:00
aleksei.plate
bf62d444bf TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: general settings of 'IdeaVim compatibility with external plugin' build configuration were updated 2022-06-28 08:47:35 +00:00
aleksei.plate
5dcff5657b TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: general settings of 'IdeaVim compativility with external plugin' build configuration were updated 2022-06-28 08:47:11 +00:00
Alex Plate
7e79d5a960 Add method for compatibility 2022-06-28 11:13:54 +03:00
Alex Plate
c1b480976d Include source files into distribution 2022-06-28 11:13:54 +03:00
Alex Plate
ddabbe6891 Use vim-engine as API instead of implementation 2022-06-28 11:13:54 +03:00
Alex Plate
ffa3052b50 Update build version of IJ 2022-06-28 11:13:54 +03:00
Alex Plate
654ea88851 Add collecting of sources to the resulting jar 2022-06-28 11:13:54 +03:00
filipp
4dc7982baa (EA-480768) Better exception message 2022-06-27 16:19:45 +06:00
aleksei.plate
ae2fc1cd85 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: runners of 'Build' build configuration were updated 2022-06-27 06:17:38 +00:00
aleksei.plate
78bc8666e6 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: build features of 'Build' build configuration were updated 2022-06-27 06:16:33 +00:00
aleksei.plate
9c2de2cfc7 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: build configuration was created from URL 2022-06-27 06:16:18 +00:00
aleksei.plate
71e81465f3 TeamCity change in 'IntelliJ IDEA plugins / IdeaVim' project: 'IdeaVimCompatibility' VCS root was created 2022-06-27 06:15:35 +00:00
Alex Plate
885031e086 Fix test class without test methods 2022-06-27 07:59:22 +03:00
Alex Plate
d77c5bb5cf Update formatting 2022-06-26 00:20:17 +00:00
Alex Plate
781bce0000 Update changelog 2022-06-24 05:27:52 +00:00
566 changed files with 91313 additions and 8968 deletions

View File

@@ -4,6 +4,7 @@
name: Update Changelog On PR
on:
workflow_dispatch:
pull_request:
types: [ closed ]
@@ -29,7 +30,7 @@ jobs:
id: update_authors
run: ./gradlew updateMergedPr -PprId=${{ github.event.number }}
env:
GITHUB_OAUTH: ${{ secrets.AUTOMATION_TOKEN }}
GITHUB_OAUTH: ${{ secrets.MERGE_PR }}
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4

40
.github/workflows/mergePrTest.yml vendored Normal file
View File

@@ -0,0 +1,40 @@
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle
name: Update Changelog On PR (Test)
on:
workflow_dispatch:
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
with:
fetch-depth: 50
- name: Set up JDK 11
uses: actions/setup-java@v2
with:
java-version: '11'
distribution: 'adopt'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file
- name: Update authors
id: update_authors
run: ./gradlew updateMergedPr -PprId=525
env:
GITHUB_OAUTH: ${{ secrets.MERGE_PR }}
# - name: Commit changes
# uses: stefanzweifel/git-auto-commit-action@v4
# with:
# branch: master
# commit_message: Update changelog after merging PR
# commit_user_name: Alex Plate
# commit_user_email: aleksei.plate@jetbrains.com
# commit_author: Alex Plate <aleksei.plate@jetbrains.com>
# file_pattern: CHANGES.md

View File

@@ -37,7 +37,7 @@ jobs:
run: ./gradlew updateAuthors --stacktrace
env:
SUCCESS_COMMIT: ${{ steps.last_successful_commit.outputs.commit_hash }}
GITHUB_OAUTH: ${{ secrets.AUTOMATION_TOKEN }}
GITHUB_OAUTH: ${{ secrets.GITHUB_TOKEN }}
- name: Commit changes
uses: stefanzweifel/git-auto-commit-action@v4

View File

@@ -5,15 +5,16 @@ object Constants {
const val EAP_CHANNEL = "eap"
const val DEV_CHANNEL = "Dev"
const val VERSION = "1.10.3"
const val DEV_VERSION = "1.11.0"
const val VERSION = "1.11.1"
const val DEV_VERSION = "1.12.0"
const val GITHUB_TESTS = "LATEST-EAP-SNAPSHOT"
const val NVIM_TESTS = "LATEST-EAP-SNAPSHOT"
const val PROPERTY_TESTS = "LATEST-EAP-SNAPSHOT"
const val LONG_RUNNING_TESTS = "LATEST-EAP-SNAPSHOT"
const val QODANA_TESTS = "LATEST-EAP-SNAPSHOT"
const val RELEASE = "2021.3"
const val RELEASE = "LATEST-EAP-SNAPSHOT"
const val RELEASE_DEV = "LATEST-EAP-SNAPSHOT"
const val RELEASE_EAP = "LATEST-EAP-SNAPSHOT"
}

View File

@@ -1,6 +1,13 @@
package _Self
import _Self.buildTypes.*
import _Self.buildTypes.Compatibility
import _Self.buildTypes.LongRunning
import _Self.buildTypes.Nvim
import _Self.buildTypes.PluginVerifier
import _Self.buildTypes.PropertyBased
import _Self.buildTypes.Qodana
import _Self.buildTypes.TestsForIntelliJ20222
import _Self.buildTypes.TestsForIntelliJEAP
import _Self.subprojects.GitHub
import _Self.subprojects.OldTests
import _Self.subprojects.Releases
@@ -10,6 +17,7 @@ import _Self.vcsRoots.Branch_191_193
import _Self.vcsRoots.Branch_201
import _Self.vcsRoots.Branch_202
import _Self.vcsRoots.Branch_203_212
import _Self.vcsRoots.Branch_213_221
import _Self.vcsRoots.Branch_Release
import _Self.vcsRoots.GitHubPullRequest
import jetbrains.buildServer.configs.kotlin.v2019_2.Project
@@ -26,18 +34,20 @@ object Project : Project({
vcsRoot(Branch_201)
vcsRoot(Branch_202)
vcsRoot(Branch_203_212)
vcsRoot(Branch_213_221)
vcsRoot(Branch_Release)
vcsRoot(GitHubPullRequest)
// Builds
buildType(TestsForIntelliJ20213)
buildType(TestsForIntelliJEAP)
buildType(TestsForIntelliJ20222)
buildType(PropertyBased)
buildType(LongRunning)
buildType(Nvim)
buildType(PluginVerifier)
buildType(Compatibility)
buildType(Qodana)
@@ -47,7 +57,7 @@ object Project : Project({
type = "CloudImage"
id = "PROJECT_EXT_768"
param("agent_pool_id", "41")
param("amazon-id", "ami-0d1a6a32faa92923e")
param("amazon-id", "ami-0fa17ce8238eb8868")
param("ebs-optimized", "false")
param("image-instances-limit", "")
param("image-name-prefix", "BuildAgentsIdeaVim")

View File

@@ -55,4 +55,4 @@ sealed class ActiveTests(buildName: String, ijVersion: String) : BuildType({
})
object TestsForIntelliJEAP : ActiveTests("Tests for IntelliJ Latest EAP", "LATEST-EAP-SNAPSHOT")
object TestsForIntelliJ20213 : ActiveTests("Tests for IntelliJ 2021.3", "2021.3.2")
object TestsForIntelliJ20222 : ActiveTests("Tests for IntelliJ 2022.2", "2022.2.1")

View File

@@ -0,0 +1,49 @@
package _Self.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.golang
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.script
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule
object Compatibility : BuildType({
id("IdeaVimCompatibility")
name = "IdeaVim compatibility with external plugins"
vcs {
root(DslContext.settingsRoot)
}
steps {
script {
name = "Check"
scriptContent = """
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}org.jetbrains.IdeaVim-EasyMotion' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}io.github.mishkun.ideavimsneak' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}IdeaVimExtension' [latest-IU] -team-city
# Outdated java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}github.zgqq.intellij-enhance' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.github.copilot' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.github.dankinsoid.multicursor' [latest-IU] -team-city
java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}com.joshestein.ideavim-quickscope' [latest-IU] -team-city
""".trimIndent()
}
}
triggers {
schedule {
schedulingPolicy = daily {
hour = 4
}
branchFilter = ""
triggerBuild = always()
withPendingChangesOnly = false
}
}
features {
golang {
testFormat = "json"
}
}
})

View File

@@ -31,7 +31,7 @@ object Nvim : BuildType({
script {
name = "Set up NeoVim"
scriptContent = """
wget https://github.com/neovim/neovim/releases/download/v0.4.4/nvim-linux64.tar.gz
wget https://github.com/neovim/neovim/releases/download/v0.7.2/nvim-linux64.tar.gz
tar xzf nvim-linux64.tar.gz
cd nvim-linux64/bin
chmod +x nvim

View File

@@ -4,6 +4,7 @@ import _Self.Constants.QODANA_TESTS
import jetbrains.buildServer.configs.kotlin.v2019_2.BuildType
import jetbrains.buildServer.configs.kotlin.v2019_2.CheckoutMode
import jetbrains.buildServer.configs.kotlin.v2019_2.DslContext
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.Qodana
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana
import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.BuildFailureOnMetric
import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange
@@ -46,12 +47,15 @@ object Qodana : BuildType({
param("clonefinder-enable", "true")
param("clonefinder-reference-projects", "src")
param("yaml-configuration", "")
linter = jvm {
version = Qodana.JVMVersion.LATEST
}
}
}
triggers {
vcs {
enabled = false
enabled = true
branchFilter = ""
}
schedule {

View File

@@ -0,0 +1,62 @@
@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.failureConditions.BuildFailureOnMetric
import jetbrains.buildServer.configs.kotlin.v2019_2.failureConditions.failOnMetricChange
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
sealed class TestsForIntelliJ_213_221_branch(private val version: String) : BuildType({
name = "Tests for IntelliJ $version"
params {
param("env.ORG_GRADLE_PROJECT_downloadIdeaSources", "false")
param("env.ORG_GRADLE_PROJECT_legacyNoJavaPlugin", "true")
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_213_221)
checkoutMode = CheckoutMode.AUTO
}
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")
}
failureConditions {
failOnMetricChange {
metric = BuildFailureOnMetric.MetricType.TEST_COUNT
threshold = 20
units = BuildFailureOnMetric.MetricUnit.PERCENTS
comparison = BuildFailureOnMetric.MetricComparison.LESS
compareTo = build {
buildRule = lastSuccessful()
}
}
}
})
object TestsForIntelliJ20213 : TestsForIntelliJ_213_221_branch("2021.3.2")

View File

@@ -11,6 +11,7 @@ import _Self.buildTypes.TestsForIntelliJ20202
import _Self.buildTypes.TestsForIntelliJ20203
import _Self.buildTypes.TestsForIntelliJ20211
import _Self.buildTypes.TestsForIntelliJ20212
import _Self.buildTypes.TestsForIntelliJ20213
import jetbrains.buildServer.configs.kotlin.v2019_2.Project
object OldTests : Project({
@@ -28,4 +29,5 @@ object OldTests : Project({
buildType(TestsForIntelliJ20203)
buildType(TestsForIntelliJ20211)
buildType(TestsForIntelliJ20212)
buildType(TestsForIntelliJ20213)
})

View File

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

View File

@@ -1,25 +0,0 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.VcsTrigger
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, change the buildType with id = 'Nvim'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("Nvim")) {
triggers {
val trigger1 = find<VcsTrigger> {
vcs {
branchFilter = ""
}
}
trigger1.apply {
enabled = false
}
}
}

View File

@@ -1,25 +0,0 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.VcsTrigger
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.vcs
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, change the buildType with id = 'PluginVerifier'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("PluginVerifier")) {
triggers {
val trigger1 = find<VcsTrigger> {
vcs {
branchFilter = ""
}
}
trigger1.apply {
enabled = false
}
}
}

View File

@@ -2,9 +2,8 @@ package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.Qodana
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.gradle
import jetbrains.buildServer.configs.kotlin.v2019_2.buildSteps.qodana
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.ScheduleTrigger
import jetbrains.buildServer.configs.kotlin.v2019_2.triggers.schedule
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/*
@@ -16,9 +15,8 @@ changeBuildType(RelativeId("Qodana")) {
expectSteps {
qodana {
name = "Qodana"
reportAsTests = true
inspectionProfile = customProfile {
path = ".idea/inspectionProfiles/Qodana.xml"
linter = jvm {
version = Qodana.JVMVersion.LATEST
}
param("clonefinder-enable", "true")
param("clonefinder-languages", "Java")
@@ -26,7 +24,6 @@ changeBuildType(RelativeId("Qodana")) {
param("clonefinder-mode", "")
param("clonefinder-queried-project", "src")
param("clonefinder-reference-projects", "src")
param("fail-build-on-errors", "")
param("licenseaudit-enable", "true")
param("namesAndTagsCustom", "repo.labs.intellij.net/static-analyser/qodana")
param("report-version", "")
@@ -34,27 +31,25 @@ changeBuildType(RelativeId("Qodana")) {
}
}
steps {
update<Qodana>(0) {
insert(0) {
gradle {
name = "Generate grammar"
tasks = "generateGrammarSource"
param("org.jfrog.artifactory.selectedDeployableServer.defaultModuleVersionConfiguration", "GLOBAL")
}
}
update<Qodana>(1) {
clearConditions()
linter = jvm {
version = Qodana.JVMVersion.LATEST
}
}
}
triggers {
val trigger1 = find<ScheduleTrigger> {
schedule {
schedulingPolicy = weekly {
dayOfWeek = ScheduleTrigger.DAY.Tuesday
}
branchFilter = ""
triggerBuild = always()
}
}
trigger1.apply {
enabled = false
reportAsTests = true
argumentsCommandDocker = "-e QODANA_TOKEN=eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJvcmdhbml6YXRpb24iOiIzUFZrQSIsInByb2plY3QiOiIzN1FlQSIsInRva2VuIjoiM0t2bXoifQ.uohp81tM7iAfvvB6k8faarfpV-OjusAaEbWQ8iNrOgs"
argumentsEntryPointDocker = "--baseline qodana.sarif.json"
param("clonefinder-languages", "")
param("collect-anonymous-statistics", "")
param("licenseaudit-enable", "")
param("clonefinder-languages-container", "")
param("clonefinder-queried-project", "")
param("clonefinder-enable", "")
param("clonefinder-reference-projects", "")
}
}
}

View File

@@ -0,0 +1,27 @@
package patches.buildTypes
import jetbrains.buildServer.configs.kotlin.v2019_2.*
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.VcsLabeling
import jetbrains.buildServer.configs.kotlin.v2019_2.buildFeatures.vcsLabeling
import jetbrains.buildServer.configs.kotlin.v2019_2.ui.*
/*
This patch script was generated by TeamCity on settings change in UI.
To apply the patch, change the buildType with id = 'ReleaseEap'
accordingly, and delete the patch script.
*/
changeBuildType(RelativeId("ReleaseEap")) {
features {
val feature1 = find<VcsLabeling> {
vcsLabeling {
vcsRootId = "${DslContext.settingsRoot.id}"
labelingPattern = "%system.build.number%"
successfulOnly = true
branchFilter = ""
}
}
feature1.apply {
successfulOnly = false
}
}
}

View File

@@ -32,16 +32,48 @@ Contributors:
[![icon][github]](https://github.com/yole)
&nbsp;
Dmitry Jemerov
* [![icon][mail]](mailto:tony.kay@gmail.com)
[![icon][github]](https://github.com/awkay)
&nbsp;
Tony Kay
* [![icon][mail]](mailto:jamescmartinez@gmail.com)
[![icon][github]](https://github.com/jamescmartinez)
&nbsp;
James Martinez
* [![icon][mail]](mailto:almas337519@gmail.com)
[![icon][github]](https://github.com/strogiyotec)
&nbsp;
strogiyotec
* [![icon][mail]](mailto:raimon49@hotmail.com)
[![icon][github]](https://github.com/raimon49)
&nbsp;
raimon
* [![icon][mail]](mailto:agrsbm@gmail.com)
[![icon][github-off]](#)
&nbsp;
Alexander Griesbaum
* [![icon][mail]](mailto:manwe64@gmail.com)
[![icon][github]](https://github.com/baldrs)
&nbsp;
Baldrs
* [![icon][mail]](mailto:yury@shurup.com)
[![icon][github]](https://github.com/zyv)
&nbsp;
Yury V. Zaytsev
* [![icon][mail]](mailto:jflorian@doubledog.org)
[![icon][github]](https://github.com/jflorian)
&nbsp;
John Florian
* [![icon][mail]](mailto:marquis@marquiswang.com)
[![icon][github]](https://github.com/marquiswang)
&nbsp;
Marquis Wang
* [![icon][mail]](mailto:madgnome@gmail.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/madgnome)
&nbsp;
Julien Hoarau
* [![icon][mail]](mailto:masanobu.imai@gmail.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/masanobuimai)
&nbsp;
Masanobu Imai
* [![icon][mail]](mailto:poxvuibr@gmail.com)
@@ -57,7 +89,7 @@ Contributors:
&nbsp;
John Lindquist
* [![icon][mail]](mailto:iklotzko@ltech.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/iklotzko)
&nbsp;
Ira Klotzko
* [![icon][mail]](mailto:alex@selesse.com)
@@ -65,7 +97,7 @@ Contributors:
&nbsp;
Alex Selesse
* [![icon][mail]](mailto:dbennett@palantir.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/dathanb)
&nbsp;
Dathan Bennett
* [![icon][mail]](mailto:kphayen@gmail.com)
@@ -77,11 +109,11 @@ Contributors:
&nbsp;
Alexey Shmalko
* [![icon][mail]](mailto:a.m.brookins@gmail.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/abrookins)
&nbsp;
Andrew Brookins
* [![icon][mail]](mailto:changwang83@gmail.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/changwang)
&nbsp;
Chang Wang
* [![icon][mail]](mailto:josejaime.sanchez@gmail.com)
@@ -89,19 +121,19 @@ Contributors:
&nbsp;
Jaime Sanchez
* [![icon][mail]](mailto:thomas@homburg.dk)
[![icon][github-off]](#)
[![icon][github]](https://github.com/homburg)
&nbsp;
Thomas B Homburg
* [![icon][mail]](mailto:smartbomb@server.fake)
[![icon][github-off]](#)
[![icon][github]](https://github.com/smartbomb)
&nbsp;
smartbomb
* [![icon][mail]](mailto:tuomas.tynkkynen@iki.fi)
[![icon][github-off]](#)
[![icon][github]](https://github.com/dezgeg)
&nbsp;
Tuomas Tynkkynen
* [![icon][mail]](mailto:jackson@donorschoose.org)
[![icon][github-off]](#)
[![icon][github]](https://github.com/jdpopkin)
&nbsp;
Jackson Popkin
* [![icon][mail]](mailto:yuyuyu1999@gmail.com)
@@ -109,7 +141,7 @@ Contributors:
&nbsp;
Teruo Kunihiro
* [![icon][mail]](mailto:lubashka.994@mail.ru)
[![icon][github-off]](#)
[![icon][github]](https://github.com/lubba)
&nbsp;
Liubov Paina
* [![icon][mail]](mailto:me@dhleong.net)
@@ -137,7 +169,7 @@ Contributors:
&nbsp;
tieTYT
* [![icon][mail]](mailto:nickgieschen@gmail.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/nickgieschen)
&nbsp;
Nick Gieschen
* [![icon][mail]](mailto:ikenox@gmail.com)
@@ -149,7 +181,7 @@ Contributors:
&nbsp;
Maximilian Luz
* [![icon][mail]](mailto:vparfinenko@excelsior-usa.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/cypok)
&nbsp;
Vladimir Parfinenko
* [![icon][mail]](mailto:hassmann@hwdev.de)
@@ -193,7 +225,7 @@ Contributors:
&nbsp;
Marcel Hild
* [![icon][mail]](mailto:vedranb@gmail.com)
[![icon][github-off]](#)
[![icon][github]](https://github.com/vedran)
&nbsp;
Vedran Budimcic
* [![icon][mail]](mailto:andreigasparovici1@gmail.com)
@@ -208,10 +240,13 @@ Contributors:
[![icon][github]](https://github.com/TonyArra)
&nbsp;
Tony Arra
* [![icon][mail]](mailto:bradziolko@gmail.com)
[![icon][github]](https://github.com/bradziolko)
* [![icon][mail]](mailto:mj@ziolko.dev)
[![icon][github]](https://github.com/mjziolko)
&nbsp;
Brad Ziolko
Madeline Ziolko
[Original contribution from:
[![icon][mail]](mailto:bradziolko@gmail.com)
[![icon][github]](https://github.com/bradziolko)]
* [![icon][mail]](mailto:sumoooru2@gmail.com)
[![icon][github]](https://github.com/sumoooru2)
&nbsp;
@@ -416,6 +451,10 @@ Contributors:
[![icon][github]](https://github.com/Vvalter)
&nbsp;
Simon Rainer
* [![icon][mail]](mailto:filipp.vakhitov@jetbrains.com)
[![icon][github]](https://github.com/lippfi)
&nbsp;
lippfi
If you are a contributor and your name is not listed here, feel free to
contact the maintainers.

View File

@@ -25,6 +25,17 @@ usual beta standards.
## To Be Released
### Fixes:
* [VIM-1758](https://youtrack.jetbrains.com/issue/VIM-1758) Commentary plugin in rider
* [VIM-1903](https://youtrack.jetbrains.com/issue/VIM-1903) Autoindent now works in rider
* [VIM-2744](https://youtrack.jetbrains.com/issue/VIM-2744) Fix undo from ex line
* [VIM-2749](https://youtrack.jetbrains.com/issue/VIM-2749) Fix :tabn and :tabN commands
* [VIM-2718](https://youtrack.jetbrains.com/issue/VIM-2718) Fixed case where the primary caret was changed
* [VIM-2766](https://youtrack.jetbrains.com/issue/VIM-2766) Move NERDTree update to background thread
* [VIM-2768](https://youtrack.jetbrains.com/issue/VIM-2768) Refactor listeners
## 1.11.0, 2022-08-09
### Features:
* Add `gcu` command for Commentary plugin
* Add `:Commentary` command, which works great for commands such as `:%g/fun/Commentary`
@@ -36,6 +47,7 @@ usual beta standards.
E.g. `<Plug>Commentary` instead of `<Plug>(CommentMotion)`. Old mappings are maintained for compatibility.
* If you open `~/.ideavimrc` in IDE, remove a mapping, and reload the config using the reload button,
the mapping will actually be unmapped.
* New vim (and IdeaVim) behaviour: `ci(`& friends searches for the brackets in the line.
### Fixes:
* [VIM-2587](https://youtrack.jetbrains.com/issue/VIM-2587) Use ctrl-6 as ctrl-^
@@ -52,10 +64,14 @@ usual beta standards.
* [VIM-2595](https://youtrack.jetbrains.com/issue/VIM-2595) Support plugins in macro execution
* [VIM-2671](https://youtrack.jetbrains.com/issue/VIM-2671) Fix using plugins from mappings
* [VIM-2675](https://youtrack.jetbrains.com/issue/VIM-2675) Fix numbering register in visual mode
* [VIM-696](https://youtrack.jetbrains.com/issue/VIM-696/vim-selection-issue-after-undo) Fix selection after undo
* [VIM-744](https://youtrack.jetbrains.com/issue/VIM-744/Use-undoredo-with-count-modifier) Add count to undo/redo
* [VIM-1862](https://youtrack.jetbrains.com/issue/VIM-1862/Ex-commands-executed-in-keymaps-and-macros-are-added-to-the-command-history) Fix command history
* [VIM-2227](https://youtrack.jetbrains.com/issue/VIM-2227) Wrong behavior when deleting / changing surround with invalid character
* [VIM-2691](https://youtrack.jetbrains.com/issue/VIM-2691) Save file on :w
* [VIM-2710](https://youtrack.jetbrains.com/issue/VIM-2710) Show options value on `set opt`
* [VIM-913](https://youtrack.jetbrains.com/issue/VIM-913) Partially fix the issue with macros and autocompletion
* [VIM-2723](https://youtrack.jetbrains.com/issue/VIM-2723) Move focus to editor after :q
* [VIM-2728](https://youtrack.jetbrains.com/issue/VIM-2728) Give access to global variables
### Merged PRs:
* [468](https://github.com/JetBrains/ideavim/pull/468) by [Thomas Schouten](https://github.com/PHPirates): Implement UserDataHolder for EditorDataContext
@@ -65,6 +81,10 @@ usual beta standards.
* [494](https://github.com/JetBrains/ideavim/pull/494) by [Matt Ellis](https://github.com/citizenmatt): Cleanup pre-212 CaretVisualAttributes compatibility code
* [504](https://github.com/JetBrains/ideavim/pull/504) by [Matt Ellis](https://github.com/citizenmatt): Minor bug fixes
* [519](https://github.com/JetBrains/ideavim/pull/519) by [chylex](https://github.com/chylex): Fix(VIM-2227): Wrong behavior when deleting / changing surround with invalid character
* [525](https://github.com/JetBrains/ideavim/pull/525) by [Matt Ellis](https://github.com/citizenmatt): Improve handling of fractional width fonts
* [526](https://github.com/JetBrains/ideavim/pull/526) by [Alex Pláte](https://github.com/AlexPl292): Create gradle.properties
* [528](https://github.com/JetBrains/ideavim/pull/528) by [chylex](https://github.com/chylex): Implement partial code completion support in macros
* [531](https://github.com/JetBrains/ideavim/pull/531) by [Matt Ellis](https://github.com/citizenmatt): Consolidate doTest methods
## 1.10.0, 2022-02-17

View File

@@ -5,7 +5,7 @@ IdeaVim is an open source project created by 80+ contributors. Would you like to
This page is created to help you start contributing. And who knows, maybe in a few days this project will be brighter than ever!
:warning: The plugin is currently under a huge refactoring aiming to split into vim-engine and IdeaVim in order to
support the new [Fleet IDE](https://www.jetbrains.com/fleet/).
support the new [Fleet IDE](https://www.jetbrains.com/fleet/). Please see [Fleet refactoring](#Fleet-refactoring).
## Before you begin
@@ -32,7 +32,7 @@ OK, ready to do some coding?
Yoo hoo! Youre all set to begin contributing.
We've prepared some useful configurations for you:
![Prepared configurations](assets/contributing/configurations.png)
![Prepared configurations light](assets/contributing/configs-light.png#gh-light-mode-only)![Prepared configurations dark](assets/contributing/configs-dark.png#gh-dark-mode-only)
And here are useful gradle commands:
@@ -120,6 +120,17 @@ so you can reuse your `.vimrc` settings.
We also support proper command mappings (functions are mapped to `<Plug>...`), the operator function (`OperatorFunction`), and so on.
- Magic is supported as well. See `Magic`.
## Fleet refactoring
At the moment, IdeaVim is under an active refactoring aiming to split IdeaVim into two modules: vim-engine and IdeaVim.
If you develop a plugin that depends on IdeaVim: We have an instrument to check that our changes don't affect
the plugins in the marketplace. Also, we commit to support currently used API at least till the end of 2022.
If you still encounter any issues with the newer versions of IdeaVim, please [contact maintainers](https://github.com/JetBrains/ideavim#contact-maintainers).
We kindly ask you not to use anything from the new API (like `VimEditor`, `injector`) because at the moment we don't
guarantee the compatibility of this API in the future versions.
-----
### I read the whole page but something is still unclear.

View File

@@ -11,7 +11,7 @@ IdeaVim
[![Gitter][gitter-svg]][gitter]
[![Twitter][twitter-svg]][twitter]
IdeaVim is a Vim emulation plugin for IntelliJ Platform-based IDEs.
IdeaVim is a Vim engine for JetBrains IDEs.
##### Contact maintainers:
* [Bug tracker](https://youtrack.jetbrains.com/issues/VIM)
@@ -36,7 +36,7 @@ Setup
- IdeaVim can be installed via `Settings | Plugins`.
See the [detailed instructions](https://www.jetbrains.com/help/idea/managing-plugins.html#).
- Use `Tools | Vim Emulator` in the menu to enable or disable emulation.
- Use `Tools | Vim` in the menu to enable or disable vim.
- Use the `~/.ideavimrc` file as an analog of `~/.vimrc` ([learn more](#Files)). The XDG standard is supported, as well.
@@ -88,7 +88,7 @@ Here are some examples of supported vim features and commands:
* Vim web help
* `~/.ideavimrc` configuration file
[Emulated Vim plugins](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins):
[IdeaVim plugins](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins):
* vim-easymotion
* NERDTree
@@ -198,7 +198,7 @@ Alternatively, you can set up initialization commands using [XDG](https://specif
Put your settings to `$XDG_CONFIG_HOME/ideavim/ideavimrc` file.
Emulated Vim Plugins
IdeaVim Plugins
--------------------
See [doc/emulated-plugins.md](https://github.com/JetBrains/ideavim/wiki/Emulated-plugins)
@@ -226,7 +226,10 @@ Ex commands or via `:map` command mappings:
<details>
<summary><strong>"Track action Ids" Details</strong> (click to see)</summary>
<img src="assets/readme/track_action_id.gif" alt="track action ids"/>
<picture>
<source media="(prefers-color-scheme: dark)" srcset="assets/readme/track_action_dark.gif">
<img src="assets/readme/track_action_light.gif" alt="track action ids"/>
</picture>
</details>

Binary file not shown.

After

Width:  |  Height:  |  Size: 27 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.0 MiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

View File

@@ -15,7 +15,9 @@ buildscript {
classpath("com.github.AlexPl292:mark-down-to-slack:1.1.2")
classpath("org.eclipse.jgit:org.eclipse.jgit:6.1.0.202203080745-r")
classpath("org.kohsuke:github-api:1.305")
classpath("org.jetbrains:markdown:0.3.1")
// This comes from the changelog plugin
// classpath("org.jetbrains:markdown:0.3.1")
}
}
@@ -24,11 +26,11 @@ plugins {
java
kotlin("jvm") version "1.6.21"
id("org.jetbrains.intellij") version "1.6.0"
id("org.jetbrains.intellij") version "1.10.0-SNAPSHOT"
id("org.jetbrains.changelog") version "1.3.1"
// ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
id("org.jlleitschuh.gradle.ktlint") version "10.2.1"
id("org.jlleitschuh.gradle.ktlint") version "10.3.0"
}
// Import variables from gradle.properties file
@@ -70,7 +72,9 @@ dependencies {
runtimeOnly("org.antlr:antlr4-runtime:$antlrVersion")
antlr("org.antlr:antlr4:$antlrVersion")
implementation(project(":vim-engine"))
api(project(":vim-engine"))
testApi("com.squareup.okhttp3:okhttp:4.10.0")
}
configurations {
@@ -85,6 +89,8 @@ tasks.register<Test>("testWithNeovim") {
group = "verification"
systemProperty("ideavim.nvim.test", "true")
exclude("/ui/**")
exclude("**/longrunning/**")
exclude("**/propertybased/**")
}
tasks.register<Test>("testPropertyBased") {
@@ -115,6 +121,8 @@ tasks {
include("**/*test.class")
include("**/*Tests.class")
exclude("**/ParserTest.class")
exclude("**/longrunning/**")
exclude("**/propertybased/**")
}
val testPropertyBased by getting(Test::class) {
@@ -144,19 +152,32 @@ tasks {
compileKotlin {
kotlinOptions {
jvmTarget = javaVersion
apiVersion = "1.5"
apiVersion = "1.6"
freeCompilerArgs = listOf("-Xjvm-default=all-compatibility")
// allWarningsAsErrors = true
}
}
compileTestKotlin {
kotlinOptions {
jvmTarget = javaVersion
apiVersion = "1.5"
apiVersion = "1.6"
// allWarningsAsErrors = true
}
}
}
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(javaVersion))
}
}
kotlin {
jvmToolchain {
(this as JavaToolchainSpec).languageVersion.set(JavaLanguageVersion.of(javaVersion))
}
}
gradle.projectsEvaluated {
tasks.compileJava {
// options.compilerArgs.add("-Werror")
@@ -199,7 +220,7 @@ tasks {
runPluginVerifier {
downloadDir.set("${project.buildDir}/pluginVerifier/ides")
teamCityOutputFormat.set(true)
ideVersions.set(listOf("IC-2021.3.4"))
// ideVersions.set(listOf("IC-2021.3.4"))
}
generateGrammarSource {
@@ -211,12 +232,37 @@ tasks {
named("compileKotlin") {
dependsOn("generateGrammarSource")
}
// Add plugin open API sources to the plugin ZIP
val createOpenApiSourceJar by registering(Jar::class) {
// Java sources
from(sourceSets.main.get().java) {
include("**/com/maddyhome/idea/vim/**/*.java")
}
// Kotlin sources
from(kotlin.sourceSets.main.get().kotlin) {
include("**/com/maddyhome/idea/vim/**/*.kt")
}
destinationDirectory.set(layout.buildDirectory.dir("libs"))
archiveClassifier.set("src")
}
buildPlugin {
dependsOn(createOpenApiSourceJar)
from(createOpenApiSourceJar) { into("lib/src") }
}
// Don't forget to update plugin.xml
patchPluginXml {
sinceBuild.set("222")
}
}
// --- Linting
ktlint {
disabledRules.add("no-wildcard-imports")
version.set("0.43.0")
}
// --- Tests
@@ -241,7 +287,7 @@ changelog {
itemPrefix.set("*")
path.set("${project.projectDir}/CHANGES.md")
unreleasedTerm.set("To Be Released")
headerParserRegex.set("\\d\\.\\d+(.\\d+)?".toRegex())
headerParserRegex.set("(\\d\\.\\d+(.\\d+)?)".toRegex())
// header = { "${project.version}" }
// version = "0.60"
}
@@ -294,20 +340,30 @@ tasks.register("slackNotification") {
println("Response code: $postRc")
if (postRc == 200) {
println(inputStream.bufferedReader().use { it.readText() })
} else {
println(errorStream.bufferedReader().use { it.readText() })
}
}
}
}
// --- Update authors
// Uncomment to enable FUS testing mode
// tasks {
// withType<org.jetbrains.intellij.tasks.RunIdeTask> {
// jvmArgs("-Didea.is.internal=true")
// jvmArgs("-Dfus.internal.test.mode=true")
// }
// }
// --- Update authors
tasks.register("updateAuthors") {
doLast {
val uncheckedEmails = setOf(
"aleksei.plate@jetbrains.com",
"aleksei.plate@teamcity",
"aleksei.plate@TeamCity",
"alex.plate@192.168.0.109"
"alex.plate@192.168.0.109",
"nikita.koshcheev@TeamCity",
)
updateAuthors(uncheckedEmails)
}
@@ -318,6 +374,7 @@ val prId: String by project
tasks.register("updateMergedPr") {
doLast {
if (project.hasProperty("prId")) {
println("Got pr id: $prId")
updateMergedPr(prId.toInt())
} else {
error("Cannot get prId")
@@ -481,7 +538,9 @@ data class Change(val id: String, val text: String)
fun updateMergedPr(number: Int) {
val gitHub = org.kohsuke.github.GitHub.connect()
println("Connecting to the repo...")
val repository = gitHub.getRepository("JetBrains/ideavim")
println("Getting pull requests...")
val pullRequest = repository.getPullRequest(number)
if (pullRequest.user.login == "dependabot[bot]") return

View File

@@ -1,11 +1,11 @@
# suppress inspection "UnusedProperty" for whole file
ideaVersion=LATEST-EAP-SNAPSHOT
ideaVersion=2022.2.2
downloadIdeaSources=true
instrumentPluginCode=true
version=SNAPSHOT
javaVersion=11
remoteRobotVersion=0.11.10
version=chylex-13
javaVersion=17
remoteRobotVersion=0.11.15
antlrVersion=4.10.1
# Please don't forget to update kotlin version in buildscript section

79982
qodana.sarif.json Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -1,3 +1,13 @@
// Set repository for snapshot versions of gradle plugin
pluginManagement {
repositories {
maven {
url 'https://oss.sonatype.org/content/repositories/snapshots/'
}
gradlePluginPortal()
}
}
rootProject.name = 'IdeaVIM'
include 'vim-engine'

View File

@@ -27,6 +27,7 @@ import com.intellij.openapi.editor.EditorFactory;
import com.intellij.openapi.editor.actionSystem.TypedAction;
import com.intellij.openapi.editor.actionSystem.TypedActionHandler;
import com.intellij.openapi.editor.event.*;
import com.intellij.openapi.util.Disposer;
import com.maddyhome.idea.vim.helper.HandlerInjector;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -101,38 +102,41 @@ public class EventFacade {
EditorFactory.getInstance().addEditorFactoryListener(listener, parentDisposable);
}
@SuppressWarnings("deprecation")
public void removeEditorFactoryListener(@NotNull EditorFactoryListener listener) {
// Listener is removed not only if application is disposed
EditorFactory.getInstance().removeEditorFactoryListener(listener);
}
public void addEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) {
editor.addEditorMouseListener(listener);
public void addEditorMouseListener(@NotNull Editor editor,
@NotNull EditorMouseListener listener,
@NotNull Disposable disposable) {
editor.addEditorMouseListener(listener, disposable);
}
public void removeEditorMouseListener(@NotNull Editor editor, @NotNull EditorMouseListener listener) {
editor.removeEditorMouseListener(listener);
}
public void addComponentMouseListener(@NotNull Component component, @NotNull MouseListener mouseListener) {
public void addComponentMouseListener(@NotNull Component component,
@NotNull MouseListener mouseListener,
@NotNull Disposable disposable) {
component.addMouseListener(mouseListener);
Disposer.register(disposable, () -> component.removeMouseListener(mouseListener));
}
public void removeComponentMouseListener(@NotNull Component component, @NotNull MouseListener mouseListener) {
component.removeMouseListener(mouseListener);
}
public void addEditorMouseMotionListener(@NotNull Editor editor, @NotNull EditorMouseMotionListener listener) {
editor.addEditorMouseMotionListener(listener);
public void addEditorMouseMotionListener(@NotNull Editor editor,
@NotNull EditorMouseMotionListener listener,
@NotNull Disposable disposable) {
editor.addEditorMouseMotionListener(listener, disposable);
}
public void removeEditorMouseMotionListener(@NotNull Editor editor, @NotNull EditorMouseMotionListener listener) {
editor.removeEditorMouseMotionListener(listener);
}
public void addEditorSelectionListener(@NotNull Editor editor, @NotNull SelectionListener listener) {
editor.getSelectionModel().addSelectionListener(listener);
public void addEditorSelectionListener(@NotNull Editor editor,
@NotNull SelectionListener listener,
@NotNull Disposable disposable) {
editor.getSelectionModel().addSelectionListener(listener, disposable);
}
public void removeEditorSelectionListener(@NotNull Editor editor, @NotNull SelectionListener listener) {

View File

@@ -18,8 +18,14 @@
package com.maddyhome.idea.vim
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
import com.intellij.openapi.project.Project
import com.intellij.openapi.project.ProjectManagerListener
import com.intellij.openapi.startup.StartupActivity
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.localEditors
import com.maddyhome.idea.vim.options.OptionScope
/**
* @author Alex Plate
@@ -36,3 +42,19 @@ class PluginStartup : StartupActivity.DumbAware/*, LightEditCompatible*/ {
VimPlugin.getInstance().initialize()
}
}
// This is a temporal workaround for VIM-2487
class PyNotebooksCloseWorkaround : ProjectManagerListener {
override fun projectClosingBeforeSave(project: Project) {
val close = injector.optionService.getOptionValue(OptionScope.GLOBAL, "closenotebooks").asBoolean()
if (close) {
localEditors().forEach { editor ->
val virtualFile = EditorHelper.getVirtualFile(editor)
if (virtualFile?.extension == "ipynb") {
val fileEditorManager = FileEditorManagerEx.getInstanceEx(project)
fileEditorManager.closeFile(virtualFile)
}
}
}
}
}

View File

@@ -19,8 +19,6 @@ package com.maddyhome.idea.vim;
import com.intellij.ide.plugins.IdeaPluginDescriptor;
import com.intellij.ide.plugins.PluginManagerCore;
import com.intellij.notification.Notification;
import com.intellij.notification.NotificationListener;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.application.Application;
import com.intellij.openapi.application.ApplicationManager;
@@ -32,9 +30,9 @@ import com.intellij.openapi.extensions.PluginId;
import com.intellij.openapi.keymap.Keymap;
import com.intellij.openapi.keymap.ex.KeymapManagerEx;
import com.intellij.openapi.keymap.impl.DefaultKeymap;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.util.Disposer;
import com.intellij.openapi.util.SystemInfo;
import com.maddyhome.idea.vim.api.VimInjectorKt;
import com.maddyhome.idea.vim.api.VimKeyGroup;
@@ -48,20 +46,17 @@ import com.maddyhome.idea.vim.group.visual.VisualMotionGroup;
import com.maddyhome.idea.vim.helper.MacKeyRepeat;
import com.maddyhome.idea.vim.listener.VimListenerManager;
import com.maddyhome.idea.vim.newapi.IjVimInjector;
import com.maddyhome.idea.vim.options.OptionService;
import com.maddyhome.idea.vim.ui.StatusBarIconFactory;
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable;
import com.maddyhome.idea.vim.ui.ex.ExEntryPanel;
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage;
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService;
import com.maddyhome.idea.vim.vimscript.services.VimVariableService;
import com.maddyhome.idea.vim.vimscript.services.OptionService;
import com.maddyhome.idea.vim.vimscript.services.VariableService;
import org.jdom.Element;
import org.jetbrains.annotations.Nls;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import javax.swing.event.HyperlinkEvent;
import static com.maddyhome.idea.vim.group.EditorGroup.EDITOR_STORE_ELEMENT;
import static com.maddyhome.idea.vim.group.KeyGroup.SHORTCUT_CONFLICTS_ELEMENT;
import static com.maddyhome.idea.vim.vimscript.services.VimRcService.executeIdeaVimRc;
@@ -94,6 +89,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
private final @NotNull VimState state = new VimState();
public Disposable onOffDisposable;
VimPlugin() {
ApplicationConfigurationMigrator.getInstance().migrate();
}
@@ -117,7 +114,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
@Override
public void dispose() {
LOG.debug("disposeComponent");
turnOffPlugin();
turnOffPlugin(false);
LOG.debug("done");
}
@@ -226,8 +223,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
return (PutGroup)VimInjectorKt.getInjector().getPut();
}
public static @NotNull VimVariableService getVariableService() {
return ApplicationManager.getApplication().getService(VimVariableService.class);
public static @NotNull VariableService getVariableService() {
return ApplicationManager.getApplication().getService(VariableService.class);
}
public static @NotNull OptionService getOptionService() {
@@ -275,7 +272,7 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
if (isEnabled() == enabled) return;
if (!enabled) {
getInstance().turnOffPlugin();
getInstance().turnOffPlugin(true);
}
getInstance().enabled = enabled;
@@ -341,6 +338,8 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
* execution, what theoretically may cause bugs (e.g. VIM-2540)
*/
private void turnOnPlugin() {
onOffDisposable = Disposer.newDisposable(this, "IdeaVimOnOffDisposer");
// 1) Update state
ApplicationManager.getApplication().invokeLater(this::updateState);
@@ -366,16 +365,20 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
VimListenerManager.INSTANCE.turnOn();
}
private void turnOffPlugin() {
private void turnOffPlugin(boolean unsubscribe) {
SearchGroup searchGroup = getSearchIfCreated();
if (searchGroup != null) {
searchGroup.turnOff();
}
VimListenerManager.INSTANCE.turnOff();
if (unsubscribe) {
VimListenerManager.INSTANCE.turnOff();
}
ExEntryPanel.fullReset();
// Unregister vim actions in command mode
RegisterActions.unregisterActions();
Disposer.dispose(onOffDisposable);
}
private boolean stateUpdated = false;
@@ -389,7 +392,9 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
final Boolean enabled = keyRepeat.isEnabled();
final Boolean isKeyRepeat = getEditor().isKeyRepeat();
if ((enabled == null || !enabled) && (isKeyRepeat == null || isKeyRepeat)) {
if (VimPlugin.getNotifications().enableRepeatingMode() == Messages.YES) {
// This system property is used in IJ ui robot to hide the startup tips
boolean showNotification = Boolean.getBoolean("ide.show.tips.on.startup.default.value");
if (showNotification && VimPlugin.getNotifications().enableRepeatingMode() == Messages.YES) {
getEditor().setKeyRepeat(true);
keyRepeat.setEnabled(true);
}
@@ -408,12 +413,6 @@ public class VimPlugin implements PersistentStateComponent<Element>, Disposable
keymap = manager.getKeymap(DefaultKeymap.getInstance().getDefaultKeymapName());
}
assert keymap != null : "Default keymap not found";
VimPlugin.getNotifications().specialKeymap(keymap, new NotificationListener.Adapter() {
@Override
protected void hyperlinkActivated(@NotNull Notification notification, @NotNull HyperlinkEvent e) {
ShowSettingsUtil.getInstance().showSettingsDialog(null, VimEmulationConfigurable.class);
}
});
manager.setActiveKeymap(keymap);
}
if (previousStateVersion > 0 && previousStateVersion < 4) {

View File

@@ -19,6 +19,7 @@
package com.maddyhome.idea.vim.action
import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.project.DumbAwareToggleAction
import com.maddyhome.idea.vim.VimPlugin
@@ -42,4 +43,6 @@ class VimPluginToggleAction : DumbAwareToggleAction()/*, LightEditCompatible*/ {
if (VimPlugin.isEnabled()) MessageHelper.message("action.VimPluginToggle.enabled") else MessageHelper.message("action.VimPluginToggle.enable")
} else MessageHelper.message("action.VimPluginToggle.text")
}
override fun getActionUpdateThread() = ActionUpdateThread.BGT
}

View File

@@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.action
import com.google.common.collect.ImmutableSet
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.EmptyAction
@@ -95,6 +96,10 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
}
}
// There is a chance that we can use BGT, but we call for isCell inside the update.
// Not sure if can can use BGT with this call. Let's use EDT for now.
override fun getActionUpdateThread() = ActionUpdateThread.EDT
override fun update(e: AnActionEvent) {
val start = if (traceTime) System.currentTimeMillis() else null
e.presentation.isEnabled = isEnabled(e)
@@ -148,6 +153,10 @@ class VimShortcutKeyAction : AnAction(), DumbAware/*, LightEditCompatible*/ {
if (keyCode == KeyEvent.VK_TAB && editor.isTemplateActive()) return false
if ((keyCode == KeyEvent.VK_TAB || keyCode == KeyEvent.VK_ENTER) && editor.appCodeTemplateCaptured()) return false
if (keyCode == KeyEvent.VK_LEFT || keyCode == KeyEvent.VK_RIGHT) return false
if (keyCode == KeyEvent.VK_UP || keyCode == KeyEvent.VK_DOWN) return false
if (keyCode == KeyEvent.VK_HOME || keyCode == KeyEvent.VK_END) return false
if (editor.inInsertMode) {
if (keyCode == KeyEvent.VK_TAB) {

View File

@@ -22,6 +22,7 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
@@ -34,13 +35,13 @@ import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.handler.VisualOperatorActionHandler
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.ij
import java.util.*
private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textRange: TextRange, selectionType: SelectionType): Boolean {
val operatorFunction = VimPlugin.getKey().operatorFunction
val operatorFunction = injector.keyGroup.operatorFunction
if (operatorFunction == null) {
VimPlugin.showMessage(MessageHelper.message("E774"))
return false
@@ -49,7 +50,7 @@ private fun doOperatorAction(editor: VimEditor, context: ExecutionContext, textR
val saveRepeatHandler = VimRepeater.repeatHandler
VimPlugin.getMark().setChangeMarks(editor, textRange)
KeyHandler.getInstance().reset(editor)
val result = operatorFunction.apply(editor.ij, context.ij, selectionType)
val result = operatorFunction.apply(editor, context, selectionType)
VimRepeater.repeatHandler = saveRepeatHandler
return result
}
@@ -61,7 +62,7 @@ class OperatorAction : VimActionHandler.SingleExecution() {
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val argument = cmd.argument ?: return false
if (!editor.commandState.isDotRepeatInProgress) {
if (!editor.vimStateMachine.isDotRepeatInProgress) {
argumentCaptured = argument
}
val range = getMotionRange(editor, context, argument, operatorArguments)

View File

@@ -25,14 +25,14 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.handler.VimActionHandler
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.ij
class RepeatChangeAction : VimActionHandler.SingleExecution() {
override val type: Command.Type = Command.Type.OTHER_WRITABLE
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
val state = editor.commandState
val state = editor.vimStateMachine
val lastCommand = VimRepeater.lastChangeCommand
if (lastCommand == null && Extension.lastExtensionHandler == null) return false

View File

@@ -45,7 +45,7 @@ class DeleteJoinLinesAction : ChangeEditorActionHandler.SingleExecution() {
val res = arrayOf(true)
editor.forEachNativeCaret(
{ caret: VimCaret ->
if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false)) res[0] = false
if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, false, operatorArguments)) res[0] = false
},
true
)

View File

@@ -45,7 +45,7 @@ class DeleteJoinLinesSpacesAction : ChangeEditorActionHandler.SingleExecution()
val res = arrayOf(true)
editor.forEachNativeCaret(
{ caret: VimCaret ->
if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true)) res[0] = false
if (!injector.changeGroup.deleteJoinLines(editor, caret, operatorArguments.count1, true, operatorArguments)) res[0] = false
},
true
)

View File

@@ -57,7 +57,14 @@ class DeleteJoinVisualLinesAction : VisualOperatorActionHandler.SingleExecution(
caret: VimCaret ->
if (!caret.isValid) return@forEachNativeCaret
val range = caretsAndSelections[caret] ?: return@forEachNativeCaret
if (!injector.changeGroup.deleteJoinRange(editor, caret, range.toVimTextRange(true).normalize(), false)) {
if (!injector.changeGroup.deleteJoinRange(
editor,
caret,
range.toVimTextRange(true).normalize(),
false,
operatorArguments
)
) {
res[0] = false
}
}, true

View File

@@ -56,7 +56,14 @@ class DeleteJoinVisualLinesSpacesAction : VisualOperatorActionHandler.SingleExec
{ caret: VimCaret ->
if (!caret.isValid) return@forEachNativeCaret
val range = caretsAndSelections[caret] ?: return@forEachNativeCaret
if (!injector.changeGroup.deleteJoinRange(editor, caret, range.toVimTextRange(true).normalize(), true)) {
if (!injector.changeGroup.deleteJoinRange(
editor,
caret,
range.toVimTextRange(true).normalize(),
true,
operatorArguments
)
) {
res[0] = false
}
},

View File

@@ -18,6 +18,7 @@
package com.maddyhome.idea.vim.action.internal
import com.intellij.ide.ui.AntialiasingType
import com.intellij.ide.ui.UISettings
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
@@ -124,7 +125,7 @@ class AddBlockInlaysAction : AnAction() {
val editorContext = FontInfo.getFontRenderContext(editor.contentComponent)
return FontRenderContext(
editorContext.transform, AntialiasingType.getKeyForCurrentScope(false),
if (editor is EditorImpl) editor.myFractionalMetricsHintValue else RenderingHints.VALUE_FRACTIONALMETRICS_OFF
if (editor is EditorImpl) UISettings.editorFractionalMetricsHint else RenderingHints.VALUE_FRACTIONALMETRICS_OFF
)
}

View File

@@ -0,0 +1,97 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2022 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.command
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.vim
/**
* COMPATIBILITY-LAYER: Additional class
* Please see: https://jb.gg/zo8n0r
*/
class CommandState(private val machine: VimStateMachine) {
val isOperatorPending: Boolean
get() = machine.isOperatorPending
val mode: CommandState.Mode
get() = machine.mode.ij
val commandBuilder: CommandBuilder
get() = machine.commandBuilder
val mappingState: MappingState
get() = machine.mappingState
enum class Mode {
// Basic modes
COMMAND, VISUAL, SELECT, INSERT, CMD_LINE, /*EX*/
// Additional modes
OP_PENDING, REPLACE /*, VISUAL_REPLACE*/, INSERT_NORMAL, INSERT_VISUAL, INSERT_SELECT
}
enum class SubMode {
NONE, VISUAL_CHARACTER, VISUAL_LINE, VISUAL_BLOCK
}
companion object {
@JvmStatic
fun getInstance(editor: Editor): CommandState {
return CommandState(editor.vim.vimStateMachine)
}
}
}
val CommandState.SubMode.engine: VimStateMachine.SubMode
get() = when (this) {
CommandState.SubMode.NONE -> VimStateMachine.SubMode.NONE
CommandState.SubMode.VISUAL_CHARACTER -> VimStateMachine.SubMode.VISUAL_CHARACTER
CommandState.SubMode.VISUAL_LINE -> VimStateMachine.SubMode.VISUAL_LINE
CommandState.SubMode.VISUAL_BLOCK -> VimStateMachine.SubMode.VISUAL_BLOCK
}
val CommandState.Mode.engine: VimStateMachine.Mode
get() = when (this) {
CommandState.Mode.COMMAND -> VimStateMachine.Mode.COMMAND
CommandState.Mode.VISUAL -> VimStateMachine.Mode.VISUAL
CommandState.Mode.SELECT -> VimStateMachine.Mode.SELECT
CommandState.Mode.INSERT -> VimStateMachine.Mode.INSERT
CommandState.Mode.CMD_LINE -> VimStateMachine.Mode.CMD_LINE
CommandState.Mode.OP_PENDING -> VimStateMachine.Mode.OP_PENDING
CommandState.Mode.REPLACE -> VimStateMachine.Mode.REPLACE
CommandState.Mode.INSERT_NORMAL -> VimStateMachine.Mode.INSERT_NORMAL
CommandState.Mode.INSERT_VISUAL -> VimStateMachine.Mode.INSERT_VISUAL
CommandState.Mode.INSERT_SELECT -> VimStateMachine.Mode.INSERT_SELECT
}
val VimStateMachine.Mode.ij: CommandState.Mode
get() = when (this) {
VimStateMachine.Mode.COMMAND -> CommandState.Mode.COMMAND
VimStateMachine.Mode.VISUAL -> CommandState.Mode.VISUAL
VimStateMachine.Mode.SELECT -> CommandState.Mode.SELECT
VimStateMachine.Mode.INSERT -> CommandState.Mode.INSERT
VimStateMachine.Mode.CMD_LINE -> CommandState.Mode.CMD_LINE
VimStateMachine.Mode.OP_PENDING -> CommandState.Mode.OP_PENDING
VimStateMachine.Mode.REPLACE -> CommandState.Mode.REPLACE
VimStateMachine.Mode.INSERT_NORMAL -> CommandState.Mode.INSERT_NORMAL
VimStateMachine.Mode.INSERT_VISUAL -> CommandState.Mode.INSERT_VISUAL
VimStateMachine.Mode.INSERT_SELECT -> CommandState.Mode.INSERT_SELECT
}

View File

@@ -23,14 +23,15 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.change.Extension
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.CommandAlias
import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.helper.CommandLineHelper
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.TestInputModel
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.vim
@@ -48,6 +49,22 @@ import javax.swing.KeyStroke
object VimExtensionFacade {
/** The 'map' command for mapping keys to handlers defined in extensions. */
@JvmStatic
fun putExtensionHandlerMapping(
modes: Set<MappingMode>,
fromKeys: List<KeyStroke>,
pluginOwner: MappingOwner,
extensionHandler: ExtensionHandler,
recursive: Boolean,
) {
VimPlugin.getKey().putKeyMapping(modes, fromKeys, pluginOwner, extensionHandler, recursive)
}
/**
* COMPATIBILITY-LAYER: Additional method
* Please see: https://jb.gg/zo8n0r
*/
/** The 'map' command for mapping keys to handlers defined in extensions. */
@JvmStatic
fun putExtensionHandlerMapping(
modes: Set<MappingMode>,
fromKeys: List<KeyStroke>,
@@ -110,7 +127,7 @@ object VimExtensionFacade {
/** Sets the value of 'operatorfunc' to be used as the operator function in 'g@'. */
@JvmStatic
fun setOperatorFunction(function: OperatorFunction) {
VimPlugin.getKey().setOperatorFunction(function)
VimPlugin.getKey().operatorFunction = function
}
/**
@@ -129,7 +146,7 @@ object VimExtensionFacade {
/** Returns a single key stroke from the user input similar to 'getchar()'. */
@JvmStatic
fun inputKeyStroke(editor: Editor): KeyStroke {
if (editor.vim.commandState.isDotRepeatInProgress) {
if (editor.vim.vimStateMachine.isDotRepeatInProgress) {
val input = Extension.consumeKeystroke()
return input ?: error("Not enough keystrokes saved: ${Extension.lastExtensionHandler}")
}
@@ -137,7 +154,7 @@ object VimExtensionFacade {
val key: KeyStroke? = if (ApplicationManager.getApplication().isUnitTestMode) {
val mappingStack = KeyHandler.getInstance().keyStack
mappingStack.feedSomeStroke() ?: TestInputModel.getInstance(editor).nextKeyStroke()?.also {
if (editor.vim.commandState.isRecording) {
if (editor.vim.vimStateMachine.isRecording) {
KeyHandler.getInstance().modalEntryKeys += it
}
}
@@ -167,12 +184,24 @@ object VimExtensionFacade {
return reg.keys
}
@JvmStatic
fun getRegisterForCaret(register: Char, caret: VimCaret): List<KeyStroke>? {
val reg = caret.registerStorage.getRegister(caret, register) ?: return null
return reg.keys
}
/** Set the current contents of the given register */
@JvmStatic
fun setRegister(register: Char, keys: List<KeyStroke?>?) {
VimPlugin.getRegister().setKeys(register, keys?.filterNotNull() ?: emptyList())
}
/** Set the current contents of the given register */
@JvmStatic
fun setRegisterForCaret(register: Char, caret: VimCaret, keys: List<KeyStroke?>?) {
caret.registerStorage.setKeys(caret, register, keys?.filterNotNull() ?: emptyList())
}
/** Set the current contents of the given register */
@JvmStatic
fun setRegister(register: Char, keys: List<KeyStroke?>?, type: SelectionType) {

View File

@@ -0,0 +1,39 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2022 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.extension
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.newapi.ij
/**
* COMPATIBILITY-LAYER: Created a class, renamed original class
* Please see: https://jb.gg/zo8n0r
*/
interface VimExtensionHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
execute(editor.ij, context.ij)
}
fun execute(editor: Editor, context: DataContext)
abstract class WithCallback : ExtensionHandler.WithCallback(), VimExtensionHandler
}

View File

@@ -25,9 +25,9 @@ import com.maddyhome.idea.vim.api.VimExtensionRegistrator
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.ex.ExException
import com.maddyhome.idea.vim.key.MappingOwner.Plugin.Companion.remove
import com.maddyhome.idea.vim.option.ToggleOption
import com.maddyhome.idea.vim.options.OptionChangeListener
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.options.ToggleOption
import com.maddyhome.idea.vim.statistic.PluginState
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimDataType

View File

@@ -18,24 +18,21 @@
package com.maddyhome.idea.vim.extension.argtextobj;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.command.*;
import com.maddyhome.idea.vim.common.MappingMode;
import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.extension.VimExtension;
import com.maddyhome.idea.vim.extension.VimExtensionHandler;
import com.maddyhome.idea.vim.extension.ExtensionHandler;
import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
import com.maddyhome.idea.vim.helper.InlayHelperKt;
import com.maddyhome.idea.vim.helper.MessageHelper;
import com.maddyhome.idea.vim.helper.VimNlsSafe;
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor;
import com.maddyhome.idea.vim.listener.VimListenerSuppressor;
import com.maddyhome.idea.vim.newapi.IjExecutionContext;
import com.maddyhome.idea.vim.newapi.IjVimCaret;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString;
@@ -186,7 +183,7 @@ public class VimArgTextObjExtension implements VimExtension {
/**
* A text object for an argument to a function definition or a call.
*/
static class ArgumentHandler implements VimExtensionHandler {
static class ArgumentHandler implements ExtensionHandler {
final boolean isInner;
ArgumentHandler(boolean isInner) {
@@ -262,17 +259,17 @@ public class VimArgTextObjExtension implements VimExtension {
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context) {
IjVimEditor vimEditor = (IjVimEditor) editor;
@NotNull CommandState commandState = CommandState.getInstance(vimEditor);
int count = Math.max(1, commandState.getCommandBuilder().getCount());
@NotNull VimStateMachine vimStateMachine = VimStateMachine.getInstance(vimEditor);
int count = Math.max(1, vimStateMachine.getCommandBuilder().getCount());
final ArgumentTextObjectHandler textObjectHandler = new ArgumentTextObjectHandler(isInner);
//noinspection DuplicatedCode
if (!commandState.isOperatorPending()) {
if (!vimStateMachine.isOperatorPending()) {
vimEditor.getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
final TextRange range = textObjectHandler.getRange(vimEditor, new IjVimCaret(caret), context, count, 0, null);
if (range != null) {
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
if (commandState.getMode() == CommandState.Mode.VISUAL) {
if (vimStateMachine.getMode() == VimStateMachine.Mode.VISUAL) {
vimSetSelection(caret, range.getStartOffset(), range.getEndOffset() - 1, true);
} else {
InlayHelperKt.moveToInlayAwareOffset(caret, range.getStartOffset());
@@ -282,8 +279,8 @@ public class VimArgTextObjExtension implements VimExtension {
});
} else {
commandState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
textObjectHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags.class))));
vimStateMachine.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
textObjectHandler, Command.Type.MOTION, EnumSet.noneOf(CommandFlags.class))));
}
}
}

View File

@@ -17,10 +17,11 @@
*/
package com.maddyhome.idea.vim.extension.commentary
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.codeInsight.actions.AsyncActionExecutionService
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.util.Ref
import com.intellij.psi.PsiComment
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
@@ -34,13 +35,14 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.TextObjectVisualType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.addCommand
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
@@ -48,55 +50,72 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.handler.TextObjectActionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.PsiHelper
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import java.util.*
class CommentaryExtension : VimExtension {
companion object {
fun doCommentary(editor: VimEditor, context: ExecutionContext, range: TextRange, selectionType: SelectionType, resetCaret: Boolean): Boolean {
val mode = editor.commandState.mode
if (mode !== CommandState.Mode.VISUAL) {
fun doCommentary(
editor: VimEditor,
context: ExecutionContext,
range: TextRange,
selectionType: SelectionType,
resetCaret: Boolean,
): Boolean {
val mode = editor.vimStateMachine.mode
if (mode !== VimStateMachine.Mode.VISUAL) {
editor.ij.selectionModel.setSelection(range.startOffset, range.endOffset)
}
return runWriteAction {
try {
// Treat block- and character-wise selections as block comments. Be ready to fall back to if the first action
// isn't available
val actions = if (selectionType === SelectionType.LINE_WISE) {
listOf(IdeActions.ACTION_COMMENT_LINE, IdeActions.ACTION_COMMENT_BLOCK)
} else {
listOf(IdeActions.ACTION_COMMENT_BLOCK, IdeActions.ACTION_COMMENT_LINE)
}
injector.actionExecutor.executeAction(actions[0], context) ||
injector.actionExecutor.executeAction(actions[1], context)
} finally {
// Remove the selection, if we added it
if (mode !== CommandState.Mode.VISUAL) {
editor.removeSelection()
}
// Put the caret back at the start of the range, as though it was moved by the operator's motion argument.
// This is what Vim does. If IntelliJ is configured to add comments at the start of the line, this might put
// the caret in the "wrong" place. E.g. gc_ should put the caret on the first non-whitespace character. This
// is calculated by the motion, saved in the marks, and then we insert the comment. If it's inserted at the
// first non-whitespace character, then the caret is in the right place. If it's inserted at the first column,
// then the caret is now in a bit of a weird place. We can't detect this scenario, so we just have to accept
// the difference
if (resetCaret) {
editor.primaryCaret().moveToOffset(range.startOffset)
}
// Treat block- and character-wise selections as block comments. Be ready to fall back to if the first action
// isn't available
val actions = if (selectionType === SelectionType.LINE_WISE) {
listOf(IdeActions.ACTION_COMMENT_LINE, IdeActions.ACTION_COMMENT_BLOCK)
} else {
listOf(IdeActions.ACTION_COMMENT_BLOCK, IdeActions.ACTION_COMMENT_LINE)
}
val res = Ref.create<Boolean>(true)
AsyncActionExecutionService.getInstance(editor.ij.project!!).withExecutionAfterAction(actions[0], {
res.set(injector.actionExecutor.executeAction(actions[0], context))
}, { afterCommenting(mode, editor, resetCaret, range) })
if (!res.get()) {
AsyncActionExecutionService.getInstance(editor.ij.project!!).withExecutionAfterAction(actions[1], {
res.set(injector.actionExecutor.executeAction(actions[1], context))
}, { afterCommenting(mode, editor, resetCaret, range) })
}
res.get()
}
}
private fun afterCommenting(
mode: VimStateMachine.Mode,
editor: VimEditor,
resetCaret: Boolean,
range: TextRange,
) {
// Remove the selection, if we added it
if (mode !== VimStateMachine.Mode.VISUAL) {
editor.removeSelection()
}
// Put the caret back at the start of the range, as though it was moved by the operator's motion argument.
// This is what Vim does. If IntelliJ is configured to add comments at the start of the line, this might put
// the caret in the "wrong" place. E.g. gc_ should put the caret on the first non-whitespace character. This
// is calculated by the motion, saved in the marks, and then we insert the comment. If it's inserted at the
// first non-whitespace character, then the caret is in the right place. If it's inserted at the first column,
// then the caret is now in a bit of a weird place. We can't detect this scenario, so we just have to accept
// the difference
if (resetCaret) {
editor.primaryCaret().moveToOffset(range.startOffset)
}
}
}
@@ -112,7 +131,13 @@ class CommentaryExtension : VimExtension {
putKeyMappingIfMissing(MappingMode.NXO, injector.parser.parseKeys("gc"), owner, plugCommentaryKeys, true)
putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gcc"), owner, plugCommentaryLineKeys, true)
putKeyMappingIfMissing(MappingMode.N, injector.parser.parseKeys("gcu"), owner, injector.parser.parseKeys("<Plug>Commentary<Plug>Commentary"), true)
putKeyMappingIfMissing(
MappingMode.N,
injector.parser.parseKeys("gcu"),
owner,
injector.parser.parseKeys("<Plug>Commentary<Plug>Commentary"),
true
)
// Previous versions of IdeaVim used different mappings to Vim's Commentary. Make sure everything works if someone
// is still using the old mapping
@@ -129,17 +154,22 @@ class CommentaryExtension : VimExtension {
* E.g. handles the `gc` in `gc_`, by setting the operator function, then invoking `g@` to receive the `_` motion to
* invoke the operator. This object is both the mapping handler and the operator function.
*/
private class CommentaryOperatorHandler : OperatorFunction, VimExtensionHandler {
private class CommentaryOperatorHandler : OperatorFunction, ExtensionHandler {
override val isRepeatable = true
// In this operator we process selection by ourselves. This is necessary for rider, VIM-1758
override fun postProcessSelection(): Boolean {
return false
}
override fun execute(editor: VimEditor, context: ExecutionContext) {
setOperatorFunction(this)
executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
}
override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
val range = VimPlugin.getMark().getChangeMarks(editor.vim) ?: return false
return doCommentary(editor.vim, context.vim, range, selectionType, true)
override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean {
val range = VimPlugin.getMark().getChangeMarks(editor) ?: return false
return doCommentary(editor, context, range, selectionType, true)
}
}
@@ -148,11 +178,11 @@ class CommentaryExtension : VimExtension {
*
* This object is both the `<Plug>Commentary` mapping handler and the text object handler
*/
private class CommentaryTextObjectMotionHandler : TextObjectActionHandler(), VimExtensionHandler {
private class CommentaryTextObjectMotionHandler : TextObjectActionHandler(), ExtensionHandler {
override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext) {
val commandState = editor.commandState
val commandState = editor.vimStateMachine
val count = maxOf(1, commandState.commandBuilder.count)
val textObjectHandler = this
@@ -174,7 +204,7 @@ class CommentaryExtension : VimExtension {
context: ExecutionContext,
count: Int,
rawCount: Int,
argument: Argument?
argument: Argument?,
): TextRange? {
val nativeEditor = (editor as IjVimEditor).editor

View File

@@ -18,7 +18,6 @@
package com.maddyhome.idea.vim.extension.exchange
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.LogicalPosition
@@ -31,10 +30,11 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
@@ -42,7 +42,6 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister
import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.moveToInlayAwareLogicalPosition
@@ -95,7 +94,7 @@ class VimExchangeExtension : VimExtension {
val EXCHANGE_KEY = Key<Exchange>("exchange")
// End mark has always greater of eq offset than start mark
class Exchange(val type: CommandState.SubMode, val start: Mark, val end: Mark, val text: String) {
class Exchange(val type: VimStateMachine.SubMode, val start: Mark, val end: Mark, val text: String) {
private var myHighlighter: RangeHighlighter? = null
fun setHighlighter(highlighter: RangeHighlighter) {
myHighlighter = highlighter
@@ -112,7 +111,7 @@ class VimExchangeExtension : VimExtension {
}
}
private class ExchangeHandler(private val isLine: Boolean) : VimExtensionHandler {
private class ExchangeHandler(private val isLine: Boolean) : ExtensionHandler {
override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext) {
@@ -121,37 +120,38 @@ class VimExchangeExtension : VimExtension {
}
}
private class ExchangeClearHandler : VimExtensionHandler {
private class ExchangeClearHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
clearExchange(editor.ij)
}
}
private class VExchangeHandler : VimExtensionHandler {
private class VExchangeHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
runWriteAction {
val subMode = editor.subMode
// Leave visual mode to create selection marks
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
Operator(true).apply(editor.ij, context.ij, SelectionType.fromSubMode(subMode))
Operator(true).apply(editor, context, SelectionType.fromSubMode(subMode))
}
}
}
private class Operator(private val isVisual: Boolean) : OperatorFunction {
fun Editor.getMarkOffset(mark: Mark) = EditorHelper.getOffset(this, mark.logicalLine, mark.col)
fun CommandState.SubMode.getString() = when (this) {
CommandState.SubMode.VISUAL_CHARACTER -> "v"
CommandState.SubMode.VISUAL_LINE -> "V"
CommandState.SubMode.VISUAL_BLOCK -> "\\<C-V>"
fun VimStateMachine.SubMode.getString() = when (this) {
VimStateMachine.SubMode.VISUAL_CHARACTER -> "v"
VimStateMachine.SubMode.VISUAL_LINE -> "V"
VimStateMachine.SubMode.VISUAL_BLOCK -> "\\<C-V>"
else -> error("Invalid SubMode: $this")
}
override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean {
val editor = vimEditor.ij
fun highlightExchange(ex: Exchange): RangeHighlighter {
val attributes = editor.colorsScheme.getAttributes(EditorColors.TEXT_SEARCH_RESULT_ATTRIBUTES)
val hlArea = when (ex.type) {
CommandState.SubMode.VISUAL_LINE -> HighlighterTargetArea.LINES_IN_RANGE
VimStateMachine.SubMode.VISUAL_LINE -> HighlighterTargetArea.LINES_IN_RANGE
// TODO: handle other modes
else -> HighlighterTargetArea.EXACT_RANGE
}
@@ -274,7 +274,7 @@ class VimExchangeExtension : VimExtension {
x.logicalLine - y.logicalLine
}
return if (x.type == CommandState.SubMode.VISUAL_BLOCK && y.type == CommandState.SubMode.VISUAL_BLOCK) {
return if (x.type == VimStateMachine.SubMode.VISUAL_BLOCK && y.type == VimStateMachine.SubMode.VISUAL_BLOCK) {
when {
intersects(x, y) -> {
ExchangeCompareResult.OVERLAP

View File

@@ -33,21 +33,21 @@ import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.Command
import com.maddyhome.idea.vim.command.CommandFlags
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.MotionType
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.common.Direction
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.handler.Motion
import com.maddyhome.idea.vim.handler.MotionActionHandler
import com.maddyhome.idea.vim.handler.toMotionOrError
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.PsiHelper
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.enumSetOf
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import java.util.*
@@ -94,14 +94,14 @@ class Matchit : VimExtension {
override var motionType: MotionType = MotionType.INCLUSIVE
}
private class MatchitHandler(private val reverse: Boolean) : VimExtensionHandler {
private class MatchitHandler(private val reverse: Boolean) : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
val commandState = editor.commandState
val commandState = editor.vimStateMachine
val count = commandState.commandBuilder.count
// Reset the command count so it doesn't transfer onto subsequent commands.
editor.commandState.commandBuilder.resetCount()
editor.vimStateMachine.commandBuilder.resetCount()
// Normally we want to jump to the start of the matching pair. But when moving forward in operator
// pending mode, we want to include the entire match. isInOpPending makes that distinction.
@@ -233,7 +233,7 @@ private object FileTypePatterns {
} else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") {
this.cMakePatterns
} else {
return null
this.htmlPatterns
}
}

View File

@@ -29,13 +29,13 @@ import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.group.visual.vimSetSelection
import com.maddyhome.idea.vim.helper.EditorHelper
@@ -111,7 +111,7 @@ class VimMultipleCursorsExtension : VimExtension {
putKeyMappingIfMissing(MappingMode.X, injector.parser.parseKeys("<A-p>"), owner, injector.parser.parseKeys(REMOVE_OCCURRENCE), true)
}
abstract class WriteActionHandler : VimExtensionHandler {
abstract class WriteActionHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
ApplicationManager.getApplication().runWriteAction {
executeInWriteAction(editor.ij, context.ij)
@@ -313,7 +313,7 @@ class VimMultipleCursorsExtension : VimExtension {
private fun enterVisualMode(editor: VimEditor) {
// We need to reset the key handler to make sure we pick up the fact that we're in visual mode
VimPlugin.getVisualMotion().enterVisualMode(editor, CommandState.SubMode.VISUAL_CHARACTER)
VimPlugin.getVisualMotion().enterVisualMode(editor, VimStateMachine.SubMode.VISUAL_CHARACTER)
KeyHandler.getInstance().reset(editor)
}

View File

@@ -21,6 +21,7 @@ package com.maddyhome.idea.vim.extension.nerdtree
import com.intellij.ide.projectView.ProjectView
import com.intellij.ide.projectView.impl.ProjectViewImpl
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.application.ApplicationManager
@@ -44,18 +45,18 @@ import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.CommandAlias
import com.maddyhome.idea.vim.common.CommandAliasHandler
import com.maddyhome.idea.vim.common.CommandNode
import com.maddyhome.idea.vim.common.CommandPartNode
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.RootNode
import com.maddyhome.idea.vim.common.addLeafs
import com.maddyhome.idea.vim.ex.ranges.Ranges
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.group.KeyGroup
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.helper.runAfterGotFocus
import com.maddyhome.idea.vim.key.CommandNode
import com.maddyhome.idea.vim.key.CommandPartNode
import com.maddyhome.idea.vim.key.MappingOwner
import com.maddyhome.idea.vim.key.Node
import com.maddyhome.idea.vim.key.RequiredShortcut
import com.maddyhome.idea.vim.key.RootNode
import com.maddyhome.idea.vim.key.addLeafs
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString
@@ -172,7 +173,7 @@ class NerdTree : VimExtension {
}
class ProjectViewListener(private val project: Project) : ToolWindowManagerListener {
override fun toolWindowShown(id: String, toolWindow: ToolWindow) {
override fun toolWindowShown(toolWindow: ToolWindow) {
if (ToolWindowId.PROJECT_VIEW != toolWindow.id) return
val dispatcher = NerdDispatcher.getInstance(project)
@@ -242,6 +243,8 @@ class NerdTree : VimExtension {
e.presentation.isEnabled = !speedSearchIsHere(project)
}
override fun getActionUpdateThread() = ActionUpdateThread.EDT
private fun speedSearchIsHere(project: Project): Boolean {
val component = ProjectView.getInstance(project).currentProjectViewPane.tree ?: return false
return SpeedSearchSupply.getSupply(component) != null
@@ -342,7 +345,7 @@ class NerdTree : VimExtension {
if (file.isDirectory) return@Code
val splitters = FileEditorManagerEx.getInstanceEx(project).splitters
val currentWindow = splitters.currentWindow
currentWindow.split(SwingConstants.HORIZONTAL, true, file, true)
currentWindow?.split(SwingConstants.HORIZONTAL, true, file, true)
}
)
registerCommand(
@@ -351,7 +354,7 @@ class NerdTree : VimExtension {
val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code
val splitters = FileEditorManagerEx.getInstanceEx(project).splitters
val currentWindow = splitters.currentWindow
currentWindow.split(SwingConstants.VERTICAL, true, file, true)
currentWindow?.split(SwingConstants.VERTICAL, true, file, true)
// FIXME: 22.01.2021 This solution bouncing a bit
callAction("ActivateProjectToolWindow", context.vim)
@@ -363,7 +366,7 @@ class NerdTree : VimExtension {
val file = event.getData(CommonDataKeys.VIRTUAL_FILE) ?: return@Code
val splitters = FileEditorManagerEx.getInstanceEx(project).splitters
val currentWindow = splitters.currentWindow
currentWindow.split(SwingConstants.HORIZONTAL, true, file, true)
currentWindow?.split(SwingConstants.HORIZONTAL, true, file, true)
callAction("ActivateProjectToolWindow", context.vim)
}
@@ -560,7 +563,3 @@ class NerdTree : VimExtension {
}
}
}
private fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) {
addLeafs(injector.parser.parseKeys(keys), actionHolder)
}

View File

@@ -23,11 +23,11 @@ import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.SearchHelper
@@ -45,7 +45,7 @@ class ParagraphMotion : VimExtension {
putKeyMappingIfMissing(MappingMode.NXO, injector.parser.parseKeys("{"), owner, injector.parser.parseKeys("<Plug>(ParagraphPrevMotion)"), true)
}
private class ParagraphMotionHandler(private val count: Int) : VimExtensionHandler {
private class ParagraphMotionHandler(private val count: Int) : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
editor.ij.vimForEachCaret { caret ->
val motion = moveCaretToNextParagraph(editor.ij, caret, count)

View File

@@ -18,28 +18,30 @@
package com.maddyhome.idea.vim.extension.replacewithregister
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.isLine
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.group.visual.VimSelection
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjExecutionContext
import com.maddyhome.idea.vim.newapi.IjVimEditor
@@ -63,22 +65,21 @@ class ReplaceWithRegister : VimExtension {
putKeyMappingIfMissing(MappingMode.X, injector.parser.parseKeys("gr"), owner, injector.parser.parseKeys(RWR_VISUAL), true)
}
private class RwrVisual : VimExtensionHandler {
private class RwrVisual : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
val caretsAndSelections = mutableMapOf<VimCaret, VimSelection>()
val typeInEditor = SelectionType.fromSubMode(editor.subMode)
editor.forEachCaret { caret ->
val selectionStart = caret.selectionStart
val selectionEnd = caret.selectionEnd
caretsAndSelections += caret to VimSelection.create(selectionStart, selectionEnd - 1, typeInEditor, editor)
val visualSelection = caret to VimSelection.create(selectionStart, selectionEnd - 1, typeInEditor, editor)
doReplace(editor.ij, caret, PutData.VisualSelection(mapOf(visualSelection), typeInEditor))
}
doReplace(editor.ij, PutData.VisualSelection(caretsAndSelections, typeInEditor))
editor.exitVisualModeNative()
}
}
private class RwrMotion : VimExtensionHandler {
private class RwrMotion : ExtensionHandler {
override val isRepeatable: Boolean = true
override fun execute(editor: VimEditor, context: ExecutionContext) {
@@ -87,7 +88,7 @@ class ReplaceWithRegister : VimExtension {
}
}
private class RwrLine : VimExtensionHandler {
private class RwrLine : ExtensionHandler {
override val isRepeatable: Boolean = true
override fun execute(editor: VimEditor, context: ExecutionContext) {
@@ -97,11 +98,11 @@ class ReplaceWithRegister : VimExtension {
val lineStart = editor.getLineStartOffset(logicalLine)
val lineEnd = editor.getLineEndOffset(logicalLine, true)
caretsAndSelections += caret to VimSelection.create(lineStart, lineEnd, SelectionType.LINE_WISE, editor)
}
val visualSelection = caret to VimSelection.create(lineStart, lineEnd, SelectionType.LINE_WISE, editor)
caretsAndSelections += visualSelection
val visualSelection = PutData.VisualSelection(caretsAndSelections, SelectionType.LINE_WISE)
doReplace(editor.ij, visualSelection)
doReplace(editor.ij, caret, PutData.VisualSelection(mapOf(visualSelection), SelectionType.LINE_WISE))
}
editor.forEachCaret { caret ->
val vimStart = caretsAndSelections[caret]?.vimStart
@@ -113,26 +114,28 @@ class ReplaceWithRegister : VimExtension {
}
private class Operator : OperatorFunction {
override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean {
val editor = (vimEditor as IjVimEditor).editor
val range = getRange(editor) ?: return false
val visualSelection = PutData.VisualSelection(
mapOf(
editor.caretModel.primaryCaret.vim to VimSelection.create(
vimEditor.primaryCaret() to VimSelection.create(
range.startOffset,
range.endOffset - 1,
selectionType,
IjVimEditor(editor)
vimEditor
)
),
selectionType
)
doReplace(editor, visualSelection)
// todo multicaret
doReplace(editor, vimEditor.primaryCaret(), visualSelection)
return true
}
private fun getRange(editor: Editor): TextRange? = when (editor.vim.mode) {
CommandState.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim)
CommandState.Mode.VISUAL -> editor.caretModel.primaryCaret.run { TextRange(selectionStart, selectionEnd) }
VimStateMachine.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim)
VimStateMachine.Mode.VISUAL -> editor.caretModel.primaryCaret.run { TextRange(selectionStart, selectionEnd) }
else -> null
}
}
@@ -147,8 +150,9 @@ class ReplaceWithRegister : VimExtension {
@NonNls
private const val RWR_VISUAL = "<Plug>ReplaceWithRegisterVisual"
private fun doReplace(editor: Editor, visualSelection: PutData.VisualSelection) {
val savedRegister = VimPlugin.getRegister().lastRegister ?: return
private fun doReplace(editor: Editor, caret: VimCaret, visualSelection: PutData.VisualSelection) {
val lastRegisterChar = injector.registerGroup.lastRegisterChar
val savedRegister = caret.registerStorage.getRegister(caret, lastRegisterChar) ?: return
var usedType = savedRegister.type
var usedText = savedRegister.text
@@ -170,11 +174,19 @@ class ReplaceWithRegister : VimExtension {
putToLine = -1
)
ClipboardOptionHelper.IdeaputDisabler().use {
VimPlugin.getPut().putText(IjVimEditor(editor), IjExecutionContext(EditorDataContext.init(editor)), putData)
VimPlugin.getPut().putText(
IjVimEditor(editor),
IjExecutionContext(EditorDataContext.init(editor)),
putData,
operatorArguments = OperatorArguments(
editor.vimStateMachine?.isOperatorPending ?: false,
0, editor.editorMode, editor.subMode
)
)
}
VimPlugin.getRegister().saveRegister(savedRegister.name, savedRegister)
VimPlugin.getRegister().saveRegister(VimPlugin.getRegister().defaultRegister, savedRegister)
caret.registerStorage.saveRegister(caret, savedRegister.name, savedRegister)
caret.registerStorage.saveRegister(caret, VimPlugin.getRegister().defaultRegister, savedRegister)
}
}
}

View File

@@ -17,30 +17,29 @@
*/
package com.maddyhome.idea.vim.extension.surround
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.application.runWriteAction
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimChangeGroup
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.MappingMode
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.extension.ExtensionHandler
import com.maddyhome.idea.vim.extension.VimExtension
import com.maddyhome.idea.vim.extension.VimExtensionFacade.executeNormalWithoutMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegister
import com.maddyhome.idea.vim.extension.VimExtensionFacade.getRegisterForCaret
import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputKeyStroke
import com.maddyhome.idea.vim.extension.VimExtensionFacade.inputString
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMapping
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegister
import com.maddyhome.idea.vim.extension.VimExtensionHandler
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
import com.maddyhome.idea.vim.key.OperatorFunction
import com.maddyhome.idea.vim.newapi.IjVimCaret
@@ -48,6 +47,7 @@ import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
import com.maddyhome.idea.vim.put.PutData
import org.jetbrains.annotations.NonNls
import java.awt.event.KeyEvent
import javax.swing.KeyStroke
@@ -82,7 +82,7 @@ class VimSurroundExtension : VimExtension {
}
}
private class YSurroundHandler : VimExtensionHandler {
private class YSurroundHandler : ExtensionHandler {
override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext) {
@@ -91,10 +91,10 @@ class VimSurroundExtension : VimExtension {
}
}
private class VSurroundHandler : VimExtensionHandler {
private class VSurroundHandler : ExtensionHandler {
override fun execute(editor: VimEditor, context: ExecutionContext) {
// NB: Operator ignores SelectionType anyway
if (!Operator(supportsMultipleCursors = true).apply(editor.ij, context.ij, SelectionType.CHARACTER_WISE)) {
if (!Operator(supportsMultipleCursors = true).apply(editor, context, SelectionType.CHARACTER_WISE)) {
return
}
runWriteAction {
@@ -104,7 +104,7 @@ class VimSurroundExtension : VimExtension {
}
}
private class CSurroundHandler : VimExtensionHandler {
private class CSurroundHandler : ExtensionHandler {
override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext) {
@@ -115,37 +115,74 @@ class VimSurroundExtension : VimExtension {
if (charTo.code == 0) return
val newSurround = getOrInputPair(charTo, editor.ij) ?: return
runWriteAction { change(editor.ij, charFrom, newSurround) }
runWriteAction { change(editor, context, charFrom, newSurround) }
}
companion object {
fun change(editor: Editor, charFrom: Char, newSurround: Pair<String, String>?) {
editor.runWithEveryCaretAndRestore { changeAtCaret(editor, charFrom, newSurround) }
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
}
fun changeAtCaret(editor: Editor, charFrom: Char, newSurround: Pair<String, String>?) {
// We take over the " register, so preserve it
val oldValue: List<KeyStroke>? = getRegister(REGISTER)
// Empty the " register
setRegister(REGISTER, null)
// Extract the inner value
perform("di" + pick(charFrom), editor)
val innerValue: MutableList<KeyStroke> = getRegister(REGISTER)?.toMutableList() ?: mutableListOf()
// If the surrounding characters were not found, the register will be empty
if (innerValue.isNotEmpty()) {
// Delete the surrounding
perform("da" + pick(charFrom), editor)
// Insert the surrounding characters and paste
if (newSurround != null) {
innerValue.addAll(0, injector.parser.parseKeys(newSurround.first))
innerValue.addAll(injector.parser.parseKeys(newSurround.second))
fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
// Save old register values for carets
val surroundings = editor.sortedCarets()
.map {
val oldValue: List<KeyStroke>? = getRegisterForCaret(REGISTER, it)
setRegisterForCaret(REGISTER, it, null)
SurroundingInfo(it, null, oldValue, null)
}
// Delete surrounding's content
perform("di" + pick(charFrom), editor.ij)
// Add info about surrounding's inner text and location
surroundings.forEach {
val registerValue = getRegisterForCaret(REGISTER, it.caret)
val innerValue = if (registerValue.isNullOrEmpty()) null else registerValue
it.innerText = innerValue
val lineEndOffset = injector.engineEditorHelper.getLineEndOffset(editor, it.caret.getLine().line, false)
if (lineEndOffset == it.caret.offset.point) {
it.isLineEnd = true
}
pasteSurround(innerValue, editor)
// Jump back to start
executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
}
// Restore the old value
setRegister(REGISTER, oldValue)
// Remove surrounding
perform("da" + pick(charFrom), editor.ij)
surroundings.forEach {
if (it.innerText == null && getRegisterForCaret(REGISTER, it.caret)?.isNotEmpty() == true) {
it.innerText = emptyList()
}
// caret should be placed at the first char of inserted text
// the best solution would be using [ mark after the paste, but marks are not supported by multicaret
// todo
if (it.innerText != null) {
it.offset = it.caret.offset.point
}
}
surroundings
.filter { it.innerText != null } // we do nothing with carets that are not inside the surrounding
.map { surrounding ->
val innerValue = injector.parser.toPrintableString(surrounding.innerText!!)
val text = newSurround?.let { it.first + innerValue + it.second } ?: innerValue
val textData = PutData.TextData(text, SelectionType.CHARACTER_WISE, emptyList())
val putData = PutData(textData, null, 1, insertTextBeforeCaret = !surrounding.isLineEnd, rawIndent = true, caretAfterInsertedText = false)
surrounding.caret to putData
}.forEach {
injector.put.putTextForCaret(editor, it.first, context, it.second)
}
surroundings.forEach {
it.restoreRegister()
}
if (surroundings.size == 1) {
surroundings.first().moveCaret()
}
}
private fun perform(sequence: String, editor: Editor) {
@@ -153,21 +190,6 @@ class VimSurroundExtension : VimExtension {
.use { executeNormalWithoutMapping(injector.parser.parseKeys("\"" + REGISTER + sequence), editor) }
}
private fun pasteSurround(
innerValue: List<KeyStroke?>,
editor: Editor,
) { // This logic is direct from vim-surround
val offset = editor.caretModel.offset
val lineEndOffset = EditorHelper.getLineEndForOffset(editor, offset)
val motionEndMark = VimPlugin.getMark().getMark(editor.vim, ']')
val motionEndOffset = if (motionEndMark != null) {
EditorHelper.getOffset(editor, motionEndMark.logicalLine, motionEndMark.col)
} else -1
val pasteCommand = if (motionEndOffset == lineEndOffset && offset + 1 == lineEndOffset) "p" else "P"
setRegister(REGISTER, innerValue)
perform(pasteCommand, editor)
}
private fun pick(charFrom: Char) = when (charFrom) {
'a' -> '>'
'r' -> ']'
@@ -176,7 +198,19 @@ class VimSurroundExtension : VimExtension {
}
}
private class DSurroundHandler : VimExtensionHandler {
private data class SurroundingInfo(val caret: VimCaret, var innerText: List<KeyStroke>?, val oldRegisterContent: List<KeyStroke>?, var offset: Int?, var isLineEnd: Boolean = false) {
fun restoreRegister() {
setRegisterForCaret(REGISTER, caret, oldRegisterContent)
}
fun moveCaret() {
if (innerText != null && offset != null) {
caret.moveToOffset(offset!! + if (isLineEnd) 1 else 0)
}
}
}
private class DSurroundHandler : ExtensionHandler {
override val isRepeatable = true
override fun execute(editor: VimEditor, context: ExecutionContext) {
@@ -184,12 +218,13 @@ class VimSurroundExtension : VimExtension {
val charFrom = getChar(editor.ij)
if (charFrom.code == 0) return
runWriteAction { CSurroundHandler.change(editor.ij, charFrom, null) }
runWriteAction { CSurroundHandler.change(editor, context, charFrom, null) }
}
}
private class Operator(private val supportsMultipleCursors: Boolean) : OperatorFunction {
override fun apply(editor: Editor, context: DataContext, selectionType: SelectionType): Boolean {
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType): Boolean {
val editor = vimEditor.ij
val c = getChar(editor)
if (c.code == 0) return true
@@ -226,9 +261,9 @@ class VimSurroundExtension : VimExtension {
}
}
private fun getSurroundRange(editor: Editor): TextRange? = when (editor.mode) {
CommandState.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim)
CommandState.Mode.VISUAL -> editor.caretModel.primaryCaret.run { TextRange(selectionStart, selectionEnd) }
private fun getSurroundRange(editor: Editor): TextRange? = when (editor.editorMode) {
VimStateMachine.Mode.COMMAND -> VimPlugin.getMark().getChangeMarks(editor.vim)
VimStateMachine.Mode.VISUAL -> editor.caretModel.primaryCaret.run { TextRange(selectionStart, selectionEnd) }
else -> null
}
}

View File

@@ -18,26 +18,22 @@
package com.maddyhome.idea.vim.extension.textobjentire;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.maddyhome.idea.vim.api.ExecutionContext;
import com.maddyhome.idea.vim.api.VimCaret;
import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.api.VimInjectorKt;
import com.maddyhome.idea.vim.command.*;
import com.maddyhome.idea.vim.common.MappingMode;
import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.extension.VimExtension;
import com.maddyhome.idea.vim.extension.VimExtensionHandler;
import com.maddyhome.idea.vim.extension.ExtensionHandler;
import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
import com.maddyhome.idea.vim.helper.InlayHelperKt;
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor;
import com.maddyhome.idea.vim.listener.VimListenerSuppressor;
import com.maddyhome.idea.vim.newapi.IjExecutionContext;
import com.maddyhome.idea.vim.newapi.IjVimCaret;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import org.apache.tools.ant.taskdefs.Exec;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -88,7 +84,7 @@ public class VimTextObjEntireExtension implements VimExtension {
putKeyMappingIfMissing(MappingMode.XO, VimInjectorKt.getInjector().getParser().parseKeys("ie"), getOwner(), VimInjectorKt.getInjector().getParser().parseKeys("<Plug>textobj-entire-i"), true);
}
static class EntireHandler implements VimExtensionHandler {
static class EntireHandler implements ExtensionHandler {
final boolean ignoreLeadingAndTrailing;
EntireHandler(boolean ignoreLeadingAndTrailing) {
@@ -148,17 +144,17 @@ public class VimTextObjEntireExtension implements VimExtension {
@Override
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context) {
@NotNull CommandState commandState = CommandState.getInstance(editor);
int count = Math.max(1, commandState.getCommandBuilder().getCount());
@NotNull VimStateMachine vimStateMachine = VimStateMachine.getInstance(editor);
int count = Math.max(1, vimStateMachine.getCommandBuilder().getCount());
final EntireTextObjectHandler textObjectHandler = new EntireTextObjectHandler(ignoreLeadingAndTrailing);
//noinspection DuplicatedCode
if (!commandState.isOperatorPending()) {
if (!vimStateMachine.isOperatorPending()) {
((IjVimEditor) editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
final TextRange range = textObjectHandler.getRange(editor, new IjVimCaret(caret), context, count, 0, null);
if (range != null) {
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
if (commandState.getMode() == CommandState.Mode.VISUAL) {
if (vimStateMachine.getMode() == VimStateMachine.Mode.VISUAL) {
vimSetSelection(caret, range.getStartOffset(), range.getEndOffset() - 1, true);
} else {
InlayHelperKt.moveToInlayAwareOffset(caret, range.getStartOffset());
@@ -168,9 +164,9 @@ public class VimTextObjEntireExtension implements VimExtension {
});
} else {
commandState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
textObjectHandler, Command.Type.MOTION,
EnumSet.noneOf(CommandFlags.class))));
vimStateMachine.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
textObjectHandler, Command.Type.MOTION,
EnumSet.noneOf(CommandFlags.class))));
}
}
}

View File

@@ -18,23 +18,20 @@
package com.maddyhome.idea.vim.extension.textobjindent;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Caret;
import com.intellij.openapi.editor.Editor;
import com.maddyhome.idea.vim.api.ExecutionContext;
import com.maddyhome.idea.vim.api.VimCaret;
import com.maddyhome.idea.vim.api.VimEditor;
import com.maddyhome.idea.vim.api.VimInjectorKt;
import com.maddyhome.idea.vim.command.*;
import com.maddyhome.idea.vim.common.MappingMode;
import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.extension.VimExtension;
import com.maddyhome.idea.vim.extension.VimExtensionHandler;
import com.maddyhome.idea.vim.extension.ExtensionHandler;
import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
import com.maddyhome.idea.vim.helper.InlayHelperKt;
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor;
import com.maddyhome.idea.vim.listener.VimListenerSuppressor;
import com.maddyhome.idea.vim.newapi.IjExecutionContext;
import com.maddyhome.idea.vim.newapi.IjVimCaret;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import org.jetbrains.annotations.NotNull;
@@ -86,7 +83,7 @@ public class VimIndentObject implements VimExtension {
putKeyMapping(MappingMode.XO, VimInjectorKt.getInjector().getParser().parseKeys("ii"), getOwner(), VimInjectorKt.getInjector().getParser().parseKeys("<Plug>textobj-indent-ii"), true);
}
static class IndentObject implements VimExtensionHandler {
static class IndentObject implements ExtensionHandler {
final boolean includeAbove;
final boolean includeBelow;
@@ -275,17 +272,17 @@ public class VimIndentObject implements VimExtension {
@Override
public void execute(@NotNull VimEditor editor, @NotNull ExecutionContext context) {
IjVimEditor vimEditor = (IjVimEditor)editor;
@NotNull CommandState commandState = CommandState.getInstance(vimEditor);
int count = Math.max(1, commandState.getCommandBuilder().getCount());
@NotNull VimStateMachine vimStateMachine = VimStateMachine.getInstance(vimEditor);
int count = Math.max(1, vimStateMachine.getCommandBuilder().getCount());
final IndentObjectHandler textObjectHandler = new IndentObjectHandler(includeAbove, includeBelow);
if (!commandState.isOperatorPending()) {
if (!vimStateMachine.isOperatorPending()) {
((IjVimEditor)editor).getEditor().getCaretModel().runForEachCaret((Caret caret) -> {
final TextRange range = textObjectHandler.getRange(vimEditor, new IjVimCaret(caret), context, count, 0, null);
if (range != null) {
try (VimListenerSuppressor.Locked ignored = SelectionVimListenerSuppressor.INSTANCE.lock()) {
if (commandState.getMode() == CommandState.Mode.VISUAL) {
if (vimStateMachine.getMode() == VimStateMachine.Mode.VISUAL) {
vimSetSelection(caret, range.getStartOffset(), range.getEndOffset() - 1, true);
} else {
InlayHelperKt.moveToInlayAwareOffset(caret, range.getStartOffset());
@@ -295,9 +292,9 @@ public class VimIndentObject implements VimExtension {
});
} else {
commandState.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
textObjectHandler, Command.Type.MOTION,
EnumSet.noneOf(CommandFlags.class))));
vimStateMachine.getCommandBuilder().completeCommandPart(new Argument(new Command(count,
textObjectHandler, Command.Type.MOTION,
EnumSet.noneOf(CommandFlags.class))));
}
}
}

View File

@@ -20,7 +20,10 @@ package com.maddyhome.idea.vim.group;
import com.google.common.base.Splitter;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.intellij.codeInsight.actions.AsyncActionExecutionService;
import com.intellij.openapi.Disposable;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.IdeActions;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.command.CommandProcessor;
import com.intellij.openapi.command.UndoConfirmationPolicy;
@@ -33,6 +36,9 @@ import com.intellij.openapi.editor.event.EditorMouseEvent;
import com.intellij.openapi.editor.event.EditorMouseListener;
import com.intellij.openapi.editor.impl.TextRangeInterval;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.MessageType;
import com.intellij.openapi.ui.popup.Balloon;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.psi.PsiFile;
import com.intellij.psi.codeStyle.CodeStyleManager;
@@ -48,13 +54,19 @@ import com.maddyhome.idea.vim.ex.ranges.LineRange;
import com.maddyhome.idea.vim.group.visual.VimSelection;
import com.maddyhome.idea.vim.group.visual.VisualModeHelperKt;
import com.maddyhome.idea.vim.helper.*;
import com.maddyhome.idea.vim.icons.VimIcons;
import com.maddyhome.idea.vim.key.KeyHandlerKeeper;
import com.maddyhome.idea.vim.listener.VimInsertListener;
import com.maddyhome.idea.vim.newapi.*;
import com.maddyhome.idea.vim.newapi.IjExecutionContext;
import com.maddyhome.idea.vim.newapi.IjExecutionContextKt;
import com.maddyhome.idea.vim.newapi.IjVimCaret;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.options.OptionConstants;
import com.maddyhome.idea.vim.options.OptionScope;
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString;
import kotlin.Pair;
import kotlin.Unit;
import kotlin.jvm.functions.Function0;
import kotlin.text.StringsKt;
import org.jetbrains.annotations.NonNls;
import org.jetbrains.annotations.NotNull;
@@ -85,6 +97,8 @@ public class ChangeGroup extends VimChangeGroupBase {
private final List<VimInsertListener> insertListeners = ContainerUtil.createLockFreeCopyOnWriteList();
private long lastShownTime = 0L;
/**
* Inserts a new line above the caret position
*
@@ -106,7 +120,7 @@ public class ChangeGroup extends VimChangeGroupBase {
injector.getMotion().moveCaret(editor, caret, VimPlugin.getMotion().moveCaretToLineEnd(editor, caret));
}
UserDataManager.setVimChangeActionSwitchMode(((IjVimEditor) editor).getEditor(), CommandState.Mode.INSERT);
UserDataManager.setVimChangeActionSwitchMode(((IjVimEditor) editor).getEditor(), VimStateMachine.Mode.INSERT);
insertText(editor, caret, "\n" + IndentConfig.create(((IjVimEditor) editor).getEditor()).createIndentBySize(col));
if (firstLiner) {
@@ -125,7 +139,7 @@ public class ChangeGroup extends VimChangeGroupBase {
if (editor.isOneLineMode()) return;
caret.moveToOffset(injector.getMotion().moveCaretToLineEnd(editor, caret));
editor.setVimChangeActionSwitchMode(CommandState.Mode.INSERT);
editor.setVimChangeActionSwitchMode(VimStateMachine.Mode.INSERT);
insertText(editor, caret, "\n" + IndentConfig.create(((IjVimEditor) editor).getEditor()).createIndentBySize(col));
}
@@ -142,14 +156,12 @@ public class ChangeGroup extends VimChangeGroupBase {
}
};
@Override
public void editorCreated(VimEditor editor) {
EventFacade.getInstance().addEditorMouseListener(((IjVimEditor) editor).getEditor(), listener);
public void editorCreated(Editor editor, @NotNull Disposable disposable) {
EventFacade.getInstance().addEditorMouseListener(editor, listener, disposable);
}
@Override
public void editorReleased(VimEditor editor) {
EventFacade.getInstance().removeEditorMouseListener(((IjVimEditor) editor).getEditor(), listener);
public void editorReleased(Editor editor) {
EventFacade.getInstance().removeEditorMouseListener(editor, listener);
}
@Override
@@ -245,9 +257,9 @@ public class ChangeGroup extends VimChangeGroupBase {
final boolean lastWordChar =
offset >= fileSize - 1 || CharacterHelper.charType(chars.charAt(offset + 1), bigWord) != charType;
if (wordMotions.contains(id) && lastWordChar && motion.getCount() == 1) {
final boolean res = deleteCharacter(editor, caret, 1, true);
final boolean res = deleteCharacter(editor, caret, 1, true, operatorArguments);
if (res) {
editor.setVimChangeActionSwitchMode(CommandState.Mode.INSERT);
editor.setVimChangeActionSwitchMode(VimStateMachine.Mode.INSERT);
}
return res;
}
@@ -306,7 +318,8 @@ public class ChangeGroup extends VimChangeGroupBase {
Pair<TextRange, SelectionType> deleteRangeAndType =
getDeleteRangeAndType(editor, caret, context, argument, true, operatorArguments.withCount0(count0));
if (deleteRangeAndType == null) return false;
return changeRange(editor, caret, deleteRangeAndType.getFirst(), deleteRangeAndType.getSecond(), context);
return changeRange(editor, caret, deleteRangeAndType.getFirst(), deleteRangeAndType.getSecond(), context,
operatorArguments);
}
}
@@ -338,8 +351,8 @@ public class ChangeGroup extends VimChangeGroupBase {
final int lines = VimChangeGroupBase.Companion.getLinesCountInVisualBlock(editor, range);
final VimLogicalPosition startPosition = editor.offsetToLogicalPosition(range.getStartOffset());
boolean visualBlockMode = operatorArguments.getMode() == CommandState.Mode.VISUAL &&
operatorArguments.getSubMode() == CommandState.SubMode.VISUAL_BLOCK;
boolean visualBlockMode = operatorArguments.getMode() == VimStateMachine.Mode.VISUAL &&
operatorArguments.getSubMode() == VimStateMachine.SubMode.VISUAL_BLOCK;
for (Caret caret : ((IjVimEditor) editor).getEditor().getCaretModel().getAllCarets()) {
final int line = startPosition.getLine();
int column = startPosition.getColumn();
@@ -425,10 +438,11 @@ public class ChangeGroup extends VimChangeGroupBase {
/**
* Deletes the range of text and enters insert mode
*
* @param editor The editor to change
* @param caret The caret to be moved after range deletion
* @param range The range to change
* @param type The type of the range
* @param editor The editor to change
* @param caret The caret to be moved after range deletion
* @param range The range to change
* @param type The type of the range
* @param operatorArguments
* @return true if able to delete the range, false if not
*/
@Override
@@ -436,7 +450,8 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull VimCaret caret,
@NotNull TextRange range,
@NotNull SelectionType type,
ExecutionContext context) {
@Nullable ExecutionContext context,
@NotNull OperatorArguments operatorArguments) {
int col = 0;
int lines = 0;
if (type == SelectionType.BLOCK_WISE) {
@@ -450,7 +465,7 @@ public class ChangeGroup extends VimChangeGroupBase {
final VimLogicalPosition lp = editor.offsetToLogicalPosition(injector.getMotion().moveCaretToLineStartSkipLeading(editor, caret));
boolean res = deleteRange(editor, caret, range, type, true);
boolean res = deleteRange(editor, caret, range, type, true, operatorArguments);
if (res) {
if (type == SelectionType.LINE_WISE) {
// Please don't use `getDocument().getText().isEmpty()` because it converts CharSequence into String
@@ -468,7 +483,7 @@ public class ChangeGroup extends VimChangeGroupBase {
if (type == SelectionType.BLOCK_WISE) {
setInsertRepeat(lines, col, false);
}
UserDataManager.setVimChangeActionSwitchMode(((IjVimEditor) editor).getEditor(), CommandState.Mode.INSERT);
UserDataManager.setVimChangeActionSwitchMode(((IjVimEditor) editor).getEditor(), VimStateMachine.Mode.INSERT);
}
}
else {
@@ -568,17 +583,31 @@ public class ChangeGroup extends VimChangeGroupBase {
final int startOffset = injector.getEngineEditorHelper().getLineStartForOffset(editor, range.getStartOffset());
final int endOffset = injector.getEngineEditorHelper().getLineEndForOffset(editor, range.getEndOffset());
VisualModeHelperKt.vimSetSystemSelectionSilently(((IjVimEditor) editor).getEditor().getSelectionModel(), startOffset, endOffset);
Editor ijEditor = ((IjVimEditor)editor).getEditor();
VisualModeHelperKt.vimSetSystemSelectionSilently(ijEditor.getSelectionModel(), startOffset, endOffset);
NativeAction joinLinesAction = VimInjectorKt.getInjector().getNativeActionManager().getIndentLines();
if (joinLinesAction != null) {
VimInjectorKt.getInjector().getActionExecutor().executeAction(joinLinesAction, context);
Project project = ijEditor.getProject();
Function0<Unit> actionExecution = () -> {
NativeAction joinLinesAction = VimInjectorKt.getInjector().getNativeActionManager().getIndentLines();
if (joinLinesAction != null) {
VimInjectorKt.getInjector().getActionExecutor().executeAction(joinLinesAction, context);
}
return null;
};
Function0<Unit> afterAction = () -> {
final int firstLine = editor.offsetToLogicalPosition(Math.min(startOffset, endOffset)).getLine();
final int newOffset = VimPlugin.getMotion().moveCaretToLineStartSkipLeading(editor, firstLine);
injector.getMotion().moveCaret(editor, caret, newOffset);
restoreCursor(editor, caret, ((IjVimCaret)caret).getCaret().getLogicalPosition().line);
return null;
};
if (project != null) {
AsyncActionExecutionService.Companion.getInstance(project)
.withExecutionAfterAction(IdeActions.ACTION_EDITOR_AUTO_INDENT_LINES, actionExecution, afterAction);
} else {
actionExecution.invoke();
afterAction.invoke();
}
final int firstLine = editor.offsetToLogicalPosition(Math.min(startOffset, endOffset)).getLine();
final int newOffset = VimPlugin.getMotion().moveCaretToLineStartSkipLeading(editor, firstLine);
injector.getMotion().moveCaret(editor, caret, newOffset);
restoreCursor(editor, caret, ((IjVimCaret) caret).getCaret().getLogicalPosition().line);
}
@Override
@@ -586,10 +615,11 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull VimCaret caret,
@NotNull ExecutionContext context,
int lines,
int dir) {
int dir,
@NotNull OperatorArguments operatorArguments) {
int start = ((IjVimCaret) caret).getCaret().getOffset();
int end = VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret, lines - 1, true);
indentRange(editor, caret, context, new TextRange(start, end), 1, dir);
indentRange(editor, caret, context, new TextRange(start, end), 1, dir, operatorArguments);
}
@Override
@@ -602,7 +632,7 @@ public class ChangeGroup extends VimChangeGroupBase {
final TextRange range =
injector.getMotion().getMotionRange(editor, caret, context, argument, operatorArguments);
if (range != null) {
indentRange(editor, caret, context, range, 1, dir);
indentRange(editor, caret, context, range, 1, dir, operatorArguments);
}
}
@@ -629,7 +659,8 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull ExecutionContext context,
@NotNull TextRange range,
int count,
int dir) {
int dir,
@NotNull OperatorArguments operatorArguments) {
if (logger.isDebugEnabled()) {
logger.debug("count=" + count);
}
@@ -675,7 +706,7 @@ public class ChangeGroup extends VimChangeGroupBase {
}
}
if (pos > wsoff) {
deleteText(editor, new TextRange(wsoff, pos), null);
deleteText(editor, new TextRange(wsoff, pos), null, caret, operatorArguments);
}
}
}
@@ -768,6 +799,23 @@ public class ChangeGroup extends VimChangeGroupBase {
@NotNull TextRange selectedRange,
final int count,
boolean avalanche) {
// Just an easter egg
if (avalanche) {
long currentTime = System.currentTimeMillis();
if (currentTime - lastShownTime > 60_000) {
lastShownTime = currentTime;
ApplicationManager.getApplication().invokeLater(() -> {
final Balloon balloon = JBPopupFactory.getInstance()
.createHtmlTextBalloonBuilder("Wow, nice vim skills!", VimIcons.IDEAVIM,
MessageType.INFO.getTitleForeground(), MessageType.INFO.getPopupBackground(),
null).createBalloon();
balloon.show(JBPopupFactory.getInstance().guessBestPopupLocation(((IjVimEditor)editor).getEditor()),
Balloon.Position.below);
});
}
}
String nf = ((VimString) VimPlugin.getOptionService().getOptionValue(new OptionScope.LOCAL(editor), OptionConstants.nrformatsName, OptionConstants.nrformatsName)).getValue();
boolean alpha = nf.contains("alpha");
boolean hex = nf.contains("hex");

View File

@@ -232,7 +232,7 @@ public class EditorGroup implements PersistentStateComponent<Element>, VimEditor
KeyHandler.getInstance().reset(new IjVimEditor(editor));
}
updateCaretsVisualAttributes(editor);
editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
//editor.getSettings().setRefrainFromScrolling(REFRAIN_FROM_SCROLLING_VIM_VALUE);
}
public void editorDeinit(@NotNull Editor editor, boolean isReleased) {

View File

@@ -20,6 +20,7 @@ package com.maddyhome.idea.vim.group;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.editor.Editor;
@@ -27,6 +28,7 @@ import com.intellij.openapi.editor.LogicalPosition;
import com.intellij.openapi.fileEditor.*;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.EditorWindow;
import com.intellij.openapi.fileEditor.impl.EditorsSplitters;
import com.intellij.openapi.fileTypes.FileType;
import com.intellij.openapi.fileTypes.FileTypeManager;
import com.intellij.openapi.project.Project;
@@ -38,8 +40,7 @@ import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileVisitor;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.command.CommandState;
import com.maddyhome.idea.vim.common.GoalCommand;
import com.maddyhome.idea.vim.command.VimStateMachine;
import com.maddyhome.idea.vim.common.TextRange;
import com.maddyhome.idea.vim.helper.EditorHelper;
import com.maddyhome.idea.vim.helper.EditorHelperRt;
@@ -48,7 +49,6 @@ import com.maddyhome.idea.vim.helper.SearchHelper;
import com.maddyhome.idea.vim.newapi.ExecuteExtensionKt;
import com.maddyhome.idea.vim.newapi.IjExecutionContext;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.options.OptionConstants;
import com.maddyhome.idea.vim.options.OptionScope;
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimString;
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService;
@@ -161,6 +161,10 @@ public class FileGroup extends VimFileBase {
if (virtualFile != null && window != null) {
window.closeFile(virtualFile);
}
if (!ApplicationManager.getApplication().isUnitTestMode()) {
// This thing doesn't have an implementation in test mode
EditorsSplitters.focusDefaultComponentInSplittersIfPresent(project);
}
}
}
@@ -177,6 +181,10 @@ public class FileGroup extends VimFileBase {
if (number >= 0 && number < editors.length) {
fileEditorManager.closeFile(editors[number], window);
}
if (!ApplicationManager.getApplication().isUnitTestMode()) {
// This thing doesn't have an implementation in test mode
EditorsSplitters.focusDefaultComponentInSplittersIfPresent(project);
}
}
/**
@@ -290,7 +298,7 @@ public class FileGroup extends VimFileBase {
StringBuilder msg = new StringBuilder();
Document doc = editor.getDocument();
if (CommandState.getInstance(new IjVimEditor(editor)).getMode() != CommandState.Mode.VISUAL) {
if (VimStateMachine.getInstance(new IjVimEditor(editor)).getMode() != VimStateMachine.Mode.VISUAL) {
LogicalPosition lp = editor.getCaretModel().getLogicalPosition();
int col = editor.getCaretModel().getOffset() - doc.getLineStartOffset(lp.line);
int endoff = doc.getLineEndOffset(lp.line);

View File

@@ -36,6 +36,7 @@ class IjVimStorageService : VimStorageServiceBase() {
editor.ij.putUserData(getOrCreateIjKey(key), data)
}
@Suppress("UNCHECKED_CAST")
override fun <T> getDataFromBuffer(editor: VimEditor, key: com.maddyhome.idea.vim.api.Key<T>): T? {
val buffer = EditorHelper.getVirtualFile(editor.ij)?.path ?: "empty path"
return bufferToKey[buffer]?.get(key.name) as T?
@@ -60,6 +61,7 @@ class IjVimStorageService : VimStorageServiceBase() {
}
private val ijKeys = mutableMapOf<String, Key<out Any?>>()
@Suppress("UNCHECKED_CAST")
private fun <T> getOrCreateIjKey(key: com.maddyhome.idea.vim.api.Key<T>): Key<T> {
val storedIjKey = ijKeys[key.name]
if (storedIjKey != null) {

View File

@@ -37,9 +37,8 @@ import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.action.ComplicatedKeysAction;
import com.maddyhome.idea.vim.action.VimShortcutKeyAction;
import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.common.MappingMode;
import com.maddyhome.idea.vim.common.Node;
import com.maddyhome.idea.vim.common.NodesKt;
import com.maddyhome.idea.vim.command.MappingMode;
import com.maddyhome.idea.vim.key.Node;
import com.maddyhome.idea.vim.ex.ExOutputModel;
import com.maddyhome.idea.vim.handler.EditorActionHandlerBase;
import com.maddyhome.idea.vim.helper.HelperKt;
@@ -74,8 +73,6 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
private static final Logger logger = Logger.getInstance(KeyGroup.class);
private @Nullable OperatorFunction operatorFunction = null;
public void registerRequiredShortcutKeys(@NotNull VimEditor editor) {
EventFacade.getInstance()
.registerCustomShortcutSet(VimShortcutKeyAction.getInstance(), toShortcutSet(getRequiredShortcutKeys()),
@@ -120,14 +117,6 @@ public class KeyGroup extends VimKeyGroupBase implements PersistentStateComponen
}
}
public @Nullable OperatorFunction getOperatorFunction() {
return operatorFunction;
}
public void setOperatorFunction(@NotNull OperatorFunction function) {
operatorFunction = function;
}
public void saveData(@NotNull Element element) {
final Element conflictsElement = new Element(SHORTCUT_CONFLICTS_ELEMENT);
for (Map.Entry<KeyStroke, ShortcutOwnerInfo> entry : myShortcutConflicts.entrySet()) {

View File

@@ -108,7 +108,9 @@ public class MacroGroup extends VimMacroBase {
KeyHandler.getInstance().handleKey(editor, key, context);
});
}
keyStack.resetFirst();
}
keyStack.removeFirst();
});
}
}

View File

@@ -44,7 +44,6 @@ import com.maddyhome.idea.vim.helper.EditorHelper;
import com.maddyhome.idea.vim.helper.HelperKt;
import com.maddyhome.idea.vim.mark.*;
import com.maddyhome.idea.vim.newapi.IjVimEditor;
import com.maddyhome.idea.vim.options.OptionConstants;
import com.maddyhome.idea.vim.options.OptionScope;
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService;
import org.jdom.Element;
@@ -60,8 +59,7 @@ import static com.maddyhome.idea.vim.mark.VimMarkConstants.SAVE_FILE_MARKS;
* This class contains all the mark related functionality
*/
@State(name = "VimMarksSettings", storages = {
@Storage(value = "$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)
})
@Storage(value = "$APP_CONFIG$/vim_settings_local.xml", roamingType = RoamingType.DISABLED)})
public class MarkGroup extends VimMarkGroupBase implements PersistentStateComponent<Element> {
public void editorReleased(@NotNull EditorFactoryEvent event) {
// Save off the last caret position of the file before it is closed
@@ -92,7 +90,7 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
*
* @param doc The editor to get the marks for
* @return The map of marks. The keys are <code>Character</code>s of the mark names, the values are
* <code>Mark</code>s.
* <code>Mark</code>s.
*/
private @Nullable FileMarks<Character, Mark> getFileMarks(final @NotNull Document doc) {
VirtualFile vf = FileDocumentManager.getInstance().getFile(doc);
@@ -127,7 +125,8 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
public void saveData(@NotNull Element element) {
Element marksElem = new Element("globalmarks");
if (!VimPlugin.getOptionService().isSet(OptionScope.GLOBAL.INSTANCE, IjVimOptionService.ideamarksName, IjVimOptionService.ideamarksName)) {
if (!VimPlugin.getOptionService()
.isSet(OptionScope.GLOBAL.INSTANCE, IjVimOptionService.ideamarksName, IjVimOptionService.ideamarksName)) {
for (Mark mark : globalMarks.values()) {
if (!mark.isClear()) {
Element markElem = new Element("mark");
@@ -165,8 +164,7 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
fileMarkElem.setAttribute("name", file);
fileMarkElem.setAttribute("timestamp", Long.toString(marks.getMyTimestamp().getTime()));
for (Mark mark : marks.values()) {
if (!mark.isClear() && !Character.isUpperCase(mark.getKey()) &&
SAVE_FILE_MARKS.indexOf(mark.getKey()) >= 0) {
if (!mark.isClear() && !Character.isUpperCase(mark.getKey()) && SAVE_FILE_MARKS.indexOf(mark.getKey()) >= 0) {
Element markElem = new Element("mark");
markElem.setAttribute("key", Character.toString(mark.getKey()));
markElem.setAttribute("line", Integer.toString(mark.getLogicalLine()));
@@ -200,14 +198,15 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
// (see com.intellij.openapi.application.Application.runReadAction())
Element marksElem = element.getChild("globalmarks");
if (marksElem != null && !VimPlugin.getOptionService().isSet(OptionScope.GLOBAL.INSTANCE, IjVimOptionService.ideamarksName, IjVimOptionService.ideamarksName)) {
if (marksElem != null &&
!VimPlugin.getOptionService()
.isSet(OptionScope.GLOBAL.INSTANCE, IjVimOptionService.ideamarksName, IjVimOptionService.ideamarksName)) {
List<Element> markList = marksElem.getChildren("mark");
for (Element aMarkList : markList) {
Mark mark = VimMark.create(aMarkList.getAttributeValue("key").charAt(0),
Integer.parseInt(aMarkList.getAttributeValue("line")),
Integer.parseInt(aMarkList.getAttributeValue("column")),
aMarkList.getAttributeValue("filename"),
aMarkList.getAttributeValue("protocol"));
aMarkList.getAttributeValue("filename"), aMarkList.getAttributeValue("protocol"));
if (mark != null) {
globalMarks.put(mark.getKey(), mark);
@@ -239,8 +238,7 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
for (Element aMarkList : markList) {
Mark mark = VimMark.create(aMarkList.getAttributeValue("key").charAt(0),
Integer.parseInt(aMarkList.getAttributeValue("line")),
Integer.parseInt(aMarkList.getAttributeValue("column")),
filename,
Integer.parseInt(aMarkList.getAttributeValue("column")), filename,
aMarkList.getAttributeValue("protocol"));
if (mark != null) fmarks.put(mark.getKey(), mark);
@@ -290,6 +288,7 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
public static class MarkUpdater implements DocumentListener {
public static MarkUpdater INSTANCE = new MarkUpdater();
/**
* Creates the listener for the supplied editor
*/
@@ -313,8 +312,7 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
Editor anEditor = getAnEditor(doc);
VimInjectorKt.getInjector().getMarkGroup()
.updateMarkFromDelete(anEditor == null ? null : new IjVimEditor(anEditor),
VimPlugin.getMark().getAllFileMarks(doc),
event.getOffset(), event.getOldLength());
VimPlugin.getMark().getAllFileMarks(doc), event.getOffset(), event.getOldLength());
// TODO - update jumps
}
@@ -361,7 +359,10 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
@Override
public void bookmarkAdded(@NotNull BookmarkGroup group, com.intellij.ide.bookmark.@NotNull Bookmark bookmark) {
if (!VimPlugin.isEnabled()) return;
if (!VimPlugin.getOptionService().isSet(OptionScope.GLOBAL.INSTANCE, IjVimOptionService.ideamarksName, IjVimOptionService.ideamarksName)) return;
if (!VimPlugin.getOptionService()
.isSet(OptionScope.GLOBAL.INSTANCE, IjVimOptionService.ideamarksName, IjVimOptionService.ideamarksName)) {
return;
}
if (!(bookmark instanceof LineBookmark)) return;
BookmarksManager bookmarksManager = BookmarksManager.getInstance(myProject);
@@ -378,7 +379,10 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
@Override
public void bookmarkRemoved(@NotNull BookmarkGroup group, com.intellij.ide.bookmark.@NotNull Bookmark bookmark) {
if (!VimPlugin.isEnabled()) return;
if (!VimPlugin.getOptionService().isSet(OptionScope.GLOBAL.INSTANCE, IjVimOptionService.ideamarksName, IjVimOptionService.ideamarksName)) return;
if (!VimPlugin.getOptionService()
.isSet(OptionScope.GLOBAL.INSTANCE, IjVimOptionService.ideamarksName, IjVimOptionService.ideamarksName)) {
return;
}
if (!(bookmark instanceof LineBookmark)) return;
BookmarksManager bookmarksManager = BookmarksManager.getInstance(myProject);
@@ -387,7 +391,8 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
if (type == null) return;
char ch = type.getMnemonic();
if (GLOBAL_MARKS.indexOf(ch) != -1) {
FileMarks<Character, Mark> fmarks = VimPlugin.getMark().getFileMarks(((LineBookmark)bookmark).getFile().getPath());
FileMarks<Character, Mark> fmarks =
VimPlugin.getMark().getFileMarks(((LineBookmark)bookmark).getFile().getPath());
fmarks.remove(ch);
VimPlugin.getMark().globalMarks.remove(ch);
}
@@ -404,6 +409,17 @@ public class MarkGroup extends VimMarkGroupBase implements PersistentStateCompon
}
}
/**
* COMPATIBILITY-LAYER: Method added
* Please see: <a href="https://jb.gg/zo8n0r">doc</a>
*
* @deprecated Please use method with VimEditor
*/
@Deprecated
public void saveJumpLocation(Editor editor) {
this.saveJumpLocation(new IjVimEditor(editor));
}
private static final int SAVE_MARK_COUNT = 20;
private static final Logger logger = Logger.getInstance(MarkGroup.class.getName());

View File

@@ -23,8 +23,10 @@ import com.intellij.openapi.editor.ex.util.EditorUtil;
import com.intellij.openapi.fileEditor.FileEditor;
import com.intellij.openapi.fileEditor.FileEditorManagerEvent;
import com.intellij.openapi.fileEditor.TextEditor;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.EditorTabbedContainer;
import com.intellij.openapi.fileEditor.impl.EditorWindow;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.LocalFileSystem;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.openapi.vfs.VirtualFileManager;
@@ -711,7 +713,7 @@ public class MotionGroup extends VimMotionGroupBase {
}
private static int getScrollJump(@NotNull Editor editor, int height) {
final EnumSet<CommandFlags> flags = CommandState.getInstance(new IjVimEditor(editor)).getExecutingCommandFlags();
final EnumSet<CommandFlags> flags = VimStateMachine.getInstance(new IjVimEditor(editor)).getExecutingCommandFlags();
final boolean scrollJump = !flags.contains(CommandFlags.FLAG_IGNORE_SCROLL_JUMP);
// Default value is 1. Zero is a valid value, but we normalise to 1 - we always want to scroll at least one line
@@ -736,7 +738,7 @@ public class MotionGroup extends VimMotionGroupBase {
final int halfWidth = getApproximateScreenWidth(editor) / 2;
final int scrollOffset = getNormalizedSideScrollOffset(editor);
final EnumSet<CommandFlags> flags = CommandState.getInstance(new IjVimEditor(editor)).getExecutingCommandFlags();
final EnumSet<CommandFlags> flags = VimStateMachine.getInstance(new IjVimEditor(editor)).getExecutingCommandFlags();
final boolean allowSidescroll = !flags.contains(CommandFlags.FLAG_IGNORE_SIDE_SCROLL_JUMP);
int sidescroll = ((VimInt) VimPlugin.getOptionService().getOptionValue(new OptionScope.LOCAL(new IjVimEditor(editor)), OptionConstants.sidescrollName, OptionConstants.sidescrollName)).getValue();
@@ -1168,15 +1170,25 @@ public class MotionGroup extends VimMotionGroupBase {
@Override
public int moveCaretGotoPreviousTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) {
switchEditorTab(EditorWindow.DATA_KEY.getData((DataContext)context.getContext()), rawCount >= 1 ? -rawCount : -1, false);
Project project = ((IjVimEditor)editor).getEditor().getProject();
if (project == null) {
return editor.currentCaret().getOffset().getPoint();
}
EditorWindow currentWindow = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow();
switchEditorTab(currentWindow, rawCount >= 1 ? -rawCount : -1, false);
return editor.currentCaret().getOffset().getPoint();
}
@Override
public int moveCaretGotoNextTab(@NotNull VimEditor editor, @NotNull ExecutionContext context, int rawCount) {
final boolean absolute = rawCount >= 1;
switchEditorTab(EditorWindow.DATA_KEY.getData((DataContext)context.getContext()), absolute ? rawCount - 1 : 1,
absolute);
Project project = ((IjVimEditor)editor).getEditor().getProject();
if (project == null) {
return editor.currentCaret().getOffset().getPoint();
}
EditorWindow currentWindow = FileEditorManagerEx.getInstanceEx(project).getSplitters().getCurrentWindow();
switchEditorTab(currentWindow, absolute ? rawCount - 1 : 1, absolute);
return editor.currentCaret().getOffset().getPoint();
}
@@ -1200,7 +1212,7 @@ public class MotionGroup extends VimMotionGroupBase {
if (fileEditor instanceof TextEditor) {
final Editor editor = ((TextEditor)fileEditor).getEditor();
ExOutputModel.getInstance(editor).clear();
if (CommandState.getInstance(new IjVimEditor(editor)).getMode() == CommandState.Mode.VISUAL) {
if (VimStateMachine.getInstance(new IjVimEditor(editor)).getMode() == VimStateMachine.Mode.VISUAL) {
ModeHelper.exitVisualMode(editor);
KeyHandler.getInstance().reset(new IjVimEditor(editor));
}

View File

@@ -20,26 +20,24 @@ package com.maddyhome.idea.vim.group
import com.intellij.icons.AllIcons
import com.intellij.ide.BrowserUtil
import com.intellij.ide.IdeBundle
import com.intellij.ide.actions.OpenFileAction
import com.intellij.ide.actions.RevealFileAction
import com.intellij.notification.ActionCenter
import com.intellij.notification.Notification
import com.intellij.notification.NotificationGroup
import com.intellij.notification.NotificationGroupManager
import com.intellij.notification.NotificationListener
import com.intellij.notification.NotificationType
import com.intellij.openapi.actionSystem.ActionUpdateThread
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.KeyboardShortcut
import com.intellij.openapi.ide.CopyPasteManager
import com.intellij.openapi.keymap.Keymap
import com.intellij.openapi.keymap.KeymapUtil
import com.intellij.openapi.options.ShowSettingsUtil
import com.intellij.openapi.project.DumbAwareAction
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.util.SystemInfo
import com.intellij.openapi.util.registry.Registry
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.helper.MessageHelper
import com.maddyhome.idea.vim.key.ShortcutOwner
@@ -50,7 +48,6 @@ import com.maddyhome.idea.vim.statistic.ActionTracker
import com.maddyhome.idea.vim.ui.VimEmulationConfigurable
import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
import com.maddyhome.idea.vim.vimscript.services.VimRcService
import org.jetbrains.annotations.Nls
import java.awt.datatransfer.StringSelection
import java.io.File
import javax.swing.KeyStroke
@@ -115,23 +112,6 @@ class NotificationService(private val project: Project?) {
Messages.getQuestionIcon()
)
fun specialKeymap(keymap: Keymap, listener: NotificationListener.Adapter) {
val notification = IDEAVIM_STICKY_GROUP.createNotification(
IDEAVIM_NOTIFICATION_TITLE,
"IdeaVim plugin doesn't use the special \"Vim\" keymap any longer. " +
"Switching to \"${keymap.presentableName}\" keymap.<br/><br/>" +
"Now it is possible to set up:<br/>" +
"<ul>" +
"<li>Vim keys in your ~/.ideavimrc file using key mapping commands</li>" +
"<li>IDE action shortcuts in \"File | Settings | Keymap\"</li>" +
"<li>Vim or IDE handlers for conflicting shortcuts in <a href='#settings'>Vim Emulation</a> settings</li>" +
"</ul>",
NotificationType.INFORMATION
)
notification.setListener(listener)
notification.notify(project)
}
fun noVimrcAsDefault() {
val notification = IDEAVIM_STICKY_GROUP.createNotification(
IDEAVIM_NOTIFICATION_TITLE,
@@ -208,7 +188,7 @@ class NotificationService(private val project: Project?) {
Notification(IDEAVIM_NOTIFICATION_ID, IDEAVIM_NOTIFICATION_TITLE, content, NotificationType.INFORMATION).let {
notification = it
it.whenExpired { notification = null }
it.setContent(it.content + "<br><br><small>Use ${getToolwindowName()} to see previous ids</small>")
it.setContent(it.content + "<br><br><small>Use ${ActionCenter.getToolwindowName()} to see previous ids</small>")
it.addAction(StopTracking())
@@ -222,15 +202,6 @@ class NotificationService(private val project: Project?) {
}
}
// [VERSION UPDATE] 221+ Use ActionCenter.getToolWindowName
private fun getToolwindowName(): @Nls String {
return IdeBundle.message(if (isEnabled()) "toolwindow.stripe.Notifications" else "toolwindow.stripe.Event_Log")
}
private fun isEnabled(): Boolean {
return Registry.`is`("ide.notification.action.center", true)
}
class CopyActionId(val id: String?, val project: Project?) : DumbAwareAction(MessageHelper.message("action.copy.action.id.text")) {
override fun actionPerformed(e: AnActionEvent) {
CopyPasteManager.getInstance().setContents(StringSelection(id ?: ""))
@@ -251,6 +222,8 @@ class NotificationService(private val project: Project?) {
override fun update(e: AnActionEvent) {
e.presentation.isEnabled = id != null
}
override fun getActionUpdateThread() = ActionUpdateThread.BGT
}
class StopTracking : DumbAwareAction("Stop Tracking") {
@@ -287,6 +260,8 @@ class NotificationService(private val project: Project?) {
val actionText = if (VimRcService.findIdeaVimRc() != null) "Open ~/.ideavimrc" else "Create ~/.ideavimrc"
e.presentation.text = actionText
}
override fun getActionUpdateThread() = ActionUpdateThread.BGT
}
@Suppress("DialogTitleCapitalization")

View File

@@ -37,7 +37,7 @@ import com.maddyhome.idea.vim.KeyHandler;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.api.*;
import com.maddyhome.idea.vim.command.Command;
import com.maddyhome.idea.vim.command.CommandState;
import com.maddyhome.idea.vim.command.VimStateMachine;
import com.maddyhome.idea.vim.ex.ExException;
import com.maddyhome.idea.vim.ex.InvalidCommandException;
import com.maddyhome.idea.vim.helper.UiHelper;
@@ -90,9 +90,9 @@ public class ProcessGroup extends VimProcessGroupBase {
if (editor.isOneLineMode()) return;
String initText = getRange(((IjVimEditor) editor).getEditor(), cmd);
CommandState.getInstance(editor).pushModes(CommandState.Mode.CMD_LINE, CommandState.SubMode.NONE);
VimStateMachine.getInstance(editor).pushModes(VimStateMachine.Mode.CMD_LINE, VimStateMachine.SubMode.NONE);
ExEntryPanel panel = ExEntryPanel.getInstance();
panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, 1);
panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, cmd.getCount());
}
@Override
@@ -108,7 +108,7 @@ public class ProcessGroup extends VimProcessGroupBase {
return true;
}
else {
CommandState.getInstance(editor).popModes();
VimStateMachine.getInstance(editor).popModes();
KeyHandler.getInstance().reset(editor);
return false;
}
@@ -119,11 +119,11 @@ public class ProcessGroup extends VimProcessGroupBase {
panel.deactivate(true);
boolean res = true;
try {
CommandState.getInstance(editor).popModes();
VimStateMachine.getInstance(editor).popModes();
logger.debug("processing command");
final String text = panel.getText();
String text = panel.getText();
if (!panel.getLabel().equals(":")) {
// Search is handled via Argument.Type.EX_STRING. Although ProcessExEntryAction is registered as the handler for
@@ -134,7 +134,15 @@ public class ProcessGroup extends VimProcessGroupBase {
if (logger.isDebugEnabled()) logger.debug("swing=" + SwingUtilities.isEventDispatchThread());
VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE);
int repeat = 1;
if (text.contains("raction ")) {
text = text.replace("raction ", "action ");
repeat = panel.getCount();
}
for (int i = 0; i < repeat; i++) {
VimInjectorKt.getInjector().getVimscriptExecutor().execute(text, editor, context, skipHistory(editor), true, CommandLineVimLContext.INSTANCE);
}
}
catch (ExException e) {
VimPlugin.showMessage(e.getMessage());
@@ -152,11 +160,11 @@ public class ProcessGroup extends VimProcessGroupBase {
// commands executed from map command / macro should not be added to history
private boolean skipHistory(VimEditor editor) {
return CommandState.getInstance(editor).getMappingState().isExecutingMap() || injector.getMacro().isExecutingMacro();
return VimStateMachine.getInstance(editor).getMappingState().isExecutingMap() || injector.getMacro().isExecutingMacro();
}
public void cancelExEntry(final @NotNull VimEditor editor, boolean resetCaret) {
CommandState.getInstance(editor).popModes();
VimStateMachine.getInstance(editor).popModes();
KeyHandler.getInstance().reset(editor);
ExEntryPanel panel = ExEntryPanel.getInstance();
panel.deactivate(true, resetCaret);
@@ -165,14 +173,14 @@ public class ProcessGroup extends VimProcessGroupBase {
@Override
public void startFilterCommand(@NotNull VimEditor editor, ExecutionContext context, @NotNull Command cmd) {
String initText = getRange(((IjVimEditor) editor).getEditor(), cmd) + "!";
CommandState.getInstance(editor).pushModes(CommandState.Mode.CMD_LINE, CommandState.SubMode.NONE);
VimStateMachine.getInstance(editor).pushModes(VimStateMachine.Mode.CMD_LINE, VimStateMachine.SubMode.NONE);
ExEntryPanel panel = ExEntryPanel.getInstance();
panel.activate(((IjVimEditor) editor).getEditor(), ((IjExecutionContext) context).getContext(), ":", initText, 1);
}
private @NotNull String getRange(Editor editor, @NotNull Command cmd) {
String initText = "";
if (CommandState.getInstance(new IjVimEditor(editor)).getMode() == CommandState.Mode.VISUAL) {
if (VimStateMachine.getInstance(new IjVimEditor(editor)).getMode() == VimStateMachine.Mode.VISUAL) {
initText = "'<,'>";
}
else if (cmd.getRawCount() > 0) {

View File

@@ -61,7 +61,10 @@ internal fun Project.createLineBookmark(editor: Editor, line: Int, mnemonic: Cha
val type = BookmarkType.get(mnemonic)
if (type == BookmarkType.DEFAULT) return null
val group = bookmarksManager.defaultGroup ?: bookmarksManager.addGroup("IdeaVim", true) ?: return null
val group = bookmarksManager.defaultGroup
?: bookmarksManager.getGroup("IdeaVim")
?: bookmarksManager.addGroup("IdeaVim", true)
?: return null
if (group.canAdd(bookmark)) {
group.add(bookmark, type)
return bookmark

View File

@@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.group;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.actionSystem.PlatformDataKeys;
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx;
import com.intellij.openapi.fileEditor.impl.EditorComposite;
import com.intellij.openapi.fileEditor.impl.EditorWindow;
import com.intellij.openapi.fileEditor.impl.EditorWithProviderComposite;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.concurrency.annotations.RequiresReadLock;
@@ -183,7 +183,7 @@ public class WindowGroup extends WindowGroupBase {
}
private static @Nullable Rectangle getEditorWindowRectangle(@NotNull EditorWindow window) {
final EditorWithProviderComposite editor = window.getSelectedEditor();
final EditorComposite editor = window.getSelectedComposite();
if (editor != null) {
final Point point = editor.getComponent().getLocationOnScreen();
final Dimension dimension = editor.getComponent().getSize();

View File

@@ -34,8 +34,9 @@ import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.isBlock
import com.maddyhome.idea.vim.command.isChar
import com.maddyhome.idea.vim.command.isLine
@@ -43,7 +44,9 @@ import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.TestClipboardModel
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.mark.VimMarkConstants.MARK_CHANGE_POS
import com.maddyhome.idea.vim.newapi.IjVimCaret
import com.maddyhome.idea.vim.newapi.IjVimEditor
@@ -60,10 +63,20 @@ import java.awt.datatransfer.DataFlavor
import kotlin.math.min
class PutGroup : VimPutBase() {
override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData): Boolean {
override fun putTextForCaret(editor: VimEditor, caret: VimCaret, context: ExecutionContext, data: PutData, updateVisualMarks: Boolean): Boolean {
val additionalData = collectPreModificationData(editor, data)
data.visualSelection?.let {
deleteSelectedText(
editor,
data,
OperatorArguments(false, 0, editor.mode, editor.subMode)
)
}
val processedText = processText(editor, data) ?: return false
putForCaret(editor, caret, data, additionalData, context, processedText)
if (editor.primaryCaret() == caret && updateVisualMarks) {
wrapInsertedTextWithVisualMarks(editor, data, processedText)
}
return true
}
@@ -75,7 +88,7 @@ class PutGroup : VimPutBase() {
additionalData: Map<String, Any>,
) {
val visualSelection = data.visualSelection
val subMode = visualSelection?.typeInEditor?.toSubMode() ?: CommandState.SubMode.NONE
val subMode = visualSelection?.typeInEditor?.toSubMode() ?: VimStateMachine.SubMode.NONE
if (OptionConstants.clipboard_ideaput in (
injector.optionService
.getOptionValue(OptionScope.GLOBAL, OptionConstants.clipboardName) as VimString
@@ -89,7 +102,6 @@ class PutGroup : VimPutBase() {
}
}
notifyAboutIdeaPut(editor)
logger.debug("Perform put via plugin")
val myCarets = if (visualSelection != null) {
visualSelection.caretsAndSelections.keys.sortedByDescending { it.getLogicalPosition() }
@@ -109,16 +121,19 @@ class PutGroup : VimPutBase() {
context: ExecutionContext,
text: ProcessedTextData,
) {
notifyAboutIdeaPut(editor)
if (data.visualSelection?.typeInEditor?.isLine == true && editor.isOneLineMode()) return
val startOffsets = prepareDocumentAndGetStartOffsets(editor, caret, text.typeInRegister, data, additionalData)
startOffsets.forEach { startOffset ->
val subMode = data.visualSelection?.typeInEditor?.toSubMode() ?: CommandState.SubMode.NONE
val subMode = data.visualSelection?.typeInEditor?.toSubMode() ?: VimStateMachine.SubMode.NONE
val endOffset = putTextInternal(
editor, caret, context, text.text, text.typeInRegister, subMode,
startOffset, data.count, data.indent, data.caretAfterInsertedText
)
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
if (caret == editor.primaryCaret()) {
VimPlugin.getMark().setChangeMarks(editor, TextRange(startOffset, endOffset))
}
moveCaretToEndPosition(
editor,
caret,
@@ -175,7 +190,12 @@ class PutGroup : VimPutBase() {
}
}
visualSelection.typeInEditor.isLine -> {
if (caret.offset == editor.fileSize && editor.fileSize != 0) {
val lastChar = if (editor.fileSize > 0) {
editor.document.getText(com.intellij.openapi.util.TextRange(editor.fileSize - 1, editor.fileSize))[0]
} else {
null
}
if (caret.offset == editor.fileSize && editor.fileSize != 0 && lastChar != '\n') {
application.runWriteAction { editor.document.insertString(caret.offset, "\n") }
listOf(caret.offset + 1)
} else listOf(caret.offset)
@@ -233,7 +253,7 @@ class PutGroup : VimPutBase() {
vimEditor: VimEditor,
vimContext: ExecutionContext,
text: ProcessedTextData,
subMode: CommandState.SubMode,
subMode: VimStateMachine.SubMode,
data: PutData,
additionalData: Map<String, Any>,
) {

View File

@@ -18,23 +18,20 @@
package com.maddyhome.idea.vim.group.copy
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.intellij.util.containers.ContainerUtil
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.action.motion.updown.MotionDownLess1FirstNonSpaceAction
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.Argument
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.group.MotionGroup
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.listener.VimYankListener
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.yank.YankGroupBase
import org.jetbrains.annotations.Contract
import kotlin.math.min
@@ -46,8 +43,8 @@ class YankGroup : YankGroupBase() {
fun removeListener(listener: VimYankListener) = yankListeners.remove(listener)
private fun notifyListeners(editor: Editor, textRange: TextRange) = yankListeners.forEach {
it.yankPerformed(editor, textRange)
private fun notifyListeners(editor: VimEditor, textRange: TextRange) = yankListeners.forEach {
it.yankPerformed(editor.ij, textRange)
}
/**
@@ -67,32 +64,38 @@ class YankGroup : YankGroupBase() {
operatorArguments: OperatorArguments
): Boolean {
val motion = argument.motion
val type = if (motion.isLinewiseMotion()) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE
val caretModel = editor.ij.caretModel
if (caretModel.caretCount <= 0) return false
val nativeCaretCount = editor.nativeCarets().size
if (nativeCaretCount <= 0) return false
val ranges = ArrayList<Pair<Int, Int>>(caretModel.caretCount)
val carretToRange = HashMap<VimCaret, TextRange>(nativeCaretCount)
val ranges = ArrayList<Pair<Int, Int>>(nativeCaretCount)
// This logic is from original vim
val startOffsets =
if (argument.motion.action is MotionDownLess1FirstNonSpaceAction) null else HashMap<Caret, Int>(caretModel.caretCount)
val startOffsets = if (argument.motion.action is MotionDownLess1FirstNonSpaceAction) null else HashMap<VimCaret, Int>(nativeCaretCount)
for (caret in caretModel.allCarets) {
val motionRange = MotionGroup.getMotionRange(editor.ij, caret, context.ij, argument, operatorArguments)
for (caret in editor.nativeCarets()) {
val motionRange = injector.motion.getMotionRange(editor, caret, context, argument, operatorArguments)
?: continue
assert(motionRange.size() == 1)
ranges.add(motionRange.startOffset to motionRange.endOffset)
startOffsets?.put(caret, motionRange.normalize().startOffset)
carretToRange[caret] = TextRange(motionRange.startOffset, motionRange.endOffset)
}
val type = if (motion.isLinewiseMotion()) SelectionType.LINE_WISE else SelectionType.CHARACTER_WISE
val range = getTextRange(ranges, type) ?: return false
if (range.size() == 0) return false
val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type
return yankRange(editor.ij, range, selectionType, startOffsets)
return yankRange(
editor,
carretToRange,
range,
type,
startOffsets
)
}
/**
@@ -103,19 +106,21 @@ class YankGroup : YankGroupBase() {
* @return true if able to yank the lines, false if not
*/
override fun yankLine(editor: VimEditor, count: Int): Boolean {
val caretModel = editor.ij.caretModel
val ranges = ArrayList<Pair<Int, Int>>(caretModel.caretCount)
for (caret in caretModel.allCarets) {
val start = VimPlugin.getMotion().moveCaretToLineStart(editor, caret.vim)
val end = min(VimPlugin.getMotion().moveCaretToLineEndOffset(editor, caret.vim, count - 1, true) + 1, editor.fileSize().toInt())
val caretCount = editor.nativeCarets().size
val ranges = ArrayList<Pair<Int, Int>>(caretCount)
val caretToRange = HashMap<VimCaret, TextRange>(caretCount)
for (caret in editor.nativeCarets()) {
val start = injector.motion.moveCaretToLineStart(editor, caret)
val end = min(injector.motion.moveCaretToLineEndOffset(editor, caret, count - 1, true) + 1, editor.fileSize().toInt())
if (end == -1) continue
ranges.add(start to end)
caretToRange[caret] = TextRange(start, end)
}
val range = getTextRange(ranges, SelectionType.LINE_WISE) ?: return false
return yankRange(editor.ij, range, SelectionType.LINE_WISE, null)
return yankRange(editor, caretToRange, range, SelectionType.LINE_WISE, null)
}
/**
@@ -129,6 +134,7 @@ class YankGroup : YankGroupBase() {
override fun yankRange(editor: VimEditor, range: TextRange?, type: SelectionType, moveCursor: Boolean): Boolean {
range ?: return false
val caretToRange = HashMap<VimCaret, TextRange>()
val selectionType = if (type == SelectionType.CHARACTER_WISE && range.isMultiple) SelectionType.BLOCK_WISE else type
if (type == SelectionType.LINE_WISE) {
@@ -143,24 +149,25 @@ class YankGroup : YankGroupBase() {
}
}
val caretModel = editor.ij.caretModel
val rangeStartOffsets = range.startOffsets
val rangeEndOffsets = range.endOffsets
return if (moveCursor) {
val startOffsets = HashMap<Caret, Int>(caretModel.caretCount)
if (type == SelectionType.BLOCK_WISE) {
startOffsets[caretModel.primaryCaret] = range.normalize().startOffset
} else {
val carets = caretModel.allCarets
for (i in carets.indices) {
startOffsets[carets[i]] = TextRange(rangeStartOffsets[i], rangeEndOffsets[i]).normalize().startOffset
}
}
yankRange(editor.ij, range, selectionType, startOffsets)
val startOffsets = HashMap<VimCaret, Int>(editor.nativeCarets().size)
if (type == SelectionType.BLOCK_WISE) {
startOffsets[editor.primaryCaret()] = range.normalize().startOffset
caretToRange[editor.primaryCaret()] = range
} else {
yankRange(editor.ij, range, selectionType, null)
for ((i, caret) in editor.nativeCarets().withIndex()) {
val textRange = TextRange(rangeStartOffsets[i], rangeEndOffsets[i])
startOffsets[caret] = textRange.normalize().startOffset
caretToRange[caret] = textRange
}
}
return if (moveCursor) {
yankRange(editor, caretToRange, range, selectionType, startOffsets)
} else {
yankRange(editor, caretToRange, range, selectionType, null)
}
}
@@ -192,15 +199,20 @@ class YankGroup : YankGroupBase() {
}
private fun yankRange(
editor: Editor,
editor: VimEditor,
caretToRange: Map<VimCaret, TextRange>,
range: TextRange,
type: SelectionType,
startOffsets: Map<Caret, Int>?,
startOffsets: Map<VimCaret, Int>?,
): Boolean {
startOffsets?.forEach { (caret, offset) -> MotionGroup.moveCaret(editor, caret, offset) }
startOffsets?.forEach { (caret, offset) -> injector.motion.moveCaret(editor, caret, offset) }
notifyListeners(editor, range)
return VimPlugin.getRegister().storeText(editor.vim, range, type, false)
var result = true
for ((caret, myRange) in caretToRange) {
result = caret.registerStorage.storeText(caret, editor, myRange, type, false) && result
}
return result
}
}

View File

@@ -23,9 +23,9 @@ import com.intellij.openapi.diagnostic.trace
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.exitSelectMode
import com.maddyhome.idea.vim.helper.exitVisualMode
import com.maddyhome.idea.vim.helper.hasVisualSelection
@@ -35,8 +35,8 @@ import com.maddyhome.idea.vim.helper.inSelectMode
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
import com.maddyhome.idea.vim.helper.isTemplateActive
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.popAllModes
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.listener.VimListenerManager
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.vim
@@ -58,7 +58,7 @@ object IdeaSelectionControl {
editor: Editor,
selectionSource: VimListenerManager.SelectionSource = VimListenerManager.SelectionSource.OTHER,
) {
VimVisualTimer.singleTask(editor.mode) { initialMode ->
VimVisualTimer.singleTask(editor.editorMode) { initialMode ->
if (editor.isIdeaVimDisabledHere) return@singleTask
@@ -80,13 +80,13 @@ object IdeaSelectionControl {
return@singleTask
}
logger.debug("Some carets have selection. State before adjustment: ${editor.vim.commandState.toSimpleString()}")
logger.debug("Some carets have selection. State before adjustment: ${editor.vim.vimStateMachine.toSimpleString()}")
editor.popAllModes()
activateMode(editor, chooseSelectionMode(editor, selectionSource, true))
} else {
logger.debug("None of carets have selection. State before adjustment: ${editor.vim.commandState.toSimpleString()}")
logger.debug("None of carets have selection. State before adjustment: ${editor.vim.vimStateMachine.toSimpleString()}")
if (editor.inVisualMode) editor.exitVisualMode()
if (editor.inSelectMode) editor.exitSelectMode(false)
@@ -96,7 +96,7 @@ object IdeaSelectionControl {
}
KeyHandler.getInstance().reset(editor.vim)
logger.debug("${editor.mode} is enabled")
logger.debug("${editor.editorMode} is enabled")
}
}
@@ -110,68 +110,68 @@ object IdeaSelectionControl {
* This method is created to improve user experience. It allows avoiding delay in some operations
* (because [controlNonVimSelectionChange] is not executed immediately)
*/
fun predictMode(editor: Editor, selectionSource: VimListenerManager.SelectionSource): CommandState.Mode {
fun predictMode(editor: Editor, selectionSource: VimListenerManager.SelectionSource): VimStateMachine.Mode {
if (editor.selectionModel.hasSelection(true)) {
if (dontChangeMode(editor)) return editor.mode
if (dontChangeMode(editor)) return editor.editorMode
return chooseSelectionMode(editor, selectionSource, false)
} else {
return chooseNonSelectionMode(editor)
}
}
private fun activateMode(editor: Editor, mode: CommandState.Mode) {
private fun activateMode(editor: Editor, mode: VimStateMachine.Mode) {
when (mode) {
CommandState.Mode.VISUAL -> VimPlugin.getVisualMotion()
VimStateMachine.Mode.VISUAL -> VimPlugin.getVisualMotion()
.enterVisualMode(editor.vim, VimPlugin.getVisualMotion().autodetectVisualSubmode(editor.vim))
CommandState.Mode.SELECT -> VimPlugin.getVisualMotion()
VimStateMachine.Mode.SELECT -> VimPlugin.getVisualMotion()
.enterSelectMode(editor.vim, VimPlugin.getVisualMotion().autodetectVisualSubmode(editor.vim))
CommandState.Mode.INSERT -> VimPlugin.getChange().insertBeforeCursor(
VimStateMachine.Mode.INSERT -> VimPlugin.getChange().insertBeforeCursor(
editor.vim,
EditorDataContext.init(editor).vim
)
CommandState.Mode.COMMAND -> Unit
VimStateMachine.Mode.COMMAND -> Unit
else -> error("Unexpected mode: $mode")
}
}
private fun dontChangeMode(editor: Editor): Boolean =
editor.isTemplateActive() && (IdeaRefactorModeHelper.keepMode() || editor.mode.hasVisualSelection)
editor.isTemplateActive() && (IdeaRefactorModeHelper.keepMode() || editor.editorMode.hasVisualSelection)
private fun chooseNonSelectionMode(editor: Editor): CommandState.Mode {
private fun chooseNonSelectionMode(editor: Editor): VimStateMachine.Mode {
val templateActive = editor.isTemplateActive()
if (templateActive && editor.inNormalMode || editor.inInsertMode) {
return CommandState.Mode.INSERT
return VimStateMachine.Mode.INSERT
}
return CommandState.Mode.COMMAND
return VimStateMachine.Mode.COMMAND
}
private fun chooseSelectionMode(
editor: Editor,
selectionSource: VimListenerManager.SelectionSource,
logReason: Boolean,
): CommandState.Mode {
): VimStateMachine.Mode {
val selectmode = (VimPlugin.getOptionService().getOptionValue(OptionScope.LOCAL(IjVimEditor(editor)), OptionConstants.selectmodeName) as VimString).value
return when {
editor.isOneLineMode -> {
if (logReason) logger.debug("Enter select mode. Reason: one line mode")
CommandState.Mode.SELECT
VimStateMachine.Mode.SELECT
}
selectionSource == VimListenerManager.SelectionSource.MOUSE && OptionConstants.selectmode_mouse in selectmode -> {
if (logReason) logger.debug("Enter select mode. Selection source is mouse and selectMode option has mouse")
CommandState.Mode.SELECT
VimStateMachine.Mode.SELECT
}
editor.isTemplateActive() && IdeaRefactorModeHelper.selectMode() -> {
if (logReason) logger.debug("Enter select mode. Template is active and selectMode has template")
CommandState.Mode.SELECT
VimStateMachine.Mode.SELECT
}
selectionSource == VimListenerManager.SelectionSource.OTHER &&
OptionConstants.selectmode_ideaselection in (VimPlugin.getOptionService().getOptionValue(OptionScope.GLOBAL, OptionConstants.selectmodeName) as VimString).value -> {
if (logReason) logger.debug("Enter select mode. Selection source is OTHER and selectMode has refactoring")
CommandState.Mode.SELECT
VimStateMachine.Mode.SELECT
}
else -> {
if (logReason) logger.debug("Enter visual mode")
CommandState.Mode.VISUAL
VimStateMachine.Mode.VISUAL
}
}
}

View File

@@ -19,7 +19,7 @@
package com.maddyhome.idea.vim.group.visual
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.group.visual.VimVisualTimer.mode
import com.maddyhome.idea.vim.group.visual.VimVisualTimer.singleTask
import com.maddyhome.idea.vim.options.OptionScope
@@ -66,9 +66,9 @@ import javax.swing.Timer
object VimVisualTimer {
var swingTimer: Timer? = null
var mode: CommandState.Mode? = null
var mode: VimStateMachine.Mode? = null
inline fun singleTask(currentMode: CommandState.Mode, crossinline task: (initialMode: CommandState.Mode?) -> Unit) {
inline fun singleTask(currentMode: VimStateMachine.Mode, crossinline task: (initialMode: VimStateMachine.Mode?) -> Unit) {
swingTimer?.stop()
if (mode == null) mode = currentMode
@@ -92,7 +92,7 @@ object VimVisualTimer {
}
}
inline fun timerAction(task: (initialMode: CommandState.Mode?) -> Unit) {
inline fun timerAction(task: (initialMode: VimStateMachine.Mode?) -> Unit) {
task(mode)
swingTimer = null
mode = null

View File

@@ -23,13 +23,13 @@ import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.VisualPosition
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimMotionGroupBase
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorHelper
import com.maddyhome.idea.vim.helper.editorMode
import com.maddyhome.idea.vim.helper.inBlockSubMode
import com.maddyhome.idea.vim.helper.inSelectMode
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.helper.isEndAllowed
import com.maddyhome.idea.vim.helper.mode
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.subMode
import com.maddyhome.idea.vim.helper.updateCaretsVisualAttributes
@@ -108,7 +108,7 @@ val Caret.vimLeadSelectionOffset: Int
}
}
return if (editor.subMode == CommandState.SubMode.VISUAL_LINE) {
return if (editor.subMode == VimStateMachine.SubMode.VISUAL_LINE) {
val selectionStartLine = editor.offsetToLogicalPosition(selectionStart).line
val caretLine = editor.offsetToLogicalPosition(this.offset).line
if (caretLine == selectionStartLine) {
@@ -132,8 +132,8 @@ val Caret.vimLeadSelectionOffset: Int
return caretOffset
}
fun moveCaretOneCharLeftFromSelectionEnd(editor: Editor, predictedMode: CommandState.Mode) {
if (predictedMode != CommandState.Mode.VISUAL) {
fun moveCaretOneCharLeftFromSelectionEnd(editor: Editor, predictedMode: VimStateMachine.Mode) {
if (predictedMode != VimStateMachine.Mode.VISUAL) {
if (!predictedMode.isEndAllowed) {
editor.caretModel.allCarets.forEach { caret ->
val lineEnd = EditorHelper.getLineEndForOffset(editor, caret.offset)
@@ -161,18 +161,18 @@ private fun setVisualSelection(selectionStart: Int, selectionEnd: Int, caret: Ca
val (start, end) = if (selectionStart > selectionEnd) selectionEnd to selectionStart else selectionStart to selectionEnd
val editor = caret.editor
val subMode = editor.subMode
val mode = editor.mode
val mode = editor.editorMode
val vimEditor = IjVimEditor(editor)
when (subMode) {
CommandState.SubMode.VISUAL_CHARACTER -> {
VimStateMachine.SubMode.VISUAL_CHARACTER -> {
val (nativeStart, nativeEnd) = charToNativeSelection(vimEditor, start, end, mode)
caret.vimSetSystemSelectionSilently(nativeStart, nativeEnd)
}
CommandState.SubMode.VISUAL_LINE -> {
VimStateMachine.SubMode.VISUAL_LINE -> {
val (nativeStart, nativeEnd) = lineToNativeSelection(vimEditor, start, end)
caret.vimSetSystemSelectionSilently(nativeStart, nativeEnd)
}
CommandState.SubMode.VISUAL_BLOCK -> {
VimStateMachine.SubMode.VISUAL_BLOCK -> {
editor.caretModel.removeSecondaryCarets()
// Set system selection
@@ -200,7 +200,7 @@ private fun setVisualSelection(selectionStart: Int, selectionEnd: Int, caret: Ca
// Put right caret position for tab character
aCaret.moveToVisualPosition(visualPosition)
}
if (mode != CommandState.Mode.SELECT &&
if (mode != VimStateMachine.Mode.SELECT &&
!EditorHelper.isLineEmpty(editor, line, false) &&
aCaret.offset == aCaret.selectionEnd &&
aCaret.selectionEnd - 1 >= lineStartOffset &&

View File

@@ -19,22 +19,34 @@
package com.maddyhome.idea.vim.group.visual
import com.intellij.find.FindManager
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimVisualMotionGroupBase
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.engine
import com.maddyhome.idea.vim.newapi.ij
import com.maddyhome.idea.vim.newapi.vim
/**
* @author Alex Plate
*/
class VisualMotionGroup : VimVisualMotionGroupBase() {
override fun autodetectVisualSubmode(editor: VimEditor): CommandState.SubMode {
override fun autodetectVisualSubmode(editor: VimEditor): VimStateMachine.SubMode {
// IJ specific. See https://youtrack.jetbrains.com/issue/VIM-1924.
val project = editor.ij.project
if (project != null && FindManager.getInstance(project).selectNextOccurrenceWasPerformed()) {
return CommandState.SubMode.VISUAL_CHARACTER
return VimStateMachine.SubMode.VISUAL_CHARACTER
}
return super.autodetectVisualSubmode(editor)
}
/**
* COMPATIBILITY-LAYER: Added a method
* Please see: https://jb.gg/zo8n0r
*/
fun enterVisualMode(editor: Editor, subMode: CommandState.SubMode? = null): Boolean {
return this.enterVisualMode(editor.vim, subMode?.engine)
}
}

View File

@@ -21,7 +21,7 @@ package com.maddyhome.idea.vim.handler
import com.intellij.serviceContainer.BaseKeyedLazyInstance
import com.intellij.util.SmartList
import com.intellij.util.xmlb.annotations.Attribute
import com.maddyhome.idea.vim.common.MappingMode
import com.maddyhome.idea.vim.command.MappingMode
import javax.swing.KeyStroke
/**

View File

@@ -23,7 +23,7 @@ import com.intellij.openapi.editor.CaretVisualAttributes
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.editor.ex.EditorSettingsExternalizable
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionChangeListener
import com.maddyhome.idea.vim.options.helpers.GuiCursorMode
@@ -75,7 +75,7 @@ object GuicursorChangeListener : OptionChangeListener<VimDataType> {
}
private fun Editor.guicursorMode(): GuiCursorMode {
if (this.vim.commandState.isReplaceCharacter) {
if (this.vim.vimStateMachine.isReplaceCharacter) {
// Can be true for NORMAL and VISUAL
return GuiCursorMode.REPLACE
}
@@ -84,18 +84,18 @@ private fun Editor.guicursorMode(): GuiCursorMode {
// makes much more use of SELECT than Vim does (e.g. it's the default for idearefactormode) so it makes sense for us
// to more visually distinguish VISUAL and SELECT. So we use INSERT; a selection and the insert caret is intuitively
// the same as SELECT
return when (mode) {
CommandState.Mode.COMMAND -> GuiCursorMode.NORMAL
CommandState.Mode.VISUAL -> GuiCursorMode.VISUAL // TODO: VISUAL_EXCLUSIVE
CommandState.Mode.SELECT -> GuiCursorMode.INSERT
CommandState.Mode.INSERT -> GuiCursorMode.INSERT
CommandState.Mode.OP_PENDING -> GuiCursorMode.OP_PENDING
CommandState.Mode.REPLACE -> GuiCursorMode.REPLACE
return when (editorMode) {
VimStateMachine.Mode.COMMAND -> GuiCursorMode.NORMAL
VimStateMachine.Mode.VISUAL -> GuiCursorMode.VISUAL // TODO: VISUAL_EXCLUSIVE
VimStateMachine.Mode.SELECT -> GuiCursorMode.INSERT
VimStateMachine.Mode.INSERT -> GuiCursorMode.INSERT
VimStateMachine.Mode.OP_PENDING -> GuiCursorMode.OP_PENDING
VimStateMachine.Mode.REPLACE -> GuiCursorMode.REPLACE
// This doesn't handle ci and cr, but we don't care - our CMD_LINE will never call this
CommandState.Mode.CMD_LINE -> GuiCursorMode.CMD_LINE
CommandState.Mode.INSERT_NORMAL -> GuiCursorMode.NORMAL
CommandState.Mode.INSERT_VISUAL -> GuiCursorMode.VISUAL
CommandState.Mode.INSERT_SELECT -> GuiCursorMode.INSERT
VimStateMachine.Mode.CMD_LINE -> GuiCursorMode.CMD_LINE
VimStateMachine.Mode.INSERT_NORMAL -> GuiCursorMode.NORMAL
VimStateMachine.Mode.INSERT_VISUAL -> GuiCursorMode.VISUAL
VimStateMachine.Mode.INSERT_SELECT -> GuiCursorMode.INSERT
}
}

View File

@@ -34,7 +34,7 @@ class CommandLineHelper : VimCommandLineHelper {
override fun inputString(vimEditor: VimEditor, prompt: String, finishOn: Char?): String? {
val editor = vimEditor.ij
if (vimEditor.commandState.isDotRepeatInProgress) {
if (vimEditor.vimStateMachine.isDotRepeatInProgress) {
val input = Extension.consumeString()
return input ?: error("Not enough strings saved: ${Extension.lastExtensionHandler}")
}

View File

@@ -23,89 +23,106 @@ package com.maddyhome.idea.vim.helper
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.command.engine
import com.maddyhome.idea.vim.command.ij
import com.maddyhome.idea.vim.newapi.vim
val Editor.isEndAllowed: Boolean
get() = when (this.mode) {
CommandState.Mode.INSERT, CommandState.Mode.VISUAL, CommandState.Mode.SELECT, CommandState.Mode.INSERT_VISUAL, CommandState.Mode.INSERT_SELECT -> true
CommandState.Mode.COMMAND, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.OP_PENDING, CommandState.Mode.INSERT_NORMAL -> {
get() = when (this.editorMode) {
VimStateMachine.Mode.INSERT, VimStateMachine.Mode.VISUAL, VimStateMachine.Mode.SELECT, VimStateMachine.Mode.INSERT_VISUAL, VimStateMachine.Mode.INSERT_SELECT -> true
VimStateMachine.Mode.COMMAND, VimStateMachine.Mode.CMD_LINE, VimStateMachine.Mode.REPLACE, VimStateMachine.Mode.OP_PENDING, VimStateMachine.Mode.INSERT_NORMAL -> {
// One day we'll use a proper insert_normal mode
if (this.mode.inSingleMode) true else usesVirtualSpace
if (this.editorMode.inSingleMode) true else usesVirtualSpace
}
}
val CommandState.Mode.isEndAllowedIgnoringOnemore: Boolean
val VimStateMachine.Mode.isEndAllowedIgnoringOnemore: Boolean
get() = when (this) {
CommandState.Mode.INSERT, CommandState.Mode.VISUAL, CommandState.Mode.SELECT -> true
CommandState.Mode.COMMAND, CommandState.Mode.CMD_LINE, CommandState.Mode.REPLACE, CommandState.Mode.OP_PENDING -> false
CommandState.Mode.INSERT_NORMAL -> false
CommandState.Mode.INSERT_VISUAL -> true
CommandState.Mode.INSERT_SELECT -> true
VimStateMachine.Mode.INSERT, VimStateMachine.Mode.VISUAL, VimStateMachine.Mode.SELECT -> true
VimStateMachine.Mode.COMMAND, VimStateMachine.Mode.CMD_LINE, VimStateMachine.Mode.REPLACE, VimStateMachine.Mode.OP_PENDING -> false
VimStateMachine.Mode.INSERT_NORMAL -> false
VimStateMachine.Mode.INSERT_VISUAL -> true
VimStateMachine.Mode.INSERT_SELECT -> true
}
val CommandState.Mode.hasVisualSelection
val VimStateMachine.Mode.hasVisualSelection
get() = when (this) {
CommandState.Mode.VISUAL, CommandState.Mode.SELECT -> true
CommandState.Mode.REPLACE, CommandState.Mode.CMD_LINE, CommandState.Mode.COMMAND, CommandState.Mode.INSERT, CommandState.Mode.OP_PENDING -> false
CommandState.Mode.INSERT_NORMAL -> false
CommandState.Mode.INSERT_VISUAL -> true
CommandState.Mode.INSERT_SELECT -> true
VimStateMachine.Mode.VISUAL, VimStateMachine.Mode.SELECT -> true
VimStateMachine.Mode.REPLACE, VimStateMachine.Mode.CMD_LINE, VimStateMachine.Mode.COMMAND, VimStateMachine.Mode.INSERT, VimStateMachine.Mode.OP_PENDING -> false
VimStateMachine.Mode.INSERT_NORMAL -> false
VimStateMachine.Mode.INSERT_VISUAL -> true
VimStateMachine.Mode.INSERT_SELECT -> true
}
val Editor.editorMode
get() = this.vim.vimStateMachine.mode
/**
* COMPATIBILITY-LAYER: New method
* Please see: https://jb.gg/zo8n0r
*/
val Editor.mode
get() = this.vim.commandState.mode
get() = this.vim.vimStateMachine.mode.ij
/**
* COMPATIBILITY-LAYER: New method
* Please see: https://jb.gg/zo8n0r
*/
val CommandState.Mode.isEndAllowed: Boolean
get() = this.engine.isEndAllowed
var Editor.subMode
get() = this.vim.commandState.subMode
get() = this.vim.vimStateMachine.subMode
set(value) {
this.vim.commandState.subMode = value
this.vim.vimStateMachine.subMode = value
}
@get:JvmName("inNormalMode")
val Editor.inNormalMode
get() = this.mode.inNormalMode
get() = this.editorMode.inNormalMode
@get:JvmName("inNormalMode")
val CommandState.Mode.inNormalMode
get() = this == CommandState.Mode.COMMAND || this == CommandState.Mode.INSERT_NORMAL
val VimStateMachine.Mode.inNormalMode
get() = this == VimStateMachine.Mode.COMMAND || this == VimStateMachine.Mode.INSERT_NORMAL
@get:JvmName("inInsertMode")
val Editor.inInsertMode
get() = this.mode == CommandState.Mode.INSERT || this.mode == CommandState.Mode.REPLACE
get() = this.editorMode == VimStateMachine.Mode.INSERT || this.editorMode == VimStateMachine.Mode.REPLACE
@get:JvmName("inRepeatMode")
val Editor.inRepeatMode
get() = this.vim.commandState.isDotRepeatInProgress
get() = this.vim.vimStateMachine.isDotRepeatInProgress
@get:JvmName("inVisualMode")
val Editor.inVisualMode
get() = this.mode.inVisualMode
get() = this.editorMode.inVisualMode
@get:JvmName("inSelectMode")
val Editor.inSelectMode
get() = this.mode == CommandState.Mode.SELECT || this.mode == CommandState.Mode.INSERT_SELECT
get() = this.editorMode == VimStateMachine.Mode.SELECT || this.editorMode == VimStateMachine.Mode.INSERT_SELECT
val VimEditor.inSelectMode
get() = this.mode == CommandState.Mode.SELECT || this.mode == CommandState.Mode.INSERT_SELECT
get() = this.mode == VimStateMachine.Mode.SELECT || this.mode == VimStateMachine.Mode.INSERT_SELECT
@get:JvmName("inBlockSubMode")
val Editor.inBlockSubMode
get() = this.subMode == CommandState.SubMode.VISUAL_BLOCK
get() = this.subMode == VimStateMachine.SubMode.VISUAL_BLOCK
@get:JvmName("inSingleCommandMode")
val Editor.inSingleCommandMode: Boolean
get() = this.mode.inSingleMode
get() = this.editorMode.inSingleMode
@get:JvmName("inSingleMode")
val CommandState.Mode.inSingleMode: Boolean
val VimStateMachine.Mode.inSingleMode: Boolean
get() = when (this) {
CommandState.Mode.INSERT_NORMAL, CommandState.Mode.INSERT_SELECT, CommandState.Mode.INSERT_VISUAL -> true
VimStateMachine.Mode.INSERT_NORMAL, VimStateMachine.Mode.INSERT_SELECT, VimStateMachine.Mode.INSERT_VISUAL -> true
else -> false
}
@get:JvmName("inSingleNormalMode")
val CommandState.Mode.inSingleNormalMode: Boolean
val VimStateMachine.Mode.inSingleNormalMode: Boolean
get() = when (this) {
CommandState.Mode.INSERT_NORMAL -> true
VimStateMachine.Mode.INSERT_NORMAL -> true
else -> false
}

View File

@@ -37,6 +37,7 @@ import org.jetbrains.annotations.Nullable;
import org.jetbrains.annotations.Range;
import java.awt.*;
import java.awt.geom.Point2D;
import java.nio.CharBuffer;
import java.util.Collections;
import java.util.Comparator;
@@ -152,6 +153,14 @@ public class EditorHelper {
: VimInjectorKt.getInjector().getEngineEditorHelper().logicalLineToVisualLine(editor, count - 1) + 1;
}
/**
* COMPATIBILITY-LAYER: Created a function
* Please see: <a href="https://jb.gg/zo8n0r">doc</a>
*/
public static int getVisualLineCount(final @NotNull Editor editor) {
return getVisualLineCount(new IjVimEditor(editor));
}
/**
* Gets the number of actual lines in the file
*
@@ -238,12 +247,27 @@ public class EditorHelper {
* font. It does not include inlays or folds.
* <p>
* Note that this value is only approximate and should be avoided whenever possible!
* </p>
*
* @param editor The editor
* @return The number of screen columns
*/
public static int getApproximateScreenWidth(final @NotNull Editor editor) {
return getVisibleArea(editor).width / EditorUtil.getPlainSpaceWidth(editor);
return (int)(getVisibleArea(editor).width / getPlainSpaceWidthFloat(editor));
}
/**
* Gets the width of the space character in the editor's plain font as a float.
* <p>
* Font width can be fractional, but {@link EditorUtil#getPlainSpaceWidth(Editor)} returns it as an int, which can
* lead to rounding errors.
* </p>
*
* @param editor The editor
* @return The width of the space character in the editor's plain font in pixels. It might be a fractional value.
*/
public static float getPlainSpaceWidthFloat(final @NotNull Editor editor) {
return EditorUtil.fontForChar(' ', Font.PLAIN, editor).charWidth2D(' ');
}
/**
@@ -795,19 +819,20 @@ public class EditorHelper {
}
}
final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x;
final int columnLeftX = (int) Math.round(editor.visualPositionToPoint2D(new VisualPosition(visualLine, targetVisualColumn)).getX());
scrollHorizontally(editor, columnLeftX);
}
public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn));
final Point2D point = editor.visualPositionToPoint2D(new VisualPosition(visualLine, visualColumn));
final int screenWidth = getVisibleArea(editor).width;
// Snap the column to the nearest standard column grid. This positions us nicely if there are an odd or even number
// of columns. It also works with inline inlays and folds. It is slightly inaccurate for proportional fonts, but is
// still a good solution. Besides, what kind of monster uses Vim with proportional fonts?
final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor);
final int x = max(0, point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth));
final float standardColumnWidth = EditorHelper.getPlainSpaceWidthFloat(editor);
final int screenMidColumn = (int) (screenWidth / standardColumnWidth / 2);
final int x = max(0, (int) Math.round(point.getX() - (screenMidColumn * standardColumnWidth)));
scrollHorizontally(editor, x);
}
@@ -832,7 +857,7 @@ public class EditorHelper {
}
// Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays
final int targetColumnRightX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x;
final int targetColumnRightX = (int) Math.round(editor.visualPositionToPoint2D(new VisualPosition(visualLine, targetVisualColumn + 1)).getX());
final int screenWidth = getVisibleArea(editor).width;
scrollHorizontally(editor, targetColumnRightX - screenWidth);
}
@@ -853,7 +878,7 @@ public class EditorHelper {
if (inlayAwareOffset == vimLastColumn) return vimLastColumn;
Editor editor = caret.getEditor();
boolean isEndAllowed = CommandStateHelper.isEndAllowedIgnoringOnemore(CommandStateHelper.getMode(editor));
boolean isEndAllowed = CommandStateHelper.isEndAllowedIgnoringOnemore(CommandStateHelper.getEditorMode(editor));
final LogicalPosition logicalPosition = caret.getLogicalPosition();
int lastColumn = EditorHelper.lastColumnForLine(editor, logicalPosition.line, isEndAllowed);
@@ -994,18 +1019,18 @@ public class EditorHelper {
// Note that visualPos.leansRight will be true for the right half side of the character grid
VisualPosition closestVisualPosition = editor.xyToVisualPosition(new Point(x, y));
// Make sure we get the character that contains this XY, not the editor's decision about closest character. The
// editor will give us the next character if X is over half way through the character grid.
int xActualLeft = editor.visualPositionToXY(closestVisualPosition).x;
// Make sure we get the character that contains this XY, not the editor's decision about the closest character. The
// editor will give us the next character if X is over halfway through the character grid. Take into account that
// the font size might be fractional, but the editor's area is integer. Use floating point values and round.
long xActualLeft = Math.round(editor.visualPositionToPoint2D(closestVisualPosition).getX());
if (xActualLeft > x) {
closestVisualPosition = getPreviousNonInlayVisualPosition(editor, closestVisualPosition);
xActualLeft = editor.visualPositionToXY(closestVisualPosition).x;
xActualLeft = Math.round(editor.visualPositionToPoint2D(closestVisualPosition).getX());
}
if (xActualLeft >= leftBound) {
final int xActualRight =
editor.visualPositionToXY(new VisualPosition(closestVisualPosition.line, closestVisualPosition.column + 1)).x -
1;
final VisualPosition nextVisualPosition = new VisualPosition(closestVisualPosition.line, closestVisualPosition.column + 1);
final long xActualRight = Math.round(editor.visualPositionToPoint2D(nextVisualPosition).getX()) - 1;
if (xActualRight <= rightBound) {
return closestVisualPosition.column;
}

View File

@@ -22,6 +22,7 @@ import com.intellij.codeInsight.template.TemplateManager
import com.intellij.codeWithMe.ClientId
import com.intellij.injected.editor.EditorWindow
import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.ClientEditorManager
import com.intellij.openapi.editor.Document
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.EditorFactory
@@ -30,6 +31,7 @@ import com.intellij.openapi.util.Key
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import kotlin.streams.toList
/**
* This annotation is created for test functions (methods).
@@ -83,10 +85,9 @@ fun Editor.getTopLevelEditor() = if (this is EditorWindow) this.delegate else th
/**
* Return list of editors for local host (for code with me plugin)
* [VERSION UPDATE] 212+ ClientEditorManager.editors()
*/
fun localEditors(): List<Editor> {
return EditorFactory.getInstance().allEditors.filter { editor -> editor.editorClientId.let { it == null || it == ClientId.currentOrNull } }
return ClientEditorManager.getCurrentInstance().editors().toList()
}
fun localEditors(doc: Document): List<Editor> {

View File

@@ -24,11 +24,8 @@ import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.AnActionResult
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.PlatformCoreDataKeys
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.actionSystem.Presentation
import com.intellij.openapi.actionSystem.ex.ActionManagerEx
import com.intellij.openapi.actionSystem.ex.ActionUtil
import com.intellij.openapi.command.CommandProcessor
@@ -86,7 +83,7 @@ class IjActionExecutor : VimActionExecutor {
// This method executes inside of lastUpdateAndCheckDumb
// Another related issue: VIM-2604
if (!ActionUtil.lastUpdateAndCheckDumb(ijAction, event, false)) return false
if (ijAction is ActionGroup && !canBePerformed(event, ijAction, context.ij)) {
if (ijAction is ActionGroup && !event.presentation.isPerformGroup) {
// Some ActionGroups should not be performed, but shown as a popup
val popup = JBPopupFactory.getInstance()
.createActionGroupPopup(event.presentation.text, ijAction, context.ij, false, null, -1)
@@ -118,10 +115,9 @@ class IjActionExecutor : VimActionExecutor {
var indexError: IndexNotReadyException? = null
val manager = ActionManagerEx.getInstanceEx()
manager.fireBeforeActionPerformed(action, event)
val component = event.getData(PlatformCoreDataKeys.CONTEXT_COMPONENT)
var result: AnActionResult? = null
try {
SlowOperations.allowSlowOperations(SlowOperations.ACTION_PERFORM).use { ignore ->
SlowOperations.allowSlowOperations(SlowOperations.ACTION_PERFORM).use {
performRunnable.run()
result = AnActionResult.PERFORMED
}
@@ -143,17 +139,6 @@ class IjActionExecutor : VimActionExecutor {
}
}
private fun canBePerformed(event: AnActionEvent, action: ActionGroup, context: DataContext): Boolean {
val presentation = event.presentation
return try {
// [VERSION UPDATE] 221+ Just use Presentation.isPerformGroup
val method = Presentation::class.java.getMethod("isPerformGroup")
method.invoke(presentation) as Boolean
} catch (e: Exception) {
action.canBePerformed(context)
}
}
/**
* Execute an action by name
*

View File

@@ -25,9 +25,9 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.TextRange
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
import com.maddyhome.idea.vim.newapi.IjExecutionContext
@@ -39,8 +39,8 @@ import com.maddyhome.idea.vim.newapi.vim
* Pop all modes, but leave editor state. E.g. editor selection is not removed.
*/
fun Editor.popAllModes() {
val commandState = this.vim.commandState
while (commandState.mode != CommandState.Mode.COMMAND) {
val commandState = this.vim.vimStateMachine
while (commandState.mode != VimStateMachine.Mode.COMMAND) {
commandState.popModes()
}
}
@@ -63,7 +63,7 @@ fun Editor.exitVisualMode() {
VimPlugin.getMark().setVisualSelectionMarks(this.vim, TextRange(vimSelectionStart, primaryCaret.offset))
this.caretModel.allCarets.forEach { it.vimSelectionStartClear() }
this.vim.commandState.popModes()
this.vim.vimStateMachine.popModes()
}
}
@@ -71,7 +71,7 @@ fun Editor.exitVisualMode() {
fun Editor.exitSelectMode(adjustCaretPosition: Boolean) {
if (!this.inSelectMode) return
this.vim.commandState.popModes()
this.vim.vimStateMachine.popModes()
SelectionVimListenerSuppressor.lock().use {
this.caretModel.allCarets.forEach {
it.removeSelection()
@@ -91,7 +91,7 @@ fun Editor.exitSelectMode(adjustCaretPosition: Boolean) {
fun VimEditor.exitSelectMode(adjustCaretPosition: Boolean) {
if (!this.inSelectMode) return
this.commandState.popModes()
this.vimStateMachine.popModes()
SelectionVimListenerSuppressor.lock().use {
this.carets().forEach { vimCaret ->
val caret = (vimCaret as IjVimCaret).caret

View File

@@ -31,7 +31,8 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile;
import com.intellij.psi.util.PsiTreeUtil;
import com.maddyhome.idea.vim.VimPlugin;
import com.maddyhome.idea.vim.command.CommandState;
import com.maddyhome.idea.vim.api.VimSearchHelperBase;
import com.maddyhome.idea.vim.command.VimStateMachine;
import com.maddyhome.idea.vim.common.CharacterPosition;
import com.maddyhome.idea.vim.common.Direction;
import com.maddyhome.idea.vim.common.TextRange;
@@ -529,6 +530,9 @@ public class SearchHelper {
CharSequence subSequence = chars.subSequence(startOffset, endOffset);
int inQuotePos = pos - startOffset;
int inQuoteStart = findBlockLocation(subSequence, close, type, Direction.BACKWARDS, inQuotePos, count, false);
if (inQuoteStart == -1) {
inQuoteStart = findBlockLocation(subSequence, close, type, Direction.FORWARDS, inQuotePos, count, false);
}
if (inQuoteStart != -1) {
startPosInStringFound = true;
int inQuoteEnd = findBlockLocation(subSequence, type, close, Direction.FORWARDS, inQuoteStart, 1, false);
@@ -542,6 +546,9 @@ public class SearchHelper {
if (!startPosInStringFound) {
bstart = findBlockLocation(chars, close, type, Direction.BACKWARDS, pos, count, false);
if (bstart == -1) {
bstart = findBlockLocation(chars, close, type, Direction.FORWARDS, pos, count, false);
}
if (bstart != -1) {
bend = findBlockLocation(chars, type, close, Direction.FORWARDS, bstart, 1, false);
}
@@ -893,8 +900,8 @@ public class SearchHelper {
selectionEndWithoutNewline++;
}
final CommandState.Mode mode = CommandState.getInstance(new IjVimEditor(editor)).getMode();
if (mode == CommandState.Mode.VISUAL) {
final VimStateMachine.Mode mode = VimStateMachine.getInstance(new IjVimEditor(editor)).getMode();
if (mode == VimStateMachine.Mode.VISUAL) {
if (closingTagTextRange.getStartOffset() == selectionEndWithoutNewline &&
openingTag.getEndOffset() == selectionStart) {
// Special case: if the inner tag is already selected we should like isOuter is active
@@ -1195,7 +1202,7 @@ public class SearchHelper {
int last = -1;
int res = start;
while (true) {
res = findNextWordOne(chars, res, end, 1, true, false);
res = (int)VimSearchHelperBase.Companion.findNextWordOne(chars, res, end, 1, true, false);
if (res == start || res == 0 || res > end || res == last) {
break;
}
@@ -1224,105 +1231,6 @@ public class SearchHelper {
return new CountPosition(count, position);
}
public static int findNextWord(@NotNull Editor editor, int searchFrom, int count, boolean bigWord) {
CharSequence chars = editor.getDocument().getCharsSequence();
final int size = EditorHelperRt.getFileSize(editor);
return findNextWord(chars, searchFrom, size, count, bigWord, false);
}
public static int findNextWord(@NotNull CharSequence chars,
int pos,
int size,
int count,
boolean bigWord,
boolean spaceWords) {
int step = count >= 0 ? 1 : -1;
count = Math.abs(count);
int res = pos;
for (int i = 0; i < count; i++) {
res = findNextWordOne(chars, res, size, step, bigWord, spaceWords);
if (res == pos || res == 0 || res == size - 1) {
break;
}
}
return res;
}
private static int findNextWordOne(@NotNull CharSequence chars,
int pos,
int size,
int step,
boolean bigWord,
boolean spaceWords) {
boolean found = false;
pos = pos < size ? pos : Math.min(size, chars.length() - 1);
// For back searches, skip any current whitespace so we start at the end of a word
if (step < 0 && pos > 0) {
if (CharacterHelper.charType(chars.charAt(pos - 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE &&
!spaceWords) {
pos = skipSpace(chars, pos - 1, step, size) + 1;
}
if (pos > 0 &&
CharacterHelper.charType(chars.charAt(pos), bigWord) !=
CharacterHelper.charType(chars.charAt(pos - 1), bigWord)) {
pos += step;
}
}
int res = pos;
if (pos < 0 || pos >= size) {
return pos;
}
CharacterHelper.CharacterType type = CharacterHelper.charType(chars.charAt(pos), bigWord);
if (type == CharacterHelper.CharacterType.WHITESPACE && step < 0 && pos > 0 && !spaceWords) {
type = CharacterHelper.charType(chars.charAt(pos - 1), bigWord);
}
pos += step;
while (pos >= 0 && pos < size && !found) {
CharacterHelper.CharacterType newType = CharacterHelper.charType(chars.charAt(pos), bigWord);
if (newType != type) {
if (newType == CharacterHelper.CharacterType.WHITESPACE && step >= 0 && !spaceWords) {
pos = skipSpace(chars, pos, step, size);
res = pos;
}
else if (step < 0) {
res = pos + 1;
}
else {
res = pos;
}
type = CharacterHelper.charType(chars.charAt(res), bigWord);
found = true;
}
pos += step;
}
if (found) {
if (res < 0) //(pos <= 0)
{
res = 0;
}
else if (res >= size) //(pos >= size)
{
res = size - 1;
}
}
else if (pos <= 0) {
res = 0;
}
else if (pos >= size) {
res = size;
}
return res;
}
public static @NotNull List<Pair<TextRange, NumberType>> findNumbersInRange(final @NotNull Editor editor,
@NotNull TextRange textRange,
final boolean alpha,
@@ -1648,10 +1556,10 @@ public class SearchHelper {
if ((!onWordStart && !(startSpace && isOuter)) || hasSelection || (count > 1 && dir == -1)) {
if (dir == 1) {
start = findNextWord(chars, pos, max, -1, isBig, !isOuter);
start = (int)VimSearchHelperBase.Companion.findNextWord(chars, pos, max, -1, isBig, !isOuter);
}
else {
start = findNextWord(chars, pos, max, -(count - (onWordStart && !hasSelection ? 1 : 0)), isBig, !isOuter);
start = (int)VimSearchHelperBase.Companion.findNextWord(chars, pos, max, -(count - (onWordStart && !hasSelection ? 1 : 0)), isBig, !isOuter);
}
start = EditorHelper.normalizeOffset(editor, start, false);
@@ -1799,7 +1707,7 @@ public class SearchHelper {
if (step > 0 && pos < size - 1) {
if (CharacterHelper.charType(chars.charAt(pos + 1), bigWord) == CharacterHelper.CharacterType.WHITESPACE &&
!spaceWords) {
pos = skipSpace(chars, pos + 1, step, size) - 1;
pos = (int)(VimSearchHelperBase.Companion.skipSpace(chars, pos + 1, step, size) - 1);
}
if (pos < size - 1 &&
CharacterHelper.charType(chars.charAt(pos), bigWord) !=
@@ -1824,7 +1732,7 @@ public class SearchHelper {
res = pos - 1;
}
else if (newType == CharacterHelper.CharacterType.WHITESPACE && step < 0 && !spaceWords) {
pos = skipSpace(chars, pos, step, size);
pos = (int)VimSearchHelperBase.Companion.skipSpace(chars, pos, step, size);
res = pos;
}
else {
@@ -1852,34 +1760,6 @@ public class SearchHelper {
return res;
}
/**
* Skip whitespace starting with the supplied position.
* <p>
* An empty line is considered a whitespace break.
*
* @param chars The text as a character array
* @param offset The starting position
* @param step The direction to move
* @param size The size of the document
* @return The new position. This will be the first non-whitespace character found or an empty line
*/
private static int skipSpace(@NotNull CharSequence chars, int offset, int step, int size) {
char prev = 0;
while (offset >= 0 && offset < size) {
final char c = chars.charAt(offset);
if (c == '\n' && c == prev) {
break;
}
if (CharacterHelper.charType(c, false) != CharacterHelper.CharacterType.WHITESPACE) {
break;
}
prev = c;
offset += step;
}
return offset < size ? offset : size - 1;
}
/**
* This locates the position with the document of the count-th occurrence of ch on the current line
*

View File

@@ -0,0 +1,45 @@
/*
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
* Copyright (C) 2003-2022 The IdeaVim authors
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
package com.maddyhome.idea.vim.helper
import com.maddyhome.idea.vim.api.injector
import java.util.*
import java.util.stream.Collectors
import javax.swing.KeyStroke
/**
* COMPATIBILITY-LAYER: Created a helper class
* Please see: https://jb.gg/zo8n0r
*/
object StringHelper {
@JvmStatic
fun parseKeys(string: String): List<KeyStroke> {
return injector.parser.parseKeys(string)
}
@JvmStatic
fun parseKeys(vararg string: String): List<KeyStroke> {
return Arrays.stream(string).flatMap { o: String -> injector.parser.parseKeys(o).stream() }
.collect(Collectors.toList())
}
@JvmStatic
fun isCloseKeyStroke(stroke: KeyStroke): Boolean {
return stroke.isCloseKeyStroke()
}
}

View File

@@ -21,8 +21,11 @@ package com.maddyhome.idea.vim.helper
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.PlatformDataKeys
import com.intellij.openapi.command.CommandProcessor
import com.intellij.openapi.command.impl.UndoManagerImpl
import com.intellij.openapi.command.undo.UndoManager
import com.intellij.openapi.components.Service
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
import com.maddyhome.idea.vim.api.ExecutionContext
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.ChangesListener
@@ -39,27 +42,36 @@ import com.maddyhome.idea.vim.vimscript.services.IjVimOptionService
*/
@Service
class UndoRedoHelper : UndoRedoBase() {
init {
injector.optionService.addListener(IjVimOptionService.oldUndo, { UndoManagerImpl.ourNeverAskUser = !injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo) }, true)
}
override fun undo(context: ExecutionContext): Boolean {
val ijContext = context.context as DataContext
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext)
val editor = CommonDataKeys.EDITOR.getData(context.ij) ?: return false
val vimEditor = editor.vim
val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor)
val undoManager = UndoManager.getInstance(project)
if (fileEditor != null && undoManager.isUndoAvailable(fileEditor)) {
if (undoManager.isUndoAvailable(fileEditor)) {
if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) {
SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
} else {
val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
performUntilFileChanges(editor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) })
editor?.carets()?.forEach {
performUntilFileChanges(vimEditor, { undoManager.isUndoAvailable(fileEditor) }, { undoManager.undo(fileEditor) })
vimEditor.carets().forEach {
val ijCaret = it.ij
val hasSelection = ijCaret.hasSelection()
if (hasSelection) {
val selectionStart = ijCaret.selectionStart
it.ij.removeSelection()
it.ij.moveToOffset(selectionStart)
CommandProcessor.getInstance().runUndoTransparentAction {
it.ij.removeSelection()
it.ij.moveToOffset(selectionStart)
}
}
}
}
return true
}
return false
@@ -68,15 +80,18 @@ class UndoRedoHelper : UndoRedoBase() {
override fun redo(context: ExecutionContext): Boolean {
val ijContext = context.context as DataContext
val project = PlatformDataKeys.PROJECT.getData(ijContext) ?: return false
val fileEditor = PlatformDataKeys.FILE_EDITOR.getData(ijContext)
val editor = CommonDataKeys.EDITOR.getData(context.ij) ?: return false
val vimEditor = editor.vim
val fileEditor = TextEditorProvider.getInstance().getTextEditor(editor)
val undoManager = UndoManager.getInstance(project)
if (fileEditor != null && undoManager.isRedoAvailable(fileEditor)) {
if (undoManager.isRedoAvailable(fileEditor)) {
if (injector.optionService.isSet(OptionScope.GLOBAL, IjVimOptionService.oldUndo)) {
SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
} else {
val editor = CommonDataKeys.EDITOR.getData(context.ij)?.vim
performUntilFileChanges(editor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) })
editor?.carets()?.forEach { it.ij.removeSelection() }
performUntilFileChanges(vimEditor, { undoManager.isRedoAvailable(fileEditor) }, { undoManager.redo(fileEditor) })
CommandProcessor.getInstance().runUndoTransparentAction {
vimEditor.carets().forEach { it.ij.removeSelection() }
}
}
return true
}
@@ -95,10 +110,15 @@ class UndoRedoHelper : UndoRedoBase() {
}
}
val oldPath = editor.getPath()
vimDocument.addChangeListener(changeListener)
while (check() && !changeListener.hasChanged) {
while (check() && !changeListener.hasChanged && !ifFilePathChanged(editor, oldPath)) {
action.run()
}
vimDocument.removeChangeListener(changeListener)
}
private fun ifFilePathChanged(editor: IjVimEditor, oldPath: String?): Boolean {
return editor.getPath() != oldPath
}
}

View File

@@ -27,8 +27,9 @@ import com.intellij.openapi.editor.RangeMarker
import com.intellij.openapi.editor.markup.RangeHighlighter
import com.intellij.openapi.util.Key
import com.intellij.openapi.util.UserDataHolder
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.group.visual.VisualChange
import com.maddyhome.idea.vim.group.visual.vimLeadSelectionOffset
@@ -73,11 +74,12 @@ var Caret.vimInsertStart: RangeMarker by userDataOr {
this.offset
)
}
var Caret.registerStorage: CaretRegisterStorageBase? by userDataCaretToEditor()
// ------------------ Editor
fun unInitializeEditor(editor: Editor) {
editor.vimLastSelectionType = null
editor.vimCommandState = null
editor.vimStateMachine = null
editor.vimMorePanel = null
editor.vimExOutput = null
editor.vimLastHighlighters = null
@@ -91,7 +93,7 @@ var Editor.vimIncsearchCurrentMatchOffset: Int? by userData()
* @see :help visualmode()
*/
var Editor.vimLastSelectionType: SelectionType? by userData()
var Editor.vimCommandState: CommandState? by userData()
var Editor.vimStateMachine: VimStateMachine? by userData()
var Editor.vimEditorGroup: Boolean by userDataOr { false }
var Editor.vimLineNumbersInitialState: Boolean by userDataOr { false }
var Editor.vimHasRelativeLineNumbersInstalled: Boolean by userDataOr { false }
@@ -103,7 +105,7 @@ var Editor.vimTestInputModel: TestInputModel? by userData()
* Checks whether a keeping visual mode visual operator action is performed on editor.
*/
var Editor.vimKeepingVisualOperatorAction: Boolean by userDataOr { false }
var Editor.vimChangeActionSwitchMode: CommandState.Mode? by userData()
var Editor.vimChangeActionSwitchMode: VimStateMachine.Mode? by userData()
/**
* Function for delegated properties.

View File

@@ -19,8 +19,6 @@
package com.maddyhome.idea.vim.key
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.common.Node
import com.maddyhome.idea.vim.common.addLeafs
fun <T> Node<T>.addLeafs(keys: String, actionHolder: T) {
addLeafs(injector.parser.parseKeys(keys), actionHolder)

View File

@@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.listener
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.AnActionResult
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.editor.Caret
@@ -35,7 +35,6 @@ import com.maddyhome.idea.vim.group.visual.VimVisualTimer
import com.maddyhome.idea.vim.helper.fileSize
import com.maddyhome.idea.vim.helper.inVisualMode
import com.maddyhome.idea.vim.newapi.vim
import org.jetbrains.annotations.NotNull
/**
* A collection of hacks to improve the interaction with fancy AppCode templates
@@ -50,16 +49,16 @@ object AppCodeTemplates {
private var editor: Editor? = null
override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return
val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR)
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) {
editor = hostEditor
}
}
override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) {
if (!VimPlugin.isEnabled()) return
if (ActionManager.getInstance().getId(action) == IdeActions.ACTION_CHOOSE_LOOKUP_ITEM) {
@@ -77,8 +76,8 @@ object AppCodeTemplates {
@JvmStatic
fun onMovement(
editor: @NotNull Editor,
caret: @NotNull Caret,
editor: Editor,
caret: Caret,
toRight: Boolean,
) {
val offset = caret.offset

View File

@@ -19,8 +19,10 @@
package com.maddyhome.idea.vim.listener
import com.intellij.codeInsight.lookup.Lookup
import com.intellij.codeInsight.lookup.LookupManager
import com.intellij.codeInsight.lookup.LookupManagerListener
import com.intellij.codeInsight.lookup.impl.LookupImpl
import com.intellij.codeInsight.lookup.impl.actions.ChooseItemAction
import com.intellij.codeInsight.template.Template
import com.intellij.codeInsight.template.TemplateEditingAdapter
import com.intellij.codeInsight.template.TemplateManagerListener
@@ -29,26 +31,28 @@ import com.intellij.find.FindModelListener
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.AnActionResult
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.project.DumbAwareToggleAction
import com.intellij.openapi.util.TextRange
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.group.NotificationService
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.helper.EditorDataContext
import com.maddyhome.idea.vim.helper.commandState
import com.maddyhome.idea.vim.helper.inNormalMode
import com.maddyhome.idea.vim.helper.isIdeaVimDisabledHere
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
import com.maddyhome.idea.vim.vimscript.model.datatypes.VimInt
import com.maddyhome.idea.vim.vimscript.model.options.helpers.IdeaRefactorModeHelper
import org.jetbrains.annotations.NonNls
import java.awt.event.KeyEvent
import javax.swing.KeyStroke
/**
* @author Alex Plate
@@ -60,27 +64,62 @@ object IdeaSpecifics {
private val surrounderAction =
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
private var editor: Editor? = null
override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
private var completionPrevDocumentLength: Int? = null
private var completionPrevDocumentOffset: Int? = null
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return
val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR)
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) {
editor = hostEditor
}
//region Track action id
if (VimPlugin.getOptionService().isSet(OptionScope.GLOBAL, OptionConstants.trackactionidsName)) {
if (action !is NotificationService.ActionIdNotifier.CopyActionId && action !is NotificationService.ActionIdNotifier.StopTracking) {
val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId
VimPlugin.getNotifications(dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id)
val id: String? = ActionManager.getInstance().getId(action) ?: (action.shortcutSet as? ProxyShortcutSet)?.actionId
VimPlugin.getNotifications(event.dataContext.getData(CommonDataKeys.PROJECT)).notifyActionId(id)
}
if (hostEditor != null && action is ChooseItemAction && hostEditor.vimStateMachine?.isRecording == true) {
val lookup = LookupManager.getActiveLookup(hostEditor)
if (lookup != null) {
val charsToRemove = hostEditor.caretModel.primaryCaret.offset - lookup.lookupStart
val register = VimPlugin.getRegister()
val backSpace = KeyStroke.getKeyStroke(KeyEvent.VK_BACK_SPACE, 0)
repeat(charsToRemove) {
register.recordKeyStroke(backSpace)
}
completionPrevDocumentLength = hostEditor.document.textLength - charsToRemove
completionPrevDocumentOffset = lookup.lookupStart
}
}
//endregion
}
override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) {
if (!VimPlugin.isEnabled()) return
val editor = editor
if (editor != null && action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) {
val prevDocumentLength = completionPrevDocumentLength
val prevDocumentOffset = completionPrevDocumentOffset
if (prevDocumentLength != null && prevDocumentOffset != null) {
val register = VimPlugin.getRegister()
val addedTextLength = editor.document.textLength - prevDocumentLength
val caretShift = addedTextLength - (editor.caretModel.primaryCaret.offset - prevDocumentOffset)
val leftArrow = KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0)
register.recordText(editor.document.getText(TextRange(prevDocumentOffset, prevDocumentOffset + addedTextLength)))
repeat(caretShift.coerceAtLeast(0)) {
register.recordKeyStroke(leftArrow)
}
}
this.completionPrevDocumentLength = null
this.completionPrevDocumentOffset = null
}
//region Enter insert mode after surround with if
if (surrounderAction == action.javaClass.name && surrounderItems.any {
action.templatePresentation.text.endsWith(
@@ -89,17 +128,17 @@ object IdeaSpecifics {
}
) {
editor?.let {
val commandState = it.vim.commandState
while (commandState.mode != CommandState.Mode.COMMAND) {
val commandState = it.vim.vimStateMachine
while (commandState.mode != VimStateMachine.Mode.COMMAND) {
commandState.popModes()
}
VimPlugin.getChange().insertBeforeCursor(it.vim, dataContext.vim)
VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim)
KeyHandler.getInstance().reset(it.vim)
}
}
//endregion
editor = null
this.editor = null
}
}

View File

@@ -21,8 +21,8 @@ package com.maddyhome.idea.vim.listener
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.AnAction
import com.intellij.openapi.actionSystem.AnActionEvent
import com.intellij.openapi.actionSystem.AnActionResult
import com.intellij.openapi.actionSystem.CommonDataKeys
import com.intellij.openapi.actionSystem.DataContext
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.ex.AnActionListener
import com.intellij.openapi.editor.Editor
@@ -36,16 +36,16 @@ import com.maddyhome.idea.vim.helper.getTopLevelEditor
class RiderActionListener : AnActionListener {
private var editor: Editor? = null
override fun beforeActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
if (!VimPlugin.isEnabled()) return
val hostEditor = dataContext.getData(CommonDataKeys.HOST_EDITOR)
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
if (hostEditor != null) {
editor = hostEditor
}
}
override fun afterActionPerformed(action: AnAction, dataContext: DataContext, event: AnActionEvent) {
override fun afterActionPerformed(action: AnAction, event: AnActionEvent, result: AnActionResult) {
if (!VimPlugin.isEnabled()) return
//region Extend Selection for Rider

View File

@@ -36,15 +36,20 @@ import com.intellij.openapi.editor.event.SelectionEvent
import com.intellij.openapi.editor.event.SelectionListener
import com.intellij.openapi.editor.ex.DocumentEx
import com.intellij.openapi.editor.impl.EditorComponentImpl
import com.intellij.openapi.editor.impl.EditorImpl
import com.intellij.openapi.fileEditor.FileEditorManagerEvent
import com.intellij.openapi.fileEditor.FileEditorManagerListener
import com.intellij.openapi.rd.createLifetime
import com.intellij.openapi.rd.createNestedDisposable
import com.intellij.openapi.util.Disposer
import com.intellij.util.ExceptionUtil
import com.jetbrains.rd.util.lifetime.intersect
import com.maddyhome.idea.vim.EventFacade
import com.maddyhome.idea.vim.KeyHandler
import com.maddyhome.idea.vim.VimKeyListener
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.VimTypedActionHandler
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.ex.ExOutputModel
import com.maddyhome.idea.vim.group.EditorGroup
import com.maddyhome.idea.vim.group.FileGroup
@@ -73,8 +78,6 @@ import com.maddyhome.idea.vim.helper.vimLastColumn
import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipEvents
import com.maddyhome.idea.vim.listener.MouseEventsDataHolder.skipNDragEvents
import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.add
import com.maddyhome.idea.vim.listener.VimListenerManager.EditorListeners.remove
import com.maddyhome.idea.vim.newapi.IjVimEditor
import com.maddyhome.idea.vim.newapi.vim
import com.maddyhome.idea.vim.options.OptionConstants
import com.maddyhome.idea.vim.options.OptionScope
@@ -122,9 +125,9 @@ object VimListenerManager {
VimPlugin.getOptionService().addListener(OptionConstants.guicursorName, GuicursorChangeListener)
VimPlugin.getOptionService().addListener(OptionConstants.iskeywordName, KeywordOptionChangeListener, true)
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance())
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance().onOffDisposable)
EditorFactory.getInstance().eventMulticaster.addCaretListener(VimCaretListener, VimPlugin.getInstance())
EditorFactory.getInstance().eventMulticaster.addCaretListener(VimCaretListener, VimPlugin.getInstance().onOffDisposable)
}
fun disable() {
@@ -136,10 +139,6 @@ object VimListenerManager {
VimPlugin.getOptionService().removeListener(OptionConstants.showcmdName, ShowCmdOptionChangeListener)
VimPlugin.getOptionService().removeListener(OptionConstants.guicursorName, GuicursorChangeListener)
VimPlugin.getOptionService().removeListener(OptionConstants.iskeywordName, KeywordOptionChangeListener)
EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener)
EditorFactory.getInstance().eventMulticaster.removeCaretListener(VimCaretListener)
}
}
@@ -157,17 +156,26 @@ object VimListenerManager {
}
fun add(editor: Editor) {
val pluginLifetime = VimPlugin.getInstance().createLifetime()
val editorLifetime = (editor as EditorImpl).disposable.createLifetime()
val disposable = editorLifetime.intersect(pluginLifetime).createNestedDisposable("MyLifetimedDisposable")
editor.contentComponent.addKeyListener(VimKeyListener)
Disposer.register(disposable) { editor.contentComponent.removeKeyListener(VimKeyListener) }
val eventFacade = EventFacade.getInstance()
eventFacade.addEditorMouseListener(editor, EditorMouseHandler)
eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler)
eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler)
eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener)
eventFacade.addEditorMouseListener(editor, EditorMouseHandler, disposable)
eventFacade.addEditorMouseMotionListener(editor, EditorMouseHandler, disposable)
eventFacade.addEditorSelectionListener(editor, EditorSelectionHandler, disposable)
eventFacade.addComponentMouseListener(editor.contentComponent, ComponentMouseListener, disposable)
VimPlugin.getEditor().editorCreated(editor)
VimPlugin.getChange().editorCreated(IjVimEditor(editor))
VimPlugin.getChange().editorCreated(editor, disposable)
Disposer.register(disposable) {
VimPlugin.getEditorIfCreated()?.editorDeinit(editor, true)
}
}
fun remove(editor: Editor, isReleased: Boolean) {
@@ -181,7 +189,7 @@ object VimListenerManager {
VimPlugin.getEditorIfCreated()?.editorDeinit(editor, isReleased)
VimPlugin.getChange().editorReleased(IjVimEditor(editor))
VimPlugin.getChange().editorReleased(editor)
}
}
@@ -213,7 +221,6 @@ object VimListenerManager {
}
override fun editorReleased(event: EditorFactoryEvent) {
remove(event.editor, true)
VimPlugin.getMark().editorReleased(event)
}
}
@@ -425,7 +432,7 @@ object VimListenerManager {
ExOutputModel.getInstance(editor).clear()
val caretModel = editor.caretModel
if (editor.subMode != CommandState.SubMode.NONE) {
if (editor.subMode != VimStateMachine.SubMode.NONE) {
caretModel.removeSecondaryCarets()
}

View File

@@ -32,8 +32,8 @@ import com.maddyhome.idea.vim.api.VimChangeGroupBase
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimMotionGroupBase
import com.maddyhome.idea.vim.api.injector
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.EditorLine
import com.maddyhome.idea.vim.common.IndentConfig
import com.maddyhome.idea.vim.common.OperatedRange
@@ -99,11 +99,12 @@ fun changeRange(
vimCaret.moveToOffset(deletedInfo.leftOffset.point)
}
is OperatedRange.Block -> TODO()
else -> TODO()
}
if (type == SelectionType.BLOCK_WISE) {
VimPlugin.getChange().setInsertRepeat(lines, col, false)
}
editor.vimChangeActionSwitchMode = CommandState.Mode.INSERT
editor.vimChangeActionSwitchMode = VimStateMachine.Mode.INSERT
}
} else {
VimPlugin.getChange().insertBeforeCursor(editor.vim, context.vim)
@@ -158,9 +159,9 @@ fun deleteRange(
fun insertLineAround(editor: VimEditor, context: ExecutionContext, shift: Int) {
val project = (editor as IjVimEditor).editor.project
VimPlugin.getChange().initInsert(editor, context, CommandState.Mode.INSERT)
VimPlugin.getChange().initInsert(editor, context, VimStateMachine.Mode.INSERT)
if (!CommandState.getInstance(editor).isDotRepeatInProgress) {
if (!VimStateMachine.getInstance(editor).isDotRepeatInProgress) {
for (vimCaret in editor.carets()) {
val caret = (vimCaret as IjVimCaret).caret
val line = vimCaret.getLine()
@@ -179,7 +180,7 @@ fun insertLineAround(editor: VimEditor, context: ExecutionContext, shift: Int) {
}
val position = EditorLine.Offset.init(editor.offsetToLogicalPosition(lineEndOffset).line + shift, editor)
val insertedLine = editor.addLine(position) ?: continue
val insertedLine = editor.addLine(position)
VimPlugin.getChange().saveStrokes("\n")
var lineStart = editor.getLineRange(insertedLine).first

View File

@@ -49,6 +49,7 @@ class IjClipboardManager : VimClipboardManager {
return Pair(res, transferableData)
}
@Suppress("UNCHECKED_CAST")
override fun setClipboardText(text: String, rawText: String, transferableData: List<Any>): Any? {
val transferableData1 = (transferableData as List<TextBlockTransferableData>).toMutableList()
try {
@@ -97,6 +98,7 @@ class IjClipboardManager : VimClipboardManager {
return transferableData
}
@Suppress("UNCHECKED_CAST")
override fun preprocessText(
vimEditor: VimEditor,
textRange: TextRange,

View File

@@ -33,11 +33,11 @@ class IjExecutionContextManager : ExecutionContextManagerBase() {
}
override fun onCaret(caret: VimCaret, prevContext: ExecutionContext): ExecutionContext {
return IjExecutionContext(CaretSpecificDataContext(prevContext.ij, caret.ij))
return IjExecutionContext(CaretSpecificDataContext.create(prevContext.ij, caret.ij))
}
override fun createCaretSpecificDataContext(context: ExecutionContext, caret: VimCaret): ExecutionContext {
return IjExecutionContext(CaretSpecificDataContext(context.ij, caret.ij))
return IjExecutionContext(CaretSpecificDataContext.create(context.ij, caret.ij))
}
override fun createEditorDataContext(editor: VimEditor, context: ExecutionContext): ExecutionContext {

View File

@@ -22,7 +22,10 @@ import com.intellij.openapi.editor.Caret
import com.intellij.openapi.editor.LogicalPosition
import com.intellij.openapi.editor.VisualPosition
import com.maddyhome.idea.vim.VimPlugin
import com.maddyhome.idea.vim.api.CaretRegisterStorage
import com.maddyhome.idea.vim.api.CaretRegisterStorageBase
import com.maddyhome.idea.vim.api.VimCaret
import com.maddyhome.idea.vim.api.VimCaretBase
import com.maddyhome.idea.vim.api.VimEditor
import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.api.VimVisualPosition
@@ -38,13 +41,23 @@ import com.maddyhome.idea.vim.group.visual.vimSetSystemSelectionSilently
import com.maddyhome.idea.vim.group.visual.vimUpdateEditorSelection
import com.maddyhome.idea.vim.helper.inlayAwareVisualColumn
import com.maddyhome.idea.vim.helper.moveToInlayAwareOffset
import com.maddyhome.idea.vim.helper.registerStorage
import com.maddyhome.idea.vim.helper.vimInsertStart
import com.maddyhome.idea.vim.helper.vimLastColumn
import com.maddyhome.idea.vim.helper.vimLastVisualOperatorRange
import com.maddyhome.idea.vim.helper.vimLine
import com.maddyhome.idea.vim.helper.vimSelectionStart
class IjVimCaret(val caret: Caret) : VimCaret {
class IjVimCaret(val caret: Caret) : VimCaretBase() {
override val registerStorage: CaretRegisterStorage
get() {
var storage = this.caret.registerStorage
if (storage == null) {
storage = CaretRegisterStorageBase()
this.caret.registerStorage = storage
}
return storage
}
override val editor: VimEditor
get() = IjVimEditor(caret.editor)
override val offset: Offset
@@ -74,6 +87,8 @@ class IjVimCaret(val caret: Caret) : VimCaret {
}
override val vimLine: Int
get() = this.caret.vimLine
override val isPrimary: Boolean
get() = editor.primaryCaret().ij == this.caret
override fun moveToOffset(offset: Int) {
// TODO: 17.12.2021 Unpack internal actions

View File

@@ -38,9 +38,9 @@ import com.maddyhome.idea.vim.api.VimLogicalPosition
import com.maddyhome.idea.vim.api.VimSelectionModel
import com.maddyhome.idea.vim.api.VimVisualPosition
import com.maddyhome.idea.vim.api.VirtualFile
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.OperatorArguments
import com.maddyhome.idea.vim.command.SelectionType
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.EditorLine
import com.maddyhome.idea.vim.common.LiveRange
import com.maddyhome.idea.vim.common.Offset
@@ -62,7 +62,9 @@ import com.maddyhome.idea.vim.helper.updateCaretsVisualPosition
import com.maddyhome.idea.vim.helper.vimChangeActionSwitchMode
import com.maddyhome.idea.vim.helper.vimKeepingVisualOperatorAction
import com.maddyhome.idea.vim.helper.vimLastSelectionType
import org.jetbrains.annotations.ApiStatus
@ApiStatus.Internal
class IjVimEditor(editor: Editor) : MutableLinearEditor() {
// All the editor actions should be performed with top level editor!!!
@@ -72,7 +74,7 @@ class IjVimEditor(editor: Editor) : MutableLinearEditor() {
val originalEditor = editor
override val lfMakesNewLine: Boolean = true
override var vimChangeActionSwitchMode: CommandState.Mode?
override var vimChangeActionSwitchMode: VimStateMachine.Mode?
get() = editor.vimChangeActionSwitchMode
set(value) {
editor.vimChangeActionSwitchMode = value

View File

@@ -3,6 +3,7 @@ package com.maddyhome.idea.vim.newapi
import com.intellij.openapi.components.service
import com.intellij.openapi.components.serviceIfCreated
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.editor.Editor
import com.maddyhome.idea.vim.api.EngineEditorHelper
import com.maddyhome.idea.vim.api.ExEntryPanel
import com.maddyhome.idea.vim.api.ExecutionContextManager
@@ -39,7 +40,7 @@ import com.maddyhome.idea.vim.api.VimrcFileState
import com.maddyhome.idea.vim.api.VimscriptExecutor
import com.maddyhome.idea.vim.api.VimscriptFunctionService
import com.maddyhome.idea.vim.api.VimscriptParser
import com.maddyhome.idea.vim.command.CommandState
import com.maddyhome.idea.vim.command.VimStateMachine
import com.maddyhome.idea.vim.common.VimMachine
import com.maddyhome.idea.vim.diagnostic.VimLogger
import com.maddyhome.idea.vim.ex.ExOutputModel
@@ -63,19 +64,19 @@ import com.maddyhome.idea.vim.helper.IjEditorHelper
import com.maddyhome.idea.vim.helper.IjVimStringParser
import com.maddyhome.idea.vim.helper.UndoRedoHelper
import com.maddyhome.idea.vim.helper.VimCommandLineHelper
import com.maddyhome.idea.vim.helper.vimCommandState
import com.maddyhome.idea.vim.helper.vimStateMachine
import com.maddyhome.idea.vim.history.VimHistory
import com.maddyhome.idea.vim.macro.VimMacro
import com.maddyhome.idea.vim.mark.VimMarkGroup
import com.maddyhome.idea.vim.options.OptionService
import com.maddyhome.idea.vim.put.VimPut
import com.maddyhome.idea.vim.register.VimRegisterGroup
import com.maddyhome.idea.vim.ui.VimRcFileState
import com.maddyhome.idea.vim.undo.VimUndoRedo
import com.maddyhome.idea.vim.vimscript.Executor
import com.maddyhome.idea.vim.vimscript.services.FunctionStorage
import com.maddyhome.idea.vim.vimscript.services.OptionService
import com.maddyhome.idea.vim.vimscript.services.PatternService
import com.maddyhome.idea.vim.vimscript.services.VimVariableService
import com.maddyhome.idea.vim.vimscript.services.VariableService
import com.maddyhome.idea.vim.yank.VimYankGroup
class IjVimInjector : VimInjectorBase() {
@@ -160,7 +161,7 @@ class IjVimInjector : VimInjectorBase() {
override val functionService: VimscriptFunctionService
get() = FunctionStorage
override val variableService: VimVariableService
override val variableService: VariableService
get() = service()
override val vimrcFileState: VimrcFileState
get() = VimRcFileState
@@ -179,15 +180,23 @@ class IjVimInjector : VimInjectorBase() {
override val vimStorageService: VimStorageService
get() = service()
override fun commandStateFor(editor: VimEditor): CommandState {
var res = editor.ij.vimCommandState
override fun commandStateFor(editor: VimEditor): VimStateMachine {
var res = editor.ij.vimStateMachine
if (res == null) {
res = CommandState(editor)
editor.ij.vimCommandState = res
res = VimStateMachine(editor)
editor.ij.vimStateMachine = res
}
return res
}
override fun commandStateFor(editor: Any): VimStateMachine {
return when (editor) {
is VimEditor -> this.commandStateFor(editor)
is Editor -> this.commandStateFor(IjVimEditor(editor))
else -> error("Unexpected type: $editor")
}
}
override val engineEditorHelper: EngineEditorHelper
get() = service<IjEditorHelper>()
override val editorGroup: VimEditorGroup

View File

@@ -37,19 +37,19 @@ class IjVimMessages : VimMessagesBase() {
private var error = false
private var lastBeepTimeMillis = 0L
override fun showStatusBarMessage(msg: String?) {
override fun showStatusBarMessage(message: String?) {
if (ApplicationManager.getApplication().isUnitTestMode) {
message = msg
this.message = message
}
val pm = ProjectManager.getInstance()
val projects = pm.openProjects
for (project in projects) {
val bar = WindowManager.getInstance().getStatusBar(project)
if (bar != null) {
if (msg.isNullOrEmpty()) {
if (message.isNullOrEmpty()) {
bar.info = ""
} else {
bar.info = "VIM - $msg"
bar.info = "VIM - $message"
}
}
}

Some files were not shown because too many files have changed in this diff Show More