mirror of
https://github.com/chylex/IntelliJ-IdeaVim.git
synced 2025-09-18 07:24:48 +02:00
Compare commits
60 Commits
54c16c97b9
...
customized
Author | SHA1 | Date | |
---|---|---|---|
8de7a9f741
|
|||
5977840cef
|
|||
d0fea229c4
|
|||
9eeac4a788
|
|||
8370661b0d
|
|||
3f88e64abf
|
|||
28e3a7c894
|
|||
bc859c65f5
|
|||
141fc8ed22
|
|||
dec494639c
|
|||
d06688033b
|
|||
98110b9132
|
|||
a0404b8664
|
|||
a2a30d545e
|
|||
4f3bf039c9
|
|||
1f4b97fa00
|
|||
61301fdbf5
|
|||
c980250529
|
|||
bdb4b02016
|
|||
62039a00d3
|
|||
95c66fd4a6
|
|||
![]() |
fb9bfbaeeb | ||
![]() |
09668f4fcb | ||
![]() |
4c7a6165ed | ||
![]() |
12d0d2613f | ||
![]() |
42ee78cd3d | ||
![]() |
58d308c1ed | ||
![]() |
29e1bcc53d | ||
![]() |
3531574e5e | ||
![]() |
b9721218ab | ||
![]() |
a119ea6a29 | ||
![]() |
95ef5f5f32 | ||
![]() |
b81b18645b | ||
![]() |
ce591f1b43 | ||
![]() |
28afa4b3ce | ||
![]() |
89a24d71a6 | ||
f69630b668 | |||
![]() |
a2d34a883b | ||
![]() |
5c79b887d8 | ||
![]() |
d0475bf659 | ||
![]() |
85c9576699 | ||
![]() |
2483450a1f | ||
![]() |
519d5eed06 | ||
![]() |
d87965775a | ||
![]() |
8c6f81aa00 | ||
![]() |
6ea0ab0968 | ||
![]() |
70ab3ecdbe | ||
![]() |
a24ae616df | ||
![]() |
cc838f614f | ||
![]() |
ae62a9f378 | ||
![]() |
1b5778a58c | ||
![]() |
27a689e7b8 | ||
![]() |
8e6c490c62 | ||
![]() |
ccda70fe53 | ||
![]() |
26c42e4f0d | ||
![]() |
3244dd52eb | ||
![]() |
4c6807a0c2 | ||
![]() |
03a6a2749a | ||
![]() |
82f69456e9 | ||
![]() |
6beda371fb |
1
.gitattributes
vendored
Normal file
1
.gitattributes
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
* text=auto eol=lf
|
10
.github/workflows/runUiOctopusTests.yml
vendored
10
.github/workflows/runUiOctopusTests.yml
vendored
@@ -11,12 +11,12 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
- name: Apply Patch
|
- name: Apply Patch
|
||||||
run: |
|
run: |
|
||||||
git apply src/test/java/ui/octopus.patch
|
git apply tests/ui-ij-tests/src/test/kotlin/ui/octopus.patch
|
||||||
- name: Setup Java
|
- name: Setup Java
|
||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: zulu
|
distribution: zulu
|
||||||
java-version: 11
|
java-version: 17
|
||||||
- name: Setup FFmpeg
|
- name: Setup FFmpeg
|
||||||
uses: FedericoCarboni/setup-ffmpeg@v3
|
uses: FedericoCarboni/setup-ffmpeg@v3
|
||||||
with:
|
with:
|
||||||
@@ -30,7 +30,7 @@ jobs:
|
|||||||
- name: Run Idea
|
- name: Run Idea
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build/reports
|
mkdir -p build/reports
|
||||||
gradle :runIdeForUiTests > build/reports/idea.log &
|
gradle runIdeForUiTests > build/reports/idea.log &
|
||||||
- name: Wait for Idea started
|
- name: Wait for Idea started
|
||||||
uses: jtalk/url-health-check-action@v3
|
uses: jtalk/url-health-check-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -38,10 +38,10 @@ jobs:
|
|||||||
max-attempts: 20
|
max-attempts: 20
|
||||||
retry-delay: 10s
|
retry-delay: 10s
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: gradle :testUi
|
run: gradle :tests:ui-ij-tests:testUi
|
||||||
- name: Move video
|
- name: Move video
|
||||||
if: always()
|
if: always()
|
||||||
run: mv video build/reports
|
run: mv tests/ui-ij-tests/video build/reports
|
||||||
- name: Move sandbox logs
|
- name: Move sandbox logs
|
||||||
if: always()
|
if: always()
|
||||||
run: mv build/idea-sandbox/system/log sandbox-idea-log
|
run: mv build/idea-sandbox/system/log sandbox-idea-log
|
||||||
|
55
.github/workflows/runUiPyTests.yml
vendored
Normal file
55
.github/workflows/runUiPyTests.yml
vendored
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
name: Run UI PyCharm Tests
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 12 * * *'
|
||||||
|
jobs:
|
||||||
|
build-for-ui-test-mac-os:
|
||||||
|
if: github.repository == 'JetBrains/ideavim'
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Setup Java
|
||||||
|
uses: actions/setup-java@v4
|
||||||
|
with:
|
||||||
|
distribution: zulu
|
||||||
|
java-version: 17
|
||||||
|
- uses: actions/setup-python@v5
|
||||||
|
with:
|
||||||
|
python-version: '3.10'
|
||||||
|
- name: Setup FFmpeg
|
||||||
|
uses: FedericoCarboni/setup-ffmpeg@v3
|
||||||
|
with:
|
||||||
|
# Not strictly necessary, but it may prevent rate limit
|
||||||
|
# errors especially on GitHub-hosted macos machines.
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
- name: Setup Gradle
|
||||||
|
uses: gradle/gradle-build-action@v2.4.2
|
||||||
|
- name: Build Plugin
|
||||||
|
run: gradle :buildPlugin
|
||||||
|
- name: Run Idea
|
||||||
|
run: |
|
||||||
|
mkdir -p build/reports
|
||||||
|
gradle :runIdeForUiTests -PideaType=PC > build/reports/idea.log &
|
||||||
|
- name: Wait for Idea started
|
||||||
|
uses: jtalk/url-health-check-action@v3
|
||||||
|
with:
|
||||||
|
url: http://127.0.0.1:8082
|
||||||
|
max-attempts: 20
|
||||||
|
retry-delay: 10s
|
||||||
|
- name: Tests
|
||||||
|
run: gradle :tests:ui-py-tests:testUi
|
||||||
|
- name: Move video
|
||||||
|
if: always()
|
||||||
|
run: mv tests/ui-py-tests/video build/reports
|
||||||
|
- name: Move sandbox logs
|
||||||
|
if: always()
|
||||||
|
run: mv build/idea-sandbox/system/log sandbox-idea-log
|
||||||
|
- name: Save report
|
||||||
|
if: always()
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: ui-test-fails-report-mac
|
||||||
|
path: |
|
||||||
|
build/reports
|
||||||
|
sandbox-idea-log
|
8
.github/workflows/runUiTests.yml
vendored
8
.github/workflows/runUiTests.yml
vendored
@@ -13,7 +13,7 @@ jobs:
|
|||||||
uses: actions/setup-java@v4
|
uses: actions/setup-java@v4
|
||||||
with:
|
with:
|
||||||
distribution: zulu
|
distribution: zulu
|
||||||
java-version: 11
|
java-version: 17
|
||||||
- name: Setup FFmpeg
|
- name: Setup FFmpeg
|
||||||
uses: FedericoCarboni/setup-ffmpeg@v3
|
uses: FedericoCarboni/setup-ffmpeg@v3
|
||||||
with:
|
with:
|
||||||
@@ -27,7 +27,7 @@ jobs:
|
|||||||
- name: Run Idea
|
- name: Run Idea
|
||||||
run: |
|
run: |
|
||||||
mkdir -p build/reports
|
mkdir -p build/reports
|
||||||
gradle :runIdeForUiTests > build/reports/idea.log &
|
gradle runIdeForUiTests > build/reports/idea.log &
|
||||||
- name: Wait for Idea started
|
- name: Wait for Idea started
|
||||||
uses: jtalk/url-health-check-action@v3
|
uses: jtalk/url-health-check-action@v3
|
||||||
with:
|
with:
|
||||||
@@ -35,10 +35,10 @@ jobs:
|
|||||||
max-attempts: 20
|
max-attempts: 20
|
||||||
retry-delay: 10s
|
retry-delay: 10s
|
||||||
- name: Tests
|
- name: Tests
|
||||||
run: gradle :testUi
|
run: gradle :tests:ui-ij-tests:testUi
|
||||||
- name: Move video
|
- name: Move video
|
||||||
if: always()
|
if: always()
|
||||||
run: mv video build/reports
|
run: mv tests/ui-ij-tests/video build/reports
|
||||||
- name: Move sandbox logs
|
- name: Move sandbox logs
|
||||||
if: always()
|
if: always()
|
||||||
run: mv build/idea-sandbox/system/log sandbox-idea-log
|
run: mv build/idea-sandbox/system/log sandbox-idea-log
|
||||||
|
1
.idea/codeStyles/Project.xml
generated
1
.idea/codeStyles/Project.xml
generated
@@ -6,6 +6,7 @@
|
|||||||
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
<option name="CONTINUATION_INDENT_SIZE" value="4" />
|
||||||
</value>
|
</value>
|
||||||
</option>
|
</option>
|
||||||
|
<option name="LINE_SEPARATOR" value=" " />
|
||||||
<JavaCodeStyleSettings>
|
<JavaCodeStyleSettings>
|
||||||
<option name="FIELD_NAME_PREFIX" value="my" />
|
<option name="FIELD_NAME_PREFIX" value="my" />
|
||||||
<option name="STATIC_FIELD_NAME_PREFIX" value="our" />
|
<option name="STATIC_FIELD_NAME_PREFIX" value="our" />
|
||||||
|
1
.teamcity/_Self/buildTypes/Compatibility.kt
vendored
1
.teamcity/_Self/buildTypes/Compatibility.kt
vendored
@@ -34,7 +34,6 @@ object Compatibility : IdeaVimBuildType({
|
|||||||
|
|
||||||
java --version
|
java --version
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}org.jetbrains.IdeaVim-EasyMotion' [latest-IU] -team-city
|
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}org.jetbrains.IdeaVim-EasyMotion' [latest-IU] -team-city
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}io.github.mishkun.ideavimsneak' [latest-IU] -team-city
|
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city
|
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}eu.theblob42.idea.whichkey' [latest-IU] -team-city
|
||||||
java -jar verifier1/verifier-cli-dev-all-1.jar check-plugin '${'$'}IdeaVimExtension' [latest-IU] -team-city
|
java -jar verifier1/verifier-cli-dev-all-1.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
|
# Outdated java -jar verifier/verifier-cli-dev-all.jar check-plugin '${'$'}github.zgqq.intellij-enhance' [latest-IU] -team-city
|
||||||
|
2
.teamcity/_Self/buildTypes/LongRunning.kt
vendored
2
.teamcity/_Self/buildTypes/LongRunning.kt
vendored
@@ -25,7 +25,7 @@ object LongRunning : IdeaVimBuildType({
|
|||||||
|
|
||||||
steps {
|
steps {
|
||||||
gradle {
|
gradle {
|
||||||
tasks = "clean testLongRunning"
|
tasks = "clean :tests:long-running-tests:testLongRunning"
|
||||||
buildFile = ""
|
buildFile = ""
|
||||||
enableStacktrace = true
|
enableStacktrace = true
|
||||||
}
|
}
|
||||||
|
2
.teamcity/_Self/buildTypes/Nvim.kt
vendored
2
.teamcity/_Self/buildTypes/Nvim.kt
vendored
@@ -39,7 +39,7 @@ object Nvim : IdeaVimBuildType({
|
|||||||
""".trimIndent()
|
""".trimIndent()
|
||||||
}
|
}
|
||||||
gradle {
|
gradle {
|
||||||
tasks = "clean testWithNeovim"
|
tasks = "clean test -Dnvim"
|
||||||
buildFile = ""
|
buildFile = ""
|
||||||
enableStacktrace = true
|
enableStacktrace = true
|
||||||
}
|
}
|
||||||
|
2
.teamcity/_Self/buildTypes/PropertyBased.kt
vendored
2
.teamcity/_Self/buildTypes/PropertyBased.kt
vendored
@@ -24,7 +24,7 @@ object PropertyBased : IdeaVimBuildType({
|
|||||||
|
|
||||||
steps {
|
steps {
|
||||||
gradle {
|
gradle {
|
||||||
tasks = "clean testPropertyBased"
|
tasks = "clean :tests:property-tests:testPropertyBased"
|
||||||
buildFile = ""
|
buildFile = ""
|
||||||
enableStacktrace = true
|
enableStacktrace = true
|
||||||
}
|
}
|
||||||
|
19
.teamcity/patches/buildTypes/PublishVimEngine.kts
vendored
Normal file
19
.teamcity/patches/buildTypes/PublishVimEngine.kts
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package patches.buildTypes
|
||||||
|
|
||||||
|
import jetbrains.buildServer.configs.kotlin.v2019_2.*
|
||||||
|
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 = 'PublishVimEngine'
|
||||||
|
accordingly, and delete the patch script.
|
||||||
|
*/
|
||||||
|
changeBuildType(RelativeId("PublishVimEngine")) {
|
||||||
|
vcs {
|
||||||
|
|
||||||
|
check(branchFilter == "+:<default>") {
|
||||||
|
"Unexpected option value: branchFilter = $branchFilter"
|
||||||
|
}
|
||||||
|
branchFilter = "+:fleet"
|
||||||
|
}
|
||||||
|
}
|
@@ -30,6 +30,7 @@ usual beta standards.
|
|||||||
|
|
||||||
### Merged PRs:
|
### Merged PRs:
|
||||||
* [725](https://github.com/JetBrains/ideavim/pull/725) by [Emanuel Gestosa](https://github.com/emanuelgestosa): Regex
|
* [725](https://github.com/JetBrains/ideavim/pull/725) by [Emanuel Gestosa](https://github.com/emanuelgestosa): Regex
|
||||||
|
* [805](https://github.com/JetBrains/ideavim/pull/805) by [chylex](https://github.com/chylex): VIM-3238 Fix recording a macro that replays another macro
|
||||||
|
|
||||||
## 2.8.0, 2024-01-30
|
## 2.8.0, 2024-01-30
|
||||||
|
|
||||||
|
143
build.gradle.kts
143
build.gradle.kts
@@ -70,12 +70,9 @@ plugins {
|
|||||||
application
|
application
|
||||||
id("java-test-fixtures")
|
id("java-test-fixtures")
|
||||||
|
|
||||||
id("org.jetbrains.intellij") version "1.17.0"
|
id("org.jetbrains.intellij") version "1.17.1"
|
||||||
id("org.jetbrains.changelog") version "2.2.0"
|
id("org.jetbrains.changelog") version "2.2.0"
|
||||||
|
|
||||||
// ktlint linter - read more: https://github.com/JLLeitschuh/ktlint-gradle
|
|
||||||
// id("org.jlleitschuh.gradle.ktlint") version "11.3.1"
|
|
||||||
|
|
||||||
id("org.jetbrains.kotlinx.kover") version "0.6.1"
|
id("org.jetbrains.kotlinx.kover") version "0.6.1"
|
||||||
id("com.dorongold.task-tree") version "2.1.1"
|
id("com.dorongold.task-tree") version "2.1.1"
|
||||||
|
|
||||||
@@ -104,8 +101,8 @@ val ideaVersion: String by project
|
|||||||
val ideaType: String by project
|
val ideaType: String by project
|
||||||
val downloadIdeaSources: String by project
|
val downloadIdeaSources: String by project
|
||||||
val instrumentPluginCode: String by project
|
val instrumentPluginCode: String by project
|
||||||
val remoteRobotVersion: String by project
|
|
||||||
val antlrVersion: String by project
|
val antlrVersion: String by project
|
||||||
|
val remoteRobotVersion: String by project
|
||||||
|
|
||||||
val publishChannels: String by project
|
val publishChannels: String by project
|
||||||
val publishToken: String by project
|
val publishToken: String by project
|
||||||
@@ -147,11 +144,6 @@ dependencies {
|
|||||||
// https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
|
// https://mvnrepository.com/artifact/org.mockito.kotlin/mockito-kotlin
|
||||||
testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
|
testImplementation("org.mockito.kotlin:mockito-kotlin:5.2.1")
|
||||||
|
|
||||||
testImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion")
|
|
||||||
testImplementation("com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion")
|
|
||||||
testImplementation("com.intellij.remoterobot:ide-launcher:$remoteRobotVersion")
|
|
||||||
testImplementation("com.automation-remarks:video-recorder-junit5:2.0")
|
|
||||||
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
|
testImplementation("org.junit.jupiter:junit-jupiter-api:5.10.1")
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.1")
|
testImplementation("org.junit.jupiter:junit-jupiter-engine:5.10.1")
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.1")
|
testImplementation("org.junit.jupiter:junit-jupiter-params:5.10.1")
|
||||||
@@ -166,74 +158,17 @@ configurations {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Compilation
|
|
||||||
// This can be moved to other test registration when issue with tests in gradle will be fixed
|
|
||||||
tasks.register<Test>("testWithNeovim") {
|
|
||||||
group = "verification"
|
|
||||||
systemProperty("ideavim.nvim.test", "true")
|
|
||||||
exclude("/ui/**")
|
|
||||||
exclude("**/longrunning/**")
|
|
||||||
exclude("**/propertybased/**")
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register<Test>("testPropertyBased") {
|
|
||||||
group = "verification"
|
|
||||||
// include("**/propertybased/**")
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks.register<Test>("testLongRunning") {
|
|
||||||
group = "verification"
|
|
||||||
// include("**/longrunning/**")
|
|
||||||
useJUnitPlatform()
|
|
||||||
}
|
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
// Issue in gradle 7.3
|
test {
|
||||||
val test by getting(Test::class) {
|
|
||||||
isScanForTestClasses = false
|
|
||||||
// Only run tests from classes that end with "Test"
|
|
||||||
include("**/*Test.class")
|
|
||||||
include("**/*test.class")
|
|
||||||
include("**/*Tests.class")
|
|
||||||
exclude("**/ParserTest.class")
|
|
||||||
|
|
||||||
// Set teamcity env variable locally to run additional tests for leaks.
|
// Set teamcity env variable locally to run additional tests for leaks.
|
||||||
// By default, this test runs on TC only, but this test doesn't take a lot of time,
|
// By default, this test runs on TC only, but this test doesn't take a lot of time,
|
||||||
// so we can turn it on for local development
|
// so we can turn it on for local development
|
||||||
if (environment["TEAMCITY_VERSION"] == null) {
|
if (environment["TEAMCITY_VERSION"] == null) {
|
||||||
println("Set env TEAMCITY_VERSION to X")
|
println("Set env TEAMCITY_VERSION to X to enable project leak checks from the platform")
|
||||||
environment("TEAMCITY_VERSION" to "X")
|
environment("TEAMCITY_VERSION" to "X")
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
val testWithNeovim by getting(Test::class) {
|
systemProperty("ideavim.nvim.test", System.getProperty("nvim") ?: false)
|
||||||
isScanForTestClasses = false
|
|
||||||
// Only run tests from classes that end with "Test"
|
|
||||||
include("**/*Test.class")
|
|
||||||
include("**/*test.class")
|
|
||||||
include("**/*Tests.class")
|
|
||||||
exclude("**/ParserTest.class")
|
|
||||||
exclude("**/longrunning/**")
|
|
||||||
exclude("**/propertybased/**")
|
|
||||||
}
|
|
||||||
|
|
||||||
val testPropertyBased by getting(Test::class) {
|
|
||||||
isScanForTestClasses = false
|
|
||||||
// Only run tests from classes that end with "Test"
|
|
||||||
include("**/propertybased/*Test.class")
|
|
||||||
include("**/propertybased/*test.class")
|
|
||||||
include("**/propertybased/*Tests.class")
|
|
||||||
}
|
|
||||||
|
|
||||||
val testLongRunning by getting(Test::class) {
|
|
||||||
isScanForTestClasses = false
|
|
||||||
// Only run tests from classes that end with "Test"
|
|
||||||
include("**/longrunning/**/*Test.class")
|
|
||||||
include("**/longrunning/**/*test.class")
|
|
||||||
include("**/longrunning/**/*Tests.class")
|
|
||||||
exclude("**/longrunning/**/ParserTest.class")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
compileJava {
|
compileJava {
|
||||||
@@ -253,6 +188,7 @@ tasks {
|
|||||||
// allWarningsAsErrors = true
|
// allWarningsAsErrors = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
compileTestKotlin {
|
compileTestKotlin {
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = javaVersion
|
jvmTarget = javaVersion
|
||||||
@@ -260,6 +196,18 @@ tasks {
|
|||||||
// allWarningsAsErrors = true
|
// allWarningsAsErrors = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
downloadRobotServerPlugin {
|
||||||
|
version.set(remoteRobotVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
runIdeForUiTests {
|
||||||
|
systemProperty("robot-server.port", "8082")
|
||||||
|
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
|
||||||
|
systemProperty("jb.privacy.policy.text", "<!--999.999-->")
|
||||||
|
systemProperty("jb.consents.confirmation.enabled", "false")
|
||||||
|
systemProperty("ide.show.tips.on.startup.default.value", "false")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
java {
|
java {
|
||||||
@@ -286,6 +234,7 @@ gradle.projectsEvaluated {
|
|||||||
|
|
||||||
intellij {
|
intellij {
|
||||||
version.set(ideaVersion)
|
version.set(ideaVersion)
|
||||||
|
type.set(ideaType)
|
||||||
pluginName.set("IdeaVim")
|
pluginName.set("IdeaVim")
|
||||||
|
|
||||||
updateSinceUntilBuild.set(false)
|
updateSinceUntilBuild.set(false)
|
||||||
@@ -297,10 +246,6 @@ intellij {
|
|||||||
}
|
}
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
downloadRobotServerPlugin {
|
|
||||||
version.set(remoteRobotVersion)
|
|
||||||
}
|
|
||||||
|
|
||||||
publishPlugin {
|
publishPlugin {
|
||||||
channels.set(publishChannels.split(","))
|
channels.set(publishChannels.split(","))
|
||||||
token.set(publishToken)
|
token.set(publishToken)
|
||||||
@@ -312,14 +257,6 @@ tasks {
|
|||||||
password.set(providers.environmentVariable("PRIVATE_KEY_PASSWORD"))
|
password.set(providers.environmentVariable("PRIVATE_KEY_PASSWORD"))
|
||||||
}
|
}
|
||||||
|
|
||||||
runIdeForUiTests {
|
|
||||||
systemProperty("robot-server.port", "8082")
|
|
||||||
systemProperty("ide.mac.message.dialogs.as.sheets", "false")
|
|
||||||
systemProperty("jb.privacy.policy.text", "<!--999.999-->")
|
|
||||||
systemProperty("jb.consents.confirmation.enabled", "false")
|
|
||||||
systemProperty("ide.show.tips.on.startup.default.value", "false")
|
|
||||||
}
|
|
||||||
|
|
||||||
runPluginVerifier {
|
runPluginVerifier {
|
||||||
downloadDir.set("${project.buildDir}/pluginVerifier/ides")
|
downloadDir.set("${project.buildDir}/pluginVerifier/ides")
|
||||||
teamCityOutputFormat.set(true)
|
teamCityOutputFormat.set(true)
|
||||||
@@ -371,8 +308,6 @@ tasks {
|
|||||||
val pluginVersion = version
|
val pluginVersion = version
|
||||||
// Don't forget to update plugin.xml
|
// Don't forget to update plugin.xml
|
||||||
patchPluginXml {
|
patchPluginXml {
|
||||||
sinceBuild.set("233.11799.30")
|
|
||||||
|
|
||||||
// Get the latest available change notes from the changelog file
|
// Get the latest available change notes from the changelog file
|
||||||
changeNotes.set(
|
changeNotes.set(
|
||||||
provider {
|
provider {
|
||||||
@@ -392,29 +327,14 @@ tasks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// --- Linting
|
|
||||||
|
|
||||||
//ktlint {
|
|
||||||
// version.set("0.48.2")
|
|
||||||
//}
|
|
||||||
|
|
||||||
// --- Tests
|
// --- Tests
|
||||||
|
|
||||||
tasks {
|
tasks {
|
||||||
test {
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
exclude("**/propertybased/**")
|
|
||||||
exclude("**/longrunning/**")
|
|
||||||
exclude("/ui/**")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.register<Test>("testUi") {
|
|
||||||
group = "verification"
|
|
||||||
useJUnitPlatform()
|
|
||||||
include("/ui/**")
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Changelog
|
// --- Changelog
|
||||||
|
|
||||||
changelog {
|
changelog {
|
||||||
@@ -433,16 +353,6 @@ koverMerged {
|
|||||||
enable()
|
enable()
|
||||||
}
|
}
|
||||||
|
|
||||||
kover {
|
|
||||||
instrumentation {
|
|
||||||
// set of test tasks names to exclude from instrumentation. The results of their execution will not be presented in the report
|
|
||||||
excludeTasks += "testPropertyBased"
|
|
||||||
excludeTasks += "testLongRunning"
|
|
||||||
excludeTasks += "testWithNeovim"
|
|
||||||
excludeTasks += "testUi"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// --- Slack notification
|
// --- Slack notification
|
||||||
|
|
||||||
tasks.register("slackNotification") {
|
tasks.register("slackNotification") {
|
||||||
@@ -636,7 +546,8 @@ fun addReleaseToYoutrack(name: String): String {
|
|||||||
println("Creating new release version in YouTrack: $name")
|
println("Creating new release version in YouTrack: $name")
|
||||||
|
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
val response = client.post("https://youtrack.jetbrains.com/api/admin/projects/$vimProjectId/customFields/$fixVersionsFieldId/bundle/values?fields=id,name") {
|
val response =
|
||||||
|
client.post("https://youtrack.jetbrains.com/api/admin/projects/$vimProjectId/customFields/$fixVersionsFieldId/bundle/values?fields=id,name") {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
accept(ContentType.Application.Json)
|
accept(ContentType.Application.Json)
|
||||||
val request = buildJsonObject {
|
val request = buildJsonObject {
|
||||||
@@ -653,7 +564,8 @@ fun getVersionIdByName(name: String): String? {
|
|||||||
val client = httpClient()
|
val client = httpClient()
|
||||||
|
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
val response = client.get("https://youtrack.jetbrains.com/api/admin/projects/$vimProjectId/customFields/$fixVersionsFieldId/bundle/values?fields=id,name&query=$name")
|
val response =
|
||||||
|
client.get("https://youtrack.jetbrains.com/api/admin/projects/$vimProjectId/customFields/$fixVersionsFieldId/bundle/values?fields=id,name&query=$name")
|
||||||
response.body<JsonArray>().singleOrNull()?.jsonObject?.get("id")?.jsonPrimitive?.content
|
response.body<JsonArray>().singleOrNull()?.jsonObject?.get("id")?.jsonPrimitive?.content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -691,7 +603,8 @@ fun setYoutrackStatus(tickets: Collection<String>, status: String) {
|
|||||||
runBlocking {
|
runBlocking {
|
||||||
for (ticket in tickets) {
|
for (ticket in tickets) {
|
||||||
println("Try to set $ticket to $status")
|
println("Try to set $ticket to $status")
|
||||||
val response = client.post("https://youtrack.jetbrains.com/api/issues/$ticket?fields=customFields(id,name,value(id,name))") {
|
val response =
|
||||||
|
client.post("https://youtrack.jetbrains.com/api/issues/$ticket?fields=customFields(id,name,value(id,name))") {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
accept(ContentType.Application.Json)
|
accept(ContentType.Application.Json)
|
||||||
val request = buildJsonObject {
|
val request = buildJsonObject {
|
||||||
@@ -730,7 +643,8 @@ fun setYoutrackFixVersion(tickets: Collection<String>, version: String) {
|
|||||||
runBlocking {
|
runBlocking {
|
||||||
for (ticket in tickets) {
|
for (ticket in tickets) {
|
||||||
println("Try to set fix version $version for $ticket")
|
println("Try to set fix version $version for $ticket")
|
||||||
val response = client.post("https://youtrack.jetbrains.com/api/issues/$ticket?fields=customFields(id,name,value(id,name))") {
|
val response =
|
||||||
|
client.post("https://youtrack.jetbrains.com/api/issues/$ticket?fields=customFields(id,name,value(id,name))") {
|
||||||
contentType(ContentType.Application.Json)
|
contentType(ContentType.Application.Json)
|
||||||
accept(ContentType.Application.Json)
|
accept(ContentType.Application.Json)
|
||||||
val request = buildJsonObject {
|
val request = buildJsonObject {
|
||||||
@@ -768,7 +682,8 @@ fun getYoutrackStatus(ticket: String): String {
|
|||||||
val client = httpClient()
|
val client = httpClient()
|
||||||
|
|
||||||
return runBlocking {
|
return runBlocking {
|
||||||
val response = client.get("https://youtrack.jetbrains.com/api/issues/$ticket/customFields/123-129?fields=value(name)")
|
val response =
|
||||||
|
client.get("https://youtrack.jetbrains.com/api/issues/$ticket/customFields/123-129?fields=value(name)")
|
||||||
response.body<JsonObject>()["value"]!!.jsonObject.getValue("name").jsonPrimitive.content
|
response.body<JsonObject>()["value"]!!.jsonObject.getValue("name").jsonPrimitive.content
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -8,16 +8,17 @@
|
|||||||
|
|
||||||
# suppress inspection "UnusedProperty" for whole file
|
# suppress inspection "UnusedProperty" for whole file
|
||||||
|
|
||||||
ideaVersion=2023.3.2
|
ideaVersion=2023.3.3
|
||||||
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
|
# Values for type: https://plugins.jetbrains.com/docs/intellij/tools-gradle-intellij-plugin.html#intellij-extension-type
|
||||||
ideaType=IC
|
ideaType=IC
|
||||||
downloadIdeaSources=true
|
downloadIdeaSources=true
|
||||||
instrumentPluginCode=true
|
instrumentPluginCode=true
|
||||||
version=SNAPSHOT
|
version=chylex-27
|
||||||
javaVersion=17
|
javaVersion=17
|
||||||
remoteRobotVersion=0.11.21
|
remoteRobotVersion=0.11.22
|
||||||
antlrVersion=4.10.1
|
antlrVersion=4.10.1
|
||||||
|
|
||||||
|
kotlin.incremental.useClasspathSnapshot=false
|
||||||
|
|
||||||
# Please don't forget to update kotlin version in buildscript section
|
# Please don't forget to update kotlin version in buildscript section
|
||||||
# Also update kotlinxSerializationVersion version
|
# Also update kotlinxSerializationVersion version
|
||||||
|
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
BIN
gradle/wrapper/gradle-wrapper.jar
vendored
Binary file not shown.
3
gradle/wrapper/gradle-wrapper.properties
vendored
3
gradle/wrapper/gradle-wrapper.properties
vendored
@@ -1,6 +1,7 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
5
gradlew
vendored
5
gradlew
vendored
@@ -130,11 +130,14 @@ location of your Java installation."
|
|||||||
fi
|
fi
|
||||||
else
|
else
|
||||||
JAVACMD=java
|
JAVACMD=java
|
||||||
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
if ! command -v java >/dev/null 2>&1
|
||||||
|
then
|
||||||
|
die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
|
||||||
|
|
||||||
Please set the JAVA_HOME variable in your environment to match the
|
Please set the JAVA_HOME variable in your environment to match the
|
||||||
location of your Java installation."
|
location of your Java installation."
|
||||||
fi
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
# Increase the maximum file descriptors if we can.
|
# Increase the maximum file descriptors if we can.
|
||||||
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
|
||||||
|
@@ -13,4 +13,8 @@ include 'vim-engine'
|
|||||||
include 'scripts'
|
include 'scripts'
|
||||||
include 'annotation-processors'
|
include 'annotation-processors'
|
||||||
include 'tests:java-tests'
|
include 'tests:java-tests'
|
||||||
|
include 'tests:property-tests'
|
||||||
|
include 'tests:long-running-tests'
|
||||||
|
include 'tests:ui-ij-tests'
|
||||||
|
include 'tests:ui-py-tests'
|
||||||
|
include 'tests:ui-fixtures'
|
||||||
|
@@ -217,6 +217,8 @@ private object FileTypePatterns {
|
|||||||
|
|
||||||
return if (fileTypeName in htmlLikeFileTypes) {
|
return if (fileTypeName in htmlLikeFileTypes) {
|
||||||
this.htmlPatterns
|
this.htmlPatterns
|
||||||
|
} else if (fileTypeName == "JAVA" || fileExtension == "java") {
|
||||||
|
this.javaPatterns
|
||||||
} else if (fileTypeName == "Ruby" || fileExtension == "rb") {
|
} else if (fileTypeName == "Ruby" || fileExtension == "rb") {
|
||||||
this.rubyPatterns
|
this.rubyPatterns
|
||||||
} else if (fileTypeName == "RHTML" || fileExtension == "erb") {
|
} else if (fileTypeName == "RHTML" || fileExtension == "erb") {
|
||||||
@@ -231,7 +233,7 @@ private object FileTypePatterns {
|
|||||||
} else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") {
|
} else if (fileTypeName == "CMakeLists.txt" || fileName == "CMakeLists") {
|
||||||
this.cMakePatterns
|
this.cMakePatterns
|
||||||
} else {
|
} else {
|
||||||
return null
|
this.htmlPatterns
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,6 +244,7 @@ private object FileTypePatterns {
|
|||||||
)
|
)
|
||||||
|
|
||||||
private val htmlPatterns = createHtmlPatterns()
|
private val htmlPatterns = createHtmlPatterns()
|
||||||
|
private val javaPatterns = createJavaPatterns()
|
||||||
private val rubyPatterns = createRubyPatterns()
|
private val rubyPatterns = createRubyPatterns()
|
||||||
private val rubyAndHtmlPatterns = rubyPatterns + htmlPatterns
|
private val rubyAndHtmlPatterns = rubyPatterns + htmlPatterns
|
||||||
private val phpPatterns = createPhpPatterns()
|
private val phpPatterns = createPhpPatterns()
|
||||||
@@ -271,6 +274,14 @@ private object FileTypePatterns {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun createJavaPatterns(): LanguagePatterns {
|
||||||
|
return (
|
||||||
|
LanguagePatterns("\\b(?<!else\\s+)if\\b", "\\belse\\s+if\\b", "\\belse(?!\\s+if)\\b") +
|
||||||
|
LanguagePatterns("\\bdo\\b", "\\bwhile\\b") +
|
||||||
|
LanguagePatterns("\\btry\\b", "\\bcatch\\b", "\\bfinally\\b")
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
private fun createRubyPatterns(): LanguagePatterns {
|
private fun createRubyPatterns(): LanguagePatterns {
|
||||||
// Original patterns: https://github.com/vim/vim/blob/master/runtime/ftplugin/ruby.vim
|
// Original patterns: https://github.com/vim/vim/blob/master/runtime/ftplugin/ruby.vim
|
||||||
// We use non-capturing groups (?:) since we don't need any back refs. The \\b marker takes care of word boundaries.
|
// We use non-capturing groups (?:) since we don't need any back refs. The \\b marker takes care of word boundaries.
|
||||||
|
@@ -502,6 +502,13 @@ internal class NerdTree : VimExtension {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
|
for (c in ('a'..'z') + ('A'..'Z')) {
|
||||||
|
val ks = KeyStroke.getKeyStroke(c)
|
||||||
|
if (ks !in actionsRoot) {
|
||||||
|
registerCommand(c.toString(), NerdAction.Code { _, _, _ -> })
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@@ -11,8 +11,8 @@ package com.maddyhome.idea.vim.extension.paragraphmotion
|
|||||||
import com.intellij.openapi.editor.Caret
|
import com.intellij.openapi.editor.Caret
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
|
import com.maddyhome.idea.vim.api.getLineEndForOffset
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.api.normalizeOffset
|
|
||||||
import com.maddyhome.idea.vim.command.MappingMode
|
import com.maddyhome.idea.vim.command.MappingMode
|
||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.extension.ExtensionHandler
|
import com.maddyhome.idea.vim.extension.ExtensionHandler
|
||||||
@@ -45,8 +45,7 @@ internal class ParagraphMotion : VimExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun moveCaretToNextParagraph(editor: VimEditor, caret: Caret, count: Int): Int? {
|
fun moveCaretToNextParagraph(editor: VimEditor, caret: Caret, count: Int): Int? {
|
||||||
return injector.searchHelper.findNextParagraph(editor, caret.vim, count, true)
|
return injector.searchHelper.findNextParagraph(editor, caret.vim, count, true)?.let(editor::getLineEndForOffset)
|
||||||
?.let { editor.normalizeOffset(it, true) }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -9,7 +9,6 @@
|
|||||||
package com.maddyhome.idea.vim.extension.sneak
|
package com.maddyhome.idea.vim.extension.sneak
|
||||||
|
|
||||||
import com.intellij.openapi.actionSystem.DataContext
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.ScrollType
|
import com.intellij.openapi.editor.ScrollType
|
||||||
import com.intellij.openapi.editor.colors.EditorColors
|
import com.intellij.openapi.editor.colors.EditorColors
|
||||||
@@ -19,6 +18,7 @@ import com.intellij.openapi.editor.markup.HighlighterTargetArea
|
|||||||
import com.intellij.openapi.editor.markup.RangeHighlighter
|
import com.intellij.openapi.editor.markup.RangeHighlighter
|
||||||
import com.intellij.openapi.editor.markup.TextAttributes
|
import com.intellij.openapi.editor.markup.TextAttributes
|
||||||
import com.intellij.openapi.util.Disposer
|
import com.intellij.openapi.util.Disposer
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.VimProjectService
|
import com.maddyhome.idea.vim.VimProjectService
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
@@ -30,16 +30,16 @@ import com.maddyhome.idea.vim.common.TextRange
|
|||||||
import com.maddyhome.idea.vim.extension.ExtensionHandler
|
import com.maddyhome.idea.vim.extension.ExtensionHandler
|
||||||
import com.maddyhome.idea.vim.extension.VimExtension
|
import com.maddyhome.idea.vim.extension.VimExtension
|
||||||
import com.maddyhome.idea.vim.extension.VimExtensionFacade
|
import com.maddyhome.idea.vim.extension.VimExtensionFacade
|
||||||
|
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMapping
|
||||||
import com.maddyhome.idea.vim.extension.VimExtensionHandler
|
import com.maddyhome.idea.vim.extension.VimExtensionHandler
|
||||||
import com.maddyhome.idea.vim.helper.StrictMode
|
import com.maddyhome.idea.vim.helper.StrictMode
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import java.awt.Font
|
import java.awt.Font
|
||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
import java.util.concurrent.Executors
|
import javax.swing.Timer
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
|
|
||||||
|
|
||||||
private const val DEFAULT_HIGHLIGHT_DURATION_SNEAK: Long = 300
|
private const val DEFAULT_HIGHLIGHT_DURATION_SNEAK = 300
|
||||||
|
|
||||||
// By [Mikhail Levchenko](https://github.com/Mishkun)
|
// By [Mikhail Levchenko](https://github.com/Mishkun)
|
||||||
// Original repository with the plugin: https://github.com/Mishkun/ideavim-sneak
|
// Original repository with the plugin: https://github.com/Mishkun/ideavim-sneak
|
||||||
@@ -250,11 +250,13 @@ internal class IdeaVimSneakExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun setClearHighlightRangeTimer(highlighter: RangeHighlighter) {
|
private fun setClearHighlightRangeTimer(highlighter: RangeHighlighter) {
|
||||||
Executors.newSingleThreadScheduledExecutor().schedule({
|
val timer = Timer(DEFAULT_HIGHLIGHT_DURATION_SNEAK) {
|
||||||
ApplicationManager.getApplication().invokeLater {
|
if (editor?.isDisposed != true) {
|
||||||
editor?.markupModel?.removeHighlighter(highlighter) ?: StrictMode.fail("Highlighters without an editor")
|
editor?.markupModel?.removeHighlighter(highlighter)
|
||||||
}
|
}
|
||||||
}, DEFAULT_HIGHLIGHT_DURATION_SNEAK, TimeUnit.MILLISECONDS)
|
}
|
||||||
|
timer.isRepeats = false
|
||||||
|
timer.start()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getHighlightTextAttributes() = TextAttributes(
|
private fun getHighlightTextAttributes() = TextAttributes(
|
||||||
@@ -279,13 +281,41 @@ private fun VimExtension.mapToFunctionAndProvideKeys(keys: String, handler: Exte
|
|||||||
handler,
|
handler,
|
||||||
false
|
false
|
||||||
)
|
)
|
||||||
VimExtensionFacade.putKeyMapping(
|
VimExtensionFacade.putExtensionHandlerMapping(
|
||||||
MappingMode.NXO,
|
MappingMode.NXO,
|
||||||
injector.parser.parseKeys(keys),
|
injector.parser.parseKeys(commandFromOriginalPlugin(keys)),
|
||||||
owner,
|
owner,
|
||||||
injector.parser.parseKeys(command(keys)),
|
handler,
|
||||||
|
false
|
||||||
|
)
|
||||||
|
|
||||||
|
// This is a combination to meet the following requirements:
|
||||||
|
// - Now we should support mappings from sneak `Sneak_s` and mappings from the previous version of the plugin `(sneak-s)`
|
||||||
|
// - The shortcut should not be registered if any of these mappings is overridden in .ideavimrc
|
||||||
|
// - The shortcut should not be registered if some other shortcut for this key exists
|
||||||
|
val fromKeys = injector.parser.parseKeys(keys)
|
||||||
|
val filteredModes = MappingMode.NXO.filterNotTo(HashSet()) {
|
||||||
|
VimPlugin.getKey().hasmapto(it, injector.parser.parseKeys(command(keys)))
|
||||||
|
}
|
||||||
|
val filteredModes2 = MappingMode.NXO.filterNotTo(HashSet()) {
|
||||||
|
VimPlugin.getKey().hasmapto(it, injector.parser.parseKeys(commandFromOriginalPlugin(keys)))
|
||||||
|
}
|
||||||
|
val filteredFromModes = MappingMode.NXO.filterNotTo(HashSet()) {
|
||||||
|
injector.keyGroup.hasmapfrom(it, fromKeys)
|
||||||
|
}
|
||||||
|
|
||||||
|
val doubleFiltered = MappingMode.NXO
|
||||||
|
.filter { it in filteredModes2 && it in filteredModes && it in filteredFromModes }
|
||||||
|
.toSet()
|
||||||
|
putKeyMapping(doubleFiltered, fromKeys, owner, injector.parser.parseKeys(command(keys)), true)
|
||||||
|
putKeyMapping(
|
||||||
|
doubleFiltered,
|
||||||
|
fromKeys,
|
||||||
|
owner,
|
||||||
|
injector.parser.parseKeys(commandFromOriginalPlugin(keys)),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun command(keys: String) = "<Plug>(sneak-$keys)"
|
private fun command(keys: String) = "<Plug>(sneak-$keys)"
|
||||||
|
private fun commandFromOriginalPlugin(keys: String) = "<Plug>Sneak_$keys"
|
||||||
|
@@ -0,0 +1,30 @@
|
|||||||
|
package com.maddyhome.idea.vim.extension.surround
|
||||||
|
|
||||||
|
import com.intellij.util.text.CharSequenceSubSequence
|
||||||
|
|
||||||
|
internal data class RepeatedCharSequence(val text: CharSequence, val count: Int) : CharSequence {
|
||||||
|
override val length = text.length * count
|
||||||
|
|
||||||
|
override fun get(index: Int): Char {
|
||||||
|
if (index < 0 || index >= length) throw IndexOutOfBoundsException()
|
||||||
|
return text[index % text.length]
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun subSequence(startIndex: Int, endIndex: Int): CharSequence {
|
||||||
|
return CharSequenceSubSequence(this, startIndex, endIndex)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return text.repeat(count)
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
fun of(text: CharSequence, count: Int): CharSequence {
|
||||||
|
return when (count) {
|
||||||
|
0 -> ""
|
||||||
|
1 -> text
|
||||||
|
else -> RepeatedCharSequence(text, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -13,6 +13,7 @@ import com.intellij.openapi.editor.Editor
|
|||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimCaret
|
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.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.endsWithNewLine
|
import com.maddyhome.idea.vim.api.endsWithNewLine
|
||||||
import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
|
import com.maddyhome.idea.vim.api.getLeadingCharacterOffset
|
||||||
@@ -31,7 +32,10 @@ import com.maddyhome.idea.vim.extension.VimExtensionFacade.putExtensionHandlerMa
|
|||||||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
|
import com.maddyhome.idea.vim.extension.VimExtensionFacade.putKeyMappingIfMissing
|
||||||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
|
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setOperatorFunction
|
||||||
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
|
import com.maddyhome.idea.vim.extension.VimExtensionFacade.setRegisterForCaret
|
||||||
|
import com.maddyhome.idea.vim.helper.runWithEveryCaretAndRestore
|
||||||
import com.maddyhome.idea.vim.key.OperatorFunction
|
import com.maddyhome.idea.vim.key.OperatorFunction
|
||||||
|
import com.maddyhome.idea.vim.newapi.IjVimCaret
|
||||||
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
|
import com.maddyhome.idea.vim.options.helpers.ClipboardOptionHelper
|
||||||
@@ -80,7 +84,7 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
override val isRepeatable = true
|
override val isRepeatable = true
|
||||||
|
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
||||||
setOperatorFunction(Operator())
|
setOperatorFunction(Operator(supportsMultipleCursors = false, count = 1)) // TODO
|
||||||
executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
|
executeNormalWithoutMapping(injector.parser.parseKeys("g@"), editor.ij)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -101,7 +105,7 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
val lastNonWhiteSpaceOffset = getLastNonWhitespaceCharacterOffset(editor.text(), lineStartOffset, lineEndOffset)
|
val lastNonWhiteSpaceOffset = getLastNonWhitespaceCharacterOffset(editor.text(), lineStartOffset, lineEndOffset)
|
||||||
if (lastNonWhiteSpaceOffset != null) {
|
if (lastNonWhiteSpaceOffset != null) {
|
||||||
val range = TextRange(lineStartOffset, lastNonWhiteSpaceOffset + 1)
|
val range = TextRange(lineStartOffset, lastNonWhiteSpaceOffset + 1)
|
||||||
performSurround(pair, range, it)
|
performSurround(pair, range, it, count = operatorArguments.count1)
|
||||||
}
|
}
|
||||||
// it.moveToOffset(lineStartOffset)
|
// it.moveToOffset(lineStartOffset)
|
||||||
}
|
}
|
||||||
@@ -121,15 +125,13 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
|
|
||||||
private class VSurroundHandler : ExtensionHandler {
|
private class VSurroundHandler : ExtensionHandler {
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
override fun execute(editor: VimEditor, context: ExecutionContext, operatorArguments: OperatorArguments) {
|
||||||
val selectionStart = editor.ij.caretModel.primaryCaret.selectionStart
|
|
||||||
// NB: Operator ignores SelectionType anyway
|
// NB: Operator ignores SelectionType anyway
|
||||||
if (!Operator().apply(editor, context, editor.mode.selectionType)) {
|
if (!Operator(supportsMultipleCursors = true, count = operatorArguments.count1).apply(editor, context, editor.mode.selectionType)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
// Leave visual mode
|
// Leave visual mode
|
||||||
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
|
executeNormalWithoutMapping(injector.parser.parseKeys("<Esc>"), editor.ij)
|
||||||
editor.ij.caretModel.moveToOffset(selectionStart)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -150,6 +152,10 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
|
fun change(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
|
||||||
|
editor.ij.runWithEveryCaretAndRestore { changeAtCaret(editor, context, charFrom, newSurround) }
|
||||||
|
}
|
||||||
|
|
||||||
|
fun changeAtCaret(editor: VimEditor, context: ExecutionContext, charFrom: Char, newSurround: Pair<String, String>?) {
|
||||||
// Save old register values for carets
|
// Save old register values for carets
|
||||||
val surroundings = editor.sortedCarets()
|
val surroundings = editor.sortedCarets()
|
||||||
.map {
|
.map {
|
||||||
@@ -257,21 +263,42 @@ internal class VimSurroundExtension : VimExtension {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class Operator : OperatorFunction {
|
private class Operator(private val supportsMultipleCursors: Boolean, private val count: Int) : OperatorFunction {
|
||||||
override fun apply(editor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
|
override fun apply(vimEditor: VimEditor, context: ExecutionContext, selectionType: SelectionType?): Boolean {
|
||||||
val ijEditor = editor.ij
|
val editor = vimEditor.ij
|
||||||
val c = getChar(ijEditor)
|
val c = getChar(editor)
|
||||||
if (c.code == 0) return true
|
if (c.code == 0) return true
|
||||||
|
|
||||||
val pair = getOrInputPair(c, ijEditor) ?: return false
|
val pair = getOrInputPair(c, editor) ?: return false
|
||||||
// XXX: Will it work with line-wise or block-wise selections?
|
|
||||||
val range = getSurroundRange(editor.currentCaret()) ?: return false
|
runWriteAction {
|
||||||
performSurround(pair, range, editor.currentCaret(), selectionType == SelectionType.LINE_WISE)
|
val change = VimPlugin.getChange()
|
||||||
|
if (supportsMultipleCursors) {
|
||||||
|
editor.runWithEveryCaretAndRestore {
|
||||||
|
applyOnce(editor, change, pair, count)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
applyOnce(editor, change, pair, count)
|
||||||
// Jump back to start
|
// Jump back to start
|
||||||
executeNormalWithoutMapping(injector.parser.parseKeys("`["), ijEditor)
|
executeNormalWithoutMapping(injector.parser.parseKeys("`["), editor)
|
||||||
|
}
|
||||||
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun applyOnce(editor: Editor, change: VimChangeGroup, pair: Pair<String, String>, count: Int) {
|
||||||
|
// XXX: Will it work with line-wise or block-wise selections?
|
||||||
|
val primaryCaret = editor.caretModel.primaryCaret
|
||||||
|
val range = getSurroundRange(primaryCaret.vim)
|
||||||
|
if (range != null) {
|
||||||
|
val start = RepeatedCharSequence.of(pair.first, count)
|
||||||
|
val end = RepeatedCharSequence.of(pair.second, count)
|
||||||
|
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.startOffset, start)
|
||||||
|
change.insertText(IjVimEditor(editor), IjVimCaret(primaryCaret), range.endOffset + start.length, end)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun getSurroundRange(caret: VimCaret): TextRange? {
|
private fun getSurroundRange(caret: VimCaret): TextRange? {
|
||||||
val editor = caret.editor
|
val editor = caret.editor
|
||||||
val ijEditor = editor.ij
|
val ijEditor = editor.ij
|
||||||
@@ -354,15 +381,15 @@ private fun getChar(editor: Editor): Char {
|
|||||||
return res
|
return res
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, tagsOnNewLines: Boolean = false) {
|
private fun performSurround(pair: Pair<String, String>, range: TextRange, caret: VimCaret, count: Int, tagsOnNewLines: Boolean = false) {
|
||||||
runWriteAction {
|
runWriteAction {
|
||||||
val editor = caret.editor
|
val editor = caret.editor
|
||||||
val change = VimPlugin.getChange()
|
val change = VimPlugin.getChange()
|
||||||
val leftSurround = pair.first + if (tagsOnNewLines) "\n" else ""
|
val leftSurround = RepeatedCharSequence.of(pair.first + if (tagsOnNewLines) "\n" else "", count)
|
||||||
|
|
||||||
val isEOF = range.endOffset == editor.text().length
|
val isEOF = range.endOffset == editor.text().length
|
||||||
val hasNewLine = editor.endsWithNewLine()
|
val hasNewLine = editor.endsWithNewLine()
|
||||||
val rightSurround = if (tagsOnNewLines) {
|
val rightSurround = (if (tagsOnNewLines) {
|
||||||
if (isEOF && !hasNewLine) {
|
if (isEOF && !hasNewLine) {
|
||||||
"\n" + pair.second
|
"\n" + pair.second
|
||||||
} else {
|
} else {
|
||||||
@@ -370,7 +397,7 @@ private fun performSurround(pair: Pair<String, String>, range: TextRange, caret:
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
pair.second
|
pair.second
|
||||||
}
|
}).let { RepeatedCharSequence.of(it, count) }
|
||||||
|
|
||||||
change.insertText(editor, caret, range.startOffset, leftSurround)
|
change.insertText(editor, caret, range.startOffset, leftSurround)
|
||||||
change.insertText(editor, caret, range.endOffset + leftSurround.length, rightSurround)
|
change.insertText(editor, caret, range.endOffset + leftSurround.length, rightSurround)
|
||||||
|
@@ -78,7 +78,6 @@ import java.math.BigInteger
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.function.Consumer
|
import java.util.function.Consumer
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides all the insert/replace related functionality
|
* Provides all the insert/replace related functionality
|
||||||
@@ -395,6 +394,7 @@ public class ChangeGroup : VimChangeGroupBase() {
|
|||||||
context: ExecutionContext,
|
context: ExecutionContext,
|
||||||
range: TextRange,
|
range: TextRange,
|
||||||
) {
|
) {
|
||||||
|
val startPos = editor.offsetToBufferPosition(caret.offset.point)
|
||||||
val startOffset = editor.getLineStartForOffset(range.startOffset)
|
val startOffset = editor.getLineStartForOffset(range.startOffset)
|
||||||
val endOffset = editor.getLineEndForOffset(range.endOffset)
|
val endOffset = editor.getLineEndForOffset(range.endOffset)
|
||||||
val ijEditor = (editor as IjVimEditor).editor
|
val ijEditor = (editor as IjVimEditor).editor
|
||||||
@@ -419,11 +419,7 @@ public class ChangeGroup : VimChangeGroupBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
val afterAction = {
|
val afterAction = {
|
||||||
val firstLine = editor.offsetToBufferPosition(
|
caret.moveToOffset(injector.motion.moveCaretToLineStartSkipLeading(editor, startPos.line))
|
||||||
min(startOffset.toDouble(), endOffset.toDouble()).toInt()
|
|
||||||
).line
|
|
||||||
val newOffset = injector.motion.moveCaretToLineStartSkipLeading(editor, firstLine)
|
|
||||||
caret.moveToOffset(newOffset)
|
|
||||||
restoreCursor(editor, caret, (caret as IjVimCaret).caret.logicalPosition.line)
|
restoreCursor(editor, caret, (caret as IjVimCaret).caret.logicalPosition.line)
|
||||||
}
|
}
|
||||||
if (project != null) {
|
if (project != null) {
|
||||||
|
@@ -83,7 +83,7 @@ public object IjOptions {
|
|||||||
public val trackactionids: ToggleOption = addOption(ToggleOption("trackactionids", GLOBAL, "tai", false))
|
public val trackactionids: ToggleOption = addOption(ToggleOption("trackactionids", GLOBAL, "tai", false))
|
||||||
public val unifyjumps: ToggleOption = addOption(ToggleOption("unifyjumps", GLOBAL, "unifyjumps", true))
|
public val unifyjumps: ToggleOption = addOption(ToggleOption("unifyjumps", GLOBAL, "unifyjumps", true))
|
||||||
public val visualdelay: UnsignedNumberOption = addOption(UnsignedNumberOption("visualdelay", GLOBAL, "visualdelay", 100))
|
public val visualdelay: UnsignedNumberOption = addOption(UnsignedNumberOption("visualdelay", GLOBAL, "visualdelay", 100))
|
||||||
public val oldundo: ToggleOption = addOption(ToggleOption("oldundo", GLOBAL, "oldundo", false, isTemporary = true))
|
public val oldundo: ToggleOption = addOption(ToggleOption("oldundo", GLOBAL, "oldundo", true, isTemporary = true))
|
||||||
public val vimscriptFunctionAnnotation: ToggleOption = addOption(ToggleOption("vimscriptfunctionannotation", GLOBAL, "vimscriptfunctionannotation", true, isTemporary = true))
|
public val vimscriptFunctionAnnotation: ToggleOption = addOption(ToggleOption("vimscriptfunctionannotation", GLOBAL, "vimscriptfunctionannotation", true, isTemporary = true))
|
||||||
public val commandOrMotionAnnotation: ToggleOption = addOption(ToggleOption("commandormotionannotation", GLOBAL, "commandormotionannotation", true, isTemporary = true))
|
public val commandOrMotionAnnotation: ToggleOption = addOption(ToggleOption("commandormotionannotation", GLOBAL, "commandormotionannotation", true, isTemporary = true))
|
||||||
public val showmodewidget: ToggleOption = addOption(ToggleOption("showmodewidget", GLOBAL, "showmodewidget", false, isTemporary = true))
|
public val showmodewidget: ToggleOption = addOption(ToggleOption("showmodewidget", GLOBAL, "showmodewidget", false, isTemporary = true))
|
||||||
|
@@ -0,0 +1,68 @@
|
|||||||
|
package com.maddyhome.idea.vim.group
|
||||||
|
|
||||||
|
import com.intellij.codeInsight.daemon.ReferenceImporter
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys
|
||||||
|
import com.intellij.openapi.actionSystem.DataContext
|
||||||
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
|
import com.intellij.openapi.application.ReadAction
|
||||||
|
import com.intellij.openapi.command.WriteCommandAction
|
||||||
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.fileEditor.FileDocumentManager
|
||||||
|
import com.intellij.openapi.progress.ProgressIndicator
|
||||||
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
|
import com.intellij.openapi.progress.Task
|
||||||
|
import com.intellij.psi.PsiDocumentManager
|
||||||
|
import com.intellij.psi.PsiElement
|
||||||
|
import com.intellij.psi.PsiRecursiveElementWalkingVisitor
|
||||||
|
import java.util.function.BooleanSupplier
|
||||||
|
|
||||||
|
internal object MacroAutoImport {
|
||||||
|
fun run(editor: Editor, dataContext: DataContext) {
|
||||||
|
val project = CommonDataKeys.PROJECT.getData(dataContext) ?: return
|
||||||
|
val file = PsiDocumentManager.getInstance(project).getPsiFile(editor.document) ?: return
|
||||||
|
|
||||||
|
if (!FileDocumentManager.getInstance().requestWriting(editor.document, project)) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
val importers = ReferenceImporter.EP_NAME.extensionList
|
||||||
|
if (importers.isEmpty()) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
ProgressManager.getInstance().run(object : Task.Backgroundable(project, "Auto import", true) {
|
||||||
|
override fun run(indicator: ProgressIndicator) {
|
||||||
|
val fixes = ReadAction.nonBlocking<List<BooleanSupplier>> {
|
||||||
|
val fixes = mutableListOf<BooleanSupplier>()
|
||||||
|
|
||||||
|
file.accept(object : PsiRecursiveElementWalkingVisitor() {
|
||||||
|
override fun visitElement(element: PsiElement) {
|
||||||
|
for (reference in element.references) {
|
||||||
|
if (reference.resolve() != null) {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
for (importer in importers) {
|
||||||
|
importer.computeAutoImportAtOffset(editor, file, element.textRange.startOffset, true)
|
||||||
|
?.let(fixes::add)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
super.visitElement(element)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return@nonBlocking fixes
|
||||||
|
}.executeSynchronously()
|
||||||
|
|
||||||
|
ApplicationManager.getApplication().invokeAndWait {
|
||||||
|
WriteCommandAction.writeCommandAction(project)
|
||||||
|
.withName("Auto Import")
|
||||||
|
.withGroupId("IdeaVimAutoImportAfterMacro")
|
||||||
|
.shouldRecordActionForActiveDocument(true)
|
||||||
|
.run<RuntimeException> {
|
||||||
|
fixes.forEach { it.asBoolean }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@@ -7,8 +7,6 @@
|
|||||||
*/
|
*/
|
||||||
package com.maddyhome.idea.vim.group
|
package com.maddyhome.idea.vim.group
|
||||||
|
|
||||||
import com.intellij.codeInsight.completion.CompletionPhase
|
|
||||||
import com.intellij.codeInsight.completion.impl.CompletionServiceImpl
|
|
||||||
import com.intellij.openapi.application.ApplicationManager
|
import com.intellij.openapi.application.ApplicationManager
|
||||||
import com.intellij.openapi.diagnostic.logger
|
import com.intellij.openapi.diagnostic.logger
|
||||||
import com.intellij.openapi.progress.ProcessCanceledException
|
import com.intellij.openapi.progress.ProcessCanceledException
|
||||||
@@ -21,6 +19,7 @@ import com.maddyhome.idea.vim.api.injector
|
|||||||
import com.maddyhome.idea.vim.helper.MessageHelper.message
|
import com.maddyhome.idea.vim.helper.MessageHelper.message
|
||||||
import com.maddyhome.idea.vim.macro.VimMacroBase
|
import com.maddyhome.idea.vim.macro.VimMacroBase
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Used to handle playback of macros
|
* Used to handle playback of macros
|
||||||
@@ -78,7 +77,7 @@ internal class MacroGroup : VimMacroBase() {
|
|||||||
ProgressManager.getInstance().executeNonCancelableSection {
|
ProgressManager.getInstance().executeNonCancelableSection {
|
||||||
// Prevent autocompletion during macros.
|
// Prevent autocompletion during macros.
|
||||||
// See https://github.com/JetBrains/ideavim/pull/772 for details
|
// See https://github.com/JetBrains/ideavim/pull/772 for details
|
||||||
CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion)
|
// CompletionServiceImpl.setCompletionPhase(CompletionPhase.NoCompletion)
|
||||||
getInstance().handleKey(editor, key, context)
|
getInstance().handleKey(editor, key, context)
|
||||||
}
|
}
|
||||||
if (injector.messages.isError()) return@runnable
|
if (injector.messages.isError()) return@runnable
|
||||||
@@ -90,6 +89,9 @@ internal class MacroGroup : VimMacroBase() {
|
|||||||
} finally {
|
} finally {
|
||||||
keyStack.removeFirst()
|
keyStack.removeFirst()
|
||||||
}
|
}
|
||||||
|
if (!isInternalMacro) {
|
||||||
|
MacroAutoImport.run(editor.ij, context.ij)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isInternalMacro) {
|
if (isInternalMacro) {
|
||||||
|
@@ -214,8 +214,8 @@ public class SearchGroup extends IjVimSearchGroup implements PersistentStateComp
|
|||||||
* @param patternOffset The pattern offset, e.g. `/{pattern}/{offset}`
|
* @param patternOffset The pattern offset, e.g. `/{pattern}/{offset}`
|
||||||
* @param direction The direction to search
|
* @param direction The direction to search
|
||||||
*/
|
*/
|
||||||
@TestOnly
|
@Override
|
||||||
public void setLastSearchState(@SuppressWarnings("unused") @NotNull Editor editor, @NotNull String pattern,
|
public void setLastSearchState(@SuppressWarnings("unused") @NotNull VimEditor editor, @NotNull String pattern,
|
||||||
@NotNull String patternOffset, Direction direction) {
|
@NotNull String patternOffset, Direction direction) {
|
||||||
if (globalIjOptions(injector).getUseNewRegex()) {
|
if (globalIjOptions(injector).getUseNewRegex()) {
|
||||||
super.setLastSearchState(pattern, patternOffset, direction);
|
super.setLastSearchState(pattern, patternOffset, direction);
|
||||||
|
@@ -329,7 +329,7 @@ public class EditorHelper {
|
|||||||
|
|
||||||
final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
|
final int offset = y - ((screenHeight - lineHeight) / lineHeight / 2 * lineHeight);
|
||||||
@NotNull final VimEditor editor1 = new IjVimEditor(editor);
|
@NotNull final VimEditor editor1 = new IjVimEditor(editor);
|
||||||
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) - 1;
|
final int lastVisualLine = EngineEditorHelperKt.getVisualLineCount(editor1) + editor.getSettings().getAdditionalLinesCount();
|
||||||
final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
|
final int offsetForLastLineAtBottom = getOffsetToScrollVisualLineToBottomOfScreen(editor, lastVisualLine);
|
||||||
|
|
||||||
// For `zz`, we want to use virtual space and move any line, including the last one, to the middle of the screen.
|
// For `zz`, we want to use virtual space and move any line, including the last one, to the middle of the screen.
|
||||||
|
@@ -12,6 +12,7 @@ package com.maddyhome.idea.vim.helper
|
|||||||
|
|
||||||
import com.intellij.codeWithMe.ClientId
|
import com.intellij.codeWithMe.ClientId
|
||||||
import com.intellij.openapi.editor.Caret
|
import com.intellij.openapi.editor.Caret
|
||||||
|
import com.intellij.openapi.editor.CaretState
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.openapi.editor.ex.util.EditorUtil
|
import com.intellij.openapi.editor.ex.util.EditorUtil
|
||||||
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
import com.intellij.openapi.fileEditor.ex.FileEditorManagerEx
|
||||||
@@ -19,6 +20,8 @@ import com.intellij.util.ui.table.JBTableRowEditor
|
|||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.group.IjOptionConstants
|
import com.maddyhome.idea.vim.group.IjOptionConstants
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.mode.inBlockSelection
|
||||||
import java.awt.Component
|
import java.awt.Component
|
||||||
import javax.swing.JComponent
|
import javax.swing.JComponent
|
||||||
import javax.swing.JTable
|
import javax.swing.JTable
|
||||||
@@ -93,3 +96,41 @@ internal val Caret.vimLine: Int
|
|||||||
*/
|
*/
|
||||||
internal val Editor.vimLine: Int
|
internal val Editor.vimLine: Int
|
||||||
get() = this.caretModel.currentCaret.vimLine
|
get() = this.caretModel.currentCaret.vimLine
|
||||||
|
|
||||||
|
internal inline fun Editor.runWithEveryCaretAndRestore(action: () -> Unit) {
|
||||||
|
val caretModel = this.caretModel
|
||||||
|
val carets = if (this.vim.inBlockSelection) null else caretModel.allCarets
|
||||||
|
if (carets == null || carets.size == 1) {
|
||||||
|
action()
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
var initialDocumentSize = this.document.textLength
|
||||||
|
var documentSizeDifference = 0
|
||||||
|
|
||||||
|
val caretOffsets = carets.map { it.selectionStart to it.selectionEnd }
|
||||||
|
val restoredCarets = mutableListOf<CaretState>()
|
||||||
|
|
||||||
|
caretModel.removeSecondaryCarets()
|
||||||
|
|
||||||
|
for ((selectionStart, selectionEnd) in caretOffsets) {
|
||||||
|
if (selectionStart == selectionEnd) {
|
||||||
|
caretModel.primaryCaret.moveToOffset(selectionStart + documentSizeDifference)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
caretModel.primaryCaret.setSelection(
|
||||||
|
selectionStart + documentSizeDifference,
|
||||||
|
selectionEnd + documentSizeDifference
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
action()
|
||||||
|
restoredCarets.add(caretModel.caretsAndSelections.single())
|
||||||
|
|
||||||
|
val documentLength = this.document.textLength
|
||||||
|
documentSizeDifference += documentLength - initialDocumentSize
|
||||||
|
initialDocumentSize = documentLength
|
||||||
|
}
|
||||||
|
|
||||||
|
caretModel.caretsAndSelections = restoredCarets
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@@ -14,7 +14,6 @@ import com.maddyhome.idea.vim.api.injector
|
|||||||
import com.maddyhome.idea.vim.api.normalizeVisualColumn
|
import com.maddyhome.idea.vim.api.normalizeVisualColumn
|
||||||
import com.maddyhome.idea.vim.api.options
|
import com.maddyhome.idea.vim.api.options
|
||||||
import com.maddyhome.idea.vim.command.CommandFlags
|
import com.maddyhome.idea.vim.command.CommandFlags
|
||||||
import com.maddyhome.idea.vim.state.VimStateMachine
|
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenHeight
|
import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenHeight
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenWidth
|
import com.maddyhome.idea.vim.helper.EditorHelper.getApproximateScreenWidth
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper.getNonNormalizedVisualLineAtBottomOfScreen
|
import com.maddyhome.idea.vim.helper.EditorHelper.getNonNormalizedVisualLineAtBottomOfScreen
|
||||||
@@ -29,6 +28,7 @@ import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToBottomOfScre
|
|||||||
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
|
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToMiddleOfScreen
|
||||||
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
|
import com.maddyhome.idea.vim.helper.EditorHelper.scrollVisualLineToTopOfScreen
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.VimStateMachine
|
||||||
import kotlin.math.max
|
import kotlin.math.max
|
||||||
import kotlin.math.min
|
import kotlin.math.min
|
||||||
import kotlin.math.roundToInt
|
import kotlin.math.roundToInt
|
||||||
@@ -56,7 +56,7 @@ internal object ScrollViewHelper {
|
|||||||
// that this needs to be replaced as a more or less dumb line for line rewrite.
|
// that this needs to be replaced as a more or less dumb line for line rewrite.
|
||||||
val topLine = getVisualLineAtTopOfScreen(editor)
|
val topLine = getVisualLineAtTopOfScreen(editor)
|
||||||
val bottomLine = getVisualLineAtBottomOfScreen(editor)
|
val bottomLine = getVisualLineAtBottomOfScreen(editor)
|
||||||
val lastLine = vimEditor.getVisualLineCount() - 1
|
val lastLine = vimEditor.getVisualLineCount() + editor.settings.additionalLinesCount
|
||||||
|
|
||||||
// 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
|
||||||
val scrollOffset = injector.options(vimEditor).scrolloff
|
val scrollOffset = injector.options(vimEditor).scrolloff
|
||||||
|
@@ -9,6 +9,7 @@
|
|||||||
package com.maddyhome.idea.vim.helper;
|
package com.maddyhome.idea.vim.helper;
|
||||||
|
|
||||||
import com.google.common.collect.Lists;
|
import com.google.common.collect.Lists;
|
||||||
|
import com.intellij.codeInsight.daemon.impl.DaemonCodeAnalyzerEx;
|
||||||
import com.intellij.lang.CodeDocumentationAwareCommenter;
|
import com.intellij.lang.CodeDocumentationAwareCommenter;
|
||||||
import com.intellij.lang.Commenter;
|
import com.intellij.lang.Commenter;
|
||||||
import com.intellij.lang.Language;
|
import com.intellij.lang.Language;
|
||||||
@@ -16,22 +17,30 @@ import com.intellij.lang.LanguageCommenters;
|
|||||||
import com.intellij.openapi.diagnostic.Logger;
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.editor.Caret;
|
import com.intellij.openapi.editor.Caret;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.psi.PsiComment;
|
import com.intellij.psi.PsiComment;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import com.intellij.psi.util.PsiTreeUtil;
|
import com.intellij.psi.util.PsiTreeUtil;
|
||||||
|
import com.intellij.spellchecker.SpellCheckerSeveritiesProvider;
|
||||||
import com.maddyhome.idea.vim.VimPlugin;
|
import com.maddyhome.idea.vim.VimPlugin;
|
||||||
import com.maddyhome.idea.vim.api.EngineEditorHelperKt;
|
import com.maddyhome.idea.vim.api.EngineEditorHelperKt;
|
||||||
import com.maddyhome.idea.vim.api.VimEditor;
|
import com.maddyhome.idea.vim.api.VimEditor;
|
||||||
import com.maddyhome.idea.vim.regexp.*;
|
import com.maddyhome.idea.vim.regexp.*;
|
||||||
import com.maddyhome.idea.vim.regexp.match.VimMatchResult;
|
import com.maddyhome.idea.vim.regexp.match.VimMatchResult;
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode;
|
|
||||||
import com.maddyhome.idea.vim.state.VimStateMachine;
|
|
||||||
import com.maddyhome.idea.vim.common.CharacterPosition;
|
import com.maddyhome.idea.vim.common.CharacterPosition;
|
||||||
import com.maddyhome.idea.vim.common.Direction;
|
import com.maddyhome.idea.vim.common.Direction;
|
||||||
import com.maddyhome.idea.vim.common.TextRange;
|
import com.maddyhome.idea.vim.common.TextRange;
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimCaret;
|
import com.maddyhome.idea.vim.newapi.IjVimCaret;
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
import com.maddyhome.idea.vim.newapi.IjVimEditor;
|
||||||
|
import com.maddyhome.idea.vim.regexp.CharPointer;
|
||||||
|
import com.maddyhome.idea.vim.regexp.RegExp;
|
||||||
|
import com.maddyhome.idea.vim.state.VimStateMachine;
|
||||||
|
import com.maddyhome.idea.vim.state.mode.Mode;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntComparator;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntIterator;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntSortedSet;
|
||||||
import kotlin.Pair;
|
import kotlin.Pair;
|
||||||
import org.jetbrains.annotations.Contract;
|
import org.jetbrains.annotations.Contract;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
@@ -1573,6 +1582,42 @@ public class SearchHelper {
|
|||||||
return PsiHelper.findMethodEnd(editor, caret.getOffset(), count);
|
return PsiHelper.findMethodEnd(editor, caret.getOffset(), count);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int findMisspelledWords(@NotNull Editor editor,
|
||||||
|
int startOffset,
|
||||||
|
int endOffset,
|
||||||
|
int skipCount,
|
||||||
|
IntComparator offsetOrdering) {
|
||||||
|
Project project = editor.getProject();
|
||||||
|
if (project == null) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
IntSortedSet offsets = new IntRBTreeSet(offsetOrdering);
|
||||||
|
DaemonCodeAnalyzerEx.processHighlights(editor.getDocument(), project, SpellCheckerSeveritiesProvider.TYPO,
|
||||||
|
startOffset, endOffset, highlight -> {
|
||||||
|
if (highlight.getSeverity() == SpellCheckerSeveritiesProvider.TYPO) {
|
||||||
|
int offset = highlight.getStartOffset();
|
||||||
|
if (offset >= startOffset && offset <= endOffset) {
|
||||||
|
offsets.add(offset);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (offsets.isEmpty()) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (skipCount >= offsets.size()) {
|
||||||
|
return offsets.lastInt();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
IntIterator offsetIterator = offsets.iterator();
|
||||||
|
offsetIterator.skip(skipCount);
|
||||||
|
return offsetIterator.nextInt();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private static @NotNull String parseMatchPairsOption(final VimEditor vimEditor) {
|
private static @NotNull String parseMatchPairsOption(final VimEditor vimEditor) {
|
||||||
List<String> pairs = options(injector, vimEditor).getMatchpairs();
|
List<String> pairs = options(injector, vimEditor).getMatchpairs();
|
||||||
StringBuilder res = new StringBuilder();
|
StringBuilder res = new StringBuilder();
|
||||||
|
@@ -14,6 +14,7 @@ import com.intellij.openapi.command.CommandProcessor
|
|||||||
import com.intellij.openapi.command.undo.UndoManager
|
import com.intellij.openapi.command.undo.UndoManager
|
||||||
import com.intellij.openapi.components.Service
|
import com.intellij.openapi.components.Service
|
||||||
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
|
import com.intellij.openapi.fileEditor.impl.text.TextEditorProvider
|
||||||
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
@@ -21,6 +22,8 @@ import com.maddyhome.idea.vim.common.ChangesListener
|
|||||||
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
|
import com.maddyhome.idea.vim.listener.SelectionVimListenerSuppressor
|
||||||
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
import com.maddyhome.idea.vim.newapi.globalIjOptions
|
||||||
import com.maddyhome.idea.vim.newapi.ij
|
import com.maddyhome.idea.vim.newapi.ij
|
||||||
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
|
import com.maddyhome.idea.vim.state.mode.inVisualMode
|
||||||
import com.maddyhome.idea.vim.undo.UndoRedoBase
|
import com.maddyhome.idea.vim.undo.UndoRedoBase
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -39,6 +42,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
|
|||||||
|
|
||||||
if (injector.globalIjOptions().oldundo) {
|
if (injector.globalIjOptions().oldundo) {
|
||||||
SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
|
SelectionVimListenerSuppressor.lock().use { undoManager.undo(fileEditor) }
|
||||||
|
restoreVisualMode(editor)
|
||||||
} else {
|
} else {
|
||||||
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
|
// TODO refactor me after VIM-308 when restoring selection and caret movement will be ignored by undo
|
||||||
editor.runWithChangeTracking {
|
editor.runWithChangeTracking {
|
||||||
@@ -74,6 +78,7 @@ internal class UndoRedoHelper : UndoRedoBase() {
|
|||||||
if (undoManager.isRedoAvailable(fileEditor)) {
|
if (undoManager.isRedoAvailable(fileEditor)) {
|
||||||
if (injector.globalIjOptions().oldundo) {
|
if (injector.globalIjOptions().oldundo) {
|
||||||
SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
|
SelectionVimListenerSuppressor.lock().use { undoManager.redo(fileEditor) }
|
||||||
|
restoreVisualMode(editor)
|
||||||
} else {
|
} else {
|
||||||
undoManager.redo(fileEditor)
|
undoManager.redo(fileEditor)
|
||||||
CommandProcessor.getInstance().runUndoTransparentAction {
|
CommandProcessor.getInstance().runUndoTransparentAction {
|
||||||
@@ -131,4 +136,21 @@ internal class UndoRedoHelper : UndoRedoBase() {
|
|||||||
val hasChanges: Boolean
|
val hasChanges: Boolean
|
||||||
get() = changeListener.hasChanged || initialPath != editor.getPath()
|
get() = changeListener.hasChanged || initialPath != editor.getPath()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun restoreVisualMode(editor: VimEditor) {
|
||||||
|
if (!editor.inVisualMode && editor.getSelectionModel().hasSelection()) {
|
||||||
|
val detectedMode = VimPlugin.getVisualMotion().autodetectVisualSubmode(editor)
|
||||||
|
|
||||||
|
// Visual block selection is restored into multiple carets, so multi-carets that form a block are always
|
||||||
|
// identified as visual block mode, leading to false positives.
|
||||||
|
// Since I use visual block mode much less often than multi-carets, this is a judgment call to never restore
|
||||||
|
// visual block mode.
|
||||||
|
val wantedMode = if (detectedMode == SelectionType.BLOCK_WISE)
|
||||||
|
SelectionType.CHARACTER_WISE
|
||||||
|
else
|
||||||
|
detectedMode
|
||||||
|
|
||||||
|
VimPlugin.getVisualMotion().enterVisualMode(editor, wantedMode)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,32 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE.txt file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package com.maddyhome.idea.vim.helper
|
|
||||||
|
|
||||||
import com.intellij.ide.plugins.StandalonePluginUpdateChecker
|
|
||||||
import com.intellij.openapi.components.Service
|
|
||||||
import com.intellij.openapi.components.service
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
|
||||||
import com.maddyhome.idea.vim.group.NotificationService
|
|
||||||
import com.maddyhome.idea.vim.icons.VimIcons
|
|
||||||
|
|
||||||
@Service(Service.Level.APP)
|
|
||||||
internal class VimStandalonePluginUpdateChecker : StandalonePluginUpdateChecker(
|
|
||||||
VimPlugin.getPluginId(),
|
|
||||||
updateTimestampProperty = PROPERTY_NAME,
|
|
||||||
NotificationService.IDEAVIM_STICKY_GROUP,
|
|
||||||
VimIcons.IDEAVIM,
|
|
||||||
) {
|
|
||||||
|
|
||||||
override fun skipUpdateCheck(): Boolean = VimPlugin.isNotEnabled() || "dev" in VimPlugin.getVersion()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private const val PROPERTY_NAME = "ideavim.statistics.timestamp"
|
|
||||||
val instance: VimStandalonePluginUpdateChecker = service()
|
|
||||||
}
|
|
||||||
}
|
|
@@ -27,6 +27,7 @@ import com.intellij.openapi.actionSystem.CommonDataKeys
|
|||||||
import com.intellij.openapi.actionSystem.ex.AnActionListener
|
import com.intellij.openapi.actionSystem.ex.AnActionListener
|
||||||
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
|
import com.intellij.openapi.actionSystem.impl.ProxyShortcutSet
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
|
import com.intellij.openapi.editor.impl.ScrollingModelImpl
|
||||||
import com.intellij.openapi.project.DumbAwareToggleAction
|
import com.intellij.openapi.project.DumbAwareToggleAction
|
||||||
import com.intellij.openapi.util.TextRange
|
import com.intellij.openapi.util.TextRange
|
||||||
import com.maddyhome.idea.vim.KeyHandler
|
import com.maddyhome.idea.vim.KeyHandler
|
||||||
@@ -56,6 +57,7 @@ internal object IdeaSpecifics {
|
|||||||
private val surrounderAction =
|
private val surrounderAction =
|
||||||
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
|
"com.intellij.codeInsight.generation.surroundWith.SurroundWithHandler\$InvokeSurrounderAction"
|
||||||
private var editor: Editor? = null
|
private var editor: Editor? = null
|
||||||
|
private var caretOffset = -1
|
||||||
private var completionPrevDocumentLength: Int? = null
|
private var completionPrevDocumentLength: Int? = null
|
||||||
private var completionPrevDocumentOffset: Int? = null
|
private var completionPrevDocumentOffset: Int? = null
|
||||||
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
|
override fun beforeActionPerformed(action: AnAction, event: AnActionEvent) {
|
||||||
@@ -64,6 +66,7 @@ internal object IdeaSpecifics {
|
|||||||
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
|
val hostEditor = event.dataContext.getData(CommonDataKeys.HOST_EDITOR)
|
||||||
if (hostEditor != null) {
|
if (hostEditor != null) {
|
||||||
editor = hostEditor
|
editor = hostEditor
|
||||||
|
caretOffset = hostEditor.caretModel.offset
|
||||||
}
|
}
|
||||||
|
|
||||||
val isVimAction = (action as? AnActionWrapper)?.delegate is VimShortcutKeyAction
|
val isVimAction = (action as? AnActionWrapper)?.delegate is VimShortcutKeyAction
|
||||||
@@ -95,7 +98,8 @@ internal object IdeaSpecifics {
|
|||||||
if (VimPlugin.isNotEnabled()) return
|
if (VimPlugin.isNotEnabled()) return
|
||||||
|
|
||||||
val editor = editor
|
val editor = editor
|
||||||
if (editor != null && action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) {
|
if (editor != null) {
|
||||||
|
if (action is ChooseItemAction && editor.vimStateMachine?.isRecording == true) {
|
||||||
val prevDocumentLength = completionPrevDocumentLength
|
val prevDocumentLength = completionPrevDocumentLength
|
||||||
val prevDocumentOffset = completionPrevDocumentOffset
|
val prevDocumentOffset = completionPrevDocumentOffset
|
||||||
|
|
||||||
@@ -122,16 +126,28 @@ internal object IdeaSpecifics {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
editor?.let {
|
val commandState = editor.vim.vimStateMachine
|
||||||
val commandState = it.vim.vimStateMachine
|
|
||||||
commandState.mode = Mode.NORMAL()
|
commandState.mode = Mode.NORMAL()
|
||||||
VimPlugin.getChange().insertBeforeCursor(it.vim, event.dataContext.vim)
|
VimPlugin.getChange().insertBeforeCursor(editor.vim, event.dataContext.vim)
|
||||||
KeyHandler.getInstance().reset(it.vim)
|
KeyHandler.getInstance().reset(editor.vim)
|
||||||
}
|
|
||||||
}
|
}
|
||||||
//endregion
|
//endregion
|
||||||
|
|
||||||
|
if (caretOffset != -1 && caretOffset != editor.caretModel.offset) {
|
||||||
|
val scrollModel = editor.scrollingModel as ScrollingModelImpl
|
||||||
|
if (scrollModel.isScrollingNow) {
|
||||||
|
val v = scrollModel.verticalScrollOffset
|
||||||
|
val h = scrollModel.horizontalScrollOffset
|
||||||
|
scrollModel.finishAnimation()
|
||||||
|
scrollModel.scroll(h, v)
|
||||||
|
scrollModel.finishAnimation()
|
||||||
|
}
|
||||||
|
injector.scroll.scrollCaretIntoView(editor.vim)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.editor = null
|
this.editor = null
|
||||||
|
this.caretOffset = -1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -75,7 +75,6 @@ import com.maddyhome.idea.vim.handler.correctorRequester
|
|||||||
import com.maddyhome.idea.vim.handler.keyCheckRequests
|
import com.maddyhome.idea.vim.handler.keyCheckRequests
|
||||||
import com.maddyhome.idea.vim.helper.GuicursorChangeListener
|
import com.maddyhome.idea.vim.helper.GuicursorChangeListener
|
||||||
import com.maddyhome.idea.vim.helper.StrictMode
|
import com.maddyhome.idea.vim.helper.StrictMode
|
||||||
import com.maddyhome.idea.vim.helper.VimStandalonePluginUpdateChecker
|
|
||||||
import com.maddyhome.idea.vim.helper.exitSelectMode
|
import com.maddyhome.idea.vim.helper.exitSelectMode
|
||||||
import com.maddyhome.idea.vim.helper.exitVisualMode
|
import com.maddyhome.idea.vim.helper.exitVisualMode
|
||||||
import com.maddyhome.idea.vim.helper.forceBarCursor
|
import com.maddyhome.idea.vim.helper.forceBarCursor
|
||||||
@@ -92,6 +91,8 @@ 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.add
|
||||||
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
import com.maddyhome.idea.vim.newapi.IjVimEditor
|
||||||
import com.maddyhome.idea.vim.newapi.vim
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.VimStateMachine
|
||||||
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.state.mode.inSelectMode
|
import com.maddyhome.idea.vim.state.mode.inSelectMode
|
||||||
import com.maddyhome.idea.vim.state.mode.mode
|
import com.maddyhome.idea.vim.state.mode.mode
|
||||||
import com.maddyhome.idea.vim.state.mode.selectionType
|
import com.maddyhome.idea.vim.state.mode.selectionType
|
||||||
@@ -305,6 +306,16 @@ internal object VimListenerManager {
|
|||||||
class VimFileEditorManagerListener : FileEditorManagerListener {
|
class VimFileEditorManagerListener : FileEditorManagerListener {
|
||||||
override fun selectionChanged(event: FileEditorManagerEvent) {
|
override fun selectionChanged(event: FileEditorManagerEvent) {
|
||||||
if (VimPlugin.isNotEnabled()) return
|
if (VimPlugin.isNotEnabled()) return
|
||||||
|
|
||||||
|
val newEditor = event.newEditor
|
||||||
|
if (newEditor is TextEditor) {
|
||||||
|
val editor = newEditor.editor
|
||||||
|
if (editor.isInsertMode) {
|
||||||
|
VimStateMachine.getInstance(editor).mode = Mode.NORMAL()
|
||||||
|
KeyHandler.getInstance().reset(editor.vim)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
|
MotionGroup.fileEditorManagerSelectionChangedCallback(event)
|
||||||
FileGroup.fileEditorManagerSelectionChangedCallback(event)
|
FileGroup.fileEditorManagerSelectionChangedCallback(event)
|
||||||
VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
|
VimPlugin.getSearch().fileEditorManagerSelectionChangedCallback(event)
|
||||||
@@ -369,8 +380,6 @@ internal object VimListenerManager {
|
|||||||
|
|
||||||
event.editor.putUserData(openingEditorKey, OpeningEditor(openingEditor, owningEditorWindow, isPreview, canBeReused))
|
event.editor.putUserData(openingEditorKey, OpeningEditor(openingEditor, owningEditorWindow, isPreview, canBeReused))
|
||||||
}
|
}
|
||||||
|
|
||||||
VimStandalonePluginUpdateChecker.instance.pluginUsed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun editorReleased(event: EditorFactoryEvent) {
|
override fun editorReleased(event: EditorFactoryEvent) {
|
||||||
|
@@ -32,7 +32,7 @@ import com.maddyhome.idea.vim.vimscript.parser.VimscriptParser.parseExpression
|
|||||||
import org.jetbrains.annotations.TestOnly
|
import org.jetbrains.annotations.TestOnly
|
||||||
import javax.swing.KeyStroke
|
import javax.swing.KeyStroke
|
||||||
|
|
||||||
public open class IjVimSearchGroup : VimSearchGroupBase() {
|
public abstract class IjVimSearchGroup : VimSearchGroupBase() {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
// TODO: Investigate migrating these listeners to use the effective value change listener
|
// TODO: Investigate migrating these listeners to use the effective value change listener
|
||||||
|
@@ -29,6 +29,8 @@ import com.maddyhome.idea.vim.helper.checkInString
|
|||||||
import com.maddyhome.idea.vim.helper.fileSize
|
import com.maddyhome.idea.vim.helper.fileSize
|
||||||
import com.maddyhome.idea.vim.state.VimStateMachine.Companion.getInstance
|
import com.maddyhome.idea.vim.state.VimStateMachine.Companion.getInstance
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
|
import com.maddyhome.idea.vim.state.mode.Mode.VISUAL
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntComparator
|
||||||
|
import it.unimi.dsi.fastutil.ints.IntComparators
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import java.util.function.Function
|
import java.util.function.Function
|
||||||
import java.util.regex.Pattern
|
import java.util.regex.Pattern
|
||||||
@@ -689,4 +691,26 @@ internal class IjVimSearchHelper : VimSearchHelperBase() {
|
|||||||
// End offset exclusive
|
// End offset exclusive
|
||||||
return TextRange(bstart, bend + 1)
|
return TextRange(bstart, bend + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun findMisspelledWord(editor: VimEditor, caret: ImmutableVimCaret, count: Int): Int {
|
||||||
|
val startOffset: Int
|
||||||
|
val endOffset: Int
|
||||||
|
val skipCount: Int
|
||||||
|
val offsetOrdering: IntComparator
|
||||||
|
|
||||||
|
if (count < 0) {
|
||||||
|
startOffset = 0
|
||||||
|
endOffset = caret.offset.point - 1
|
||||||
|
skipCount = -count - 1
|
||||||
|
offsetOrdering = IntComparators.OPPOSITE_COMPARATOR
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
startOffset = caret.offset.point + 1
|
||||||
|
endOffset = editor.ij.document.textLength
|
||||||
|
skipCount = count - 1
|
||||||
|
offsetOrdering = IntComparators.NATURAL_COMPARATOR
|
||||||
|
}
|
||||||
|
|
||||||
|
return SearchHelper.findMisspelledWords(editor.ij, startOffset, endOffset, skipCount, offsetOrdering)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -333,7 +333,7 @@
|
|||||||
* |[m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
|
* |[m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodPreviousStartAction}
|
||||||
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
|
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
|
||||||
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
|
* |[p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
|
||||||
* |[s| TO BE IMPLEMENTED
|
* |[s| {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordPreviousAction}
|
||||||
* |[z| TO BE IMPLEMENTED
|
* |[z| TO BE IMPLEMENTED
|
||||||
* |[{| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
|
* |[{| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceOpenAction}
|
||||||
* |]_CTRL-D| TO BE IMPLEMENTED
|
* |]_CTRL-D| TO BE IMPLEMENTED
|
||||||
@@ -358,7 +358,7 @@
|
|||||||
* |]m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
|
* |]m| {@link com.maddyhome.idea.vim.action.motion.text.MotionMethodNextStartAction}
|
||||||
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
|
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutVisualTextAfterCursorNoIndentAction}
|
||||||
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
|
* |]p| {@link com.maddyhome.idea.vim.action.copy.PutTextAfterCursorNoIndentAction}
|
||||||
* |]s| TO BE IMPLEMENTED
|
* |]s| {@link com.maddyhome.idea.vim.action.motion.text.MotionMisspelledWordNextAction}
|
||||||
* |]z| TO BE IMPLEMENTED
|
* |]z| TO BE IMPLEMENTED
|
||||||
* |]}| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
|
* |]}| {@link com.maddyhome.idea.vim.action.motion.text.MotionUnmatchedBraceCloseAction}
|
||||||
*
|
*
|
||||||
|
@@ -1,12 +1,4 @@
|
|||||||
<!--
|
<idea-plugin xmlns:xi="http://www.w3.org/2001/XInclude">
|
||||||
~ Copyright 2003-2023 The IdeaVim authors
|
|
||||||
~
|
|
||||||
~ Use of this source code is governed by an MIT-style
|
|
||||||
~ license that can be found in the LICENSE.txt file or at
|
|
||||||
~ https://opensource.org/licenses/MIT.
|
|
||||||
-->
|
|
||||||
|
|
||||||
<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>
|
||||||
<description><![CDATA[
|
<description><![CDATA[
|
||||||
@@ -21,13 +13,13 @@
|
|||||||
<li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li>
|
<li><a href="https://youtrack.jetbrains.com/issues/VIM">Issue tracker</a>: feature requests and bug reports</li>
|
||||||
</ul>
|
</ul>
|
||||||
]]></description>
|
]]></description>
|
||||||
<version>SNAPSHOT</version>
|
<version>chylex</version>
|
||||||
<vendor>JetBrains</vendor>
|
<vendor>JetBrains</vendor>
|
||||||
|
|
||||||
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
|
<!-- Please search for "[VERSION UPDATE]" in project in case you update the since-build version -->
|
||||||
<!-- Check for [Version Update] tag in YouTrack as well -->
|
<!-- Check for [Version Update] tag in YouTrack as well -->
|
||||||
<!-- Also, please update the value in build.gradle.kts file-->
|
<!-- Also, please update the value in build.gradle.kts file-->
|
||||||
<idea-version since-build="233.11799.30"/>
|
<idea-version since-build="232"/>
|
||||||
|
|
||||||
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
|
<!-- Mark the plugin as compatible with RubyMine and other products based on the IntelliJ platform (including CWM) -->
|
||||||
<depends>com.intellij.modules.platform</depends>
|
<depends>com.intellij.modules.platform</depends>
|
||||||
@@ -158,5 +150,6 @@
|
|||||||
</group>
|
</group>
|
||||||
|
|
||||||
<action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
|
<action id="VimFindActionIdAction" class="com.maddyhome.idea.vim.listener.FindActionIdAction"/>
|
||||||
|
<action id="VimJumpToSource" class="com.intellij.diff.actions.impl.OpenInEditorAction" />
|
||||||
</actions>
|
</actions>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
|
@@ -12,8 +12,9 @@ package org.jetbrains.plugins.ideavim.action.motion.gn
|
|||||||
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
import com.maddyhome.idea.vim.common.Direction
|
import com.maddyhome.idea.vim.common.Direction
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
@@ -85,7 +86,7 @@ class GnNextTextObjectTest : VimTestCase() {
|
|||||||
|
|
||||||
private fun doTestWithSearch(keys: List<KeyStroke>, before: String, after: String) {
|
private fun doTestWithSearch(keys: List<KeyStroke>, before: String, after: String) {
|
||||||
configureByText(before)
|
configureByText(before)
|
||||||
VimPlugin.getSearch().setLastSearchState(fixture.editor, "test", "", Direction.FORWARDS)
|
VimPlugin.getSearch().setLastSearchState(fixture.editor.vim, "test", "", Direction.FORWARDS)
|
||||||
typeText(keys)
|
typeText(keys)
|
||||||
assertState(after)
|
assertState(after)
|
||||||
assertState(Mode.NORMAL())
|
assertState(Mode.NORMAL())
|
||||||
|
@@ -12,8 +12,9 @@ package org.jetbrains.plugins.ideavim.action.motion.gn
|
|||||||
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
|
||||||
import com.maddyhome.idea.vim.common.Direction
|
import com.maddyhome.idea.vim.common.Direction
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
@@ -63,7 +64,7 @@ class GnPreviousTextObjectTest : VimTestCase() {
|
|||||||
|
|
||||||
private fun doTestWithSearch(keys: List<KeyStroke>, before: String, after: String) {
|
private fun doTestWithSearch(keys: List<KeyStroke>, before: String, after: String) {
|
||||||
configureByText(before)
|
configureByText(before)
|
||||||
VimPlugin.getSearch().setLastSearchState(fixture.editor, "test", "", Direction.FORWARDS)
|
VimPlugin.getSearch().setLastSearchState(fixture.editor.vim, "test", "", Direction.FORWARDS)
|
||||||
typeText(keys)
|
typeText(keys)
|
||||||
assertState(after)
|
assertState(after)
|
||||||
assertState(Mode.NORMAL())
|
assertState(Mode.NORMAL())
|
||||||
|
@@ -11,9 +11,10 @@ import com.intellij.idea.TestFor
|
|||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
|
import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.common.Direction
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.common.Direction
|
|
||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
@@ -57,7 +58,7 @@ class VisualSelectNextSearchTest : VimTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun testWithoutSpaces() {
|
fun testWithoutSpaces() {
|
||||||
configureByText("test<caret>test")
|
configureByText("test<caret>test")
|
||||||
VimPlugin.getSearch().setLastSearchState(fixture.editor, "test", "", Direction.FORWARDS)
|
VimPlugin.getSearch().setLastSearchState(fixture.editor.vim, "test", "", Direction.FORWARDS)
|
||||||
typeText(injector.parser.parseKeys("gn"))
|
typeText(injector.parser.parseKeys("gn"))
|
||||||
assertOffset(7)
|
assertOffset(7)
|
||||||
assertSelection("test")
|
assertSelection("test")
|
||||||
|
@@ -11,9 +11,10 @@ import com.intellij.idea.TestFor
|
|||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
|
import com.maddyhome.idea.vim.action.motion.search.SearchWholeWordForwardAction
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
|
import com.maddyhome.idea.vim.common.Direction
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import com.maddyhome.idea.vim.state.mode.SelectionType
|
import com.maddyhome.idea.vim.state.mode.SelectionType
|
||||||
import com.maddyhome.idea.vim.common.Direction
|
|
||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
@@ -54,7 +55,7 @@ class VisualSelectPreviousSearchTest : VimTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun testWithoutSpaces() {
|
fun testWithoutSpaces() {
|
||||||
configureByText("tes<caret>ttest")
|
configureByText("tes<caret>ttest")
|
||||||
VimPlugin.getSearch().setLastSearchState(fixture.editor, "test", "", Direction.FORWARDS)
|
VimPlugin.getSearch().setLastSearchState(fixture.editor.vim, "test", "", Direction.FORWARDS)
|
||||||
typeText(injector.parser.parseKeys("gN"))
|
typeText(injector.parser.parseKeys("gN"))
|
||||||
assertOffset(0)
|
assertOffset(0)
|
||||||
assertSelection("test")
|
assertSelection("test")
|
||||||
|
@@ -10,6 +10,7 @@ package org.jetbrains.plugins.ideavim.action.motion.search
|
|||||||
|
|
||||||
import com.maddyhome.idea.vim.VimPlugin
|
import com.maddyhome.idea.vim.VimPlugin
|
||||||
import com.maddyhome.idea.vim.common.Direction
|
import com.maddyhome.idea.vim.common.Direction
|
||||||
|
import com.maddyhome.idea.vim.newapi.vim
|
||||||
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
import org.jetbrains.plugins.ideavim.SkipNeovimReason
|
||||||
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
import org.jetbrains.plugins.ideavim.TestWithoutNeovim
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
@@ -167,7 +168,7 @@ class SearchAgainPreviousActionTest : VimTestCase() {
|
|||||||
|
|
||||||
private fun doTestWithSearch(keys: String, before: String, after: String) {
|
private fun doTestWithSearch(keys: String, before: String, after: String) {
|
||||||
doTest(keys, before, after) {
|
doTest(keys, before, after) {
|
||||||
VimPlugin.getSearch().setLastSearchState(it, "all", "", Direction.FORWARDS)
|
VimPlugin.getSearch().setLastSearchState(it.vim, "all", "", Direction.FORWARDS)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -23,7 +23,7 @@ class BasicStringFunctions : VimTestCase() {
|
|||||||
@Test
|
@Test
|
||||||
fun `test tolower`() {
|
fun `test tolower`() {
|
||||||
configureByText("\n")
|
configureByText("\n")
|
||||||
typeText(commandToKeys("echo toupper('Vim is awesome')"))
|
typeText(commandToKeys("echo tolower('Vim is awesome')"))
|
||||||
assertExOutput("vim is awesome\n")
|
assertExOutput("vim is awesome\n")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.plugins.ideavim.extension.sneak
|
package org.jetbrains.plugins.ideavim.extension.sneak
|
||||||
|
|
||||||
|
import com.maddyhome.idea.vim.api.keys
|
||||||
import com.maddyhome.idea.vim.state.mode.Mode
|
import com.maddyhome.idea.vim.state.mode.Mode
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
@@ -162,4 +163,26 @@ class IdeaVimSneakTest : VimTestCase() {
|
|||||||
|
|
||||||
doTest("sa<ESC>sdw", before, after, Mode.NORMAL())
|
doTest("sa<ESC>sdw", before, after, Mode.NORMAL())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSneakForwardFromMapping() {
|
||||||
|
val before = "som${c}e text"
|
||||||
|
val after = "some te${c}xt"
|
||||||
|
|
||||||
|
doTest("fxt", before, after, Mode.NORMAL()) {
|
||||||
|
// This should be fixed, but now we process `<Plug>` as a single key
|
||||||
|
typeText(keys(":map f <") + keys("Plug>Sneak_s<CR>"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testSneakForwardFromMappingWithOldMappings() {
|
||||||
|
val before = "som${c}e text"
|
||||||
|
val after = "some te${c}xt"
|
||||||
|
|
||||||
|
doTest("fxt", before, after, Mode.NORMAL()) {
|
||||||
|
// This should be fixed, but now we process `<Plug>` as a single key
|
||||||
|
typeText(keys(":map f <") + keys("Plug>(sneak-s)<CR>"))
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2003-2024 The IdeaVim authors
|
|
||||||
*
|
|
||||||
* Use of this source code is governed by an MIT-style
|
|
||||||
* license that can be found in the LICENSE.txt file or at
|
|
||||||
* https://opensource.org/licenses/MIT.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package ui
|
|
||||||
|
|
||||||
import com.automation.remarks.junit5.Video
|
|
||||||
import com.intellij.remoterobot.steps.CommonSteps
|
|
||||||
import org.junit.jupiter.api.AfterAll
|
|
||||||
import org.junit.jupiter.api.BeforeAll
|
|
||||||
import org.junit.jupiter.api.Disabled
|
|
||||||
import org.junit.jupiter.api.Test
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
|
||||||
|
|
||||||
class PyCharmTest {
|
|
||||||
init {
|
|
||||||
// StepsLogger.init()
|
|
||||||
}
|
|
||||||
|
|
||||||
private lateinit var commonSteps: CommonSteps
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
private var ideaProcess: Process? = null
|
|
||||||
private var tmpDir: Path = Files.createTempDirectory("launcher")
|
|
||||||
|
|
||||||
@BeforeAll
|
|
||||||
@JvmStatic
|
|
||||||
fun beforeAll() {
|
|
||||||
// val client = OkHttpClient()
|
|
||||||
// val ideDownloader = IdeDownloader(client)
|
|
||||||
// val downloadedIdePath = ideDownloader.downloadAndExtractLatestEap(Ide.PYCHARM, tmpDir)
|
|
||||||
// // This hack doesn't work because it breaks .app. Waiting for the new version of robot with the fix.
|
|
||||||
//// if (Os.hostOS() == Os.MAC) {
|
|
||||||
//// // Hack for the problem of double vmoptions file
|
|
||||||
//// // The ides now have two vmoptions files: one for ide itself and one for jetbrains client
|
|
||||||
//// // Because of some reason, when ide detects more than one vmoptions file, it tries to find one that ends on
|
|
||||||
//// // "64". And since it doesn't find one, the robot fails.
|
|
||||||
//// val dataPath = downloadedIdePath.resolve("Contents/bin")
|
|
||||||
//// Files.list(dataPath).filter {
|
|
||||||
//// it.fileName.toString().endsWith("jetbrains_client.vmoptions")
|
|
||||||
//// }.forEach { Files.delete(it) }
|
|
||||||
//// }
|
|
||||||
// ideaProcess = IdeLauncher.launchIde(
|
|
||||||
// downloadedIdePath,
|
|
||||||
// mapOf("robot-server.port" to 8083),
|
|
||||||
// emptyList(),
|
|
||||||
// listOf(ideDownloader.downloadRobotPlugin(tmpDir)),
|
|
||||||
// tmpDir
|
|
||||||
// )
|
|
||||||
}
|
|
||||||
|
|
||||||
@AfterAll
|
|
||||||
@JvmStatic
|
|
||||||
fun cleanUp() {
|
|
||||||
// ideaProcess?.destroy()
|
|
||||||
// tmpDir.toFile().deleteRecursively()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
@Video
|
|
||||||
@Disabled("Waiting for the new version of the robot with fixes")
|
|
||||||
fun run() {
|
|
||||||
println("Hey")
|
|
||||||
}
|
|
||||||
}
|
|
@@ -31,7 +31,7 @@ import com.maddyhome.idea.vim.state.mode.toVimNotation
|
|||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.jupiter.api.TestInfo
|
import org.junit.jupiter.api.TestInfo
|
||||||
|
|
||||||
internal object NeovimTesting {
|
object NeovimTesting {
|
||||||
private lateinit var neovimApi: NeovimApi
|
private lateinit var neovimApi: NeovimApi
|
||||||
private lateinit var neovim: Process
|
private lateinit var neovim: Process
|
||||||
|
|
||||||
@@ -88,7 +88,7 @@ internal object NeovimTesting {
|
|||||||
val noBehaviourDiffers = !method.isAnnotationPresent(VimBehaviorDiffers::class.java)
|
val noBehaviourDiffers = !method.isAnnotationPresent(VimBehaviorDiffers::class.java)
|
||||||
val noTestingWithoutNeovim = !method.isAnnotationPresent(TestWithoutNeovim::class.java) &&
|
val noTestingWithoutNeovim = !method.isAnnotationPresent(TestWithoutNeovim::class.java) &&
|
||||||
!test.javaClass.isAnnotationPresent(TestWithoutNeovim::class.java)
|
!test.javaClass.isAnnotationPresent(TestWithoutNeovim::class.java)
|
||||||
val neovimTestingEnabled = System.getProperty("ideavim.nvim.test", "false")!!.toBoolean()
|
val neovimTestingEnabled = isNeovimTestingEnabled()
|
||||||
val notParserTest = "org.jetbrains.plugins.ideavim.ex.parser" !in test.javaClass.packageName
|
val notParserTest = "org.jetbrains.plugins.ideavim.ex.parser" !in test.javaClass.packageName
|
||||||
val notScriptImplementation = "org.jetbrains.plugins.ideavim.ex.implementation" !in test.javaClass.packageName
|
val notScriptImplementation = "org.jetbrains.plugins.ideavim.ex.implementation" !in test.javaClass.packageName
|
||||||
val notExtension = "org.jetbrains.plugins.ideavim.extension" !in test.javaClass.packageName
|
val notExtension = "org.jetbrains.plugins.ideavim.extension" !in test.javaClass.packageName
|
||||||
@@ -104,6 +104,12 @@ internal object NeovimTesting {
|
|||||||
singleCaret
|
singleCaret
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun isNeovimTestingEnabled(): Boolean {
|
||||||
|
val property = System.getProperty("ideavim.nvim.test", "false")
|
||||||
|
val neovimTestingEnabled = if (property.isBlank()) true else property.toBoolean()
|
||||||
|
return neovimTestingEnabled
|
||||||
|
}
|
||||||
|
|
||||||
fun setupEditor(editor: Editor, test: TestInfo) {
|
fun setupEditor(editor: Editor, test: TestInfo) {
|
||||||
if (!neovimEnabled(test, editor)) return
|
if (!neovimEnabled(test, editor)) return
|
||||||
neovimApi.currentBuffer.get().setLines(0, -1, false, editor.document.text.split("\n")).get()
|
neovimApi.currentBuffer.get().setLines(0, -1, false, editor.document.text.split("\n")).get()
|
||||||
|
@@ -80,6 +80,7 @@ import com.maddyhome.idea.vim.vimscript.model.datatypes.VimFuncref
|
|||||||
import com.maddyhome.idea.vim.vimscript.parser.errors.IdeavimErrorListener
|
import com.maddyhome.idea.vim.vimscript.parser.errors.IdeavimErrorListener
|
||||||
import org.jetbrains.annotations.ApiStatus
|
import org.jetbrains.annotations.ApiStatus
|
||||||
import org.junit.jupiter.api.AfterEach
|
import org.junit.jupiter.api.AfterEach
|
||||||
|
import org.junit.jupiter.api.BeforeAll
|
||||||
import org.junit.jupiter.api.BeforeEach
|
import org.junit.jupiter.api.BeforeEach
|
||||||
import org.junit.jupiter.api.TestInfo
|
import org.junit.jupiter.api.TestInfo
|
||||||
import org.junit.jupiter.api.assertThrows
|
import org.junit.jupiter.api.assertThrows
|
||||||
@@ -105,7 +106,7 @@ import kotlin.test.assertTrue
|
|||||||
abstract class VimTestCase {
|
abstract class VimTestCase {
|
||||||
protected lateinit var fixture: CodeInsightTestFixture
|
protected lateinit var fixture: CodeInsightTestFixture
|
||||||
|
|
||||||
internal lateinit var testInfo: TestInfo
|
lateinit var testInfo: TestInfo
|
||||||
|
|
||||||
@BeforeEach
|
@BeforeEach
|
||||||
open fun setUp(testInfo: TestInfo) {
|
open fun setUp(testInfo: TestInfo) {
|
||||||
@@ -800,6 +801,12 @@ abstract class VimTestCase {
|
|||||||
const val s = EditorTestUtil.SELECTION_START_TAG
|
const val s = EditorTestUtil.SELECTION_START_TAG
|
||||||
const val se = EditorTestUtil.SELECTION_END_TAG
|
const val se = EditorTestUtil.SELECTION_END_TAG
|
||||||
|
|
||||||
|
@BeforeAll
|
||||||
|
@JvmStatic
|
||||||
|
fun beforeAll() {
|
||||||
|
println("Neovim testing: ${NeovimTesting.isNeovimTestingEnabled()}")
|
||||||
|
}
|
||||||
|
|
||||||
fun typeText(keys: List<KeyStroke?>, editor: Editor, project: Project?) {
|
fun typeText(keys: List<KeyStroke?>, editor: Editor, project: Project?) {
|
||||||
val keyHandler = KeyHandler.getInstance()
|
val keyHandler = KeyHandler.getInstance()
|
||||||
val dataContext = injector.executionContextManager.onEditor(editor.vim)
|
val dataContext = injector.executionContextManager.onEditor(editor.vim)
|
||||||
|
@@ -12,13 +12,6 @@ plugins {
|
|||||||
id("org.jetbrains.intellij")
|
id("org.jetbrains.intellij")
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "org.example"
|
|
||||||
version = "SNAPSHOT"
|
|
||||||
|
|
||||||
repositories {
|
|
||||||
mavenCentral()
|
|
||||||
}
|
|
||||||
|
|
||||||
val kotlinVersion: String by project
|
val kotlinVersion: String by project
|
||||||
val ideaVersion: String by project
|
val ideaVersion: String by project
|
||||||
val javaVersion: String by project
|
val javaVersion: String by project
|
||||||
@@ -29,17 +22,30 @@ repositories {
|
|||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
|
||||||
testImplementation(platform("org.junit:junit-bom:5.10.0"))
|
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter")
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
||||||
testImplementation(testFixtures(project(":"))) // The root project
|
testImplementation(testFixtures(project(":"))) // The root project
|
||||||
}
|
}
|
||||||
|
|
||||||
tasks.test {
|
tasks {
|
||||||
|
test {
|
||||||
useJUnitPlatform()
|
useJUnitPlatform()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
verifyPlugin {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
publishPlugin {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
runIde {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
intellij {
|
intellij {
|
||||||
version.set(ideaVersion)
|
version.set(ideaVersion)
|
||||||
type.set("IC")
|
type.set("IC")
|
||||||
|
65
tests/long-running-tests/build.gradle.kts
Normal file
65
tests/long-running-tests/build.gradle.kts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
plugins {
|
||||||
|
java
|
||||||
|
kotlin("jvm")
|
||||||
|
id("org.jetbrains.intellij")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri("https://cache-redirector.jetbrains.com/intellij-dependencies") }
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinVersion: String by project
|
||||||
|
val ideaVersion: String by project
|
||||||
|
val javaVersion: String by project
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
||||||
|
testImplementation(testFixtures(project(":"))) // The root project
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
// This task is disabled because it should be excluded from `gradle test` run (because it's slow)
|
||||||
|
// I didn't find a better way to exclude except disabling and defining a new task with a different name
|
||||||
|
test {
|
||||||
|
enabled = false
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
register<Test>("testLongRunning") {
|
||||||
|
group = "verification"
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyPlugin {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
publishPlugin {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
runIde {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intellij {
|
||||||
|
version.set(ideaVersion)
|
||||||
|
type.set("IC")
|
||||||
|
plugins.set(listOf("java"))
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
||||||
@@ -16,7 +16,6 @@ import org.jetbrains.plugins.ideavim.VimTestCase
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
class MacroTest : VimTestCase() {
|
class MacroTest : VimTestCase() {
|
||||||
|
|
||||||
// was a problem on revision affec9bb61ea5e1e635673a0041d61f7af3722b2
|
// was a problem on revision affec9bb61ea5e1e635673a0041d61f7af3722b2
|
||||||
@TestWithoutNeovim(reason = SkipNeovimReason.NOT_VIM_TESTING)
|
@TestWithoutNeovim(reason = SkipNeovimReason.NOT_VIM_TESTING)
|
||||||
@Test
|
@Test
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
||||||
@@ -15,7 +15,6 @@ import org.jetbrains.plugins.ideavim.VimTestCase
|
|||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
|
|
||||||
class MapCommandTest : VimTestCase() {
|
class MapCommandTest : VimTestCase() {
|
||||||
|
|
||||||
@TestWithoutNeovim(reason = SkipNeovimReason.NOT_VIM_TESTING)
|
@TestWithoutNeovim(reason = SkipNeovimReason.NOT_VIM_TESTING)
|
||||||
@Test
|
@Test
|
||||||
fun `test double recursion`() {
|
fun `test double recursion`() {
|
65
tests/property-tests/build.gradle.kts
Normal file
65
tests/property-tests/build.gradle.kts
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
plugins {
|
||||||
|
java
|
||||||
|
kotlin("jvm")
|
||||||
|
id("org.jetbrains.intellij")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri("https://cache-redirector.jetbrains.com/intellij-dependencies") }
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinVersion: String by project
|
||||||
|
val ideaVersion: String by project
|
||||||
|
val javaVersion: String by project
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
||||||
|
testImplementation(testFixtures(project(":"))) // The root project
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
// This task is disabled because it should be excluded from `gradle test` run (because it's slow)
|
||||||
|
// I didn't find a better way to exclude except disabling and defining a new task with a different name
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
register<Test>("testPropertyBased") {
|
||||||
|
group = "verification"
|
||||||
|
useJUnitPlatform()
|
||||||
|
}
|
||||||
|
|
||||||
|
verifyPlugin {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
publishPlugin {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
runIde {
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
intellij {
|
||||||
|
version.set(ideaVersion)
|
||||||
|
type.set("IC")
|
||||||
|
plugins.set(listOf("java"))
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
||||||
@@ -11,7 +11,6 @@ package org.jetbrains.plugins.ideavim.propertybased
|
|||||||
import com.intellij.ide.IdeEventQueue
|
import com.intellij.ide.IdeEventQueue
|
||||||
import com.intellij.openapi.editor.Editor
|
import com.intellij.openapi.editor.Editor
|
||||||
import com.intellij.testFramework.PlatformTestUtil
|
import com.intellij.testFramework.PlatformTestUtil
|
||||||
import com.maddyhome.idea.vim.action.change.LazyVimCommand
|
|
||||||
import com.maddyhome.idea.vim.api.injector
|
import com.maddyhome.idea.vim.api.injector
|
||||||
import com.maddyhome.idea.vim.helper.vimStateMachine
|
import com.maddyhome.idea.vim.helper.vimStateMachine
|
||||||
import com.maddyhome.idea.vim.key.CommandNode
|
import com.maddyhome.idea.vim.key.CommandNode
|
||||||
@@ -20,8 +19,8 @@ import org.jetbrains.jetCheck.Generator
|
|||||||
import org.jetbrains.jetCheck.ImperativeCommand
|
import org.jetbrains.jetCheck.ImperativeCommand
|
||||||
import org.jetbrains.jetCheck.PropertyChecker
|
import org.jetbrains.jetCheck.PropertyChecker
|
||||||
import org.jetbrains.plugins.ideavim.VimTestCase
|
import org.jetbrains.plugins.ideavim.VimTestCase
|
||||||
|
import org.jetbrains.plugins.ideavim.propertybased.samples.javaText
|
||||||
import org.jetbrains.plugins.ideavim.propertybased.samples.loremText
|
import org.jetbrains.plugins.ideavim.propertybased.samples.loremText
|
||||||
import org.junit.jupiter.api.Disabled
|
|
||||||
import org.junit.jupiter.api.Test
|
import org.junit.jupiter.api.Test
|
||||||
import java.awt.event.KeyEvent
|
import java.awt.event.KeyEvent
|
||||||
import javax.swing.KeyStroke
|
import javax.swing.KeyStroke
|
||||||
@@ -63,19 +62,18 @@ class RandomActionsPropertyTest : VimPropertyTestBase() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
@Disabled
|
|
||||||
fun testRandomActionsOnJavaCode() {
|
fun testRandomActionsOnJavaCode() {
|
||||||
// PropertyChecker.checkScenarios {
|
PropertyChecker.checkScenarios {
|
||||||
// ImperativeCommand { env ->
|
ImperativeCommand { env ->
|
||||||
// val editor = configureByJavaText(javaText)
|
val editor = configureByJavaText(javaText)
|
||||||
// try {
|
try {
|
||||||
// moveCaretToRandomPlace(env, editor)
|
moveCaretToRandomPlace(env, editor)
|
||||||
// env.executeCommands(Generator.sampledFrom(AvailableActions(editor)))
|
env.executeCommands(Generator.sampledFrom(AvailableActions(editor)))
|
||||||
// } finally {
|
} finally {
|
||||||
// reset(editor)
|
reset(editor)
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@@ -100,7 +98,7 @@ private class AvailableActions(private val editor: Editor) : ImperativeCommand {
|
|||||||
val usedKey = env.generateValue(keyGenerator, null)
|
val usedKey = env.generateValue(keyGenerator, null)
|
||||||
val node = currentNode[usedKey]
|
val node = currentNode[usedKey]
|
||||||
|
|
||||||
env.logMessage("Use command: ${injector.parser.toKeyNotation(usedKey)}. ${if (node is CommandNode) "Action: ${(node.actionHolder as LazyVimCommand).actionId}" else ""}")
|
env.logMessage("Use command: ${injector.parser.toKeyNotation(usedKey)}. ${if (node is CommandNode) "Action: ${node.actionHolder.actionId}" else ""}")
|
||||||
VimTestCase.typeText(listOf(usedKey), editor, editor.project)
|
VimTestCase.typeText(listOf(usedKey), editor, editor.project)
|
||||||
|
|
||||||
IdeEventQueue.getInstance().flushQueue()
|
IdeEventQueue.getInstance().flushQueue()
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
||||||
@@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.plugins.ideavim.propertybased
|
package org.jetbrains.plugins.ideavim.propertybased
|
||||||
|
|
||||||
|
import com.intellij.ide.highlighter.JavaFileType
|
||||||
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.VimPlugin
|
||||||
@@ -35,4 +36,6 @@ abstract class VimPropertyTestBase : VimTestCase() {
|
|||||||
VimPlugin.getSearch().resetState()
|
VimPlugin.getSearch().resetState()
|
||||||
VimPlugin.getChange().reset()
|
VimPlugin.getChange().reset()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected fun configureByJavaText(content: String) = configureByText(JavaFileType.INSTANCE, content)
|
||||||
}
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
47
tests/ui-fixtures/build.gradle.kts
Normal file
47
tests/ui-fixtures/build.gradle.kts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
plugins {
|
||||||
|
java
|
||||||
|
kotlin("jvm")
|
||||||
|
id("java-test-fixtures")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri("https://cache-redirector.jetbrains.com/intellij-dependencies") }
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinVersion: String by project
|
||||||
|
val ideaVersion: String by project
|
||||||
|
val javaVersion: String by project
|
||||||
|
val remoteRobotVersion: String by project
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testFixturesImplementation("org.junit.jupiter:junit-jupiter:5.10.1")
|
||||||
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
|
testFixturesImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
||||||
|
testFixturesImplementation(testFixtures(project(":"))) // The root project
|
||||||
|
|
||||||
|
testFixturesImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion")
|
||||||
|
testFixturesImplementation("com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion")
|
||||||
|
testFixturesImplementation("com.intellij.remoterobot:ide-launcher:$remoteRobotVersion")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
// This task is disabled because it should be excluded from `gradle test` run (because it's slow)
|
||||||
|
// I didn't find a better way to exclude except disabling and defining a new task with a different name
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
57
tests/ui-ij-tests/build.gradle.kts
Normal file
57
tests/ui-ij-tests/build.gradle.kts
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
plugins {
|
||||||
|
java
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri("https://cache-redirector.jetbrains.com/intellij-dependencies") }
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinVersion: String by project
|
||||||
|
val ideaVersion: String by project
|
||||||
|
val javaVersion: String by project
|
||||||
|
val remoteRobotVersion: String by project
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
||||||
|
testImplementation(testFixtures(project(":"))) // The root project
|
||||||
|
testImplementation(testFixtures(project(":tests:ui-fixtures"))) // The root project
|
||||||
|
|
||||||
|
testImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion")
|
||||||
|
testImplementation("com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion")
|
||||||
|
testImplementation("com.automation-remarks:video-recorder-junit5:2.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
// This task is disabled because it should be excluded from `gradle test` run (because it's slow)
|
||||||
|
// I didn't find a better way to exclude except disabling and defining a new task with a different name
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
register<Test>("testUi") {
|
||||||
|
group = "verification"
|
||||||
|
useJUnitPlatform()
|
||||||
|
|
||||||
|
// This is needed for the robot to access the message of the exception
|
||||||
|
// Usually these opens are provided by the intellij gradle plugin
|
||||||
|
// https://github.com/JetBrains/gradle-intellij-plugin/blob/b21e3f382e9885948a6427001d5e64234c602613/src/main/kotlin/org/jetbrains/intellij/utils/OpenedPackages.kt#L26
|
||||||
|
jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
@@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2003-2023 The IdeaVim authors
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
*
|
*
|
||||||
* Use of this source code is governed by an MIT-style
|
* Use of this source code is governed by an MIT-style
|
||||||
* license that can be found in the LICENSE.txt file or at
|
* license that can be found in the LICENSE.txt file or at
|
58
tests/ui-py-tests/build.gradle.kts
Normal file
58
tests/ui-py-tests/build.gradle.kts
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
plugins {
|
||||||
|
java
|
||||||
|
kotlin("jvm")
|
||||||
|
}
|
||||||
|
|
||||||
|
repositories {
|
||||||
|
mavenCentral()
|
||||||
|
maven { url = uri("https://cache-redirector.jetbrains.com/intellij-dependencies") }
|
||||||
|
}
|
||||||
|
|
||||||
|
val kotlinVersion: String by project
|
||||||
|
val ideaVersion: String by project
|
||||||
|
val javaVersion: String by project
|
||||||
|
val remoteRobotVersion: String by project
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
testImplementation("org.junit.jupiter:junit-jupiter")
|
||||||
|
compileOnly("org.jetbrains.kotlin:kotlin-stdlib:$kotlinVersion")
|
||||||
|
testImplementation("org.jetbrains.kotlin:kotlin-test:$kotlinVersion")
|
||||||
|
testImplementation(testFixtures(project(":"))) // The root project
|
||||||
|
testImplementation(testFixtures(project(":tests:ui-fixtures")))
|
||||||
|
|
||||||
|
testImplementation("com.intellij.remoterobot:remote-robot:$remoteRobotVersion")
|
||||||
|
testImplementation("com.intellij.remoterobot:remote-fixtures:$remoteRobotVersion")
|
||||||
|
testImplementation("com.intellij.remoterobot:ide-launcher:$remoteRobotVersion")
|
||||||
|
testImplementation("com.automation-remarks:video-recorder-junit5:2.0")
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks {
|
||||||
|
// This task is disabled because it should be excluded from `gradle test` run (because it's slow)
|
||||||
|
// I didn't find a better way to exclude except disabling and defining a new task with a different name
|
||||||
|
test {
|
||||||
|
useJUnitPlatform()
|
||||||
|
enabled = false
|
||||||
|
}
|
||||||
|
|
||||||
|
register<Test>("testUi") {
|
||||||
|
group = "verification"
|
||||||
|
useJUnitPlatform()
|
||||||
|
|
||||||
|
// This is needed for the robot to access the message of the exception
|
||||||
|
// Usually these opens are provided by the intellij gradle plugin
|
||||||
|
// https://github.com/JetBrains/gradle-intellij-plugin/blob/b21e3f382e9885948a6427001d5e64234c602613/src/main/kotlin/org/jetbrains/intellij/utils/OpenedPackages.kt#L26
|
||||||
|
jvmArgs("--add-opens", "java.base/java.lang=ALL-UNNAMED")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
java {
|
||||||
|
toolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
jvmToolchain {
|
||||||
|
languageVersion.set(JavaLanguageVersion.of(javaVersion))
|
||||||
|
}
|
||||||
|
}
|
64
tests/ui-py-tests/src/test/kotlin/PyCharmTest.kt
Normal file
64
tests/ui-py-tests/src/test/kotlin/PyCharmTest.kt
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2024 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style
|
||||||
|
* license that can be found in the LICENSE.txt file or at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import com.automation.remarks.junit5.Video
|
||||||
|
import com.intellij.remoterobot.RemoteRobot
|
||||||
|
import com.intellij.remoterobot.steps.CommonSteps
|
||||||
|
import com.intellij.remoterobot.utils.keyboard
|
||||||
|
import com.intellij.remoterobot.utils.waitFor
|
||||||
|
import org.junit.jupiter.api.Test
|
||||||
|
import ui.pages.IdeaFrame
|
||||||
|
import ui.pages.idea
|
||||||
|
import ui.pages.welcomeFrame
|
||||||
|
import ui.utils.StepsLogger
|
||||||
|
import ui.utils.uiTest
|
||||||
|
|
||||||
|
class PyCharmTest {
|
||||||
|
init {
|
||||||
|
StepsLogger.init()
|
||||||
|
}
|
||||||
|
|
||||||
|
private lateinit var commonSteps: CommonSteps
|
||||||
|
|
||||||
|
@Test
|
||||||
|
@Video
|
||||||
|
fun run() = uiTest("ideaVimTest") {
|
||||||
|
commonSteps = CommonSteps(this)
|
||||||
|
|
||||||
|
startNewProject()
|
||||||
|
Thread.sleep(1000)
|
||||||
|
|
||||||
|
idea {
|
||||||
|
waitSmartMode()
|
||||||
|
|
||||||
|
testEnterWorksInPyConsole()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun IdeaFrame.testEnterWorksInPyConsole() {
|
||||||
|
findText("Python Console").click()
|
||||||
|
|
||||||
|
Thread.sleep(10_000)
|
||||||
|
|
||||||
|
keyboard {
|
||||||
|
enterText("print(123 + 321)")
|
||||||
|
enter()
|
||||||
|
}
|
||||||
|
|
||||||
|
waitFor {
|
||||||
|
findAllText("444").isNotEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun RemoteRobot.startNewProject() {
|
||||||
|
welcomeFrame {
|
||||||
|
createNewProjectLink.click()
|
||||||
|
button("Create").click()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@@ -16,7 +16,7 @@ import com.maddyhome.idea.vim.command.Command
|
|||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||||
|
|
||||||
@CommandOrMotion(keys = ["<C-R>"], modes = [Mode.NORMAL])
|
@CommandOrMotion(keys = ["U", "<C-R>"], modes = [Mode.NORMAL, Mode.VISUAL])
|
||||||
public class RedoAction : VimActionHandler.SingleExecution() {
|
public class RedoAction : VimActionHandler.SingleExecution() {
|
||||||
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
|
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
|
||||||
|
|
||||||
|
@@ -16,7 +16,7 @@ import com.maddyhome.idea.vim.command.Command
|
|||||||
import com.maddyhome.idea.vim.command.OperatorArguments
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
import com.maddyhome.idea.vim.handler.VimActionHandler
|
import com.maddyhome.idea.vim.handler.VimActionHandler
|
||||||
|
|
||||||
@CommandOrMotion(keys = ["u", "<Undo>"], modes = [Mode.NORMAL])
|
@CommandOrMotion(keys = ["u", "<Undo>"], modes = [Mode.NORMAL, Mode.VISUAL])
|
||||||
public class UndoAction : VimActionHandler.SingleExecution() {
|
public class UndoAction : VimActionHandler.SingleExecution() {
|
||||||
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
|
override val type: Command.Type = Command.Type.OTHER_SELF_SYNCHRONIZED
|
||||||
|
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
package com.maddyhome.idea.vim.action.change.change
|
package com.maddyhome.idea.vim.action.change.change
|
||||||
|
|
||||||
import com.intellij.vim.annotations.CommandOrMotion
|
import com.intellij.vim.annotations.CommandOrMotion
|
||||||
import com.intellij.vim.annotations.Mode
|
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimCaret
|
import com.maddyhome.idea.vim.api.VimCaret
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
@@ -22,7 +21,7 @@ import com.maddyhome.idea.vim.helper.CharacterHelper
|
|||||||
/**
|
/**
|
||||||
* @author vlan
|
* @author vlan
|
||||||
*/
|
*/
|
||||||
@CommandOrMotion(keys = ["u"], modes = [Mode.VISUAL])
|
@CommandOrMotion(keys = [], modes = [])
|
||||||
public class ChangeCaseLowerVisualAction : VisualOperatorActionHandler.ForEachCaret() {
|
public class ChangeCaseLowerVisualAction : VisualOperatorActionHandler.ForEachCaret() {
|
||||||
override val type: Command.Type = Command.Type.CHANGE
|
override val type: Command.Type = Command.Type.CHANGE
|
||||||
|
|
||||||
|
@@ -8,7 +8,6 @@
|
|||||||
package com.maddyhome.idea.vim.action.change.change
|
package com.maddyhome.idea.vim.action.change.change
|
||||||
|
|
||||||
import com.intellij.vim.annotations.CommandOrMotion
|
import com.intellij.vim.annotations.CommandOrMotion
|
||||||
import com.intellij.vim.annotations.Mode
|
|
||||||
import com.maddyhome.idea.vim.api.ExecutionContext
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
import com.maddyhome.idea.vim.api.VimCaret
|
import com.maddyhome.idea.vim.api.VimCaret
|
||||||
import com.maddyhome.idea.vim.api.VimEditor
|
import com.maddyhome.idea.vim.api.VimEditor
|
||||||
@@ -22,7 +21,7 @@ import com.maddyhome.idea.vim.helper.CharacterHelper
|
|||||||
/**
|
/**
|
||||||
* @author vlan
|
* @author vlan
|
||||||
*/
|
*/
|
||||||
@CommandOrMotion(keys = ["U"], modes = [Mode.VISUAL])
|
@CommandOrMotion(keys = [], modes = [])
|
||||||
public class ChangeCaseUpperVisualAction : VisualOperatorActionHandler.ForEachCaret() {
|
public class ChangeCaseUpperVisualAction : VisualOperatorActionHandler.ForEachCaret() {
|
||||||
override val type: Command.Type = Command.Type.CHANGE
|
override val type: Command.Type = Command.Type.CHANGE
|
||||||
|
|
||||||
|
@@ -30,6 +30,7 @@ public class FilterVisualLinesAction : VimActionHandler.SingleExecution() {
|
|||||||
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_MOT_LINEWISE)
|
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_MOT_LINEWISE)
|
||||||
|
|
||||||
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
override fun execute(editor: VimEditor, context: ExecutionContext, cmd: Command, operatorArguments: OperatorArguments): Boolean {
|
||||||
|
injector.markService.setVisualSelectionMarks(editor)
|
||||||
injector.processGroup.startFilterCommand(editor, context, cmd)
|
injector.processGroup.startFilterCommand(editor, context, cmd)
|
||||||
editor.exitVisualMode()
|
editor.exitVisualMode()
|
||||||
return true
|
return true
|
||||||
|
@@ -82,6 +82,13 @@ public sealed class TillCharacterMotion(
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
injector.motion.setLastFTCmd(tillCharacterMotionType, argument.character)
|
injector.motion.setLastFTCmd(tillCharacterMotionType, argument.character)
|
||||||
|
|
||||||
|
val offset = if (!finishBeforeCharacter) ""
|
||||||
|
else if (direction == Direction.FORWARDS) "s-1"
|
||||||
|
else "s+1"
|
||||||
|
|
||||||
|
injector.searchGroup.setLastSearchState(editor, argument.character.let { if (it == '.') "\\." else it.toString() }, offset, direction)
|
||||||
|
|
||||||
return res.toMotionOrError()
|
return res.toMotionOrError()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -0,0 +1,58 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2003-2023 The IdeaVim authors
|
||||||
|
*
|
||||||
|
* Use of this source code is governed by an MIT-style
|
||||||
|
* license that can be found in the LICENSE.txt file or at
|
||||||
|
* https://opensource.org/licenses/MIT.
|
||||||
|
*/
|
||||||
|
package com.maddyhome.idea.vim.action.motion.text
|
||||||
|
|
||||||
|
import com.intellij.vim.annotations.CommandOrMotion
|
||||||
|
import com.intellij.vim.annotations.Mode
|
||||||
|
import com.maddyhome.idea.vim.api.ExecutionContext
|
||||||
|
import com.maddyhome.idea.vim.api.ImmutableVimCaret
|
||||||
|
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.CommandFlags
|
||||||
|
import com.maddyhome.idea.vim.command.MotionType
|
||||||
|
import com.maddyhome.idea.vim.command.OperatorArguments
|
||||||
|
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.enumSetOf
|
||||||
|
import java.util.*
|
||||||
|
|
||||||
|
@CommandOrMotion(keys = ["]s"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
|
||||||
|
public class MotionMisspelledWordNextAction : MotionActionHandler.ForEachCaret() {
|
||||||
|
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_JUMP)
|
||||||
|
|
||||||
|
override fun getOffset(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: ImmutableVimCaret,
|
||||||
|
context: ExecutionContext,
|
||||||
|
argument: Argument?,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
): Motion {
|
||||||
|
return injector.searchHelper.findMisspelledWord(editor, caret, operatorArguments.count1).toMotionOrError()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val motionType: MotionType = MotionType.EXCLUSIVE
|
||||||
|
}
|
||||||
|
|
||||||
|
@CommandOrMotion(keys = ["[s"], modes = [Mode.NORMAL, Mode.VISUAL, Mode.OP_PENDING])
|
||||||
|
public class MotionMisspelledWordPreviousAction : MotionActionHandler.ForEachCaret() {
|
||||||
|
override val flags: EnumSet<CommandFlags> = enumSetOf(CommandFlags.FLAG_SAVE_JUMP)
|
||||||
|
|
||||||
|
override fun getOffset(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: ImmutableVimCaret,
|
||||||
|
context: ExecutionContext,
|
||||||
|
argument: Argument?,
|
||||||
|
operatorArguments: OperatorArguments,
|
||||||
|
): Motion {
|
||||||
|
return injector.searchHelper.findMisspelledWord(editor, caret, -operatorArguments.count1).toMotionOrError()
|
||||||
|
}
|
||||||
|
|
||||||
|
override val motionType: MotionType = MotionType.EXCLUSIVE
|
||||||
|
}
|
@@ -145,7 +145,7 @@ public interface VimChangeGroup {
|
|||||||
operatorArguments: OperatorArguments,
|
operatorArguments: OperatorArguments,
|
||||||
)
|
)
|
||||||
|
|
||||||
public fun insertText(editor: VimEditor, caret: VimCaret, offset: Int, str: String): VimCaret
|
public fun insertText(editor: VimEditor, caret: VimCaret, offset: Int, str: CharSequence): VimCaret
|
||||||
|
|
||||||
public fun insertText(editor: VimEditor, caret: VimCaret, str: String): VimCaret
|
public fun insertText(editor: VimEditor, caret: VimCaret, str: String): VimCaret
|
||||||
|
|
||||||
|
@@ -203,7 +203,7 @@ public abstract class VimChangeGroupBase : VimChangeGroup {
|
|||||||
* @param caret The caret to start insertion in
|
* @param caret The caret to start insertion in
|
||||||
* @param str The text to insert
|
* @param str The text to insert
|
||||||
*/
|
*/
|
||||||
override fun insertText(editor: VimEditor, caret: VimCaret, offset: Int, str: String): VimCaret {
|
override fun insertText(editor: VimEditor, caret: VimCaret, offset: Int, str: CharSequence): VimCaret {
|
||||||
(editor as MutableVimEditor).insertText(Offset(offset), str)
|
(editor as MutableVimEditor).insertText(Offset(offset), str)
|
||||||
val newCaret = caret.moveToInlayAwareOffset(offset + str.length)
|
val newCaret = caret.moveToInlayAwareOffset(offset + str.length)
|
||||||
|
|
||||||
|
@@ -62,6 +62,7 @@ public interface VimKeyGroup {
|
|||||||
public fun unregisterCommandActions()
|
public fun unregisterCommandActions()
|
||||||
public fun resetKeyMappings()
|
public fun resetKeyMappings()
|
||||||
public fun hasmapto(mode: MappingMode, toKeys: List<KeyStroke>): Boolean
|
public fun hasmapto(mode: MappingMode, toKeys: List<KeyStroke>): Boolean
|
||||||
|
public fun hasmapfrom(mode: MappingMode, fromKeys: List<KeyStroke>): Boolean
|
||||||
|
|
||||||
public val shortcutConflicts: MutableMap<KeyStroke, ShortcutOwnerInfo>
|
public val shortcutConflicts: MutableMap<KeyStroke, ShortcutOwnerInfo>
|
||||||
public val savedShortcutConflicts: MutableMap<KeyStroke, ShortcutOwnerInfo>
|
public val savedShortcutConflicts: MutableMap<KeyStroke, ShortcutOwnerInfo>
|
||||||
|
@@ -48,6 +48,10 @@ public abstract class VimKeyGroupBase : VimKeyGroup {
|
|||||||
return this.getKeyMapping(mode).hasmapto(toKeys)
|
return this.getKeyMapping(mode).hasmapto(toKeys)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun hasmapfrom(mode: MappingMode, fromKeys: List<KeyStroke>): Boolean {
|
||||||
|
return this.getKeyMapping(mode).hasmapfrom(fromKeys)
|
||||||
|
}
|
||||||
|
|
||||||
override fun getKeyMapping(mode: MappingMode): KeyMapping {
|
override fun getKeyMapping(mode: MappingMode): KeyMapping {
|
||||||
return keyMappings.getOrPut(mode) { KeyMapping() }
|
return keyMappings.getOrPut(mode) { KeyMapping() }
|
||||||
}
|
}
|
||||||
|
@@ -25,7 +25,7 @@ public interface VimSearchGroup {
|
|||||||
* Last used pattern to perform a substitution.
|
* Last used pattern to perform a substitution.
|
||||||
*/
|
*/
|
||||||
public var lastSubstitutePattern: String?
|
public var lastSubstitutePattern: String?
|
||||||
|
public fun setLastSearchState(editor: VimEditor, pattern: String, patternOffset: String, direction: Direction?)
|
||||||
public fun searchBackward(editor: VimEditor, offset: Int, count: Int): TextRange?
|
public fun searchBackward(editor: VimEditor, offset: Int, count: Int): TextRange?
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@@ -239,4 +239,10 @@ public interface VimSearchHelper {
|
|||||||
count: Int,
|
count: Int,
|
||||||
isOuter: Boolean,
|
isOuter: Boolean,
|
||||||
): TextRange?
|
): TextRange?
|
||||||
|
|
||||||
|
public fun findMisspelledWord(
|
||||||
|
editor: VimEditor,
|
||||||
|
caret: ImmutableVimCaret,
|
||||||
|
count: Int,
|
||||||
|
): Int
|
||||||
}
|
}
|
||||||
|
@@ -163,6 +163,11 @@ public class KeyMapping : Iterable<List<KeyStroke?>?>, KeyMappingLayer {
|
|||||||
.anyMatch { o: MappingInfo? -> o is ToKeysMappingInfo && o.toKeys == toKeys }
|
.anyMatch { o: MappingInfo? -> o is ToKeysMappingInfo && o.toKeys == toKeys }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public fun hasmapfrom(fromKeys: List<KeyStroke?>): Boolean {
|
||||||
|
return myKeys.values.stream()
|
||||||
|
.anyMatch { o: MappingInfo? -> o is ToKeysMappingInfo && o.fromKeys == fromKeys }
|
||||||
|
}
|
||||||
|
|
||||||
public fun getMapTo(toKeys: List<KeyStroke?>): List<Pair<List<KeyStroke>, MappingInfo>> {
|
public fun getMapTo(toKeys: List<KeyStroke?>): List<Pair<List<KeyStroke>, MappingInfo>> {
|
||||||
return myKeys.entries.stream()
|
return myKeys.entries.stream()
|
||||||
.filter { (_, value): Map.Entry<List<KeyStroke>, MappingInfo> -> value is ToKeysMappingInfo && value.toKeys == toKeys }
|
.filter { (_, value): Map.Entry<List<KeyStroke>, MappingInfo> -> value is ToKeysMappingInfo && value.toKeys == toKeys }
|
||||||
|
@@ -106,6 +106,10 @@ public class ToKeysMappingInfo(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun toString(): String {
|
||||||
|
return "Mapping[$fromKeys -> $toKeys]"
|
||||||
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
private val LOG = vimLogger<ToKeysMappingInfo>()
|
private val LOG = vimLogger<ToKeysMappingInfo>()
|
||||||
}
|
}
|
||||||
@@ -255,8 +259,13 @@ public class ToActionMappingInfo(
|
|||||||
LOG.debug("Executing 'ToAction' mapping...")
|
LOG.debug("Executing 'ToAction' mapping...")
|
||||||
val editorDataContext = injector.executionContextManager.onEditor(editor, context)
|
val editorDataContext = injector.executionContextManager.onEditor(editor, context)
|
||||||
val dataContext = injector.executionContextManager.onCaret(editor.currentCaret(), editorDataContext)
|
val dataContext = injector.executionContextManager.onCaret(editor.currentCaret(), editorDataContext)
|
||||||
|
|
||||||
|
val commandBuilder = editor.vimStateMachine.commandBuilder
|
||||||
|
for (i in 0 until commandBuilder.count.coerceAtLeast(1)) {
|
||||||
injector.actionExecutor.executeAction(action, dataContext)
|
injector.actionExecutor.executeAction(action, dataContext)
|
||||||
}
|
}
|
||||||
|
commandBuilder.resetCount()
|
||||||
|
}
|
||||||
|
|
||||||
public companion object {
|
public companion object {
|
||||||
private val LOG = vimLogger<ToActionMappingInfo>()
|
private val LOG = vimLogger<ToActionMappingInfo>()
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user