in DbgShell/ColorConsoleHost.cs [207:434]
public void Run()
{
StringBuilder sbCmd = new StringBuilder();
while( !m_timeToStop && !m_host.ShouldExit )
{
string input;
bool addToHistory;
if( _IsOutermostInputLoop && _HaveInjectedCommands )
{
// From "guest mode".
addToHistory = false;
input = sm_injectedCommands.Dequeue();
}
else
{
addToHistory = true;
string prompt;
if( 0 == sbCmd.Length )
{
prompt = m_host._GetPrompt( m_shell );
}
else
{
prompt = "\u009b97m>>\u009bm ";
}
m_host.UI.Write( prompt );
try
{
input = m_host.m_ui.ReadLineWithTabCompletion( true );
}
catch( PipelineStoppedException ) // thrown if calling user-defined tab completion (TODO: except we don't actually ever call user-defined tab completion yet)
{
sbCmd.Clear();
_ClearAutoRepeatCmd();
continue;
}
}
if( null == input )
{
// It returns null if input was canceled via CTRL-C.
//
// (and it's a good thing--if we tried to use a CtrlCInterceptor
// to cancel multi-line input, it wouldn't work well, because the
// CTRL-C thread races with the input thread)
sbCmd.Clear();
_ClearAutoRepeatCmd();
m_host.m_ui.WriteLine();
continue;
}
if( String.IsNullOrWhiteSpace( input ) )
{
if( sbCmd.Length != 0 )
{
sbCmd.Append( input ); // let's keep the whitespace for looks.
sbCmd.AppendLine();
continue;
}
else
{
if( 0 == input.Length )
{
//
// Someone just hit [Enter].
//
// We'll retrieve the DbgAutoRepeatCommand command.
//
if( !m_shell.IsNested )
{
string autoRepeatCmd = m_shell.Runspace.SessionStateProxy.PSVariable.GetValue(
c_DbgAutoRepeatCmd,
null ) as string;
m_shell.Runspace.SessionStateProxy.PSVariable.Set( c_DbgAutoRepeatCmd, null );
sbCmd.Append( autoRepeatCmd );
}
else
{
// Unbelievably, you cannot access session state via the Runspace.SessionStateProxy
// (doing so will yield a PSInvalidOperationException: "A pipeline is already
// running. Concurrent SessionStateProxy method call is not allowed.", whether you
// access it from the pipeline execution thread or the main thread (that owns the
// shell). So we'll get around that by just running some script to get and set the
// variable.
var results = m_host._ExecScriptNoExceptionHandling( m_shell,
Util.Sprintf( "Get-Variable {0}",
c_DbgAutoRepeatCmd ),
false,
false );
if( (null != results) &&
(results.Count > 0) &&
(results[ 0 ].BaseObject is PSVariable) )
{
PSVariable psvar = (PSVariable) results[ 0 ].BaseObject;
if( psvar.Value is string )
sbCmd.Append( (string) psvar.Value );
}
m_host._ExecScriptNoExceptionHandling( m_shell,
Util.Sprintf( "Set-Variable {0} $null",
c_DbgAutoRepeatCmd ),
false,
false );
} // end else( nested shell )
if( 0 == sbCmd.Length )
continue;
}
else
{ // input.Length != 0
//
// This is for the type-space-then-enter scenario, which
// windbg users use to clear the auto-run command.
//
_ClearAutoRepeatCmd();
continue;
}
} // end else( no multiline input )
} // end if( current input is empty )
#if DEBUG
else if( 0 == Util.Strcmp_OI( "Test-CaStringUtil", input ) )
{
CaStringUtil.SelfTest();
continue;
}
else if( 0 == Util.Strcmp_OI( "Test-MassageTypeName", input ) )
{
Util.TestMassageTypeName();
continue;
}
#endif
else
{
_ClearAutoRepeatCmd();
sbCmd.Append( input );
}
try
{
using( _CreateTryStopShellCtrlHandler( m_shell ) )
{
LogManager.Trace( "Attempting to execute input: {0}", sbCmd.ToString() );
m_host._ExecScriptNoExceptionHandling( m_shell,
sbCmd.ToString(),
addToHistory );
sbCmd.Clear();
//
// Now that the command has been executed, we'll discard any
// leftover progress stuff.
//
m_host.m_ui.ResetProgress();
if( !m_timeToStop && !m_host.ShouldExit )
{
try
{
// If we make it back to here and the execution status is
// "go", then we need to wait.
//
// This can happen, for instance, when DbgShell.exe is the
// host (we are not in guest mode), and a breakpoint
// command runs a !dbgshell command which resumes
// execution. Resuming execution from the bp cmd will use
// "exit" to terminate the bp cmd, and we'll end up back
// here. So rather than just show another prompt, we need
// to actually do the wait here.
//
// In the guest mode case, the "exit" causes us to
// passivate, returning control to windbg (or whoever the
// host is), and the host performs the wait.
var execStatus = DbgEngDebugger._GlobalDebugger.GetExecutionStatus();
bool statusRequiresWait = _StatusRequiresWait( execStatus );
while( statusRequiresWait )
{
LogManager.Trace( "InputLoop.Run: current status requires we wait: {0}", execStatus );
// Rather than just calling
// DbgEngDebugger._GlobalDebugger.WaitForEventAsync(),
// we will call a cmdlet (Resume-Process) to do the
// wait for us. This will set up a pipeline so that
// events can be reported, a CTRL-C handler, etc.
m_host._ExecScriptNoExceptionHandling( m_shell,
"Resume-Process -ResumeType Passive",
addToHistory: false );
execStatus = DbgEngDebugger._GlobalDebugger.GetExecutionStatus();
statusRequiresWait = _StatusRequiresWait( execStatus );
}
}
catch( DbgEngException dee )
{
m_host._ReportException( dee, m_shell ); // <-- this may be a nested shell
}
} // end if( !m_timeToStop && !m_host.ShouldExit )
} // end using( _CreateTryStopShellCtrlHandler( m_shell ) )
}
catch( IncompleteParseException )
{
// We'll just keep appending to sbCmd.
sbCmd.AppendLine();
}
catch( PipelineStoppedException )
{
sbCmd.Clear();
// ignore
}
catch( RuntimeException rte )
{
sbCmd.Clear();
m_host._ReportException( rte, m_shell ); // <-- this may be a nested shell
}
catch( Exception e )
{
Util.Fail( Util.Sprintf( "What error is this? {0}", e ) );
sbCmd.Clear();
}
} // end while( !m_timeToStop && !m_host.m_shouldExit )
} // end Run()