mirror of
https://github.com/PowerShell/PowerShell
synced 2026-06-08 12:12:50 +00:00
513 lines
16 KiB
C#
513 lines
16 KiB
C#
// Copyright (c) Microsoft Corporation.
|
|
// Licensed under the MIT License.
|
|
|
|
// this file contains the data structures for the in memory database
|
|
// containing display and formatting information
|
|
|
|
using System.Collections.Generic;
|
|
using Microsoft.PowerShell.Commands;
|
|
using Microsoft.PowerShell.Commands.Internal.Format;
|
|
|
|
namespace Microsoft.PowerShell.Commands.Internal.Format
|
|
{
|
|
#region Complex View Definitions
|
|
|
|
/// <summary>
|
|
/// In line definition of a complex control.
|
|
/// </summary>
|
|
internal sealed class ComplexControlBody : ControlBody
|
|
{
|
|
/// <summary>
|
|
/// Default list entry definition
|
|
/// It's mandatory.
|
|
/// </summary>
|
|
internal ComplexControlEntryDefinition defaultEntry;
|
|
|
|
/// <summary>
|
|
/// Optional list of list entry definition overrides. It can be empty if there are no overrides.
|
|
/// </summary>
|
|
internal List<ComplexControlEntryDefinition> optionalEntryList = new List<ComplexControlEntryDefinition>();
|
|
}
|
|
|
|
internal sealed class ComplexControlEntryDefinition
|
|
{
|
|
/// <summary>
|
|
/// Applicability clause
|
|
/// Only valid if not the default definition.
|
|
/// </summary>
|
|
internal AppliesTo appliesTo = null;
|
|
|
|
/// <summary>
|
|
/// Item associated with this entry definition.
|
|
/// </summary>
|
|
internal ComplexControlItemDefinition itemDefinition = new ComplexControlItemDefinition();
|
|
}
|
|
|
|
internal sealed class ComplexControlItemDefinition
|
|
{
|
|
/// <summary>
|
|
/// List of tokens the item can contain.
|
|
/// </summary>
|
|
internal List<FormatToken> formatTokenList = new List<FormatToken>();
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
|
|
namespace System.Management.Automation
|
|
{
|
|
/// <summary/>
|
|
public sealed class CustomControl : PSControl
|
|
{
|
|
/// <summary/>
|
|
public List<CustomControlEntry> Entries { get; set; }
|
|
|
|
internal ComplexControlBody _cachedBody;
|
|
|
|
internal CustomControl()
|
|
{
|
|
Entries = new List<CustomControlEntry>();
|
|
}
|
|
|
|
internal CustomControl(ComplexControlBody body, ViewDefinition viewDefinition)
|
|
{
|
|
// viewDefinition can be null for nested controls
|
|
if (viewDefinition != null)
|
|
{
|
|
OutOfBand = viewDefinition.outOfBand;
|
|
GroupBy = PSControlGroupBy.Get(viewDefinition.groupBy);
|
|
}
|
|
|
|
Entries = new List<CustomControlEntry>();
|
|
|
|
// Default entry
|
|
var cce = new CustomControlEntry(body.defaultEntry);
|
|
Entries.Add(cce);
|
|
|
|
foreach (var entry in body.optionalEntryList)
|
|
{
|
|
cce = new CustomControlEntry(entry);
|
|
Entries.Add(cce);
|
|
}
|
|
}
|
|
|
|
/// <summary/>
|
|
public static CustomControlBuilder Create(bool outOfBand = false)
|
|
{
|
|
var customControl = new CustomControl { OutOfBand = outOfBand };
|
|
return new CustomControlBuilder(customControl);
|
|
}
|
|
|
|
internal override void WriteToXml(FormatXmlWriter writer)
|
|
{
|
|
writer.WriteCustomControl(this);
|
|
}
|
|
|
|
internal override bool SafeForExport()
|
|
{
|
|
if (!base.SafeForExport())
|
|
return false;
|
|
|
|
foreach (var entry in Entries)
|
|
{
|
|
if (!entry.SafeForExport())
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
internal override bool CompatibleWithOldPowerShell()
|
|
{
|
|
// Old versions of PowerShell know nothing about CustomControl.
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/// <summary/>
|
|
public sealed class CustomControlEntry
|
|
{
|
|
internal CustomControlEntry()
|
|
{
|
|
CustomItems = new List<CustomItemBase>();
|
|
}
|
|
|
|
internal CustomControlEntry(ComplexControlEntryDefinition entry)
|
|
{
|
|
if (entry.appliesTo != null)
|
|
{
|
|
SelectedBy = EntrySelectedBy.Get(entry.appliesTo.referenceList);
|
|
}
|
|
|
|
CustomItems = new List<CustomItemBase>();
|
|
foreach (var tok in entry.itemDefinition.formatTokenList)
|
|
{
|
|
CustomItems.Add(CustomItemBase.Create(tok));
|
|
}
|
|
}
|
|
|
|
/// <summary/>
|
|
public EntrySelectedBy SelectedBy { get; set; }
|
|
|
|
/// <summary/>
|
|
public List<CustomItemBase> CustomItems { get; set; }
|
|
|
|
internal bool SafeForExport()
|
|
{
|
|
foreach (var item in CustomItems)
|
|
{
|
|
if (!item.SafeForExport())
|
|
return false;
|
|
}
|
|
|
|
return SelectedBy == null || SelectedBy.SafeForExport();
|
|
}
|
|
}
|
|
|
|
/// <summary/>
|
|
public abstract class CustomItemBase
|
|
{
|
|
internal virtual bool SafeForExport()
|
|
{
|
|
return true;
|
|
}
|
|
|
|
internal static CustomItemBase Create(FormatToken token)
|
|
{
|
|
if (token is NewLineToken)
|
|
{
|
|
return new CustomItemNewline();
|
|
}
|
|
|
|
if (token is TextToken textToken)
|
|
{
|
|
return new CustomItemText { Text = textToken.text };
|
|
}
|
|
|
|
if (token is FrameToken frameToken)
|
|
{
|
|
var frame = new CustomItemFrame
|
|
{
|
|
RightIndent = (uint)frameToken.frameInfoDefinition.rightIndentation,
|
|
LeftIndent = (uint)frameToken.frameInfoDefinition.leftIndentation
|
|
};
|
|
var firstLine = frameToken.frameInfoDefinition.firstLine;
|
|
if (firstLine > 0)
|
|
{
|
|
frame.FirstLineIndent = (uint)firstLine;
|
|
}
|
|
else if (firstLine < 0)
|
|
{
|
|
frame.FirstLineHanging = (uint)-firstLine;
|
|
}
|
|
|
|
foreach (var frameItemToken in frameToken.itemDefinition.formatTokenList)
|
|
{
|
|
frame.CustomItems.Add(CustomItemBase.Create(frameItemToken));
|
|
}
|
|
|
|
return frame;
|
|
}
|
|
|
|
if (token is CompoundPropertyToken cpt)
|
|
{
|
|
var cie = new CustomItemExpression { EnumerateCollection = cpt.enumerateCollection };
|
|
|
|
if (cpt.conditionToken != null)
|
|
{
|
|
cie.ItemSelectionCondition = new DisplayEntry(cpt.conditionToken);
|
|
}
|
|
|
|
if (cpt.expression.expressionValue != null)
|
|
{
|
|
cie.Expression = new DisplayEntry(cpt.expression);
|
|
}
|
|
|
|
if (cpt.control is ComplexControlBody complexControlBody)
|
|
{
|
|
cie.CustomControl = new CustomControl(complexControlBody, null);
|
|
}
|
|
|
|
return cie;
|
|
}
|
|
|
|
Diagnostics.Assert(false, "Unexpected formatting token kind");
|
|
|
|
return null;
|
|
}
|
|
}
|
|
|
|
/// <summary/>
|
|
public sealed class CustomItemExpression : CustomItemBase
|
|
{
|
|
internal CustomItemExpression() { }
|
|
|
|
/// <summary/>
|
|
public DisplayEntry ItemSelectionCondition { get; set; }
|
|
|
|
/// <summary/>
|
|
public DisplayEntry Expression { get; set; }
|
|
|
|
/// <summary/>
|
|
public bool EnumerateCollection { get; set; }
|
|
|
|
/// <summary/>
|
|
public CustomControl CustomControl { get; set; }
|
|
|
|
internal override bool SafeForExport()
|
|
{
|
|
return (ItemSelectionCondition == null || ItemSelectionCondition.SafeForExport()) &&
|
|
(Expression == null || Expression.SafeForExport()) &&
|
|
(CustomControl == null || CustomControl.SafeForExport());
|
|
}
|
|
}
|
|
|
|
/// <summary/>
|
|
public sealed class CustomItemFrame : CustomItemBase
|
|
{
|
|
/// <summary/>
|
|
public uint LeftIndent { get; set; }
|
|
/// <summary/>
|
|
public uint RightIndent { get; set; }
|
|
/// <summary/>
|
|
public uint FirstLineHanging { get; set; }
|
|
/// <summary/>
|
|
public uint FirstLineIndent { get; set; }
|
|
|
|
internal CustomItemFrame()
|
|
{
|
|
CustomItems = new List<CustomItemBase>();
|
|
}
|
|
|
|
/// <summary/>
|
|
public List<CustomItemBase> CustomItems { get; set; }
|
|
|
|
internal override bool SafeForExport()
|
|
{
|
|
foreach (var frameItem in CustomItems)
|
|
{
|
|
if (!frameItem.SafeForExport())
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
}
|
|
|
|
/// <summary/>
|
|
public sealed class CustomItemNewline : CustomItemBase
|
|
{
|
|
/// <summary/>
|
|
public CustomItemNewline()
|
|
{
|
|
this.Count = 1;
|
|
}
|
|
/// <summary/>
|
|
public int Count { get; set; }
|
|
}
|
|
|
|
/// <summary/>
|
|
public sealed class CustomItemText : CustomItemBase
|
|
{
|
|
/// <summary/>
|
|
public string Text { get; set; }
|
|
}
|
|
|
|
/// <summary/>
|
|
public sealed class CustomEntryBuilder
|
|
{
|
|
private readonly Stack<List<CustomItemBase>> _entryStack;
|
|
private readonly CustomControlBuilder _controlBuilder;
|
|
|
|
internal CustomEntryBuilder(CustomControlBuilder controlBuilder, CustomControlEntry entry)
|
|
{
|
|
_entryStack = new Stack<List<CustomItemBase>>();
|
|
_entryStack.Push(entry.CustomItems);
|
|
_controlBuilder = controlBuilder;
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomEntryBuilder AddNewline(int count = 1)
|
|
{
|
|
_entryStack.Peek().Add(new CustomItemNewline { Count = count });
|
|
return this;
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomEntryBuilder AddText(string text)
|
|
{
|
|
_entryStack.Peek().Add(new CustomItemText { Text = text });
|
|
return this;
|
|
}
|
|
|
|
private void AddDisplayExpressionBinding(
|
|
string value,
|
|
DisplayEntryValueType valueType,
|
|
bool enumerateCollection = false,
|
|
string selectedByType = null,
|
|
string selectedByScript = null,
|
|
CustomControl customControl = null)
|
|
{
|
|
_entryStack.Peek().Add(new CustomItemExpression()
|
|
{
|
|
ItemSelectionCondition = selectedByScript != null
|
|
? new DisplayEntry(selectedByScript, DisplayEntryValueType.ScriptBlock)
|
|
: selectedByType != null
|
|
? new DisplayEntry(selectedByType, DisplayEntryValueType.Property)
|
|
: null,
|
|
EnumerateCollection = enumerateCollection,
|
|
Expression = new DisplayEntry(value, valueType),
|
|
CustomControl = customControl
|
|
});
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomEntryBuilder AddPropertyExpressionBinding(
|
|
string property,
|
|
bool enumerateCollection = false,
|
|
string selectedByType = null,
|
|
string selectedByScript = null,
|
|
CustomControl customControl = null)
|
|
{
|
|
AddDisplayExpressionBinding(property, DisplayEntryValueType.Property, enumerateCollection, selectedByType, selectedByScript, customControl);
|
|
return this;
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomEntryBuilder AddScriptBlockExpressionBinding(
|
|
string scriptBlock,
|
|
bool enumerateCollection = false,
|
|
string selectedByType = null,
|
|
string selectedByScript = null,
|
|
CustomControl customControl = null)
|
|
{
|
|
AddDisplayExpressionBinding(scriptBlock, DisplayEntryValueType.ScriptBlock, enumerateCollection, selectedByType, selectedByScript, customControl);
|
|
return this;
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomEntryBuilder AddCustomControlExpressionBinding(
|
|
CustomControl customControl,
|
|
bool enumerateCollection = false,
|
|
string selectedByType = null,
|
|
string selectedByScript = null)
|
|
{
|
|
_entryStack.Peek().Add(new CustomItemExpression()
|
|
{
|
|
ItemSelectionCondition = selectedByScript != null
|
|
? new DisplayEntry(selectedByScript, DisplayEntryValueType.ScriptBlock)
|
|
: selectedByType != null
|
|
? new DisplayEntry(selectedByType, DisplayEntryValueType.Property)
|
|
: null,
|
|
EnumerateCollection = enumerateCollection,
|
|
CustomControl = customControl
|
|
});
|
|
|
|
return this;
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomEntryBuilder StartFrame(uint leftIndent = 0, uint rightIndent = 0, uint firstLineHanging = 0, uint firstLineIndent = 0)
|
|
{
|
|
// Mutually exclusive
|
|
if (leftIndent != 0 && rightIndent != 0)
|
|
{
|
|
throw PSTraceSource.NewArgumentException(nameof(leftIndent));
|
|
}
|
|
|
|
// Mutually exclusive
|
|
if (firstLineHanging != 0 && firstLineIndent != 0)
|
|
{
|
|
throw PSTraceSource.NewArgumentException(nameof(firstLineHanging));
|
|
}
|
|
|
|
var frame = new CustomItemFrame
|
|
{
|
|
LeftIndent = leftIndent,
|
|
RightIndent = rightIndent,
|
|
FirstLineHanging = firstLineHanging,
|
|
FirstLineIndent = firstLineIndent
|
|
};
|
|
_entryStack.Peek().Add(frame);
|
|
_entryStack.Push(frame.CustomItems);
|
|
return this;
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomEntryBuilder EndFrame()
|
|
{
|
|
if (_entryStack.Count < 2)
|
|
{
|
|
throw PSTraceSource.NewInvalidOperationException();
|
|
}
|
|
|
|
_entryStack.Pop();
|
|
return this;
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomControlBuilder EndEntry()
|
|
{
|
|
if (_entryStack.Count != 1)
|
|
{
|
|
throw PSTraceSource.NewInvalidOperationException();
|
|
}
|
|
|
|
_entryStack.Pop();
|
|
return _controlBuilder;
|
|
}
|
|
}
|
|
|
|
/// <summary/>
|
|
public sealed class CustomControlBuilder
|
|
{
|
|
internal CustomControl _control;
|
|
|
|
internal CustomControlBuilder(CustomControl control)
|
|
{
|
|
_control = control;
|
|
}
|
|
|
|
/// <summary>Group instances by the property name with an optional label.</summary>
|
|
public CustomControlBuilder GroupByProperty(string property, CustomControl customControl = null, string label = null)
|
|
{
|
|
_control.GroupBy = new PSControlGroupBy
|
|
{
|
|
Expression = new DisplayEntry(property, DisplayEntryValueType.Property),
|
|
CustomControl = customControl,
|
|
Label = label
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/// <summary>Group instances by the script block expression with an optional label.</summary>
|
|
public CustomControlBuilder GroupByScriptBlock(string scriptBlock, CustomControl customControl = null, string label = null)
|
|
{
|
|
_control.GroupBy = new PSControlGroupBy
|
|
{
|
|
Expression = new DisplayEntry(scriptBlock, DisplayEntryValueType.ScriptBlock),
|
|
CustomControl = customControl,
|
|
Label = label
|
|
};
|
|
return this;
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomEntryBuilder StartEntry(IEnumerable<string> entrySelectedByType = null, IEnumerable<DisplayEntry> entrySelectedByCondition = null)
|
|
{
|
|
var entry = new CustomControlEntry
|
|
{
|
|
SelectedBy = EntrySelectedBy.Get(entrySelectedByType, entrySelectedByCondition)
|
|
};
|
|
_control.Entries.Add(entry);
|
|
return new CustomEntryBuilder(this, entry);
|
|
}
|
|
|
|
/// <summary/>
|
|
public CustomControl EndControl()
|
|
{
|
|
return _control;
|
|
}
|
|
}
|
|
}
|