HandleIncomingProgressRecord(long sourceId, ProgressRecord record)
        {
            Dbg.Assert(record != null, "record should not be null");

            if (_pendingProgress == null)
            {
                Dbg.Assert(_progPane == null, "If there is no data struct, there shouldn't be a pane, either.");

                _pendingProgress = new PendingProgress();
            }

            _pendingProgress.Update(sourceId, record);

            if (_progPane == null)
            {
                // This is the first time we've received a progress record
                // Create a progress pane
                // Set up a update flag
                // Create a timer for updating the flag

                _progPane = new ProgressPane(this);

                if (_progPaneUpdateTimer == null)
                {
                    // Show a progress pane at the first time we've received a progress record
                    progPaneUpdateFlag = 1;

                    // The timer will be auto restarted every 'UpdateTimerThreshold' ms
                    _progPaneUpdateTimer = new Timer(new TimerCallback(ProgressPaneUpdateTimerElapsed), null, UpdateTimerThreshold, UpdateTimerThreshold);
                }
            }

            if (Interlocked.CompareExchange(ref progPaneUpdateFlag, 0, 1) == 1 || record.RecordType == ProgressRecordType.Completed)
            {
                // Update the progress pane only when the timer set up the update flag or WriteProgress is completed.
                // As a result, we do not block WriteProgress and whole script and eliminate unnecessary console locks and updates.
                if (SupportsVirtualTerminal && ExperimentalFeature.IsEnabled(ExperimentalFeature.PSAnsiProgressFeatureName) && PSStyle.Instance.Progress.UseOSCIndicator)
                {
                    int percentComplete = record.PercentComplete;
                    if (percentComplete < 0)
                    {
                        // Write-Progress allows for negative percent complete, but not greater than 100
                        // but OSC sequence is limited from 0 to 100.
                        percentComplete = 0;
                    }

                    // OSC sequence to turn on progress indicator
                    // https://github.com/microsoft/terminal/issues/6700
                    Console.Write($"\x1b]9;4;1;{percentComplete}\x1b\\");
                }

                // If VT is not supported, we change ProgressView to classic
                if (!SupportsVirtualTerminal && ExperimentalFeature.IsEnabled(ExperimentalFeature.PSAnsiProgressFeatureName))
                {
                    PSStyle.Instance.Progress.View = ProgressView.Classic;
                }

                _progPane.Show(_pendingProgress);
            }
        }
Exemplo n.º 2
0
        internal int GenerateHeader(string[] values, LineOutput lo)
        {
            if (_disabled || _hideHeader)
            {
                return(0);
            }
            else if (_header != null)
            {
                foreach (string line in _header)
                {
                    if (ExperimentalFeature.IsEnabled("PSAnsiRendering"))
                    {
                        lo.WriteLine(PSStyle.Instance.Formatting.TableHeader + line + PSStyle.Instance.Reset);
                    }
                    else
                    {
                        lo.WriteLine(line);
                    }
                }

                return(_header.Count);
            }

            _header = new List <string>();

            // generate the row with the header labels
            GenerateRow(values, lo, true, null, lo.DisplayCells, _header, isHeader: true);

            // generate an array of "--" as header markers below
            // the column header labels
            string[] breakLine = new string[values.Length];
            for (int k = 0; k < breakLine.Length; k++)
            {
                // the column can be hidden
                if (_si.columnInfo[k].width <= 0)
                {
                    breakLine[k] = string.Empty;
                    continue;
                }
                // the title can be larger than the width
                int count = _si.columnInfo[k].width;
                if (!string.IsNullOrEmpty(values[k]))
                {
                    int labelDisplayCells = lo.DisplayCells.Length(values[k]);
                    if (labelDisplayCells < count)
                    {
                        count = labelDisplayCells;
                    }
                }
                // NOTE: we can do this because "-" is a single cell character
                // on all devices. If changed to some other character, this assumption
                // would be invalidated
                breakLine[k] = StringUtil.DashPadding(count);
            }

            GenerateRow(breakLine, lo, false, null, lo.DisplayCells, _header, isHeader: true);
            return(_header.Count);
        }
