diff --git a/src/main/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecorator.kt b/src/main/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecorator.kt index 62a4557..2fa3307 100644 --- a/src/main/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecorator.kt +++ b/src/main/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecorator.kt @@ -7,18 +7,23 @@ import com.intellij.ui.SimpleTextAttributes import com.jetbrains.python.icons.PythonIcons.Python.Virtualenv +import com.github.pyvenvmanage.settings.PyVenvManageSettings + class VenvProjectViewNodeDecorator : ProjectViewNodeDecorator { override fun decorate( node: ProjectViewNode<*>, data: PresentationData, ) { VenvUtils.getPyVenvCfg(node.virtualFile)?.let { pyVenvCfgPath -> - val pythonVersion = VenvVersionCache.getInstance().getVersion(pyVenvCfgPath.toString()) - pythonVersion?.let { version -> - data.presentableText?.let { fileName -> - data.clearText() - data.addText(fileName, SimpleTextAttributes.REGULAR_ATTRIBUTES) - data.addText(" [$version]", SimpleTextAttributes.GRAY_ATTRIBUTES) + val settings = PyVenvManageSettings.getInstance() + if (settings.showVersionInProjectView) { + val pythonVersion = VenvVersionCache.getInstance().getVersion(pyVenvCfgPath.toString()) + pythonVersion?.let { version -> + data.presentableText?.let { fileName -> + data.clearText() + data.addText(fileName, SimpleTextAttributes.REGULAR_ATTRIBUTES) + data.addText(settings.formatVersion(version), SimpleTextAttributes.GRAY_ATTRIBUTES) + } } } data.setIcon(Virtualenv) diff --git a/src/main/kotlin/com/github/pyvenvmanage/settings/PyVenvManageConfigurable.kt b/src/main/kotlin/com/github/pyvenvmanage/settings/PyVenvManageConfigurable.kt new file mode 100644 index 0000000..85c70fc --- /dev/null +++ b/src/main/kotlin/com/github/pyvenvmanage/settings/PyVenvManageConfigurable.kt @@ -0,0 +1,55 @@ +package com.github.pyvenvmanage.settings + +import javax.swing.JCheckBox +import javax.swing.JComponent +import javax.swing.JPanel +import javax.swing.JTextField + +import com.intellij.openapi.options.Configurable +import com.intellij.ui.components.JBLabel +import com.intellij.util.ui.FormBuilder + +class PyVenvManageConfigurable : Configurable { + private var showVersionCheckBox: JCheckBox? = null + private var versionFormatField: JTextField? = null + + override fun getDisplayName(): String = "PyVenv Manage" + + override fun createComponent(): JComponent { + showVersionCheckBox = JCheckBox("Show Python version in project view") + versionFormatField = + JTextField().apply { + toolTipText = "Use \$version as placeholder for the version number" + } + + return FormBuilder + .createFormBuilder() + .addComponent(showVersionCheckBox!!) + .addLabeledComponent(JBLabel("Version format:"), versionFormatField!!) + .addComponentFillVertically(JPanel(), 0) + .panel + } + + override fun isModified(): Boolean { + val settings = PyVenvManageSettings.getInstance() + return showVersionCheckBox?.isSelected != settings.showVersionInProjectView || + versionFormatField?.text != settings.versionFormat + } + + override fun apply() { + val settings = PyVenvManageSettings.getInstance() + showVersionCheckBox?.isSelected?.let { settings.showVersionInProjectView = it } + versionFormatField?.text?.let { settings.versionFormat = it } + } + + override fun reset() { + val settings = PyVenvManageSettings.getInstance() + showVersionCheckBox?.isSelected = settings.showVersionInProjectView + versionFormatField?.text = settings.versionFormat + } + + override fun disposeUIResources() { + showVersionCheckBox = null + versionFormatField = null + } +} diff --git a/src/main/kotlin/com/github/pyvenvmanage/settings/PyVenvManageSettings.kt b/src/main/kotlin/com/github/pyvenvmanage/settings/PyVenvManageSettings.kt new file mode 100644 index 0000000..15232fe --- /dev/null +++ b/src/main/kotlin/com/github/pyvenvmanage/settings/PyVenvManageSettings.kt @@ -0,0 +1,45 @@ +package com.github.pyvenvmanage.settings + +import com.intellij.openapi.components.PersistentStateComponent +import com.intellij.openapi.components.Service +import com.intellij.openapi.components.State +import com.intellij.openapi.components.Storage +import com.intellij.openapi.components.service + +@Service(Service.Level.APP) +@State( + name = "PyVenvManageSettings", + storages = [Storage("PyVenvManageSettings.xml")], +) +class PyVenvManageSettings : PersistentStateComponent { + private var state = State() + + data class State( + var showVersionInProjectView: Boolean = true, + var versionFormat: String = " [\$version]", + ) + + override fun getState(): State = state + + override fun loadState(state: State) { + this.state = state + } + + var showVersionInProjectView: Boolean + get() = state.showVersionInProjectView + set(value) { + state.showVersionInProjectView = value + } + + var versionFormat: String + get() = state.versionFormat + set(value) { + state.versionFormat = value + } + + fun formatVersion(version: String): String = versionFormat.replace("\$version", version) + + companion object { + fun getInstance(): PyVenvManageSettings = service() + } +} diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml index c4b4d1e..a65f18e 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -10,6 +10,11 @@ + diff --git a/src/test/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecoratorTest.kt b/src/test/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecoratorTest.kt index 22b194f..c59e822 100644 --- a/src/test/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecoratorTest.kt +++ b/src/test/kotlin/com/github/pyvenvmanage/VenvProjectViewNodeDecoratorTest.kt @@ -19,6 +19,8 @@ import com.intellij.ide.projectView.ProjectViewNode import com.intellij.openapi.vfs.VirtualFile import com.intellij.ui.SimpleTextAttributes +import com.github.pyvenvmanage.settings.PyVenvManageSettings + class VenvProjectViewNodeDecoratorTest { private lateinit var decorator: VenvProjectViewNodeDecorator private lateinit var node: ProjectViewNode<*> @@ -38,6 +40,7 @@ class VenvProjectViewNodeDecoratorTest { @Nested inner class DecorateTest { private lateinit var versionCache: VenvVersionCache + private lateinit var settings: PyVenvManageSettings @BeforeEach fun setUpMocks() { @@ -45,12 +48,18 @@ class VenvProjectViewNodeDecoratorTest { versionCache = mockk(relaxed = true) mockkObject(VenvVersionCache.Companion) every { VenvVersionCache.getInstance() } returns versionCache + settings = mockk(relaxed = true) + mockkObject(PyVenvManageSettings.Companion) + every { PyVenvManageSettings.getInstance() } returns settings + every { settings.showVersionInProjectView } returns true + every { settings.formatVersion(any()) } answers { " [${firstArg()}]" } } @AfterEach fun tearDown() { unmockkObject(VenvUtils) unmockkObject(VenvVersionCache.Companion) + unmockkObject(PyVenvManageSettings.Companion) } @Test @@ -143,5 +152,23 @@ class VenvProjectViewNodeDecoratorTest { // Version cache should be called twice (caching is handled by the cache service) verify(exactly = 2) { versionCache.getVersion(pyvenvCfgPath.toString()) } } + + @Test + fun `respects showVersionInProjectView setting`( + @TempDir tempDir: Path, + ) { + val pyvenvCfgPath = tempDir.resolve("pyvenv.cfg") + Files.writeString(pyvenvCfgPath, "version = 3.11.0") + + every { settings.showVersionInProjectView } returns false + every { VenvUtils.getPyVenvCfg(virtualFile) } returns pyvenvCfgPath + every { data.presentableText } returns "venv" + + decorator.decorate(node, data) + + verify(exactly = 0) { data.clearText() } + verify(exactly = 0) { data.addText(any(), any()) } + verify { data.setIcon(any()) } // Icon is still set + } } }