backport: 12.0.0
ci: 12.0.0 (cherry picked from commit 2f80528cb46ee5a13dd5cb960d361c41d62c7e28) (cherry picked from commit 87d7db94410dd30be154e585138498c67c262db8) chore: Isolate C++ toolchain into separate package to fix verifier error (cherry picked from commit c393120bf24c40d5fc5e8ce41dacc560bcb29ae8) chore: Forgot to bump gradle version in properties (cherry picked from commit b8639b0e8dc7d4e8177339d5466d98af9b87c900) fix(zig): Make go to references non-blocking (cherry picked from commit a1cee2b1ea399776f5d4bbf33c2403a9c4bf9b03) feat(zig)!: Go to declaration/usages and go to definition are now separate actions (cherry picked from commit 18e130cc52e78b69dfdd08e5f160e82d3215deb2) fix(zig): Refresh syntax highlighting after running code edits (cherry picked from commit 64eba369d61073f1dd57c999449e9ee7b914bd49) chore: Cleanup dependencies (cherry picked from commit baabbb030dc8ad729f5a1f82c523c1d6da27489b) docs: Extra information about module tree (cherry picked from commit 12ad175f510124353fd9cc6b8994355e44965161) feat(zig)!: Autogenerate zls config if not specified, based on project toolchain (cherry picked from commit 59a56b67646b0253734130a84d8d9d825effe114) feat(debugger): Library frame filter (cherry picked from commit 4e3336add808801097acc792fa3e899b26cbdaee) docs: update changelog (cherry picked from commit 7db1c621288ba1cac25e85b682d981fd8cc2d4b8) feat!: Reimplemented go to declaration/usages to replace the built-in action Also removed mouse handling, no longer needed (cherry picked from commit 6f481ac844f80701f22d9383a3ff228ea3ee440d) feat(debugger): Detect C++ debugger toolchains (cherry picked from commit 6df7cb6dc059c622a0e06ace38558c8b495bd91e) fix(zig): Add proper lang key for notification group (cherry picked from commit b8f64ac0062847279b6c85b00083711900e8f7cf) chore(buildscript): Update gradle and gradle plugins (cherry picked from commit 45ab2d9bb7834be9bc2914f962d3a21bef494fbd) fix(lsp): Force always creating a new DocumentEventManager34b29ee729
(cherry picked from commit 59c1f4612d353de3230419d005206dada4900a7f) fix(lsp): unregisterManager method's cleanupbc9c5ea31c
(cherry picked from commit 14a1a9d79f09573d3d7c8cfb27bb008cb63ca38b) chore(lsp): Extract shared logic75a5fd8919
(cherry picked from commit 857a0224897e27968fa03f93b0f9a02bc109f0b0) fix(lsp): Remove duplicated changedConfiguration calls9b2b0557c9
(cherry picked from commit ceb347d8723130c8ee4097a78fed5f14615805ee) chore(lsp): Small code cleanup8c1e6736df
(cherry picked from commit 1e1b4aaaeafabfe76abad22cc18aa51629098012) fix(lsp): Code action annotations lose range00bbd6ff45
(cherry picked from commit d920fa37f32549d7d7419fa07e478b94cc8ae8ba) fix(lsp): Request code actions immediately after diagnostics arrive0fe2cf98fe
(cherry picked from commit 36138213ba878eaf97e9c7f0642b9927672d2e59)
This commit is contained in:
parent
11c5eb0b85
commit
b8a448d7fe
44 changed files with 838 additions and 601 deletions
24
CHANGELOG.md
24
CHANGELOG.md
|
@ -18,6 +18,30 @@ Changelog structure reference:
|
||||||
|
|
||||||
## [Unreleased]
|
## [Unreleased]
|
||||||
|
|
||||||
|
## [12.0.0]
|
||||||
|
|
||||||
|
### Added
|
||||||
|
|
||||||
|
- Debugger
|
||||||
|
- Now uses the toolchains you set in Settings | Build, Execution, Deployment | Toolchains
|
||||||
|
- Standard library stack frames are now automatically filtered from the debug stack trace
|
||||||
|
|
||||||
|
- Zig
|
||||||
|
- Go to Declaration/Usages now functions as expected, taking you to the declaration of a symbol instead of its resolved
|
||||||
|
implementation.
|
||||||
|
- For the time being, the "Quick Definition" (CTRL+Shift+I) action has been repurposed as Go To Definition. This will be
|
||||||
|
replaced with a properly integrated solution once a way to couple the PSI symbol system and the LSP has been found.
|
||||||
|
|
||||||
|
### Fixed
|
||||||
|
|
||||||
|
- LSP
|
||||||
|
- Diagnostics race condition
|
||||||
|
- Code action annotations no longer lose range
|
||||||
|
|
||||||
|
- Zig
|
||||||
|
- Syntax highlighting no longer breaks after refactoring or reformatting
|
||||||
|
- Go to Usages no longer freezes the IDE
|
||||||
|
|
||||||
## [11.1.0]
|
## [11.1.0]
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
|
|
|
@ -2,8 +2,18 @@ For now this project is still pretty small, but here are some general guidelines
|
||||||
|
|
||||||
- This project ships with a code style config in .idea, your IDE should automatically apply it when you pull the repo.
|
- This project ships with a code style config in .idea, your IDE should automatically apply it when you pull the repo.
|
||||||
When making pull requests, please try to keep to this style as much as possible.
|
When making pull requests, please try to keep to this style as much as possible.
|
||||||
|
|
||||||
- Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), and scope as much as you can.
|
- Use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/), and scope as much as you can.
|
||||||
- The project has support for the PSI tree, but try to keep "intelligent" behaviour out of it, all code inspection and
|
|
||||||
other semantics-aware help should come from ZLS where possible.
|
- Do not edit the relationship tree between modules without unanimous agreement from the project lead.
|
||||||
- Generally, if the answer to "Can i write some glue code that can get this info from ZLS?" is YES, do not use the PSI
|
|
||||||
tree.
|
If you want an "upstream" module (for instance, the LSP) receive data from a "downstream" module
|
||||||
|
(for instance, the project module), you should use service providers, dependency injections, or other ways to implement
|
||||||
|
the dataflow in a way where the upstream module is not directly aware of downstream modules.
|
||||||
|
|
||||||
|
The main purpose of this is to avoid any circular dependencies, which could cause proprietary IDE-only features
|
||||||
|
(for instance, the CLion debugger module) to be depended on by FOSS modules. This restriction is non-negotiable.
|
||||||
|
|
||||||
|
- Any complex language inspection, syntax action, or similar, should be done by ZLS, and ZigBrains will just act as an
|
||||||
|
adapter for these features. This notion of "complexity" is determined by the project maintainer. Open an issue
|
||||||
|
that explains the feature before you start implementing anything!
|
44
MODULE_TREE.md
Normal file
44
MODULE_TREE.md
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
## What is this?
|
||||||
|
This document describes the relationships between the different "modules" of ZigBrains.
|
||||||
|
|
||||||
|
These relationships are strictly enforced, and modules that do not directly (or indirectly) depend on another
|
||||||
|
module cannot access their classes.
|
||||||
|
|
||||||
|
The primary purpose of this strictly enforced module system is to avoid code compatible with open source IDEs (IDEA/PyCharm Community)
|
||||||
|
from depending on code that only works on proprietary IDEs (IDEA Ultimate/CLion/...).
|
||||||
|
|
||||||
|
NOTE: These "modules" are in no way related to the module system introduced in Java 9. They're just called the same.
|
||||||
|
|
||||||
|
The suffix after the module name signifies which IDE it depends on.
|
||||||
|
|
||||||
|
- IC: IDEA Community
|
||||||
|
- CL: CLion
|
||||||
|
- EXT: External maven library
|
||||||
|
|
||||||
|
IC modules MUST NOT depend on CL modules, as this violates the restrictions set forth above.
|
||||||
|
|
||||||
|
## Modules
|
||||||
|
|
||||||
|
### Common (IC)
|
||||||
|
|
||||||
|
### LSP (IC)
|
||||||
|
- LSP4J (EXT)
|
||||||
|
- Flexmark (EXT)
|
||||||
|
- Apache Commons Lang 3 (EXT)
|
||||||
|
|
||||||
|
### Zig (IC)
|
||||||
|
- Grammarkit (EXT)
|
||||||
|
- Common (IC)
|
||||||
|
- LSP (IC)
|
||||||
|
|
||||||
|
### Project (IC)
|
||||||
|
- Common (IC)
|
||||||
|
- Zig (IC)
|
||||||
|
|
||||||
|
### Zon (IC)
|
||||||
|
- Grammarkit (EXT)
|
||||||
|
- Common (IC)
|
||||||
|
|
||||||
|
### Debugger (CL)
|
||||||
|
- Zig (IC)
|
||||||
|
- Project (IC)
|
44
README.md
44
README.md
|
@ -80,7 +80,17 @@ LSP server is running.
|
||||||
|
|
||||||
## Debugging
|
## Debugging
|
||||||
|
|
||||||
Currently, the debugger only works with the bundled LLDB debugger, so make sure you have that.
|
ZigBrains uses the CLion C++ toolchains (Settings | Build, Execution, Deployment | Toolchains) for debugging purposes,
|
||||||
|
and it is fully compatible with both GDB and LLDB debuggers.
|
||||||
|
|
||||||
|
Additionally, ZigBrains will prioritize a toolchain if it is called `Zig`, otherwise it will use the default toolchain.
|
||||||
|
|
||||||
|
If no toolchain is available, ZigBrains will attempt to use the bundled LLDB debugger, and if that is not available either,
|
||||||
|
an error popup will be shown when you try to run with debugging.
|
||||||
|
|
||||||
|
Note: There is a small issue with the LLDB debugger which does not happen with GDB: The debugger will pause on the first
|
||||||
|
instruction (usually, deep inside the zig standard library's startup code). Unfortunately, we have not found a fix for
|
||||||
|
this yet, but fortunately it doesn't break anything, just a bit of inconvenience.
|
||||||
|
|
||||||
## Feature tracker:
|
## Feature tracker:
|
||||||
|
|
||||||
|
@ -96,7 +106,7 @@ Currently, the debugger only works with the bundled LLDB debugger, so make sure
|
||||||
- Hover documentation
|
- Hover documentation
|
||||||
- Go to implementations / find usages
|
- Go to implementations / find usages
|
||||||
- Brace/Parenthesis/Bracket matching
|
- Brace/Parenthesis/Bracket matching
|
||||||
- Breakpoints (CLion/IDEA Ultimate)
|
- Debugging (CLion/CLion Nova)
|
||||||
- File creation prompt
|
- File creation prompt
|
||||||
- Gutter launch buttons
|
- Gutter launch buttons
|
||||||
- Commenter (thanks @MarioAriasC !)
|
- Commenter (thanks @MarioAriasC !)
|
||||||
|
@ -117,36 +127,6 @@ Currently, the debugger only works with the bundled LLDB debugger, so make sure
|
||||||
- Debugging (CLion/IDEA Ultimate)
|
- Debugging (CLion/IDEA Ultimate)
|
||||||
- Project generation (thanks @JensvandeWiel !)
|
- Project generation (thanks @JensvandeWiel !)
|
||||||
|
|
||||||
## The motivation
|
|
||||||
The other existing Zig language plugins for IntelliJ rely a lot on the PSI tree.
|
|
||||||
This seems correct in theory, until
|
|
||||||
the sheer power of Zig's comptime is taken into consideration.
|
|
||||||
|
|
||||||
The comptime makes any sort of contextual help implemented with the PSI tree a lot more restrictive,
|
|
||||||
and adding LSP integration at that point is an uphill battle.
|
|
||||||
|
|
||||||
## Current state of the project
|
|
||||||
This project takes the opposite approach: The initial implementation *completely* relies on ZLS, with no lexer or parser
|
|
||||||
in sight.
|
|
||||||
Using a language server immediately gives us access to advanced features such as refactoring, go to definition,
|
|
||||||
semantics-based highlighting, and so on.
|
|
||||||
|
|
||||||
However, this also restricts the amount of IDE integration the language plugin can achieve,
|
|
||||||
and things like live previews, peek definition, go to usage previews, and many other features that deeply integrate with
|
|
||||||
the PSI system just don't work at all.
|
|
||||||
|
|
||||||
## Long-term plans
|
|
||||||
The first and foremost goal of this project is deeply integrating ZLS into the IDE,
|
|
||||||
and LSP-provided information *always* takes the first seat.
|
|
||||||
|
|
||||||
However, we must also not completely reject the PSI tree,
|
|
||||||
as it has its own merits when used wisely, such as basic "dumb mode" syntax highlighting,
|
|
||||||
proper caret placements with go to usages, and so on.
|
|
||||||
|
|
||||||
Thus, this project will still use PSI trees and the IntelliJ lexer/parser system, but with heavy moderation, and any
|
|
||||||
sort of "smart inspection" *shall not* be implemented in the PSI, but instead retrieved from the language server.
|
|
||||||
|
|
||||||
|
|
||||||
## Licenses
|
## Licenses
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
|
|
@ -12,9 +12,9 @@ fun environment(key: String) = providers.environmentVariable(key)
|
||||||
plugins {
|
plugins {
|
||||||
id("java") // Java support
|
id("java") // Java support
|
||||||
id("java-library")
|
id("java-library")
|
||||||
id("org.jetbrains.intellij") version("1.17.0")
|
id("org.jetbrains.intellij") version("1.17.2")
|
||||||
id("org.jetbrains.changelog") version("2.2.0")
|
id("org.jetbrains.changelog") version("2.2.0")
|
||||||
id("org.jetbrains.grammarkit") version("2022.3.2.1")
|
id("org.jetbrains.grammarkit") version("2022.3.2.2")
|
||||||
}
|
}
|
||||||
|
|
||||||
val grammarKitGenDir = "build/generated/sources/grammarkit/java"
|
val grammarKitGenDir = "build/generated/sources/grammarkit/java"
|
||||||
|
@ -58,8 +58,6 @@ allprojects {
|
||||||
maven("https://cache-redirector.jetbrains.com/intellij-dependencies")
|
maven("https://cache-redirector.jetbrains.com/intellij-dependencies")
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
compileOnly("org.jetbrains:annotations:24.1.0")
|
|
||||||
|
|
||||||
compileOnly("org.projectlombok:lombok:1.18.30")
|
compileOnly("org.projectlombok:lombok:1.18.30")
|
||||||
annotationProcessor("org.projectlombok:lombok:1.18.30")
|
annotationProcessor("org.projectlombok:lombok:1.18.30")
|
||||||
}
|
}
|
||||||
|
@ -116,7 +114,7 @@ allprojects {
|
||||||
purgeOldFiles = true
|
purgeOldFiles = true
|
||||||
}
|
}
|
||||||
generateParser {
|
generateParser {
|
||||||
targetRoot = "${grammarKitGenDir}/parser"
|
targetRootOutputDir = file("${grammarKitGenDir}/parser")
|
||||||
purgeOldFiles = true
|
purgeOldFiles = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,7 +169,7 @@ project(":lsp") {
|
||||||
plugin("java-library")
|
plugin("java-library")
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
api("org.eclipse.lsp4j:org.eclipse.lsp4j:0.21.2")
|
api("org.eclipse.lsp4j:org.eclipse.lsp4j:0.22.0")
|
||||||
implementation("com.vladsch.flexmark:flexmark:0.64.8")
|
implementation("com.vladsch.flexmark:flexmark:0.64.8")
|
||||||
api("org.apache.commons:commons-lang3:3.14.0")
|
api("org.apache.commons:commons-lang3:3.14.0")
|
||||||
}
|
}
|
||||||
|
@ -186,8 +184,7 @@ project(":zig") {
|
||||||
generateLexer {
|
generateLexer {
|
||||||
enabled = true
|
enabled = true
|
||||||
sourceFile = file("src/main/grammar/Zig.flex")
|
sourceFile = file("src/main/grammar/Zig.flex")
|
||||||
targetDir = "${grammarKitGenDir}/lexer/${rootPackagePath}/zig/lexer"
|
targetOutputDir = file("${grammarKitGenDir}/lexer/${rootPackagePath}/zig/lexer")
|
||||||
targetClass = "ZigFlexLexer"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generateParser {
|
generateParser {
|
||||||
|
@ -219,8 +216,7 @@ project(":zon") {
|
||||||
generateLexer {
|
generateLexer {
|
||||||
enabled = true
|
enabled = true
|
||||||
sourceFile = file("src/main/grammar/Zon.flex")
|
sourceFile = file("src/main/grammar/Zon.flex")
|
||||||
targetDir = "${grammarKitGenDir}/lexer/${rootPackagePath}/zon/lexer"
|
targetOutputDir = file("${grammarKitGenDir}/lexer/${rootPackagePath}/zon/lexer")
|
||||||
targetClass = "ZonFlexLexer"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
generateParser {
|
generateParser {
|
||||||
|
|
|
@ -2,7 +2,7 @@ pluginGroup = com.falsepattern.zigbrains
|
||||||
pluginName = ZigBrains
|
pluginName = ZigBrains
|
||||||
pluginRepositoryUrl = https://github.com/FalsePattern/ZigBrains
|
pluginRepositoryUrl = https://github.com/FalsePattern/ZigBrains
|
||||||
# SemVer format -> https://semver.org
|
# SemVer format -> https://semver.org
|
||||||
pluginVersion = 11.1.0
|
pluginVersion = 12.0.0
|
||||||
|
|
||||||
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
|
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
|
||||||
pluginSinceBuild = 232
|
pluginSinceBuild = 232
|
||||||
|
@ -14,7 +14,7 @@ ideaVersion = IC-2023.2.5
|
||||||
clionVersion = CL-2023.2.2
|
clionVersion = CL-2023.2.2
|
||||||
|
|
||||||
# Gradle Releases -> https://github.com/gradle/gradle/releases
|
# Gradle Releases -> https://github.com/gradle/gradle/releases
|
||||||
gradleVersion = 8.2.1
|
gradleVersion = 8.6
|
||||||
|
|
||||||
# Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html
|
# Enable Gradle Build Cache -> https://docs.gradle.org/current/userguide/build_cache.html
|
||||||
org.gradle.caching = true
|
org.gradle.caching = true
|
||||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2.1-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.zig.cpp;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.zig.debugbridge.DebuggerDriverProvider;
|
||||||
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionGDBDriverConfiguration;
|
||||||
|
import com.jetbrains.cidr.cpp.execution.debugger.backend.CLionLLDBDriverConfiguration;
|
||||||
|
import com.jetbrains.cidr.cpp.toolchains.CPPToolchains;
|
||||||
|
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class CPPDebuggerDriverProvider implements DebuggerDriverProvider {
|
||||||
|
private static final Logger LOG = Logger.getInstance(CPPDebuggerDriverProvider.class);
|
||||||
|
@Override
|
||||||
|
public @Nullable DebuggerDriverConfiguration getDebuggerConfiguration(Project project) {
|
||||||
|
val toolchains = CPPToolchains.getInstance();
|
||||||
|
var toolchain = toolchains.getToolchainByNameOrDefault("Zig");
|
||||||
|
if (toolchain == null || !toolchain.isDebuggerSupported()) {
|
||||||
|
LOG.info("Couldn't find debug-compatible C++ toolchain with name \"Zig\"");
|
||||||
|
toolchain = toolchains.getDefaultToolchain();
|
||||||
|
}
|
||||||
|
if (toolchain == null || !toolchain.isDebuggerSupported()) {
|
||||||
|
LOG.info("Couldn't find debug-compatible C++ default toolchain");
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return switch (toolchain.getDebuggerKind()) {
|
||||||
|
case CUSTOM_GDB, BUNDLED_GDB -> new CLionGDBDriverConfiguration(project, toolchain);
|
||||||
|
case BUNDLED_LLDB -> new CLionLLDBDriverConfiguration(project, toolchain);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.zig.debugbridge;
|
||||||
|
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.util.UserDataHolder;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getDebuggerConfiguration should return com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration, it's UserDataHolder here to
|
||||||
|
* avoid a plugin verifier error.
|
||||||
|
*/
|
||||||
|
public interface DebuggerDriverProvider {
|
||||||
|
ExtensionPointName<DebuggerDriverProvider> EXTENSION_POINT_NAME = ExtensionPointName.create("com.falsepattern.zigbrains.debuggerDriverProvider");
|
||||||
|
|
||||||
|
static @NotNull Stream<UserDataHolder> findDebuggerConfigurations(Project project) {
|
||||||
|
return EXTENSION_POINT_NAME.getExtensionList()
|
||||||
|
.stream()
|
||||||
|
.map(it -> it.getDebuggerConfiguration(project))
|
||||||
|
.filter(Objects::nonNull);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Nullable UserDataHolder getDebuggerConfiguration(Project project);
|
||||||
|
}
|
|
@ -0,0 +1,49 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.zig.debugger;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.zig.debugbridge.DebuggerDriverProvider;
|
||||||
|
import com.intellij.notification.Notification;
|
||||||
|
import com.intellij.notification.NotificationType;
|
||||||
|
import com.intellij.notification.Notifications;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
|
||||||
|
import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
public class Utils {
|
||||||
|
public static @Nullable DebuggerDriverConfiguration getDebuggerConfiguration(Project project) {
|
||||||
|
val providedDebugger = DebuggerDriverProvider.findDebuggerConfigurations(project)
|
||||||
|
.filter(x -> x instanceof DebuggerDriverConfiguration)
|
||||||
|
.map(x -> (DebuggerDriverConfiguration)x)
|
||||||
|
.findFirst()
|
||||||
|
.orElse(null);
|
||||||
|
if (providedDebugger != null)
|
||||||
|
return providedDebugger;
|
||||||
|
|
||||||
|
|
||||||
|
if (LLDBDriverConfiguration.hasBundledLLDB()) {
|
||||||
|
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Warn",
|
||||||
|
"Couldn't find a working debug toolchain, using bundled LLDB debugger!",
|
||||||
|
NotificationType.WARNING));
|
||||||
|
return new LLDBDriverConfiguration();
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -21,14 +21,16 @@ import com.jetbrains.cidr.execution.Installer;
|
||||||
import com.jetbrains.cidr.execution.RunParameters;
|
import com.jetbrains.cidr.execution.RunParameters;
|
||||||
import com.jetbrains.cidr.execution.TrivialInstaller;
|
import com.jetbrains.cidr.execution.TrivialInstaller;
|
||||||
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
|
import com.jetbrains.cidr.execution.debugger.backend.DebuggerDriverConfiguration;
|
||||||
import com.jetbrains.cidr.execution.debugger.backend.lldb.LLDBDriverConfiguration;
|
|
||||||
import lombok.RequiredArgsConstructor;
|
import lombok.RequiredArgsConstructor;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
|
||||||
@RequiredArgsConstructor
|
@RequiredArgsConstructor
|
||||||
public class ZigDebugRunParameters extends RunParameters {
|
public class ZigDebugRunParameters extends RunParameters {
|
||||||
private final GeneralCommandLine cmd;
|
private final GeneralCommandLine cmd;
|
||||||
|
private final DebuggerDriverConfiguration driverConfiguration;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull Installer getInstaller() {
|
public @NotNull Installer getInstaller() {
|
||||||
return new TrivialInstaller(cmd);
|
return new TrivialInstaller(cmd);
|
||||||
|
@ -36,11 +38,7 @@ public class ZigDebugRunParameters extends RunParameters {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public @NotNull DebuggerDriverConfiguration getDebuggerDriverConfiguration() {
|
public @NotNull DebuggerDriverConfiguration getDebuggerDriverConfiguration() {
|
||||||
if (LLDBDriverConfiguration.hasBundledLLDB()) {
|
return driverConfiguration;
|
||||||
return new LLDBDriverConfiguration();
|
|
||||||
} else {
|
|
||||||
throw new IllegalStateException("The bundled LLDB debugger is missing from your IDE!");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -24,6 +24,9 @@ import com.intellij.execution.executors.DefaultDebugExecutor;
|
||||||
import com.intellij.execution.process.ProcessTerminatedListener;
|
import com.intellij.execution.process.ProcessTerminatedListener;
|
||||||
import com.intellij.execution.runners.ExecutionEnvironment;
|
import com.intellij.execution.runners.ExecutionEnvironment;
|
||||||
import com.intellij.execution.ui.RunContentDescriptor;
|
import com.intellij.execution.ui.RunContentDescriptor;
|
||||||
|
import com.intellij.notification.Notification;
|
||||||
|
import com.intellij.notification.NotificationType;
|
||||||
|
import com.intellij.notification.Notifications;
|
||||||
import com.intellij.xdebugger.XDebugProcess;
|
import com.intellij.xdebugger.XDebugProcess;
|
||||||
import com.intellij.xdebugger.XDebugProcessStarter;
|
import com.intellij.xdebugger.XDebugProcessStarter;
|
||||||
import com.intellij.xdebugger.XDebugSession;
|
import com.intellij.xdebugger.XDebugSession;
|
||||||
|
@ -32,6 +35,8 @@ import lombok.val;
|
||||||
import org.jetbrains.annotations.NonNls;
|
import org.jetbrains.annotations.NonNls;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Arrays;
|
||||||
|
|
||||||
public class ZigDebugRunnerBase extends ZigExecutableRunner {
|
public class ZigDebugRunnerBase extends ZigExecutableRunner {
|
||||||
public ZigDebugRunnerBase() {
|
public ZigDebugRunnerBase() {
|
||||||
super(DefaultDebugExecutor.EXECUTOR_ID, "Unable to run Zig debugger");
|
super(DefaultDebugExecutor.EXECUTOR_ID, "Unable to run Zig debugger");
|
||||||
|
@ -40,9 +45,16 @@ public class ZigDebugRunnerBase extends ZigExecutableRunner {
|
||||||
@Override
|
@Override
|
||||||
protected RunContentDescriptor showRunContent(ZigRunExecutionConfigurationRunProfileState state, ExecutionEnvironment environment, GeneralCommandLine runExecutable)
|
protected RunContentDescriptor showRunContent(ZigRunExecutionConfigurationRunProfileState state, ExecutionEnvironment environment, GeneralCommandLine runExecutable)
|
||||||
throws ExecutionException {
|
throws ExecutionException {
|
||||||
val runParameters = new ZigDebugRunParameters(runExecutable);
|
val project = environment.getProject();
|
||||||
return XDebuggerManager.getInstance(environment.getProject())
|
val debuggerDriver = Utils.getDebuggerConfiguration(project);
|
||||||
.startSession(environment, new XDebugProcessStarter() {
|
if (debuggerDriver == null) {
|
||||||
|
Notifications.Bus.notify(new Notification("ZigBrains.Debugger.Error", "Couldn't find a working GDB or LLDB debugger! Please check your Toolchains! (Settings | Build, Execution, Deployment | Toolchains)", NotificationType.ERROR));
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
val runParameters = new ZigDebugRunParameters(runExecutable, debuggerDriver);
|
||||||
|
val manager = XDebuggerManager.getInstance(project);
|
||||||
|
return manager.startSession(environment,
|
||||||
|
new XDebugProcessStarter() {
|
||||||
@Override
|
@Override
|
||||||
public @NotNull XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException {
|
public @NotNull XDebugProcess start(@NotNull XDebugSession session) throws ExecutionException {
|
||||||
val process = new ZigLocalDebugProcess(runParameters, session, state.getConsoleBuilder());
|
val process = new ZigLocalDebugProcess(runParameters, session, state.getConsoleBuilder());
|
||||||
|
|
|
@ -29,11 +29,4 @@ public class ZigLocalDebugProcess extends CidrLocalDebugProcess {
|
||||||
throws ExecutionException {
|
throws ExecutionException {
|
||||||
super(parameters, session, consoleBuilder, (project) -> Filter.EMPTY_ARRAY, false);
|
super(parameters, session, consoleBuilder, (project) -> Filter.EMPTY_ARRAY, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLibraryFrameFilterSupported() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,23 @@
|
||||||
|
<!--
|
||||||
|
~ Copyright 2023-2024 FalsePattern
|
||||||
|
~
|
||||||
|
~ Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
~ you may not use this file except in compliance with the License.
|
||||||
|
~ You may obtain a copy of the License at
|
||||||
|
~
|
||||||
|
~ http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
~
|
||||||
|
~ Unless required by applicable law or agreed to in writing, software
|
||||||
|
~ distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
~ See the License for the specific language governing permissions and
|
||||||
|
~ limitations under the License.
|
||||||
|
-->
|
||||||
|
|
||||||
|
<idea-plugin package="com.falsepattern.zigbrains.zig.cpp">
|
||||||
|
<depends>com.intellij.modules.clion</depends>
|
||||||
|
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
||||||
|
<debuggerDriverProvider implementation="com.falsepattern.zigbrains.zig.cpp.CPPDebuggerDriverProvider"/>
|
||||||
|
</extensions>
|
||||||
|
|
||||||
|
</idea-plugin>
|
|
@ -16,10 +16,20 @@
|
||||||
|
|
||||||
<idea-plugin package="com.falsepattern.zigbrains.zig.debugger">
|
<idea-plugin package="com.falsepattern.zigbrains.zig.debugger">
|
||||||
<depends>com.intellij.modules.cidr.debugger</depends>
|
<depends>com.intellij.modules.cidr.debugger</depends>
|
||||||
|
<resource-bundle>zigbrains.zig.debugger.Bundle</resource-bundle>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="com.intellij">
|
<extensions defaultExtensionNs="com.intellij">
|
||||||
<programRunner implementation="com.falsepattern.zigbrains.zig.debugger.ZigDebugRunner"
|
<programRunner implementation="com.falsepattern.zigbrains.zig.debugger.ZigDebugRunner"
|
||||||
id="ZigDebugRunner"/>
|
id="ZigDebugRunner"/>
|
||||||
|
|
||||||
|
<notificationGroup displayType="BALLOON"
|
||||||
|
bundle="zigbrains.zig.debugger.Bundle"
|
||||||
|
key="notif-debug-error"
|
||||||
|
id="ZigBrains.Debugger.Error"/>
|
||||||
|
<notificationGroup displayType="BALLOON"
|
||||||
|
bundle="zigbrains.zig.debugger.Bundle"
|
||||||
|
key="notif-debug-warn"
|
||||||
|
id="ZigBrains.Debugger.Warn"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<extensions defaultExtensionNs="cidr.debugger">
|
<extensions defaultExtensionNs="cidr.debugger">
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
notif-debug-warn=ZigBrains debugger warning
|
||||||
|
notif-debug-error=ZigBrains debugger error
|
|
@ -0,0 +1,62 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.lsp.actions;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
||||||
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase;
|
||||||
|
import com.falsepattern.zigbrains.lsp.requests.ReformatHandler;
|
||||||
|
import com.falsepattern.zigbrains.lsp.utils.ApplicationUtils;
|
||||||
|
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||||
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.intellij.openapi.fileEditor.FileDocumentManager;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.psi.PsiDocumentManager;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class LSPGotoDeclarationAction extends GotoDeclarationAction {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||||
|
Project project = e.getData(CommonDataKeys.PROJECT);
|
||||||
|
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
||||||
|
if (editor == null || project == null) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||||
|
if (file == null || !IntellijLanguageClient.isExtensionSupported(file.getVirtualFile())) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EditorEventManager manager = EditorEventManagerBase.forEditor(editor);
|
||||||
|
if (manager == null) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val offset = editor.getCaretModel().getOffset();
|
||||||
|
val psiElement = file.findElementAt(offset);
|
||||||
|
if (psiElement == null) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manager.gotoDeclarationOrUsages(psiElement);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.lsp.actions;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
||||||
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase;
|
||||||
|
import com.intellij.codeInsight.hint.actions.ShowImplementationsAction;
|
||||||
|
import com.intellij.codeInsight.navigation.CtrlMouseAction;
|
||||||
|
import com.intellij.codeInsight.navigation.actions.GotoDeclarationAction;
|
||||||
|
import com.intellij.openapi.actionSystem.AnAction;
|
||||||
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
|
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||||
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import com.intellij.openapi.project.DumbAware;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.psi.PsiDocumentManager;
|
||||||
|
import com.intellij.psi.PsiFile;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public class LSPGotoDefinitionAction extends ShowImplementationsAction {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(@NotNull AnActionEvent e) {
|
||||||
|
Project project = e.getData(CommonDataKeys.PROJECT);
|
||||||
|
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
||||||
|
if (editor == null || project == null) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||||
|
if (file == null || !IntellijLanguageClient.isExtensionSupported(file.getVirtualFile())) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
EditorEventManager manager = EditorEventManagerBase.forEditor(editor);
|
||||||
|
if (manager == null) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val offset = editor.getCaretModel().getOffset();
|
||||||
|
val psiElement = file.findElementAt(offset);
|
||||||
|
if (psiElement == null) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
manager.gotoDefinition(psiElement);
|
||||||
|
}
|
||||||
|
}
|
|
@ -24,6 +24,8 @@ import com.intellij.find.findUsages.FindUsagesOptions;
|
||||||
import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
|
import com.intellij.find.findUsages.PsiElement2UsageTargetAdapter;
|
||||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||||
|
import com.intellij.openapi.application.ModalityState;
|
||||||
|
import com.intellij.openapi.application.ReadAction;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.editor.LogicalPosition;
|
import com.intellij.openapi.editor.LogicalPosition;
|
||||||
import com.intellij.openapi.project.DumbAwareAction;
|
import com.intellij.openapi.project.DumbAwareAction;
|
||||||
|
@ -41,6 +43,8 @@ import com.intellij.usages.UsageInfo2UsageAdapter;
|
||||||
import com.intellij.usages.UsageTarget;
|
import com.intellij.usages.UsageTarget;
|
||||||
import com.intellij.usages.UsageViewManager;
|
import com.intellij.usages.UsageViewManager;
|
||||||
import com.intellij.usages.UsageViewPresentation;
|
import com.intellij.usages.UsageViewPresentation;
|
||||||
|
import com.intellij.util.concurrency.AppExecutorUtil;
|
||||||
|
import lombok.val;
|
||||||
|
|
||||||
import javax.swing.JLabel;
|
import javax.swing.JLabel;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
@ -63,8 +67,8 @@ public class LSPReferencesAction extends DumbAwareAction {
|
||||||
}
|
}
|
||||||
List<PsiElement2UsageTargetAdapter> targets = new ArrayList<>();
|
List<PsiElement2UsageTargetAdapter> targets = new ArrayList<>();
|
||||||
Pair<List<PsiElement>, List<VirtualFile>> references = eventManager
|
Pair<List<PsiElement>, List<VirtualFile>> references = eventManager
|
||||||
.references(editor.getCaretModel().getCurrentCaret().getOffset());
|
.references(editor.getCaretModel().getCurrentCaret().getOffset(), true, true);
|
||||||
if (references.first != null && references.second != null) {
|
if (references.first != null) {
|
||||||
references.first.forEach(element -> targets.add(new PsiElement2UsageTargetAdapter(element, true)));
|
references.first.forEach(element -> targets.add(new PsiElement2UsageTargetAdapter(element, true)));
|
||||||
}
|
}
|
||||||
showReferences(editor, targets, editor.getCaretModel().getCurrentCaret().getLogicalPosition());
|
showReferences(editor, targets, editor.getCaretModel().getCurrentCaret().getLogicalPosition());
|
||||||
|
@ -72,13 +76,22 @@ public class LSPReferencesAction extends DumbAwareAction {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void forManagerAndOffset(EditorEventManager manager, int offset) {
|
public void forManagerAndOffset(EditorEventManager manager, int offset) {
|
||||||
List<PsiElement2UsageTargetAdapter> targets = new ArrayList<>();
|
ReadAction.nonBlocking(() -> {
|
||||||
Pair<List<PsiElement>, List<VirtualFile>> references = manager.references(offset);
|
val references = manager.references(offset, true, true);
|
||||||
if (references.first != null && references.second != null) {
|
val targets = new ArrayList<PsiElement2UsageTargetAdapter>();
|
||||||
|
if (references.first != null) {
|
||||||
references.first.forEach(element -> targets.add(new PsiElement2UsageTargetAdapter(element, true)));
|
references.first.forEach(element -> targets.add(new PsiElement2UsageTargetAdapter(element, true)));
|
||||||
}
|
}
|
||||||
Editor editor = manager.editor;
|
return targets;
|
||||||
|
})
|
||||||
|
.expireWhen(() -> manager.editor.isDisposed())
|
||||||
|
.finishOnUiThread(ModalityState.nonModal(), targets -> {
|
||||||
|
val editor = manager.editor;
|
||||||
|
if (editor.isDisposed())
|
||||||
|
return;
|
||||||
showReferences(editor, targets, editor.offsetToLogicalPosition(offset));
|
showReferences(editor, targets, editor.offsetToLogicalPosition(offset));
|
||||||
|
})
|
||||||
|
.submit(AppExecutorUtil.getAppExecutorService());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void showReferences(Editor editor, List<PsiElement2UsageTargetAdapter> targets, LogicalPosition position) {
|
private void showReferences(Editor editor, List<PsiElement2UsageTargetAdapter> targets, LogicalPosition position) {
|
||||||
|
@ -108,7 +121,7 @@ public class LSPReferencesAction extends DumbAwareAction {
|
||||||
UsageViewPresentation presentation = createPresentation(targets.get(0).getElement(),
|
UsageViewPresentation presentation = createPresentation(targets.get(0).getElement(),
|
||||||
new FindUsagesOptions(editor.getProject()), false);
|
new FindUsagesOptions(editor.getProject()), false);
|
||||||
UsageViewManager.getInstance(project)
|
UsageViewManager.getInstance(project)
|
||||||
.showUsages(new UsageTarget[] { targets.get(0) }, usages.toArray(new Usage[usages.size()]),
|
.showUsages(new UsageTarget[0], usages.toArray(new Usage[0]),
|
||||||
presentation);
|
presentation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,10 +43,14 @@ public class LSPReformatAction extends ReformatCodeAction implements DumbAware {
|
||||||
Project project = e.getData(CommonDataKeys.PROJECT);
|
Project project = e.getData(CommonDataKeys.PROJECT);
|
||||||
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
Editor editor = e.getData(CommonDataKeys.EDITOR);
|
||||||
if (editor == null || project == null) {
|
if (editor == null || project == null) {
|
||||||
|
super.actionPerformed(e);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
PsiFile file = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
||||||
if (IntellijLanguageClient.isExtensionSupported(file.getVirtualFile())) {
|
if (file == null || !IntellijLanguageClient.isExtensionSupported(file.getVirtualFile())) {
|
||||||
|
super.actionPerformed(e);
|
||||||
|
return;
|
||||||
|
}
|
||||||
ApplicationUtils.writeAction(() -> FileDocumentManager.getInstance().saveDocument(editor.getDocument()));
|
ApplicationUtils.writeAction(() -> FileDocumentManager.getInstance().saveDocument(editor.getDocument()));
|
||||||
// if editor hasSelection, only reformat selection, not reformat the whole file
|
// if editor hasSelection, only reformat selection, not reformat the whole file
|
||||||
if (editor.getSelectionModel().hasSelection()) {
|
if (editor.getSelectionModel().hasSelection()) {
|
||||||
|
@ -54,9 +58,6 @@ public class LSPReformatAction extends ReformatCodeAction implements DumbAware {
|
||||||
} else {
|
} else {
|
||||||
ReformatHandler.reformatFile(editor);
|
ReformatHandler.reformatFile(editor);
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
super.actionPerformed(e);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -33,6 +33,7 @@ import org.eclipse.lsp4j.CompletionItem;
|
||||||
import org.eclipse.lsp4j.CompletionList;
|
import org.eclipse.lsp4j.CompletionList;
|
||||||
import org.eclipse.lsp4j.CompletionOptions;
|
import org.eclipse.lsp4j.CompletionOptions;
|
||||||
import org.eclipse.lsp4j.CompletionParams;
|
import org.eclipse.lsp4j.CompletionParams;
|
||||||
|
import org.eclipse.lsp4j.DeclarationParams;
|
||||||
import org.eclipse.lsp4j.DefinitionParams;
|
import org.eclipse.lsp4j.DefinitionParams;
|
||||||
import org.eclipse.lsp4j.DidChangeConfigurationParams;
|
import org.eclipse.lsp4j.DidChangeConfigurationParams;
|
||||||
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
|
import org.eclipse.lsp4j.DidChangeTextDocumentParams;
|
||||||
|
@ -572,6 +573,21 @@ public class DefaultRequestManager implements RequestManager {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> declaration(DeclarationParams params) {
|
||||||
|
if (checkStatus()) {
|
||||||
|
try {
|
||||||
|
return Optional.ofNullable(serverCapabilities.getDefinitionProvider())
|
||||||
|
.map(e -> e.getLeft() || e.getRight() != null).orElse(false) ?
|
||||||
|
textDocumentService.declaration(params) : null;
|
||||||
|
} catch (Exception e) {
|
||||||
|
crashed(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) {
|
public CompletableFuture<List<Either<Command, CodeAction>>> codeAction(CodeActionParams params) {
|
||||||
if (checkStatus()) {
|
if (checkStatus()) {
|
||||||
|
|
|
@ -28,8 +28,6 @@ import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
import com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase;
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase;
|
||||||
import com.falsepattern.zigbrains.lsp.extensions.LSPExtensionManager;
|
import com.falsepattern.zigbrains.lsp.extensions.LSPExtensionManager;
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.DocumentListenerImpl;
|
import com.falsepattern.zigbrains.lsp.listeners.DocumentListenerImpl;
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.EditorMouseListenerImpl;
|
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.EditorMouseMotionListenerImpl;
|
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.LSPCaretListenerImpl;
|
import com.falsepattern.zigbrains.lsp.listeners.LSPCaretListenerImpl;
|
||||||
import com.falsepattern.zigbrains.lsp.requests.Timeout;
|
import com.falsepattern.zigbrains.lsp.requests.Timeout;
|
||||||
import com.falsepattern.zigbrains.lsp.requests.Timeouts;
|
import com.falsepattern.zigbrains.lsp.requests.Timeouts;
|
||||||
|
@ -67,6 +65,7 @@ import org.eclipse.lsp4j.DidChangeWatchedFilesCapabilities;
|
||||||
import org.eclipse.lsp4j.DocumentHighlightCapabilities;
|
import org.eclipse.lsp4j.DocumentHighlightCapabilities;
|
||||||
import org.eclipse.lsp4j.ExecuteCommandCapabilities;
|
import org.eclipse.lsp4j.ExecuteCommandCapabilities;
|
||||||
import org.eclipse.lsp4j.FoldingRangeCapabilities;
|
import org.eclipse.lsp4j.FoldingRangeCapabilities;
|
||||||
|
import org.eclipse.lsp4j.FoldingRangeKind;
|
||||||
import org.eclipse.lsp4j.FoldingRangeKindSupportCapabilities;
|
import org.eclipse.lsp4j.FoldingRangeKindSupportCapabilities;
|
||||||
import org.eclipse.lsp4j.FoldingRangeSupportCapabilities;
|
import org.eclipse.lsp4j.FoldingRangeSupportCapabilities;
|
||||||
import org.eclipse.lsp4j.FormattingCapabilities;
|
import org.eclipse.lsp4j.FormattingCapabilities;
|
||||||
|
@ -355,30 +354,24 @@ public class LanguageServerWrapper {
|
||||||
//Todo - Implement
|
//Todo - Implement
|
||||||
// SelectionListenerImpl selectionListener = new SelectionListenerImpl();
|
// SelectionListenerImpl selectionListener = new SelectionListenerImpl();
|
||||||
DocumentListenerImpl documentListener = new DocumentListenerImpl();
|
DocumentListenerImpl documentListener = new DocumentListenerImpl();
|
||||||
EditorMouseListenerImpl mouseListener = new EditorMouseListenerImpl();
|
|
||||||
EditorMouseMotionListenerImpl mouseMotionListener = new EditorMouseMotionListenerImpl();
|
|
||||||
LSPCaretListenerImpl caretListener = new LSPCaretListenerImpl();
|
LSPCaretListenerImpl caretListener = new LSPCaretListenerImpl();
|
||||||
|
|
||||||
ServerOptions serverOptions = new ServerOptions(capabilities);
|
ServerOptions serverOptions = new ServerOptions(capabilities);
|
||||||
EditorEventManager manager;
|
EditorEventManager manager;
|
||||||
if (extManager != null) {
|
if (extManager != null) {
|
||||||
manager = extManager.getExtendedEditorEventManagerFor(editor, documentListener,
|
manager = extManager.getExtendedEditorEventManagerFor(editor, documentListener,
|
||||||
mouseListener, mouseMotionListener, caretListener, requestManager, serverOptions,
|
caretListener, requestManager, serverOptions,
|
||||||
this);
|
this);
|
||||||
if (manager == null) {
|
if (manager == null) {
|
||||||
manager = new EditorEventManager(editor, documentListener, mouseListener,
|
manager = new EditorEventManager(editor, documentListener, caretListener,
|
||||||
mouseMotionListener, caretListener,
|
|
||||||
requestManager, serverOptions, this);
|
requestManager, serverOptions, this);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
manager = new EditorEventManager(editor, documentListener, mouseListener,
|
manager = new EditorEventManager(editor, documentListener, caretListener,
|
||||||
mouseMotionListener, caretListener,
|
|
||||||
requestManager, serverOptions, this);
|
requestManager, serverOptions, this);
|
||||||
}
|
}
|
||||||
// selectionListener.setManager(manager);
|
// selectionListener.setManager(manager);
|
||||||
documentListener.setManager(manager);
|
documentListener.setManager(manager);
|
||||||
mouseListener.setManager(manager);
|
|
||||||
mouseMotionListener.setManager(manager);
|
|
||||||
caretListener.setManager(manager);
|
caretListener.setManager(manager);
|
||||||
manager.registerListeners();
|
manager.registerListeners();
|
||||||
if (!urisUnderLspControl.contains(uri)) {
|
if (!urisUnderLspControl.contains(uri)) {
|
||||||
|
@ -464,7 +457,6 @@ public class LanguageServerWrapper {
|
||||||
|
|
||||||
// sadly this whole editor closing stuff runs asynchronously, so we cannot be sure the state is really clean here...
|
// sadly this whole editor closing stuff runs asynchronously, so we cannot be sure the state is really clean here...
|
||||||
// therefore clear the mapping from here as it should be empty by now.
|
// therefore clear the mapping from here as it should be empty by now.
|
||||||
DocumentEventManager.clearState();
|
|
||||||
uriToEditorManagers.clear();
|
uriToEditorManagers.clear();
|
||||||
urisUnderLspControl.clear();
|
urisUnderLspControl.clear();
|
||||||
launcherFuture = null;
|
launcherFuture = null;
|
||||||
|
@ -590,7 +582,8 @@ public class LanguageServerWrapper {
|
||||||
textDocumentClientCapabilities.setSynchronization(new SynchronizationCapabilities(true, true, true));
|
textDocumentClientCapabilities.setSynchronization(new SynchronizationCapabilities(true, true, true));
|
||||||
|
|
||||||
FoldingRangeCapabilities foldingRangeCapabilities = new FoldingRangeCapabilities();
|
FoldingRangeCapabilities foldingRangeCapabilities = new FoldingRangeCapabilities();
|
||||||
foldingRangeCapabilities.setFoldingRangeKind(new FoldingRangeKindSupportCapabilities(List.of("comment", "region", "imports")));
|
foldingRangeCapabilities.setFoldingRangeKind(new FoldingRangeKindSupportCapabilities(List.of(
|
||||||
|
FoldingRangeKind.Comment, FoldingRangeKind.Imports, FoldingRangeKind.Region)));
|
||||||
foldingRangeCapabilities.setFoldingRange(new FoldingRangeSupportCapabilities(true));
|
foldingRangeCapabilities.setFoldingRange(new FoldingRangeSupportCapabilities(true));
|
||||||
textDocumentClientCapabilities.setFoldingRange(foldingRangeCapabilities);
|
textDocumentClientCapabilities.setFoldingRange(foldingRangeCapabilities);
|
||||||
|
|
||||||
|
|
|
@ -109,16 +109,7 @@ public class LSPAnnotator extends ExternalAnnotator<Object, Object> {
|
||||||
if (eventManager == null) {
|
if (eventManager == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (eventManager.isCodeActionSyncRequired()) {
|
if (eventManager.isDiagnosticSyncRequired()) {
|
||||||
try {
|
|
||||||
updateAnnotations(holder, eventManager);
|
|
||||||
} catch (ConcurrentModificationException e) {
|
|
||||||
// Todo - Add proper fix to handle concurrent modifications gracefully.
|
|
||||||
LOG.warn("Error occurred when updating LSP diagnostics due to concurrent modifications.", e);
|
|
||||||
} catch (Throwable t) {
|
|
||||||
LOG.warn("Error occurred when updating LSP diagnostics.", t);
|
|
||||||
}
|
|
||||||
} else if (eventManager.isDiagnosticSyncRequired()) {
|
|
||||||
try {
|
try {
|
||||||
createAnnotations(holder, eventManager);
|
createAnnotations(holder, eventManager);
|
||||||
} catch (ConcurrentModificationException e) {
|
} catch (ConcurrentModificationException e) {
|
||||||
|
@ -127,6 +118,15 @@ public class LSPAnnotator extends ExternalAnnotator<Object, Object> {
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
LOG.warn("Error occurred when updating LSP code actions.", t);
|
LOG.warn("Error occurred when updating LSP code actions.", t);
|
||||||
}
|
}
|
||||||
|
} else if (eventManager.isCodeActionSyncRequired()) {
|
||||||
|
try {
|
||||||
|
updateAnnotations(holder, eventManager);
|
||||||
|
} catch (ConcurrentModificationException e) {
|
||||||
|
// Todo - Add proper fix to handle concurrent modifications gracefully.
|
||||||
|
LOG.warn("Error occurred when updating LSP diagnostics due to concurrent modifications.", e);
|
||||||
|
} catch (Throwable t) {
|
||||||
|
LOG.warn("Error occurred when updating LSP diagnostics.", t);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -140,7 +140,12 @@ public class LSPAnnotator extends ExternalAnnotator<Object, Object> {
|
||||||
annotations.forEach(annotation -> {
|
annotations.forEach(annotation -> {
|
||||||
if (annotation.getQuickFixes() != null && !annotation.getQuickFixes().isEmpty()) {
|
if (annotation.getQuickFixes() != null && !annotation.getQuickFixes().isEmpty()) {
|
||||||
AnnotationBuilder builder = holder.newAnnotation(annotation.getSeverity(), annotation.getMessage());
|
AnnotationBuilder builder = holder.newAnnotation(annotation.getSeverity(), annotation.getMessage());
|
||||||
|
boolean range = true;
|
||||||
for (Annotation.QuickFixInfo quickFixInfo : annotation.getQuickFixes()) {
|
for (Annotation.QuickFixInfo quickFixInfo : annotation.getQuickFixes()) {
|
||||||
|
if (range) {
|
||||||
|
builder = builder.range(quickFixInfo.textRange);
|
||||||
|
range = false;
|
||||||
|
}
|
||||||
builder = builder.withFix(quickFixInfo.quickFix);
|
builder = builder.withFix(quickFixInfo.quickFix);
|
||||||
}
|
}
|
||||||
builder.create();
|
builder.create();
|
||||||
|
|
|
@ -39,9 +39,7 @@ import org.eclipse.lsp4j.TextDocumentSyncKind;
|
||||||
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
|
import org.eclipse.lsp4j.VersionedTextDocumentIdentifier;
|
||||||
|
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
|
|
||||||
public class DocumentEventManager {
|
public class DocumentEventManager {
|
||||||
|
@ -52,7 +50,6 @@ public class DocumentEventManager {
|
||||||
private final TextDocumentIdentifier identifier;
|
private final TextDocumentIdentifier identifier;
|
||||||
private int version = -1;
|
private int version = -1;
|
||||||
protected Logger LOG = Logger.getInstance(EditorEventManager.class);
|
protected Logger LOG = Logger.getInstance(EditorEventManager.class);
|
||||||
private static final Map<String, DocumentEventManager> uriToDocumentEventManager = new HashMap<>();
|
|
||||||
|
|
||||||
private final Set<Document> openDocuments = new HashSet<>();
|
private final Set<Document> openDocuments = new HashSet<>();
|
||||||
|
|
||||||
|
@ -64,22 +61,6 @@ public class DocumentEventManager {
|
||||||
this.identifier = new TextDocumentIdentifier(FileUtils.documentToUri(document));
|
this.identifier = new TextDocumentIdentifier(FileUtils.documentToUri(document));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void clearState() {
|
|
||||||
uriToDocumentEventManager.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public static DocumentEventManager getOrCreateDocumentManager(Document document, DocumentListener listener, TextDocumentSyncKind syncKind, LanguageServerWrapper wrapper) {
|
|
||||||
DocumentEventManager manager = uriToDocumentEventManager.get(FileUtils.documentToUri(document));
|
|
||||||
if (manager != null) {
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
manager = new DocumentEventManager(document, listener, syncKind, wrapper);
|
|
||||||
|
|
||||||
uriToDocumentEventManager.put(FileUtils.documentToUri(document), manager);
|
|
||||||
return manager;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void removeListeners() {
|
public void removeListeners() {
|
||||||
document.removeDocumentListener(documentListener);
|
document.removeDocumentListener(documentListener);
|
||||||
}
|
}
|
||||||
|
|
|
@ -72,11 +72,13 @@ import com.intellij.openapi.util.Pair;
|
||||||
import com.intellij.openapi.util.TextRange;
|
import com.intellij.openapi.util.TextRange;
|
||||||
import com.intellij.openapi.vfs.VfsUtil;
|
import com.intellij.openapi.vfs.VfsUtil;
|
||||||
import com.intellij.openapi.vfs.VirtualFile;
|
import com.intellij.openapi.vfs.VirtualFile;
|
||||||
|
import com.intellij.openapi.vfs.VirtualFileManager;
|
||||||
import com.intellij.psi.PsiDocumentManager;
|
import com.intellij.psi.PsiDocumentManager;
|
||||||
import com.intellij.psi.PsiElement;
|
import com.intellij.psi.PsiElement;
|
||||||
import com.intellij.psi.PsiFile;
|
import com.intellij.psi.PsiFile;
|
||||||
import com.intellij.ui.Hint;
|
import com.intellij.ui.Hint;
|
||||||
import com.intellij.util.SmartList;
|
import com.intellij.util.SmartList;
|
||||||
|
import lombok.val;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.eclipse.lsp4j.CodeAction;
|
import org.eclipse.lsp4j.CodeAction;
|
||||||
import org.eclipse.lsp4j.CodeActionContext;
|
import org.eclipse.lsp4j.CodeActionContext;
|
||||||
|
@ -86,6 +88,7 @@ import org.eclipse.lsp4j.CompletionItem;
|
||||||
import org.eclipse.lsp4j.CompletionItemKind;
|
import org.eclipse.lsp4j.CompletionItemKind;
|
||||||
import org.eclipse.lsp4j.CompletionList;
|
import org.eclipse.lsp4j.CompletionList;
|
||||||
import org.eclipse.lsp4j.CompletionParams;
|
import org.eclipse.lsp4j.CompletionParams;
|
||||||
|
import org.eclipse.lsp4j.DeclarationParams;
|
||||||
import org.eclipse.lsp4j.DefinitionParams;
|
import org.eclipse.lsp4j.DefinitionParams;
|
||||||
import org.eclipse.lsp4j.Diagnostic;
|
import org.eclipse.lsp4j.Diagnostic;
|
||||||
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
|
import org.eclipse.lsp4j.DidSaveTextDocumentParams;
|
||||||
|
@ -119,7 +122,9 @@ import org.eclipse.lsp4j.WorkspaceEdit;
|
||||||
import org.eclipse.lsp4j.jsonrpc.JsonRpcException;
|
import org.eclipse.lsp4j.jsonrpc.JsonRpcException;
|
||||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||||
import org.eclipse.lsp4j.jsonrpc.messages.Tuple;
|
import org.eclipse.lsp4j.jsonrpc.messages.Tuple;
|
||||||
|
import org.eclipse.lsp4j.services.TextDocumentService;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
import javax.swing.Icon;
|
import javax.swing.Icon;
|
||||||
import java.awt.Point;
|
import java.awt.Point;
|
||||||
|
@ -138,12 +143,11 @@ import java.util.concurrent.CompletableFuture;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
|
import java.util.function.BiFunction;
|
||||||
|
import java.util.function.Function;
|
||||||
import java.util.regex.Matcher;
|
import java.util.regex.Matcher;
|
||||||
import java.util.regex.Pattern;
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
import static com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase.getCtrlRange;
|
|
||||||
import static com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase.getIsCtrlDown;
|
|
||||||
import static com.falsepattern.zigbrains.lsp.editor.EditorEventManagerBase.setCtrlRange;
|
|
||||||
import static com.falsepattern.zigbrains.lsp.utils.ApplicationUtils.computableReadAction;
|
import static com.falsepattern.zigbrains.lsp.utils.ApplicationUtils.computableReadAction;
|
||||||
import static com.falsepattern.zigbrains.lsp.utils.ApplicationUtils.computableWriteAction;
|
import static com.falsepattern.zigbrains.lsp.utils.ApplicationUtils.computableWriteAction;
|
||||||
import static com.falsepattern.zigbrains.lsp.utils.ApplicationUtils.invokeLater;
|
import static com.falsepattern.zigbrains.lsp.utils.ApplicationUtils.invokeLater;
|
||||||
|
@ -173,8 +177,6 @@ public class EditorEventManager {
|
||||||
public LanguageServerWrapper wrapper;
|
public LanguageServerWrapper wrapper;
|
||||||
private Project project;
|
private Project project;
|
||||||
private TextDocumentIdentifier identifier;
|
private TextDocumentIdentifier identifier;
|
||||||
private EditorMouseListener mouseListener;
|
|
||||||
private EditorMouseMotionListener mouseMotionListener;
|
|
||||||
private LSPCaretListenerImpl caretListener;
|
private LSPCaretListenerImpl caretListener;
|
||||||
|
|
||||||
public List<String> completionTriggers;
|
public List<String> completionTriggers;
|
||||||
|
@ -200,13 +202,10 @@ public class EditorEventManager {
|
||||||
public static final String SNIPPET_PLACEHOLDER_REGEX = "(\\$\\{\\d+:?([^{^}]*)}|\\$\\d+)";
|
public static final String SNIPPET_PLACEHOLDER_REGEX = "(\\$\\{\\d+:?([^{^}]*)}|\\$\\d+)";
|
||||||
|
|
||||||
//Todo - Revisit arguments order and add remaining listeners
|
//Todo - Revisit arguments order and add remaining listeners
|
||||||
public EditorEventManager(Editor editor, DocumentListener documentListener, EditorMouseListener mouseListener,
|
public EditorEventManager(Editor editor, DocumentListener documentListener, LSPCaretListenerImpl caretListener,
|
||||||
EditorMouseMotionListener mouseMotionListener, LSPCaretListenerImpl caretListener,
|
|
||||||
RequestManager requestmanager, ServerOptions serverOptions, LanguageServerWrapper wrapper) {
|
RequestManager requestmanager, ServerOptions serverOptions, LanguageServerWrapper wrapper) {
|
||||||
|
|
||||||
this.editor = editor;
|
this.editor = editor;
|
||||||
this.mouseListener = mouseListener;
|
|
||||||
this.mouseMotionListener = mouseMotionListener;
|
|
||||||
this.wrapper = wrapper;
|
this.wrapper = wrapper;
|
||||||
this.caretListener = caretListener;
|
this.caretListener = caretListener;
|
||||||
|
|
||||||
|
@ -229,7 +228,7 @@ public class EditorEventManager {
|
||||||
|
|
||||||
this.currentHint = null;
|
this.currentHint = null;
|
||||||
|
|
||||||
this.documentEventManager = DocumentEventManager.getOrCreateDocumentManager(editor.getDocument(), documentListener, syncKind, wrapper);
|
this.documentEventManager = new DocumentEventManager(editor.getDocument(), documentListener, syncKind, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused")
|
@SuppressWarnings("unused")
|
||||||
|
@ -258,159 +257,53 @@ public class EditorEventManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the manager that the mouse is in the editor
|
|
||||||
*/
|
|
||||||
public void mouseEntered() {
|
|
||||||
mouseInEditor = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tells the manager that the mouse is not in the editor
|
|
||||||
*/
|
|
||||||
public void mouseExited() {
|
|
||||||
mouseInEditor = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Will show documentation if the mouse doesn't move for a given time (Hover)
|
|
||||||
*
|
|
||||||
* @param e the event
|
|
||||||
*/
|
|
||||||
public void mouseMoved(EditorMouseEvent e) {
|
|
||||||
// if (e.getEditor() != editor) {
|
|
||||||
// LOG.error("Wrong editor for EditorEventManager");
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// PsiFile psiFile = PsiDocumentManager.getInstance(project).getPsiFile(editor.getDocument());
|
|
||||||
// if (psiFile == null) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
// Language language = psiFile.getLanguage();
|
|
||||||
// if ((!LanguageDocumentation.INSTANCE.allForLanguage(language).isEmpty() && !isSupportedLanguageFile(psiFile))
|
|
||||||
// || (!getIsCtrlDown() && !EditorSettingsExternalizable.getInstance().isShowQuickDocOnMouseOverElement())) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// long curTime = System.nanoTime();
|
|
||||||
// if (predTime == (-1L) || ctrlTime == (-1L)) {
|
|
||||||
// predTime = curTime;
|
|
||||||
// ctrlTime = curTime;
|
|
||||||
// } else {
|
|
||||||
// LogicalPosition lPos = getPos(e);
|
|
||||||
// if (lPos == null || getIsKeyPressed() && !getIsCtrlDown()) {
|
|
||||||
// return;
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// int offset = editor.logicalPositionToOffset(lPos);
|
|
||||||
// if ((getIsCtrlDown() || EditorSettingsExternalizable.getInstance().isShowQuickDocOnMouseOverElement())
|
|
||||||
// && curTime - ctrlTime > CTRL_THRESH) {
|
|
||||||
// if (getCtrlRange() == null || !getCtrlRange().highlightContainsOffset(offset)) {
|
|
||||||
// if (currentHint != null) {
|
|
||||||
// currentHint.hide();
|
|
||||||
// }
|
|
||||||
// currentHint = null;
|
|
||||||
// if (getCtrlRange() != null) {
|
|
||||||
// getCtrlRange().dispose();
|
|
||||||
// }
|
|
||||||
// setCtrlRange(null);
|
|
||||||
// pool(() -> requestAndShowDoc(lPos, e.getMouseEvent().getPoint()));
|
|
||||||
// } else if (getCtrlRange().definitionContainsOffset(offset)) {
|
|
||||||
// createAndShowEditorHint(editor, "Click to show usages", editor.offsetToXY(offset));
|
|
||||||
// } else {
|
|
||||||
// editor.getContentComponent().setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
|
||||||
// }
|
|
||||||
// ctrlTime = curTime;
|
|
||||||
// }
|
|
||||||
// predTime = curTime;
|
|
||||||
// }
|
|
||||||
}
|
|
||||||
|
|
||||||
private boolean isSupportedLanguageFile(PsiFile file) {
|
private boolean isSupportedLanguageFile(PsiFile file) {
|
||||||
return file.getLanguage().isKindOf(PlainTextLanguage.INSTANCE)
|
return file.getLanguage().isKindOf(PlainTextLanguage.INSTANCE)
|
||||||
|| FileUtils.isFileSupported(file.getVirtualFile());
|
|| FileUtils.isFileSupported(file.getVirtualFile());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Called when the mouse is clicked
|
|
||||||
* At the moment, is used by CTRL+click to see references / goto definition
|
|
||||||
*
|
|
||||||
* @param e The mouse event
|
|
||||||
*/
|
|
||||||
public void mouseClicked(EditorMouseEvent e) {
|
|
||||||
if (e.getEditor() != editor) {
|
|
||||||
LOG.error("Wrong editor for EditorEventManager");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getIsCtrlDown()) {
|
|
||||||
// If CTRL/CMD key is pressed, triggers goto definition/references and hover.
|
|
||||||
try {
|
|
||||||
trySourceNavigationAndHover(e);
|
|
||||||
} catch (Exception err) {
|
|
||||||
LOG.warn("Error occurred when trying source navigation", err);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void createCtrlRange(Position logicalPos, Range range) {
|
|
||||||
Location location = requestDefinition(logicalPos);
|
|
||||||
if (location == null || location.getRange() == null || editor.isDisposed()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Range corRange;
|
|
||||||
if (range == null) {
|
|
||||||
corRange = new Range(logicalPos, logicalPos);
|
|
||||||
} else {
|
|
||||||
corRange = range;
|
|
||||||
}
|
|
||||||
int startOffset = DocumentUtils.LSPPosToOffset(editor, corRange.getStart());
|
|
||||||
int endOffset = DocumentUtils.LSPPosToOffset(editor, corRange.getEnd());
|
|
||||||
boolean isDefinition = DocumentUtils.LSPPosToOffset(editor, location.getRange().getStart()) == startOffset;
|
|
||||||
|
|
||||||
CtrlRangeMarker ctrlRange = getCtrlRange();
|
|
||||||
if (!editor.isDisposed()) {
|
|
||||||
if (ctrlRange != null) {
|
|
||||||
ctrlRange.dispose();
|
|
||||||
}
|
|
||||||
setCtrlRange(new CtrlRangeMarker(location, editor, !isDefinition ?
|
|
||||||
(editor.getMarkupModel().addRangeHighlighter(startOffset, endOffset, HighlighterLayer.HYPERLINK,
|
|
||||||
editor.getColorsScheme().getAttributes(EditorColors.REFERENCE_HYPERLINK_COLOR),
|
|
||||||
HighlighterTargetArea.EXACT_RANGE)) : null));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the position of the definition given a position in the editor
|
* Returns the position of the definition given a position in the editor
|
||||||
*
|
*
|
||||||
* @param position The position
|
* @param position The position
|
||||||
* @return The location of the definition
|
* @return The location of the definition
|
||||||
*/
|
*/
|
||||||
|
private Location requestDeclaration(Position position) {
|
||||||
|
return requestDefinitionOrDeclaration(position, Timeouts.DECLARATION, DeclarationParams::new, TextDocumentService::declaration);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the position of the declaration given a position in the editor
|
||||||
|
*
|
||||||
|
* @param position The position
|
||||||
|
* @return The location of the declaration
|
||||||
|
*/
|
||||||
private Location requestDefinition(Position position) {
|
private Location requestDefinition(Position position) {
|
||||||
DefinitionParams params = new DefinitionParams(identifier, position);
|
return requestDefinitionOrDeclaration(position, Timeouts.DEFINITION, DefinitionParams::new, TextDocumentService::definition);
|
||||||
CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>> request =
|
}
|
||||||
wrapper.getRequestManager().definition(params);
|
|
||||||
|
private <T> Location requestDefinitionOrDeclaration(Position position, Timeouts timeout, BiFunction<TextDocumentIdentifier, Position, T> paramsConstructor, BiFunction<TextDocumentService, T, CompletableFuture<Either<List<? extends Location>, List<? extends LocationLink>>>> requester) {
|
||||||
|
val params = paramsConstructor.apply(identifier, position);
|
||||||
|
val request = requester.apply(wrapper.getRequestManager(), params);
|
||||||
|
|
||||||
if (request == null) {
|
if (request == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
Either<List<? extends Location>, List<? extends LocationLink>> definition =
|
val result = request.get(Timeout.getTimeout(timeout), TimeUnit.MILLISECONDS);
|
||||||
request.get(Timeout.getTimeout(Timeouts.DEFINITION), TimeUnit.MILLISECONDS);
|
wrapper.notifySuccess(timeout);
|
||||||
wrapper.notifySuccess(Timeouts.DEFINITION);
|
if (result == null) {
|
||||||
if (definition == null) {
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
if (definition.isLeft() && !definition.getLeft().isEmpty()) {
|
if (result.isLeft() && !result.getLeft().isEmpty()) {
|
||||||
return definition.getLeft().get(0);
|
return result.getLeft().get(0);
|
||||||
} else if (definition.isRight() && !definition.getRight().isEmpty()) {
|
} else if (result.isRight() && !result.getRight().isEmpty()) {
|
||||||
var def = definition.getRight().get(0);
|
var def = result.getRight().get(0);
|
||||||
return new Location(def.getTargetUri(), def.getTargetRange());
|
return new Location(def.getTargetUri(), def.getTargetRange());
|
||||||
}
|
}
|
||||||
} catch (TimeoutException e) {
|
} catch (TimeoutException e) {
|
||||||
LOG.warn(e);
|
LOG.warn(e);
|
||||||
wrapper.notifyFailure(Timeouts.DEFINITION);
|
wrapper.notifyFailure(timeout);
|
||||||
return null;
|
return null;
|
||||||
} catch (InterruptedException | JsonRpcException | ExecutionException e) {
|
} catch (InterruptedException | JsonRpcException | ExecutionException e) {
|
||||||
LOG.warn(e);
|
LOG.warn(e);
|
||||||
|
@ -459,7 +352,7 @@ public class EditorEventManager {
|
||||||
* @param offset The offset in the editor
|
* @param offset The offset in the editor
|
||||||
* @return An array of PsiElement
|
* @return An array of PsiElement
|
||||||
*/
|
*/
|
||||||
public Pair<List<PsiElement>, List<VirtualFile>> references(int offset, boolean getOriginalElement, boolean close) {
|
public Pair<List<PsiElement>, List<VirtualFile>> references(int offset, boolean getOriginalElement, boolean fast) {
|
||||||
renameCache = null;
|
renameCache = null;
|
||||||
Position lspPos = DocumentUtils.offsetToLSPPos(editor, offset);
|
Position lspPos = DocumentUtils.offsetToLSPPos(editor, offset);
|
||||||
TextDocumentIdentifier textDocumentIdentifier = new TextDocumentIdentifier(FileUtils.editorToURIString(editor));
|
TextDocumentIdentifier textDocumentIdentifier = new TextDocumentIdentifier(FileUtils.editorToURIString(editor));
|
||||||
|
@ -471,17 +364,32 @@ public class EditorEventManager {
|
||||||
try {
|
try {
|
||||||
List<? extends Location> res = request.get(Timeout.getTimeout(Timeouts.REFERENCES), TimeUnit.MILLISECONDS);
|
List<? extends Location> res = request.get(Timeout.getTimeout(Timeouts.REFERENCES), TimeUnit.MILLISECONDS);
|
||||||
wrapper.notifySuccess(Timeouts.REFERENCES);
|
wrapper.notifySuccess(Timeouts.REFERENCES);
|
||||||
if (res != null && res.size() > 0) {
|
if (res != null && !res.isEmpty()) {
|
||||||
List<VirtualFile> openedEditors = new ArrayList<>();
|
List<VirtualFile> openedEditors = fast ? null : new ArrayList<>();
|
||||||
List<PsiElement> elements = new ArrayList<>();
|
List<PsiElement> elements = new ArrayList<>();
|
||||||
res.forEach(l -> {
|
res.forEach(l -> {
|
||||||
Position start = l.getRange().getStart();
|
Position start = l.getRange().getStart();
|
||||||
Position end = l.getRange().getEnd();
|
Position end = l.getRange().getEnd();
|
||||||
String uri = FileUtils.sanitizeURI(l.getUri());
|
String uri = FileUtils.sanitizeURI(l.getUri());
|
||||||
VirtualFile file = FileUtils.virtualFileFromURI(uri);
|
VirtualFile file = FileUtils.virtualFileFromURI(uri);
|
||||||
|
if (fast) {
|
||||||
|
if (file == null)
|
||||||
|
return;
|
||||||
|
val document = FileDocumentManager.getInstance().getDocument(file);
|
||||||
|
if (document == null)
|
||||||
|
return;
|
||||||
|
val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document);
|
||||||
|
if (psiFile == null)
|
||||||
|
return;
|
||||||
|
val element = psiFile.findElementAt(DocumentUtils.LSPPosToOffset(document, start));
|
||||||
|
if (element == null)
|
||||||
|
return;
|
||||||
|
elements.add(element);
|
||||||
|
} else {
|
||||||
Editor curEditor = FileUtils.editorFromUri(uri, project);
|
Editor curEditor = FileUtils.editorFromUri(uri, project);
|
||||||
if (curEditor == null && file != null) {
|
if (curEditor == null && file != null) {
|
||||||
OpenFileDescriptor descriptor = new OpenFileDescriptor(project, file, start.getLine(), start.getCharacter());
|
OpenFileDescriptor descriptor =
|
||||||
|
new OpenFileDescriptor(project, file, start.getLine(), start.getCharacter());
|
||||||
curEditor = computableWriteAction(
|
curEditor = computableWriteAction(
|
||||||
() -> FileEditorManager.getInstance(project).openTextEditor(descriptor, false));
|
() -> FileEditorManager.getInstance(project).openTextEditor(descriptor, false));
|
||||||
openedEditors.add(file);
|
openedEditors.add(file);
|
||||||
|
@ -494,13 +402,10 @@ public class EditorEventManager {
|
||||||
int logicalEnd = DocumentUtils.LSPPosToOffset(curEditor, end);
|
int logicalEnd = DocumentUtils.LSPPosToOffset(curEditor, end);
|
||||||
String name = curEditor.getDocument().getText(new TextRange(logicalStart, logicalEnd));
|
String name = curEditor.getDocument().getText(new TextRange(logicalStart, logicalEnd));
|
||||||
elements.add(new LSPPsiElement(name, project, logicalStart, logicalEnd,
|
elements.add(new LSPPsiElement(name, project, logicalStart, logicalEnd,
|
||||||
PsiDocumentManager.getInstance(project).getPsiFile(curEditor.getDocument())));
|
PsiDocumentManager.getInstance(project)
|
||||||
});
|
.getPsiFile(curEditor.getDocument())));
|
||||||
if (close) {
|
|
||||||
writeAction(
|
|
||||||
() -> openedEditors.forEach(f -> FileEditorManager.getInstance(project).closeFile(f)));
|
|
||||||
openedEditors.clear();
|
|
||||||
}
|
}
|
||||||
|
});
|
||||||
return new Pair<>(elements, openedEditors);
|
return new Pair<>(elements, openedEditors);
|
||||||
} else {
|
} else {
|
||||||
return new Pair<>(null, null);
|
return new Pair<>(null, null);
|
||||||
|
@ -797,57 +702,6 @@ public class EditorEventManager {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the hover request and shows it
|
|
||||||
*
|
|
||||||
* @param editorPos The editor position
|
|
||||||
* @param point The point at which to show the hint
|
|
||||||
*/
|
|
||||||
private void requestAndShowDoc(LogicalPosition editorPos, Point point) {
|
|
||||||
Position serverPos = computableReadAction(() -> DocumentUtils.logicalToLSPPos(editorPos, editor));
|
|
||||||
CompletableFuture<Hover> request = wrapper.getRequestManager().hover(new HoverParams(identifier, serverPos));
|
|
||||||
if (request == null) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Hover hover = request.get(Timeout.getTimeout(Timeouts.HOVER), TimeUnit.MILLISECONDS);
|
|
||||||
wrapper.notifySuccess(Timeouts.HOVER);
|
|
||||||
|
|
||||||
if (hover == null) {
|
|
||||||
LOG.debug(String.format("Hover is null for file %s and pos (%d;%d)", identifier.getUri(),
|
|
||||||
serverPos.getLine(), serverPos.getCharacter()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
String string = HoverHandler.getHoverString(hover);
|
|
||||||
if (StringUtils.isEmpty(string)) {
|
|
||||||
LOG.warn(String.format("Hover string returned is empty for file %s and pos (%d;%d)",
|
|
||||||
identifier.getUri(), serverPos.getLine(), serverPos.getCharacter()));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getIsCtrlDown()) {
|
|
||||||
invokeLater(() -> {
|
|
||||||
if (!editor.isDisposed()) {
|
|
||||||
currentHint = createAndShowEditorHint(editor, string, point, HintManager.HIDE_BY_OTHER_HINT);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
invokeLater(() -> {
|
|
||||||
if (!editor.isDisposed()) {
|
|
||||||
currentHint = createAndShowEditorHint(editor, string, point);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
} catch (TimeoutException e) {
|
|
||||||
LOG.warn(e);
|
|
||||||
wrapper.notifyFailure(Timeouts.HOVER);
|
|
||||||
} catch (InterruptedException | JsonRpcException | ExecutionException e) {
|
|
||||||
LOG.warn(e);
|
|
||||||
wrapper.crashed(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the completion suggestions given a position
|
* Returns the completion suggestions given a position
|
||||||
*
|
*
|
||||||
|
@ -1290,8 +1144,6 @@ public class EditorEventManager {
|
||||||
* Adds all the listeners
|
* Adds all the listeners
|
||||||
*/
|
*/
|
||||||
public void registerListeners() {
|
public void registerListeners() {
|
||||||
editor.addEditorMouseListener(mouseListener);
|
|
||||||
editor.addEditorMouseMotionListener(mouseMotionListener);
|
|
||||||
editor.getCaretModel().addCaretListener(caretListener);
|
editor.getCaretModel().addCaretListener(caretListener);
|
||||||
// Todo - Implement
|
// Todo - Implement
|
||||||
// editor.getSelectionModel.addSelectionListener(selectionListener)
|
// editor.getSelectionModel.addSelectionListener(selectionListener)
|
||||||
|
@ -1301,8 +1153,6 @@ public class EditorEventManager {
|
||||||
* Removes all the listeners
|
* Removes all the listeners
|
||||||
*/
|
*/
|
||||||
public void removeListeners() {
|
public void removeListeners() {
|
||||||
editor.removeEditorMouseListener(mouseListener);
|
|
||||||
editor.removeEditorMouseMotionListener(mouseMotionListener);
|
|
||||||
editor.getCaretModel().removeCaretListener(caretListener);
|
editor.getCaretModel().removeCaretListener(caretListener);
|
||||||
// Todo - Implement
|
// Todo - Implement
|
||||||
// editor.getSelectionModel.removeSelectionListener(selectionListener)
|
// editor.getSelectionModel.removeSelectionListener(selectionListener)
|
||||||
|
@ -1444,50 +1294,58 @@ public class EditorEventManager {
|
||||||
saveDocument();
|
saveDocument();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// Tries to go to definition
|
||||||
// Tries to go to definition / show usages based on the element which is
|
public void gotoDefinition(PsiElement element) {
|
||||||
private void trySourceNavigationAndHover(EditorMouseEvent e) {
|
|
||||||
if (editor.isDisposed()) {
|
if (editor.isDisposed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
val sourceOffset = element.getTextOffset();
|
||||||
|
val loc = requestDefinition(DocumentUtils.offsetToLSPPos(editor, sourceOffset));
|
||||||
|
|
||||||
createCtrlRange(DocumentUtils.logicalToLSPPos(editor.xyToLogicalPosition(e.getMouseEvent().getPoint()), editor),
|
|
||||||
null);
|
|
||||||
final CtrlRangeMarker ctrlRange = getCtrlRange();
|
|
||||||
|
|
||||||
if (ctrlRange == null) {
|
|
||||||
int offset = editor.logicalPositionToOffset(editor.xyToLogicalPosition(e.getMouseEvent().getPoint()));
|
|
||||||
LSPReferencesAction referencesAction = (LSPReferencesAction) ActionManager.getInstance()
|
|
||||||
.getAction("LSPFindUsages");
|
|
||||||
if (referencesAction != null) {
|
|
||||||
referencesAction.forManagerAndOffset(this, offset);
|
|
||||||
}
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Location loc = ctrlRange.location;
|
|
||||||
invokeLater(() -> {
|
invokeLater(() -> {
|
||||||
if (editor.isDisposed()) {
|
if (editor.isDisposed()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
int offset = editor.logicalPositionToOffset(editor.xyToLogicalPosition(e.getMouseEvent().getPoint()));
|
gotoLocation(loc);
|
||||||
String locUri = FileUtils.sanitizeURI(loc.getUri());
|
});
|
||||||
|
}
|
||||||
|
|
||||||
if (identifier.getUri().equals(locUri)
|
// Tries to go to declaration / show usages based on the element which is
|
||||||
&& offset >= DocumentUtils.LSPPosToOffset(editor, loc.getRange().getStart())
|
public void gotoDeclarationOrUsages(PsiElement element) {
|
||||||
&& offset <= DocumentUtils.LSPPosToOffset(editor, loc.getRange().getEnd())) {
|
if (editor.isDisposed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
val sourceOffset = element.getTextOffset();
|
||||||
|
val loc = requestDeclaration(DocumentUtils.offsetToLSPPos(editor, sourceOffset));
|
||||||
|
|
||||||
|
if (loc == null) {
|
||||||
LSPReferencesAction referencesAction = (LSPReferencesAction) ActionManager.getInstance()
|
LSPReferencesAction referencesAction = (LSPReferencesAction) ActionManager.getInstance()
|
||||||
.getAction("LSPFindUsages");
|
.getAction("LSPFindUsages");
|
||||||
if (referencesAction != null) {
|
if (referencesAction != null) {
|
||||||
referencesAction.forManagerAndOffset(this, offset);
|
referencesAction.forManagerAndOffset(this, sourceOffset);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
invokeLater(() -> {
|
||||||
|
if (editor.isDisposed()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String locUri = FileUtils.sanitizeURI(loc.getUri());
|
||||||
|
|
||||||
|
if (identifier.getUri().equals(locUri)
|
||||||
|
&& sourceOffset >= DocumentUtils.LSPPosToOffset(editor, loc.getRange().getStart())
|
||||||
|
&& sourceOffset <= DocumentUtils.LSPPosToOffset(editor, loc.getRange().getEnd())) {
|
||||||
|
LSPReferencesAction referencesAction = (LSPReferencesAction) ActionManager.getInstance()
|
||||||
|
.getAction("LSPFindUsages");
|
||||||
|
if (referencesAction != null) {
|
||||||
|
referencesAction.forManagerAndOffset(this, sourceOffset);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
gotoLocation(loc);
|
gotoLocation(loc);
|
||||||
}
|
}
|
||||||
|
|
||||||
ctrlRange.dispose();
|
|
||||||
setCtrlRange(null);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1599,7 +1457,8 @@ public class EditorEventManager {
|
||||||
});
|
});
|
||||||
// If code actions are updated, forcefully triggers the inspection tool.
|
// If code actions are updated, forcefully triggers the inspection tool.
|
||||||
if (codeActionSyncRequired) {
|
if (codeActionSyncRequired) {
|
||||||
updateErrorAnnotations();
|
// double-delay the update to ensure that the code analyzer finishes.
|
||||||
|
invokeLater(this::updateErrorAnnotations);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -19,6 +19,7 @@ import com.falsepattern.zigbrains.lsp.utils.ApplicationUtils;
|
||||||
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
|
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
|
||||||
import com.falsepattern.zigbrains.lsp.utils.OSUtils;
|
import com.falsepattern.zigbrains.lsp.utils.OSUtils;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
|
import lombok.val;
|
||||||
import org.eclipse.lsp4j.Diagnostic;
|
import org.eclipse.lsp4j.Diagnostic;
|
||||||
|
|
||||||
import java.awt.KeyboardFocusManager;
|
import java.awt.KeyboardFocusManager;
|
||||||
|
@ -36,56 +37,6 @@ public class EditorEventManagerBase {
|
||||||
|
|
||||||
private static final Map<String, Set<EditorEventManager>> uriToManagers = new ConcurrentHashMap<>();
|
private static final Map<String, Set<EditorEventManager>> uriToManagers = new ConcurrentHashMap<>();
|
||||||
private static final Map<Editor, EditorEventManager> editorToManager = new ConcurrentHashMap<>();
|
private static final Map<Editor, EditorEventManager> editorToManager = new ConcurrentHashMap<>();
|
||||||
private static final int CTRL_KEY_CODE = OSUtils.isMac() ? KeyEvent.VK_META : KeyEvent.VK_CONTROL;
|
|
||||||
private volatile static boolean isKeyPressed = false;
|
|
||||||
private volatile static boolean isCtrlDown = false;
|
|
||||||
private volatile static CtrlRangeMarker ctrlRange;
|
|
||||||
|
|
||||||
static {
|
|
||||||
KeyboardFocusManager.getCurrentKeyboardFocusManager().addKeyEventDispatcher((KeyEvent e) -> {
|
|
||||||
int eventId = e.getID();
|
|
||||||
if (eventId == KeyEvent.KEY_PRESSED) {
|
|
||||||
setIsKeyPressed(true);
|
|
||||||
if (e.getKeyCode() == CTRL_KEY_CODE) {
|
|
||||||
setIsCtrlDown(true);
|
|
||||||
}
|
|
||||||
} else if (eventId == KeyEvent.KEY_RELEASED) {
|
|
||||||
setIsKeyPressed(false);
|
|
||||||
if (e.getKeyCode() == CTRL_KEY_CODE) {
|
|
||||||
setIsCtrlDown(false);
|
|
||||||
if (getCtrlRange() != null) {
|
|
||||||
getCtrlRange().dispose();
|
|
||||||
setCtrlRange(null);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static synchronized CtrlRangeMarker getCtrlRange() {
|
|
||||||
return ctrlRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
static synchronized void setCtrlRange(CtrlRangeMarker ctrlRange) {
|
|
||||||
EditorEventManagerBase.ctrlRange = ctrlRange;
|
|
||||||
}
|
|
||||||
|
|
||||||
static synchronized boolean getIsCtrlDown() {
|
|
||||||
return isCtrlDown;
|
|
||||||
}
|
|
||||||
|
|
||||||
static synchronized void setIsCtrlDown(boolean isCtrlDown) {
|
|
||||||
EditorEventManagerBase.isCtrlDown = isCtrlDown;
|
|
||||||
}
|
|
||||||
|
|
||||||
static synchronized boolean getIsKeyPressed() {
|
|
||||||
return isKeyPressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
static synchronized void setIsKeyPressed(boolean isKeyPressed) {
|
|
||||||
EditorEventManagerBase.isKeyPressed = isKeyPressed;
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void prune() {
|
private static void prune() {
|
||||||
pruneEditorManagerMap();
|
pruneEditorManagerMap();
|
||||||
|
@ -159,12 +110,15 @@ public class EditorEventManagerBase {
|
||||||
|
|
||||||
String uri = FileUtils.editorToURIString(manager.editor);
|
String uri = FileUtils.editorToURIString(manager.editor);
|
||||||
synchronized (uriToManagers) {
|
synchronized (uriToManagers) {
|
||||||
Set<EditorEventManager> set = getEditorEventManagerCopy(uri);
|
val managers = uriToManagers.get(uri);
|
||||||
if (set.isEmpty()) {
|
if (managers != null) {
|
||||||
|
managers.remove(manager);
|
||||||
|
if (managers.isEmpty()) {
|
||||||
uriToManagers.remove(uri);
|
uriToManagers.remove(uri);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @param editor An editor
|
* @param editor An editor
|
||||||
|
|
|
@ -26,8 +26,6 @@ import com.falsepattern.zigbrains.lsp.contributors.icon.LSPIconProvider;
|
||||||
import com.falsepattern.zigbrains.lsp.contributors.label.LSPDefaultLabelProvider;
|
import com.falsepattern.zigbrains.lsp.contributors.label.LSPDefaultLabelProvider;
|
||||||
import com.falsepattern.zigbrains.lsp.contributors.label.LSPLabelProvider;
|
import com.falsepattern.zigbrains.lsp.contributors.label.LSPLabelProvider;
|
||||||
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.EditorMouseListenerImpl;
|
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.EditorMouseMotionListenerImpl;
|
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.LSPCaretListenerImpl;
|
import com.falsepattern.zigbrains.lsp.listeners.LSPCaretListenerImpl;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.editor.event.DocumentListener;
|
import com.intellij.openapi.editor.event.DocumentListener;
|
||||||
|
@ -69,8 +67,6 @@ public interface LSPExtensionManager {
|
||||||
*/
|
*/
|
||||||
EditorEventManager getExtendedEditorEventManagerFor(Editor editor,
|
EditorEventManager getExtendedEditorEventManagerFor(Editor editor,
|
||||||
DocumentListener documentListener,
|
DocumentListener documentListener,
|
||||||
EditorMouseListenerImpl mouseListener,
|
|
||||||
EditorMouseMotionListenerImpl mouseMotionListener,
|
|
||||||
LSPCaretListenerImpl caretListener,
|
LSPCaretListenerImpl caretListener,
|
||||||
RequestManager requestManager,
|
RequestManager requestManager,
|
||||||
ServerOptions serverOptions,
|
ServerOptions serverOptions,
|
||||||
|
|
|
@ -1,56 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023-2024 FalsePattern
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.falsepattern.zigbrains.lsp.listeners;
|
|
||||||
|
|
||||||
import com.intellij.openapi.editor.event.EditorMouseEvent;
|
|
||||||
import com.intellij.openapi.editor.event.EditorMouseListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* An EditorMouseListener implementation which listens to mouseExited, mouseEntered and mouseClicked events.
|
|
||||||
*/
|
|
||||||
public class EditorMouseListenerImpl extends LSPListener implements EditorMouseListener {
|
|
||||||
@Override
|
|
||||||
public void mousePressed(EditorMouseEvent editorMouseEvent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseClicked(EditorMouseEvent editorMouseEvent) {
|
|
||||||
if (checkEnabled()) {
|
|
||||||
manager.mouseClicked(editorMouseEvent);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseReleased(EditorMouseEvent editorMouseEvent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseEntered(EditorMouseEvent editorMouseEvent) {
|
|
||||||
if (checkEnabled()) {
|
|
||||||
manager.mouseEntered();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseExited(EditorMouseEvent editorMouseEvent) {
|
|
||||||
if (checkEnabled()) {
|
|
||||||
manager.mouseExited();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,37 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright 2023-2024 FalsePattern
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package com.falsepattern.zigbrains.lsp.listeners;
|
|
||||||
|
|
||||||
import com.intellij.openapi.editor.event.EditorMouseEvent;
|
|
||||||
import com.intellij.openapi.editor.event.EditorMouseMotionListener;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Class listening for mouse movement in an editor (used for hover)
|
|
||||||
*/
|
|
||||||
public class EditorMouseMotionListenerImpl extends LSPListener implements EditorMouseMotionListener {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseMoved(EditorMouseEvent e) {
|
|
||||||
if (checkEnabled()) {
|
|
||||||
manager.mouseMoved(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void mouseDragged(EditorMouseEvent editorMouseEvent) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -102,28 +102,7 @@ class LSPFileEventManager {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
String oldFileUri = String.format("%s/%s", oldParentUri, event.getFileName());
|
String oldFileUri = String.format("%s/%s", oldParentUri, event.getFileName());
|
||||||
|
closeAndReopenAffectedFile(file, oldFileUri);
|
||||||
ApplicationUtils.invokeAfterPsiEvents(() -> {
|
|
||||||
// Notifies the language server.
|
|
||||||
FileUtils.findProjectsFor(file).forEach(p -> changedConfiguration(oldFileUri,
|
|
||||||
FileUtils.projectToUri(p), FileChangeType.Deleted));
|
|
||||||
FileUtils.findProjectsFor(file).forEach(p -> changedConfiguration(newFileUri,
|
|
||||||
FileUtils.projectToUri(p), FileChangeType.Created));
|
|
||||||
|
|
||||||
FileUtils.findProjectsFor(file).forEach(p -> {
|
|
||||||
// Detaches old file from the wrappers.
|
|
||||||
Set<LanguageServerWrapper> wrappers = IntellijLanguageClient.getAllServerWrappersFor(FileUtils.projectToUri(p));
|
|
||||||
if (wrappers != null) {
|
|
||||||
wrappers.forEach(wrapper -> wrapper.disconnect(oldFileUri, FileUtils.projectToUri(p)));
|
|
||||||
}
|
|
||||||
// Re-open file to so that the new editor will be connected to the language server.
|
|
||||||
FileEditorManager fileEditorManager = FileEditorManager.getInstance(p);
|
|
||||||
ApplicationUtils.invokeLater(() -> {
|
|
||||||
fileEditorManager.closeFile(file);
|
|
||||||
fileEditorManager.openFile(file, true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
LOG.warn("LSP file move event failed due to :", e);
|
LOG.warn("LSP file move event failed due to :", e);
|
||||||
}
|
}
|
||||||
|
@ -169,6 +148,16 @@ class LSPFileEventManager {
|
||||||
}
|
}
|
||||||
String newFileUri = FileUtils.VFSToURI(file);
|
String newFileUri = FileUtils.VFSToURI(file);
|
||||||
String oldFileUri = newFileUri.replace(file.getName(), oldFileName);
|
String oldFileUri = newFileUri.replace(file.getName(), oldFileName);
|
||||||
|
closeAndReopenAffectedFile(file, oldFileUri);
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
LOG.warn("LSP file rename event failed due to : ", e);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void closeAndReopenAffectedFile(VirtualFile file, String oldFileUri) {
|
||||||
|
String newFileUri = FileUtils.VFSToURI(file);
|
||||||
|
|
||||||
// Notifies the language server.
|
// Notifies the language server.
|
||||||
FileUtils.findProjectsFor(file).forEach(p -> changedConfiguration(oldFileUri,
|
FileUtils.findProjectsFor(file).forEach(p -> changedConfiguration(oldFileUri,
|
||||||
|
@ -179,17 +168,7 @@ class LSPFileEventManager {
|
||||||
FileUtils.findProjectsFor(file).forEach(p -> {
|
FileUtils.findProjectsFor(file).forEach(p -> {
|
||||||
// Detaches old file from the wrappers.
|
// Detaches old file from the wrappers.
|
||||||
Set<LanguageServerWrapper> wrappers = IntellijLanguageClient.getAllServerWrappersFor(FileUtils.projectToUri(p));
|
Set<LanguageServerWrapper> wrappers = IntellijLanguageClient.getAllServerWrappersFor(FileUtils.projectToUri(p));
|
||||||
if (wrappers != null) {
|
wrappers.forEach(wrapper -> wrapper.disconnect(oldFileUri, FileUtils.projectToUri(p)));
|
||||||
wrappers.forEach(wrapper -> {
|
|
||||||
// make these calls first since the disconnect might stop the LS client if its last file.
|
|
||||||
wrapper.getRequestManager().didChangeWatchedFiles(
|
|
||||||
getDidChangeWatchedFilesParams(oldFileUri, FileChangeType.Deleted));
|
|
||||||
wrapper.getRequestManager().didChangeWatchedFiles(
|
|
||||||
getDidChangeWatchedFilesParams(newFileUri, FileChangeType.Created));
|
|
||||||
|
|
||||||
wrapper.disconnect(oldFileUri, FileUtils.projectToUri(p));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (!newFileUri.equals(oldFileUri)) {
|
if (!newFileUri.equals(oldFileUri)) {
|
||||||
// Re-open file to so that the new editor will be connected to the language server.
|
// Re-open file to so that the new editor will be connected to the language server.
|
||||||
FileEditorManager fileEditorManager = FileEditorManager.getInstance(p);
|
FileEditorManager fileEditorManager = FileEditorManager.getInstance(p);
|
||||||
|
@ -200,11 +179,6 @@ class LSPFileEventManager {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
|
||||||
LOG.warn("LSP file rename event failed due to : ", e);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called when a file is created. Notifies the server if needed.
|
* Called when a file is created. Notifies the server if needed.
|
||||||
|
|
|
@ -19,7 +19,7 @@ package com.falsepattern.zigbrains.lsp.requests;
|
||||||
* Enumeration for the timeouts
|
* Enumeration for the timeouts
|
||||||
*/
|
*/
|
||||||
public enum Timeouts {
|
public enum Timeouts {
|
||||||
CODEACTION(2000), CODELENS(2000), COMPLETION(1000), DEFINITION(2000), DOC_HIGHLIGHT(1000), EXECUTE_COMMAND(
|
CODEACTION(2000), CODELENS(2000), COMPLETION(1000), DECLARATION(2000), DEFINITION(2000), DOC_HIGHLIGHT(1000), EXECUTE_COMMAND(
|
||||||
2000), FORMATTING(2000), HOVER(2000), INIT(10000), REFERENCES(2000), SIGNATURE(1000), SHUTDOWN(
|
2000), FORMATTING(2000), HOVER(2000), INIT(10000), REFERENCES(2000), SIGNATURE(1000), SHUTDOWN(
|
||||||
5000), SYMBOLS(2000), WILLSAVE(2000), FOLDING(1000), HIGHLIGHTING(1000), INLAY_HINTS(2000);
|
5000), SYMBOLS(2000), WILLSAVE(2000), FOLDING(1000), HIGHLIGHTING(1000), INLAY_HINTS(2000);
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,10 @@ public class DocumentUtils {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int LSPPosToOffset(Document document, Position pos) {
|
||||||
|
return document.getLineStartOffset(pos.getLine()) + pos.getCharacter();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms an LSP position to an editor offset
|
* Transforms an LSP position to an editor offset
|
||||||
*
|
*
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
package com.falsepattern.zigbrains.project.ide.project;
|
package com.falsepattern.zigbrains.project.ide.project;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
|
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
|
||||||
|
import com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity;
|
||||||
import com.intellij.openapi.options.Configurable;
|
import com.intellij.openapi.options.Configurable;
|
||||||
import com.intellij.openapi.options.ConfigurationException;
|
import com.intellij.openapi.options.ConfigurationException;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
|
@ -66,10 +67,14 @@ public class ZigProjectConfigurable implements Configurable {
|
||||||
public void apply() throws ConfigurationException {
|
public void apply() throws ConfigurationException {
|
||||||
val zigSettings = ZigProjectSettingsService.getInstance(project);
|
val zigSettings = ZigProjectSettingsService.getInstance(project);
|
||||||
val settingsData = settingsPanel.getData();
|
val settingsData = settingsPanel.getData();
|
||||||
|
boolean modified = isModified();
|
||||||
zigSettings.modify((settings) -> {
|
zigSettings.modify((settings) -> {
|
||||||
settings.setToolchain(settingsData.toolchain());
|
settings.setToolchain(settingsData.toolchain());
|
||||||
settings.setExplicitPathToStd(settingsData.explicitPathToStd());
|
settings.setExplicitPathToStd(settingsData.explicitPathToStd());
|
||||||
});
|
});
|
||||||
|
if (modified) {
|
||||||
|
ZLSStartupActivity.initZLS(project);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.project.toolchain;
|
||||||
|
|
||||||
|
import com.falsepattern.zigbrains.project.openapi.components.ZigProjectSettingsService;
|
||||||
|
import com.falsepattern.zigbrains.zig.environment.ZLSConfig;
|
||||||
|
import com.falsepattern.zigbrains.zig.environment.ZLSConfigProvider;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import com.intellij.openapi.project.ProjectUtil;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
public class ToolchainZLSConfigProvider implements ZLSConfigProvider {
|
||||||
|
@Override
|
||||||
|
public @NotNull ZLSConfig getEnvironment(Project project) {
|
||||||
|
val projectSettings = ZigProjectSettingsService.getInstance(project);
|
||||||
|
val toolchain = projectSettings.getToolchain();
|
||||||
|
if (toolchain == null)
|
||||||
|
return ZLSConfig.EMPTY;
|
||||||
|
val projectDir = ProjectUtil.guessProjectDir(project);
|
||||||
|
val env = toolchain.zig().getEnv(projectDir == null ? Path.of(".") : projectDir.toNioPath());
|
||||||
|
return env.map(e -> new ZLSConfig(e.zigExecutable(), e.libDirectory())).orElse(ZLSConfig.EMPTY);
|
||||||
|
}
|
||||||
|
}
|
|
@ -38,6 +38,7 @@
|
||||||
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
<extensions defaultExtensionNs="com.falsepattern.zigbrains">
|
||||||
<toolchainFlavour implementation="com.falsepattern.zigbrains.project.toolchain.flavours.ZigSystemPathToolchainFlavour"/>
|
<toolchainFlavour implementation="com.falsepattern.zigbrains.project.toolchain.flavours.ZigSystemPathToolchainFlavour"/>
|
||||||
<toolchainProvider implementation="com.falsepattern.zigbrains.project.toolchain.LocalZigToolchainProvider"/>
|
<toolchainProvider implementation="com.falsepattern.zigbrains.project.toolchain.LocalZigToolchainProvider"/>
|
||||||
|
<zlsConfigProvider implementation="com.falsepattern.zigbrains.project.toolchain.ToolchainZLSConfigProvider"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
<actions>
|
<actions>
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.zig.environment;
|
||||||
|
|
||||||
|
import com.google.gson.JsonObject;
|
||||||
|
import com.google.gson.annotations.SerializedName;
|
||||||
|
import lombok.val;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
public record ZLSConfig(@NotNull Optional<String> zigExePath,
|
||||||
|
@NotNull Optional<String> zigLibPath) {
|
||||||
|
public ZLSConfig(String zigExePath, String zigLibPath) {
|
||||||
|
this(Optional.ofNullable(zigExePath), Optional.ofNullable(zigLibPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public ZLSConfig overrideWith(ZLSConfig other) {
|
||||||
|
return new ZLSConfig(other.zigExePath.or(() -> zigExePath),
|
||||||
|
other.zigLibPath.or(() -> zigLibPath));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final ZLSConfig EMPTY = new ZLSConfig(Optional.empty(), Optional.empty());
|
||||||
|
|
||||||
|
public JsonObject toJson() {
|
||||||
|
val result = new JsonObject();
|
||||||
|
zigExePath.ifPresent(s -> result.addProperty("zig_exe_path", s));
|
||||||
|
zigLibPath.ifPresent(s -> result.addProperty("zig_lib_path", s));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright 2023-2024 FalsePattern
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package com.falsepattern.zigbrains.zig.environment;
|
||||||
|
|
||||||
|
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||||
|
import com.intellij.openapi.project.Project;
|
||||||
|
import org.jetbrains.annotations.NotNull;
|
||||||
|
|
||||||
|
public interface ZLSConfigProvider {
|
||||||
|
ExtensionPointName<ZLSConfigProvider> EXTENSION_POINT_NAME = ExtensionPointName.create("com.falsepattern.zigbrains.zlsConfigProvider");
|
||||||
|
|
||||||
|
static @NotNull ZLSConfig findEnvironment(Project project) {
|
||||||
|
return EXTENSION_POINT_NAME.getExtensionList()
|
||||||
|
.stream()
|
||||||
|
.map(it -> it.getEnvironment(project))
|
||||||
|
.reduce(ZLSConfig.EMPTY, ZLSConfig::overrideWith);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NotNull ZLSConfig getEnvironment(Project project);
|
||||||
|
}
|
|
@ -23,17 +23,20 @@ import com.falsepattern.zigbrains.lsp.editor.EditorEventManager;
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.LSPCaretListenerImpl;
|
import com.falsepattern.zigbrains.lsp.listeners.LSPCaretListenerImpl;
|
||||||
import com.falsepattern.zigbrains.lsp.requests.Timeouts;
|
import com.falsepattern.zigbrains.lsp.requests.Timeouts;
|
||||||
import com.falsepattern.zigbrains.zig.ide.SemaEdit;
|
import com.falsepattern.zigbrains.zig.ide.SemaEdit;
|
||||||
|
import com.falsepattern.zigbrains.zig.util.HighlightingUtil;
|
||||||
import com.falsepattern.zigbrains.zig.util.TokenDecoder;
|
import com.falsepattern.zigbrains.zig.util.TokenDecoder;
|
||||||
import com.intellij.lang.annotation.Annotation;
|
import com.intellij.lang.annotation.Annotation;
|
||||||
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.editor.event.DocumentListener;
|
import com.intellij.openapi.editor.event.DocumentListener;
|
||||||
import com.intellij.openapi.editor.event.EditorMouseListener;
|
import lombok.val;
|
||||||
import com.intellij.openapi.editor.event.EditorMouseMotionListener;
|
import org.eclipse.lsp4j.InsertReplaceEdit;
|
||||||
import org.eclipse.lsp4j.SemanticTokens;
|
import org.eclipse.lsp4j.SemanticTokens;
|
||||||
import org.eclipse.lsp4j.SemanticTokensDelta;
|
import org.eclipse.lsp4j.SemanticTokensDelta;
|
||||||
import org.eclipse.lsp4j.SemanticTokensDeltaParams;
|
import org.eclipse.lsp4j.SemanticTokensDeltaParams;
|
||||||
import org.eclipse.lsp4j.SemanticTokensEdit;
|
import org.eclipse.lsp4j.SemanticTokensEdit;
|
||||||
import org.eclipse.lsp4j.SemanticTokensParams;
|
import org.eclipse.lsp4j.SemanticTokensParams;
|
||||||
|
import org.eclipse.lsp4j.TextEdit;
|
||||||
import org.eclipse.lsp4j.jsonrpc.JsonRpcException;
|
import org.eclipse.lsp4j.jsonrpc.JsonRpcException;
|
||||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||||
|
|
||||||
|
@ -49,8 +52,8 @@ import static com.falsepattern.zigbrains.lsp.requests.Timeout.getTimeout;
|
||||||
public class ZLSEditorEventManager extends EditorEventManager {
|
public class ZLSEditorEventManager extends EditorEventManager {
|
||||||
private static String previousResultID = null;
|
private static String previousResultID = null;
|
||||||
|
|
||||||
public ZLSEditorEventManager(Editor editor, DocumentListener documentListener, EditorMouseListener mouseListener, EditorMouseMotionListener mouseMotionListener, LSPCaretListenerImpl caretListener, RequestManager requestmanager, ServerOptions serverOptions, LanguageServerWrapper wrapper) {
|
public ZLSEditorEventManager(Editor editor, DocumentListener documentListener, LSPCaretListenerImpl caretListener, RequestManager requestmanager, ServerOptions serverOptions, LanguageServerWrapper wrapper) {
|
||||||
super(editor, documentListener, mouseListener, mouseMotionListener, caretListener, requestmanager,
|
super(editor, documentListener, caretListener, requestmanager,
|
||||||
serverOptions, wrapper);
|
serverOptions, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -108,4 +111,15 @@ public class ZLSEditorEventManager extends EditorEventManager {
|
||||||
}
|
}
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Runnable getEditsRunnable(int version, List<Either<TextEdit, InsertReplaceEdit>> edits, String name, boolean setCaret) {
|
||||||
|
val run = super.getEditsRunnable(version, edits, name, setCaret);
|
||||||
|
return () -> {
|
||||||
|
run.run();
|
||||||
|
if (!editor.isDisposed()) {
|
||||||
|
ApplicationManager.getApplication().invokeLater(() -> HighlightingUtil.refreshHighlighting(this));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -21,8 +21,6 @@ import com.falsepattern.zigbrains.lsp.client.languageserver.ServerOptions;
|
||||||
import com.falsepattern.zigbrains.lsp.client.languageserver.requestmanager.RequestManager;
|
import com.falsepattern.zigbrains.lsp.client.languageserver.requestmanager.RequestManager;
|
||||||
import com.falsepattern.zigbrains.lsp.client.languageserver.wrapper.LanguageServerWrapper;
|
import com.falsepattern.zigbrains.lsp.client.languageserver.wrapper.LanguageServerWrapper;
|
||||||
import com.falsepattern.zigbrains.lsp.extensions.LSPExtensionManager;
|
import com.falsepattern.zigbrains.lsp.extensions.LSPExtensionManager;
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.EditorMouseListenerImpl;
|
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.EditorMouseMotionListenerImpl;
|
|
||||||
import com.falsepattern.zigbrains.lsp.listeners.LSPCaretListenerImpl;
|
import com.falsepattern.zigbrains.lsp.listeners.LSPCaretListenerImpl;
|
||||||
import com.intellij.openapi.editor.Editor;
|
import com.intellij.openapi.editor.Editor;
|
||||||
import com.intellij.openapi.editor.event.DocumentListener;
|
import com.intellij.openapi.editor.event.DocumentListener;
|
||||||
|
@ -37,8 +35,8 @@ public class ZLSExtensionManager implements LSPExtensionManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public ZLSEditorEventManager getExtendedEditorEventManagerFor(Editor editor, DocumentListener documentListener, EditorMouseListenerImpl mouseListener, EditorMouseMotionListenerImpl mouseMotionListener, LSPCaretListenerImpl caretListener, RequestManager requestManager, ServerOptions serverOptions, LanguageServerWrapper wrapper) {
|
public ZLSEditorEventManager getExtendedEditorEventManagerFor(Editor editor, DocumentListener documentListener, LSPCaretListenerImpl caretListener, RequestManager requestManager, ServerOptions serverOptions, LanguageServerWrapper wrapper) {
|
||||||
return new ZLSEditorEventManager(editor, documentListener, mouseListener, mouseMotionListener,
|
return new ZLSEditorEventManager(editor, documentListener,
|
||||||
caretListener, requestManager, serverOptions, wrapper);
|
caretListener, requestManager, serverOptions, wrapper);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -18,18 +18,23 @@ package com.falsepattern.zigbrains.zig.lsp;
|
||||||
|
|
||||||
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
import com.falsepattern.zigbrains.lsp.IntellijLanguageClient;
|
||||||
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
|
import com.falsepattern.zigbrains.lsp.utils.FileUtils;
|
||||||
|
import com.falsepattern.zigbrains.zig.environment.ZLSConfigProvider;
|
||||||
import com.falsepattern.zigbrains.zig.settings.ZLSSettingsState;
|
import com.falsepattern.zigbrains.zig.settings.ZLSSettingsState;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import com.intellij.notification.Notification;
|
import com.intellij.notification.Notification;
|
||||||
import com.intellij.notification.NotificationType;
|
import com.intellij.notification.NotificationType;
|
||||||
import com.intellij.notification.Notifications;
|
import com.intellij.notification.Notifications;
|
||||||
import com.intellij.openapi.application.ApplicationManager;
|
import com.intellij.openapi.application.ApplicationManager;
|
||||||
|
import com.intellij.openapi.diagnostic.Logger;
|
||||||
import com.intellij.openapi.project.Project;
|
import com.intellij.openapi.project.Project;
|
||||||
import com.intellij.openapi.startup.ProjectActivity;
|
import com.intellij.openapi.startup.ProjectActivity;
|
||||||
import kotlin.Unit;
|
import kotlin.Unit;
|
||||||
import kotlin.coroutines.Continuation;
|
import kotlin.coroutines.Continuation;
|
||||||
|
import lombok.val;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.InvalidPathException;
|
import java.nio.file.InvalidPathException;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
|
@ -37,6 +42,7 @@ import java.util.ArrayList;
|
||||||
import java.util.concurrent.locks.ReentrantLock;
|
import java.util.concurrent.locks.ReentrantLock;
|
||||||
|
|
||||||
public class ZLSStartupActivity implements ProjectActivity {
|
public class ZLSStartupActivity implements ProjectActivity {
|
||||||
|
private static final Logger LOG = Logger.getInstance(ZLSStartupActivity.class);
|
||||||
private static final ReentrantLock lock = new ReentrantLock();
|
private static final ReentrantLock lock = new ReentrantLock();
|
||||||
|
|
||||||
public static void initZLS(Project project) {
|
public static void initZLS(Project project) {
|
||||||
|
@ -59,12 +65,31 @@ public class ZLSStartupActivity implements ProjectActivity {
|
||||||
var configPath = settings.zlsConfigPath;
|
var configPath = settings.zlsConfigPath;
|
||||||
boolean configOK = true;
|
boolean configOK = true;
|
||||||
if (!"".equals(configPath) && !validatePath("ZLS Config", configPath, false)) {
|
if (!"".equals(configPath) && !validatePath("ZLS Config", configPath, false)) {
|
||||||
configOK = false;
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "Using default config path.",
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.Nag", "Using default config path.",
|
|
||||||
NotificationType.INFORMATION));
|
NotificationType.INFORMATION));
|
||||||
|
configPath = "";
|
||||||
}
|
}
|
||||||
if ("".equals(configPath)) {
|
if ("".equals(configPath)) {
|
||||||
|
blk:
|
||||||
|
try {
|
||||||
|
val tmpFile = Files.createTempFile("zigbrains-zls-autoconf", ".json");
|
||||||
|
val config = ZLSConfigProvider.findEnvironment(project);
|
||||||
|
if (config.zigExePath().isEmpty() && config.zigLibPath().isEmpty()) {
|
||||||
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "(ZLS) Failed to detect zig path from project toolchain", NotificationType.WARNING));
|
||||||
configOK = false;
|
configOK = false;
|
||||||
|
break blk;
|
||||||
|
}
|
||||||
|
try (val writer = Files.newBufferedWriter(tmpFile)) {
|
||||||
|
val gson = new Gson();
|
||||||
|
gson.toJson(config.toJson(), writer);
|
||||||
|
}
|
||||||
|
configPath = tmpFile.toAbsolutePath().toString();
|
||||||
|
} catch (IOException e) {
|
||||||
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "Failed to create automatic zls config file",
|
||||||
|
NotificationType.WARNING));
|
||||||
|
LOG.warn(e);
|
||||||
|
configOK = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IntellijLanguageClient.getExtensionManagerFor("zig") == null) {
|
if (IntellijLanguageClient.getExtensionManagerFor("zig") == null) {
|
||||||
|
@ -112,18 +137,18 @@ public class ZLSStartupActivity implements ProjectActivity {
|
||||||
path = Path.of(pathTxt);
|
path = Path.of(pathTxt);
|
||||||
} catch (InvalidPathException e) {
|
} catch (InvalidPathException e) {
|
||||||
Notifications.Bus.notify(
|
Notifications.Bus.notify(
|
||||||
new Notification("ZigBrains.Nag", "No " + name, "Invalid " + name + " path \"" + pathTxt + "\"",
|
new Notification("ZigBrains.ZLS", "No " + name, "Invalid " + name + " path \"" + pathTxt + "\"",
|
||||||
NotificationType.ERROR));
|
NotificationType.ERROR));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!Files.exists(path)) {
|
if (!Files.exists(path)) {
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.Nag", "No " + name,
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "No " + name,
|
||||||
"The " + name + " at \"" + pathTxt + "\" doesn't exist!",
|
"The " + name + " at \"" + pathTxt + "\" doesn't exist!",
|
||||||
NotificationType.ERROR));
|
NotificationType.ERROR));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (Files.isDirectory(path) != dir) {
|
if (Files.isDirectory(path) != dir) {
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.Nag", "No " + name,
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "No " + name,
|
||||||
"The " + name + " at \"" + pathTxt + "\" is a " +
|
"The " + name + " at \"" + pathTxt + "\" is a " +
|
||||||
(Files.isDirectory(path) ? "directory" : "file") +
|
(Files.isDirectory(path) ? "directory" : "file") +
|
||||||
" , expected a " + (dir ? "directory" : "file"),
|
" , expected a " + (dir ? "directory" : "file"),
|
||||||
|
@ -146,8 +171,8 @@ public class ZLSStartupActivity implements ProjectActivity {
|
||||||
zlsPath = settings.zlsPath = thePath.get();
|
zlsPath = settings.zlsPath = thePath.get();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ("".equals(zlsPath)) {
|
if (zlsPath.isEmpty()) {
|
||||||
Notifications.Bus.notify(new Notification("ZigBrains.Nag", "No ZLS binary",
|
Notifications.Bus.notify(new Notification("ZigBrains.ZLS", "No ZLS binary",
|
||||||
"Please configure the path to the zls executable in the Zig language configuration menu!",
|
"Please configure the path to the zls executable in the Zig language configuration menu!",
|
||||||
NotificationType.INFORMATION));
|
NotificationType.INFORMATION));
|
||||||
return null;
|
return null;
|
||||||
|
|
|
@ -46,7 +46,7 @@ public class ZLSSettingsComponent {
|
||||||
.addVerticalGap(10)
|
.addVerticalGap(10)
|
||||||
.addLabeledComponent(new JBLabel("ZLS path: "), zlsPathText, 1, false)
|
.addLabeledComponent(new JBLabel("ZLS path: "), zlsPathText, 1, false)
|
||||||
.addComponent(autodetectZls)
|
.addComponent(autodetectZls)
|
||||||
.addLabeledComponent(new JBLabel("ZLS config path (leave empty to use default): "),
|
.addLabeledComponent(new JBLabel("ZLS config path (leave empty to use built-in config): "),
|
||||||
zlsConfigPathText, 1, false)
|
zlsConfigPathText, 1, false)
|
||||||
.addLabeledComponent(new JBLabel("Increase timeouts"), increaseTimeouts, 1, false)
|
.addLabeledComponent(new JBLabel("Increase timeouts"), increaseTimeouts, 1, false)
|
||||||
.addLabeledComponent(new JBLabel("Asynchronous code folding ranges: "),
|
.addLabeledComponent(new JBLabel("Asynchronous code folding ranges: "),
|
||||||
|
|
|
@ -105,7 +105,9 @@
|
||||||
|
|
||||||
<postStartupActivity implementation="com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity"/>
|
<postStartupActivity implementation="com.falsepattern.zigbrains.zig.lsp.ZLSStartupActivity"/>
|
||||||
<notificationGroup displayType="BALLOON"
|
<notificationGroup displayType="BALLOON"
|
||||||
id="ZigBrains.Nag"/>
|
bundle="zigbrains.zig.Bundle"
|
||||||
|
key="notif-zls"
|
||||||
|
id="ZigBrains.ZLS"/>
|
||||||
</extensions>
|
</extensions>
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,6 +123,10 @@
|
||||||
</action>
|
</action>
|
||||||
<action class="com.falsepattern.zigbrains.lsp.actions.LSPReformatAction" id="ReformatCode" use-shortcut-of="ReformatCode"
|
<action class="com.falsepattern.zigbrains.lsp.actions.LSPReformatAction" id="ReformatCode" use-shortcut-of="ReformatCode"
|
||||||
overrides="true" text="Reformat Code"/>
|
overrides="true" text="Reformat Code"/>
|
||||||
|
<action class="com.falsepattern.zigbrains.lsp.actions.LSPGotoDeclarationAction" id="GotoDeclaration" use-shortcut-of="GotoDeclaration"
|
||||||
|
overrides="true" text="Go to Declaration or Usages"/>
|
||||||
|
<action class="com.falsepattern.zigbrains.lsp.actions.LSPGotoDefinitionAction" id="QuickImplementations" use-shortcut-of="QuickImplementations"
|
||||||
|
overrides="true" text="View Implementations"/>
|
||||||
<action class="com.falsepattern.zigbrains.lsp.actions.LSPShowReformatDialogAction" id="ShowReformatFileDialog"
|
<action class="com.falsepattern.zigbrains.lsp.actions.LSPShowReformatDialogAction" id="ShowReformatFileDialog"
|
||||||
use-shortcut-of="ShowReformatFileDialog" overrides="true" text="Show Reformat File Dialog"/>
|
use-shortcut-of="ShowReformatFileDialog" overrides="true" text="Show Reformat File Dialog"/>
|
||||||
|
|
||||||
|
|
|
@ -1 +1,2 @@
|
||||||
inlayprovider=ZLS Inlay Provider
|
inlayprovider=ZLS Inlay Provider
|
||||||
|
notif-zls=ZLS Error Notification
|
|
@ -11,6 +11,7 @@
|
||||||
<xi:include href="/META-INF/zigbrains-project.xml"/>
|
<xi:include href="/META-INF/zigbrains-project.xml"/>
|
||||||
<!--suppress PluginXmlValidity -->
|
<!--suppress PluginXmlValidity -->
|
||||||
<depends optional="true" config-file="zigbrains-zig-debugger.xml">com.intellij.modules.cidr.debugger</depends>
|
<depends optional="true" config-file="zigbrains-zig-debugger.xml">com.intellij.modules.cidr.debugger</depends>
|
||||||
|
<depends optional="true" config-file="zigbrains-zig-cpp.xml">com.intellij.modules.clion</depends>
|
||||||
|
|
||||||
<extensionPoints>
|
<extensionPoints>
|
||||||
<!-- region zigbrains-project -->
|
<!-- region zigbrains-project -->
|
||||||
|
@ -20,6 +21,12 @@
|
||||||
<extensionPoint
|
<extensionPoint
|
||||||
interface="com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider" dynamic="true"
|
interface="com.falsepattern.zigbrains.project.toolchain.ZigToolchainProvider" dynamic="true"
|
||||||
name="toolchainProvider"/>
|
name="toolchainProvider"/>
|
||||||
|
<extensionPoint
|
||||||
|
interface="com.falsepattern.zigbrains.zig.environment.ZLSConfigProvider" dynamic="true"
|
||||||
|
name="zlsConfigProvider"/>
|
||||||
|
<extensionPoint
|
||||||
|
interface="com.falsepattern.zigbrains.zig.debugbridge.DebuggerDriverProvider" dynamic="true"
|
||||||
|
name="debuggerDriverProvider"/>
|
||||||
<!-- endregion zigbrains-project -->
|
<!-- endregion zigbrains-project -->
|
||||||
</extensionPoints>
|
</extensionPoints>
|
||||||
</idea-plugin>
|
</idea-plugin>
|
||||||
|
|
Loading…
Add table
Reference in a new issue