Exemplo n.º 3
0
        private string GenerateRow(string[] values, ReadOnlySpan <int> alignment, DisplayCells dc)
        {
            StringBuilder sb = new StringBuilder();

            bool addPadding = true;

            for (int k = 0; k < _si.columnInfo.Length; k++)
            {
                // don't pad the last column
                if (k == _si.columnInfo.Length - 1)
                {
                    addPadding = false;
                }

                if (_si.columnInfo[k].width <= 0)
                {
                    // skip columns that are not at least a single character wide
                    continue;
                }

                // NOTE: the following padding operations assume that we
                // pad with a blank (or any character that ALWAYS maps to a single screen cell
                if (k > 0)
                {
                    sb.Append(StringUtil.Padding(ScreenInfo.separatorCharacterCount));
                }
                else
                {
                    // add indentation padding if needed
                    if (_startColumn > 0)
                    {
                        sb.Append(StringUtil.Padding(_startColumn));
                    }
                }

                sb.Append(GenerateRowField(values[k], _si.columnInfo[k].width, alignment[k], dc, addPadding));
                if (values[k].Contains(ESC))
                {
                    // Reset the console output if the content of this column contains ESC
                    if (ExperimentalFeature.IsEnabled("PSAnsiRendering"))
                    {
                        // Remove definition of `ResetConsoleVt10Code` when PSAnsiRendering is not experimental
                        sb.Append(PSStyle.Instance.Reset);
                    }
                    else
                    {
                        sb.Append(ResetConsoleVt100Code);
                    }
                }
            }

            return(sb.ToString());
        }
