Skip to content

Commit 5658672

Browse files
committed
feat: support raw/json modes in custom panels
1 parent 02eb379 commit 5658672

File tree

9 files changed

+141
-37
lines changed

9 files changed

+141
-37
lines changed
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
package com.github.xepozz.php_dump.notification
2+
3+
import com.github.xepozz.php_dump.PhpDumpIcons
4+
import com.intellij.notification.NotificationGroupManager
5+
import com.intellij.notification.NotificationType
6+
import com.intellij.openapi.actionSystem.AnAction
7+
import com.intellij.openapi.project.Project
8+
9+
object NotificationUtil {
10+
fun sendNotification(
11+
project: Project,
12+
title: String,
13+
message: String,
14+
actions: Collection<AnAction> = emptyList(),
15+
) {
16+
val notification = NotificationGroupManager.getInstance()
17+
.getNotificationGroup("PHP Dump Errors")
18+
.createNotification(
19+
title,
20+
message,
21+
NotificationType.ERROR,
22+
)
23+
notification.isImportant = true
24+
notification.icon = PhpDumpIcons.POT
25+
26+
notification.addActions(actions)
27+
28+
notification.notify(project)
29+
}
30+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
package com.github.xepozz.php_dump.services
2+
3+
import com.github.xepozz.php_dump.stubs.token_object.TokensList
4+
5+
data class CustomDumpResult(
6+
var tokens: TokensList = TokensList(),
7+
var raw: String = "",
8+
var error: Throwable? = null,
9+
)
Lines changed: 14 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package com.github.xepozz.php_dump.services
22

3-
import com.github.xepozz.php_dump.StringBufferProcessAdapter
43
import com.github.xepozz.php_dump.command.PathMapper
54
import com.github.xepozz.php_dump.command.PhpCommandExecutor
65
import com.github.xepozz.php_dump.stubs.token_object.TokenParser
7-
import com.github.xepozz.php_dump.stubs.token_object.TokensList
6+
import com.intellij.execution.process.CapturingProcessAdapter
87
import com.intellij.openapi.components.Service
98
import com.intellij.openapi.project.Project
109
import kotlinx.coroutines.Dispatchers
@@ -14,29 +13,34 @@ import kotlinx.coroutines.withContext
1413
class CustomTreeDumperService(var project: Project) : DumperServiceInterface {
1514
var phpSnippet: String? = null
1615

17-
override suspend fun dump(file: String): Any {
18-
val phpSnippet = phpSnippet ?: return TokensList()
16+
override suspend fun dump(file: String): CustomDumpResult {
17+
val phpSnippet = phpSnippet ?: return CustomDumpResult()
1918

2019
val localFile = PathMapper.map(project, file)
2120

2221
return withContext(Dispatchers.IO) {
23-
val output = StringBuilder()
22+
val capture = CapturingProcessAdapter()
2423

2524
PhpCommandExecutor.execute(
2625
localFile,
2726
phpSnippet,
2827
project,
29-
StringBufferProcessAdapter(output),
28+
capture,
3029
)
3130

31+
val result = CustomDumpResult()
3232

33-
val jsonString = output.toString()
33+
result.raw = capture.output.stdout
3434
// println("jsonString: $jsonString")
3535

36-
val tree = TokenParser.parseTokens(jsonString)
37-
// println("result tree: $tree")
36+
try {
37+
val tree = TokenParser.parseTokens(result.raw)
38+
result.tokens = tree
39+
} catch (e: Throwable) {
40+
result.error = e
41+
}
3842

39-
tree
43+
result
4044
}
4145
}
4246
}

src/main/kotlin/com/github/xepozz/php_dump/services/EditorProvider.kt

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,44 @@ import com.intellij.openapi.editor.EditorFactory
66
import com.intellij.openapi.editor.ex.EditorEx
77
import com.intellij.openapi.project.Project
88
import com.intellij.openapi.util.Key
9+
import com.intellij.openapi.vfs.VirtualFile
910
import com.intellij.psi.PsiDocumentManager
1011
import com.intellij.psi.PsiManager
1112
import com.intellij.testFramework.LightVirtualFile
1213

1314
@Service(Service.Level.PROJECT)
1415
class EditorProvider(var project: Project) {
1516
companion object {
16-
val editorId = Key.create<Boolean>("opcodes.editor.id")
17+
val opcodesEditorId = Key.create<Boolean>("opcodes.editor.id")
1718
}
1819

1920
val documentManager = PsiDocumentManager.getInstance(project)
2021
val editorFactory = EditorFactory.getInstance()
2122

22-
var editor: EditorEx? = null
23+
var editors = mutableMapOf<Key<*>, EditorEx>()
24+
var editorsByFile = mutableMapOf<VirtualFile, EditorEx>()
25+
var virtualFilesByEditorId = mutableMapOf<Key<*>, VirtualFile>()
2326

24-
fun getOrCreateEditor(): EditorEx = synchronized(this) {
25-
editor?.let { return it }
27+
fun getOrCreateEditor(editorId: Key<Boolean>): EditorEx =
28+
synchronized(this) {
29+
editors.getOrPut(editorId) {
30+
val virtualFile = virtualFilesByEditorId.getOrPut(editorId) {
31+
LightVirtualFile("opcodes.phpop", PHPOpFileType.INSTANCE, "")
32+
}
33+
createEditor(virtualFile)
34+
}
35+
}
2636

27-
val virtualFile = LightVirtualFile(
28-
"opcodes.phpop",
29-
PHPOpFileType.INSTANCE,
30-
""
31-
)
37+
fun getOrCreateEditorFor(virtualFile: VirtualFile): EditorEx =
38+
synchronized(this) {
39+
editorsByFile.getOrPut(virtualFile) { createEditor(virtualFile) }
40+
}
41+
42+
private fun createEditor(virtualFile: VirtualFile): EditorEx {
3243
val psiFile = PsiManager.getInstance(project).findFile(virtualFile)!!
3344
val document = documentManager.getDocument(psiFile)!!
3445

35-
return@synchronized (editorFactory.createEditor(document, project, virtualFile, false) as EditorEx)
46+
return (editorFactory.createEditor(document, project, virtualFile, false) as EditorEx)
3647
.apply {
3748
settings.apply {
3849
isBlinkCaret = true
@@ -45,9 +56,6 @@ class EditorProvider(var project: Project) {
4556
}
4657

4758
setCaretEnabled(true)
48-
putUserData(editorId, true)
49-
50-
editor = this
5159
}
5260
}
5361
}

src/main/kotlin/com/github/xepozz/php_dump/services/TokensTreeDumperService.kt

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
package com.github.xepozz.php_dump.services
22

3-
import com.github.xepozz.php_dump.StringBufferProcessAdapter
43
import com.github.xepozz.php_dump.command.PathMapper
54
import com.github.xepozz.php_dump.command.PhpCommandExecutor
65
import com.github.xepozz.php_dump.stubs.token_object.TokenParser
6+
import com.intellij.execution.process.CapturingProcessAdapter
77
import com.intellij.openapi.components.Service
88
import com.intellij.openapi.project.Project
99
import kotlinx.coroutines.Dispatchers
@@ -31,17 +31,16 @@ class TokensTreeDumperService(var project: Project) : DumperServiceInterface {
3131
val localFile = PathMapper.map(project, file)
3232

3333
return withContext(Dispatchers.IO) {
34-
val output = StringBuilder()
34+
val capture = CapturingProcessAdapter()
3535

3636
PhpCommandExecutor.execute(
3737
localFile,
3838
phpSnippet,
3939
project,
40-
StringBufferProcessAdapter(output),
40+
capture,
4141
)
4242

43-
44-
val jsonString = output.toString()
43+
val jsonString = capture.output.stdout
4544
// println("jsonString: $jsonString")
4645

4746
val tree = TokenParser.parseTokens(jsonString)

src/main/kotlin/com/github/xepozz/php_dump/startup/EditorListener.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ class EditorListener : EditorMouseListener {
3333
method: Method
3434
) {
3535
val editorProvider = project.getService(EditorProvider::class.java)
36-
val opcodesEditor = editorProvider.getOrCreateEditor()
36+
val opcodesEditor = editorProvider.getOrCreateEditor(EditorProvider.opcodesEditorId)
3737

3838
val psiFile = psiDocumentManager.getPsiFile(opcodesEditor.document) as? PHPOpFile ?: return
3939

src/main/kotlin/com/github/xepozz/php_dump/toolWindow/panel/CustomTreePanel.kt

Lines changed: 55 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,35 @@ import com.github.xepozz.php_dump.actions.EditPhpSnippetAction
55
import com.github.xepozz.php_dump.actions.ExpandTreeAction
66
import com.github.xepozz.php_dump.actions.OpenPhpSettingsAction
77
import com.github.xepozz.php_dump.actions.RefreshAction
8+
import com.github.xepozz.php_dump.notification.NotificationUtil
9+
import com.github.xepozz.php_dump.services.CustomDumpResult
810
import com.github.xepozz.php_dump.services.CustomTreeDumperService
11+
import com.github.xepozz.php_dump.services.EditorProvider
912
import com.github.xepozz.php_dump.stubs.token_object.TokensList
1013
import com.github.xepozz.php_dump.toolWindow.tabs.CompositeWindowTabsState
1114
import com.github.xepozz.php_dump.tree.RootNode
1215
import com.github.xepozz.php_dump.tree.TokenNode
1316
import com.github.xepozz.php_dump.tree.TokensTreeStructure
17+
import com.intellij.icons.AllIcons
1418
import com.intellij.ide.util.treeView.AbstractTreeStructure
1519
import com.intellij.openapi.Disposable
1620
import com.intellij.openapi.actionSystem.ActionManager
21+
import com.intellij.openapi.actionSystem.AnActionEvent
1722
import com.intellij.openapi.actionSystem.DefaultActionGroup
23+
import com.intellij.openapi.actionSystem.ToggleAction
1824
import com.intellij.openapi.application.EDT
25+
import com.intellij.openapi.application.runWriteAction
1926
import com.intellij.openapi.editor.markup.EffectType
2027
import com.intellij.openapi.editor.markup.HighlighterLayer
2128
import com.intellij.openapi.editor.markup.HighlighterTargetArea
2229
import com.intellij.openapi.editor.markup.TextAttributes
2330
import com.intellij.openapi.fileEditor.FileEditorManager
2431
import com.intellij.openapi.project.Project
2532
import com.intellij.openapi.ui.SimpleToolWindowPanel
33+
import com.intellij.openapi.vfs.findDocument
2634
import com.intellij.pom.Navigatable
2735
import com.intellij.psi.PsiDocumentManager
36+
import com.intellij.testFramework.LightVirtualFile
2837
import com.intellij.ui.JBColor
2938
import com.intellij.ui.TreeUIHelper
3039
import com.intellij.ui.components.JBScrollPane
@@ -37,6 +46,7 @@ import kotlinx.coroutines.Dispatchers
3746
import kotlinx.coroutines.launch
3847
import java.awt.BorderLayout
3948
import java.awt.GridLayout
49+
import javax.swing.JComponent
4050
import javax.swing.JPanel
4151
import javax.swing.JProgressBar
4252
import javax.swing.SwingUtilities
@@ -53,6 +63,7 @@ class CustomTreePanel(
5363
val fileEditorManager = FileEditorManager.getInstance(project)
5464
private val progressBar = JProgressBar()
5565

66+
var rawOutput = ""
5667
private val treeModel = StructureTreeModel(TokensTreeStructure(RootNode(null)), this)
5768
private val tree = Tree(DefaultTreeModel(DefaultMutableTreeNode())).apply {
5869
setModel(AsyncTreeModel(treeModel, this@CustomTreePanel))
@@ -68,7 +79,12 @@ class CustomTreePanel(
6879
}, true)
6980
}
7081
val service: CustomTreeDumperService = project.getService(CustomTreeDumperService::class.java)
82+
val editorProvider: EditorProvider = project.getService(EditorProvider::class.java)
7183

84+
val scrollPane = JBScrollPane(tree)
85+
var contentPanel: JComponent = JPanel(BorderLayout()).apply { add(scrollPane) }
86+
val rawVirtualFile = LightVirtualFile("Raw Output", "")
87+
val rawPanel = editorProvider.getOrCreateEditorFor(rawVirtualFile).component
7288

7389
init {
7490
treeModel.invalidateAsync()
@@ -81,6 +97,7 @@ class CustomTreePanel(
8197
SwingUtilities.invokeLater { refreshData() }
8298
}
8399

100+
private var showRawOutput = false
84101
fun createToolbar() {
85102
val actionGroup = DefaultActionGroup().apply {
86103
add(RefreshAction { refreshData() })
@@ -91,6 +108,20 @@ class CustomTreePanel(
91108
add(EditPhpSnippetAction(project, tabConfig) { snippet ->
92109
tabConfig.snippet = snippet
93110
})
111+
add(object :
112+
ToggleAction("Use Object Tokens", "Switches engine to dump lexical tokens", AllIcons.FileTypes.Json) {
113+
override fun isSelected(event: AnActionEvent): Boolean = showRawOutput
114+
115+
override fun setSelected(event: AnActionEvent, value: Boolean) {
116+
println("switch content")
117+
event.presentation.icon = if (value) AllIcons.FileTypes.Json else AllIcons.FileTypes.Text
118+
showRawOutput = value
119+
contentPanel.components.forEach { contentPanel.remove(it) }
120+
contentPanel.add(if (showRawOutput) rawPanel else scrollPane)
121+
SwingUtilities.invokeLater { contentPanel.repaint() }
122+
}
123+
124+
})
94125
add(OpenPhpSettingsAction())
95126
}
96127

@@ -106,7 +137,7 @@ class CustomTreePanel(
106137
private fun createContent() {
107138
val responsivePanel = JPanel(BorderLayout())
108139
responsivePanel.add(progressBar, BorderLayout.NORTH)
109-
responsivePanel.add(JBScrollPane(tree), BorderLayout.CENTER)
140+
responsivePanel.add(contentPanel, BorderLayout.CENTER)
110141

111142
setContent(responsivePanel)
112143
}
@@ -153,7 +184,8 @@ class CustomTreePanel(
153184

154185
val result = getViewData()
155186
tree.emptyText.text = "Nothing to show"
156-
rebuildTree(result)
187+
rebuildTree(result.tokens)
188+
rawOutput = result.raw
157189

158190
progressBar.setIndeterminate(false)
159191
progressBar.isVisible = false
@@ -169,16 +201,33 @@ class CustomTreePanel(
169201
TreeUtil.expandAll(tree)
170202
}
171203

172-
private suspend fun getViewData(): TokensList {
173-
val result = TokensList()
204+
private suspend fun getViewData(): CustomDumpResult {
205+
val result = CustomDumpResult()
174206
val editor = fileEditorManager.selectedTextEditor ?: return result
175207
val virtualFile = editor.virtualFile ?: return result
176208

177209
service.phpSnippet = tabConfig.snippet
178210

179-
val runBlocking = service.dump(virtualFile)
211+
val runResult = service.dump(virtualFile) as CustomDumpResult
212+
213+
val error = runResult.error
214+
val document = rawVirtualFile.findDocument()
215+
if (document != null) {
216+
runWriteAction {
217+
document.setText(runResult.raw ?: "")
218+
}
219+
}
220+
221+
if (error != null) {
222+
NotificationUtil
223+
.sendNotification(
224+
project,
225+
"Error ${error.javaClass}",
226+
error.message ?: "Unknown error",
227+
)
228+
}
180229

181-
return runBlocking as? TokensList ?: result
230+
return runResult
182231
}
183232

184233
override fun refresh(project: Project, type: RefreshType) {

src/main/kotlin/com/github/xepozz/php_dump/toolWindow/panel/OpcodesTerminalPanel.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,11 +47,10 @@ class OpcodesTerminalPanel(
4747
private val editorProvider = project.getService(EditorProvider::class.java)
4848
private val state = PhpDumpSettingsService.getInstance(project)
4949

50-
val editor = editorProvider.getOrCreateEditor()
50+
val editor = editorProvider.getOrCreateEditor(EditorProvider.opcodesEditorId)
5151
val viewComponent = editor.component
5252

5353
init {
54-
5554
createToolBar()
5655
createContent()
5756
}

src/main/resources/META-INF/plugin.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,12 @@
1717
id="PHP Dump" anchor="right" secondary="false" icon="/icons/pot.svg"/>
1818
<editorFactoryMouseListener
1919
implementation="com.github.xepozz.php_dump.startup.EditorListener"/>
20+
<notificationGroup
21+
id="PHP Dump Errors"
22+
displayType="BALLOON"
23+
hideFromSettings="true"
24+
isLogByDefault="true"
25+
/>
2026
</extensions>
2127
<projectListeners>
2228
<listener

0 commit comments

Comments
 (0)