Skip to content

Commit 9304788

Browse files
FantoomForNeVeR
authored andcommitted
Add debugger runner and breakpoints
1 parent 279f32e commit 9304788

8 files changed

+244
-4
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
package com.intellij.plugin.powershell.ide.debugger
2+
3+
import com.intellij.openapi.project.Project
4+
import com.intellij.openapi.ui.MessageType
5+
import com.intellij.openapi.vfs.VfsUtil
6+
import com.intellij.openapi.vfs.VirtualFile
7+
import com.intellij.xdebugger.XDebugSession
8+
import com.intellij.xdebugger.breakpoints.XBreakpointHandler
9+
import com.intellij.xdebugger.breakpoints.XBreakpointProperties
10+
import com.intellij.xdebugger.breakpoints.XBreakpointType
11+
import com.intellij.xdebugger.breakpoints.XLineBreakpoint
12+
13+
class PowerShellBreakpointHandler(powerShellDebugProcess: PowerShellDebugProcess, breakpointTypeClass: Class<out XBreakpointType<XLineBreakpoint<XBreakpointProperties<*>>, *>>): XBreakpointHandler<XLineBreakpoint<XBreakpointProperties<*>>>(
14+
breakpointTypeClass
15+
) {
16+
val myPowerShellDebugProcess = powerShellDebugProcess;
17+
18+
override fun registerBreakpoint(breakpoint: XLineBreakpoint<XBreakpointProperties<*>>) {
19+
val sourcePosition = breakpoint.sourcePosition
20+
if (sourcePosition == null || !sourcePosition.file.exists() || !sourcePosition.file.isValid) {
21+
return
22+
}
23+
val file = sourcePosition.file
24+
val project: Project = myPowerShellDebugProcess.getSession().getProject()
25+
val fileURL: String = getFileURL(file)
26+
val lineNumber: Int = breakpoint.line
27+
if (lineNumber == -1) {
28+
//myXsltDebugProcess.getSession().setBreakpointInvalid(breakpoint, "Unsupported breakpoint position")
29+
return
30+
}
31+
/*try {
32+
val manager: BreakpointManager = myPowerShellDebugProcess.getBreakpointManager()
33+
var bp: Breakpoint
34+
if ((manager.getBreakpoint(fileURL, lineNumber).also { bp = it }) != null) {
35+
bp.setEnabled(true)
36+
} else {
37+
manager.setBreakpoint(fileURL, lineNumber)
38+
}
39+
} catch (ignore: DebuggerStoppedException) {
40+
} catch (e: VMPausedException) {
41+
val session: XDebugSession = myXsltDebugProcess.getSession()
42+
session.reportMessage(
43+
XsltDebuggerBundle.message("notification.content.target.vm.not.responding.breakpoint.can.not.be.set"),
44+
MessageType.ERROR
45+
)
46+
session.setBreakpointInvalid(breakpoint, "Target VM is not responding. Breakpoint can not be set")
47+
}*/
48+
}
49+
50+
override fun unregisterBreakpoint(breakpoint: XLineBreakpoint<XBreakpointProperties<*>>, temporary: Boolean) {
51+
TODO("Not yet implemented")
52+
}
53+
54+
fun getFileURL(file: VirtualFile?): String {
55+
return VfsUtil.virtualToIoFile(file!!).toURI().toASCIIString()
56+
}
57+
58+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.intellij.plugin.powershell.ide.debugger
2+
3+
import com.intellij.ide.highlighter.XmlFileType
4+
import com.intellij.openapi.fileEditor.FileDocumentManager
5+
import com.intellij.openapi.project.Project
6+
import com.intellij.openapi.vfs.VirtualFile
7+
import com.intellij.plugin.powershell.PowerShellFileType
8+
import com.intellij.plugin.powershell.ide.MessagesBundle
9+
import com.intellij.psi.PsiDocumentManager
10+
import com.intellij.xdebugger.breakpoints.XBreakpointProperties
11+
import com.intellij.xdebugger.breakpoints.XLineBreakpointType
12+
13+
//XsltDebuggerBundle.message("title.xslt.breakpoints")
14+
class PowerShellBreakpointType : XLineBreakpointType<XBreakpointProperties<*>>("powershell", MessagesBundle.message("powershell.debugger.breakpoints.title")) {
15+
override fun canPutAt(file: VirtualFile, line: Int, project: Project): Boolean {
16+
val document = FileDocumentManager.getInstance().getDocument(file) ?: return false
17+
18+
val psiFile = PsiDocumentManager.getInstance(project).getPsiFile(document) ?: return false
19+
val fileType = psiFile.fileType
20+
if (fileType != PowerShellFileType.INSTANCE) {
21+
return false
22+
}
23+
return true
24+
}
25+
override fun createBreakpointProperties(file: VirtualFile, line: Int): XBreakpointProperties<*>? {
26+
return null
27+
}
28+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package com.intellij.plugin.powershell.ide.debugger
2+
3+
import com.intellij.execution.ExecutionResult
4+
import com.intellij.execution.ui.ExecutionConsole
5+
import com.intellij.openapi.Disposable
6+
import com.intellij.openapi.util.Key
7+
import com.intellij.xdebugger.XDebugProcess
8+
import com.intellij.xdebugger.XDebugSession
9+
import com.intellij.xdebugger.breakpoints.XBreakpointHandler
10+
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider
11+
12+
class PowerShellDebugProcess(session: XDebugSession, executionResult: ExecutionResult) : XDebugProcess(session), Disposable {
13+
14+
val KEY: Key<PowerShellDebugProcess> = Key.create("com.intellij.plugin.powershell.ide.debugger.PowerShellDebugProcess")
15+
16+
val myProcessHandler = executionResult.processHandler
17+
init {
18+
myProcessHandler.putUserData(KEY, this)
19+
}
20+
val myExecutionConsole = executionResult.executionConsole
21+
val myEditorsProvider = PowerShellDebuggerEditorsProvider()
22+
init {
23+
com.intellij.openapi.util.Disposer.register(myExecutionConsole, this)
24+
}
25+
26+
private val myXBreakpointHandlers = arrayOf<XBreakpointHandler<*>>(
27+
PowerShellBreakpointHandler(
28+
this,
29+
PowerShellBreakpointType::class.java
30+
),
31+
)
32+
33+
override fun createConsole(): ExecutionConsole {
34+
return myExecutionConsole
35+
}
36+
override fun getEditorsProvider(): XDebuggerEditorsProvider {
37+
return myEditorsProvider
38+
}
39+
40+
override fun getBreakpointHandlers(): Array<XBreakpointHandler<*>> {
41+
return myXBreakpointHandlers
42+
}
43+
44+
override fun dispose() {
45+
TODO("Not yet implemented")
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
package com.intellij.plugin.powershell.ide.debugger
2+
3+
import com.intellij.openapi.editor.Document
4+
import com.intellij.openapi.fileTypes.FileType
5+
import com.intellij.openapi.project.Project
6+
import com.intellij.plugin.powershell.PowerShellFileType
7+
import com.intellij.psi.PsiDocumentManager
8+
import com.intellij.psi.PsiElement
9+
import com.intellij.psi.PsiFileFactory
10+
import com.intellij.util.LocalTimeCounter
11+
import com.intellij.xdebugger.XExpression
12+
import com.intellij.xdebugger.XSourcePosition
13+
import com.intellij.xdebugger.evaluation.EvaluationMode
14+
import com.intellij.xdebugger.evaluation.XDebuggerEditorsProvider
15+
16+
class PowerShellDebuggerEditorsProvider: XDebuggerEditorsProvider() {
17+
private var myFileType: PowerShellFileType = PowerShellFileType.INSTANCE
18+
19+
override fun getFileType(): FileType {
20+
return myFileType
21+
}
22+
23+
override fun createDocument(
24+
project: Project,
25+
expression: XExpression,
26+
sourcePosition: XSourcePosition?,
27+
mode: EvaluationMode
28+
): Document {
29+
val psiFile = PsiFileFactory.getInstance(project)
30+
.createFileFromText(
31+
"pwsh." + myFileType.getDefaultExtension(), myFileType, expression.expression,
32+
LocalTimeCounter.currentTime(), true
33+
)
34+
35+
val document = checkNotNull(PsiDocumentManager.getInstance(project).getDocument(psiFile))
36+
return document
37+
}
38+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.intellij.plugin.powershell.ide.debugger
2+
3+
import com.intellij.xdebugger.XSourcePosition
4+
import com.intellij.xdebugger.XSourcePositionWrapper
5+
6+
class PowerShellSourcePosition(position: XSourcePosition) : XSourcePositionWrapper(position) {
7+
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
package com.intellij.plugin.powershell.ide.run
2+
3+
import com.intellij.execution.ExecutionException
4+
import com.intellij.execution.ExecutionResult
5+
import com.intellij.execution.configurations.RunProfile
6+
import com.intellij.execution.configurations.RunProfileState
7+
import com.intellij.execution.configurations.RunnerSettings
8+
import com.intellij.execution.executors.DefaultDebugExecutor
9+
import com.intellij.execution.runners.AsyncProgramRunner
10+
import com.intellij.execution.runners.ExecutionEnvironment
11+
import com.intellij.execution.ui.RunContentDescriptor
12+
import com.intellij.openapi.fileEditor.FileDocumentManager
13+
import com.intellij.openapi.rd.util.toPromise
14+
import com.intellij.openapi.rd.util.withUiContext
15+
import com.intellij.plugin.powershell.ide.PluginProjectRoot
16+
import com.intellij.plugin.powershell.ide.debugger.PowerShellDebugProcess
17+
import com.intellij.xdebugger.XDebugProcess
18+
import com.intellij.xdebugger.XDebugProcessStarter
19+
import com.intellij.xdebugger.XDebugSession
20+
import com.intellij.xdebugger.XDebuggerManager
21+
import kotlinx.coroutines.Dispatchers
22+
import kotlinx.coroutines.ExperimentalCoroutinesApi
23+
import kotlinx.coroutines.async
24+
import org.jetbrains.concurrency.Promise
25+
import java.lang.Boolean
26+
import kotlin.OptIn
27+
import kotlin.String
28+
import kotlin.Throws
29+
30+
/**
31+
* The main purpose of this runner is to call [RunProfileState.execute] or a background thread instead of a foreground
32+
* one, as our [RunProfileState] implementation requires FS access that's only possible from the background.
33+
*/
34+
class PowerShellProgramDebugRunner : AsyncProgramRunner<RunnerSettings>() {
35+
36+
override fun getRunnerId() = "com.intellij.plugin.powershell.ide.run.PowerShellProgramDebugRunner"
37+
38+
override fun canRun(executorId: String, profile: RunProfile) =
39+
executorId == DefaultDebugExecutor.EXECUTOR_ID && profile is PowerShellRunConfiguration
40+
41+
@OptIn(ExperimentalCoroutinesApi::class)
42+
override fun execute(environment: ExecutionEnvironment, state: RunProfileState): Promise<RunContentDescriptor?> =
43+
PluginProjectRoot.getInstance(environment.project).coroutineScope.async(Dispatchers.Default) {
44+
state as PowerShellScriptCommandLineState
45+
withUiContext {
46+
FileDocumentManager.getInstance().saveAllDocuments()
47+
}
48+
state.prepareExecution()
49+
val executionResult = state.execute(environment.executor, this@PowerShellProgramDebugRunner)
50+
val descriptor = withUiContext {
51+
XDebuggerManager.getInstance(environment.project).startSession(environment, object : XDebugProcessStarter() {
52+
@Throws(ExecutionException::class)
53+
override fun start(session: XDebugSession): XDebugProcess {
54+
return PowerShellDebugProcess(session, executionResult)
55+
}
56+
}).runContentDescriptor
57+
}
58+
descriptor
59+
}.toPromise()
60+
}

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

+3-4
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,6 @@
2020

2121
<extensions defaultExtensionNs="com.intellij">
2222

23-
<toolWindow id="DebugLogWindow"
24-
anchor="bottom"
25-
factoryClass="com.intellij.execution."></toolWindow>
26-
2723
<fileType name="PowerShell" language="PowerShell" extensions="ps1;psm1;psd1"
2824
implementationClass="com.intellij.plugin.powershell.PowerShellFileType" />
2925

@@ -69,7 +65,10 @@
6965
<runConfigurationProducer
7066
implementation="com.intellij.plugin.powershell.ide.run.PowerShellConfigurationProducer" order="first"/>
7167

68+
<xdebugger.breakpointType implementation="com.intellij.plugin.powershell.ide.debugger.PowerShellBreakpointType"/>
69+
7270
<programRunner implementation="com.intellij.plugin.powershell.ide.run.PowerShellProgramRunner"/>
71+
<programRunner implementation="com.intellij.plugin.powershell.ide.run.PowerShellProgramDebugRunner"/>
7372

7473
<targetElementEvaluator language="PowerShell"
7574
implementationClass="com.intellij.plugin.powershell.ide.search.PowerShellTargetElementEvaluator"/>

src/main/resources/messages/MessagesBundle.properties

+2
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,5 @@ wrapping.attribute.argument=Attribute arguments
3131
wrapping.block.parameters=Block parameters
3232
wrapping.catch,type.list=Catch type list
3333
wrapping.pipeline=Pipeline
34+
35+
powershell.debugger.breakpoints.title=Breakpoints

0 commit comments

Comments
 (0)