Skip to content

Commit e1df074

Browse files
authored
Add plugin settings page (#103)
1 parent c142457 commit e1df074

5 files changed

Lines changed: 143 additions & 6 deletions

File tree

src/main/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecorator.kt

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,18 +7,23 @@ import com.intellij.ui.SimpleTextAttributes
77

88
import com.jetbrains.python.icons.PythonIcons.Python.Virtualenv
99

10+
import com.github.pyvenvmanage.settings.PyVenvManageSettings
11+
1012
class VenvProjectViewNodeDecorator : ProjectViewNodeDecorator {
1113
override fun decorate(
1214
node: ProjectViewNode<*>,
1315
data: PresentationData,
1416
) {
1517
VenvUtils.getPyVenvCfg(node.virtualFile)?.let { pyVenvCfgPath ->
16-
val pythonVersion = VenvVersionCache.getInstance().getVersion(pyVenvCfgPath.toString())
17-
pythonVersion?.let { version ->
18-
data.presentableText?.let { fileName ->
19-
data.clearText()
20-
data.addText(fileName, SimpleTextAttributes.REGULAR_ATTRIBUTES)
21-
data.addText(" [$version]", SimpleTextAttributes.GRAY_ATTRIBUTES)
18+
val settings = PyVenvManageSettings.getInstance()
19+
if (settings.showVersionInProjectView) {
20+
val pythonVersion = VenvVersionCache.getInstance().getVersion(pyVenvCfgPath.toString())
21+
pythonVersion?.let { version ->
22+
data.presentableText?.let { fileName ->
23+
data.clearText()
24+
data.addText(fileName, SimpleTextAttributes.REGULAR_ATTRIBUTES)
25+
data.addText(settings.formatVersion(version), SimpleTextAttributes.GRAY_ATTRIBUTES)
26+
}
2227
}
2328
}
2429
data.setIcon(Virtualenv)
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package com.github.pyvenvmanage.settings
2+
3+
import javax.swing.JCheckBox
4+
import javax.swing.JComponent
5+
import javax.swing.JPanel
6+
import javax.swing.JTextField
7+
8+
import com.intellij.openapi.options.Configurable
9+
import com.intellij.ui.components.JBLabel
10+
import com.intellij.util.ui.FormBuilder
11+
12+
class PyVenvManageConfigurable : Configurable {
13+
private var showVersionCheckBox: JCheckBox? = null
14+
private var versionFormatField: JTextField? = null
15+
16+
override fun getDisplayName(): String = "PyVenv Manage"
17+
18+
override fun createComponent(): JComponent {
19+
showVersionCheckBox = JCheckBox("Show Python version in project view")
20+
versionFormatField =
21+
JTextField().apply {
22+
toolTipText = "Use \$version as placeholder for the version number"
23+
}
24+
25+
return FormBuilder
26+
.createFormBuilder()
27+
.addComponent(showVersionCheckBox!!)
28+
.addLabeledComponent(JBLabel("Version format:"), versionFormatField!!)
29+
.addComponentFillVertically(JPanel(), 0)
30+
.panel
31+
}
32+
33+
override fun isModified(): Boolean {
34+
val settings = PyVenvManageSettings.getInstance()
35+
return showVersionCheckBox?.isSelected != settings.showVersionInProjectView ||
36+
versionFormatField?.text != settings.versionFormat
37+
}
38+
39+
override fun apply() {
40+
val settings = PyVenvManageSettings.getInstance()
41+
showVersionCheckBox?.isSelected?.let { settings.showVersionInProjectView = it }
42+
versionFormatField?.text?.let { settings.versionFormat = it }
43+
}
44+
45+
override fun reset() {
46+
val settings = PyVenvManageSettings.getInstance()
47+
showVersionCheckBox?.isSelected = settings.showVersionInProjectView
48+
versionFormatField?.text = settings.versionFormat
49+
}
50+
51+
override fun disposeUIResources() {
52+
showVersionCheckBox = null
53+
versionFormatField = null
54+
}
55+
}
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package com.github.pyvenvmanage.settings
2+
3+
import com.intellij.openapi.components.PersistentStateComponent
4+
import com.intellij.openapi.components.Service
5+
import com.intellij.openapi.components.State
6+
import com.intellij.openapi.components.Storage
7+
import com.intellij.openapi.components.service
8+
9+
@Service(Service.Level.APP)
10+
@State(
11+
name = "PyVenvManageSettings",
12+
storages = [Storage("PyVenvManageSettings.xml")],
13+
)
14+
class PyVenvManageSettings : PersistentStateComponent<PyVenvManageSettings.State> {
15+
private var state = State()
16+
17+
data class State(
18+
var showVersionInProjectView: Boolean = true,
19+
var versionFormat: String = " [\$version]",
20+
)
21+
22+
override fun getState(): State = state
23+
24+
override fun loadState(state: State) {
25+
this.state = state
26+
}
27+
28+
var showVersionInProjectView: Boolean
29+
get() = state.showVersionInProjectView
30+
set(value) {
31+
state.showVersionInProjectView = value
32+
}
33+
34+
var versionFormat: String
35+
get() = state.versionFormat
36+
set(value) {
37+
state.versionFormat = value
38+
}
39+
40+
fun formatVersion(version: String): String = versionFormat.replace("\$version", version)
41+
42+
companion object {
43+
fun getInstance(): PyVenvManageSettings = service()
44+
}
45+
}

src/main/resources/META-INF/plugin.xml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@
1010
<notificationGroup id="Python SDK change"
1111
displayType="BALLOON"/>
1212
<projectViewNodeDecorator implementation="com.github.pyvenvmanage.VenvProjectViewNodeDecorator"/>
13+
<applicationConfigurable
14+
parentId="tools"
15+
instance="com.github.pyvenvmanage.settings.PyVenvManageConfigurable"
16+
id="com.github.pyvenvmanage.settings.PyVenvManageConfigurable"
17+
displayName="PyVenv Manage"/>
1318
</extensions>
1419

1520
<actions>

src/test/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecoratorTest.kt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import com.intellij.ide.projectView.ProjectViewNode
1919
import com.intellij.openapi.vfs.VirtualFile
2020
import com.intellij.ui.SimpleTextAttributes
2121

22+
import com.github.pyvenvmanage.settings.PyVenvManageSettings
23+
2224
class VenvProjectViewNodeDecoratorTest {
2325
private lateinit var decorator: VenvProjectViewNodeDecorator
2426
private lateinit var node: ProjectViewNode<*>
@@ -38,19 +40,26 @@ class VenvProjectViewNodeDecoratorTest {
3840
@Nested
3941
inner class DecorateTest {
4042
private lateinit var versionCache: VenvVersionCache
43+
private lateinit var settings: PyVenvManageSettings
4144

4245
@BeforeEach
4346
fun setUpMocks() {
4447
mockkObject(VenvUtils)
4548
versionCache = mockk(relaxed = true)
4649
mockkObject(VenvVersionCache.Companion)
4750
every { VenvVersionCache.getInstance() } returns versionCache
51+
settings = mockk(relaxed = true)
52+
mockkObject(PyVenvManageSettings.Companion)
53+
every { PyVenvManageSettings.getInstance() } returns settings
54+
every { settings.showVersionInProjectView } returns true
55+
every { settings.formatVersion(any()) } answers { " [${firstArg<String>()}]" }
4856
}
4957

5058
@AfterEach
5159
fun tearDown() {
5260
unmockkObject(VenvUtils)
5361
unmockkObject(VenvVersionCache.Companion)
62+
unmockkObject(PyVenvManageSettings.Companion)
5463
}
5564

5665
@Test
@@ -143,5 +152,23 @@ class VenvProjectViewNodeDecoratorTest {
143152
// Version cache should be called twice (caching is handled by the cache service)
144153
verify(exactly = 2) { versionCache.getVersion(pyvenvCfgPath.toString()) }
145154
}
155+
156+
@Test
157+
fun `respects showVersionInProjectView setting`(
158+
@TempDir tempDir: Path,
159+
) {
160+
val pyvenvCfgPath = tempDir.resolve("pyvenv.cfg")
161+
Files.writeString(pyvenvCfgPath, "version = 3.11.0")
162+
163+
every { settings.showVersionInProjectView } returns false
164+
every { VenvUtils.getPyVenvCfg(virtualFile) } returns pyvenvCfgPath
165+
every { data.presentableText } returns "venv"
166+
167+
decorator.decorate(node, data)
168+
169+
verify(exactly = 0) { data.clearText() }
170+
verify(exactly = 0) { data.addText(any(), any<SimpleTextAttributes>()) }
171+
verify { data.setIcon(any()) } // Icon is still set
172+
}
146173
}
147174
}

0 commit comments

Comments
 (0)