1
0
mirror of https://github.com/chylex/IntelliJ-Inspection-Lens.git synced 2024-11-24 22:42:52 +01:00

Compare commits

..

2 Commits

Author SHA1 Message Date
e28804ad5d
Release 1.4 2024-06-15 01:55:33 +02:00
043c02e432
Add settings panel for configuring shown severities
Closes #2
2024-06-15 01:08:48 +02:00
10 changed files with 247 additions and 15 deletions

View File

@ -1,10 +1,8 @@
# Inspection Lens <img align="right" src="logo.png" alt="Plugin Logo">
IntelliJ plugin that shows errors, warnings, and other inspection highlights inline.
Displays errors, warnings, and other inspections inline. Highlights the background of lines with inspections. Supports light and dark themes out of the box.
After installing the plugin, inspection descriptions will appear after the ends of lines, and the lines will be highlighted with a background color. Shown inspection severities are **Errors**, **Warnings**, **Weak Warnings**, **Server Problems**, **Grammar Errors**, **Typos**, and other inspections from plugins or future IntelliJ versions that have a high enough severity level. Each severity has a different color, with support for both light and dark themes.
Note: The plugin is not customizable outside the ability to disable/enable the plugin without restarting the IDE. If the defaults don't work for you, I recommend trying the [Inline Error](https://plugins.jetbrains.com/plugin/17302-inlineerror) plugin which can be customized, building your own version of Inspection Lens, or proposing your change in the [issue tracker](https://github.com/chylex/IntelliJ-Inspection-Lens/issues).
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**.
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

