} // end constructor // // IEquatable-related stuff // public bool Equals(PropertyListItem other) { if (other == null) { return(false); } return((PropertyName == other.PropertyName) && (FormatString?.ToString(true) == other.FormatString?.ToString(true)) && (m_label == other.m_label)); }
protected StringBuilder ObjectToMarkedUpString(object obj, ColorString formatString, StringBuilder sb) { if (null == sb) { sb = new StringBuilder(); } if (null == obj) { //return sb; return(sb.Append("$null")); } PSObject pso = obj as PSObject; if (null != pso) { // Check if there is a custom .ToString() method attached to this // PSObject. (which is used, for instance, for displaying enum values) var toStringMethods = Util.TryGetCustomToStringMethod(pso); if (null != toStringMethods) { // TODO: check overloads/signature? obj = toStringMethods.Invoke(); if (obj is string) { return(sb.Append((string)obj)); } else { LogManager.Trace("Interesting... a custom .ToString() method returned something besides a string."); } } else { obj = pso.BaseObject; } } ColorString cs = obj as ColorString; if (null != cs) { sb.Append(cs.ToString(DbgProvider.HostSupportsColor)); } else { ISupportColor isc = obj as ISupportColor; if (null != isc) { sb.Append(isc.ToColorString().ToString(DbgProvider.HostSupportsColor)); } else { string renderedFormatString = null; if (null != formatString) { renderedFormatString = formatString.ToString(DbgProvider.HostSupportsColor); } if (!String.IsNullOrEmpty(renderedFormatString)) { sb.Append(Util.CcSprintf(renderedFormatString, obj)); } else { // TODO: Or should it be pso.ToString here? sb.Append(obj.ToString()); } } } return(sb); } // end ObjectToMarkedUpString()
} // end GenerateView() protected override void ApplyViewToInputObject() { for (int idx = 0; idx < m_view.ListItems.Count; idx++) { if (Stopping) { break; } ColorString listItem = new ColorString(sm_labelColors); ListItem li = m_view.ListItems[idx]; listItem.Append(PadAndAlign(li.Label, m_view.MaxLabelLength + 1, ColumnAlignment.Left) + ": "); listItem.Append(sm_pop.ToString(DbgProvider.HostSupportsColor)); string val; if (li is PropertyListItem) { var pli = (PropertyListItem)li; val = RenderPropertyValue(InputObject, pli.PropertyName, pli.FormatString, dontGroupMultipleResults: false, allowMultipleLines: true); // <-- N.B. special for Format-List compat } else { var sli = (ScriptListItem)li; val = RenderScriptValue(InputObject, sli.Script); if (null == val) { val = String.Empty; } } listItem.Append(_Indent(val)); SafeWriteObject(listItem); } // N.B. Using String.Empty here used to cause 3 blank lines instead of one. // I don't understand precisely why, but the crux of the problem is that // // a) System.String has a custom view definition (which is to get around // PowerShell's reticence to properly display strings if they have // other stuff in their TypeNames) (see commit 4bc7d1c76f97d0) // b) When we write the string here, for some reason it causes a // transition between steppable pipelines, and the PS default // formatter wants to put in an extra newline at the format start and // another at the format end. // // Fortunately, it seems easy enough to workaround by sending a different type // of object down the pipeline. // // (I wonder if it might have been specific to the particular commands I was // using to test, like "uf blah!blah | fl", or symbols | fl, because of how // their formatting was done.) // //SafeWriteObject( String.Empty ); // to get a blank line SafeWriteObject(ColorString.Empty); // to get a blank line } // end ApplyViewToInputObject()
} // end _AltMainThread() static int MainWorker(string[] args) { try { var profileDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData, Environment.SpecialFolderOption.DoNotVerify), "Temp", "DbgProvider", "ProfileOpt"); Directory.CreateDirectory(profileDir); System.Runtime.ProfileOptimization.SetProfileRoot(profileDir); System.Runtime.ProfileOptimization.StartProfile("StartupProfileData-" + (DbgProvider.IsInGuestMode ? "GuestMode" : "NormalMode")); } catch { Util.Fail("SetProfileRoot/StartProfile failed"); // It's safe to ignore errors, the guarded code is just there to try and // improve startup performance. } string rootDir; try { rootDir = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } catch (Exception e) { Console.WriteLine("Exception! {0}", e); return(-1); } //Console.WriteLine( "rootDir: {0}", rootDir ); /* * string pathToMsvcr120 = Assembly.GetExecutingAssembly().Location; * pathToMsvcr120 = Path.GetDirectoryName( pathToMsvcr120 ); #if DEBUG * pathToMsvcr120 = Path.Combine( pathToMsvcr120, "Debugger", "MSVCR120d.dll" ); #else * pathToMsvcr120 = Path.Combine( pathToMsvcr120, "Debugger", "MSVCR120.dll" ); #endif * * IntPtr hMsvcr = NativeMethods.LoadLibraryEx( pathToMsvcr120, * IntPtr.Zero, * LoadLibraryExFlags.LOAD_WITH_ALTERED_SEARCH_PATH ); * if( IntPtr.Zero == hMsvcr ) * throw new Exception( "Could not load MSVCR120.dll." ); */ _ConfigureModulePath(rootDir); _RemoveMarkOfTheInternet(rootDir); string dbgModuleDir = Path.Combine(rootDir, "Debugger"); // TODO: investigate differences between CreateDefault and CreateDefault2 InitialSessionState iss = InitialSessionState.CreateDefault(); iss.ExecutionPolicy = Microsoft.PowerShell.ExecutionPolicy.Bypass; // TODO: maybe add to iss.Formats? List <InitScript> initScripts = new List <InitScript>(); initScripts.Add(new InitScript("SetStrictMode", "Set-StrictMode -Version Latest")); initScripts.Add(new InitScript("ImportOurModule", Util.Sprintf(@"Import-Module ""{0}""", Path.Combine(dbgModuleDir, "Debugger.psd1")))); initScripts.Add(new InitScript("CreateBinDrive", String.Format(CultureInfo.InvariantCulture, @"[void] (New-PSDrive Bin FileSystem ""{0}"")", rootDir))); initScripts.Add(new InitScript("SetStartLocation", "Set-Location Dbg:\\")); if (DbgProvider.IsInGuestMode) { // In guest mode, we are already attached to something, so we need to // build the namespace based on the existing dbgeng state. initScripts.Add(new InitScript("RebuildNs", "[MS.Dbg.DbgProvider]::ForceRebuildNamespace()")); } // I cannot explain why, but using Update-FormatData (which is [a proxy // function] defined in our module instead of Invoke-Script (a C# cmdlet // defined in our module) subtly changes something having to do with scope or // something, such that the $AltListIndent variable wasn't working... until // all the format data was reloaded via Update-FormatData. var fmtScripts = _GetFmtScripts(dbgModuleDir); initScripts.Add( new InitScript("LoadFmtDefinitions", String.Format(CultureInfo.InvariantCulture, @"[void] (Update-FormatData ""{0}"")", String.Join("\", \"", fmtScripts)))); // And in fact it seems that the trick to not losing our "captured contexts" // is that Update-AltFormatData needs to always be run in the context of the // Debugger.Formatting module. string monkeyPatched = @"function Update-AltFormatData { [CmdletBinding()] param( [Parameter( Mandatory = $false )] [string[]] $AppendPath = @(), [Parameter( Mandatory = $false )] [string[]] $PrependPath = @() ) process { try { # This is pretty ugly. In particular, I can't find a better way to pass in # -Verbose. Ideally it could just be captured magically, but things like # <scriptblock>.GetNewClosure() don't seem to help. Invoke-InAlternateScope -ScriptBlock { $VerbosePreference = $args[2] ; Debugger\Update-AltFormatData -AppendPath $args[0] -PrependPath $args[1] } ` -Arguments @( $AppendPath, $PrependPath, $VerbosePreference ) ` -ScopingModule ((Get-Module Debugger).NestedModules | where name -eq 'Debugger.Formatting') } finally { } } # end 'process' block <# .ForwardHelpTargetName Update-AltFormatData .ForwardHelpCategory Cmdlet #> }"; initScripts.Add(new InitScript("MonkeyPatchUpdateAltFormatData", monkeyPatched)); string typesPs1Xml = Path.Combine(dbgModuleDir, "Types.ps1xml"); if (File.Exists(typesPs1Xml)) // TODO: Remove once types.ps1xml is picked in { initScripts.Add( new InitScript("LoadTypeAdapterStuff", String.Format(CultureInfo.InvariantCulture, @"[void] (Update-TypeData ""{0}"")", c_FileSystem_PowerShellProviderPrefix + typesPs1Xml))); } var converterScripts = Directory.GetFiles(dbgModuleDir, "Debugger.Converters.*.ps1"); StringBuilder loadConvertersCmd = new StringBuilder(); foreach (var converterScript in converterScripts) { loadConvertersCmd.Append(Util.Sprintf("; [void] (& '{0}{1}')", c_FileSystem_PowerShellProviderPrefix, converterScript)); } string argCompleterScript = Path.Combine(dbgModuleDir, "Debugger.ArgumentCompleters.ps1"); loadConvertersCmd.Append(Util.Sprintf("; [void] (& '{0}{1}')", c_FileSystem_PowerShellProviderPrefix, argCompleterScript)); initScripts.Add(new InitScript("LoadConverters", loadConvertersCmd.ToString())); // TODO: wrap var colorBanner = new ColorString(ConsoleColor.Cyan, "Microsoft Debugger DbgShell\n") .AppendFg(ConsoleColor.DarkCyan).Append("Copyright (c) 2015\n\n") .AppendFg(ConsoleColor.Magenta).Append("Welcome.\n\n") .AppendFg(ConsoleColor.Gray).Append("Note that script execution policy is '") .AppendFg(ConsoleColor.Yellow).Append("Bypass") .AppendFg(ConsoleColor.Gray).Append("' for this process.\nRun '") .AppendFg(ConsoleColor.Yellow).Append("Get-Help") .AppendFg(ConsoleColor.Gray).Append(" about_DbgShell_GettingStarted' to learn about DbgShell.\n"); if (DbgProvider.IsInGuestMode) { colorBanner .AppendFg(ConsoleColor.Gray).Append("\nWhen you are finished here and want to return control back to the debugger, run '") .AppendFg(ConsoleColor.Yellow).Append("q") .AppendFg(ConsoleColor.Gray).Append("' or '") .AppendFg(ConsoleColor.Green).Append("exit") .AppendFg(ConsoleColor.Gray).Append("'."); } string banner = colorBanner.ToString(true); int rc = ColorConsoleHost.Start(iss, initScripts, banner, String.Empty, args); return(rc); } // end MainWorker()
protected StringBuilder ObjectToMarkedUpString(object obj, ColorString formatString, StringBuilder sb) { if (null == sb) { sb = new StringBuilder(); } if (null == obj) { // We used to return sb.Append( "$null" ); however I'm changing to append // nothing in order to match the behavior of FormatSingleLineDirect (which // is what is applied to obj if there is no formatString, which yields an // empty string, so when we come through here, obj is an empty string, not // null). return(sb); } PSObject pso = obj as PSObject; if (null != pso) { // Check if there is a custom .ToString() method attached to this // PSObject. (which is used, for instance, for displaying enum values) var toStringMethods = Util.TryGetCustomToStringMethod(pso); if (null != toStringMethods) { // TODO: check overloads/signature? obj = toStringMethods.Invoke(); if (obj is string) { return(sb.Append((string)obj)); } else { LogManager.Trace("Interesting... a custom .ToString() method returned something besides a string."); } } else { obj = pso.BaseObject; } } ColorString cs = obj as ColorString; if (null != cs) { sb.Append(cs.ToString(DbgProvider.HostSupportsColor)); } else { ISupportColor isc = obj as ISupportColor; if (null != isc) { sb.Append(isc.ToColorString().ToString(DbgProvider.HostSupportsColor)); } else { string renderedFormatString = null; if (null != formatString) { renderedFormatString = formatString.ToString(DbgProvider.HostSupportsColor); } if (!String.IsNullOrEmpty(renderedFormatString)) { sb.Append(Util.CcSprintf(renderedFormatString, obj)); } else { // TODO: Or should it be pso.ToString here? sb.Append(obj.ToString()); } } } return(sb); } // end ObjectToMarkedUpString()
public Answers Ask() { var answers = new Answers(_promptItems.Count); EventHandler <BeforeAfterPromptEventArgs> beforePrompt = BeforePrompt; EventHandler <BetweenPromptEventArgs> betweenPrompts = BetweenPrompts; EventHandler <BeforeAfterPromptEventArgs> afterPrompt = AfterPrompt; for (int i = 0; i < _promptItems.Count; i++) { PromptItem promptItem = _promptItems[i]; beforePrompt?.Invoke(this, new BeforeAfterPromptEventArgs { Prompt = promptItem }); object answer; // If the prompt cannot be displayed, continue the loop. // If it is a question, try assigning the default value, if available, before // continuing. if (!promptItem.CanAsk(answers)) { if (promptItem is Question q) { answer = q.DefaultValue.Resolve(answers); if (answer != null) { answers.Add(q.Name, answer); } } continue; } // If the prompt is static text, just display it and continue the loop. if (promptItem is StaticText) { promptItem.AskerFn(promptItem, answers); continue; } var question = promptItem as Question; if (question.Instructions.Count > 0) { foreach (FunctionOrColorString instruction in question.Instructions) { var cstr = new ColorString().Text(instruction.Resolve(answers), Style.Instructions.ForeColor, Style.Instructions.BackColor); ConsoleEx.PrintLine(cstr.ToString()); } } answer = null; bool validAnswer = false; do { object input = question.AskerFn(question, answers); if (question.RawValueValidator != null) { ValidationResult validationResult = question.RawValueValidator(input, answers); if (!validationResult.Valid) { if (!string.IsNullOrWhiteSpace(validationResult.ErrorMessage)) { ConsoleEx.PrintLine($"{Clr.Red}{validationResult.ErrorMessage}"); } continue; } } if (input is null || (input is string s && s.Length == 0)) { answer = question.DefaultValue.Resolve(answers); } else { answer = input; } answer = question.Convert(answer); if (question.ConvertedValueValidator != null) { ValidationResult validationResult = question.ConvertedValueValidator(answer, answers); if (!validationResult.Valid) { if (!string.IsNullOrWhiteSpace(validationResult.ErrorMessage)) { ConsoleEx.PrintLine($"{Clr.Red}{validationResult.ErrorMessage}"); } continue; } } validAnswer = true; } #pragma warning disable S2583 // Conditionally executed blocks should be reachable while (!validAnswer); #pragma warning restore S2583 // Conditionally executed blocks should be reachable answers.Add(question.Name, answer); if (i < _promptItems.Count - 1) { betweenPrompts?.Invoke(this, new BetweenPromptEventArgs { PreviousPrompt = promptItem, NextPrompt = _promptItems[i + 1], }); } afterPrompt?.Invoke(this, new BeforeAfterPromptEventArgs { Prompt = promptItem }); }
public void ToString_BuildsColorString(ColorString cs, string expectedString) { string colorString = cs.ToString(); colorString.ShouldBe(expectedString); }