From 6c1fc9d276f1d4c136cd3f91752ee1562b6fa030 Mon Sep 17 00:00:00 2001 From: Oleg Kizeev Date: Sat, 16 Dec 2023 23:12:36 +0700 Subject: [PATCH] Restarting the lsp-server after changing the settings --- .idea/misc.xml | 1 - CHANGELOG.md | 5 +- .../slint/ideaplugin/ide/actions/LspAction.kt | 13 +-- .../ideaplugin/ide/actions/PreviewAction.kt | 5 +- .../ide/actions/PreviewComponentAction.kt | 5 +- .../ideaplugin/ide/lsp/LspLanguageClient.kt | 96 +++++++++++++------ .../ideaplugin/ide/lsp/SlintLspServer.kt | 40 -------- .../ide/lsp/SlintLspServerDescriptor.kt | 33 ++++++- .../ide/lsp/SlintLspServerListener.kt | 5 - .../ide/lsp/requests/LoadFileRequest.kt | 15 --- .../ide/lsp/requests/PreviewMessageRequest.kt | 4 +- .../ide/services/SlintServerService.kt | 37 +++++++ .../ide/settings/PathsTablePanel.kt | 89 +++++++++++++++++ .../ide/settings/SlintLspSettings.kt | 34 ++++++- .../ide/settings/SlintSettingsComponent.kt | 41 +++++++- .../SlintSettingsConfigurableProvider.kt | 14 +-- .../widgets/SlintStatusBarWidgetFactory.kt | 20 ++++ .../ideaplugin/ide/widgets/SlintWidget.kt | 94 ++++++++++++++++++ src/main/resources/META-INF/plugin.xml | 11 ++- .../resources/messages/SlintBundle.properties | 10 +- 20 files changed, 446 insertions(+), 126 deletions(-) delete mode 100644 src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServer.kt delete mode 100644 src/main/kotlin/dev/slint/ideaplugin/ide/lsp/requests/LoadFileRequest.kt create mode 100644 src/main/kotlin/dev/slint/ideaplugin/ide/services/SlintServerService.kt create mode 100644 src/main/kotlin/dev/slint/ideaplugin/ide/settings/PathsTablePanel.kt create mode 100644 src/main/kotlin/dev/slint/ideaplugin/ide/widgets/SlintStatusBarWidgetFactory.kt create mode 100644 src/main/kotlin/dev/slint/ideaplugin/ide/widgets/SlintWidget.kt diff --git a/.idea/misc.xml b/.idea/misc.xml index 2c3c021..b520025 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -1,4 +1,3 @@ - diff --git a/CHANGELOG.md b/CHANGELOG.md index 900eaf0..306b0d7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,10 @@ - Added folding imports - Added a handler for brackets and buckets - Added property autocomplete -- Support relative-font-size (rem) +- Support relative-font-size (rem) +- Added settings for import paths +- Added lsp-server settings +- Restarting the lsp-server after changing the settings ### Fixed - Fixed linear marker preview diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/actions/LspAction.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/actions/LspAction.kt index 720a89a..531d1d7 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/actions/LspAction.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/actions/LspAction.kt @@ -1,13 +1,10 @@ package dev.slint.ideaplugin.ide.actions -import com.intellij.json.JsonLanguage import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.actionSystem.CommonDataKeys -import com.intellij.psi.util.elementType -import dev.slint.ideaplugin.ide.lsp.SlintLspServer -import dev.slint.ideaplugin.lang.SlintLanguage -import dev.slint.ideaplugin.lang.psi.SlintFileElementType +import com.intellij.openapi.components.service +import com.intellij.platform.lsp.api.LspServer +import dev.slint.ideaplugin.ide.services.SlintServerService import javax.swing.Icon @@ -15,12 +12,12 @@ abstract class LspAction(text: String, description: String?, icon: Icon?) : AnAc override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return - val servers = SlintLspServer.getInstances(project) + val servers = project.service().getServers() if (servers.isEmpty()) { return } actionPerformed(e, servers) } - abstract fun actionPerformed(e: AnActionEvent, servers: List) + abstract fun actionPerformed(e: AnActionEvent, servers: List) } \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/actions/PreviewAction.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/actions/PreviewAction.kt index d95f8e5..e2d0f83 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/actions/PreviewAction.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/actions/PreviewAction.kt @@ -6,7 +6,6 @@ import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.openapi.actionSystem.CommonDataKeys.VIRTUAL_FILE import com.intellij.platform.lsp.api.LspServer -import dev.slint.ideaplugin.ide.lsp.SlintLspServer import dev.slint.ideaplugin.ide.lsp.requests.PreviewMessageRequest import dev.slint.ideaplugin.lang.SlintLanguage import kotlin.io.path.Path @@ -19,12 +18,12 @@ internal class PreviewAction(private val notification: Notification? = null) : e.presentation.isEnabledAndVisible = psiFile.language.isKindOf(SlintLanguage.INSTANCE) } - override fun actionPerformed(e: AnActionEvent, servers: List) { + override fun actionPerformed(e: AnActionEvent, servers: List) { val virtualFile = e.getData(VIRTUAL_FILE) ?: return val uriFile = Path(virtualFile.path).toUri() val request = PreviewMessageRequest(servers.first(), uriFile.toString(), "") - (servers.first() as LspServer).requestExecutor.sendRequestSync(request) + servers.first().requestExecutor.sendRequestSync(request) notification?.expire() } diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/actions/PreviewComponentAction.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/actions/PreviewComponentAction.kt index cd86b67..e69c0ad 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/actions/PreviewComponentAction.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/actions/PreviewComponentAction.kt @@ -5,7 +5,6 @@ import com.intellij.notification.Notification import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.actionSystem.CommonDataKeys import com.intellij.platform.lsp.api.LspServer -import dev.slint.ideaplugin.ide.lsp.SlintLspServer import dev.slint.ideaplugin.ide.lsp.requests.PreviewMessageRequest import kotlin.io.path.Path @@ -15,12 +14,12 @@ internal class PreviewComponentAction( ) : LspAction("Show Component Preview", null, AllIcons.Actions.ShowCode) { - override fun actionPerformed(e: AnActionEvent, servers: List) { + override fun actionPerformed(e: AnActionEvent, servers: List) { val virtualFile = e.getData(CommonDataKeys.VIRTUAL_FILE) ?: return val uriFile = Path(virtualFile.path).toUri() val request = PreviewMessageRequest(servers.first(), uriFile.toString(), componentName) - (servers.first() as LspServer).requestExecutor.sendRequestSync(request) + servers.first().requestExecutor.sendRequestSync(request) notification?.expire() } diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/LspLanguageClient.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/LspLanguageClient.kt index e749ee9..0bc5d9e 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/LspLanguageClient.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/LspLanguageClient.kt @@ -1,40 +1,76 @@ package dev.slint.ideaplugin.ide.lsp +import com.google.gson.JsonDeserializationContext +import com.google.gson.JsonDeserializer +import com.google.gson.JsonElement +import com.google.gson.annotations.JsonAdapter +import com.intellij.notification.NotificationGroupManager +import com.intellij.notification.NotificationType +import com.intellij.openapi.project.Project import com.intellij.platform.lsp.api.Lsp4jClient import com.intellij.platform.lsp.api.LspServerNotificationsHandler -import org.eclipse.lsp4j.MessageActionItem -import org.eclipse.lsp4j.MessageParams -import org.eclipse.lsp4j.PublishDiagnosticsParams -import org.eclipse.lsp4j.ShowMessageRequestParams +import dev.slint.ideaplugin.SlintBundle import org.eclipse.lsp4j.jsonrpc.services.JsonNotification -import org.eclipse.lsp4j.services.LanguageClient -import java.util.concurrent.CompletableFuture +import java.lang.reflect.Type -class LspLanguageClient(serverNotificationsHandler: LspServerNotificationsHandler) : - Lsp4jClient(serverNotificationsHandler) +class LspLanguageClient( + serverNotificationsHandler: LspServerNotificationsHandler, + private val project: Project +) : Lsp4jClient(serverNotificationsHandler) { @JsonNotification("experimental/serverStatus") - fun serverStatus(params: Any) { - println("status") - println(params) + fun serverStatus(status: ServerStatus) { + when (status.health) { + Health.WARNING -> { + NotificationGroupManager.getInstance() + .getNotificationGroup("Slint") + .createNotification( + SlintBundle.message("slint.language.server.status"), + status.message, + NotificationType.WARNING + ) + .notify(project) + } + Health.ERROR -> { + NotificationGroupManager.getInstance() + .getNotificationGroup("Slint") + .createNotification( + SlintBundle.message("slint.language.server.status"), + status.message, + NotificationType.ERROR + ) + .notify(project) + } + + Health.OK -> {} + } + } + + data class ServerStatus( + @JsonAdapter(EnumDeserializer::class) + val health: Health, + val message: String, + val quiescent: Boolean, + ) + + enum class Health { + OK, + WARNING, + ERROR; + } + + class EnumDeserializer>() : JsonDeserializer { + override fun deserialize(json: JsonElement?, typeOfT: Type?, + context: JsonDeserializationContext?): T? { + return json?.asString?.let { + if (it.isNotEmpty()) { + val enumClass = typeOfT as? Class + return enumClass?.enumConstants?.first { + enumValue -> enumValue.name.equals(it, true) } + } else { + return null + } + } + } } -// override fun telemetryEvent(p0: Any?) { -// TODO("Not yet implemented") -// } -// -// override fun publishDiagnostics(p0: PublishDiagnosticsParams?) { -// TODO("Not yet implemented") -// } -// -// override fun showMessage(p0: MessageParams?) { -// TODO("Not yet implemented") -// } -// -// override fun showMessageRequest(p0: ShowMessageRequestParams?): CompletableFuture { -// TODO("Not yet implemented") -// } -// -// override fun logMessage(p0: MessageParams?) { -// TODO("Not yet implemented") -// } } \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServer.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServer.kt deleted file mode 100644 index c21135e..0000000 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServer.kt +++ /dev/null @@ -1,40 +0,0 @@ -package dev.slint.ideaplugin.ide.lsp - -import com.intellij.openapi.project.Project -import com.intellij.platform.lsp.api.LspServer -import com.intellij.platform.lsp.api.LspServerDescriptor -import com.intellij.platform.lsp.api.LspServerManager -import com.intellij.platform.lsp.api.LspServerNotificationsHandler -import com.intellij.platform.lsp.api.requests.LspRequestExecutor - -@Suppress("UnstableApiUsage") -class SlintLspServer(private val server: LspServer) : LspServer { - companion object { - // These should probably be split off into SlintLspManager or something - private fun getManager(project: Project): LspServerManager { - return LspServerManager.getInstance(project) - } - - fun startServersIfNeeded(project: Project) { - val manager = getManager(project) - manager.stopAndRestartIfNeeded(SlintLspServerSupportProvider::class.java) - } - - fun getInstances(project: Project): List { - val manager = getManager(project) - val servers = manager.getServersForProvider(SlintLspServerSupportProvider::class.java) - // There's prolly an easier way to do this but oh well - return servers.filter { it.lsp4jServer is SlintLanguageServer }.map { - SlintLspServer( - it - ) - } - } - } - - override val descriptor: LspServerDescriptor = server.descriptor - override val lsp4jServer: SlintLanguageServer = server.lsp4jServer as SlintLanguageServer - override val project: Project = server.project - override val requestExecutor: LspRequestExecutor = server.requestExecutor - override val serverNotificationsHandler: LspServerNotificationsHandler = server.serverNotificationsHandler -} \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServerDescriptor.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServerDescriptor.kt index ddb70cd..5f5fc23 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServerDescriptor.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServerDescriptor.kt @@ -8,7 +8,9 @@ import com.intellij.platform.lsp.api.LspServerListener import com.intellij.platform.lsp.api.LspServerNotificationsHandler import com.intellij.platform.lsp.api.ProjectWideLspServerDescriptor import com.intellij.platform.lsp.api.customization.LspCompletionSupport +import dev.slint.ideaplugin.ide.settings.SlintBackend import dev.slint.ideaplugin.ide.settings.SlintState +import dev.slint.ideaplugin.ide.settings.SlintStyle import dev.slint.ideaplugin.lang.SlintFileType import org.eclipse.lsp4j.services.LanguageServer @@ -19,7 +21,36 @@ class SlintLspServerDescriptor(project: Project) : ProjectWideLspServerDescripto override fun createCommandLine(): GeneralCommandLine { val settingState = SlintState.getInstance().lspSettings + + val parameters = mutableListOf() + if (settingState.args.isNotEmpty()) { + val args = settingState.args.split("\\s+".toRegex()) + parameters.addAll(args) + } + + if (settingState.includePaths.isNotEmpty()) { + parameters.add("-I") + settingState.includePaths.forEach { + parameters.add("'${it}'") + } + } + + if (settingState.backend != SlintBackend.DEFAULT) { + parameters.add("--backend") + parameters.add(settingState.backend.toString()) + } + + if (settingState.style != SlintStyle.DEFAULT) { + parameters.add("--style") + parameters.add(settingState.style.toString()) + } + + if (settingState.noToolbar) { + parameters.add("--no-toolbar") + } + return GeneralCommandLine(settingState.path).apply { + addParameters(parameters) withParentEnvironmentType(GeneralCommandLine.ParentEnvironmentType.CONSOLE) withCharset(Charsets.UTF_8) } @@ -27,7 +58,7 @@ class SlintLspServerDescriptor(project: Project) : ProjectWideLspServerDescripto override fun createInitializationOptions(): Any = SlintState.getInstance().lspSettings - override fun createLsp4jClient(handler: LspServerNotificationsHandler): Lsp4jClient = LspLanguageClient(handler) + override fun createLsp4jClient(handler: LspServerNotificationsHandler): Lsp4jClient = LspLanguageClient(handler, project) override val lsp4jServerClass: Class = SlintLanguageServer::class.java override val lspServerListener: LspServerListener = SlintLspServerListener(project) diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServerListener.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServerListener.kt index 0dad329..b19177b 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServerListener.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/SlintLspServerListener.kt @@ -7,10 +7,5 @@ import com.intellij.openapi.project.Project class SlintLspServerListener(val project: Project) : LspServerListener { override fun serverInitialized(params: InitializeResult) { super.serverInitialized(params) - - val servers = SlintLspServer.getInstances(project) - if (servers.isEmpty()) { - return - } } } \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/requests/LoadFileRequest.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/requests/LoadFileRequest.kt deleted file mode 100644 index 82c20a0..0000000 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/requests/LoadFileRequest.kt +++ /dev/null @@ -1,15 +0,0 @@ -package dev.slint.ideaplugin.ide.lsp.requests - -import com.intellij.platform.lsp.api.requests.LspRequest -import dev.slint.ideaplugin.ide.lsp.SlintLspServer -import java.util.concurrent.CompletableFuture - -class LoadFileRequest(private val server: SlintLspServer, private val path: String) : LspRequest(server) { - override fun preprocessResponse(serverResponse: String): String { - return serverResponse - } - - override fun sendRequest(): CompletableFuture { - return server.lsp4jServer.loadFile(path) - } -} \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/requests/PreviewMessageRequest.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/requests/PreviewMessageRequest.kt index f4d87c3..7b714fa 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/requests/PreviewMessageRequest.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/lsp/requests/PreviewMessageRequest.kt @@ -1,11 +1,11 @@ package dev.slint.ideaplugin.ide.lsp.requests +import com.intellij.platform.lsp.api.LspServer import com.intellij.platform.lsp.api.requests.LspRequest -import dev.slint.ideaplugin.ide.lsp.SlintLspServer import org.eclipse.lsp4j.ExecuteCommandParams import java.util.concurrent.CompletableFuture -class PreviewMessageRequest(private val server: SlintLspServer, private val path: String, private val component: String) : LspRequest(server) { +class PreviewMessageRequest(private val server: LspServer, private val path: String, private val component: String) : LspRequest(server) { override fun preprocessResponse(serverResponse: Any): Any { return serverResponse } diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/services/SlintServerService.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/services/SlintServerService.kt new file mode 100644 index 0000000..58f74b2 --- /dev/null +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/services/SlintServerService.kt @@ -0,0 +1,37 @@ +package dev.slint.ideaplugin.ide.services + +import com.intellij.notification.NotificationGroupManager +import com.intellij.notification.NotificationType +import com.intellij.openapi.components.Service +import com.intellij.openapi.project.Project +import com.intellij.platform.lsp.api.LspServer +import com.intellij.platform.lsp.api.LspServerManager +import dev.slint.ideaplugin.SlintBundle +import dev.slint.ideaplugin.ide.lsp.SlintLanguageServer +import dev.slint.ideaplugin.ide.lsp.SlintLspServerSupportProvider + +@Service(Service.Level.PROJECT) +class SlintServerService(private val project: Project) { + fun restartServer() { + LspServerManager.getInstance(project) + .stopAndRestartIfNeeded(SlintLspServerSupportProvider::class.java) + } + + fun notifyRestart() { + NotificationGroupManager.getInstance() + .getNotificationGroup("Slint") + .createNotification( + SlintBundle.message("slint.language.server.restarted"), + "", + NotificationType.INFORMATION + ) + .notify(project) + } + + fun getServers(): List { + val servers = LspServerManager.getInstance(project) + .getServersForProvider(SlintLspServerSupportProvider::class.java) + + return servers.filter { it.lsp4jServer is SlintLanguageServer } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/settings/PathsTablePanel.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/settings/PathsTablePanel.kt new file mode 100644 index 0000000..3ab19ae --- /dev/null +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/settings/PathsTablePanel.kt @@ -0,0 +1,89 @@ +package dev.slint.ideaplugin.ide.settings + +import com.intellij.ide.util.DirectoryChooser +import com.intellij.openapi.fileChooser.FileChooser +import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory +import com.intellij.openapi.fileChooser.FileChooserDialog +import com.intellij.openapi.fileTypes.FileTypeManager +import com.intellij.openapi.ui.MessageDialogBuilder +import com.intellij.ui.ToolbarDecorator +import com.intellij.ui.table.TableView +import com.intellij.util.ui.ColumnInfo +import javax.swing.JComponent +import com.intellij.util.ui.ListTableModel +import dev.slint.ideaplugin.SlintBundle +import javax.swing.table.DefaultTableCellRenderer +import javax.swing.table.TableCellRenderer +import kotlin.io.path.Path + +internal class PathsTablePanel { + val component: JComponent + + private val model: ListTableModel = ListTableModel(PathColumnInfo()) + private val table: TableView = TableView(model).apply { + visibleRowCount = 5 + rowSelectionAllowed = false + tableHeader.resizingAllowed = true + tableHeader.setUI(null) + } + + init { + val toolbarTable = ToolbarDecorator.createDecorator(table) + .setAddAction { addData() } + .setRemoveAction { removeData() } + .disableUpDownActions() + .createPanel() + + component = toolbarTable + } + + fun onModified(paths: MutableList): Boolean { + return model.items != paths + } + + fun onApply(paths: MutableList) { + paths.clear() + model.items.forEach { + paths.add(it) + } + } + + fun onReset(paths: MutableList) { + repeat(model.items.size) { model.removeRow(0) } + model.addRows(paths) + } + + private fun addData() { + val fileChooserDescriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor() + FileChooser.chooseFile(fileChooserDescriptor, null, null) { + model.addRow(it.path) + } + } + + private fun removeData() { + val dialog = MessageDialogBuilder.okCancel( + SlintBundle.message("settings.paths.table.remove.dialog.title"), + SlintBundle.message("settings.paths.table.remove.dialog.message")) + + if (dialog.guessWindowAndAsk()) { + model.removeRow(table.selectedRow) + } + } +} + +internal class PathColumnInfo : ColumnInfo(null) { + + private val renderer = DefaultTableCellRenderer() + + override fun valueOf(item: String): String = item + + override fun getRenderer(item: String?): TableCellRenderer = renderer + + override fun getComparator(): java.util.Comparator = COMPARATOR + + companion object { + private val COMPARATOR = Comparator { path1, path2 -> + path1.compareTo(path2, true) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintLspSettings.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintLspSettings.kt index e1d5d61..f61a017 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintLspSettings.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintLspSettings.kt @@ -1,5 +1,35 @@ package dev.slint.ideaplugin.ide.settings +import java.util.* + data class SlintLspSettings ( - var path: String = "slint-lsp", -) { } \ No newline at end of file + var path: String = "slint-lsp", + var args: String = "", + var style: SlintStyle = SlintStyle.DEFAULT, + var backend: SlintBackend = SlintBackend.DEFAULT, + var noToolbar: Boolean = false, + var includePaths: MutableList = mutableListOf(), +) + +enum class SlintStyle { + DEFAULT, + FLUENT, + MATERIAL, + NATIVE; + + override fun toString(): String { + return name.lowercase(Locale.getDefault()) + } +} + +enum class SlintBackend { + DEFAULT, + QT, + FEMTOVG, + SKIA, + SOFTWARE; + + override fun toString(): String { + return name.lowercase(Locale.getDefault()) + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintSettingsComponent.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintSettingsComponent.kt index 4b15078..37d65ee 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintSettingsComponent.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintSettingsComponent.kt @@ -3,17 +3,48 @@ package dev.slint.ideaplugin.ide.settings import com.intellij.openapi.ui.DialogPanel import com.intellij.ui.dsl.builder.* -class SlintSettingsComponent(settings: SlintLspSettings) { +class SlintSettingsComponent(lspSettings: SlintLspSettings) { private var panel: DialogPanel? = null - private var lspSettings: SlintLspSettings = SlintState.getInstance().lspSettings - init { panel = panel { - row("Slint-lsp path") { - textFieldWithBrowseButton() + group("Lsp Settings") { + row("Lsp path:") { + textFieldWithBrowseButton() .bindText(lspSettings::path) .align(AlignX.FILL) + } + row("Args:") { + expandableTextField() + .comment("The command line arguments passed to the Slint LSP server") + .bindText(lspSettings::args) + .align(AlignX.FILL) + } + row { + val pathsTablePanel = PathsTablePanel() + cell(pathsTablePanel.component) + .comment("List of paths in which the `import` statement and `@image-url` are looked up") + .align(AlignX.FILL) + .label("Include paths:", LabelPosition.TOP) + .onIsModified { pathsTablePanel.onModified(lspSettings.includePaths) } + .onApply { pathsTablePanel.onApply(lspSettings.includePaths) } + .onReset { pathsTablePanel.onReset(lspSettings.includePaths) } + } + } + group("Preview") { + row { + checkBox("Hide the toolbar of the preview") + .comment("") + .bindSelected(lspSettings::noToolbar) + } + row("Style:") { + comboBox(SlintStyle.values().toList()) + .bindItem(lspSettings::style.toNullableProperty()) + } + row("Backend:") { + comboBox(SlintBackend.values().toList()) + .bindItem(lspSettings::backend.toNullableProperty()) + } } } } diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintSettingsConfigurableProvider.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintSettingsConfigurableProvider.kt index 001ea98..7550df2 100644 --- a/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintSettingsConfigurableProvider.kt +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/settings/SlintSettingsConfigurableProvider.kt @@ -1,12 +1,14 @@ package dev.slint.ideaplugin.ide.settings +import com.intellij.openapi.components.service import com.intellij.openapi.options.Configurable -import com.intellij.openapi.options.ConfigurableProvider import com.intellij.openapi.options.SearchableConfigurable +import com.intellij.openapi.project.Project import dev.slint.ideaplugin.SlintBundle +import dev.slint.ideaplugin.ide.services.SlintServerService import javax.swing.JComponent -class SlintSettingsConfigurable : Configurable, SearchableConfigurable { +class SlintSettingsConfigurable(internal val project: Project) : Configurable, SearchableConfigurable { private var settingsComponent: SlintSettingsComponent? = null @@ -26,6 +28,10 @@ class SlintSettingsConfigurable : Configurable, SearchableConfigurable { override fun apply() { settingsComponent?.getPanel()?.apply() + + val slintServerService = project.service() + slintServerService.restartServer() + slintServerService.notifyRestart() } override fun reset() { @@ -35,8 +41,4 @@ class SlintSettingsConfigurable : Configurable, SearchableConfigurable { override fun disposeUIResources() { settingsComponent = null } -} - -class SlintSettingsConfigurableProvider : ConfigurableProvider() { - override fun createConfigurable(): Configurable = SlintSettingsConfigurable() } \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/widgets/SlintStatusBarWidgetFactory.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/widgets/SlintStatusBarWidgetFactory.kt new file mode 100644 index 0000000..c7087ab --- /dev/null +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/widgets/SlintStatusBarWidgetFactory.kt @@ -0,0 +1,20 @@ +package dev.slint.ideaplugin.ide.widgets + +import com.intellij.openapi.project.Project +import com.intellij.openapi.wm.StatusBar +import com.intellij.openapi.wm.StatusBarWidget +import com.intellij.openapi.wm.StatusBarWidgetFactory + +class SlintStatusBarWidgetFactory : StatusBarWidgetFactory { + override fun getId(): String { + return "SlintWidget" + } + + override fun getDisplayName(): String { + return "Slint" + } + + override fun createWidget(project: Project): StatusBarWidget { + return SlintWidget(project) + } +} \ No newline at end of file diff --git a/src/main/kotlin/dev/slint/ideaplugin/ide/widgets/SlintWidget.kt b/src/main/kotlin/dev/slint/ideaplugin/ide/widgets/SlintWidget.kt new file mode 100644 index 0000000..ac633d2 --- /dev/null +++ b/src/main/kotlin/dev/slint/ideaplugin/ide/widgets/SlintWidget.kt @@ -0,0 +1,94 @@ +package dev.slint.ideaplugin.ide.widgets + +import com.intellij.openapi.diagnostic.Logger +import com.intellij.openapi.fileEditor.FileEditorManager +import com.intellij.openapi.fileEditor.FileEditorManagerListener +import com.intellij.openapi.project.Project +import com.intellij.openapi.vfs.VirtualFile +import com.intellij.openapi.wm.StatusBarWidget +import com.intellij.openapi.wm.StatusBarWidget.WidgetPresentation +import com.intellij.openapi.wm.impl.status.EditorBasedWidget +import com.intellij.platform.lsp.api.LspServerManager +import com.intellij.platform.lsp.impl.LspServerImpl +import dev.slint.ideaplugin.SlintBundle +import dev.slint.ideaplugin.SlintIcons +import dev.slint.ideaplugin.ide.lsp.SlintLspServerSupportProvider +import dev.slint.ideaplugin.lang.SlintFileType +import javax.swing.Icon + +class SlintWidget(project: Project) : EditorBasedWidget(project), StatusBarWidget, + StatusBarWidget.MultipleTextValuesPresentation { + private val logger: Logger = Logger.getInstance(javaClass) + private var isShowWidget = false + + init { + project.messageBus.connect(this).subscribe(FileEditorManagerListener.FILE_EDITOR_MANAGER, object : FileEditorManagerListener { + override fun fileOpened(source: FileEditorManager, file: VirtualFile) { + val isSlintFile = source.openFiles.any { + it.fileType == SlintFileType + } + + if (isShowWidget != isSlintFile) { + isShowWidget = isSlintFile + update() + } + } + + override fun fileClosed(source: FileEditorManager, file: VirtualFile) { + val isSlintFile = source.openFiles.any { + it.fileType == SlintFileType + } + + if (isShowWidget != isSlintFile) { + isShowWidget = isSlintFile + update() + } + } + }) + } + + override fun ID(): String { + return javaClass.name; + } + + override fun getIcon(): Icon { + return SlintIcons.SLINT + } + + override fun getPresentation(): WidgetPresentation { + return this + } + + override fun getSelectedValue(): String? { + return if (isShowWidget) "slint-lsp" else "" + } + + override fun getTooltipText(): String { + val lspServerManager = LspServerManager.getInstance(project) + val lspServer = lspServerManager.getServersForProvider(SlintLspServerSupportProvider::class.java).firstOrNull() + + return when (lspServer) { + is LspServerImpl -> { + if (lspServer.isRunning) { + SlintBundle.message("slint.language.server.is.running") + } else { + SlintBundle.message("slint.language.server.is.stopped") + } + } + + else -> { + SlintBundle.message("slint.language.server.is.stopped") + } + } + } + + private fun update() { + if (myStatusBar == null) { + logger.warn("Failed to update slint statusbar") + return + } + + myStatusBar!!.updateWidget(ID()) + } + +} \ 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 5555b5f..c8a74f8 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -44,9 +44,10 @@ implementationClass="dev.slint.ideaplugin.ide.folding.SlintImportFoldingBuilder"/> - + @@ -54,6 +55,10 @@ + + + +