mirror of
https://github.com/chylex/IntelliJ-Inspection-Lens.git
synced 2025-05-06 05:34:06 +02:00
Rewrite inlay hint priority calculation to use position in line instead of the whole document
This commit is contained in:
parent
0aff0f49ae
commit
ca4fb0484a
src
main/kotlin/com/chylex/intellij/inspectionlens
test/kotlin/com/chylex/intellij/inspectionlens
@ -1,6 +1,5 @@
|
||||
package com.chylex.intellij.inspectionlens
|
||||
|
||||
import com.chylex.intellij.inspectionlens.EditorInlayLensManager.Companion.MAXIMUM_SEVERITY
|
||||
import com.intellij.codeInsight.daemon.impl.HighlightInfo
|
||||
import com.intellij.openapi.editor.Editor
|
||||
import com.intellij.openapi.editor.Inlay
|
||||
@ -17,10 +16,10 @@ class EditorInlayLensManager private constructor(private val editor: Editor) {
|
||||
|
||||
/**
|
||||
* Highest allowed severity for the purposes of sorting multiple highlights at the same offset.
|
||||
* A [MAXIMUM_SEVERITY] of 500 allows for 8 589 933 positions in the document before sorting breaks down.
|
||||
* The value is a little higher than the highest [com.intellij.lang.annotation.HighlightSeverity], in case severities with higher values are introduced in the future.
|
||||
*/
|
||||
private const val MAXIMUM_SEVERITY = 500
|
||||
private const val MAXIMUM_POSITION = ((Int.MAX_VALUE / MAXIMUM_SEVERITY) * 2) - 1
|
||||
|
||||
fun getOrCreate(editor: Editor): EditorInlayLensManager {
|
||||
return editor.getUserData(KEY) ?: EditorInlayLensManager(editor).also { editor.putUserData(KEY, it) }
|
||||
@ -39,18 +38,14 @@ class EditorInlayLensManager private constructor(private val editor: Editor) {
|
||||
return info.actualEndOffset - 1
|
||||
}
|
||||
|
||||
internal fun getInlayHintPriority(offset: Int, severity: Int): Int {
|
||||
// Sorts highlights first by offset in the document, then by severity.
|
||||
val positionBucket = offset.coerceAtLeast(0) * MAXIMUM_SEVERITY.toLong()
|
||||
val positionFactor = (Int.MAX_VALUE - MAXIMUM_SEVERITY - positionBucket).coerceAtLeast(Int.MIN_VALUE + 1L).toInt()
|
||||
val severityFactor = severity.coerceIn(0, MAXIMUM_SEVERITY)
|
||||
// The result is between (Int.MIN_VALUE + 1)..Int.MAX_VALUE, allowing for negation without overflow.
|
||||
internal fun getInlayHintPriority(position: Int, severity: Int): Int {
|
||||
// Sorts highlights first by position on the line, then by severity.
|
||||
val positionBucket = position.coerceIn(0, MAXIMUM_POSITION) * MAXIMUM_SEVERITY
|
||||
// The multiplication can overflow, but subtracting overflowed result from Int.MAX_VALUE does not break continuity.
|
||||
val positionFactor = Integer.MAX_VALUE - positionBucket
|
||||
val severityFactor = severity.coerceIn(0, MAXIMUM_SEVERITY) - MAXIMUM_SEVERITY
|
||||
return positionFactor + severityFactor
|
||||
}
|
||||
|
||||
private fun getInlayHintPriority(info: HighlightInfo): Int {
|
||||
return getInlayHintPriority(info.actualEndOffset, info.severity.myVal)
|
||||
}
|
||||
}
|
||||
|
||||
private val inlays = mutableMapOf<RangeHighlighter, Inlay<LensRenderer>>()
|
||||
@ -87,6 +82,17 @@ class EditorInlayLensManager private constructor(private val editor: Editor) {
|
||||
inlays.clear()
|
||||
}
|
||||
|
||||
private fun getInlayHintPriority(info: HighlightInfo): Int {
|
||||
val startOffset = info.actualStartOffset
|
||||
val positionOnLine = startOffset - getLineStartOffset(startOffset)
|
||||
return getInlayHintPriority(positionOnLine, info.severity.myVal)
|
||||
}
|
||||
|
||||
private fun getLineStartOffset(offset: Int): Int {
|
||||
val position = editor.offsetToLogicalPosition(offset)
|
||||
return editor.document.getLineStartOffset(position.line)
|
||||
}
|
||||
|
||||
private fun executeInInlayBatchMode(operations: Int, block: () -> Unit) {
|
||||
editor.inlayModel.execute(operations > 1000, block)
|
||||
}
|
||||
|
@ -10,16 +10,16 @@ import org.junit.jupiter.params.provider.ValueSource
|
||||
class EditorInlayLensManagerTest {
|
||||
@Nested
|
||||
inner class Priority {
|
||||
@ParameterizedTest(name = "offsetAndSeverity = {0}")
|
||||
@ParameterizedTest(name = "positionAndSeverity = {0}")
|
||||
@ValueSource(ints = [0, -1, Int.MIN_VALUE])
|
||||
fun minimumOffset(offsetAndSeverity: Int) {
|
||||
assertEquals(Int.MAX_VALUE, EditorInlayLensManager.getInlayHintPriority(offsetAndSeverity, Int.MAX_VALUE))
|
||||
fun minimumOffset(positionAndSeverity: Int) {
|
||||
assertEquals(Int.MAX_VALUE, EditorInlayLensManager.getInlayHintPriority(positionAndSeverity, Int.MAX_VALUE))
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "offset = {0}")
|
||||
@ValueSource(ints = [8_589_934, Int.MAX_VALUE])
|
||||
fun maximumOffset(offset: Int) {
|
||||
assertEquals(Int.MIN_VALUE + 1, EditorInlayLensManager.getInlayHintPriority(offset, Int.MIN_VALUE))
|
||||
@ParameterizedTest(name = "position = {0}")
|
||||
@ValueSource(ints = [8_589_933, Int.MAX_VALUE])
|
||||
fun maximumOffset(position: Int) {
|
||||
assertEquals(Int.MIN_VALUE + 295, EditorInlayLensManager.getInlayHintPriority(position, Int.MIN_VALUE))
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "severity = {0}")
|
||||
@ -34,17 +34,23 @@ class EditorInlayLensManagerTest {
|
||||
assertEquals(Int.MAX_VALUE - 1000 + severity, EditorInlayLensManager.getInlayHintPriority(1, severity))
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "severity = {0}")
|
||||
@ValueSource(ints = [0, 1, 250, 499, 500])
|
||||
fun middlePriorityBucket(severity: Int) {
|
||||
assertEquals(-353 + severity, EditorInlayLensManager.getInlayHintPriority(4294967, severity))
|
||||
}
|
||||
|
||||
@ParameterizedTest(name = "severity = {0}")
|
||||
@ValueSource(ints = [0, 1, 250, 499, 500])
|
||||
fun penultimatePriorityBucket(severity: Int) {
|
||||
assertEquals(Int.MIN_VALUE + 295 + severity, EditorInlayLensManager.getInlayHintPriority(8_589_933, severity))
|
||||
assertEquals(Int.MIN_VALUE + 295 + 500 + severity, EditorInlayLensManager.getInlayHintPriority(8_589_932, severity))
|
||||
}
|
||||
|
||||
/**
|
||||
* If any of these change, re-evaluate [EditorInlayLensManager.MAXIMUM_SEVERITY] and the priority calculations.
|
||||
*/
|
||||
@Nested
|
||||
inner class IdeaAssumptions {
|
||||
inner class IdeaHighlightSeverityAssumptions {
|
||||
@Test
|
||||
fun smallestSeverityHasNotChanged() {
|
||||
assertEquals(10, HighlightSeverity.DEFAULT_SEVERITIES.minOf(HighlightSeverity::myVal))
|
||||
|
Loading…
Reference in New Issue
Block a user