Skip to content

Commit 8c98be1

Browse files
committed
feat: tokens dumper
1 parent daf8213 commit 8c98be1

File tree

5 files changed

+212
-5
lines changed

5 files changed

+212
-5
lines changed

build.gradle.kts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import org.jetbrains.changelog.Changelog
22
import org.jetbrains.changelog.markdownToHTML
33
import org.jetbrains.intellij.platform.gradle.TestFrameworkType
4+
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
45

56
plugins {
67
id("java") // Java support
@@ -154,3 +155,7 @@ intellijPlatformTesting {
154155
}
155156
}
156157
}
158+
val compileKotlin: KotlinCompile by tasks
159+
compileKotlin.compilerOptions {
160+
freeCompilerArgs.set(listOf("-Xmulti-dollar-interpolation"))
161+
}

src/main/kotlin/com/github/xepozz/php_dump/CompositeWindowFactory.kt

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

33
import com.github.xepozz.php_dump.panel.OpcodesTerminalPanel
4+
import com.github.xepozz.php_dump.panel.TokensTerminalPanel
45
import com.github.xepozz.php_dump.services.OpcodesDumperService
6+
import com.github.xepozz.php_dump.services.TokensDumperService
57
import com.intellij.execution.filters.TextConsoleBuilderFactory
6-
import com.intellij.execution.filters.UrlFilter
78
import com.intellij.openapi.project.DumbAware
89
import com.intellij.openapi.project.Project
910
import com.intellij.openapi.wm.ToolWindow
1011
import com.intellij.openapi.wm.ToolWindowFactory
1112
import com.intellij.ui.content.ContentFactory
12-
import com.intellij.ui.jcef.JBCefBrowser
1313
import javax.swing.Icon
1414

