mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-08-17 16:31:45 +02:00
Compare commits
28 Commits
0.60.3-EAP
...
0.61
Author | SHA1 | Date | |
---|---|---|---|
![]() |
3881b905be | ||
![]() |
073c62f868 | ||
![]() |
d8e0f26bea | ||
![]() |
04c24ab5d0 | ||
![]() |
bfb0ba1ab9 | ||
![]() |
fb7d48af1f | ||
![]() |
559989ce4b | ||
![]() |
81f59e3c18 | ||
![]() |
b6adf9f7a9 | ||
![]() |
b972a01cf0 | ||
![]() |
0296cae712 | ||
![]() |
c38b18e16b | ||
![]() |
8d65c3ed26 | ||
![]() |
995bb966ad | ||
![]() |
dbda1a76ca | ||
![]() |
ed6f990d9a | ||
![]() |
4f86d9cc77 | ||
![]() |
d55774abab | ||
![]() |
d5591ba08d | ||
![]() |
f67d483c4e | ||
![]() |
f26ddd4a27 | ||
![]() |
dbbea642bc | ||
![]() |
0539e39977 | ||
![]() |
65235d32a1 | ||
![]() |
ecfcdf5a8c | ||
![]() |
cf127ba7f9 | ||
![]() |
1fba77d925 | ||
![]() |
5752b116f6 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -5,6 +5,7 @@
|
|||||||
!/.idea/scopes
|
!/.idea/scopes
|
||||||
!/.idea/copyright
|
!/.idea/copyright
|
||||||
!/.idea/icon.png
|
!/.idea/icon.png
|
||||||
|
!/.idea/inspectionProfiles
|
||||||
|
|
||||||
/build/
|
/build/
|
||||||
/out/
|
/out/
|
||||||
|
9
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
9
.idea/inspectionProfiles/Project_Default.xml
generated
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Project Default" />
|
||||||
|
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_requireAnnotationsFirst" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
23
.idea/inspectionProfiles/Qodana.xml
generated
Normal file
23
.idea/inspectionProfiles/Qodana.xml
generated
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<description>Inspections profile for Qodana</description>
|
||||||
|
<option name="myName" value="Qodana" />
|
||||||
|
<inspection_tool class="CanBeFinal" enabled="false" level="WARNING" enabled_by_default="false">
|
||||||
|
<option name="REPORT_CLASSES" value="false" />
|
||||||
|
<option name="REPORT_METHODS" value="false" />
|
||||||
|
<option name="REPORT_FIELDS" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="GrUnresolvedAccess" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="MissortedModifiers" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<option name="m_requireAnnotationsFirst" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="SameReturnValue" enabled="false" level="WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="SpellCheckingInspection" enabled="false" level="TYPO" enabled_by_default="false">
|
||||||
|
<option name="processCode" value="true" />
|
||||||
|
<option name="processLiterals" value="true" />
|
||||||
|
<option name="processComments" value="true" />
|
||||||
|
</inspection_tool>
|
||||||
|
<inspection_tool class="StaticMethodOnlyUsedInOneClass" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="SuperTearDownInFinally" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
2
.teamcity/_Self/buildTypes/Release.kt
vendored
2
.teamcity/_Self/buildTypes/Release.kt
vendored
@@ -10,7 +10,7 @@ object Release : BuildType({
|
|||||||
description = "Build and publish IdeaVim plugin"
|
description = "Build and publish IdeaVim plugin"
|
||||||
|
|
||||||
artifactRules = "build/distributions/*"
|
artifactRules = "build/distributions/*"
|
||||||
buildNumberPattern = "0.60"
|
buildNumberPattern = "0.61"
|
||||||
|
|
||||||
params {
|
params {
|
||||||
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
||||||
|
2
.teamcity/_Self/buildTypes/ReleaseEap.kt
vendored
2
.teamcity/_Self/buildTypes/ReleaseEap.kt
vendored
@@ -13,7 +13,7 @@ object ReleaseEap : BuildType({
|
|||||||
description = "Build and publish EAP of IdeaVim plugin"
|
description = "Build and publish EAP of IdeaVim plugin"
|
||||||
|
|
||||||
artifactRules = "build/distributions/*"
|
artifactRules = "build/distributions/*"
|
||||||
buildNumberPattern = "0.60.%build.counter%"
|
buildNumberPattern = "0.61.%build.counter%"
|
||||||
|
|
||||||
params {
|
params {
|
||||||
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
param("env.ORG_GRADLE_PROJECT_ideaVersion", "2020.2")
|
||||||
|
12
CHANGES.md
12
CHANGES.md
@@ -24,6 +24,10 @@ usual beta standards.
|
|||||||
|
|
||||||
## To Be Released
|
## To Be Released
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
## 0.61, 2020-11-12
|
||||||
|
|
||||||
### Features:
|
### Features:
|
||||||
* Ability to map IDE actions via the `<Action>` keyword. E.g. `map <C-K> <Action>(CommentByLineComment)`.
|
* Ability to map IDE actions via the `<Action>` keyword. E.g. `map <C-K> <Action>(CommentByLineComment)`.
|
||||||
Check out `README.md` for the details.
|
Check out `README.md` for the details.
|
||||||
@@ -44,14 +48,18 @@ usual beta standards.
|
|||||||
### Changes:
|
### Changes:
|
||||||
* Fix `<Esc>` for dialogs. Now `<Esc>` will exit insert / visual mode and close the dialog from normal mode.
|
* Fix `<Esc>` for dialogs. Now `<Esc>` will exit insert / visual mode and close the dialog from normal mode.
|
||||||
* Add option to disable IdeaVim in dialogs / single line editors. [VIM-765](https://youtrack.jetbrains.com/issue/VIM-765)
|
* Add option to disable IdeaVim in dialogs / single line editors. [VIM-765](https://youtrack.jetbrains.com/issue/VIM-765)
|
||||||
Use `set ideaenabledbufs=` to disable IdeaVim in dialog editors.
|
Use `set ideavimsupport=` to disable IdeaVim in dialog editors.
|
||||||
_Note for EAP users: the option name can be changed for the stable release_
|
* Reposition cursor when `scrolloff` changes
|
||||||
|
|
||||||
### Fixes:
|
### Fixes:
|
||||||
* [VIM-2150](https://youtrack.jetbrains.com/issue/VIM-2150) `Shift-D` should not delete an empty line
|
* [VIM-2150](https://youtrack.jetbrains.com/issue/VIM-2150) `Shift-D` should not delete an empty line
|
||||||
* [VIM-2157](https://youtrack.jetbrains.com/issue/VIM-2157) Fix tab with an active template
|
* [VIM-2157](https://youtrack.jetbrains.com/issue/VIM-2157) Fix tab with an active template
|
||||||
* [VIM-2156](https://youtrack.jetbrains.com/issue/VIM-2156) Correct up/down motions with inlays
|
* [VIM-2156](https://youtrack.jetbrains.com/issue/VIM-2156) Correct up/down motions with inlays
|
||||||
* [VIM-2144](https://youtrack.jetbrains.com/issue/VIM-2144) Correct text position after block insert with inlays
|
* [VIM-2144](https://youtrack.jetbrains.com/issue/VIM-2144) Correct text position after block insert with inlays
|
||||||
|
* [VIM-2158](https://youtrack.jetbrains.com/issue/VIM-2158) Fix scrolling when `scrolloff` is over half screen height, but less than full height
|
||||||
|
|
||||||
|
### Merged PRs:
|
||||||
|
* [255](https://github.com/JetBrains/ideavim/pull/255) by [Matt Ellis](https://github.com/citizenmatt): Fix various scrolling issues
|
||||||
|
|
||||||
## 0.60, 2020-10-09
|
## 0.60, 2020-10-09
|
||||||
|
|
||||||
|
40
README.md
40
README.md
@@ -11,7 +11,7 @@ IdeaVim
|
|||||||
[![Gitter][gitter-svg]][gitter]
|
[![Gitter][gitter-svg]][gitter]
|
||||||
[![Twitter][twitter-svg]][twitter]
|
[![Twitter][twitter-svg]][twitter]
|
||||||
|
|
||||||
IdeaVim is a Vim emulation plugin for IDEs based on the IntelliJ Platform.
|
IdeaVim is a Vim emulation plugin for IntelliJ Platform-based IDEs.
|
||||||
|
|
||||||
##### Contact maintainers:
|
##### Contact maintainers:
|
||||||
* [Bug tracker](https://youtrack.jetbrains.com/issues/VIM)
|
* [Bug tracker](https://youtrack.jetbrains.com/issues/VIM)
|
||||||
@@ -188,42 +188,38 @@ Changes to the IDE
|
|||||||
|
|
||||||
### Executing IDE Actions
|
### Executing IDE Actions
|
||||||
|
|
||||||
IdeaVim adds two commands for listing and executing arbitrary IDE actions as
|
IdeaVim adds various commands for listing and executing arbitrary IDE actions as
|
||||||
Ex commands or via `:map` command mappings:
|
Ex commands or via `:map` command mappings:
|
||||||
|
|
||||||
|
**Executing actions:**
|
||||||
|
* `:action {action_id}`
|
||||||
|
* Execute an action by id. Works from Ex command line.
|
||||||
|
* `<Action>(*action_id*)`
|
||||||
|
* For the mappings you can use a special `<Action>` keyword. Don't forget the parentheses.
|
||||||
|
|
||||||
|
**Finding actions:**
|
||||||
* `:actionlist [pattern]`
|
* `:actionlist [pattern]`
|
||||||
* Find IDE actions by name or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
|
* Find IDE actions by id or keymap pattern (E.g. `:actionlist extract`, `:actionlist <C-D`)
|
||||||
* `:action {name}`
|
|
||||||
* Execute an action named `NAME`
|
|
||||||
|
|
||||||
In addition to `:actionlist` command, IdeaVim provides `IdeaVim: track action Ids` option to
|
* In addition to `:actionlist` command, IdeaVim provides `IdeaVim: track action Ids` option to
|
||||||
extract the ids of executed command. This option can be found in "Search everywhere" (double `shift`). **[To Be Released]**
|
extract the ids of executed command. This option can be found in "Search everywhere" (double `shift`).
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><strong>"Track aciton Ids" Details</strong> (click to see)</summary>
|
<summary><strong>"Track aciton Ids" Details</strong> (click to see)</summary>
|
||||||
<img src="resources/readme/track_action_id.gif" alt="track actioin ids"/>
|
<img src="resources/readme/track_action_id.gif" alt="track action ids"/>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
For the mappings you can use a special `<Action>` keyword. Use `<Action>(*action_id*)` to map keys to some action. Don't
|
|
||||||
forget the parentheses. This keyword works for insert mode as well. **[To Be Released]**
|
|
||||||
|
|
||||||
Examples:
|
Examples:
|
||||||
|
|
||||||
```vim
|
```vim
|
||||||
" Map \r to the Reformat Code action
|
" Map \r to the Reformat Code action
|
||||||
:map \r :action ReformatCode<CR>
|
:map \r <Action>(ReformatCode)
|
||||||
" or
|
|
||||||
:map \r <Action>(ReformatCode) " [To Be Released]
|
|
||||||
|
|
||||||
" Map <leader>d to start debug
|
" Map <leader>d to start debug
|
||||||
:map <leader>d :action Debug<CR>
|
:map <leader>d <Action>(Debug)
|
||||||
" or
|
|
||||||
:map <leader>d <Action>(Debug) " [To Be Released]
|
|
||||||
|
|
||||||
" Map \b to toggle the breakpoint on the current line
|
" Map \b to toggle the breakpoint on the current line
|
||||||
:map \b :action ToggleLineBreakpoint<CR>
|
:map \b <Action>(ToggleLineBreakpoint)
|
||||||
" or
|
|
||||||
:map \b <Action>(ToggleLineBreakpoint) " [To Be Released]
|
|
||||||
```
|
```
|
||||||
|
|
||||||
### Undo/Redo
|
### Undo/Redo
|
||||||
|
@@ -13,7 +13,7 @@ buildscript {
|
|||||||
}
|
}
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id 'org.jetbrains.intellij' version '0.6.1'
|
id 'org.jetbrains.intellij' version '0.6.2'
|
||||||
id 'io.gitlab.arturbosch.detekt' version '1.14.1'
|
id 'io.gitlab.arturbosch.detekt' version '1.14.1'
|
||||||
id "org.jetbrains.changelog" version "0.6.2"
|
id "org.jetbrains.changelog" version "0.6.2"
|
||||||
}
|
}
|
||||||
|
@@ -4,7 +4,15 @@ Emulated Vim Plugins
|
|||||||
IdeaVim extensions emulate plugins of the original Vim. In order to use
|
IdeaVim extensions emulate plugins of the original Vim. In order to use
|
||||||
IdeaVim extensions, you have to enable them via this command in your `~/.ideavimrc`:
|
IdeaVim extensions, you have to enable them via this command in your `~/.ideavimrc`:
|
||||||
|
|
||||||
set <extension-name>
|
```
|
||||||
|
set <extension-name>
|
||||||
|
```
|
||||||
|
|
||||||
|
If you reuse your existing `.vimrc` file using `source ~/.vimrc`, IdeaVim can parse and enable plugins that are defined
|
||||||
|
using [vim-plug](https://github.com/junegunn/vim-plug) or [vundle](https://github.com/VundleVim/Vundle.vim).
|
||||||
|
No additional set commands in `~/.ideavimrc` are required.
|
||||||
|
If you'd like to disable some plugin that's enabled in `.vimrc`, you can use `set no<extension-name>`
|
||||||
|
in `~/.ideavimrc`.
|
||||||
|
|
||||||
Available extensions:
|
Available extensions:
|
||||||
|
|
||||||
@@ -20,18 +28,52 @@ Available extensions:
|
|||||||
## surround
|
## surround
|
||||||
|
|
||||||
* Setup: `set surround`
|
* Setup: `set surround`
|
||||||
|
* <details>
|
||||||
|
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||||
|
<code>Plug 'https://github.com/tpope/vim-surround'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'tpope/vim-surround'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-surround'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=1697'</code>
|
||||||
|
</details>
|
||||||
* Emulates [vim-surround](https://github.com/tpope/vim-surround)
|
* Emulates [vim-surround](https://github.com/tpope/vim-surround)
|
||||||
* Commands: `ys`, `cs`, `ds`, `S`
|
* Commands: `ys`, `cs`, `ds`, `S`
|
||||||
|
|
||||||
## multiple-cursors
|
## multiple-cursors
|
||||||
|
|
||||||
* Setup: `set multiple-cursors`
|
* Setup: `set multiple-cursors`
|
||||||
|
* <details>
|
||||||
|
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||||
|
<code>Plug 'https://github.com/terryma/vim-multiple-cursors'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'terryma/vim-multiple-cursors'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-multiple-cursors'</code>
|
||||||
|
</details>
|
||||||
* Emulates [vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors)
|
* Emulates [vim-multiple-cursors](https://github.com/terryma/vim-multiple-cursors)
|
||||||
* Commands: `<A-n>`, `<A-x>`, `<A-p>`, `g<A-n>`
|
* Commands: `<A-n>`, `<A-x>`, `<A-p>`, `g<A-n>`
|
||||||
|
|
||||||
## commentary
|
## commentary
|
||||||
|
|
||||||
* Setup: `set commentary`
|
* Setup: `set commentary`
|
||||||
|
* <details>
|
||||||
|
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||||
|
<code>Plug 'https://github.com/tpope/vim-commentary'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'tpope/vim-commentary'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-commentary'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=3695'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'tomtom/tcomment_vim'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'tcomment_vim'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=1173'</code>
|
||||||
|
</details>
|
||||||
* Emulates [commentary.vim](https://github.com/tpope/vim-commentary)
|
* Emulates [commentary.vim](https://github.com/tpope/vim-commentary)
|
||||||
* Commands: `gcc`, `gc + motion`, `v_gc`
|
* Commands: `gcc`, `gc + motion`, `v_gc`
|
||||||
* By [Daniel Leong](https://github.com/dhleong)
|
* By [Daniel Leong](https://github.com/dhleong)
|
||||||
@@ -39,6 +81,22 @@ Available extensions:
|
|||||||
## ReplaceWithRegister
|
## ReplaceWithRegister
|
||||||
|
|
||||||
* Setup: `set ReplaceWithRegister`
|
* Setup: `set ReplaceWithRegister`
|
||||||
|
* <details>
|
||||||
|
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||||
|
<code>Plug 'https://github.com/vim-scripts/ReplaceWithRegister'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-scripts/ReplaceWithRegister'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'ReplaceWithRegister'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'https://github.com/inkarkat/vim-ReplaceWithRegister'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'inkarkat/vim-ReplaceWithRegister'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-ReplaceWithRegister'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2703'</code>
|
||||||
|
</details>
|
||||||
* Emulates [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister)
|
* Emulates [ReplaceWithRegister](https://github.com/vim-scripts/ReplaceWithRegister)
|
||||||
* Commands: `gr`, `grr`
|
* Commands: `gr`, `grr`
|
||||||
* By [igrekster](https://github.com/igrekster)
|
* By [igrekster](https://github.com/igrekster)
|
||||||
@@ -47,6 +105,16 @@ Available extensions:
|
|||||||
|
|
||||||
* Setup:
|
* Setup:
|
||||||
* `set argtextobj`
|
* `set argtextobj`
|
||||||
|
* <details>
|
||||||
|
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||||
|
<code>Plug 'https://github.com/vim-scripts/argtextobj.vim'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-scripts/argtextobj.vim'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'argtextobj.vim'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2699'</code>
|
||||||
|
</details>
|
||||||
* By default, only the arguments inside parenthesis are considered. To extend the functionality
|
* By default, only the arguments inside parenthesis are considered. To extend the functionality
|
||||||
to other types of brackets, set `g:argtextobj_pairs` variable to a comma-separated
|
to other types of brackets, set `g:argtextobj_pairs` variable to a comma-separated
|
||||||
list of colon-separated pairs (same as VIM's `matchpairs` option), like
|
list of colon-separated pairs (same as VIM's `matchpairs` option), like
|
||||||
@@ -59,6 +127,14 @@ Available extensions:
|
|||||||
## exchange
|
## exchange
|
||||||
|
|
||||||
* Setup: `set exchange`
|
* Setup: `set exchange`
|
||||||
|
* <details>
|
||||||
|
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||||
|
<code>Plug 'https://github.com/tommcdo/vim-exchange'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'tommcdo/vim-exchange'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-exchange'</code>
|
||||||
|
</details>
|
||||||
* Emulates [vim-exchange](https://github.com/tommcdo/vim-exchange)
|
* Emulates [vim-exchange](https://github.com/tommcdo/vim-exchange)
|
||||||
* Commands: `cx`, `cxx`, `X`, `cxc`
|
* Commands: `cx`, `cxx`, `X`, `cxc`
|
||||||
* By [fan-tom](https://github.com/fan-tom)
|
* By [fan-tom](https://github.com/fan-tom)
|
||||||
@@ -66,6 +142,16 @@ Available extensions:
|
|||||||
## textobj-entire
|
## textobj-entire
|
||||||
|
|
||||||
* Setup: `set textobj-entire`
|
* Setup: `set textobj-entire`
|
||||||
|
* <details>
|
||||||
|
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||||
|
<code>Plug 'https://github.com/kana/vim-textobj-entire'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'kana/vim-textobj-entire'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-textobj-entire'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'https://www.vim.org/scripts/script.php?script_id=2610'</code>
|
||||||
|
</details>
|
||||||
* Emulates [vim-textobj-entire](https://github.com/kana/vim-textobj-entire)
|
* Emulates [vim-textobj-entire](https://github.com/kana/vim-textobj-entire)
|
||||||
* Additional text objects: `ae`, `ie`
|
* Additional text objects: `ae`, `ie`
|
||||||
* By [Alexandre Grison](https://github.com/agrison)
|
* By [Alexandre Grison](https://github.com/agrison)
|
||||||
@@ -74,6 +160,14 @@ Available extensions:
|
|||||||
|
|
||||||
* Setup:
|
* Setup:
|
||||||
* `set highlightedyank`
|
* `set highlightedyank`
|
||||||
|
* <details>
|
||||||
|
<summary>Alternative vim-plug / vundle syntax</summary>
|
||||||
|
<code>Plug 'https://github.com/machakann/vim-highlightedyank'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'machakann/vim-highlightedyank'</code>
|
||||||
|
<br/>
|
||||||
|
<code>Plug 'vim-highlightedyank'</code>
|
||||||
|
</details>
|
||||||
* if you want to optimize highlight duration, assign a time in milliseconds:
|
* if you want to optimize highlight duration, assign a time in milliseconds:
|
||||||
`let g:highlightedyank_highlight_duration = "1000"`
|
`let g:highlightedyank_highlight_duration = "1000"`
|
||||||
A negative number makes the highlight persistent.
|
A negative number makes the highlight persistent.
|
||||||
|
@@ -125,7 +125,7 @@ The following `:set` commands can appear in `~/.ideavimrc` or be set manually in
|
|||||||
"<C-Down>", "<C-Up>", "<PageUp>", "<PageDown>",
|
"<C-Down>", "<C-Up>", "<PageUp>", "<PageDown>",
|
||||||
"<C-J>", "<C-Q>"
|
"<C-J>", "<C-Q>"
|
||||||
|
|
||||||
`ideaenabledbufs` `ideaenabledbufs` List of strings (default "dialog") [To Be Released]
|
`ideavimsupport` `ideavimsupport` List of strings (default "dialog")
|
||||||
|
|
||||||
Define the list of additional buffers where IdeaVim is enabled.
|
Define the list of additional buffers where IdeaVim is enabled.
|
||||||
|
|
||||||
|
@@ -1,19 +1,54 @@
|
|||||||
<idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude">
|
<idea-plugin url="https://plugins.jetbrains.com/plugin/164" xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
<name>IdeaVim</name>
|
<name>IdeaVim</name>
|
||||||
<id>IdeaVIM</id>
|
<id>IdeaVIM</id>
|
||||||
<change-notes><![CDATA[
|
<change-notes>
|
||||||
<ul>
|
<h3>Features:</h3>
|
||||||
<li>Fix ESC in dialogs</li>
|
<br/>
|
||||||
<li>Add option to disable IdeaVim in dialogs and single line editors</li>
|
<ul><li>Ability to map IDE actions via the <code>&lt;Action&gt;</code> keyword. E.g.
|
||||||
<li>Ability to map IDE actions via the <Action> keyword.</li>
|
<code>map &lt;C-K&gt; &lt;Action&gt;(CommentByLineComment)</code>.
|
||||||
<li>"IdeaVim: track action Ids" command to find action ids for the :action command.
|
Check out <code>README.md</code> for the details.</li><li><code>IdeaVim: track action
|
||||||
<li>Add new option to register IdeaVim extensions. Please read the changelog for details</li>
|
Ids</code> command to find action ids for the <code>:action</code> command.
|
||||||
</ul>
|
Enable this option in &quot;Search everywhere&quot; (double shift).</li><li>Ability to enable
|
||||||
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
|
extensions using <code>vim-plug</code> or <code>vundle</code> syntax.<br />
|
||||||
]]></change-notes>
|
E.g. to enable commentary extension you can use one of the following commands:<pre><code
|
||||||
|
class="language-vim">set commentary
|
||||||
|
Plug 'tpope/vim-commentary'
|
||||||
|
Plug 'https://github.com/tpope/vim-commentary'
|
||||||
|
Plugin 'tpope/vim-commentary'
|
||||||
|
...
|
||||||
|
</code></pre><p>This approach is especially handy if you have <code>.vimrc</code> with
|
||||||
|
plugins registered via <code>vim-plug</code> or <code>vundle</code>.</p></li></ul>
|
||||||
|
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<h3>Changes:</h3>
|
||||||
|
<br/>
|
||||||
|
<ul><li>Fix <code>&lt;Esc&gt;</code> for dialogs. Now <code>&lt;Esc&gt;</code>
|
||||||
|
will exit insert / visual mode and close the dialog from normal mode.</li><li>Add option to disable
|
||||||
|
IdeaVim in dialogs / single line editors. <a href="https://youtrack.jetbrains.com/issue/VIM-765">VIM-765</a><br
|
||||||
|
/>
|
||||||
|
Use <code>set ideavimsupport=</code> to disable IdeaVim in dialog editors. </li><li>Reposition
|
||||||
|
cursor when <code>scrolloff</code> changes</li></ul>
|
||||||
|
|
||||||
|
<br/>
|
||||||
|
<h3>Fixes:</h3>
|
||||||
|
<br/>
|
||||||
|
<ul><li><a href="https://youtrack.jetbrains.com/issue/VIM-2150">VIM-2150</a> <code>Shift-D</code>
|
||||||
|
should not delete an empty line</li><li><a href="https://youtrack.jetbrains.com/issue/VIM-2157">VIM-2157</a>
|
||||||
|
Fix tab with an active template</li><li><a href="https://youtrack.jetbrains.com/issue/VIM-2156">VIM-2156</a>
|
||||||
|
Correct up/down motions with inlays</li><li><a href="https://youtrack.jetbrains.com/issue/VIM-2144">VIM-2144</a>
|
||||||
|
Correct text position after block insert with inlays</li><li><a
|
||||||
|
href="https://youtrack.jetbrains.com/issue/VIM-2158">VIM-2158</a> Fix scrolling when <code>scrolloff</code>
|
||||||
|
is over half screen height, but less than full height</li></ul>
|
||||||
|
<br/>
|
||||||
|
<p>See also the complete <a href="https://github.com/JetBrains/ideavim/blob/master/CHANGES.md">changelog</a>.</p>
|
||||||
|
</change-notes>
|
||||||
<description><![CDATA[
|
<description><![CDATA[
|
||||||
<p>Vim emulation plug-in for IDEs based on the IntelliJ platform.</p>
|
<p>Vim emulation plugin for IntelliJ Platform-based IDEs.</p>
|
||||||
<p>IdeaVim supports many Vim features including normal/insert/visual modes, motion keys, deletion/changing, marks, registers, some Ex commands, Vim regexps, configuration via ~/.ideavimrc, macros, window commands, etc.</p>
|
<br/>
|
||||||
|
<p>IdeaVim supports many Vim features including normal/insert/visual modes, motion keys, deletion/changing,
|
||||||
|
marks, registers, some Ex commands, Vim regexps, configuration via ~/.ideavimrc, macros, Vim plugins, etc.</p>
|
||||||
|
<br/>
|
||||||
<p>See also:</p>
|
<p>See also:</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href="https://github.com/JetBrains/ideavim">GitHub repository</a>: documentation and contributing</li>
|
<li><a href="https://github.com/JetBrains/ideavim">GitHub repository</a>: documentation and contributing</li>
|
||||||
|
@@ -20,15 +20,29 @@ package com.maddyhome.idea.vim.action
|
|||||||
import com.intellij.openapi.actionSystem.DataContext
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.command.Command
|
import com.maddyhome.idea.vim.command.Command
|
||||||
|
import com.maddyhome.idea.vim.command.CommandState
|
||||||
|
import com.maddyhome.idea.vim.group.MotionGroup
|
||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||||
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
||||||
|
import com.maddyhome.idea.vim.helper.mode
|
||||||
|
import com.maddyhome.idea.vim.helper.vimForEachCaret
|
||||||
|
|
||||||
class ResetModeAction : VimActionHandler.SingleExecution() {
|
class ResetModeAction : VimActionHandler.SingleExecution() {
|
||||||
override val type: Command.Type = Command.Type.OTHER_WRITABLE
|
override val type: Command.Type = Command.Type.OTHER_WRITABLE
|
||||||
|
|
||||||
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
||||||
|
val modeBeforeReset = editor.mode
|
||||||
KeyHandler.getInstance().fullReset(editor.getTopLevelEditor())
|
KeyHandler.getInstance().fullReset(editor.getTopLevelEditor())
|
||||||
|
|
||||||
|
if (modeBeforeReset == CommandState.Mode.INSERT) {
|
||||||
|
editor.vimForEachCaret { caret ->
|
||||||
|
val position = VimPlugin.getMotion().getOffsetOfHorizontalMotion(editor, caret, -1, false)
|
||||||
|
MotionGroup.moveCaret(editor, caret, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -128,7 +128,7 @@ class VimShortcutKeyAction : AnAction(), DumbAware {
|
|||||||
private fun isEnabledForEscape(editor: Editor): Boolean {
|
private fun isEnabledForEscape(editor: Editor): Boolean {
|
||||||
return editor.isPrimaryEditor()
|
return editor.isPrimaryEditor()
|
||||||
|| EditorHelper.isFileEditor(editor) && !editor.inNormalMode
|
|| EditorHelper.isFileEditor(editor) && !editor.inNormalMode
|
||||||
|| OptionsManager.ideaenabledbufs.contains("dialog") && !editor.inNormalMode
|
|| OptionsManager.ideavimsupport.contains("dialog") && !editor.inNormalMode
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isShortcutConflict(keyStroke: KeyStroke): Boolean {
|
private fun isShortcutConflict(keyStroke: KeyStroke): Boolean {
|
||||||
|
@@ -19,10 +19,14 @@ package com.maddyhome.idea.vim.action.motion.visual
|
|||||||
|
|
||||||
import com.intellij.openapi.actionSystem.DataContext
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.command.Command
|
import com.maddyhome.idea.vim.command.Command
|
||||||
|
import com.maddyhome.idea.vim.group.MotionGroup
|
||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||||
|
import com.maddyhome.idea.vim.helper.EditorHelper
|
||||||
import com.maddyhome.idea.vim.helper.exitVisualMode
|
import com.maddyhome.idea.vim.helper.exitVisualMode
|
||||||
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
import com.maddyhome.idea.vim.helper.getTopLevelEditor
|
||||||
|
import com.maddyhome.idea.vim.helper.vimForEachCaret
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author vlan
|
* @author vlan
|
||||||
@@ -32,6 +36,16 @@ class VisualExitModeAction : VimActionHandler.SingleExecution() {
|
|||||||
|
|
||||||
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
override fun execute(editor: Editor, context: DataContext, cmd: Command): Boolean {
|
||||||
editor.getTopLevelEditor().exitVisualMode()
|
editor.getTopLevelEditor().exitVisualMode()
|
||||||
|
|
||||||
|
// Should it be in [exitVisualMode]?
|
||||||
|
editor.vimForEachCaret { caret ->
|
||||||
|
val lineEnd = EditorHelper.getLineEndForOffset(editor, caret.offset)
|
||||||
|
if (lineEnd == caret.offset) {
|
||||||
|
val position = VimPlugin.getMotion().getOffsetOfHorizontalMotion(editor, caret, -1, false)
|
||||||
|
MotionGroup.moveCaret(editor, caret, position)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -178,7 +178,7 @@ class CommandState private constructor() {
|
|||||||
executingCommand = null
|
executingCommand = null
|
||||||
resetModes()
|
resetModes()
|
||||||
commandBuilder.resetInProgressCommandPart(getKeyRootNode(mappingState.mappingMode))
|
commandBuilder.resetInProgressCommandPart(getKeyRootNode(mappingState.mappingMode))
|
||||||
startDigraphSequence()
|
digraphSequence.reset()
|
||||||
updateStatus()
|
updateStatus()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -31,10 +31,11 @@ public interface VimExtension {
|
|||||||
@NotNull ExtensionPointName<ExtensionBeanClass> EP_NAME = ExtensionPointName.create("IdeaVIM.vimExtension");
|
@NotNull ExtensionPointName<ExtensionBeanClass> EP_NAME = ExtensionPointName.create("IdeaVIM.vimExtension");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @deprecated Please set extension name in <vimExtension> tag
|
* @deprecated This property is not used anymore, but we'll remove it much later to keep the compatibility of IdeaVim
|
||||||
|
* extensions with previous versions of IdeaVim.
|
||||||
*/
|
*/
|
||||||
@Deprecated
|
@Deprecated
|
||||||
@ApiStatus.ScheduledForRemoval(inVersion = "0.63")
|
@ApiStatus.ScheduledForRemoval(inVersion = "0.65")
|
||||||
@NotNull String getName();
|
@NotNull String getName();
|
||||||
|
|
||||||
default MappingOwner getOwner() {
|
default MappingOwner getOwner() {
|
||||||
|
@@ -42,10 +42,12 @@ import com.maddyhome.idea.vim.handler.MotionActionHandler;
|
|||||||
import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
|
import com.maddyhome.idea.vim.handler.TextObjectActionHandler;
|
||||||
import com.maddyhome.idea.vim.helper.*;
|
import com.maddyhome.idea.vim.helper.*;
|
||||||
import com.maddyhome.idea.vim.option.NumberOption;
|
import com.maddyhome.idea.vim.option.NumberOption;
|
||||||
|
import com.maddyhome.idea.vim.option.OptionChangeListener;
|
||||||
import com.maddyhome.idea.vim.option.OptionsManager;
|
import com.maddyhome.idea.vim.option.OptionsManager;
|
||||||
import com.maddyhome.idea.vim.ui.ExEntryPanel;
|
import com.maddyhome.idea.vim.ui.ExEntryPanel;
|
||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import kotlin.ranges.IntProgression;
|
import kotlin.ranges.IntProgression;
|
||||||
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
@@ -184,7 +186,7 @@ public class MotionGroup {
|
|||||||
if (caretVisualLine < topVisualLine + scrollOffset) {
|
if (caretVisualLine < topVisualLine + scrollOffset) {
|
||||||
newVisualLine = normalizeVisualLine(editor, topVisualLine + scrollOffset);
|
newVisualLine = normalizeVisualLine(editor, topVisualLine + scrollOffset);
|
||||||
}
|
}
|
||||||
else if (caretVisualLine >= bottomVisualLine - scrollOffset) {
|
else if (caretVisualLine > bottomVisualLine - scrollOffset) {
|
||||||
newVisualLine = normalizeVisualLine(editor, bottomVisualLine - scrollOffset);
|
newVisualLine = normalizeVisualLine(editor, bottomVisualLine - scrollOffset);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -631,10 +633,10 @@ public class MotionGroup {
|
|||||||
private static void scrollCaretIntoViewVertically(@NotNull Editor editor, final int caretLine) {
|
private static void scrollCaretIntoViewVertically(@NotNull Editor editor, final int caretLine) {
|
||||||
|
|
||||||
// TODO: Make this work with soft wraps
|
// TODO: Make this work with soft wraps
|
||||||
// Vim's algorithm works counts line heights for wrapped lines. We're using visual lines, which handles collapsed
|
// Vim's algorithm works by counting line heights for wrapped lines. We're using visual lines, which handles
|
||||||
// folds, but treats soft wrapped lines as individual lines.
|
// collapsed folds, but treats soft wrapped lines as individual lines.
|
||||||
// Ironically, after figuring out how Vim's algorithm works (although not *why*), it looks likely to be rewritten as
|
// Ironically, after figuring out how Vim's algorithm works (although not *why*) and reimplementing, it looks likely
|
||||||
// a dumb line for line reimplementation.
|
// that this needs to be replaced as a more or less dumb line for line rewrite.
|
||||||
|
|
||||||
final int topLine = getVisualLineAtTopOfScreen(editor);
|
final int topLine = getVisualLineAtTopOfScreen(editor);
|
||||||
final int bottomLine = getVisualLineAtBottomOfScreen(editor);
|
final int bottomLine = getVisualLineAtBottomOfScreen(editor);
|
||||||
@@ -642,7 +644,7 @@ public class MotionGroup {
|
|||||||
// We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
|
// We need the non-normalised value here, so we can handle cases such as so=999 to keep the current line centred
|
||||||
final int scrollOffset = OptionsManager.INSTANCE.getScrolloff().value();
|
final int scrollOffset = OptionsManager.INSTANCE.getScrolloff().value();
|
||||||
final int topBound = topLine + scrollOffset;
|
final int topBound = topLine + scrollOffset;
|
||||||
final int bottomBound = Math.max(topBound + 1, bottomLine - scrollOffset);
|
final int bottomBound = Math.max(topBound, bottomLine - scrollOffset);
|
||||||
|
|
||||||
// If we need to scroll the current line more than half a screen worth of lines then we just centre the new
|
// If we need to scroll the current line more than half a screen worth of lines then we just centre the new
|
||||||
// current line. This mimics vim behavior of e.g. 100G in a 300 line file with a screen size of 25 centering line
|
// current line. This mimics vim behavior of e.g. 100G in a 300 line file with a screen size of 25 centering line
|
||||||
@@ -650,7 +652,6 @@ public class MotionGroup {
|
|||||||
// Note that block inlays means that the pixel height we are scrolling can be larger than half the screen, even if
|
// Note that block inlays means that the pixel height we are scrolling can be larger than half the screen, even if
|
||||||
// the number of lines is less. I'm not sure what impact this has.
|
// the number of lines is less. I'm not sure what impact this has.
|
||||||
final int height = bottomLine - topLine + 1;
|
final int height = bottomLine - topLine + 1;
|
||||||
final int halfHeight = Math.max(2, (height / 2) - 1);
|
|
||||||
|
|
||||||
// Scrolljump isn't handled as you might expect. It is the minimal number of lines to scroll, but that doesn't mean
|
// Scrolljump isn't handled as you might expect. It is the minimal number of lines to scroll, but that doesn't mean
|
||||||
// newLine = caretLine +/- MAX(sj, so)
|
// newLine = caretLine +/- MAX(sj, so)
|
||||||
@@ -663,7 +664,7 @@ public class MotionGroup {
|
|||||||
// (See move.c:scroll_cursor_top)
|
// (See move.c:scroll_cursor_top)
|
||||||
//
|
//
|
||||||
// When scrolling down (`j` - scrolling window down in the buffer; more lines are visible at the bottom), Vim again
|
// When scrolling down (`j` - scrolling window down in the buffer; more lines are visible at the bottom), Vim again
|
||||||
// expands lines above and below the new bottom line, but calcualtes things a little differently. The total number
|
// expands lines above and below the new bottom line, but calculates things a little differently. The total number
|
||||||
// of lines expanded is at least scrolljump and there must be at least scrolloff lines below.
|
// of lines expanded is at least scrolljump and there must be at least scrolloff lines below.
|
||||||
// Since the lines are advancing simultaneously, it is only possible to get scrolljump/2 above the new cursor line.
|
// Since the lines are advancing simultaneously, it is only possible to get scrolljump/2 above the new cursor line.
|
||||||
// If there are fewer than scrolljump/2 lines between the current bottom line and the new cursor line, the extra
|
// If there are fewer than scrolljump/2 lines between the current bottom line and the new cursor line, the extra
|
||||||
@@ -678,10 +679,26 @@ public class MotionGroup {
|
|||||||
// out correct scroll locations
|
// out correct scroll locations
|
||||||
final int scrollJump = getScrollJump(editor, height);
|
final int scrollJump = getScrollJump(editor, height);
|
||||||
|
|
||||||
if (caretLine < topBound) {
|
// Unavoidable fudge value. Multiline rendered doc comments can mean we have very few actual lines, and scrolling
|
||||||
|
// can get stuck in a loop as we re-centre the cursor instead of actually moving it. But if we ignore all inlays
|
||||||
|
// and use the approximate screen height instead of the actual screen height (in lines), we make incorrect
|
||||||
|
// assumptions about the top/bottom line numbers and can scroll to the wrong location. E.g. if there are enough doc
|
||||||
|
// comments (String.java) it's possible to get 12 lines of actual code on screen. Given scrolloff=5, it's very easy
|
||||||
|
// to hit problems, and have (scrolloffset > height / 2) and scroll to the middle of the screen. We'll use this
|
||||||
|
// fudge value to make sure we're working with sensible values. Note that this problem doesn't affect code without
|
||||||
|
// block inlays as positioning the cursor in the middle of the screen always positions it in a deterministic manner,
|
||||||
|
// relative to other text in the file.
|
||||||
|
final int inlayAwareMinHeightFudge = getApproximateScreenHeight(editor) / 2;
|
||||||
|
|
||||||
|
// Note that while these calculations do the same thing that Vim does, it processes them differently. E.g. it
|
||||||
|
// optionally checks and moves the top line, then optionally checks the bottom line. This gives us the same results
|
||||||
|
// via the tests.
|
||||||
|
if (height > inlayAwareMinHeightFudge && scrollOffset > height / 2) {
|
||||||
|
scrollVisualLineToMiddleOfScreen(editor, caretLine);
|
||||||
|
} else if (caretLine < topBound) {
|
||||||
// Scrolling up, put the cursor at the top of the window (minus scrolloff)
|
// Scrolling up, put the cursor at the top of the window (minus scrolloff)
|
||||||
// Initial approximation in move.c:update_topline
|
// Initial approximation in move.c:update_topline (including same calculation for halfHeight)
|
||||||
if (topLine + scrollOffset - caretLine >= halfHeight) {
|
if (topLine + scrollOffset - caretLine >= Math.max(2, (height / 2) - 1)) {
|
||||||
scrollVisualLineToMiddleOfScreen(editor, caretLine);
|
scrollVisualLineToMiddleOfScreen(editor, caretLine);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -692,9 +709,12 @@ public class MotionGroup {
|
|||||||
final int scrollOffsetTopLine = Math.max(0, caretLine - scrollOffset);
|
final int scrollOffsetTopLine = Math.max(0, caretLine - scrollOffset);
|
||||||
final int newTopLine = Math.min(scrollOffsetTopLine, scrollJumpTopLine);
|
final int newTopLine = Math.min(scrollOffsetTopLine, scrollJumpTopLine);
|
||||||
|
|
||||||
// Used is set to the line height of caretLine, and then incremented by line height of the lines above and
|
// Used is set to the line height of caretLine (1 or how many lines soft wraps take up), and then incremented by
|
||||||
// below caretLine (up to scrolloff or end of file)
|
// the line heights of the lines above and below caretLine (up to scrolloff or end of file).
|
||||||
final int used = 1 + (newTopLine - topLine) + Math.min(scrollOffset, getVisualLineCount(editor) - topLine);
|
// Our implementation ignores soft wrap line heights. Folds already have a line height of 1.
|
||||||
|
final int usedAbove = caretLine - newTopLine;
|
||||||
|
final int usedBelow = Math.min(scrollOffset, getVisualLineCount(editor) - caretLine);
|
||||||
|
final int used = 1 + usedAbove + usedBelow;
|
||||||
if (used > height) {
|
if (used > height) {
|
||||||
scrollVisualLineToMiddleOfScreen(editor, caretLine);
|
scrollVisualLineToMiddleOfScreen(editor, caretLine);
|
||||||
}
|
}
|
||||||
@@ -1374,4 +1394,21 @@ public class MotionGroup {
|
|||||||
return moveCaretToLineEnd(editor, visualLineToLogicalLine(editor, line), allowPastEnd);
|
return moveCaretToLineEnd(editor, visualLineToLogicalLine(editor, line), allowPastEnd);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class ScrollOptionsChangeListener implements OptionChangeListener<String> {
|
||||||
|
public static ScrollOptionsChangeListener INSTANCE = new ScrollOptionsChangeListener();
|
||||||
|
|
||||||
|
@Contract(pure = true)
|
||||||
|
private ScrollOptionsChangeListener() {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void valueChange(String oldValue, String newValue) {
|
||||||
|
for (Editor editor : EditorFactory.getInstance().getAllEditors()) {
|
||||||
|
if (UserDataManager.getVimEditorGroup(editor)) {
|
||||||
|
MotionGroup.scrollCaretIntoView(editor);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -43,6 +43,12 @@ import static java.lang.Integer.max;
|
|||||||
* This is a set of helper methods for working with editors. All line and column values are zero based.
|
* This is a set of helper methods for working with editors. All line and column values are zero based.
|
||||||
*/
|
*/
|
||||||
public class EditorHelper {
|
public class EditorHelper {
|
||||||
|
// Set a max height on block inlays to be made visible at the top/bottom of a line when scrolling up/down. This
|
||||||
|
// mitigates the visible area bouncing around too much and even pushing the cursor line off screen with large
|
||||||
|
// multiline rendered doc comments, while still providing some visibility of the block inlay (e.g. Rider's single line
|
||||||
|
// Code Vision)
|
||||||
|
private static final int BLOCK_INLAY_MAX_LINE_HEIGHT = 3;
|
||||||
|
|
||||||
public static @NotNull Rectangle getVisibleArea(final @NotNull Editor editor) {
|
public static @NotNull Rectangle getVisibleArea(final @NotNull Editor editor) {
|
||||||
return editor.getScrollingModel().getVisibleAreaOnScrollingFinished();
|
return editor.getScrollingModel().getVisibleAreaOnScrollingFinished();
|
||||||
}
|
}
|
||||||
@@ -201,7 +207,7 @@ public class EditorHelper {
|
|||||||
* @param editor The editor
|
* @param editor The editor
|
||||||
* @return The number of screen lines
|
* @return The number of screen lines
|
||||||
*/
|
*/
|
||||||
private static int getApproximateScreenHeight(final @NotNull Editor editor) {
|
public static int getApproximateScreenHeight(final @NotNull Editor editor) {
|
||||||
return getVisibleArea(editor).height / editor.getLineHeight();
|
return getVisibleArea(editor).height / editor.getLineHeight();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -641,7 +647,10 @@ public class EditorHelper {
|
|||||||
* @return Returns true if the window was moved
|
* @return Returns true if the window was moved
|
||||||
*/
|
*/
|
||||||
public static boolean scrollVisualLineToTopOfScreen(final @NotNull Editor editor, int visualLine) {
|
public static boolean scrollVisualLineToTopOfScreen(final @NotNull Editor editor, int visualLine) {
|
||||||
int y = EditorUtil.getVisualLineAreaStartY(editor, normalizeVisualLine(editor, visualLine));
|
|
||||||
|
final int inlayHeight = EditorUtil.getInlaysHeight(editor, visualLine, true);
|
||||||
|
final int maxInlayHeight = BLOCK_INLAY_MAX_LINE_HEIGHT * editor.getLineHeight();
|
||||||
|
int y = editor.visualLineToY(visualLine) - Math.min(inlayHeight, maxInlayHeight);
|
||||||
|
|
||||||
// Normalise Y so that we don't try to scroll the editor to a location it can't reach. The editor will handle this,
|
// Normalise Y so that we don't try to scroll the editor to a location it can't reach. The editor will handle this,
|
||||||
// but when we ask for the target location to move the caret to match, we'll get the incorrect value.
|
// but when we ask for the target location to move the caret to match, we'll get the incorrect value.
|
||||||
@@ -653,7 +662,7 @@ public class EditorHelper {
|
|||||||
// Get the max line number that can sit at the top of the screen
|
// Get the max line number that can sit at the top of the screen
|
||||||
final int editorHeight = getVisibleArea(editor).height;
|
final int editorHeight = getVisibleArea(editor).height;
|
||||||
final int virtualSpaceHeight = editor.getSettings().getAdditionalLinesCount() * editor.getLineHeight();
|
final int virtualSpaceHeight = editor.getSettings().getAdditionalLinesCount() * editor.getLineHeight();
|
||||||
final int yLastLine = editor.visualLineToY(EditorHelper.getLineCount(editor)); // last line + 1
|
final int yLastLine = editor.visualLineToY(getLineCount(editor)); // last line + 1
|
||||||
y = Math.min(y, yLastLine + virtualSpaceHeight - editorHeight);
|
y = Math.min(y, yLastLine + virtualSpaceHeight - editorHeight);
|
||||||
}
|
}
|
||||||
return scrollVertically(editor, y);
|
return scrollVertically(editor, y);
|
||||||
@@ -662,21 +671,25 @@ public class EditorHelper {
|
|||||||
/**
|
/**
|
||||||
* Scrolls the editor to place the given visual line in the middle of the current window.
|
* Scrolls the editor to place the given visual line in the middle of the current window.
|
||||||
*
|
*
|
||||||
|
* <p>Snaps the line to the nearest standard line height grid, which gives a good position for both an odd and even
|
||||||
|
* number of lines and mimics what Vim does.</p>
|
||||||
|
*
|
||||||
* @param editor The editor to scroll
|
* @param editor The editor to scroll
|
||||||
* @param visualLine The visual line to place in the middle of the current window
|
* @param visualLine The visual line to place in the middle of the current window
|
||||||
*/
|
*/
|
||||||
public static void scrollVisualLineToMiddleOfScreen(@NotNull Editor editor, int visualLine) {
|
public static void scrollVisualLineToMiddleOfScreen(@NotNull Editor editor, int visualLine) {
|
||||||
int y = editor.visualLineToY(normalizeVisualLine(editor, visualLine));
|
final int y = editor.visualLineToY(normalizeVisualLine(editor, visualLine));
|
||||||
int lineHeight = editor.getLineHeight();
|
final int screenHeight = getVisibleArea(editor).height;
|
||||||
int height = getVisibleArea(editor).height;
|
final int lineHeight = editor.getLineHeight();
|
||||||
scrollVertically(editor, y - ((height - lineHeight) / 2));
|
scrollVertically(editor, y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Scrolls the editor to place the given visual line at the bottom of the screen.
|
* Scrolls the editor to place the given visual line at the bottom of the screen.
|
||||||
*
|
*
|
||||||
* When we're moving the caret down a few lines and want to scroll to keep this visible, we need to be able to place a
|
* <p>When we're moving the caret down a few lines and want to scroll to keep this visible, we need to be able to
|
||||||
* line at the bottom of the screen. Due to block inlays, we can't do this by specifying a top line to scroll to.
|
* place a line at the bottom of the screen. Due to block inlays, we can't do this by specifying a top line to scroll
|
||||||
|
* to.</p>
|
||||||
*
|
*
|
||||||
* @param editor The editor to scroll
|
* @param editor The editor to scroll
|
||||||
* @param visualLine The visual line to place at the bottom of the current window
|
* @param visualLine The visual line to place at the bottom of the current window
|
||||||
@@ -690,7 +703,12 @@ public class EditorHelper {
|
|||||||
if (ExEntryPanel.getInstanceWithoutShortcuts().isActive()) {
|
if (ExEntryPanel.getInstanceWithoutShortcuts().isActive()) {
|
||||||
exPanelHeight += ExEntryPanel.getInstanceWithoutShortcuts().getHeight();
|
exPanelHeight += ExEntryPanel.getInstanceWithoutShortcuts().getHeight();
|
||||||
}
|
}
|
||||||
final int y = EditorUtil.getVisualLineAreaEndY(editor, normalizeVisualLine(editor, visualLine)) + exPanelHeight;
|
|
||||||
|
final int normalizedVisualLine = normalizeVisualLine(editor, visualLine);
|
||||||
|
final int lineHeight = editor.getLineHeight();
|
||||||
|
final int inlayHeight = EditorUtil.getInlaysHeight(editor, normalizedVisualLine, false);
|
||||||
|
final int maxInlayHeight = BLOCK_INLAY_MAX_LINE_HEIGHT * lineHeight;
|
||||||
|
final int y = editor.visualLineToY(normalizedVisualLine) + lineHeight + Math.min(inlayHeight, maxInlayHeight) + exPanelHeight;
|
||||||
final Rectangle visibleArea = getVisibleArea(editor);
|
final Rectangle visibleArea = getVisibleArea(editor);
|
||||||
return scrollVertically(editor, max(0, y - visibleArea.height));
|
return scrollVertically(editor, max(0, y - visibleArea.height));
|
||||||
}
|
}
|
||||||
@@ -714,19 +732,19 @@ public class EditorHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x;
|
final int columnLeftX = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn)).x;
|
||||||
EditorHelper.scrollHorizontally(editor, columnLeftX);
|
scrollHorizontally(editor, columnLeftX);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
|
public static void scrollColumnToMiddleOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
|
||||||
final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn));
|
final Point point = editor.visualPositionToXY(new VisualPosition(visualLine, visualColumn));
|
||||||
final int screenWidth = EditorHelper.getVisibleArea(editor).width;
|
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
|
// 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
|
// 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?
|
// still a good solution. Besides, what kind of monster uses Vim with proportional fonts?
|
||||||
final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor);
|
final int standardColumnWidth = EditorUtil.getPlainSpaceWidth(editor);
|
||||||
final int x = point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth);
|
final int x = point.x - (screenWidth / standardColumnWidth / 2 * standardColumnWidth);
|
||||||
EditorHelper.scrollHorizontally(editor, x);
|
scrollHorizontally(editor, x);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void scrollColumnToRightOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
|
public static void scrollColumnToRightOfScreen(@NotNull Editor editor, int visualLine, int visualColumn) {
|
||||||
@@ -751,8 +769,8 @@ public class EditorHelper {
|
|||||||
|
|
||||||
// Scroll to the left edge of the target column, minus a screenwidth, and adjusted for inlays
|
// 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 = editor.visualPositionToXY(new VisualPosition(visualLine, targetVisualColumn + 1)).x;
|
||||||
final int screenWidth = EditorHelper.getVisibleArea(editor).width;
|
final int screenWidth = getVisibleArea(editor).width;
|
||||||
EditorHelper.scrollHorizontally(editor, targetColumnRightX - screenWidth);
|
scrollHorizontally(editor, targetColumnRightX - screenWidth);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -46,11 +46,11 @@ val Editor.isIdeaVimDisabledHere: Boolean
|
|||||||
val timeForCalculation = measureTimeMillis {
|
val timeForCalculation = measureTimeMillis {
|
||||||
res = (disabledInDialog.apply { times += System.currentTimeMillis() to "Disabled in dialog" }
|
res = (disabledInDialog.apply { times += System.currentTimeMillis() to "Disabled in dialog" }
|
||||||
|
|
||||||
|| (!OptionsManager.ideaenabledbufs.contains("singleline")
|
|| (!OptionsManager.ideavimsupport.contains("singleline")
|
||||||
.apply { times += System.currentTimeMillis() to "first single line check" }
|
.apply { times += System.currentTimeMillis() to "first single line check" }
|
||||||
&& isDatabaseCell(times).apply { times += System.currentTimeMillis() to "is db cell" })
|
&& isDatabaseCell(times).apply { times += System.currentTimeMillis() to "is db cell" })
|
||||||
|
|
||||||
|| (!OptionsManager.ideaenabledbufs.contains("singleline")
|
|| (!OptionsManager.ideavimsupport.contains("singleline")
|
||||||
.apply { times += System.currentTimeMillis() to "second single line check" }
|
.apply { times += System.currentTimeMillis() to "second single line check" }
|
||||||
&& isOneLineMode.apply { times += System.currentTimeMillis() to "is one line" })
|
&& isOneLineMode.apply { times += System.currentTimeMillis() to "is one line" })
|
||||||
)
|
)
|
||||||
@@ -68,7 +68,7 @@ private fun Editor.isDatabaseCell(times: MutableList<Pair<Long, String>>): Boole
|
|||||||
}
|
}
|
||||||
|
|
||||||
private val Editor.disabledInDialog: Boolean
|
private val Editor.disabledInDialog: Boolean
|
||||||
get() = (!OptionsManager.ideaenabledbufs.contains("dialog") && !OptionsManager.ideaenabledbufs.contains("dialoglegacy"))
|
get() = (!OptionsManager.ideavimsupport.contains("dialog") && !OptionsManager.ideavimsupport.contains("dialoglegacy"))
|
||||||
&& (!this.isPrimaryEditor() && !EditorHelper.isFileEditor(this))
|
&& (!this.isPrimaryEditor() && !EditorHelper.isFileEditor(this))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -786,7 +786,7 @@ public class SearchHelper {
|
|||||||
if (pos == size - 1 ||
|
if (pos == size - 1 ||
|
||||||
!Character.isLetter(chars.charAt(pos + 1)) ||
|
!Character.isLetter(chars.charAt(pos + 1)) ||
|
||||||
(Character.isUpperCase(chars.charAt(pos + 1)) &&
|
(Character.isUpperCase(chars.charAt(pos + 1)) &&
|
||||||
pos <= size - 2 &&
|
pos < size - 2 &&
|
||||||
Character.isLowerCase(chars.charAt(pos + 2)))) {
|
Character.isLowerCase(chars.charAt(pos + 2)))) {
|
||||||
res = pos;
|
res = pos;
|
||||||
found++;
|
found++;
|
||||||
@@ -1375,7 +1375,7 @@ public class SearchHelper {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (goForward && anyNonWhitespace(editor, end, 1)) {
|
if (goForward && anyNonWhitespace(editor, end, 1)) {
|
||||||
while (end < max &&
|
while (end + 1 < max &&
|
||||||
CharacterHelper.charType(chars.charAt(end + 1), false) == CharacterHelper.CharacterType.WHITESPACE) {
|
CharacterHelper.charType(chars.charAt(end + 1), false) == CharacterHelper.CharacterType.WHITESPACE) {
|
||||||
end++;
|
end++;
|
||||||
}
|
}
|
||||||
|
@@ -106,6 +106,7 @@ object VimListenerManager {
|
|||||||
|
|
||||||
OptionsManager.number.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
OptionsManager.number.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
||||||
OptionsManager.relativenumber.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
OptionsManager.relativenumber.addOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
||||||
|
OptionsManager.scrolloff.addOptionChangeListener(MotionGroup.ScrollOptionsChangeListener.INSTANCE)
|
||||||
OptionsManager.showcmd.addOptionChangeListener(ShowCmdOptionChangeListener)
|
OptionsManager.showcmd.addOptionChangeListener(ShowCmdOptionChangeListener)
|
||||||
|
|
||||||
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance())
|
EventFacade.getInstance().addEditorFactoryListener(VimEditorFactoryListener, VimPlugin.getInstance())
|
||||||
@@ -116,6 +117,7 @@ object VimListenerManager {
|
|||||||
|
|
||||||
OptionsManager.number.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
OptionsManager.number.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
||||||
OptionsManager.relativenumber.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
OptionsManager.relativenumber.removeOptionChangeListener(EditorGroup.NumberChangeListener.INSTANCE)
|
||||||
|
OptionsManager.scrolloff.removeOptionChangeListener(MotionGroup.ScrollOptionsChangeListener.INSTANCE)
|
||||||
OptionsManager.showcmd.removeOptionChangeListener(ShowCmdOptionChangeListener)
|
OptionsManager.showcmd.removeOptionChangeListener(ShowCmdOptionChangeListener)
|
||||||
|
|
||||||
EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener)
|
EventFacade.getInstance().removeEditorFactoryListener(VimEditorFactoryListener)
|
||||||
|
@@ -88,7 +88,7 @@ object OptionsManager {
|
|||||||
val ideastatusicon = addOption(BoundStringOption(IdeaStatusIcon.name, IdeaStatusIcon.name, IdeaStatusIcon.enabled, IdeaStatusIcon.allValues))
|
val ideastatusicon = addOption(BoundStringOption(IdeaStatusIcon.name, IdeaStatusIcon.name, IdeaStatusIcon.enabled, IdeaStatusIcon.allValues))
|
||||||
val ideastrictmode = addOption(ToggleOption("ideastrictmode", "ideastrictmode", false))
|
val ideastrictmode = addOption(ToggleOption("ideastrictmode", "ideastrictmode", false))
|
||||||
val ideawrite = addOption(BoundStringOption("ideawrite", "ideawrite", IdeaWriteData.all, IdeaWriteData.allValues))
|
val ideawrite = addOption(BoundStringOption("ideawrite", "ideawrite", IdeaWriteData.all, IdeaWriteData.allValues))
|
||||||
val ideaenabledbufs = addOption(BoundListOption("ideaenabledbufs", "ideaenabledbufs", arrayOf("dialog"), arrayOf("dialog", "singleline", "dialoglegacy")))
|
val ideavimsupport = addOption(BoundListOption("ideavimsupport", "ideavimsupport", arrayOf("dialog"), arrayOf("dialog", "singleline", "dialoglegacy")))
|
||||||
|
|
||||||
fun isSet(name: String): Boolean {
|
fun isSet(name: String): Boolean {
|
||||||
val option = getOption(name)
|
val option = getOption(name)
|
||||||
|
@@ -62,7 +62,7 @@
|
|||||||
* |i_CTRL-Z| TO BE IMPLEMENTED
|
* |i_CTRL-Z| TO BE IMPLEMENTED
|
||||||
* |i_<Esc>| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
* |i_<Esc>| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
||||||
* |i_CTRL-[| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
* |i_CTRL-[| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
||||||
* |i_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.change.insert.InsertExitModeAction}
|
* |i_CTRL-\_CTRL-N| {@link com.maddyhome.idea.vim.action.ResetModeAction}
|
||||||
* |i_CTRL-\_CTRL-G| TO BE IMPLEMENTED
|
* |i_CTRL-\_CTRL-G| TO BE IMPLEMENTED
|
||||||
* |i_CTRL-]} TO BE IMPLEMENTED
|
* |i_CTRL-]} TO BE IMPLEMENTED
|
||||||
* |i_CTRL-^| TO BE IMPLEMENTED
|
* |i_CTRL-^| TO BE IMPLEMENTED
|
||||||
|
@@ -1,6 +1,6 @@
|
|||||||
# Manual Tests
|
# Manual Tests
|
||||||
|
|
||||||
## #1 [Last run: 2020-10-09]
|
## #1 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Initial mode:_ NORMAL
|
_Initial mode:_ NORMAL
|
||||||
|
|
||||||
@@ -14,7 +14,7 @@ Word is selected, block-caret is placed on the word end (offset = `word end - 1`
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
## #2 [Last run: 2020-10-09]
|
## #2 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Initial mode:_ NORMAL
|
_Initial mode:_ NORMAL
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ Last word is selected, block caret is placed on the word end without bouncing
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## #3 [Last run: 2020-10-09]
|
## #3 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Initial mode:_ NORMAL
|
_Initial mode:_ NORMAL
|
||||||
|
|
||||||
@@ -38,7 +38,7 @@ Line is selected. Caret is placed on the line end
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## #4 [Last run: 2020-10-09]
|
## #4 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Initial mode:_ NORMAL
|
_Initial mode:_ NORMAL
|
||||||
|
|
||||||
@@ -51,7 +51,7 @@ After mouse release, caret moves one character back and becomes block shape
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## #5 [Last run: 2020-10-09]
|
## #5 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Initial mode:_ NORMAL
|
_Initial mode:_ NORMAL
|
||||||
|
|
||||||
@@ -65,7 +65,7 @@ After mouse release, caret moves one character back and becomes block shape
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## #6 [Last run: 2020-10-09]
|
## #6 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Initial mode:_ NORMAL
|
_Initial mode:_ NORMAL
|
||||||
|
|
||||||
@@ -77,7 +77,7 @@ Line is selected, caret is on the first position
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
## #6 [Last run: 2020-10-09]
|
## #6 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Initial mode:_ NORMAL
|
_Initial mode:_ NORMAL
|
||||||
|
|
||||||
@@ -94,7 +94,7 @@ Caret stays in _block_ shape with a normal mode
|
|||||||

|

|
||||||
|
|
||||||
|
|
||||||
## #7 [Last run: 2020-10-09]
|
## #7 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Action:_
|
_Action:_
|
||||||
Turn emulation off and on
|
Turn emulation off and on
|
||||||
@@ -102,7 +102,7 @@ Turn emulation off and on
|
|||||||
_Result:_
|
_Result:_
|
||||||
Vim emulator works as expected
|
Vim emulator works as expected
|
||||||
|
|
||||||
## #8 [Last run: 2020-10-09
|
## #8 [Last run: 2020-11-12
|
||||||
|
|
||||||
_Action:_
|
_Action:_
|
||||||
Start up IJ with disabled emulator, turn it on
|
Start up IJ with disabled emulator, turn it on
|
||||||
@@ -110,7 +110,7 @@ Start up IJ with disabled emulator, turn it on
|
|||||||
_Result:_
|
_Result:_
|
||||||
Vim emulator works as expected
|
Vim emulator works as expected
|
||||||
|
|
||||||
## #9 [Last run: 2020-10-09]
|
## #9 [Last run: 2020-11-12]
|
||||||
|
|
||||||
_Action:_
|
_Action:_
|
||||||
Wrap with if
|
Wrap with if
|
||||||
|
@@ -180,26 +180,30 @@ abstract class VimTestCase : UsefulTestCase() {
|
|||||||
|
|
||||||
@JvmOverloads
|
@JvmOverloads
|
||||||
protected fun setPositionAndScroll(scrollToLogicalLine: Int, caretLogicalLine: Int, caretLogicalColumn: Int = 0) {
|
protected fun setPositionAndScroll(scrollToLogicalLine: Int, caretLogicalLine: Int, caretLogicalColumn: Int = 0) {
|
||||||
val scrolloff = min(OptionsManager.scrolloff.value(), screenHeight / 2)
|
|
||||||
|
// Note that it is possible to request a position which would be invalid under normal Vim!
|
||||||
|
// We disable scrolloff + scrolljump, position as requested, and reset. When resetting scrolloff, Vim will
|
||||||
|
// recalculate the correct offsets, and that could move the top and/or caret line
|
||||||
|
val scrolloff = OptionsManager.scrolloff.value()
|
||||||
val scrolljump = OptionsManager.scrolljump.value()
|
val scrolljump = OptionsManager.scrolljump.value()
|
||||||
|
OptionsManager.scrolloff.set(0)
|
||||||
OptionsManager.scrolljump.set(1)
|
OptionsManager.scrolljump.set(1)
|
||||||
|
|
||||||
// Convert to visual lines to handle any collapsed folds
|
// Convert to visual lines to handle any collapsed folds
|
||||||
val scrollToVisualLine = EditorHelper.logicalLineToVisualLine(myFixture.editor, scrollToLogicalLine)
|
val scrollToVisualLine = EditorHelper.logicalLineToVisualLine(myFixture.editor, scrollToLogicalLine)
|
||||||
val bottomVisualLine = scrollToVisualLine + screenHeight - 1
|
val bottomVisualLine = scrollToVisualLine + EditorHelper.getApproximateScreenHeight(myFixture.editor) - 1
|
||||||
val bottomLogicalLine = EditorHelper.visualLineToLogicalLine(myFixture.editor, bottomVisualLine)
|
val bottomLogicalLine = EditorHelper.visualLineToLogicalLine(myFixture.editor, bottomVisualLine)
|
||||||
|
|
||||||
// Make sure we're not trying to put caret in an invalid location
|
// Make sure we're not trying to put caret in an invalid location
|
||||||
val boundsTop = EditorHelper.visualLineToLogicalLine(myFixture.editor,
|
val boundsTop = EditorHelper.visualLineToLogicalLine(myFixture.editor, scrollToVisualLine)
|
||||||
if (scrollToVisualLine > scrolloff) scrollToVisualLine + scrolloff else scrollToVisualLine)
|
val boundsBottom = EditorHelper.visualLineToLogicalLine(myFixture.editor, bottomVisualLine)
|
||||||
val boundsBottom = EditorHelper.visualLineToLogicalLine(myFixture.editor,
|
|
||||||
if (bottomVisualLine > EditorHelper.getVisualLineCount(myFixture.editor) - scrolloff - 1) bottomVisualLine - scrolloff else bottomVisualLine)
|
|
||||||
Assert.assertTrue("Caret line $caretLogicalLine not inside legal screen bounds (${boundsTop} - ${boundsBottom})",
|
Assert.assertTrue("Caret line $caretLogicalLine not inside legal screen bounds (${boundsTop} - ${boundsBottom})",
|
||||||
caretLogicalLine in boundsTop..boundsBottom)
|
caretLogicalLine in boundsTop..boundsBottom)
|
||||||
|
|
||||||
typeText(parseKeys("${scrollToLogicalLine+scrolloff+1}z<CR>", "${caretLogicalLine+1}G", "${caretLogicalColumn+1}|"))
|
typeText(parseKeys("${scrollToLogicalLine+1}z<CR>", "${caretLogicalLine+1}G", "${caretLogicalColumn+1}|"))
|
||||||
|
|
||||||
OptionsManager.scrolljump.set(scrolljump)
|
OptionsManager.scrolljump.set(scrolljump)
|
||||||
|
OptionsManager.scrolloff.set(scrolloff)
|
||||||
|
|
||||||
// Make sure we're where we want to be
|
// Make sure we're where we want to be
|
||||||
assertVisibleArea(scrollToLogicalLine, bottomLogicalLine)
|
assertVisibleArea(scrollToLogicalLine, bottomLogicalLine)
|
||||||
|
@@ -25,6 +25,7 @@ import static com.maddyhome.idea.vim.helper.StringHelper.parseKeys;
|
|||||||
public class ReformatCodeTest extends VimTestCase {
|
public class ReformatCodeTest extends VimTestCase {
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
[VERSION UPDATE] 2020.2+
|
||||||
public void testEmpty() {
|
public void testEmpty() {
|
||||||
configureByJavaText("<caret>");
|
configureByJavaText("<caret>");
|
||||||
typeText(parseKeys("gqq"));
|
typeText(parseKeys("gqq"));
|
||||||
|
@@ -47,6 +47,22 @@ class ResetModeActionTest : VimTestCase() {
|
|||||||
TestCase.assertFalse(myFixture.editor.selectionModel.hasSelection())
|
TestCase.assertFalse(myFixture.editor.selectionModel.hasSelection())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun `test reset from insert mode check position`() {
|
||||||
|
val keys = listOf("i", "<C-\\><C-N>")
|
||||||
|
val before = "A Disc${c}overy"
|
||||||
|
val after = "A Dis${c}covery"
|
||||||
|
doTest(keys, before, after, CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
|
||||||
|
TestCase.assertFalse(myFixture.editor.selectionModel.hasSelection())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test reset and execute command`() {
|
||||||
|
val keys = listOf("i", "<C-\\><C-N>", "3l")
|
||||||
|
val before = "${c}A Discovery"
|
||||||
|
val after = "A D${c}iscovery"
|
||||||
|
doTest(keys, before, after, CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
|
||||||
|
TestCase.assertFalse(myFixture.editor.selectionModel.hasSelection())
|
||||||
|
}
|
||||||
|
|
||||||
fun `test reset from visual mode`() {
|
fun `test reset from visual mode`() {
|
||||||
val keys = listOf("V", "<C-\\><C-N>")
|
val keys = listOf("V", "<C-\\><C-N>")
|
||||||
val before = "A Discovery"
|
val before = "A Discovery"
|
||||||
|
@@ -26,7 +26,8 @@ import org.jetbrains.plugins.ideavim.VimTestCase
|
|||||||
class MotionOuterBigWordActionTest : VimTestCase() {
|
class MotionOuterBigWordActionTest : VimTestCase() {
|
||||||
@TestWithoutNeovim(SkipNeovimReason.UNCLEAR, description = "Wrong caret position, but in real neovim works fine")
|
@TestWithoutNeovim(SkipNeovimReason.UNCLEAR, description = "Wrong caret position, but in real neovim works fine")
|
||||||
fun `test on last dot`() {
|
fun `test on last dot`() {
|
||||||
doTest("<aW", """
|
doTest(
|
||||||
|
"<aW", """
|
||||||
I found it in a legendary land
|
I found it in a legendary land
|
||||||
all rocks and lavender and tufted grass,
|
all rocks and lavender and tufted grass,
|
||||||
where it was settled on some sodden sand
|
where it was settled on some sodden sand
|
||||||
@@ -36,6 +37,19 @@ class MotionOuterBigWordActionTest : VimTestCase() {
|
|||||||
all rocks and lavender and tufted grass,
|
all rocks and lavender and tufted grass,
|
||||||
where it was settled on some sodden sand
|
where it was settled on some sodden sand
|
||||||
${c}hard by the torrent of a mountain pass.
|
${c}hard by the torrent of a mountain pass.
|
||||||
""".trimIndent(), CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
|
""".trimIndent(), CommandState.Mode.COMMAND, CommandState.SubMode.NONE
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun `test past end in visual`() {
|
||||||
|
doTest(
|
||||||
|
"v\$aW", """
|
||||||
|
I found it in a ${c}legendary land
|
||||||
|
}
|
||||||
|
""".trimIndent(), """
|
||||||
|
I found it in a ${s}legendary land
|
||||||
|
${c}}${se}
|
||||||
|
""".trimIndent(), CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_CHARACTER
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||||
|
* Copyright (C) 2003-2020 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.plugins.ideavim.action.motion.text
|
||||||
|
|
||||||
|
import com.maddyhome.idea.vim.command.CommandState
|
||||||
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
|
|
||||||
|
class MotionCamelEndLeftActionTest : VimTestCase() {
|
||||||
|
fun `test go with a single uppercase word`() {
|
||||||
|
doTest("]b", "TES${c}T", "TES${c}T", CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
|
||||||
|
}
|
||||||
|
}
|
@@ -0,0 +1,28 @@
|
|||||||
|
/*
|
||||||
|
* IdeaVim - Vim emulator for IDEs based on the IntelliJ platform
|
||||||
|
* Copyright (C) 2003-2020 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* This program is free software: you can redistribute it and/or modify
|
||||||
|
* it under the terms of the GNU General Public License as published by
|
||||||
|
* the Free Software Foundation, either version 2 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* This program is distributed in the hope that it will be useful,
|
||||||
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
* GNU General Public License for more details.
|
||||||
|
*
|
||||||
|
* You should have received a copy of the GNU General Public License
|
||||||
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.plugins.ideavim.action.motion.visual
|
||||||
|
|
||||||
|
import com.maddyhome.idea.vim.command.CommandState
|
||||||
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
|
|
||||||
|
class VisualExitModeAction : VimTestCase() {
|
||||||
|
fun `test exit visual mode after line end`() {
|
||||||
|
doTest("vl<Esc>", "12${c}3", "12${c}3", CommandState.Mode.COMMAND, CommandState.SubMode.NONE)
|
||||||
|
}
|
||||||
|
}
|
@@ -90,6 +90,7 @@ class VisualToggleBlockModeActionTest : VimTestCase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
[VERSION UPDATE] 2020.2+
|
||||||
fun `test on empty file`() {
|
fun `test on empty file`() {
|
||||||
doTest("<C-V>", "", "",
|
doTest("<C-V>", "", "",
|
||||||
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_BLOCK)
|
CommandState.Mode.VISUAL, CommandState.SubMode.VISUAL_BLOCK)
|
||||||
|
@@ -21,6 +21,8 @@
|
|||||||
package org.jetbrains.plugins.ideavim.group.motion
|
package org.jetbrains.plugins.ideavim.group.motion
|
||||||
|
|
||||||
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
|
import com.maddyhome.idea.vim.helper.StringHelper.parseKeys
|
||||||
|
import com.maddyhome.idea.vim.helper.VimBehaviorDiffers
|
||||||
|
import com.maddyhome.idea.vim.option.OptionsManager
|
||||||
import com.maddyhome.idea.vim.option.ScrollJumpData
|
import com.maddyhome.idea.vim.option.ScrollJumpData
|
||||||
import com.maddyhome.idea.vim.option.ScrollOffData
|
import com.maddyhome.idea.vim.option.ScrollOffData
|
||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
||||||
@@ -63,6 +65,119 @@ class MotionGroup_scrolloff_Test : VimOptionTestCase(ScrollOffData.name) {
|
|||||||
assertVisibleArea(24, 58)
|
assertVisibleArea(24, 58)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["15"]))
|
||||||
|
fun `test move up when scrolloff is slightly less than half screen height`() {
|
||||||
|
// Screen height = 35. scrolloff=15. This gives 5 possible caret lines without scrolling (48, 49, 50, 51 + 52)
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(33, 52)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(51, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(50, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(49, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(48, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(47, 0)
|
||||||
|
assertVisibleArea(32, 66)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["16"]))
|
||||||
|
fun `test move up when scrolloff is slightly less than half screen height 2`() {
|
||||||
|
// Screen height = 35. scrolloff=16. This gives 3 possible caret lines without scrolling (49, 50 + 51)
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(33, 51)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(50, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(49, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(48, 0)
|
||||||
|
assertVisibleArea(32, 66)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["16"]))
|
||||||
|
fun `test move up when scrolloff is slightly less than half screen height 3`() {
|
||||||
|
// Screen height = 34. scrolloff=16
|
||||||
|
// Even numbers. 2 possible caret lines without scrolling (49 + 50)
|
||||||
|
configureByPages(5)
|
||||||
|
setEditorVisibleSize(screenWidth, 34)
|
||||||
|
setPositionAndScroll(33, 50)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(49, 0)
|
||||||
|
assertVisibleArea(33, 66)
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(48, 0)
|
||||||
|
assertVisibleArea(32, 65)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["17"]))
|
||||||
|
@VimBehaviorDiffers(description = "Moving up in Vim will always have 16 lines above the caret line. IdeaVim keeps 17")
|
||||||
|
fun `test move up when scrolloff is exactly screen height`() {
|
||||||
|
// Page height = 34. scrolloff=17
|
||||||
|
// 2 possible caret lines without scrolling (49 + 50)
|
||||||
|
configureByPages(5)
|
||||||
|
setEditorVisibleSize(screenWidth, 34)
|
||||||
|
setPositionAndScroll(33, 50)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(49, 0)
|
||||||
|
assertVisibleArea(33, 66)
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(48, 0)
|
||||||
|
assertVisibleArea(32, 65)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["17"]))
|
||||||
|
fun `test move up when scrolloff is slightly greater than screen height keeps cursor in centre of screen`() {
|
||||||
|
// Page height = 35. scrolloff=17
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(33, 50)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(49, 0)
|
||||||
|
assertVisibleArea(32, 66)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["22"]))
|
||||||
|
fun `test move up when scrolloff is slightly greater than screen height keeps cursor in centre of screen 2`() {
|
||||||
|
// Page height = 35. scrolloff=17
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(33, 50)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(49, 0)
|
||||||
|
assertVisibleArea(32, 66)
|
||||||
|
}
|
||||||
|
|
||||||
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["0"]))
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["0"]))
|
||||||
fun `test move down shows no context with scrolloff=0`() {
|
fun `test move down shows no context with scrolloff=0`() {
|
||||||
@@ -93,14 +208,159 @@ class MotionGroup_scrolloff_Test : VimOptionTestCase(ScrollOffData.name) {
|
|||||||
assertVisibleArea(26, 60)
|
assertVisibleArea(26, 60)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["15"]))
|
||||||
|
fun `test move down when scrolloff is slightly less than half screen height`() {
|
||||||
|
// Screen height = 35. scrolloff=15. This gives 5 possible caret lines without scrolling (48, 49, 50, 51 + 52)
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(33, 48)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(49, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(50, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(51, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(52, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(53, 0)
|
||||||
|
assertVisibleArea(34, 68)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["16"]))
|
||||||
|
fun `test move down when scrolloff is slightly less than half screen height 2`() {
|
||||||
|
// Screen height = 35. scrolloff=16. This gives 3 possible caret lines without scrolling (49, 50 + 51)
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(33, 49)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(50, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(51, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(52, 0)
|
||||||
|
assertVisibleArea(34, 68)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["16"]))
|
||||||
|
fun `test move down when scrolloff is slightly less than half screen height 3`() {
|
||||||
|
// Screen height = 34. scrolloff=16
|
||||||
|
// Even numbers. 2 possible caret lines without scrolling (49 + 50)
|
||||||
|
configureByPages(5)
|
||||||
|
setEditorVisibleSize(screenWidth, 34)
|
||||||
|
setPositionAndScroll(33, 49)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(50, 0)
|
||||||
|
assertVisibleArea(33, 66)
|
||||||
|
|
||||||
|
// Scroll
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(51, 0)
|
||||||
|
assertVisibleArea(34, 67)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["17"]))
|
||||||
|
fun `test move down when scrolloff is exactly screen height`() {
|
||||||
|
// Page height = 34. scrolloff=17
|
||||||
|
// 2 possible caret lines without scrolling (49 + 50), but moving to line 51 will scroll 2 lines!
|
||||||
|
configureByPages(5)
|
||||||
|
setEditorVisibleSize(screenWidth, 34)
|
||||||
|
setPositionAndScroll(33, 49)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(50, 0)
|
||||||
|
assertVisibleArea(33, 66)
|
||||||
|
|
||||||
|
// Scroll. By 2 lines!
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(51, 0)
|
||||||
|
assertVisibleArea(35, 68)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["17"]))
|
||||||
|
fun `test move down when scrolloff is slightly greater than half screen height keeps cursor in centre of screen`() {
|
||||||
|
// Page height = 35. scrolloff=17
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(33, 50)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(51, 0)
|
||||||
|
assertVisibleArea(34, 68)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["22"]))
|
||||||
|
fun `test move down when scrolloff is slightly greater than half screen height keeps cursor in centre of screen 2`() {
|
||||||
|
// Page height = 35. scrolloff=17
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(33, 50)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(51, 0)
|
||||||
|
assertVisibleArea(34, 68)
|
||||||
|
}
|
||||||
|
|
||||||
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["999"]))
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["999"]))
|
||||||
fun `test scrolloff=999 keeps cursor in centre of screen`() {
|
fun `test scrolloff=999 keeps cursor in centre of screen`() {
|
||||||
configureByPages(5)
|
configureByPages(5)
|
||||||
setPositionAndScroll(25, 42)
|
setPositionAndScroll(25, 42)
|
||||||
|
|
||||||
typeText(parseKeys("j"))
|
typeText(parseKeys("j"))
|
||||||
assertPosition(43, 0)
|
assertPosition(43, 0)
|
||||||
assertVisibleArea(26, 60)
|
assertVisibleArea(26, 60)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(42, 0)
|
||||||
|
assertVisibleArea(25, 59)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["999"]))
|
||||||
|
fun `test scrolloff=999 keeps cursor in centre of screen with even screen height`() {
|
||||||
|
configureByPages(5)
|
||||||
|
setEditorVisibleSize(screenWidth, 34)
|
||||||
|
setPositionAndScroll(26, 42)
|
||||||
|
|
||||||
|
typeText(parseKeys("j"))
|
||||||
|
assertPosition(43, 0)
|
||||||
|
assertVisibleArea(27, 60)
|
||||||
|
|
||||||
|
typeText(parseKeys("k"))
|
||||||
|
assertPosition(42, 0)
|
||||||
|
assertVisibleArea(26, 59)
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestWithoutNeovim(SkipNeovimReason.OPTION)
|
||||||
|
@VimOptionTestConfiguration(VimTestOption(ScrollOffData.name, VimTestOptionType.NUMBER, ["0"]))
|
||||||
|
fun `test reposition cursor when scrolloff is set`() {
|
||||||
|
configureByPages(5)
|
||||||
|
setPositionAndScroll(50, 50)
|
||||||
|
|
||||||
|
OptionsManager.scrolloff.set(999)
|
||||||
|
|
||||||
|
assertPosition(50, 0)
|
||||||
|
assertVisibleArea(33, 67)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -116,5 +116,8 @@ private val stinkyKeysList = arrayListOf("K", "u", "H", "<C-Y>",
|
|||||||
// Temporally disabled due to issues in the platform
|
// Temporally disabled due to issues in the platform
|
||||||
"<C-V>", "<C-Q>",
|
"<C-V>", "<C-Q>",
|
||||||
|
|
||||||
"<C-]>"
|
"<C-]>",
|
||||||
|
|
||||||
|
// Next / previous method fails because of vfs sync
|
||||||
|
"]"
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user