1
0
mirror of https://github.com/chylex/IntelliJ-Inspection-Lens.git synced 2025-09-17 14:24:48 +02:00

10 Commits

15 changed files with 168 additions and 65 deletions

2
.github/FUNDING.yml vendored
View File

@@ -1,3 +1 @@
github: chylex
patreon: chylex
ko_fi: chylex

1
.gitignore vendored
View File

@@ -3,4 +3,5 @@
!/.idea/runConfigurations
/.gradle/
/.intellijPlatform/
/build/

View File

@@ -2,7 +2,9 @@
Displays errors, warnings, and other inspections inline. Highlights the background of lines with inspections. Supports light and dark themes out of the box.
By default, the plugin shows **Errors**, **Warnings**, **Weak Warnings**, **Server Problems**, **Grammar Errors**, **Typos**, and other inspections with a high enough severity level. Configure visible severities in **Settings | Tools | Inspection Lens**.
By default, the plugin shows **Errors**, **Warnings**, **Weak Warnings**, **Server Problems**, **Grammar Errors**, **Typos**, and other inspections with a high enough severity level. Left-click an inspection to show quick fixes. Middle-click an inspection to navigate to the relevant code in the editor.
Configure appearance, behavior of clicking on inspections, and visible severities in **Settings | Tools | Inspection Lens**.
Inspired by [Error Lens](https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens) for Visual Studio Code, and [Inline Error](https://plugins.jetbrains.com/plugin/17302-inlineerror) for IntelliJ Platform.

View File

@@ -1,48 +1,57 @@
@file:Suppress("ConvertLambdaToReference")
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.8.0"
id("org.jetbrains.intellij") version "1.17.0"
kotlin("jvm")
id("org.jetbrains.intellij.platform")
}
group = "com.chylex.intellij.inspectionlens"
version = "1.4.1"
version = "1.5.1"
repositories {
mavenCentral()
intellijPlatform {
defaultRepositories()
}
}
intellij {
version.set("2023.3.3")
updateSinceUntilBuild.set(false)
dependencies {
intellijPlatform {
intellijIdeaUltimate("2023.3.3")
bundledPlugin("tanvd.grazi")
// https://plugins.jetbrains.com/plugin/12175-grazie-lite/versions
// plugin("tanvd.grazi", "233.13135.14")
}
plugins.add("tanvd.grazi")
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
}
intellijPlatform {
pluginConfiguration {
ideaVersion {
sinceBuild.set("233.11361.10")
untilBuild.set(provider { null })
}
}
}
kotlin {
jvmToolchain(17)
compilerOptions {
freeCompilerArgs = listOf(
"-X" + "jvm-default=all"
)
}
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.9.2")
}
tasks.patchPluginXml {
sinceBuild.set("233.11361.10")
}
tasks.buildSearchableOptions {
enabled = false
}
tasks.test {
tasks.withType<Test>().configureEach {
useJUnitPlatform()
}
tasks.withType<KotlinCompile> {
kotlinOptions.freeCompilerArgs = listOf(
"-Xjvm-default=all"
)
val testSnapshot by intellijPlatformTesting.testIde.registering {
version = "LATEST-EAP-SNAPSHOT"
useInstaller = false
}

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.12-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

6
gradlew vendored
View File

@@ -15,6 +15,8 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#
##############################################################################
#
@@ -55,7 +57,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@@ -84,7 +86,7 @@ done
# shellcheck disable=SC2034
APP_BASE_NAME=${0##*/}
# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)
APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit
APP_HOME=$( cd -P "${APP_HOME:-./}" > /dev/null && printf '%s\n' "$PWD" ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum

22
gradlew.bat vendored
View File

@@ -13,6 +13,8 @@
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@rem SPDX-License-Identifier: Apache-2.0
@rem
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@@ -43,11 +45,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail
@@ -57,11 +59,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
echo. 1>&2
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2
echo. 1>&2
echo Please set the JAVA_HOME variable in your environment to match the 1>&2
echo location of your Java installation. 1>&2
goto fail

View File

@@ -1 +1,8 @@
rootProject.name = "InspectionLens"
pluginManagement {
plugins {
kotlin("jvm") version "1.9.21"
id("org.jetbrains.intellij.platform") version "2.2.1"
}
}

View File

@@ -2,26 +2,40 @@ package com.chylex.intellij.inspectionlens.editor.lens
import com.intellij.codeInsight.daemon.impl.IntentionsUI
import com.intellij.codeInsight.hint.HintManager
import com.intellij.codeInsight.intention.actions.ShowIntentionActionsAction
import com.intellij.codeInsight.intention.impl.ShowIntentionActionsHandler
import com.intellij.lang.LangBundle
import com.intellij.openapi.actionSystem.ActionManager
import com.intellij.openapi.actionSystem.ActionPlaces
import com.intellij.openapi.actionSystem.IdeActions
import com.intellij.openapi.actionSystem.ex.ActionUtil
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ScrollType
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiDocumentManager
import com.intellij.psi.PsiFile
import com.intellij.psi.util.PsiUtilBase
internal object IntentionsPopup {
fun showAt(editor: Editor, offset: Int) {
editor.caretModel.moveToOffset(offset)
editor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
if (!tryShowPopup(editor)) {
HintManager.getInstance().showInformationHint(editor, LangBundle.message("hint.text.no.context.actions.available.at.this.location"));
fun show(editor: Editor) {
if (!tryShow(editor)) {
HintManager.getInstance().showInformationHint(editor, LangBundle.message("hint.text.no.context.actions.available.at.this.location"))
}
}
private fun tryShowPopup(editor: Editor): Boolean {
private fun tryShow(editor: Editor): Boolean {
// If the IDE uses the default Show Intentions action and handler,
// use the handler directly to bypass additional logic from the action.
val action = ActionManager.getInstance().getAction(IdeActions.ACTION_SHOW_INTENTION_ACTIONS)
if (action.javaClass === ShowIntentionActionsAction::class.java) {
return tryShowWithDefaultHandler(editor)
}
else {
ActionUtil.invokeAction(action, editor.component, ActionPlaces.EDITOR_INLAY, null, null)
return true
}
}
private fun tryShowWithDefaultHandler(editor: Editor): Boolean {
val project = editor.project ?: return false
val file = PsiUtilBase.getPsiFileInEditor(editor, project) ?: return false

View File

@@ -1,11 +1,13 @@
package com.chylex.intellij.inspectionlens.editor.lens
import com.chylex.intellij.inspectionlens.settings.LensHoverMode
import com.chylex.intellij.inspectionlens.settings.LensSettingsState
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.codeInsight.daemon.impl.HintRenderer
import com.intellij.codeInsight.hints.presentation.InputHandler
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.Inlay
import com.intellij.openapi.editor.ScrollType
import com.intellij.openapi.editor.colors.EditorFontType
import com.intellij.openapi.editor.ex.EditorEx
import com.intellij.openapi.editor.impl.EditorImpl
@@ -15,6 +17,7 @@ import com.intellij.ui.paint.EffectPainter
import java.awt.Cursor
import java.awt.Graphics
import java.awt.Graphics2D
import java.awt.MouseInfo
import java.awt.Point
import java.awt.Rectangle
import java.awt.event.MouseEvent
@@ -24,8 +27,7 @@ import javax.swing.SwingUtilities
/**
* Renders the text of an inspection lens.
*/
class LensRenderer(private var info: HighlightInfo, settings: LensSettingsState) : HintRenderer(null), InputHandler {
private val useEditorFont = settings.useEditorFont
class LensRenderer(private var info: HighlightInfo, private val settings: LensSettingsState) : HintRenderer(null), InputHandler {
private lateinit var inlay: Inlay<*>
private lateinit var attributes: LensSeverityTextAttributes
private var extraRightPadding = 0
@@ -53,7 +55,7 @@ class LensRenderer(private var info: HighlightInfo, settings: LensSettingsState)
fixBaselineForTextRendering(r)
super.paint(inlay, g, r, textAttributes)
if (hovered) {
if (hovered && isHoveringText()) {
paintHoverEffect(inlay, g, r)
}
}
@@ -66,7 +68,7 @@ class LensRenderer(private var info: HighlightInfo, settings: LensSettingsState)
val font = editor.colorsScheme.getFont(EditorFontType.PLAIN)
val x = r.x + TEXT_HORIZONTAL_PADDING
val y = r.y + editor.ascent + 1
val y = r.y + editor.ascent
val w = inlay.widthInPixels - UNDERLINE_WIDTH_REDUCTION - extraRightPadding
val h = editor.descent
@@ -79,7 +81,7 @@ class LensRenderer(private var info: HighlightInfo, settings: LensSettingsState)
}
override fun useEditorFont(): Boolean {
return useEditorFont
return settings.useEditorFont
}
override fun mouseMoved(event: MouseEvent, translated: Point) {
@@ -91,6 +93,10 @@ class LensRenderer(private var info: HighlightInfo, settings: LensSettingsState)
}
private fun setHovered(hovered: Boolean) {
if (hovered && settings.lensHoverMode == LensHoverMode.DISABLED) {
return
}
if (this.hovered == hovered) {
return
}
@@ -107,12 +113,31 @@ class LensRenderer(private var info: HighlightInfo, settings: LensSettingsState)
}
override fun mousePressed(event: MouseEvent, translated: Point) {
if (!SwingUtilities.isLeftMouseButton(event) || !isHoveringText(translated)) {
val hoverMode = settings.lensHoverMode
if (hoverMode == LensHoverMode.DISABLED || !isHoveringText(translated)) {
return
}
event.consume()
IntentionsPopup.showAt(inlay.editor, info.actualStartOffset)
if (event.button.let { it == MouseEvent.BUTTON1 || it == MouseEvent.BUTTON2 }) {
event.consume()
val editor = inlay.editor
moveToOffset(editor, info.actualStartOffset)
if ((event.button == MouseEvent.BUTTON1) xor (hoverMode != LensHoverMode.DEFAULT)) {
IntentionsPopup.show(editor)
}
}
}
private fun isHoveringText(): Boolean {
val bounds = inlay.bounds ?: return false
val translatedPoint = MouseInfo.getPointerInfo().location.apply {
SwingUtilities.convertPointFromScreen(this, inlay.editor.contentComponent)
translate(-bounds.x, -bounds.y)
}
return isHoveringText(translatedPoint)
}
private fun isHoveringText(point: Point): Boolean {
@@ -167,5 +192,10 @@ class LensRenderer(private var info: HighlightInfo, settings: LensSettingsState)
private fun fixBaselineForTextRendering(rect: Rectangle) {
rect.y += 1
}
private fun moveToOffset(editor: Editor, offset: Int) {
editor.caretModel.moveToOffset(offset)
editor.scrollingModel.scrollToCaret(ScrollType.MAKE_VISIBLE)
}
}
}

View File

@@ -13,11 +13,13 @@ import com.intellij.openapi.ui.DialogPanel
import com.intellij.openapi.util.Disposer
import com.intellij.ui.DisabledTraversalPolicy
import com.intellij.ui.EditorTextFieldCellRenderer.SimpleRendererComponent
import com.intellij.ui.SimpleListCellRenderer
import com.intellij.ui.components.JBCheckBox
import com.intellij.ui.dsl.builder.Cell
import com.intellij.ui.dsl.builder.RightGap
import com.intellij.ui.dsl.builder.Row
import com.intellij.ui.dsl.builder.RowLayout
import com.intellij.ui.dsl.builder.bindItem
import com.intellij.ui.dsl.builder.bindSelected
import com.intellij.ui.dsl.builder.panel
import java.awt.Cursor
@@ -74,6 +76,20 @@ class LensApplicationConfigurable : BoundConfigurable("Inspection Lens"), Config
val settings = settingsService.state
return panel {
group("Appearance") {
row {
checkBox("Use editor font").bindSelected(settings::useEditorFont)
}
}
group("Behavior") {
row("Hover mode:") {
val items = LensHoverMode.values().toList()
val renderer = SimpleListCellRenderer.create("", LensHoverMode::description)
comboBox(items, renderer).bindItem(settings::lensHoverMode) { settings.lensHoverMode = it ?: LensHoverMode.DEFAULT }
}
}
group("Shown Severities") {
for ((id, severity, textAttributes) in allSeverities) {
row {
@@ -89,12 +105,6 @@ class LensApplicationConfigurable : BoundConfigurable("Inspection Lens"), Config
checkBox("Other").bindSelected(settings::showUnknownSeverities)
}
}
group("Appearance") {
row {
checkBox("Use editor font").bindSelected(settings::useEditorFont)
}
}
}
}

View File

@@ -0,0 +1,7 @@
package com.chylex.intellij.inspectionlens.settings
enum class LensHoverMode(val description: String) {
DISABLED("Disabled"),
DEFAULT("Left click shows intentions, middle click jumps to highlight"),
SWAPPED("Left click jumps to highlight, middle click shows intentions")
}

View File

@@ -21,6 +21,7 @@ class LensSettingsState : SimplePersistentStateComponent<LensSettingsState.State
var showUnknownSeverities by property(true)
var useEditorFont by property(true)
var lensHoverMode by enum(LensHoverMode.DEFAULT)
}
@get:Synchronized
@@ -31,6 +32,9 @@ class LensSettingsState : SimplePersistentStateComponent<LensSettingsState.State
val useEditorFont
get() = state.useEditorFont
val lensHoverMode
get() = state.lensHoverMode
override fun loadState(state: State) {
super.loadState(state)
update()

View File

@@ -6,12 +6,29 @@
<description><![CDATA[
Displays errors, warnings, and other inspections inline. Highlights the background of lines with inspections. Supports light and dark themes out of the box.
<br><br>
By default, the plugin shows <b>Errors</b>, <b>Warnings</b>, <b>Weak Warnings</b>, <b>Server Problems</b>, <b>Grammar Errors</b>, <b>Typos</b>, and other inspections with a high enough severity level. Configure visible severities in <b>Settings | Tools | Inspection Lens</a>.
By default, the plugin shows <b>Errors</b>, <b>Warnings</b>, <b>Weak Warnings</b>, <b>Server Problems</b>, <b>Grammar Errors</b>, <b>Typos</b>, and other inspections with a high enough severity level. Left-click an inspection to show quick fixes. Middle-click an inspection to navigate to the relevant code in the editor.
<br><br>
Configure appearance, behavior of clicking on inspections, and visible severities in <b>Settings | Tools | Inspection Lens</b>.
<br><br>
Inspired by <a href="https://marketplace.visualstudio.com/items?itemName=usernamehw.errorlens">Error Lens</a> for VS Code, and <a href="https://plugins.jetbrains.com/plugin/17302-inlineerror">Inline Error</a> for IntelliJ Platform.
]]></description>
<change-notes><![CDATA[
<b>Version 1.5.1</b>
<ul>
<li>Added option to change the behavior of clicking on inspections.</li>
<li>Fixed broken quick fixes in Rider and CLion Nova.</li>
<li>Fixed hover underline not rendering correctly with some combinations of high DPI and line height settings.</li>
</ul>
<b>Version 1.5</b>
<ul>
<li>Added possibility to left-click an inspection to show quick fixes.</li>
<li>Added possibility to middle-click an inspection to navigate to relevant code in the editor.</li>
<li>Added option to use UI font instead of editor font.</li>
<li>Long inspection descriptions are now truncated to 120 characters.</li>
<li>Improved descriptions of Kotlin compiler inspections.</li>
<li>Fixed visual artifacts in Rendered Doc comments.</li>
</ul>
<b>Version 1.4.1</b>
<ul>
<li>Fixed warnings in usage of IntelliJ SDK.</li>