1515
open class CompositeWindowFactory : ToolWindowFactory, DumbAware {
@@ -23,13 +23,22 @@ open class CompositeWindowFactory : ToolWindowFactory, DumbAware {
2323
val opcodesTerminalLayout = run {
2424
val consoleView = TextConsoleBuilderFactory.getInstance().createBuilder(project).console
2525

26-
val opcodesDumperService = toolWindow.project.getService(OpcodesDumperService::class.java)
27-
opcodesDumperService.consoleView = consoleView
26+
val service = toolWindow.project.getService(OpcodesDumperService::class.java)
27+
service.consoleView = consoleView
2828

29-
val terminalLayout = OpcodesTerminalPanel(consoleView.component)
3029
OpcodesTerminalPanel(consoleView.component)
3130
}
3231

32+
val tokensTerminalLayout = run {
33+
val consoleView = TextConsoleBuilderFactory.getInstance().createBuilder(project).console
34+
35+
val service = toolWindow.project.getService(TokensDumperService::class.java)
36+
service.consoleView = consoleView
37+
38+
TokensTerminalPanel(consoleView.component)
39+
}
40+
41+
3342
contentFactory.apply {
3443
this.createContent(opcodesTerminalLayout, "Opcodes", false).apply {
3544
contentManager.addContent(
@@ -39,6 +48,14 @@ open class CompositeWindowFactory : ToolWindowFactory, DumbAware {
3948
}
4049
)
4150
}
51+
this.createContent(tokensTerminalLayout, "Tokens", false).apply {
52+
contentManager.addContent(
53+
this.apply {
54+
this.isPinnable = true
55+
this.isCloseable = false
56+
}
57+
)
58+
}
4259
}
4360
}
4461
}
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.github.xepozz.php_dump.actions
2+
3+
import com.github.xepozz.php_dump.services.TokensDumperService
4+
import com.intellij.icons.AllIcons
5+
import com.intellij.openapi.actionSystem.ActionUpdateThread
6+
import com.intellij.openapi.actionSystem.AnAction
7+
import com.intellij.openapi.actionSystem.AnActionEvent
8+
import com.intellij.openapi.editor.EditorFactory
9+
import com.intellij.openapi.fileEditor.FileEditorManager
10+
11+
class RunDumpTokensCommandAction() : AnAction("Dump Tokens in Terminal", null, AllIcons.Actions.Execute) {
12+
override fun actionPerformed(e: AnActionEvent) {
13+
val project = e.project ?: return
14+
println("project $project")
15+
val basePath = project.basePath ?: return
16+
println("basePath $basePath")
17+
val editorFactory = EditorFactory.getInstance()
18+
val editors = editorFactory.allEditors
19+
println("editors $editors")
20+
21+
val editor = FileEditorManager.getInstance(project).selectedTextEditor ?: return
22+
val file = editor.virtualFile ?: return
23+
println("file $file")
24+
25+
val service = project.getService(TokensDumperService::class.java)
26+
27+
service.dump(file.path, {
28+
println("dumping $basePath")
29+
})
30+
31+
}
32+
33+
override fun getActionUpdateThread() = ActionUpdateThread.BGT
34+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
package com.github.xepozz.php_dump.panel
2+
3+
import com.github.xepozz.php_dump.actions.RunDumpTokensCommandAction
4+
import com.intellij.openapi.actionSystem.ActionManager
5+
import com.intellij.openapi.actionSystem.DefaultActionGroup
6+
import com.intellij.openapi.ui.SimpleToolWindowPanel
7+
import java.awt.BorderLayout
8+
import java.awt.GridLayout
9+
import java.awt.event.ComponentAdapter
10+
import java.awt.event.ComponentEvent
11+
import javax.swing.JComponent
12+
import javax.swing.JPanel
13+
14+
class TokensTerminalPanel(
15+
val terminalViewComponent: JComponent,
16+
) : SimpleToolWindowPanel(false, false) {
17+
init {
18+
createToolBar()
19+
createContent()
20+
}
21+
22+
private fun createToolBar() {
23+
val actionGroup = DefaultActionGroup()
24+
actionGroup.add(RunDumpTokensCommandAction())
25+
actionGroup.addSeparator()
26+
// actionGroup.add(OpenSettingsAction())
27+
28+
val actionToolbar = ActionManager.getInstance().createActionToolbar("Opcodes Toolbar", actionGroup, false)
29+
actionToolbar.targetComponent = this
30+
31+
val toolBarPanel = JPanel(GridLayout())
32+
toolBarPanel.add(actionToolbar.component)
33+
34+
toolbar = toolBarPanel
35+
}
36+
37+
private fun createContent() {
38+
val responsivePanel = JPanel(BorderLayout())
39+
responsivePanel.add(terminalViewComponent, BorderLayout.CENTER)
40+
responsivePanel.addComponentListener(object : ComponentAdapter() {
41+
override fun componentResized(e: ComponentEvent?) {
42+
terminalViewComponent.revalidate()
43+
terminalViewComponent.repaint()
44+
}
45+
})
46+
47+
setContent(responsivePanel)
48+
}
49+
}
Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
package com.github.xepozz.php_dump.services
2+
3+
import com.intellij.execution.configurations.GeneralCommandLine
4+
import com.intellij.execution.process.KillableColoredProcessHandler
5+
import com.intellij.execution.process.ProcessAdapter
6+
import com.intellij.execution.process.ProcessEvent
7+
import com.intellij.execution.process.ProcessOutputTypes
8+
import com.intellij.execution.ui.ConsoleView
9+
import com.intellij.execution.ui.ConsoleViewContentType
10+
import com.intellij.openapi.Disposable
11+
import com.intellij.openapi.components.Service
12+
import com.intellij.openapi.project.Project
13+
import com.intellij.openapi.util.Key
14+
import com.jetbrains.php.config.PhpProjectConfigurationFacade
15+
import com.jetbrains.php.config.interpreters.PhpInterpretersManagerImpl
16+
import kotlinx.coroutines.CoroutineScope
17+
import kotlinx.coroutines.Dispatchers
18+
import kotlinx.coroutines.launch
19+
import kotlinx.coroutines.withContext
20+
21+
@Service(Service.Level.PROJECT)
22+
class TokensDumperService(var project: Project) : Disposable {
23+
var consoleView: ConsoleView? = null
24+
25+
override fun dispose() {
26+
consoleView?.dispose()
27+
}
28+
29+
fun dump(file: String, callback: () -> Unit) {
30+
val interpretersManager = PhpInterpretersManagerImpl.getInstance(project)
31+
val interpreter = PhpProjectConfigurationFacade.getInstance(project).interpreter
32+
?: interpretersManager.interpreters.firstOrNull() ?: return
33+
34+
//php -l \
35+
// -ddisplay_errors=0 \
36+
// -derror_reporting=0 \
37+
// -dopcache.enable_cli=1 \
38+
// -dopcache.save_comments=1 \
39+
// -dopcache.opt_debug_level=0x10000 \
40+
// -dopcache.optimization_level=0 \
41+
// playground/test.php \
42+
// 1>/dev/null
43+
44+
// language=injectablephp
45+
val phpSnippet = $$"""
46+
print_r(
47+
array_map(
48+
function ($token) {
49+
return [
50+
'line' => $isArray = is_array($token) ? $token[2] : null,
51+
'name' => $isArray ? token_name($token[0]) : null,
52+
'value' => $isArray ? $token[1] : $token,
53+
];
54+
},
55+
token_get_all(
56+
file_get_contents($argv[1])
57+
),
58+
)
59+
);
60+
""".trimIndent()
61+
62+
val commandArgs = buildList {
63+
interpreter.apply {
64+
println("interpreter: $this")
65+
add(this.pathToPhpExecutable!!)
66+
}
67+
add("-r")
68+
add(phpSnippet)
69+
70+
add(file)
71+
}
72+
73+
CoroutineScope(Dispatchers.IO).launch {
74+
executeCommand(commandArgs)
75+
callback()
76+
}
77+
}
78+
79+
private suspend fun executeCommand(commandArgs: List<String>) = withContext(Dispatchers.IO) {
80+
val command = GeneralCommandLine(commandArgs)
81+
command.withRedirectErrorStream(false)
82+
83+
println("running command ${command.commandLineString}")
84+
val processHandler = KillableColoredProcessHandler.Silent(command)
85+
processHandler.setShouldKillProcessSoftly(false)
86+
processHandler.setShouldDestroyProcessRecursively(true)
87+
processHandler.addProcessListener(object : ProcessAdapter() {
88+
override fun onTextAvailable(event: ProcessEvent, outputType: Key<*>) {
89+
when (outputType) {
90+
ProcessOutputTypes.STDERR -> consoleView?.print(event.text, ConsoleViewContentType.ERROR_OUTPUT)
91+
ProcessOutputTypes.STDOUT -> consoleView?.print(event.text, ConsoleViewContentType.NORMAL_OUTPUT)
92+
}
93+
}
94+
})
95+
96+
consoleView?.clear()
97+
// consoleView?.attachToProcess(processHandler)
98+
// consoleView?.requestScrollingToEnd()
99+
100+
processHandler.startNotify()
101+
}
102+
}

0 commit comments

Comments
 (0)