@ -8,7 +8,7 @@ plugins {
}
group = "com.chylex.intellij.inspectionlens"
version = "1.3.3"
version = "1.4"
repositories {
mavenCentral()

View File

@ -83,6 +83,12 @@ class EditorLensManager private constructor(private val editor: Editor) {
lensManager.hide(highlighter)
}
}
object HideAll : Command {
override fun apply(lensManager: EditorLensManager) {
lensManager.hideAll()
}
}
}
/**

View File

@ -15,6 +15,10 @@ class EditorLensManagerDispatcher(private val lensManager: EditorLensManager) {
enqueue(EditorLensManager.Command.Hide(highlighter))
}
fun hideAll() {
enqueue(EditorLensManager.Command.HideAll)
}
private fun enqueue(item: EditorLensManager.Command) {
synchronized(this) {
queuedItems.add(item)

View File

@ -1,8 +1,9 @@
package com.chylex.intellij.inspectionlens.editor
import com.chylex.intellij.inspectionlens.settings.LensSettingsState
import com.intellij.codeInsight.daemon.impl.HighlightInfo
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.Disposable
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.editor.ex.MarkupModelEx
import com.intellij.openapi.editor.ex.RangeHighlighterEx
@ -48,12 +49,16 @@ internal class LensMarkupModelListener private constructor(editor: Editor) : Mar
highlighters.forEach(::showIfValid)
}
private fun hideAll() {
lensManagerDispatcher.hideAll()
}
companion object {
private val EDITOR_KEY = Key<LensMarkupModelListener>(LensMarkupModelListener::class.java.name)
private val MINIMUM_SEVERITY = HighlightSeverity.TEXT_ATTRIBUTES.myVal + 1
private val SETTINGS_SERVICE = service<LensSettingsState>()
private fun getFilteredHighlightInfo(highlighter: RangeHighlighter): HighlightInfo? {
return HighlightInfo.fromRangeHighlighter(highlighter)?.takeIf { it.severity.myVal >= MINIMUM_SEVERITY }
return HighlightInfo.fromRangeHighlighter(highlighter)?.takeIf { SETTINGS_SERVICE.severityFilter.test(it.severity) }
}
private inline fun runWithHighlighterIfValid(highlighter: RangeHighlighter, actionForImmediate: (HighlighterWithInfo) -> Unit, actionForAsync: (HighlighterWithInfo.Async) -> Unit) {
@ -101,6 +106,7 @@ internal class LensMarkupModelListener private constructor(editor: Editor) : Mar
val listener = editor.getUserData(EDITOR_KEY) ?: return
val markupModel = getMarkupModel(editor) ?: return
listener.hideAll()
listener.showAllValid(markupModel.allHighlighters)
}
}

View File

@ -0,0 +1,31 @@
package com.chylex.intellij.inspectionlens.editor
import com.intellij.codeInsight.daemon.impl.SeverityRegistrar
import com.intellij.lang.annotation.HighlightSeverity
import java.util.function.Predicate
class LensSeverityFilter(private val hiddenSeverityIds: Set<String>, private val showUnknownSeverities: Boolean) : Predicate<HighlightSeverity> {
private val knownSeverityIds = getSupportedSeverities().mapTo(HashSet(), HighlightSeverity::getName)
override fun test(severity: HighlightSeverity): Boolean {
if (!isSupported(severity)) {
return false
}
return if (severity.name in knownSeverityIds)
severity.name !in hiddenSeverityIds
else
showUnknownSeverities
}
companion object {
@Suppress("DEPRECATION")
private fun isSupported(severity: HighlightSeverity): Boolean {
return severity > HighlightSeverity.TEXT_ATTRIBUTES && severity !== HighlightSeverity.INFO
}
fun getSupportedSeverities(registrar: SeverityRegistrar = SeverityRegistrar.getSeverityRegistrar(null)): List<HighlightSeverity> {
return registrar.allSeverities.filter(::isSupported)
}
}
}

View File

@ -0,0 +1,127 @@
package com.chylex.intellij.inspectionlens.settings
import com.chylex.intellij.inspectionlens.editor.LensSeverityFilter
import com.intellij.codeInsight.daemon.impl.SeverityRegistrar
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.openapi.components.service
import com.intellij.openapi.editor.event.SelectionEvent
import com.intellij.openapi.editor.event.SelectionListener
import com.intellij.openapi.editor.markup.TextAttributes
import com.intellij.openapi.options.BoundConfigurable
import com.intellij.openapi.options.ConfigurableWithId
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.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.bindSelected
import com.intellij.ui.dsl.builder.panel
import java.awt.Cursor
class LensApplicationConfigurable : BoundConfigurable("Inspection Lens"), ConfigurableWithId {
companion object {
const val ID = "InspectionLens"
private fun getTextAttributes(registrar: SeverityRegistrar, severity: HighlightSeverity): TextAttributes? {
return registrar.getHighlightInfoTypeBySeverity(severity).attributesKey.defaultAttributes
}
}
private data class DisplayedSeverity(
val id: String,
val severity: StoredSeverity,
val textAttributes: TextAttributes? = null,
) {
constructor(
severity: HighlightSeverity,
registrar: SeverityRegistrar,
) : this(
id = severity.name,
severity = StoredSeverity(severity),
textAttributes = getTextAttributes(registrar, severity)
)
}
private val settingsService = service<LensSettingsState>()
private val allSeverities by lazy(LazyThreadSafetyMode.NONE) {
val settings = settingsService.state
val registrar = SeverityRegistrar.getSeverityRegistrar(null)
val knownSeverities = LensSeverityFilter.getSupportedSeverities(registrar).map { DisplayedSeverity(it, registrar) }
val knownSeverityIds = knownSeverities.mapTo(HashSet(), DisplayedSeverity::id)
// Update names and priorities of stored severities.
for ((id, knownSeverity, _) in knownSeverities) {
val storedSeverity = settings.hiddenSeverities[id]
if (storedSeverity != null && storedSeverity != knownSeverity) {
settings.hiddenSeverities[id] = knownSeverity
}
}
val unknownSeverities = settings.hiddenSeverities.entries
.filterNot { it.key in knownSeverityIds }
.map { DisplayedSeverity(it.key, it.value) }
(knownSeverities + unknownSeverities).sortedByDescending { it.severity.priority }
}
override fun getId(): String {
return ID
}
override fun createPanel(): DialogPanel {
val settings = settingsService.state
return panel {
group("Shown Severities") {
for ((id, severity, textAttributes) in allSeverities) {
row {
checkBox(severity.name)
.bindSelectedToNotIn(settings.hiddenSeverities, id, severity)
.gap(RightGap.COLUMNS)
labelWithAttributes("Example", textAttributes)
}.layout(RowLayout.PARENT_GRID)
}
row {
checkBox("Other").bindSelected(settings::showUnknownSeverities)
}
}
}
}
private fun <K, V> Cell<JBCheckBox>.bindSelectedToNotIn(collection: MutableMap<K, V>, key: K, value: V): Cell<JBCheckBox> {
return bindSelected({ key !in collection }, { if (it) collection.remove(key) else collection[key] = value })
}
private fun Row.labelWithAttributes(text: String, textAttributes: TextAttributes?): Cell<SimpleRendererComponent> {
val label = SimpleRendererComponent(null, null, true)
label.setText(text, textAttributes, false)
label.focusTraversalPolicy = DisabledTraversalPolicy()
val editor = label.editor
editor.setCustomCursor(this, Cursor.getDefaultCursor())
editor.contentComponent.setOpaque(false)
editor.selectionModel.addSelectionListener(object : SelectionListener {
override fun selectionChanged(e: SelectionEvent) {
if (!e.newRange.isEmpty) {
editor.selectionModel.removeSelection(true)
}
}
})
Disposer.register(disposable!!, label)
return cell(label)
}
override fun apply() {
super.apply()
settingsService.update()
}
}

View File

@ -0,0 +1,44 @@
package com.chylex.intellij.inspectionlens.settings
import com.chylex.intellij.inspectionlens.InspectionLensRefresher
import com.chylex.intellij.inspectionlens.editor.LensSeverityFilter
import com.intellij.openapi.components.BaseState
import com.intellij.openapi.components.SettingsCategory
import com.intellij.openapi.components.SimplePersistentStateComponent
import com.intellij.openapi.components.State
import com.intellij.openapi.components.Storage
import com.intellij.util.xmlb.annotations.XMap
@State(
name = LensApplicationConfigurable.ID,
storages = [ Storage("chylex.inspectionLens.xml") ],
category = SettingsCategory.UI
)
class LensSettingsState : SimplePersistentStateComponent<LensSettingsState.State>(State()) {
class State : BaseState() {
@get:XMap
val hiddenSeverities by map<String, StoredSeverity>()
var showUnknownSeverities by property(true)
}
@get:Synchronized
@set:Synchronized
var severityFilter = createSeverityFilter()
private set
override fun loadState(state: State) {
super.loadState(state)
update()
}
fun update() {
severityFilter = createSeverityFilter()
InspectionLensRefresher.scheduleRefresh()
}
private fun createSeverityFilter(): LensSeverityFilter {
val state = state
return LensSeverityFilter(state.hiddenSeverities.keys, state.showUnknownSeverities)
}
}

View File

@ -0,0 +1,9 @@
package com.chylex.intellij.inspectionlens.settings
import com.intellij.lang.annotation.HighlightSeverity
import com.intellij.util.xmlb.annotations.Tag
@Tag("severity")
data class StoredSeverity(var name: String = "", var priority: Int = 0) {
constructor(severity: HighlightSeverity) : this(severity.displayCapitalizedName, severity.myVal)
}

View File

@ -4,19 +4,18 @@
<vendor url="https://chylex.com">chylex</vendor>
<description><![CDATA[
Shows errors, warnings, and other inspection highlights inline.
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>
After installing the plugin, inspection descriptions will appear after the ends of lines, and the lines will be highlighted with a background color.
Shown inspection severities are <b>Errors</b>, <b>Warnings</b>, <b>Weak Warnings</b>, <b>Server Problems</b>, <b>Grammar Errors</b>, <b>Typos</b>, and other inspections from plugins or future IntelliJ versions that have a high enough severity level.
Each severity has a different color, with support for both light and dark themes.
<br><br>
Note: The plugin is not customizable outside the ability to disable/enable the plugin without restarting the IDE.
If the defaults don't work for you, I recommend trying the <a href="https://plugins.jetbrains.com/plugin/17302-inlineerror">Inline Error</a> plugin which can be customized, building your own version of Inspection Lens, or proposing your change in the <a href="https://github.com/chylex/IntelliJ-Inspection-Lens/issues">issue tracker</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. Configure visible severities in <b>Settings | Tools | Inspection Lens</a>.
<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.4</b>
<ul>
<li>Added configuration of visible severities to <b>Settings | Tools | Inspection Lens</b>.</li>
</ul>
<b>Version 1.3.3</b>
<ul>
<li>Partially reverted fix for inspections that include HTML in their description due to breaking inspections with angled brackets.</li>
@ -63,6 +62,14 @@
<depends>com.intellij.modules.platform</depends>
<depends optional="true" config-file="compatibility/InspectionLens-Grazie.xml">tanvd.grazi</depends>
<extensions defaultExtensionNs="com.intellij">
<applicationService serviceImplementation="com.chylex.intellij.inspectionlens.settings.LensSettingsState" />
<applicationConfigurable id="com.chylex.intellij.inspectionlens.settings.LensApplicationConfigurable"
instance="com.chylex.intellij.inspectionlens.settings.LensApplicationConfigurable"
displayName="Inspection Lens"
parentId="tools" />
</extensions>
<applicationListeners>
<listener class="com.chylex.intellij.inspectionlens.InspectionLensPluginListener" topic="com.intellij.ide.plugins.DynamicPluginListener" />
</applicationListeners>