@@ -35,14 +35,6 @@ import java.util.concurrent.ConcurrentHashMap
3535import javax.swing.Icon
3636import javax.swing.JPanel
3737
38- /* *
39- * Unified InlayHintsProvider that uses the new extensible mechanism:
40- * - LanguageTextExtractor EP to collect text blocks
41- * - FeatureGenerator EP to match features within blocks
42- * - WrapperFactory EP to create output wrappers on Run
43- *
44- * Minimal Phase 1: renders a single Run action per match.
45- */
4638@Suppress(" UnstableApiUsage" )
4739class ExecutionInlayProvider : InlayHintsProvider <NoSettings > {
4840 // key: editorId + featureId + line
@@ -83,31 +75,25 @@ class ExecutionInlayProvider : InlayHintsProvider<NoSettings> {
8375
8476 private fun computeMatches (file : PsiFile ): Map <PsiElement , List <FeatureMatch >> {
8577 val project = file.project
86- val applicable = LanguageTextExtractor .getApplicable(file)
87- if (applicable.isEmpty()) return emptyMap()
78+ val allExtractors = LanguageTextExtractor .getApplicable(file).ifEmpty { return emptyMap() }
8879
89- // Prefer language-specific extractors over the generic fallback (AdapterLanguageExtractor)
90- val specific = applicable.filter { it !is AdapterLanguageExtractor }
91- val extractors = specific.ifEmpty { applicable }
80+ val languageSpecificExtractors = allExtractors.filter { it !is AdapterLanguageExtractor }
81+ val extractors = languageSpecificExtractors.ifEmpty { allExtractors }
9282 println (" file: $file , extractors: ${extractors.map { it.javaClass }} " )
9383
94- val blocks = extractors.flatMap { it.extract(file) }
95- if (blocks.isEmpty()) return emptyMap()
84+ val blocks = extractors.flatMap { it.extract(file) }.ifEmpty { return emptyMap() }
9685
97- val features = FeatureGenerator .getApplicable(project)
98- if (features.isEmpty()) return emptyMap()
86+ val featureGenerators = FeatureGenerator .getApplicable(project).ifEmpty { return emptyMap() }
9987
10088 val matches = mutableMapOf<PsiElement , MutableList <FeatureMatch >>()
101- for (b in blocks) {
102- for (f in features) {
103- val ms = f.match(b, project)
104- if (ms.isNotEmpty()) {
105- matches.computeIfAbsent(b.element) { mutableListOf () }.addAll(ms)
106- }
89+ for (block in blocks) {
90+ for (featureGenerator in featureGenerators) {
91+ val featureMatches = featureGenerator.match(block, project).ifEmpty { continue }
92+
93+ matches.computeIfAbsent(block.element) { mutableListOf () }.addAll(featureMatches)
10794 }
10895 }
10996
110- // Sort matches by start offset for stable rendering
11197 matches.values.forEach { list ->
11298 list.sortBy { it.originalRange.startOffset }
11399 }
@@ -120,7 +106,6 @@ class ExecutionInlayProvider : InlayHintsProvider<NoSettings> {
120106 val icon: Icon ? = feature?.icon
121107 val tooltip = feature?.let { " ${it.tooltipPrefix} : ${match.value} " } ? : match.value
122108
123- // Compute session key
124109 val start = match.originalRange.startOffset
125110 val line = editor.document.getLineNumber(start)
126111 val lineEndOffset = editor.document.getLineEndOffset(line)
@@ -134,7 +119,7 @@ class ExecutionInlayProvider : InlayHintsProvider<NoSettings> {
134119 val collapseIcon = if (session.collapsed) AllIcons .General .ArrowRight else AllIcons .General .ArrowDown
135120 val collapseTooltip = if (session.collapsed) " Expand" else " Collapse"
136121 parts + = clickableIcon(collapseIcon, collapseTooltip) {
137- toggleCollapse(key )
122+ toggleCollapse(session )
138123 refreshInlays(editor)
139124 }
140125 }
@@ -152,6 +137,7 @@ class ExecutionInlayProvider : InlayHintsProvider<NoSettings> {
152137 refreshInlays(editor)
153138 }
154139 }
140+
155141 ExecutionState .IDLE -> {
156142 // Initial Run button
157143 val runText = factory.inset(factory.roundWithBackground(factory.text(" Run " )), left = 2 , right = 2 )
@@ -165,6 +151,7 @@ class ExecutionInlayProvider : InlayHintsProvider<NoSettings> {
165151 }
166152 parts + = runPres
167153 }
154+
168155 ExecutionState .FINISHED -> {
169156 // After first launch: show Rerun icon + "Run" text
170157 val rerunIcon = AllIcons .Actions .Rerun
@@ -200,7 +187,7 @@ class ExecutionInlayProvider : InlayHintsProvider<NoSettings> {
200187 return p
201188 }
202189
203- private fun <TWrapper : Wrapper > run (
190+ private fun <TWrapper : Wrapper > run (
204191 editor : Editor ,
205192 project : Project ,
206193 feature : FeatureGenerator <TWrapper >,
@@ -231,11 +218,14 @@ class ExecutionInlayProvider : InlayHintsProvider<NoSettings> {
231218 // Replace previous wrapper in the existing container
232219 val container = current.container
233220 val oldWrapper = current.wrapper
234- if (oldWrapper!= null ) {
221+ if (oldWrapper != null ) {
235222 container.remove(oldWrapper.component)
236223 }
237224 mountWrapperIntoContainer(container, wrapper)
238- try { oldWrapper?.dispose() } catch (_: Throwable ) {}
225+ try {
226+ oldWrapper?.dispose()
227+ } catch (_: Throwable ) {
228+ }
239229 current.wrapper = wrapper
240230 current.state = ExecutionState .RUNNING
241231 }
@@ -266,28 +256,27 @@ class ExecutionInlayProvider : InlayHintsProvider<NoSettings> {
266256 }
267257
268258 private fun stop (key : String ) {
269- val s = sessions[key] ? : return
270- s .processHandler?.destroyProcess()
271- s .processHandler = null
272- s .state = ExecutionState .FINISHED
259+ val session = sessions[key] ? : return
260+ session .processHandler?.destroyProcess()
261+ session .processHandler = null
262+ session .state = ExecutionState .FINISHED
273263 }
274264
275265 private fun delete (key : String ) {
276- val s = sessions.remove(key) ? : return
277- try { s .processHandler?.destroyProcess() } catch (_: Throwable ) {}
278- s .processHandler = null
266+ val session = sessions.remove(key) ? : return
267+ try { session .processHandler?.destroyProcess() } catch (_: Throwable ) { }
268+ session .processHandler = null
279269 invokeLater {
280- s .container?.parent?.remove(s .container)
270+ session .container?.parent?.remove(session .container)
281271 }
282- try { s .wrapper?.dispose() } catch (_: Throwable ) {}
283- Disposer .dispose(s .disposable)
272+ try { session .wrapper?.dispose() } catch (_: Throwable ) { }
273+ Disposer .dispose(session .disposable)
284274 }
285275
286- private fun toggleCollapse (key : String ) {
287- val s = sessions[key] ? : return
288- s.collapsed = ! s.collapsed
289- val visible = ! s.collapsed
290- invokeLater { s.container?.isVisible = visible }
276+ private fun toggleCollapse (session : Session ) {
277+ session.collapsed = ! session.collapsed
278+ val visible = ! session.collapsed
279+ invokeLater { session.container?.isVisible = visible }
291280 }
292281
293282 private fun refreshInlays (editor : Editor ) {
0 commit comments