diff --git a/CHANGELOG.md b/CHANGELOG.md index 8755719..3077eca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,8 @@ - remove a dependent log in CHANGELOG.md in build.gradle.kts - add suffix triggering or debounce triggering strategies for "goto workspace symbols/classes" in settings - make "open in find tool window" of "goto workspace symbols/classes" work +- goto definition for internal infoview +- add search for external infoview ## [0.1.9] - 2024-12-16 diff --git a/src/main/kotlin/lean4ij/actions/FindInExternalInfoview.kt b/src/main/kotlin/lean4ij/actions/FindInExternalInfoview.kt new file mode 100644 index 0000000..7912c18 --- /dev/null +++ b/src/main/kotlin/lean4ij/actions/FindInExternalInfoview.kt @@ -0,0 +1,37 @@ +package lean4ij.actions + +import com.intellij.icons.AllIcons +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import kotlinx.coroutines.launch +import lean4ij.infoview.external.JcefInfoviewService +import lean4ij.util.leanProjectScope + +class FindInExternalInfoview : AnAction() { + + init { + templatePresentation.icon = AllIcons.Actions.Find + } + + override fun actionPerformed(e: AnActionEvent) { + val project = e.project ?: return + val jcefInfoviewService = project.service() + jcefInfoviewService.searchTextField.isVisible = !jcefInfoviewService.searchTextField.isVisible + if (!jcefInfoviewService.searchTextField.isVisible) { + project.leanProjectScope.launch { + jcefInfoviewService.searchTextFlow.send("") + } + return + } + project.leanProjectScope.launch { + jcefInfoviewService.searchTextFlow.send(jcefInfoviewService.searchTextField.text) + } + + } + + override fun getActionUpdateThread(): ActionUpdateThread { + return ActionUpdateThread.BGT; + } +} \ No newline at end of file diff --git a/src/main/kotlin/lean4ij/actions/RestartInternalInfoview.kt b/src/main/kotlin/lean4ij/actions/RestartInternalInfoview.kt new file mode 100644 index 0000000..5891e6e --- /dev/null +++ b/src/main/kotlin/lean4ij/actions/RestartInternalInfoview.kt @@ -0,0 +1,32 @@ +package lean4ij.actions + +import com.intellij.icons.AllIcons +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import com.intellij.openapi.fileEditor.FileEditorManager +import lean4ij.infoview.LeanInfoviewService +import lean4ij.project.LeanProjectService + +class RestartInternalInfoview : AnAction() { + + override fun getActionUpdateThread(): ActionUpdateThread { + return ActionUpdateThread.BGT + } + + init { + templatePresentation.icon = AllIcons.Actions.Restart + } + + override fun actionPerformed(e: AnActionEvent) { + val project = e.project?:return + FileEditorManager.getInstance(project).selectedTextEditor?.let { editor -> + // TODO here in fact message up two things: + // one is recreating a new editor for removing old editor's bug + // the other is updating infoview manually + project.service().toolWindow?.restartEditor() + project.service().updateInfoviewFor(editor, true) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/lean4ij/actions/RestartJcefInfoview.kt b/src/main/kotlin/lean4ij/actions/RestartJcefInfoview.kt index 8f25e41..e1080ee 100644 --- a/src/main/kotlin/lean4ij/actions/RestartJcefInfoview.kt +++ b/src/main/kotlin/lean4ij/actions/RestartJcefInfoview.kt @@ -5,12 +5,7 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnAction import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.components.service -import com.intellij.openapi.fileEditor.FileEditorManager -import com.intellij.openapi.util.IconLoader.getIcon -import lean4ij.infoview.LeanInfoviewService import lean4ij.infoview.external.JcefInfoviewService -import lean4ij.project.LeanProjectService -import javax.swing.Icon class RestartJcefInfoview : AnAction() { @@ -28,53 +23,3 @@ class RestartJcefInfoview : AnAction() { } -class RestartInternalInfoview : AnAction() { - - override fun getActionUpdateThread(): ActionUpdateThread { - return ActionUpdateThread.BGT - } - - init { - templatePresentation.icon = AllIcons.Actions.Restart - } - - override fun actionPerformed(e: AnActionEvent) { - val project = e.project?:return - FileEditorManager.getInstance(project).selectedTextEditor?.let { editor -> - // TODO here in fact message up two things: - // one is recreating a new editor for removing old editor's bug - // the other is updating infoview manually - project.service().toolWindow?.restartEditor() - project.service().updateInfoviewFor(editor, true) - } - } -} - -/** - * TODO maybe add some buttons/actions for stop/start/toggle automatically refreshing the infoview - * which turn it into a manual mode - */ -class ToggleAutomaticallyRefreshInternalInfoview : AnAction() { - - private val onIcon: Icon = getIcon("/icons/textAutoGenerate.svg", javaClass) - private val offIcon: Icon = AllIcons.Actions.Suspend - init { - templatePresentation.icon = onIcon - templatePresentation.disabledIcon = offIcon - } - - override fun actionPerformed(e: AnActionEvent) { - val project = e.project?:return - val leanInfoviewService = project.service() - leanInfoviewService.automaticallyRefreshInternalInfoview = !leanInfoviewService.automaticallyRefreshInternalInfoview - if (!leanInfoviewService.automaticallyRefreshInternalInfoview) { - e.presentation.isEnabled = false - } else { - e.presentation.isEnabled = true - } - } - - override fun getActionUpdateThread(): ActionUpdateThread { - return ActionUpdateThread.BGT - } -} \ No newline at end of file diff --git a/src/main/kotlin/lean4ij/actions/ToggleAutomaticallyRefreshInternalInfoview.kt b/src/main/kotlin/lean4ij/actions/ToggleAutomaticallyRefreshInternalInfoview.kt new file mode 100644 index 0000000..00d59ae --- /dev/null +++ b/src/main/kotlin/lean4ij/actions/ToggleAutomaticallyRefreshInternalInfoview.kt @@ -0,0 +1,39 @@ +package lean4ij.actions + +import com.intellij.icons.AllIcons +import com.intellij.openapi.actionSystem.ActionUpdateThread +import com.intellij.openapi.actionSystem.AnAction +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.components.service +import com.intellij.openapi.util.IconLoader +import lean4ij.infoview.LeanInfoviewService +import javax.swing.Icon + +/** + * TODO maybe add some buttons/actions for stop/start/toggle automatically refreshing the infoview + * which turn it into a manual mode + */ +class ToggleAutomaticallyRefreshInternalInfoview : AnAction() { + + private val onIcon: Icon = IconLoader.getIcon("/icons/textAutoGenerate.svg", javaClass) + private val offIcon: Icon = AllIcons.Actions.Suspend + init { + templatePresentation.icon = onIcon + templatePresentation.disabledIcon = offIcon + } + + override fun actionPerformed(e: AnActionEvent) { + val project = e.project?:return + val leanInfoviewService = project.service() + leanInfoviewService.automaticallyRefreshInternalInfoview = !leanInfoviewService.automaticallyRefreshInternalInfoview + if (!leanInfoviewService.automaticallyRefreshInternalInfoview) { + e.presentation.isEnabled = false + } else { + e.presentation.isEnabled = true + } + } + + override fun getActionUpdateThread(): ActionUpdateThread { + return ActionUpdateThread.BGT + } +} \ No newline at end of file diff --git a/src/main/kotlin/lean4ij/actions/ToggleLeanInfoViewInternal.kt b/src/main/kotlin/lean4ij/actions/ToggleLeanInfoViewInternal.kt index 893d78e..15081e0 100644 --- a/src/main/kotlin/lean4ij/actions/ToggleLeanInfoViewInternal.kt +++ b/src/main/kotlin/lean4ij/actions/ToggleLeanInfoViewInternal.kt @@ -239,4 +239,5 @@ class ToggleInfoviewPreferred : AnAction() { e.presentation.isVisible = false } } -} \ No newline at end of file +} + diff --git a/src/main/kotlin/lean4ij/infoview/LeanInfoViewWindow.kt b/src/main/kotlin/lean4ij/infoview/LeanInfoViewWindow.kt index 0ce93fe..079781a 100644 --- a/src/main/kotlin/lean4ij/infoview/LeanInfoViewWindow.kt +++ b/src/main/kotlin/lean4ij/infoview/LeanInfoViewWindow.kt @@ -42,6 +42,11 @@ class LeanInfoViewWindow(val toolWindow: ToolWindow) : SimpleToolWindowPanel(tru leanProject.scope.launch(Dispatchers.EDT) { try { val editor0 = createEditor() + // There are many ways to do this + // one is ths contextMenuGroup, or handle it manually with installPopupHandler + // or using things like PopupHandler.installPopupMenu + // check: https://intellij-support.jetbrains.com/hc/en-us/community/posts/6912597187218-How-can-I-create-a-custom-right-click-menu-that-contains-a-couple-of-actions-and-attach-the-menu-to-each-element-in-a-JTree-in-my-plugin + // and https://github.com/JetBrains/intellij-community/blob/master/platform/lang-impl/src/com/intellij/packageDependencies/ui/DependenciesPanel.java editor0.contextMenuGroupId = "lean4ij.infoview.rightClickGroup" editor0.installPopupHandler { event -> val leanInfoviewService = project.service() diff --git a/src/main/kotlin/lean4ij/infoview/external/ExternalInfoViewService.kt b/src/main/kotlin/lean4ij/infoview/external/ExternalInfoViewService.kt index 692c59a..5cf141b 100644 --- a/src/main/kotlin/lean4ij/infoview/external/ExternalInfoViewService.kt +++ b/src/main/kotlin/lean4ij/infoview/external/ExternalInfoViewService.kt @@ -38,6 +38,7 @@ import java.nio.file.Paths /** * External infoview service, bridging the http service and the lean project service * TODO maybe switch to intellij's extension point to remove ktor for reducing plugin size + * TODO should this be merged with [JcefInfoviewService]? */ @Service(Service.Level.PROJECT) class ExternalInfoViewService(val project: Project) { diff --git a/src/main/kotlin/lean4ij/infoview/external/JcefInfoviewTooWindowFactory.kt b/src/main/kotlin/lean4ij/infoview/external/JcefInfoviewTooWindowFactory.kt index 246b336..74cb8c7 100644 --- a/src/main/kotlin/lean4ij/infoview/external/JcefInfoviewTooWindowFactory.kt +++ b/src/main/kotlin/lean4ij/infoview/external/JcefInfoviewTooWindowFactory.kt @@ -1,7 +1,6 @@ package lean4ij.infoview.external import com.intellij.ide.BrowserUtil -import com.intellij.openapi.actionSystem.ActionGroup import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionToolbar import com.intellij.openapi.actionSystem.DefaultActionGroup @@ -14,11 +13,16 @@ import com.intellij.openapi.ui.SimpleToolWindowPanel import com.intellij.openapi.wm.ToolWindow import com.intellij.openapi.wm.ToolWindowFactory import com.intellij.openapi.wm.ToolWindowManager +import com.intellij.ui.DocumentAdapter +import com.intellij.ui.SearchTextField import com.intellij.ui.content.ContentFactory import com.intellij.ui.dsl.builder.panel import com.intellij.ui.jcef.JBCefApp import com.intellij.ui.jcef.JBCefBrowser import com.intellij.util.ui.JBUI +import kotlinx.coroutines.channels.Channel +import kotlinx.coroutines.launch +import lean4ij.util.leanProjectScope import lean4ij.util.notify import org.cef.browser.CefBrowser import org.cef.browser.CefFrame @@ -31,13 +35,78 @@ import org.cef.misc.BoolRef import org.cef.network.CefRequest import org.cef.security.CefSSLInfo import java.awt.BorderLayout -import javax.swing.JComponent +import java.awt.event.KeyAdapter +import java.awt.event.KeyEvent +import javax.swing.event.DocumentEvent /** * TODO the name like infoview and infoView is inconsistent in the whole codebase... */ @Service(Service.Level.PROJECT) class JcefInfoviewService(private val project: Project) { + /** + * Still cannot add case-sensitive, up and down search + * - https://github.com/JetBrains/intellij-plugins/blob/master/qodana/core/src/org/jetbrains/qodana/ui/link/LinkCloudProjectView.kt + * - https://github.com/plaskowski/EmbeddedBrowserIntellijPlugin/blob/main/src/main/kotlin/com/github/plaskowski/embeddedbrowserintellijplugin/ui/TextFieldAction.kt + * + * may help + */ + val searchTextField : SearchTextField = SearchTextField() + val searchTextFlow: Channel = Channel() + + init { + searchTextField.isVisible = false + searchTextField.addDocumentListener(object: DocumentAdapter() { + override fun textChanged(e: DocumentEvent) { + project.leanProjectScope.launch { + searchTextFlow.send(searchTextField.text) + } + } + }) + searchTextField.addKeyboardListener(object : KeyAdapter() { + private fun searchDown() { + val text = searchTextField.text + if (text.isNotEmpty()) { + browser?.cefBrowser?.find(text, true, false, true) + } + } + + private fun searchUp() { + val text = searchTextField.text + if (text.isNotEmpty()) { + browser?.cefBrowser?.find(text, false, false, true) + } + return + } + + override fun keyReleased(e: KeyEvent) { + when { + e.keyCode == KeyEvent.VK_ENTER && !e.isShiftDown -> searchDown() + e.keyCode == KeyEvent.VK_DOWN -> searchDown() + e.keyCode == KeyEvent.VK_ENTER && e.isShiftDown -> searchUp() + e.keyCode == KeyEvent.VK_UP -> searchUp() + e.keyCode == KeyEvent.VK_ESCAPE -> { + searchTextField.isVisible = false + project.leanProjectScope.launch { + searchTextFlow.send("") + } + } + } + } + }) + project.leanProjectScope.launch { + // TODO should this be stopped sometime? like many other infinite loops + while (true) { + val text = searchTextFlow.receive() + if (text.isEmpty()) { + browser?.cefBrowser?.stopFinding(true) + } else { + browser?.cefBrowser?.find(text, true, false, false) + } + } + } + } + var actionToolbar: ActionToolbar? = null private var _url: String? = null val url get() = _url @@ -178,6 +247,11 @@ class JcefInfoviewTooWindowFactory : ToolWindowFactory { val jcefService = project.service() val browser = jcefService.browser if (browser != null) { + // There is a concept named speed search built in list or tree etc. + // see: https://plugins.jetbrains.com/docs/intellij/search-field.html#icons + // and maybe things like com.intellij.ui.speedSearch.SpeedSearchSupply + // and com.intellij.openapi.wm.impl.welcomeScreen.recentProjects.RecentProjectFilteringTree + browser.component.add(jcefService.searchTextField, BorderLayout.NORTH) jcefInfoview.add(browser.component) } else { jcefInfoview.add(panel { @@ -200,6 +274,7 @@ class JcefInfoviewTooWindowFactory : ToolWindowFactory { actions.add(manager.getAction("DecreaseZoomLevelForLeanInfoViewJcef")) actions.add(manager.getAction("ResetZoomLevelForLeanInfoViewJcef")) actions.add(manager.getAction("ToggleLeanInfoviewJcefToolbarVisibility")) + actions.add(manager.getAction("FindInExternalInfoview")) // TODO what is place for? val tb = manager.createActionToolbar("Lean Jcef Infoview", actions, true) diff --git a/src/main/kotlin/lean4ij/util/ProjectUtil.kt b/src/main/kotlin/lean4ij/util/ProjectUtil.kt index 5dfef99..4f5bf39 100644 --- a/src/main/kotlin/lean4ij/util/ProjectUtil.kt +++ b/src/main/kotlin/lean4ij/util/ProjectUtil.kt @@ -1,10 +1,11 @@ package lean4ij.util import com.intellij.notification.Notification -import com.intellij.notification.NotificationGroupManager -import com.intellij.notification.NotificationGroupManager.* +import com.intellij.notification.NotificationGroupManager.getInstance import com.intellij.notification.NotificationType +import com.intellij.openapi.components.service import com.intellij.openapi.project.Project +import lean4ij.project.LeanProjectService /** @@ -40,4 +41,8 @@ fun Project.notify(content: String, action: (Notification) -> Notification) { .getNotificationGroup("Custom Notification Group") .createNotification(content, NotificationType.INFORMATION) action(notification) -} \ No newline at end of file +} + +val Project.leanProjectService get(): LeanProjectService = service() + +val Project.leanProjectScope get() = leanProjectService.scope \ 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 ae195c1..4940a21 100644 --- a/src/main/resources/META-INF/plugin.xml +++ b/src/main/resources/META-INF/plugin.xml @@ -212,6 +212,10 @@ + + + +