} // end GenerateView() protected override void ApplyViewToInputObject() { string val = RenderScriptValue(InputObject, m_view.Script, false); // TODO: What to do if it spans more than a line? Just truncate? Issue a // warning? Add "..."? Also, consider that the view definition might have been // generated. if (null == val) { WriteObject(String.Empty); } else { //int idx = val.IndexOf( '\n' ); // TODO: Now we pass 'false' for dontGroupMultipleResults, so I think this // won't ever get hit unless we are formatting a string that contains a // newline. Perhaps in that case we should escape it. int idx = CaStringUtil.ApparentIndexOf(val, '\n'); if (idx < 0) { WriteObject(val); } else { WriteObject(CaStringUtil.Truncate(val, idx, false)); } } } // end ApplyViewToInputObject()
internal static string FormatSingleLineDirect(PSObject obj, ScriptBlock script, PsContext ctx) { string val; using (FormatAltSingleLineCommand cmd = new FormatAltSingleLineCommand()) { val = cmd.RenderScriptValue(obj, script, false, ctx); } // TODO: What to do if it spans more than a line? Just truncate? Issue a // warning? Add "..."? Also, consider that the view definition might have been // generated. if (null == val) { return(String.Empty); } else { int idx = CaStringUtil.ApparentIndexOf(val, '\n'); if (idx < 0) { return(val); } else { return(CaStringUtil.Truncate(val, idx)); } } } // end FormatSingleLineDirect
} // end Truncate() /// <summary> /// Creates a new ColorString object if truncation is necessary. /// </summary> public static ColorString Truncate(ColorString cs, int maxApparentWidth, bool useEllipsis) { if (cs.Length <= maxApparentWidth) { return(cs); } // Would it be better to go through all the elements? return(CaStringUtil.Truncate(cs.ToString(true), maxApparentWidth, useEllipsis)); } // end Truncate()
public ColorString AppendPushPopFg(ConsoleColor foreground, string content) { _CheckReadOnly(true); m_elements.Add(new SgrControlSequence(new int[] { PUSH, CaStringUtil.ForegroundColorMap[foreground] })); m_elements.Add(new ContentElement(content)); // The content might not be "pure"; it might be pre-rendered colorized text. m_apparentLength += CaStringUtil.Length(content); m_elements.Add(new SgrControlSequence(new int[] { POP })); return(this); }
internal static string FormatSingleLineDirect(PSObject obj, ScriptBlock script) { #if DEBUG sm_renderScriptCallDepth++; if (sm_renderScriptCallDepth > 10) { // Helps to catch runaway rendering /before/ gobbling tons of memory System.Diagnostics.Debugger.Break(); // Maybe I should just throw? } #endif var ctxVars = new List <PSVariable> { new PSVariable("_", obj), new PSVariable("PSItem", obj) }; var results = script.InvokeWithContext(null, ctxVars); #if DEBUG sm_renderScriptCallDepth--; #endif string val = null; if (results?.Count > 0) { val = ObjectsToMarkedUpString(results, "{0}", // <-- IMPORTANT: this prevents infinite recursion via Format-AltSingleLine null, false, 4).ToString(); } // TODO: What to do if it spans more than a line? Just truncate? Issue a // warning? Add "..."? Also, consider that the view definition might have been // generated. if (null == val) { return(String.Empty); } else { int idx = CaStringUtil.ApparentIndexOf(val, '\n'); if (idx < 0) { return(val); } else { return(CaStringUtil.Truncate(val, idx)); } } } // end FormatSingleLineDirect
private static string _CreateStringKey(PSObject psoKey) { string stringKey = FormatAltSingleLineCommand.FormatSingleLineDirect(psoKey); stringKey = CaStringUtil.StripControlSequences(stringKey); // For string objects, Format-AltSingleLine will yield something with quotes // around it. Let's take them off. Perhaps we should check if psoKey's // BaseObject is a string first? if ((stringKey.Length > 0) && ('"' == stringKey[0]) && ('"' == stringKey[stringKey.Length - 1])) { stringKey = stringKey.Substring(1, stringKey.Length - 2); } return(stringKey); } // end _CreateStringKey()
// This constructor is private, used only by the string -> ColorString implicit conversion // because if it is public, the C# compiler will favor it over the FormattableString constructor // for interpolated strings private ColorString(string content) { // The content might not be "pure"; it might be pre-rendered colorized text. var noColorLength = CaStringUtil.Length(content); if (noColorLength == content.Length) { m_elements.Add(new ContentElement(content)); } else { // TODO: Might be handy to be able to decompose a pre-rendered color // string. For now we'll just dump it in. m_elements.Add(new ContentElement(content)); } m_apparentLength = noColorLength; }
public ColorString Append(string content) { _CheckReadOnly(true); // The content might not be "pure"; it might be pre-rendered colorized text. var noColorLength = CaStringUtil.Length(content); if (noColorLength == content.Length) { m_elements.Add(new ContentElement(content)); } else { // TODO: Might be handy to be able to decompose a pre-rendered color // string. For now we'll just dump it in. m_elements.Add(new ContentElement(content)); } m_apparentLength += noColorLength; return(this); }
protected static string PadAndAlign(string s, int width, ColumnAlignment alignment, TrimLocation trimLocation) { Util.Assert(ColumnAlignment.Default != alignment); int len = CaStringUtil.Length(s); int pad = width - len; if (0 == pad) { return(s); } if (pad < 0) { // Oh dear... too big to fit. return(CaStringUtil.Truncate(s, width, true, trimLocation)); } switch (alignment) { case ColumnAlignment.Left: return(s + new String(' ', pad)); case ColumnAlignment.Center: int leftpad = pad / 2; int rightpad = pad - leftpad; return(new String(' ', leftpad) + s + new String(' ', rightpad)); case ColumnAlignment.Right: return(new String(' ', pad) + s); default: throw new ArgumentException(Util.Sprintf("Invalid ColumnAlignment value: {0}", alignment), "alignment"); } } // end PadAndAlign()
private static ColorString _SummarizeModuleList(bool loadedMods, List <object> modObjList, int maxWidth) { ColorString cs = new ColorString(); if (0 == modObjList.Count) { cs.AppendPushPopFg(ConsoleColor.DarkGray, "(0 modules)"); } else { cs.Append(Util.Sprintf("{0} modules: ", modObjList.Count)); for (int i = 0; i < Math.Min(modObjList.Count, 3); i++) { if (i > 0) { cs.Append(", "); } DbgModuleInfo dmi = (DbgModuleInfo)modObjList[i]; if (loadedMods) { cs.Append(DbgProvider.ColorizeModuleName(dmi.Name)); } else { cs.Append(dmi.ImageName); } } if (modObjList.Count > 3) { cs.Append(", ..."); } } return(CaStringUtil.Truncate(cs.ToString(DbgProvider.HostSupportsColor), maxWidth)); } // end _SummarizeModuleList()
} // end ResetState() private void _WriteHeaders() { ColorString headers = new ColorString(sm_tableHeaderColors); // Write labels: for (int colIdx = 0; colIdx < m_view.Columns.Count; colIdx++) { Column c = m_view.Columns[colIdx]; headers.Append(PadAndAlign(c.Label, c.CalculatedWidth, c.CalculatedAlignment, c.TrimLocation)); if (colIdx != (m_view.Columns.Count - 1)) { headers.Append(" "); // separator } } // Clear the header color: headers.Append(sm_pop); headers.AppendLine(); // Write -------: for (int colIdx = 0; colIdx < m_view.Columns.Count; colIdx++) { Column c = m_view.Columns[colIdx]; int len = CaStringUtil.Length(c.Label); headers.Append(PadAndAlign(new String('-', Math.Min(len, c.CalculatedWidth)), c.CalculatedWidth, c.CalculatedAlignment, c.TrimLocation)); if (colIdx != (m_view.Columns.Count - 1)) { headers.Append(" "); // separator } } SafeWriteObject(headers); } // end _WriteHeaders()
} // end MakeFixedWidth() public static string StripPrerenderedColor(string prerendered) { return(CaStringUtil.StripControlSequences(prerendered)); } // end StripPrerenderedColor()
internal static string FormatSingleLineDirect(PSObject obj, ScriptBlock script, bool allowMultipleLines) { #if DEBUG sm_renderScriptCallDepth++; if (sm_renderScriptCallDepth > 10) { // Helps to catch runaway rendering /before/ gobbling tons of memory System.Diagnostics.Debugger.Break(); // Maybe I should just throw? } #endif var ctxVars = new List <PSVariable> { new PSVariable("_", obj), new PSVariable("PSItem", obj) }; var results = script.InvokeWithContext(null, ctxVars); #if DEBUG sm_renderScriptCallDepth--; #endif string val = null; if (results?.Count > 0) { val = ObjectsToMarkedUpString(results, "{0}", // <-- IMPORTANT: this prevents infinite recursion via Format-AltSingleLine null, false, 4).ToString(); } // TODO: What to do if it spans more than a line? Just truncate? Issue a // warning? Add "..."? Also, consider that the view definition might have been // generated. if (null == val) { return(String.Empty); } // Q. Why might an alleged single-line view generate multiple lines? // // A. Could be buggy. Could be a generated view, and somebody's ToString() // generates multiple lines. In short: it's not necessarily "weird", or // unusual. // // Q. Why would we want to allow multiple lines? Doesn't the name of this // class / method say "format SINGLE LINE"? // // A. Sometimes multi-line views can not only be accommodated, they are // desirable, such as for compatibility with the built-in Format-List // command. if (allowMultipleLines) { return(val); } int idx = CaStringUtil.ApparentIndexOf(val, '\n'); if (idx < 0) { return(val); } return(CaStringUtil.Truncate(val, idx)); } // end FormatSingleLineDirect
} // end property AutoSizeColumns internal void CalculateWidthsAndAlignments(int bufferWidth, PSObject exampleObj) { if (bufferWidth <= 0) { throw new ArgumentOutOfRangeException("bufferWidth"); } if (m_lastUsedBufferWidth == bufferWidth) { return; } int availableWidth = bufferWidth - AccountedWidth - 1; // -1 for newline which takes a column if (availableWidth < (4 * AutoSizeColumns.Count)) { // TODO: proper error. Or... what? throw new ArgumentException("View is too wide."); } m_lastUsedBufferWidth = bufferWidth; if (AutoSizeColumns.Count > 0) { int totalSeparatorWidth = Columns.Count - 1; availableWidth -= totalSeparatorWidth; // Note that availableWidth (and therefore perCol) could be negative. int perCol = availableWidth / AutoSizeColumns.Count; int remainder = availableWidth - (perCol * AutoSizeColumns.Count); foreach (var c in AutoSizeColumns) { int fieldWidth = 0; // TODO: Maybe it would be better to just get the values for the first // line of the table and use that... if (c is PropertyColumn) { // This returns 0 if it doesn't know. try { fieldWidth = GetWidthForProperty(exampleObj, c.Label); } catch (RuntimeException rte) { LogManager.Trace("Cannot attempt to determine width of property {0} on object of type {1}: {2}", c.Label, Util.GetGenericTypeName(exampleObj.BaseObject), Util.GetExceptionMessages(rte)); } if (0 == fieldWidth) { fieldWidth = perCol; if (remainder > 0) { remainder--; fieldWidth++; } } } else { fieldWidth = perCol; if (remainder > 0) { remainder--; fieldWidth++; } } c.CalculatedWidth = Math.Max(CaStringUtil.Length(c.Label), fieldWidth); } } // end if( we have auto-size columns ) for (int colIdx = 0; colIdx < Columns.Count; colIdx++) { var c = Columns[colIdx]; if (ColumnAlignment.Default == c.Alignment) { if (0 == colIdx) { c.CalculatedAlignment = ColumnAlignment.Right; } else if ((Columns.Count - 1) == colIdx) { c.CalculatedAlignment = ColumnAlignment.Left; } else { c.CalculatedAlignment = ColumnAlignment.Center; } } } } // end CalculateWidthsAndAlignments()