From f8f22cd60848a9c0596d94ad65d34c73d370083b Mon Sep 17 00:00:00 2001
From: rockofox <5049120+rockofox@users.noreply.github.com>
Date: Mon, 29 Sep 2025 13:40:06 +0000
Subject: [PATCH 1/3] Make HLS path configurable (#20)
---
.../HaskellLanguageServerFactory.kt | 15 ++++++--
.../haskelllsp/settings/HaskellLspSettings.kt | 25 +++++++++++++
.../settings/HaskellLspSettingsComponent.kt | 32 +++++++++++++++++
.../HaskellLspSettingsConfigurable.kt | 35 +++++++++++++++++++
src/main/resources/META-INF/plugin.xml | 16 +++++++++
5 files changed, 121 insertions(+), 2 deletions(-)
create mode 100644 src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettings.kt
create mode 100644 src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponent.kt
create mode 100644 src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurable.kt
diff --git a/src/main/kotlin/boo/fox/haskelllsp/HaskellLanguageServerFactory.kt b/src/main/kotlin/boo/fox/haskelllsp/HaskellLanguageServerFactory.kt
index b546c1e..f2658e5 100644
--- a/src/main/kotlin/boo/fox/haskelllsp/HaskellLanguageServerFactory.kt
+++ b/src/main/kotlin/boo/fox/haskelllsp/HaskellLanguageServerFactory.kt
@@ -26,14 +26,25 @@ class HaskellLanguageServer(project: Project) : ProcessStreamConnectionProvider(
}?.path
init {
- val hlsPath = findExecutableInPATH()
+ val settings = boo.fox.haskelllsp.settings.HaskellLspSettings.getInstance()
+ val configuredPath = settings.hlsPath.takeIf { it.isNotEmpty() }
+ val hlsPath = when {
+ configuredPath != null && File(configuredPath).canExecute() -> configuredPath
+ else -> findExecutableInPATH()
+ }
+
if (!hlsPath.isNullOrEmpty()) {
super.setCommands(listOf(hlsPath, "--lsp"))
super.setWorkingDirectory(project.basePath)
} else {
+ val message = if (configuredPath != null) {
+ "Configured Haskell Language Server path is invalid or not executable. Please check the path in Settings | Tools | Haskell LSP."
+ } else {
+ "Haskell Language Server not found. Configure the path in Settings | Tools | Haskell LSP or make sure it is installed properly and available in PATH."
+ }
NotificationGroupManager.getInstance().getNotificationGroup("Haskell LSP").createNotification(
"Haskell LSP",
- "Haskell Language Server not found. Make sure it is installed properly (and is available in PATH), and restart the IDE.",
+ message,
NotificationType.ERROR
).notify(project)
LanguageServerManager.getInstance(project).stop("haskellLanguageServer")
diff --git a/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettings.kt b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettings.kt
new file mode 100644
index 0000000..659c360
--- /dev/null
+++ b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettings.kt
@@ -0,0 +1,25 @@
+package boo.fox.haskelllsp.settings
+
+import com.intellij.openapi.application.ApplicationManager
+import com.intellij.openapi.components.PersistentStateComponent
+import com.intellij.openapi.components.State
+import com.intellij.openapi.components.Storage
+import com.intellij.util.xmlb.XmlSerializerUtil
+
+@State(
+ name = "boo.fox.haskelllsp.settings.HaskellLspSettings",
+ storages = [Storage("HaskellLspSettings.xml")]
+)
+class HaskellLspSettings : PersistentStateComponent {
+ var hlsPath: String = ""
+
+ override fun getState(): HaskellLspSettings = this
+
+ override fun loadState(state: HaskellLspSettings) {
+ XmlSerializerUtil.copyBean(state, this)
+ }
+
+ companion object {
+ fun getInstance(): HaskellLspSettings = ApplicationManager.getApplication().getService(HaskellLspSettings::class.java)
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponent.kt b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponent.kt
new file mode 100644
index 0000000..21d4f2f
--- /dev/null
+++ b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponent.kt
@@ -0,0 +1,32 @@
+package boo.fox.haskelllsp.settings
+
+import com.intellij.openapi.fileChooser.FileChooserDescriptor
+import com.intellij.openapi.ui.TextFieldWithBrowseButton
+import com.intellij.ui.components.JBLabel
+import com.intellij.util.ui.FormBuilder
+import javax.swing.JPanel
+
+class HaskellLspSettingsComponent {
+ private val hlsPathField = TextFieldWithBrowseButton()
+ val panel: JPanel
+
+ init {
+ hlsPathField.addBrowseFolderListener(
+ "Select Haskell Language Server Path",
+ "Choose the path to haskell-language-server-wrapper",
+ null,
+ FileChooserDescriptor(true, false, false, false, false, false)
+ )
+
+ panel = FormBuilder.createFormBuilder()
+ .addLabeledComponent(JBLabel("Haskell Language Server path:"), hlsPathField)
+ .addComponentFillVertically(JPanel(), 0)
+ .panel
+ }
+
+ fun getHlsPath(): String = hlsPathField.text
+
+ fun setHlsPath(path: String) {
+ hlsPathField.text = path
+ }
+}
\ No newline at end of file
diff --git a/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurable.kt b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurable.kt
new file mode 100644
index 0000000..df05581
--- /dev/null
+++ b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurable.kt
@@ -0,0 +1,35 @@
+package boo.fox.haskelllsp.settings
+
+import com.intellij.openapi.options.Configurable
+import com.intellij.openapi.project.Project
+import javax.swing.JComponent
+
+class HaskellLspSettingsConfigurable(private val project: Project) : Configurable {
+ private var settingsComponent: HaskellLspSettingsComponent? = null
+
+ override fun getDisplayName(): String = "Haskell LSP"
+
+ override fun createComponent(): JComponent {
+ settingsComponent = HaskellLspSettingsComponent()
+ return settingsComponent!!.panel
+ }
+
+ override fun isModified(): Boolean {
+ val settings = HaskellLspSettings.getInstance()
+ return settingsComponent?.getHlsPath() != settings.hlsPath
+ }
+
+ override fun apply() {
+ val settings = HaskellLspSettings.getInstance()
+ settings.hlsPath = settingsComponent?.getHlsPath() ?: ""
+ }
+
+ override fun reset() {
+ val settings = HaskellLspSettings.getInstance()
+ settingsComponent?.setHlsPath(settings.hlsPath)
+ }
+
+ override fun disposeUIResources() {
+ settingsComponent = null
+ }
+}
\ No newline at end of file
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index c336e77..cbb8db3 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -5,6 +5,22 @@
RockoFox
+ com.intellij.modules.platform
+
+
+
+
+
+
+
+
+
+
Haskell LSP is a plugin that provides Haskell language support for IntelliJ IDEA.
From c08833f8e299d4a5ba964073effd147b08476853 Mon Sep 17 00:00:00 2001
From: rockofox
Date: Mon, 6 Oct 2025 00:24:42 +0200
Subject: [PATCH 2/3] configurable-hls-path: tests
---
.../HaskellLanguageServerErrorHandlingTest.kt | 78 +++++++++++++++++++
.../HaskellLanguageServerFactoryTest.kt | 75 ++++++++++++++++++
.../haskelllsp/HaskellLspIntegrationTest.kt | 60 ++++++++++++++
.../HaskellLspSettingsComponentTest.kt | 31 ++++++++
.../HaskellLspSettingsConfigurableTest.kt | 36 +++++++++
.../settings/HaskellLspSettingsTest.kt | 42 ++++++++++
6 files changed, 322 insertions(+)
create mode 100644 src/test/kotlin/boo/fox/haskelllsp/HaskellLanguageServerErrorHandlingTest.kt
create mode 100644 src/test/kotlin/boo/fox/haskelllsp/HaskellLanguageServerFactoryTest.kt
create mode 100644 src/test/kotlin/boo/fox/haskelllsp/HaskellLspIntegrationTest.kt
create mode 100644 src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponentTest.kt
create mode 100644 src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurableTest.kt
create mode 100644 src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsTest.kt
diff --git a/src/test/kotlin/boo/fox/haskelllsp/HaskellLanguageServerErrorHandlingTest.kt b/src/test/kotlin/boo/fox/haskelllsp/HaskellLanguageServerErrorHandlingTest.kt
new file mode 100644
index 0000000..0c77b70
--- /dev/null
+++ b/src/test/kotlin/boo/fox/haskelllsp/HaskellLanguageServerErrorHandlingTest.kt
@@ -0,0 +1,78 @@
+package boo.fox.haskelllsp
+
+import boo.fox.haskelllsp.settings.HaskellLspSettings
+import com.intellij.testFramework.fixtures.BasePlatformTestCase
+import com.intellij.util.EnvironmentUtil
+
+import java.io.File
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class HaskellLanguageServerErrorHandlingTest : BasePlatformTestCase() {
+
+ private lateinit var settings: HaskellLspSettings
+
+ override fun setUp() {
+ super.setUp()
+ settings = HaskellLspSettings.getInstance()
+ settings.hlsPath = ""
+ }
+
+ fun testErrorHandlingWithNonExistentConfiguredPath() {
+ settings.hlsPath = "/completely/nonexistent/path/haskell-language-server-wrapper"
+
+ // Server creation should not crash even with invalid path
+ val server = HaskellLanguageServer(project)
+
+ // Test passes if server creation doesn't crash
+ assertTrue(true)
+ }
+
+ fun testErrorHandlingWithNonExecutableConfiguredPath() {
+ // Create a file that exists but is not executable
+ val tempFile = File.createTempFile("non-executable-hls", "")
+ tempFile.setExecutable(false)
+ tempFile.deleteOnExit()
+
+ settings.hlsPath = tempFile.absolutePath
+
+ // Server creation should not crash even with non-executable file
+ val server = HaskellLanguageServer(project)
+
+ // Test passes if server creation doesn't crash
+ assertTrue(true)
+ }
+
+ fun testFallbackToPathWhenConfiguredPathInvalid() {
+ // Set invalid configured path
+ settings.hlsPath = "/invalid/path"
+
+ // Test fallback behavior - in a clean environment this will likely not find
+ // anything in PATH either, but the important thing is that it doesn't crash
+ val server = HaskellLanguageServer(project)
+
+ // The server should handle invalid configured path gracefully
+ // without crashing
+ assertTrue(true) // Test passes if no exception is thrown
+ }
+
+ fun testEmptyPathAndNoPathFallback() {
+ settings.hlsPath = ""
+
+ val server = HaskellLanguageServer(project)
+
+ // Should have no commands when both configured path and PATH fail
+ // This should not crash the server initialization
+ assertTrue(true) // Test passes if no exception is thrown
+ }
+
+ fun testNullPathAndNoPathFallback() {
+ settings.hlsPath = ""
+
+ val server = HaskellLanguageServer(project)
+
+ // Should have no commands when both configured path and PATH fail
+ // This should not crash the server initialization
+ assertTrue(true) // Test passes if no exception is thrown
+ }
+}
\ No newline at end of file
diff --git a/src/test/kotlin/boo/fox/haskelllsp/HaskellLanguageServerFactoryTest.kt b/src/test/kotlin/boo/fox/haskelllsp/HaskellLanguageServerFactoryTest.kt
new file mode 100644
index 0000000..923248a
--- /dev/null
+++ b/src/test/kotlin/boo/fox/haskelllsp/HaskellLanguageServerFactoryTest.kt
@@ -0,0 +1,75 @@
+package boo.fox.haskelllsp
+
+import boo.fox.haskelllsp.settings.HaskellLspSettings
+import com.intellij.testFramework.fixtures.BasePlatformTestCase
+import java.io.File
+import kotlin.test.assertEquals
+import kotlin.test.assertNotNull
+import kotlin.test.assertTrue
+
+class HaskellLanguageServerFactoryTest : BasePlatformTestCase() {
+
+ private lateinit var settings: HaskellLspSettings
+
+ override fun setUp() {
+ super.setUp()
+ settings = HaskellLspSettings.getInstance()
+ settings.hlsPath = ""
+ }
+
+ fun testFactoryCreation() {
+ val factory = HaskellLanguageServerFactory()
+ val connectionProvider = factory.createConnectionProvider(project)
+ assertNotNull(connectionProvider)
+ assertTrue(connectionProvider is HaskellLanguageServer)
+
+ val languageClient = factory.createLanguageClient(project)
+ assertNotNull(languageClient)
+ assertTrue(languageClient is HaskellLanguageClient)
+ }
+
+ fun testHaskellLanguageServerWithValidConfiguredPath() {
+ // Create a temporary executable file
+ val tempFile = File.createTempFile("hls-test", "")
+ tempFile.setExecutable(true)
+ tempFile.deleteOnExit()
+
+ settings.hlsPath = tempFile.absolutePath
+
+ // Should not throw an exception when creating the server with valid path
+ val server = HaskellLanguageServer(project)
+
+ // Test passes if server creation doesn't crash
+ assertTrue(true)
+ }
+
+ fun testHaskellLanguageServerWithInvalidConfiguredPath() {
+ settings.hlsPath = "/nonexistent/path/to/hls"
+
+ // The server should not crash, but should show error notification
+ // We can't easily test notifications in unit tests, but we can verify
+ // that server creation doesn't crash
+ val server = HaskellLanguageServer(project)
+
+ // Test passes if server creation doesn't crash
+ assertTrue(true)
+ }
+
+ fun testHaskellLanguageServerWithEmptyConfiguredPath() {
+ settings.hlsPath = ""
+
+ // Test with empty PATH - should not find executable
+ // Note: This test will not find the executable in a clean test environment
+ // but verifies the fallback behavior
+ val server = HaskellLanguageServer(project)
+
+ // The server should handle the case where no executable is found
+ // gracefully without crashing
+ assertTrue(true) // Test passes if no exception is thrown
+ }
+
+ fun testHlsExecutableName() {
+ // Test that the executable name is correctly determined
+ assertEquals("haskell-language-server-wrapper", HaskellLanguageServer.HLS_EXECUTABLE_NAME)
+ }
+}
\ No newline at end of file
diff --git a/src/test/kotlin/boo/fox/haskelllsp/HaskellLspIntegrationTest.kt b/src/test/kotlin/boo/fox/haskelllsp/HaskellLspIntegrationTest.kt
new file mode 100644
index 0000000..fe7ba6d
--- /dev/null
+++ b/src/test/kotlin/boo/fox/haskelllsp/HaskellLspIntegrationTest.kt
@@ -0,0 +1,60 @@
+package boo.fox.haskelllsp
+
+import boo.fox.haskelllsp.settings.HaskellLspSettings
+import com.intellij.testFramework.fixtures.BasePlatformTestCase
+import java.io.File
+import kotlin.test.assertTrue
+
+class HaskellLspIntegrationTest : BasePlatformTestCase() {
+
+ fun testSettingsIntegrationWithLanguageServer() {
+ val settings = HaskellLspSettings.getInstance()
+
+ // Test with empty settings
+ settings.hlsPath = ""
+ val server1 = HaskellLanguageServer(project)
+ assertTrue(true) // Should not crash
+
+ // Test with valid settings
+ val tempFile = File.createTempFile("hls-integration", "")
+ tempFile.setExecutable(true)
+ tempFile.deleteOnExit()
+
+ settings.hlsPath = tempFile.absolutePath
+ val server2 = HaskellLanguageServer(project)
+ assertTrue(true) // Should not crash
+
+ // Test with invalid settings
+ settings.hlsPath = "/invalid/path"
+ val server3 = HaskellLanguageServer(project)
+ assertTrue(true) // Should not crash
+ }
+
+ fun testFactoryWithDifferentSettings() {
+ val settings = HaskellLspSettings.getInstance()
+ val originalPath = settings.hlsPath
+
+ try {
+ // Test factory creation with different path settings
+ settings.hlsPath = ""
+ val factory1 = HaskellLanguageServerFactory()
+ val connection1 = factory1.createConnectionProvider(project)
+ assertTrue(connection1 is HaskellLanguageServer)
+
+ val tempFile = File.createTempFile("hls-factory", "")
+ tempFile.setExecutable(true)
+ tempFile.deleteOnExit()
+
+ settings.hlsPath = tempFile.absolutePath
+ val factory2 = HaskellLanguageServerFactory()
+ val connection2 = factory2.createConnectionProvider(project)
+ assertTrue(connection2 is HaskellLanguageServer)
+
+ val client = factory2.createLanguageClient(project)
+ assertTrue(client is HaskellLanguageClient)
+ } finally {
+ // Restore original settings
+ settings.hlsPath = originalPath
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponentTest.kt b/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponentTest.kt
new file mode 100644
index 0000000..b2ae4a3
--- /dev/null
+++ b/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponentTest.kt
@@ -0,0 +1,31 @@
+package boo.fox.haskelllsp.settings
+
+import com.intellij.testFramework.fixtures.BasePlatformTestCase
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+
+class HaskellLspSettingsComponentTest : BasePlatformTestCase() {
+
+ fun testComponentCreation() {
+ val component = HaskellLspSettingsComponent()
+ assertTrue(component.panel != null)
+ assertEquals("", component.getHlsPath())
+ }
+
+ fun testHlsPathSetting() {
+ val component = HaskellLspSettingsComponent()
+
+ // Test setting path
+ component.setHlsPath("/usr/bin/haskell-language-server")
+ assertEquals("/usr/bin/haskell-language-server", component.getHlsPath())
+
+ // Test setting empty path
+ component.setHlsPath("")
+ assertEquals("", component.getHlsPath())
+
+ // Test setting complex path
+ val complexPath = "/opt/custom/bin/haskell-language-server-wrapper"
+ component.setHlsPath(complexPath)
+ assertEquals(complexPath, component.getHlsPath())
+ }
+}
\ No newline at end of file
diff --git a/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurableTest.kt b/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurableTest.kt
new file mode 100644
index 0000000..426e943
--- /dev/null
+++ b/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurableTest.kt
@@ -0,0 +1,36 @@
+package boo.fox.haskelllsp.settings
+
+import com.intellij.testFramework.fixtures.BasePlatformTestCase
+import kotlin.test.assertEquals
+import kotlin.test.assertFalse
+import kotlin.test.assertTrue
+
+class HaskellLspSettingsConfigurableTest : BasePlatformTestCase() {
+
+ fun testConfigurableCreation() {
+ val configurable = HaskellLspSettingsConfigurable(project)
+ assertEquals("Haskell LSP", configurable.displayName)
+ }
+
+ fun testConfigurableComponentCreation() {
+ val configurable = HaskellLspSettingsConfigurable(project)
+
+ // Create component to test initial state
+ val component = configurable.createComponent()
+ assertTrue(component != null)
+ }
+
+ fun testConfigurableApplyAndReset() {
+ val configurable = HaskellLspSettingsConfigurable(project)
+
+ // Create component to ensure UI is initialized
+ configurable.createComponent()
+
+ // Test basic functionality - these operations should not crash
+ configurable.reset()
+ configurable.apply()
+
+ // Test passes if no exception is thrown
+ assertTrue(true)
+ }
+}
\ No newline at end of file
diff --git a/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsTest.kt b/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsTest.kt
new file mode 100644
index 0000000..06e51fe
--- /dev/null
+++ b/src/test/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsTest.kt
@@ -0,0 +1,42 @@
+package boo.fox.haskelllsp.settings
+
+import com.intellij.testFramework.fixtures.BasePlatformTestCase
+import kotlin.test.assertEquals
+import kotlin.test.assertTrue
+import kotlin.test.assertNotNull
+
+class HaskellLspSettingsTest : BasePlatformTestCase() {
+
+ fun testSettingsDefaults() {
+ val settings = HaskellLspSettings()
+ assertEquals("", settings.hlsPath)
+ }
+
+ fun testSettingsPersistence() {
+ val originalSettings = HaskellLspSettings()
+ originalSettings.hlsPath = "/usr/bin/haskell-language-server-wrapper"
+ assertEquals("/usr/bin/haskell-language-server-wrapper", originalSettings.hlsPath)
+
+ // Test loading state (simulate what happens when settings are loaded)
+ val newSettings = HaskellLspSettings()
+ newSettings.loadState(originalSettings)
+ assertEquals(originalSettings.hlsPath, newSettings.hlsPath)
+ }
+
+ fun testSettingsStateCopy() {
+ val originalSettings = HaskellLspSettings()
+ originalSettings.hlsPath = "/custom/path/hls"
+
+ val copiedSettings = HaskellLspSettings()
+ copiedSettings.loadState(originalSettings)
+
+ assertEquals(originalSettings.hlsPath, copiedSettings.hlsPath)
+ assertTrue(originalSettings !== copiedSettings)
+ }
+
+ fun testGetInstance() {
+ val instance = HaskellLspSettings.getInstance()
+ assertNotNull(instance)
+ assertTrue(instance is HaskellLspSettings)
+ }
+}
\ No newline at end of file
From f392c512b09dc15b9aaac2b539fdad9c4344951a Mon Sep 17 00:00:00 2001
From: rockofox
Date: Mon, 6 Oct 2025 01:01:17 +0200
Subject: [PATCH 3/3] configurable-hls-path: indicate default better
---
.../settings/HaskellLspSettingsComponent.kt | 27 +++++++++++++++++--
.../HaskellLspSettingsConfigurable.kt | 14 ++++++++++
src/main/resources/META-INF/plugin.xml | 2 +-
.../HaskellLspSettingsComponentTest.kt | 7 +++--
4 files changed, 45 insertions(+), 5 deletions(-)
diff --git a/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponent.kt b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponent.kt
index 21d4f2f..d4ffba4 100644
--- a/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponent.kt
+++ b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsComponent.kt
@@ -17,6 +17,24 @@ class HaskellLspSettingsComponent {
null,
FileChooserDescriptor(true, false, false, false, false, false)
)
+
+ // Set default placeholder text
+ hlsPathField.text = DEFAULT_DISPLAY_TEXT
+
+ // Add focus listener to clear default text when user starts editing
+ hlsPathField.textField.addFocusListener(object : java.awt.event.FocusAdapter() {
+ override fun focusGained(e: java.awt.event.FocusEvent?) {
+ if (hlsPathField.text == DEFAULT_DISPLAY_TEXT) {
+ hlsPathField.text = ""
+ }
+ }
+
+ override fun focusLost(e: java.awt.event.FocusEvent?) {
+ if (hlsPathField.text.isEmpty()) {
+ hlsPathField.text = DEFAULT_DISPLAY_TEXT
+ }
+ }
+ })
panel = FormBuilder.createFormBuilder()
.addLabeledComponent(JBLabel("Haskell Language Server path:"), hlsPathField)
@@ -24,9 +42,14 @@ class HaskellLspSettingsComponent {
.panel
}
- fun getHlsPath(): String = hlsPathField.text
+ fun getHlsPath(): String =
+ if (hlsPathField.text == DEFAULT_DISPLAY_TEXT) "" else hlsPathField.text
fun setHlsPath(path: String) {
- hlsPathField.text = path
+ hlsPathField.text = if (path.isEmpty()) DEFAULT_DISPLAY_TEXT else path
+ }
+
+ companion object {
+ private const val DEFAULT_DISPLAY_TEXT = "Default (search in PATH)"
}
}
\ No newline at end of file
diff --git a/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurable.kt b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurable.kt
index df05581..9ee6214 100644
--- a/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurable.kt
+++ b/src/main/kotlin/boo/fox/haskelllsp/settings/HaskellLspSettingsConfigurable.kt
@@ -2,6 +2,7 @@ package boo.fox.haskelllsp.settings
import com.intellij.openapi.options.Configurable
import com.intellij.openapi.project.Project
+import com.redhat.devtools.lsp4ij.LanguageServerManager
import javax.swing.JComponent
class HaskellLspSettingsConfigurable(private val project: Project) : Configurable {
@@ -21,7 +22,20 @@ class HaskellLspSettingsConfigurable(private val project: Project) : Configurabl
override fun apply() {
val settings = HaskellLspSettings.getInstance()
+ val oldPath = settings.hlsPath
settings.hlsPath = settingsComponent?.getHlsPath() ?: ""
+
+ // Restart language server if path changed
+ if (oldPath != settings.hlsPath) {
+ restartLanguageServer()
+ }
+ }
+
+ private fun restartLanguageServer() {
+ val manager = LanguageServerManager.getInstance(project)
+ // Stop the server first, then restart it
+ manager.stop("haskellLanguageServer")
+ manager.start("haskellLanguageServer")
}
override fun reset() {
diff --git a/src/main/resources/META-INF/plugin.xml b/src/main/resources/META-INF/plugin.xml
index cbb8db3..3ffca9f 100644
--- a/src/main/resources/META-INF/plugin.xml
+++ b/src/main/resources/META-INF/plugin.xml
@@ -14,7 +14,7 @@
-