Exemplo n.º 4
0
        protected override void EndProcessing()
        {
            string message = $"Hello World {Name}.";

            if (ExperimentalFeature.IsEnabled("ExpTest.FeatureOne"))
            {
                if (SwitchOne.IsPresent)
                {
                    message += "-SwitchOne is on.";
                }
                if (SwitchTwo.IsPresent)
                {
                    message += "-SwitchTwo is on.";
                }
            }
            WriteObject(message);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Internal helper to split a line that is too long to fit and pad it to the left
        /// with a given string.
        /// </summary>
        /// <param name="prependString">String to add to the left.</param>
        /// <param name="line">Line to print.</param>
        /// <param name="lo">LineOuput to write to.</param>
        private void WriteSingleLineHelper(string prependString, string line, LineOutput lo)
        {
            if (line == null)
            {
                line = string.Empty;
            }

            // compute the width of the field for the value string (in screen cells)
            int fieldCellCount = _columnWidth - _propertyLabelsDisplayLength;

            // split the lines
            StringCollection sc = StringManipulationHelper.GenerateLines(lo.DisplayCells, line, fieldCellCount, fieldCellCount);

            // padding to use in the lines after the first
            string padding = StringUtil.Padding(_propertyLabelsDisplayLength);

            // display the string collection
            for (int k = 0; k < sc.Count; k++)
            {
                if (k == 0)
                {
                    if (ExperimentalFeature.IsEnabled("PSAnsiRendering"))
                    {
                        lo.WriteLine(PSStyle.Instance.Formatting.FormatAccent + prependString + PSStyle.Instance.Reset + sc[k]);
                    }
                    else
                    {
                        lo.WriteLine(prependString + sc[k]);
                    }
                }
                else
                {
                    if (ExperimentalFeature.IsEnabled("PSAnsiRendering"))
                    {
                        lo.WriteLine(padding + PSStyle.Instance.Formatting.FormatAccent + PSStyle.Instance.Reset + sc[k]);
                    }
                    else
                    {
                        lo.WriteLine(padding + sc[k]);
                    }
                }
            }
        }
Exemplo n.º 6
0
        static UpdatesNotification()
        {
            s_notificationType = GetNotificationType();
            CanNotifyUpdates   = s_notificationType != NotificationType.Off && ExperimentalFeature.IsEnabled("PSUpdatesNotification");

            if (CanNotifyUpdates)
            {
                s_enumOptions    = new EnumerationOptions();
                s_cacheDirectory = Path.Combine(Platform.CacheDirectory, PSVersionInfo.GitCommitId);

                // Build the template/pattern strings for the configured notification type.
                string typeNum = ((int)s_notificationType).ToString();
                s_sentinelFileName       = $"_sentinel{typeNum}_";
                s_doneFileNameTemplate   = $"sentinel{typeNum}-{{0}}-{{1}}-{{2}}.done";
                s_doneFileNamePattern    = $"sentinel{typeNum}-*.done";
                s_updateFileNameTemplate = $"update{typeNum}_{{0}}_{{1}}";
                s_updateFileNamePattern  = $"update{typeNum}_v*.*.*_????-??-??";
            }
        }
        ResetProgress()
        {
            // destroy the data structures representing outstanding progress records
            // take down and destroy the progress display

            // If we have multiple runspaces on the host then any finished pipeline in any runspace will lead to call 'ResetProgress'
            // so we need the lock
            lock (_instanceLock)
            {
                if (_progPaneUpdateTimer != null)
                {
                    // Stop update a progress pane and destroy timer
                    _progPaneUpdateTimer.Dispose();
                    _progPaneUpdateTimer = null;
                }
                // We don't set 'progPaneUpdateFlag = 0' here, because:
                // 1. According to MSDN, the timer callback can occur after the Dispose() method has been called.
                //    So we cannot guarantee the flag is truly set to 0.
                // 2. When creating a new timer in 'HandleIncomingProgressRecord', we will set the flag to 1 anyway

                if (_progPane != null)
                {
                    Dbg.Assert(_pendingProgress != null, "How can you have a progress pane and no backing data structure?");

                    _progPane.Hide();
                    _progPane = null;
                }

                _pendingProgress = null;

                if (SupportsVirtualTerminal && ExperimentalFeature.IsEnabled(ExperimentalFeature.PSAnsiProgressFeatureName) && PSStyle.Instance.Progress.UseOSCIndicator)
                {
                    // OSC sequence to turn off progress indicator
                    // https://github.com/microsoft/terminal/issues/6700
                    Console.Write("\x1b]9;4;0\x1b\\");
                }
            }
        }
Exemplo n.º 8
0
        /// <summary>
        /// All calls to the Runspace to execute a command line must be done with this function, which properly synchronizes
        /// access to the running pipeline between the main thread and the break handler thread.  This synchronization is
        /// necessary so that executions can be aborted with Ctrl-C (including evaluation of the prompt and collection of
        /// command-completion candidates.
        ///
        /// On any given Executor instance, ExecuteCommand should be called at most once at a time by any one thread. It is NOT
        /// reentrant.
        /// </summary>
        /// <param name="command">
        /// The command line to be executed.  Must be non-null.
        /// </param>
        /// <param name="exceptionThrown">
        /// Receives the Exception thrown by the execution of the command, if any. If no exception is thrown, then set to null.
        /// Can be tested to see if the execution was successful or not.
        /// </param>
        /// <param name="options">
        /// options to govern the execution
        /// </param>
        /// <returns>
        /// the object stream resulting from the execution.  May be null.
        /// </returns>
        internal Collection <PSObject> ExecuteCommand(string command, out Exception exceptionThrown, ExecutionOptions options)
        {
            Dbg.Assert(!String.IsNullOrEmpty(command), "command should have a value");

            // Experimental:
            // Check for implicit remoting commands that can be batched, and execute as batched if able.
            if (ExperimentalFeature.IsEnabled("PSImplicitRemotingBatching"))
            {
                var addOutputter = ((options & ExecutionOptions.AddOutputter) > 0);
                if (addOutputter &&
                    !_parent.RunspaceRef.IsRunspaceOverridden &&
                    _parent.RunspaceRef.Runspace.ExecutionContext.Modules != null &&
                    _parent.RunspaceRef.Runspace.ExecutionContext.Modules.IsImplicitRemotingModuleLoaded &&
                    Utils.TryRunAsImplicitBatch(command, _parent.RunspaceRef.Runspace))
                {
                    exceptionThrown = null;
                    return(null);
                }
            }

            Pipeline tempPipeline = CreatePipeline(command, (options & ExecutionOptions.AddToHistory) > 0);

            return(ExecuteCommandHelper(tempPipeline, out exceptionThrown, options));
        }
Exemplo n.º 9
0
 internal static bool IsMinimalProgressRenderingEnabled()
 {
     return(ExperimentalFeature.IsEnabled(ExperimentalFeature.PSAnsiProgressFeatureName) && PSStyle.Instance.Progress.View == ProgressView.Minimal);
 }
Exemplo n.º 10
0
        internal void GenerateRow(string[] values, LineOutput lo, bool multiLine, ReadOnlySpan <int> alignment, DisplayCells dc, List <string> generatedRows, bool isHeader = false)
        {
            if (_disabled)
            {
                return;
            }

            // build the current row alignment settings
            int        cols             = _si.columnInfo.Length;
            Span <int> currentAlignment = cols <= OutCommandInner.StackAllocThreshold ? stackalloc int[cols] : new int[cols];

            if (alignment.IsEmpty)
            {
                for (int i = 0; i < currentAlignment.Length; i++)
                {
                    currentAlignment[i] = _si.columnInfo[i].alignment;
                }
            }
            else
            {
                for (int i = 0; i < currentAlignment.Length; i++)
                {
                    if (alignment[i] == TextAlignment.Undefined)
                    {
                        currentAlignment[i] = _si.columnInfo[i].alignment;
                    }
                    else
                    {
                        currentAlignment[i] = alignment[i];
                    }
                }
            }

            if (multiLine)
            {
                foreach (string line in GenerateTableRow(values, currentAlignment, lo.DisplayCells))
                {
                    generatedRows?.Add(line);
                    if (ExperimentalFeature.IsEnabled("PSAnsiRendering") && isHeader)
                    {
                        lo.WriteLine(PSStyle.Instance.Formatting.TableHeader + line + PSStyle.Instance.Reset);
                    }
                    else
                    {
                        lo.WriteLine(line);
                    }
                }
            }
            else
            {
                string line = GenerateRow(values, currentAlignment, dc);
                generatedRows?.Add(line);
                if (ExperimentalFeature.IsEnabled("PSAnsiRendering") && isHeader)
                {
                    lo.WriteLine(PSStyle.Instance.Formatting.TableHeader + line + PSStyle.Instance.Reset);
                }
                else
                {
                    lo.WriteLine(line);
                }
            }
        }
Exemplo n.º 11
0
        private static IEnumerable <FormatViewDefinition> ViewsOf_FileSystemTypes(CustomControl[] sharedControls)
        {
#if UNIX
            if (ExperimentalFeature.IsEnabled("PSUnixFileStat"))
            {
                yield return(new FormatViewDefinition("childrenWithUnixStat",
                                                      TableControl.Create()
                                                      .GroupByProperty("PSParentPath", customControl: sharedControls[0])
                                                      .AddHeader(Alignment.Left, label: "UnixMode", width: 10)
                                                      .AddHeader(Alignment.Left, label: "User", width: 16)
                                                      .AddHeader(Alignment.Left, label: "Group", width: 16)
                                                      .AddHeader(Alignment.Right, label: "LastWriteTime", width: 18)
                                                      .AddHeader(Alignment.Right, label: "Size", width: 14)
                                                      .AddHeader(Alignment.Left, label: "Name")
                                                      .StartRowDefinition(wrap: true)
                                                      .AddPropertyColumn("UnixMode")
                                                      .AddPropertyColumn("User")
                                                      .AddPropertyColumn("Group")
                                                      .AddScriptBlockColumn(scriptBlock: @"'{0:d} {0:HH}:{0:mm}' -f $_.LastWriteTime")
                                                      .AddPropertyColumn("Size")
                                                      .AddPropertyColumn("NameString")
                                                      .EndRowDefinition()
                                                      .EndTable()));
            }
#endif

            yield return(new FormatViewDefinition("children",
                                                  TableControl.Create()
                                                  .GroupByProperty("PSParentPath", customControl: sharedControls[0])
                                                  .AddHeader(Alignment.Left, label: "Mode", width: 7)
                                                  .AddHeader(Alignment.Right, label: "LastWriteTime", width: 26)
                                                  .AddHeader(Alignment.Right, label: "Length", width: 14)
                                                  .AddHeader(Alignment.Left, label: "Name")
                                                  .StartRowDefinition(wrap: true)
                                                  .AddPropertyColumn("ModeWithoutHardLink")
                                                  .AddPropertyColumn("LastWriteTimeString")
                                                  .AddPropertyColumn("LengthString")
                                                  .AddPropertyColumn("NameString")
                                                  .EndRowDefinition()
                                                  .EndTable()));

            yield return(new FormatViewDefinition("childrenWithHardlink",
                                                  TableControl.Create()
                                                  .GroupByProperty("PSParentPath", customControl: sharedControls[0])
                                                  .AddHeader(Alignment.Left, label: "Mode", width: 7)
                                                  .AddHeader(Alignment.Right, label: "LastWriteTime", width: 26)
                                                  .AddHeader(Alignment.Right, label: "Length", width: 14)
                                                  .AddHeader(Alignment.Left, label: "Name")
                                                  .StartRowDefinition(wrap: true)
                                                  .AddPropertyColumn("Mode")
                                                  .AddPropertyColumn("LastWriteTimeString")
                                                  .AddPropertyColumn("LengthString")
                                                  .AddPropertyColumn("NameString")
                                                  .EndRowDefinition()
                                                  .EndTable()));

            yield return(new FormatViewDefinition("children",
                                                  ListControl.Create()
                                                  .GroupByProperty("PSParentPath", customControl: sharedControls[0])
                                                  .StartEntry(entrySelectedByType: new[] { "System.IO.FileInfo" })
                                                  .AddItemProperty(@"Name")
                                                  .AddItemProperty("LengthString", label: "Length")
                                                  .AddItemProperty(@"CreationTime")
                                                  .AddItemProperty(@"LastWriteTime")
                                                  .AddItemProperty(@"LastAccessTime")
                                                  .AddItemProperty(@"Mode")
                                                  .AddItemProperty(@"LinkType")
                                                  .AddItemProperty(@"Target")
                                                  .AddItemProperty(@"VersionInfo")
                                                  .EndEntry()
                                                  .StartEntry()
                                                  .AddItemProperty(@"Name")
                                                  .AddItemProperty(@"CreationTime")
                                                  .AddItemProperty(@"LastWriteTime")
                                                  .AddItemProperty(@"LastAccessTime")
                                                  .AddItemProperty(@"Mode")
                                                  .AddItemProperty(@"LinkType")
                                                  .AddItemProperty(@"Target")
                                                  .EndEntry()
                                                  .EndList()));

            yield return(new FormatViewDefinition("children",
                                                  WideControl.Create()
                                                  .GroupByProperty("PSParentPath", customControl: sharedControls[0])
                                                  .AddPropertyEntry("Name")
                                                  .AddPropertyEntry("Name", format: "[{0}]", entrySelectedByType: new[] { "System.IO.DirectoryInfo" })
                                                  .EndWideControl()));
        }
Exemplo n.º 12
0
        Show()
        {
            if (!IsShowing)
            {
                // Get temporary reference to the progress region since it can be
                // changed at any time by a call to WriteProgress.
                BufferCell[,] tempProgressRegion = _progressRegion;
                if (tempProgressRegion == null)
                {
                    return;
                }

                // The location where we show ourselves is always relative to the screen buffer's current window position.

                int rows = tempProgressRegion.GetLength(0);
                int cols = tempProgressRegion.GetLength(1);

                if (ProgressNode.IsMinimalProgressRenderingEnabled())
                {
                    rows = _content.Length;
                    cols = PSStyle.Instance.Progress.MaxWidth;
                    if (cols > _bufSize.Width)
                    {
                        cols = _bufSize.Width;
                    }
                }

                _savedCursor = _rawui.CursorPosition;
                _location.X  = 0;

                if (!Platform.IsWindows || ProgressNode.IsMinimalProgressRenderingEnabled())
                {
                    _location.Y = _rawui.CursorPosition.Y;

                    // if cursor is not on left edge already move down one line
                    if (_rawui.CursorPosition.X != 0)
                    {
                        _location.Y++;
                        _rawui.CursorPosition = _location;
                    }

                    // if the cursor is at the bottom, create screen buffer space by scrolling
                    int scrollRows = rows - ((_rawui.BufferSize.Height - 1) - _location.Y);
                    if (scrollRows > 0)
                    {
                        // Scroll the console screen up by 'scrollRows'
                        var bottomLocation = _location;
                        bottomLocation.Y = _rawui.BufferSize.Height - 1;

                        _rawui.CursorPosition = bottomLocation;
                        for (int i = 0; i < scrollRows; i++)
                        {
                            Console.Out.Write('\n');
                        }

                        _location.Y    -= scrollRows;
                        _savedCursor.Y -= scrollRows;
                    }

                    // create cleared region to clear progress bar later
                    _savedRegion = tempProgressRegion;
                    if (ExperimentalFeature.IsEnabled(ExperimentalFeature.PSAnsiProgressFeatureName) && PSStyle.Instance.Progress.View != ProgressView.Minimal)
                    {
                        for (int row = 0; row < rows; row++)
                        {
                            for (int col = 0; col < cols; col++)
                            {
                                _savedRegion[row, col].Character = ' ';
                            }
                        }
                    }

                    // put cursor back to where output should be
                    _rawui.CursorPosition = _location;
                }
                else
                {
                    _location = _rawui.WindowPosition;

                    // We have to show the progress pane in the first column, as the screen buffer at any point might contain
                    // a CJK double-cell characters, which makes it impractical to try to find a position where the pane would
                    // not slice a character.  Column 0 is the only place where we know for sure we can place the pane.

                    _location.Y = Math.Min(_location.Y + 2, _bufSize.Height);

                    // Save off the current contents of the screen buffer in the region that we will occupy
                    _savedRegion =
                        _rawui.GetBufferContents(
                            new Rectangle(_location.X, _location.Y, _location.X + cols - 1, _location.Y + rows - 1));
                }

                if (ProgressNode.IsMinimalProgressRenderingEnabled())
                {
                    WriteContent();
                }
                else
                {
                    // replace the saved region in the screen buffer with our progress display
                    _rawui.SetBufferContents(_location, tempProgressRegion);
                }
            }
        }