@@ -3,11 +3,18 @@ package io.kotest.plugin.intellij.toolwindow
33import com.intellij.ide.util.treeView.NodeRenderer
44import com.intellij.ide.util.treeView.PresentableNodeDescriptor
55import com.intellij.openapi.project.Project
6+ import com.intellij.openapi.vfs.VirtualFile
67import com.intellij.ui.TreeUIHelper
78import javax.swing.tree.DefaultMutableTreeNode
89import javax.swing.tree.TreeModel
910import javax.swing.tree.TreeSelectionModel
1011
12+ private data class FileTreeState (
13+ val allKeys : Set <String >,
14+ val expandedKeys : Set <String >,
15+ var initiallyExpanded : Boolean ,
16+ )
17+
1118class TestFileTree (
1219 project : Project ,
1320) : com.intellij.ui.treeStructure.Tree(),
@@ -17,6 +24,8 @@ class TestFileTree(
1724 private val kotestTestExplorerService: KotestTestExplorerService =
1825 project.getService(KotestTestExplorerService ::class .java)
1926 private var initialized = false
27+ private var lastFileKey: String? = null
28+ private val stateByFileKey = mutableMapOf<String , FileTreeState >()
2029
2130 init {
2231 selectionModel.selectionMode = TreeSelectionModel .SINGLE_TREE_SELECTION
@@ -40,13 +49,64 @@ class TestFileTree(
4049 super .setModel(treeModel)
4150 return
4251 }
43- val expanded = isExpanded(0 )
52+ val newFileKey = currentFileKey()
53+
54+ // If switching away from a file, save its state first
55+ if (lastFileKey != null && lastFileKey != newFileKey) {
56+ val prevAll = collectAllPathKeys()
57+ val prevExpanded = collectExpandedPathKeys()
58+ val prevInit = stateByFileKey[lastFileKey!! ]?.initiallyExpanded ? : false
59+ stateByFileKey[lastFileKey!! ] = FileTreeState (prevAll, prevExpanded, prevInit)
60+ }
61+
62+ val sameFile = newFileKey == lastFileKey
63+ val prevStateForNew = if (newFileKey != null ) stateByFileKey[newFileKey] else null
64+ val firstOpenForFile = newFileKey != null && prevStateForNew == null
65+
66+ // Baselines (use live tree for same file; fallback to stored state when switching)
67+ val prevAllKeysForThisFile: Set <String > = when {
68+ firstOpenForFile -> emptySet()
69+ sameFile -> collectAllPathKeys()
70+ newFileKey != null -> prevStateForNew?.allKeys ? : emptySet()
71+ else -> emptySet()
72+ }
73+ val expandedKeysToRestore: Set <String > = when {
74+ firstOpenForFile -> emptySet()
75+ sameFile -> collectExpandedPathKeys()
76+ newFileKey != null -> prevStateForNew?.expandedKeys ? : emptySet()
77+ else -> emptySet()
78+ }
79+
4480 super .setModel(treeModel)
45- expandAllNodes()
46- setModuleGroupNodeExpandedState(expanded)
81+
82+ // Compute added nodes relative to the previous snapshot of this file (if any)
83+ val newAllKeys = collectAllPathKeys()
84+ if (! firstOpenForFile) {
85+ val addedKeys = newAllKeys - prevAllKeysForThisFile
86+ if (addedKeys.isNotEmpty()) expandAncestorPrefixesFor(addedKeys)
87+ }
88+
89+ if (firstOpenForFile) {
90+ // First time this file is shown in the tool window: expand everything
91+ expandAllNodes()
92+ stateByFileKey[newFileKey] = FileTreeState (newAllKeys, collectExpandedPathKeys(), initiallyExpanded = true )
93+ } else {
94+ // Restore previous expansion state for this file
95+ if (expandedKeysToRestore.isNotEmpty()) expandPathsByKeys(expandedKeysToRestore)
96+ if (newFileKey != null ) {
97+ val init = prevStateForNew?.initiallyExpanded ? : true
98+ stateByFileKey[newFileKey] = FileTreeState (newAllKeys, collectExpandedPathKeys(), init )
99+ }
100+ }
101+
102+ lastFileKey = newFileKey
47103 }
48104
49- private fun setModuleGroupNodeExpandedState (expanded : Boolean ) {
50- if (expanded) expandRow(0 ) else collapseRow(0 )
105+ fun markFileClosed (file : VirtualFile ) {
106+ stateByFileKey.remove(file.path)
107+ if (lastFileKey == file.path) lastFileKey = null
51108 }
109+
110+ private fun currentFileKey (): String? = kotestTestExplorerService.currentFile?.path
111+
52112}
0 commit comments