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); } }
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); }
// ExperimentalFeatureToString returns string version of ExperimentalFeature enum public static string ExperimentalFeatureToString(ExperimentalFeature value) { switch (value) { case ExperimentalFeature.WebFlexBasis: return("web-flex-basis"); } return("unknown"); }
// ExperimentalFeatureToString returns string version of ExperimentalFeature enum public static bool StringToExperimentalFeature(string value, out ExperimentalFeature result) { switch (value) { case "web-flex-basis": result = ExperimentalFeature.WebFlexBasis; return(true); } result = ExperimentalFeature.WebFlexBasis; return(false); }
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()); }
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); }
/// <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]); } } } }
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\\"); } } }
/// <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)); }
// IsExperimentalFeatureEnabled returns if experimental feature is enabled public bool IsExperimentalFeatureEnabled(ExperimentalFeature feature) { return(this.experimentalFeatures[(int)feature]); }
// SetExperimentalFeatureEnabled enables experimental feature public void SetExperimentalFeatureEnabled(ExperimentalFeature feature, bool enabled) { this.experimentalFeatures[(int)feature] = enabled; }
internal static bool IsMinimalProgressRenderingEnabled() { return(ExperimentalFeature.IsEnabled(ExperimentalFeature.PSAnsiProgressFeatureName) && PSStyle.Instance.Progress.View == ProgressView.Minimal); }
static bool YGConfigIsExperimentalFeatureEnabled(YogaConfig config, ExperimentalFeature feature) => config.ExperimentalFeatures[(int)feature];
public static void YGConfigSetExperimentalFeatureEnabled(YogaConfig config, ExperimentalFeature feature, bool enabled) => config.ExperimentalFeatures[(int)feature] = enabled;
void IExpSettingsBuilder.EnableExperimentalFeature(ExperimentalFeature feature, bool enable) { this.settings.featureFlags[feature] = enable; }
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())); }
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); } } }
internal bool IsFeautureEnabled(ExperimentalFeature feature) => this.featureFlags.TryGetValue(feature, out bool flag) ? flag : false;
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); } } }
/// <summary> /// Construct the string for sorting experimental feature records. /// </summary> /// <remarks> /// Engine features come before module features. /// Within engine features and module features, features are ordered by name. /// </remarks> private static (int, string) GetSortingString(ExperimentalFeature feature) { return(ExperimentalFeature.EngineSource.Equals(feature.Source, StringComparison.OrdinalIgnoreCase) ? (0, feature.Name) : (1, feature.Name)); }