Team Ai
Datasetpublic

MegaBites-AI/Windows-powershell

sourceHugging Facemitupdated 6mo agoView on Hugging Face
0likes372downloads
BaseOutputtingCommand.cs1396 linesDownload Raw Back to common
1// Copyright (c) Microsoft Corporation.2// Licensed under the MIT License.3 4using System;5using System.Collections.Generic;6using System.Management.Automation;7using System.Management.Automation.Internal;8 9namespace Microsoft.PowerShell.Commands.Internal.Format10{11    /// <summary>12    /// OutCommand base implementation13    /// it manages the formatting protocol and it writes to a generic14    /// screen host.15    /// </summary>16    internal class OutCommandInner : ImplementationCommandBase17    {18        #region tracer19        [TraceSource("format_out_OutCommandInner", "OutCommandInner")]20        internal static readonly PSTraceSource tracer = PSTraceSource.GetTracer("format_out_OutCommandInner", "OutCommandInner");21        #endregion tracer22 23        internal override void BeginProcessing()24        {25            base.BeginProcessing();26 27            _formatObjectDeserializer = new FormatObjectDeserializer(this.TerminatingErrorContext);28 29            // hook up the event handlers for the context manager object30            _ctxManager.contextCreation = new FormatMessagesContextManager.FormatContextCreationCallback(this.CreateOutputContext);31            _ctxManager.fs = new FormatMessagesContextManager.FormatStartCallback(this.ProcessFormatStart);32            _ctxManager.fe = new FormatMessagesContextManager.FormatEndCallback(this.ProcessFormatEnd);33            _ctxManager.gs = new FormatMessagesContextManager.GroupStartCallback(this.ProcessGroupStart);34            _ctxManager.ge = new FormatMessagesContextManager.GroupEndCallback(this.ProcessGroupEnd);35            _ctxManager.payload = new FormatMessagesContextManager.PayloadCallback(this.ProcessPayload);36        }37 38        /// <summary>39        /// Execution entry point override40        /// we assume that a LineOutput interface instance already has been acquired41        ///42        /// IMPORTANT: it assumes the presence of a pre-processing formatting command.43        /// </summary>44        internal override void ProcessRecord()45        {46            PSObject so = this.ReadObject();47 48            if (so == null || so == AutomationNull.Value)49                return;50 51            // try to process the object52            if (ProcessObject(so))53                return;54 55            // send to the formatter for preprocessing56            Array results = ApplyFormatting(so);57 58            if (results != null)59            {60                foreach (object r in results)61                {62                    PSObject obj = PSObjectHelper.AsPSObject(r);63 64                    obj.IsHelpObject = so.IsHelpObject;65 66                    ProcessObject(obj);67                }68            }69        }70 71        internal override void EndProcessing()72        {73            base.EndProcessing();74            if (_command != null)75            {76                // shut down the command processor, if we ever used it77                Array results = _command.ShutDown();78 79                if (results != null)80                {81                    foreach (object o in results)82                    {83                        ProcessObject(PSObjectHelper.AsPSObject(o));84                    }85                }86            }87 88            if (this.LineOutput.RequiresBuffering)89            {90                // we need to notify the interface implementor that91                // we are about to do the playback92                LineOutput.DoPlayBackCall playBackCall = new LineOutput.DoPlayBackCall(this.DrainCache);93 94                this.LineOutput.ExecuteBufferPlayBack(playBackCall);95            }96            else97            {98                // we drain the cache ourselves99                DrainCache();100            }101        }102 103        private void DrainCache()104        {105            if (_cache != null)106            {107                // drain the cache, since we are shutting down108                List<PacketInfoData> unprocessedObjects = _cache.Drain();109 110                if (unprocessedObjects != null)111                {112                    foreach (object obj in unprocessedObjects)113                    {114                        _ctxManager.Process(obj);115                    }116                }117            }118        }119 120        private bool ProcessObject(PSObject so)121        {122            object o = _formatObjectDeserializer.Deserialize(so);123 124            // Console.WriteLine("OutCommandInner.Execute() retrieved object {0}, of type {1}", o.ToString(), o.GetType());125            if (NeedsPreprocessing(o))126            {127                return false;128            }129 130            // instantiate the cache if not done yet131            _cache ??= new FormattedObjectsCache(this.LineOutput.RequiresBuffering);132 133            // no need for formatting, just process the object134            if (o is FormatStartData formatStart)135            {136                // get autosize flag from object137                // turn on group caching138                if (formatStart.autosizeInfo != null)139                {140                    FormattedObjectsCache.ProcessCachedGroupNotification callBack = new FormattedObjectsCache.ProcessCachedGroupNotification(ProcessCachedGroup);141                    _cache.EnableGroupCaching(callBack, formatStart.autosizeInfo.objectCount);142                }143                else144                {145                    // If the format info doesn't define column widths, then auto-size based on the first ten elements146                    if ((formatStart.shapeInfo is TableHeaderInfo headerInfo) &&147                        (headerInfo.tableColumnInfoList.Count > 0) &&148                        (headerInfo.tableColumnInfoList[0].width == 0))149                    {150                        FormattedObjectsCache.ProcessCachedGroupNotification callBack = new FormattedObjectsCache.ProcessCachedGroupNotification(ProcessCachedGroup);151                        _cache.EnableGroupCaching(callBack, TimeSpan.FromMilliseconds(300));152                    }153                }154            }155 156            // Console.WriteLine("OutCommandInner.Execute() calling ctxManager.Process({0})",o.ToString());157            List<PacketInfoData> info = _cache.Add((PacketInfoData)o);158 159            if (info != null)160            {161                for (int k = 0; k < info.Count; k++)162                    _ctxManager.Process(info[k]);163            }164 165            return true;166        }167 168        /// <summary>169        /// Helper to return what shape we have to use to format the output.170        /// </summary>171        private FormatShape ActiveFormattingShape172        {173            get174            {175                // we assume that the format context176                // contains the information177                const FormatShape shape = FormatShape.Table; // default178                FormatOutputContext foc = this.FormatContext;179 180                if (foc == null || foc.Data.shapeInfo == null)181                    return shape;182 183                if (foc.Data.shapeInfo is TableHeaderInfo)184                    return FormatShape.Table;185 186                if (foc.Data.shapeInfo is ListViewHeaderInfo)187                    return FormatShape.List;188 189                if (foc.Data.shapeInfo is WideViewHeaderInfo)190                    return FormatShape.Wide;191 192                if (foc.Data.shapeInfo is ComplexViewHeaderInfo)193                    return FormatShape.Complex;194 195                return shape;196            }197        }198 199        protected override void InternalDispose()200        {201            base.InternalDispose();202            if (_command != null)203            {204                _command.Dispose();205                _command = null;206            }207        }208 209        /// <summary>210        /// Enum describing the state for the output finite state machine.211        /// </summary>212        private enum FormattingState213        {214            /// <summary>215            /// We are in the clear state: no formatting in process.216            /// </summary>217            Reset,218 219            /// <summary>220            /// We received a Format Start message, but we are not inside a group.221            /// </summary>222            Formatting,223 224            /// <summary>225            /// We are inside a group because we received a Group Start.226            /// </summary>227            InsideGroup228        }229 230        /// <summary>231        /// Toggle to signal if we are in a formatting sequence.232        /// </summary>233        private FormattingState _currentFormattingState = FormattingState.Reset;234 235        /// <summary>236        /// Instance of a command wrapper to execute the237        /// default formatter when needed.238        /// </summary>239        private CommandWrapper _command;240 241        /// <summary>242        /// Enumeration to drive the preprocessing stage.243        /// </summary>244        private enum PreprocessingState { raw, processed, error }245 246        private const int DefaultConsoleWidth = 120;247        private const int DefaultConsoleHeight = int.MaxValue;248        internal const int StackAllocThreshold = 120;249 250        /// <summary>251        /// Test if an object coming from the pipeline needs to be252        /// preprocessed by the default formatter.253        /// </summary>254        /// <param name="o">Object to examine for formatting.</param>255        /// <returns>Whether the object needs to be shunted to preprocessing.</returns>256        private bool NeedsPreprocessing(object o)257        {258            if (o is FormatEntryData fed)259            {260                // we got an already pre-processed object261                if (!fed.outOfBand)262                {263                    // we allow out of band data in any state264                    ValidateCurrentFormattingState(FormattingState.InsideGroup, o);265                }266 267                return false;268            }269            else if (o is FormatStartData)270            {271                // when encountering FormatStartDate out of sequence,272                // pretend that the previous formatting directives were properly closed273                if (_currentFormattingState == FormattingState.InsideGroup)274                {275                    this.EndProcessing();276                    this.BeginProcessing();277                }278 279                // we got a Fs message, we enter a sequence280                ValidateCurrentFormattingState(FormattingState.Reset, o);281                _currentFormattingState = FormattingState.Formatting;282 283                return false;284            }285            else if (o is FormatEndData)286            {287                // we got a Fe message, we exit a sequence288                ValidateCurrentFormattingState(FormattingState.Formatting, o);289                _currentFormattingState = FormattingState.Reset;290 291                return false;292            }293            else if (o is GroupStartData)294            {295                ValidateCurrentFormattingState(FormattingState.Formatting, o);296                _currentFormattingState = FormattingState.InsideGroup;297 298                return false;299            }300            else if (o is GroupEndData)301            {302                ValidateCurrentFormattingState(FormattingState.InsideGroup, o);303                _currentFormattingState = FormattingState.Formatting;304 305                return false;306            }307 308            // this is a raw object309            return true;310        }311 312        private void ValidateCurrentFormattingState(FormattingState expectedFormattingState, object obj)313        {314            // check if we are in the expected formatting state315            if (_currentFormattingState != expectedFormattingState)316            {317                // we are not in the expected state, some message is out of sequence,318                // need to abort the command319 320                string violatingCommand = "format-*";321                if (obj is StartData sdObj)322                {323                    if (sdObj.shapeInfo is WideViewHeaderInfo)324                    {325                        violatingCommand = "format-wide";326                    }327                    else if (sdObj.shapeInfo is TableHeaderInfo)328                    {329                        violatingCommand = "format-table";330                    }331                    else if (sdObj.shapeInfo is ListViewHeaderInfo)332                    {333                        violatingCommand = "format-list";334                    }335                    else if (sdObj.shapeInfo is ComplexViewHeaderInfo)336                    {337                        violatingCommand = "format-complex";338                    }339                }340 341                string msg = StringUtil.Format(FormatAndOut_out_xxx.OutLineOutput_OutOfSequencePacket,342                    obj.GetType().FullName, violatingCommand);343 344                ErrorRecord errorRecord = new ErrorRecord(345                                                new InvalidOperationException(),346                                                "ConsoleLineOutputOutOfSequencePacket",347                                                ErrorCategory.InvalidData,348                                                null);349 350                errorRecord.ErrorDetails = new ErrorDetails(msg);351                this.TerminatingErrorContext.ThrowTerminatingError(errorRecord);352            }353        }354 355        /// <summary>356        /// Shunt object to the formatting pipeline for preprocessing.357        /// </summary>358        /// <param name="o">Object to be preprocessed.</param>359        /// <returns>Array of objects returned by the preprocessing step.</returns>360        private Array ApplyFormatting(object o)361        {362            if (_command == null)363            {364                _command = new CommandWrapper();365                _command.Initialize(this.OuterCmdlet().Context, "format-default", typeof(FormatDefaultCommand));366            }367 368            return _command.Process(o);369        }370 371        /// <summary>372        /// Class factory for output context.373        /// </summary>374        /// <param name="parentContext">Parent context in the stack.</param>375        /// <param name="formatInfoData">Fromat info data received from the pipeline.</param>376        /// <returns></returns>377        private FormatMessagesContextManager.OutputContext CreateOutputContext(378                                        FormatMessagesContextManager.OutputContext parentContext,379                                        FormatInfoData formatInfoData)380        {381            // initialize the format context382            if (formatInfoData is FormatStartData formatStartData)383            {384                FormatOutputContext foc = new FormatOutputContext(parentContext, formatStartData);385 386                return foc;387            }388 389            // we are starting a group, initialize the group context390            if (formatInfoData is GroupStartData gsd)391            {392                GroupOutputContext goc = null;393 394                switch (ActiveFormattingShape)395                {396                    case FormatShape.Table:397                        {398                            goc = new TableOutputContext(this, parentContext, gsd);399                            break;400                        }401 402                    case FormatShape.List:403                        {404                            goc = new ListOutputContext(this, parentContext, gsd);405                            break;406                        }407 408                    case FormatShape.Wide:409                        {410                            goc = new WideOutputContext(this, parentContext, gsd);411                            break;412                        }413 414                    case FormatShape.Complex:415                        {416                            goc = new ComplexOutputContext(this, parentContext, gsd);417                            break;418                        }419 420                    default:421                        {422                            Diagnostics.Assert(false, "Invalid shape. This should never happen");423                        }424 425                        break;426                }427 428                goc.Initialize();429                return goc;430            }431 432            return null;433        }434 435        /// <summary>436        /// Callback for Fs processing.437        /// </summary>438        /// <param name="c">The context containing the Fs entry.</param>439        private void ProcessFormatStart(FormatMessagesContextManager.OutputContext c)440        {441            // we just add an empty line to the display442            this.LineOutput.WriteLine(string.Empty);443        }444 445        /// <summary>446        /// Callback for Fe processing.447        /// </summary>448        /// <param name="fe">Fe notification message.</param>449        /// <param name="c">Current context, with Fs in it.</param>450        private void ProcessFormatEnd(FormatEndData fe, FormatMessagesContextManager.OutputContext c)451        {452            if (c is FormatOutputContext foContext453                && foContext.Data.shapeInfo is ListViewHeaderInfo)454            {455                // Skip writing out a new line for List view, because we already wrote out456                // an extra new line after displaying the last list entry.457                return;458            }459 460            // We just add an empty line to the display.461            LineOutput.WriteLine(string.Empty);462        }463 464        /// <summary>465        /// Callback for Gs processing.466        /// </summary>467        /// <param name="c">The context containing the Gs entry.</param>468        private void ProcessGroupStart(FormatMessagesContextManager.OutputContext c)469        {470            // Console.WriteLine("ProcessGroupStart");471            GroupOutputContext goc = (GroupOutputContext)c;472 473            if (goc.Data.groupingEntry != null)474            {475                ComplexWriter writer = new ComplexWriter();476                writer.Initialize(_lo, _lo.ColumnNumber);477                writer.WriteObject(goc.Data.groupingEntry.formatValueList);478                _lo.WriteLine(string.Empty);479            }480 481            goc.GroupStart();482        }483 484        /// <summary>485        /// Callback for Ge processing.486        /// </summary>487        /// <param name="ge">Ge notification message.</param>488        /// <param name="c">Current context, with Gs in it.</param>489        private void ProcessGroupEnd(GroupEndData ge, FormatMessagesContextManager.OutputContext c)490        {491            // Console.WriteLine("ProcessGroupEnd");492            GroupOutputContext goc = (GroupOutputContext)c;493 494            goc.GroupEnd();495        }496 497        /// <summary>498        /// Process the current payload object.499        /// </summary>500        /// <param name="fed">FormatEntryData to process.</param>501        /// <param name="c">Currently active context.</param>502        private void ProcessPayload(FormatEntryData fed, FormatMessagesContextManager.OutputContext c)503        {504            // we assume FormatEntryData as a standard wrapper505            if (fed == null)506            {507                PSTraceSource.NewArgumentNullException(nameof(fed));508            }509 510            if (fed.formatEntryInfo == null)511            {512                PSTraceSource.NewArgumentNullException("fed.formatEntryInfo");513            }514 515            WriteStreamType oldWSState = _lo.WriteStream;516            try517            {518                _lo.WriteStream = fed.writeStream;519 520                if (c == null)521                {522                    ProcessOutOfBandPayload(fed);523                }524                else525                {526                    GroupOutputContext goc = (GroupOutputContext)c;527 528                    goc.ProcessPayload(fed);529                }530            }531            finally532            {533                _lo.WriteStream = oldWSState;534            }535        }536 537        private void ProcessOutOfBandPayload(FormatEntryData fed)538        {539            // try if it is raw text540            if (fed.formatEntryInfo is RawTextFormatEntry rte)541            {542                if (fed.isHelpObject)543                {544                    ComplexWriter complexWriter = new ComplexWriter();545 546                    complexWriter.Initialize(_lo, _lo.ColumnNumber);547                    complexWriter.WriteString(rte.text);548                }549                else550                {551                    // Write out raw text without any changes to it.552                    _lo.WriteRawText(rte.text);553                }554 555                return;556            }557 558            // try if it is a complex entry559            if (fed.formatEntryInfo is ComplexViewEntry cve && cve.formatValueList != null)560            {561                ComplexWriter complexWriter = new ComplexWriter();562 563                complexWriter.Initialize(_lo, int.MaxValue);564                complexWriter.WriteObject(cve.formatValueList);565 566                return;567            }568            // try if it is a list view569            if (fed.formatEntryInfo is ListViewEntry lve && lve.listViewFieldList != null)570            {571                ListWriter listWriter = new ListWriter();572 573                _lo.WriteLine(string.Empty);574 575                string[] properties = ListOutputContext.GetProperties(lve);576                listWriter.Initialize(properties, _lo.ColumnNumber, _lo.DisplayCells);577                string[] values = ListOutputContext.GetValues(lve);578                listWriter.WriteProperties(values, _lo);579 580                _lo.WriteLine(string.Empty);581 582                return;583            }584        }585 586        /// <summary>587        /// The screen host associated with this outputter.588        /// </summary>589        private LineOutput _lo = null;590 591        internal LineOutput LineOutput592        {593            get { return _lo; }594 595            set { _lo = value; }596        }597 598        private ShapeInfo ShapeInfoOnFormatContext599        {600            get601            {602                FormatOutputContext foc = this.FormatContext;603 604                if (foc == null)605                    return null;606 607                return foc.Data.shapeInfo;608            }609        }610 611        /// <summary>612        /// Retrieve the active FormatOutputContext on the stack613        /// by walking up to the top of the stack.614        /// </summary>615        private FormatOutputContext FormatContext616        {617            get618            {619                for (FormatMessagesContextManager.OutputContext oc = _ctxManager.ActiveOutputContext; oc != null; oc = oc.ParentContext)620                {621                    if (oc is FormatOutputContext foc)622                        return foc;623                }624 625                return null;626            }627        }628 629        /// <summary>630        /// Context manager instance to guide the message traversal.631        /// </summary>632        private readonly FormatMessagesContextManager _ctxManager = new FormatMessagesContextManager();633 634        private FormattedObjectsCache _cache = null;635 636        /// <summary>637        /// Handler for processing the caching notification and responsible for638        /// setting the value of the formatting hint.639        /// </summary>640        /// <param name="formatStartData"></param>641        /// <param name="objects"></param>642        private void ProcessCachedGroup(FormatStartData formatStartData, List<PacketInfoData> objects)643        {644            _formattingHint = null;645 646            if (formatStartData.shapeInfo is TableHeaderInfo thi)647            {648                ProcessCachedGroupOnTable(thi, objects);649                return;650            }651 652            if (formatStartData.shapeInfo is WideViewHeaderInfo wvhi)653            {654                ProcessCachedGroupOnWide(wvhi, objects);655                return;656            }657        }658 659        private void ProcessCachedGroupOnTable(TableHeaderInfo thi, List<PacketInfoData> objects)660        {661            if (thi.tableColumnInfoList.Count == 0)662                return;663 664            int[] widths = new int[thi.tableColumnInfoList.Count];665 666            for (int k = 0; k < thi.tableColumnInfoList.Count; k++)667            {668                string label = thi.tableColumnInfoList[k].label;669 670                if (string.IsNullOrEmpty(label))671                    label = thi.tableColumnInfoList[k].propertyName;672 673                if (string.IsNullOrEmpty(label))674                    widths[k] = 0;675                else676                    widths[k] = _lo.DisplayCells.Length(label);677            }678 679            int cellCount; // scratch variable680            foreach (PacketInfoData o in objects)681            {682                if (o is FormatEntryData fed)683                {684                    TableRowEntry tre = fed.formatEntryInfo as TableRowEntry;685                    int kk = 0;686 687                    foreach (FormatPropertyField fpf in tre.formatPropertyFieldList)688                    {689                        cellCount = _lo.DisplayCells.Length(fpf.propertyValue);690                        if (widths[kk] < cellCount)691                            widths[kk] = cellCount;692 693                        kk++;694                    }695                }696            }697 698            TableFormattingHint hint = new TableFormattingHint();699 700            hint.columnWidths = widths;701            _formattingHint = hint;702        }703 704        private void ProcessCachedGroupOnWide(WideViewHeaderInfo wvhi, List<PacketInfoData> objects)705        {706            if (wvhi.columns != 0)707            {708                // columns forced on the client709                return;710            }711 712            int maxLen = 0;713            int cellCount; // scratch variable714 715            foreach (PacketInfoData o in objects)716            {717                if (o is FormatEntryData fed)718                {719                    WideViewEntry wve = fed.formatEntryInfo as WideViewEntry;720                    FormatPropertyField fpf = wve.formatPropertyField as FormatPropertyField;721 722                    if (!string.IsNullOrEmpty(fpf.propertyValue))723                    {724                        cellCount = _lo.DisplayCells.Length(fpf.propertyValue);725                        if (cellCount > maxLen)726                            maxLen = cellCount;727                    }728                }729            }730 731            WideFormattingHint hint = new WideFormattingHint();732 733            hint.maxWidth = maxLen;734            _formattingHint = hint;735        }736 737        /// <summary>738        /// Tables and Wides need to use spaces for padding to maintain table look even if console window is resized.739        /// For all other output, we use int.MaxValue if the user didn't explicitly specify a width.740        /// If we detect that int.MaxValue is used, first we try to get the current console window width.741        /// However, if we can't read that (for example, implicit remoting has no console window), we default742        /// to something reasonable: 120 columns.743        /// </summary>744        private static int GetConsoleWindowWidth(int columnNumber)745        {746            if (InternalTestHooks.SetConsoleWidthToZero)747            {748                return DefaultConsoleWidth;749            }750 751            if (columnNumber == int.MaxValue)752            {753                try754                {755                    // if Console width is set to 0, the default width is returned so that the output string is not null.756                    // This can happen in environments where TERM is not set.757                    return (Console.WindowWidth != 0) ? Console.WindowWidth : DefaultConsoleWidth;758                }759                catch760                {761                    return DefaultConsoleWidth;762                }763            }764 765            return columnNumber;766        }767 768        /// <summary>769        /// Return the console height.null  If not available (like when remoting), treat as Int.MaxValue.770        /// </summary>771        private static int GetConsoleWindowHeight(int rowNumber)772        {773            if (InternalTestHooks.SetConsoleHeightToZero)774            {775                return DefaultConsoleHeight;776            }777 778            if (rowNumber <= 0)779            {780                try781                {782                    // if Console height is set to 0, the default height is returned.783                    // This can happen in environments where TERM is not set.784                    return (Console.WindowHeight > 0) ? Console.WindowHeight : DefaultConsoleHeight;785                }786                catch787                {788                    return DefaultConsoleHeight;789                }790            }791 792            return rowNumber;793        }794 795        /// <summary>796        /// Base class for all the formatting hints.797        /// </summary>798        private abstract class FormattingHint799        {800        }801 802        /// <summary>803        /// Hint for format-table.804        /// </summary>805        private sealed class TableFormattingHint : FormattingHint806        {807            internal int[] columnWidths = null;808        }809 810        /// <summary>811        /// Hint for format-wide.812        /// </summary>813        private sealed class WideFormattingHint : FormattingHint814        {815            internal int maxWidth = 0;816        }817 818        /// <summary>819        /// Variable holding the autosize hint (set by the caching code and reset by the hint consumer.820        /// </summary>821        private FormattingHint _formattingHint = null;822 823        /// <summary>824        /// Helper for consuming the formatting hint.825        /// </summary>826        /// <returns></returns>827        private FormattingHint RetrieveFormattingHint()828        {829            FormattingHint fh = _formattingHint;830            _formattingHint = null;831            return fh;832        }833 834        private FormatObjectDeserializer _formatObjectDeserializer;835 836        /// <summary>837        /// Context for the outer scope of the format sequence.838        /// </summary>839        private sealed class FormatOutputContext : FormatMessagesContextManager.OutputContext840        {841            /// <summary>842            /// Construct a context to push on the stack.843            /// </summary>844            /// <param name="parentContext">Parent context in the stack.</param>845            /// <param name="formatData">Format data to put in the context.</param>846            internal FormatOutputContext(FormatMessagesContextManager.OutputContext parentContext, FormatStartData formatData)847                : base(parentContext)848            {849                Data = formatData;850            }851 852            /// <summary>853            /// Retrieve the format data in the context.854            /// </summary>855            internal FormatStartData Data { get; } = null;856        }857 858        /// <summary>859        /// Context for the currently active group.860        /// </summary>861        private abstract class GroupOutputContext : FormatMessagesContextManager.OutputContext862        {863            /// <summary>864            /// Construct a context to push on the stack.865            /// </summary>866            internal GroupOutputContext(OutCommandInner cmd,867                                    FormatMessagesContextManager.OutputContext parentContext,868                                    GroupStartData formatData)869                : base(parentContext)870            {871                InnerCommand = cmd;872                Data = formatData;873            }874 875            /// <summary>876            /// Called at creation time, overrides will initialize here, e.g.877            /// column widths, etc.878            /// </summary>879            internal virtual void Initialize() { }880 881            /// <summary>882            /// Called when a group of data is started, overridden will do883            /// things such as headers, etc...884            /// </summary>885            internal virtual void GroupStart() { }886 887            /// <summary>888            /// Called when the end of a group is reached, overrides will do889            /// things such as group footers.890            /// </summary>891            internal virtual void GroupEnd() { }892 893            /// <summary>894            /// Called when there is an entry to process, overrides will do895            /// things such as writing a row in a table.896            /// </summary>897            /// <param name="fed">FormatEntryData to process.</param>898            internal virtual void ProcessPayload(FormatEntryData fed) { }899 900            /// <summary>901            /// Retrieve the format data in the context.902            /// </summary>903            internal GroupStartData Data { get; } = null;904 905            protected OutCommandInner InnerCommand { get; }906        }907 908        private class TableOutputContextBase : GroupOutputContext909        {910            /// <summary>911            /// Construct a context to push on the stack.912            /// </summary>913            /// <param name="cmd">Reference to the OutCommandInner instance who owns this instance.</param>914            /// <param name="parentContext">Parent context in the stack.</param>915            /// <param name="formatData">Format data to put in the context.</param>916            internal TableOutputContextBase(OutCommandInner cmd,917                FormatMessagesContextManager.OutputContext parentContext,918                GroupStartData formatData)919                : base(cmd, parentContext, formatData)920            {921            }922 923            /// <summary>924            /// Get the table writer for this context.925            /// </summary>926            protected TableWriter Writer { get { return _tableWriter; } }927 928            /// <summary>929            /// Helper class to properly write a table using text output.930            /// </summary>931            private readonly TableWriter _tableWriter = new TableWriter();932        }933 934        private sealed class TableOutputContext : TableOutputContextBase935        {936            private int _rowCount = 0;937            private int _consoleHeight = -1;938            private int _consoleWidth = -1;939 940            private const int WhitespaceAndPagerLineCount = 2;941 942            private readonly bool _repeatHeader = false;943 944            /// <summary>945            /// Construct a context to push on the stack.946            /// </summary>947            /// <param name="cmd">Reference to the OutCommandInner instance who owns this instance.</param>948            /// <param name="parentContext">Parent context in the stack.</param>949            /// <param name="formatData">Format data to put in the context.</param>950            internal TableOutputContext(OutCommandInner cmd,951                FormatMessagesContextManager.OutputContext parentContext,952                GroupStartData formatData)953                : base(cmd, parentContext, formatData)954            {955                if (parentContext is FormatOutputContext foc)956                {957                    if (foc.Data.shapeInfo is TableHeaderInfo thi)958                    {959                        _repeatHeader = thi.repeatHeader;960                    }961                }962            }963 964            /// <summary>965            /// Initialize column widths.966            /// </summary>967            internal override void Initialize()968            {969                int[] columnWidthsHint = null;970                // We expect that console width is less than 120.971 972                if (this.InnerCommand.RetrieveFormattingHint() is TableFormattingHint tableHint)973                {974                    columnWidthsHint = tableHint.columnWidths;975                }976 977                _consoleHeight = GetConsoleWindowHeight(this.InnerCommand._lo.RowNumber);978                _consoleWidth = GetConsoleWindowWidth(this.InnerCommand._lo.ColumnNumber);979 980                int columns = this.CurrentTableHeaderInfo.tableColumnInfoList.Count;981                if (columns == 0)982                {983                    return;984                }985 986                // create arrays for widths and alignment987                Span<int> columnWidths = columns <= StackAllocThreshold ? stackalloc int[columns] : new int[columns];988                Span<int> alignment = columns <= StackAllocThreshold ? stackalloc int[columns] : new int[columns];989                Span<bool> headerMatchesProperty = columns <= StackAllocThreshold ? stackalloc bool[columns] : new bool[columns];990 991                int k = 0;992                foreach (TableColumnInfo tci in this.CurrentTableHeaderInfo.tableColumnInfoList)993                {994                    columnWidths[k] = (columnWidthsHint != null) ? columnWidthsHint[k] : tci.width;995                    alignment[k] = tci.alignment;996                    headerMatchesProperty[k] = tci.HeaderMatchesProperty;997                    k++;998                }999 1000                this.Writer.Initialize(0, _consoleWidth, columnWidths, alignment, headerMatchesProperty, this.CurrentTableHeaderInfo.hideHeader);1001            }1002 1003            /// <summary>1004            /// Write the headers.1005            /// </summary>1006            internal override void GroupStart()1007            {1008                int columns = this.CurrentTableHeaderInfo.tableColumnInfoList.Count;1009 1010                if (columns == 0)1011                {1012                    return;1013                }1014 1015                string[] properties = new string[columns];1016                int k = 0;1017                foreach (TableColumnInfo tci in this.CurrentTableHeaderInfo.tableColumnInfoList)1018                {1019                    properties[k++] = tci.label ?? tci.propertyName;1020                }1021 1022                _rowCount += this.Writer.GenerateHeader(properties, this.InnerCommand._lo);1023            }1024 1025            /// <summary>1026            /// Write a row into the table.1027            /// </summary>1028            /// <param name="fed">FormatEntryData to process.</param>1029            internal override void ProcessPayload(FormatEntryData fed)1030            {1031                int headerColumns = this.CurrentTableHeaderInfo.tableColumnInfoList.Count;1032 1033                if (headerColumns == 0)1034                {1035                    return;1036                }1037 1038                if (_repeatHeader && _rowCount >= _consoleHeight - WhitespaceAndPagerLineCount)1039                {1040                    this.InnerCommand._lo.WriteLine(string.Empty);1041                    _rowCount = this.Writer.GenerateHeader(null, this.InnerCommand._lo);1042                }1043 1044                TableRowEntry tre = fed.formatEntryInfo as TableRowEntry;1045 1046                // need to make sure we have matching counts: the header count will have to prevail1047                string[] values = new string[headerColumns];1048                Span<int> alignment = headerColumns <= StackAllocThreshold ? stackalloc int[headerColumns] : new int[headerColumns];1049 1050                int fieldCount = tre.formatPropertyFieldList.Count;1051 1052                for (int k = 0; k < headerColumns; k++)1053                {1054                    if (k < fieldCount)1055                    {1056                        values[k] = tre.formatPropertyFieldList[k].propertyValue;1057                        alignment[k] = tre.formatPropertyFieldList[k].alignment;1058                    }1059                    else1060                    {1061                        values[k] = string.Empty;1062                        alignment[k] = TextAlignment.Left; // hard coded default1063                    }1064                }1065 1066                this.Writer.GenerateRow(values, this.InnerCommand._lo, tre.multiLine, alignment, InnerCommand._lo.DisplayCells, generatedRows: null);1067                _rowCount++;1068            }1069 1070            private TableHeaderInfo CurrentTableHeaderInfo1071            {1072                get1073                {1074                    return (TableHeaderInfo)this.InnerCommand.ShapeInfoOnFormatContext;1075                }1076            }1077        }1078 1079        private sealed class ListOutputContext : GroupOutputContext1080        {1081            /// <summary>1082            /// Construct a context to push on the stack.1083            /// </summary>1084            /// <param name="cmd">Reference to the OutCommandInner instance who owns this instance.</param>1085            /// <param name="parentContext">Parent context in the stack.</param>1086            /// <param name="formatData">Format data to put in the context.</param>1087            internal ListOutputContext(OutCommandInner cmd,1088                FormatMessagesContextManager.OutputContext parentContext,1089                GroupStartData formatData)1090                : base(cmd, parentContext, formatData)1091            {1092            }1093 1094            /// <summary>1095            /// Initialize column widths.1096            /// </summary>1097            internal override void Initialize()1098            {1099            }1100 1101            private void InternalInitialize(ListViewEntry lve)1102            {1103                _properties = GetProperties(lve);1104                _listWriter.Initialize(_properties, this.InnerCommand._lo.ColumnNumber, InnerCommand._lo.DisplayCells);1105            }1106 1107            internal static string[] GetProperties(ListViewEntry lve)1108            {1109                int count = lve.listViewFieldList.Count;1110 1111                if (count == 0)1112                {1113                    return null;1114                }1115 1116                string[] result = new string[count];1117                for (int index = 0; index < result.Length; ++index)1118                {1119                    ListViewField lvf = lve.listViewFieldList[index];1120                    result[index] = lvf.label ?? lvf.propertyName;1121                }1122 1123                return result;1124            }1125 1126            internal static string[] GetValues(ListViewEntry lve)1127            {1128                int count = lve.listViewFieldList.Count;1129 1130                if (count == 0)1131                {1132                    return null;1133                }1134 1135                string[] result = new string[count];1136                for (int index = 0; index < result.Length; ++index)1137                {1138                    ListViewField lvf = lve.listViewFieldList[index];1139                    result[index] = lvf.formatPropertyField.propertyValue;1140                }1141 1142                return result;1143            }1144 1145            /// <summary>1146            /// Write the headers.1147            /// </summary>1148            internal override void GroupStart()1149            {1150            }1151 1152            /// <summary>1153            /// Write a row into the list.1154            /// </summary>1155            /// <param name="fed">FormatEntryData to process.</param>1156            internal override void ProcessPayload(FormatEntryData fed)1157            {1158                ListViewEntry lve = fed.formatEntryInfo as ListViewEntry;1159                InternalInitialize(lve);1160                string[] values = GetValues(lve);1161                _listWriter.WriteProperties(values, this.InnerCommand._lo);1162                this.InnerCommand._lo.WriteLine(string.Empty);1163            }1164 1165            /// <summary>1166            /// Property list currently active.1167            /// </summary>1168            private string[] _properties = null;1169 1170            /// <summary>1171            /// Writer to do the actual formatting.1172            /// </summary>1173            private readonly ListWriter _listWriter = new ListWriter();1174        }1175 1176        private sealed class WideOutputContext : TableOutputContextBase1177        {1178            /// <summary>1179            /// Construct a context to push on the stack.1180            /// </summary>1181            /// <param name="cmd">Reference to the OutCommandInner instance who owns this instance.</param>1182            /// <param name="parentContext">Parent context in the stack.</param>1183            /// <param name="formatData">Format data to put in the context.</param>1184            internal WideOutputContext(OutCommandInner cmd,1185                FormatMessagesContextManager.OutputContext parentContext,1186                GroupStartData formatData)1187                : base(cmd, parentContext, formatData)1188            {1189            }1190 1191            private StringValuesBuffer _buffer = null;1192 1193            /// <summary>1194            /// Initialize column widths.1195            /// </summary>1196            internal override void Initialize()1197            {1198                // set the hard wider default, to be used if no other info is available1199                int itemsPerRow = 2;1200 

Showing the first 1,200 of 1396 lines. Download the file for the rest.