Skip to content

Commit

Permalink
Merge pull request #93 from onriv/feat/external_infoview_search
Browse files Browse the repository at this point in the history
working on external infoview search, adding search text field
  • Loading branch information
onriv authored Dec 22, 2024
2 parents 665b068 + 69a346b commit 0dcf6ab
Show file tree
Hide file tree
Showing 11 changed files with 207 additions and 61 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
37 changes: 37 additions & 0 deletions src/main/kotlin/lean4ij/actions/FindInExternalInfoview.kt
Original file line number Diff line number Diff line change
@@ -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>()
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;

Check warning on line 35 in src/main/kotlin/lean4ij/actions/FindInExternalInfoview.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Redundant semicolon

Redundant semicolon
}
}
32 changes: 32 additions & 0 deletions src/main/kotlin/lean4ij/actions/RestartInternalInfoview.kt
Original file line number Diff line number Diff line change
@@ -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<LeanInfoviewService>().toolWindow?.restartEditor()
project.service<LeanProjectService>().updateInfoviewFor(editor, true)
}
}
}
55 changes: 0 additions & 55 deletions src/main/kotlin/lean4ij/actions/RestartJcefInfoview.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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() {

Expand All @@ -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<LeanInfoviewService>().toolWindow?.restartEditor()
project.service<LeanProjectService>().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>()
leanInfoviewService.automaticallyRefreshInternalInfoview = !leanInfoviewService.automaticallyRefreshInternalInfoview
if (!leanInfoviewService.automaticallyRefreshInternalInfoview) {
e.presentation.isEnabled = false
} else {
e.presentation.isEnabled = true
}
}

override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.BGT
}
}
Original file line number Diff line number Diff line change
@@ -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>()
leanInfoviewService.automaticallyRefreshInternalInfoview = !leanInfoviewService.automaticallyRefreshInternalInfoview
if (!leanInfoviewService.automaticallyRefreshInternalInfoview) {

Check notice on line 29 in src/main/kotlin/lean4ij/actions/ToggleAutomaticallyRefreshInternalInfoview.kt

View workflow job for this annotation

GitHub Actions / Qodana Community for JVM

Redundant 'if' statement

Redundant 'if' statement
e.presentation.isEnabled = false
} else {
e.presentation.isEnabled = true
}
}

override fun getActionUpdateThread(): ActionUpdateThread {
return ActionUpdateThread.BGT
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -239,4 +239,5 @@ class ToggleInfoviewPreferred : AnAction() {
e.presentation.isVisible = false
}
}
}
}

5 changes: 5 additions & 0 deletions src/main/kotlin/lean4ij/infoview/LeanInfoViewWindow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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<LeanInfoviewService>()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
@@ -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
Expand All @@ -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
Expand All @@ -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<String> = 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
Expand Down Expand Up @@ -178,6 +247,11 @@ class JcefInfoviewTooWindowFactory : ToolWindowFactory {
val jcefService = project.service<JcefInfoviewService>()
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 {
Expand All @@ -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)
Expand Down
11 changes: 8 additions & 3 deletions src/main/kotlin/lean4ij/util/ProjectUtil.kt
Original file line number Diff line number Diff line change
@@ -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


/**
Expand Down Expand Up @@ -40,4 +41,8 @@ fun Project.notify(content: String, action: (Notification) -> Notification) {
.getNotificationGroup("Custom Notification Group")
.createNotification(content, NotificationType.INFORMATION)
action(notification)
}
}

val Project.leanProjectService get(): LeanProjectService = service()

val Project.leanProjectScope get() = leanProjectService.scope
4 changes: 4 additions & 0 deletions src/main/resources/META-INF/plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -212,6 +212,10 @@
<add-to-group group-id="MainMenu" anchor="last"/>
</action>

<action id="FindInExternalInfoview" class="lean4ij.actions.FindInExternalInfoview" text="Find in external infoview" description="Find in external infoview">
<add-to-group group-id="MainMenu" anchor="last"/>
</action>

<group id="lean4ij.infoview.rightClickGroup" text="Infoview Right click Actions" popup="true"/>

<action id="InternalInfoviewGotoDefinition" class="lean4ij.actions.InternalInfoviewGotoDefinition" text="Go to Definition" description="InternalInfoviewGotoDefinition">
Expand Down

0 comments on commit 0dcf6ab

Please sign in to comment.