diff --git a/src/Microsoft.PowerShell.Linux.Host/main.cs b/src/Microsoft.PowerShell.Linux.Host/main.cs index 4ca6e5f56..9ff281c0f 100644 --- a/src/Microsoft.PowerShell.Linux.Host/main.cs +++ b/src/Microsoft.PowerShell.Linux.Host/main.cs @@ -122,6 +122,11 @@ namespace Microsoft.PowerShell.Linux.Host /// private object instanceLock = new object(); + /// + /// To keep track whether we've displayed the debugger help message + /// + private bool _showHelpMessage; + /// /// Gets or sets a value indicating whether the host application /// should exit. @@ -152,6 +157,17 @@ namespace Microsoft.PowerShell.Linux.Host this.myRunSpace = RunspaceFactory.CreateRunspace(this.myHost, iss); this.myRunSpace.Open(); + if (this.myRunSpace.Debugger != null) + { + this.myRunSpace.Debugger.DebuggerStop += HandleDebuggerStopEvent; + + // Workflow debugging is new for PowerShell version 4 and is an opt-in + // feature. In order to debug Workflow script functions the debugger + // DebugMode must include the DebugModes.LocalScript flag. + this.myRunSpace.Debugger.SetDebugMode(DebugModes.LocalScript); + + } + // Create a PowerShell object to run the commands used to create // $profile and load the profiles. lock (this.instanceLock) @@ -447,5 +463,96 @@ namespace Microsoft.PowerShell.Linux.Host // The exit code is set in the host by the MyHost.SetShouldExit() method. //Environment.Exit(this.ExitCode); } + + /// + /// Method to handle the Debugger DebuggerStop event. + /// + /// Debugger instance + /// DebuggerStop event args + private void HandleDebuggerStopEvent(object sender, DebuggerStopEventArgs args) + { + Debugger debugger = sender as Debugger; + DebuggerResumeAction? resumeAction = null; + + WriteDebuggerStopMessages(args); + + // loop to process Debugger commands. + while (resumeAction == null) + { + Console.Write("[DBG] PS >> "); + string command = Console.ReadLine(); + Console.WriteLine(); + + // Stream output from command processing to console. + var output = new PSDataCollection(); + output.DataAdded += (dSender, dArgs) => + { + foreach (var item in output.ReadAll()) + { + Console.WriteLine(item); + } + }; + + // Process command. + // The Debugger.ProcesCommand method will parse and handle debugger specific + // commands such as 'h' (help), 'list', 'stepover', etc. If the command is + // not specific to the debugger then it will be evaluated as a PowerShell + // command or script. The returned DebuggerCommandResults object will indicate + // whether the command was evaluated by the debugger and if the debugger should + // be released with a specific resume action. + PSCommand psCommand = new PSCommand(); + psCommand.AddScript(command).AddCommand("Out-String").AddParameter("Stream", true); + DebuggerCommandResults results = debugger.ProcessCommand(psCommand, output); + if (results.ResumeAction != null) + { + resumeAction = results.ResumeAction; + } + } + + // Return from event handler with user resume action. + args.ResumeAction = resumeAction.Value; + } + + /// + /// Helper method to write debugger stop messages. + /// + /// DebuggerStopEventArgs for current debugger stop + private void WriteDebuggerStopMessages(DebuggerStopEventArgs args) + { + // Write debugger stop information in yellow. + ConsoleColor saveFGColor = Console.ForegroundColor; + Console.ForegroundColor = ConsoleColor.Yellow; + + // Show help message only once. + if (!_showHelpMessage) + { + Console.WriteLine("Entering debug mode. Type 'h' to get help."); + Console.WriteLine(); + _showHelpMessage = true; + } + + // Breakpoint stop information. Writes all breakpoints that + // pertain to this debugger execution stop point. + if (args.Breakpoints.Count > 0) + { + Console.WriteLine("Debugger hit breakpoint on:"); + foreach (var breakPoint in args.Breakpoints) + { + Console.WriteLine(breakPoint.ToString()); + } + Console.WriteLine(); + } + + // Script position stop information. + // This writes the InvocationInfo position message if + // there is one. + if (args.InvocationInfo != null) + { + Console.WriteLine(args.InvocationInfo.PositionMessage); + Console.WriteLine(); + } + + Console.ForegroundColor = saveFGColor; + } } }