mirror of
https://github.com/nsnail/spectre.console.git
synced 2025-06-19 13:28:16 +08:00
Change IAnsiConsole to render IRenderable
This makes it possible for encoders to output better representation of the actual objects instead of working with chopped up segments. * IAnsiConsole.Write now takes an IRenderable instead of segments * Calculating cell width does no longer require a render context * Removed RenderContext.LegacyConsole * Removed RenderContext.Encoding * Added Capabilities.Unicode
This commit is contained in:

committed by
Phil Scott

parent
2ba6da3514
commit
20650f1e7e
@ -53,7 +53,7 @@ namespace Spectre.Console
|
||||
{
|
||||
var line = new Segment(string.Concat(row.Select(x => x.Lines[index])), style);
|
||||
|
||||
var lineWidth = line.CellCount(context);
|
||||
var lineWidth = line.CellCount();
|
||||
if (alignment == Justify.Left)
|
||||
{
|
||||
yield return line;
|
||||
|
@ -70,7 +70,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
var child = _child.Render(context, maxWidth - paddingWidth);
|
||||
foreach (var (_, _, _, line) in Segment.SplitLines(context, child).Enumerate())
|
||||
foreach (var line in Segment.SplitLines(child))
|
||||
{
|
||||
// Left padding
|
||||
if (Padding.GetLeftSafe() != 0)
|
||||
@ -87,7 +87,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
// Missing space on right side?
|
||||
var lineWidth = line.CellCount(context);
|
||||
var lineWidth = line.CellCount();
|
||||
var diff = width - lineWidth - Padding.GetLeftSafe() - Padding.GetRightSafe();
|
||||
if (diff > 0)
|
||||
{
|
||||
|
@ -78,7 +78,7 @@ namespace Spectre.Console
|
||||
{
|
||||
var edgeWidth = EdgeWidth;
|
||||
|
||||
var border = BoxExtensions.GetSafeBorder(Border, (context.LegacyConsole || !context.Unicode) && UseSafeBorder);
|
||||
var border = BoxExtensions.GetSafeBorder(Border, !context.Unicode && UseSafeBorder);
|
||||
var borderStyle = BorderStyle ?? Style.Plain;
|
||||
|
||||
var showBorder = true;
|
||||
@ -110,7 +110,7 @@ namespace Spectre.Console
|
||||
|
||||
// Split the child segments into lines.
|
||||
var childSegments = ((IRenderable)child).Render(context, childWidth);
|
||||
foreach (var (_, _, last, line) in Segment.SplitLines(context, childSegments, childWidth).Enumerate())
|
||||
foreach (var (_, _, last, line) in Segment.SplitLines(childSegments, childWidth).Enumerate())
|
||||
{
|
||||
if (line.Count == 1 && line[0].IsWhiteSpace)
|
||||
{
|
||||
@ -128,7 +128,7 @@ namespace Spectre.Console
|
||||
content.AddRange(line);
|
||||
|
||||
// Do we need to pad the panel?
|
||||
var length = line.Sum(segment => segment.CellCount(context));
|
||||
var length = line.Sum(segment => segment.CellCount());
|
||||
if (length < childWidth)
|
||||
{
|
||||
var diff = childWidth - length;
|
||||
|
@ -118,8 +118,8 @@ namespace Spectre.Console
|
||||
return new Measurement(0, 0);
|
||||
}
|
||||
|
||||
var min = _lines.Max(line => line.Max(segment => segment.CellCount(context)));
|
||||
var max = _lines.Max(x => x.CellCount(context));
|
||||
var min = _lines.Max(line => line.Max(segment => segment.CellCount()));
|
||||
var max = _lines.Max(x => x.CellCount());
|
||||
|
||||
return new Measurement(min, Math.Min(max, maxWidth));
|
||||
}
|
||||
@ -139,7 +139,7 @@ namespace Spectre.Console
|
||||
|
||||
var lines = context.SingleLine
|
||||
? new List<SegmentLine>(_lines)
|
||||
: SplitLines(context, maxWidth);
|
||||
: SplitLines(maxWidth);
|
||||
|
||||
// Justify lines
|
||||
var justification = context.Justification ?? Alignment ?? Justify.Left;
|
||||
@ -178,7 +178,7 @@ namespace Spectre.Console
|
||||
return result;
|
||||
}
|
||||
|
||||
private List<SegmentLine> SplitLines(RenderContext context, int maxWidth)
|
||||
private List<SegmentLine> SplitLines(int maxWidth)
|
||||
{
|
||||
if (maxWidth <= 0)
|
||||
{
|
||||
@ -186,7 +186,7 @@ namespace Spectre.Console
|
||||
return new List<SegmentLine>();
|
||||
}
|
||||
|
||||
if (_lines.Max(x => x.CellCount(context)) <= maxWidth)
|
||||
if (_lines.Max(x => x.CellCount()) <= maxWidth)
|
||||
{
|
||||
return Clone();
|
||||
}
|
||||
@ -230,15 +230,15 @@ namespace Spectre.Console
|
||||
continue;
|
||||
}
|
||||
|
||||
var length = current.CellCount(context);
|
||||
var length = current.CellCount();
|
||||
if (length > maxWidth)
|
||||
{
|
||||
// The current segment is longer than the width of the console,
|
||||
// so we will need to crop it up, into new segments.
|
||||
var segments = Segment.SplitOverflow(current, Overflow, context, maxWidth);
|
||||
var segments = Segment.SplitOverflow(current, Overflow, maxWidth);
|
||||
if (segments.Count > 0)
|
||||
{
|
||||
if (line.CellCount(context) + segments[0].CellCount(context) > maxWidth)
|
||||
if (line.CellCount() + segments[0].CellCount() > maxWidth)
|
||||
{
|
||||
lines.Add(line);
|
||||
line = new SegmentLine();
|
||||
@ -258,7 +258,7 @@ namespace Spectre.Console
|
||||
}
|
||||
else
|
||||
{
|
||||
if (line.CellCount(context) + length > maxWidth)
|
||||
if (line.CellCount() + length > maxWidth)
|
||||
{
|
||||
line.Add(Segment.Empty);
|
||||
lines.Add(line);
|
||||
|
@ -101,7 +101,7 @@ namespace Spectre.Console
|
||||
/// <inheritdoc/>
|
||||
public override IRenderable Render(RenderContext context, ProgressTask task, TimeSpan deltaTime)
|
||||
{
|
||||
var useAscii = (context.LegacyConsole || !context.Unicode) && _spinner.IsUnicode;
|
||||
var useAscii = !context.Unicode && _spinner.IsUnicode;
|
||||
var spinner = useAscii ? Spinner.Known.Ascii : _spinner ?? Spinner.Known.Default;
|
||||
|
||||
if (!task.IsStarted)
|
||||
@ -138,14 +138,14 @@ namespace Spectre.Console
|
||||
{
|
||||
if (_maxWidth == null)
|
||||
{
|
||||
var useAscii = (context.LegacyConsole || !context.Unicode) && _spinner.IsUnicode;
|
||||
var useAscii = !context.Unicode && _spinner.IsUnicode;
|
||||
var spinner = useAscii ? Spinner.Known.Ascii : _spinner ?? Spinner.Known.Default;
|
||||
|
||||
_maxWidth = Math.Max(
|
||||
Math.Max(
|
||||
((IRenderable)new Markup(PendingText ?? " ")).Measure(context, int.MaxValue).Max,
|
||||
((IRenderable)new Markup(CompletedText ?? " ")).Measure(context, int.MaxValue).Max),
|
||||
spinner.Frames.Max(frame => Cell.GetCellLength(context, frame)));
|
||||
spinner.Frames.Max(frame => Cell.GetCellLength(frame)));
|
||||
}
|
||||
|
||||
return _maxWidth.Value;
|
||||
|
@ -52,7 +52,7 @@ namespace Spectre.Console
|
||||
public void Refresh()
|
||||
{
|
||||
_renderer.Update(this);
|
||||
_console.Render(new ControlSequence(string.Empty));
|
||||
_console.Write(new ControlSequence(string.Empty));
|
||||
}
|
||||
|
||||
internal IReadOnlyList<ProgressTask> GetTasks()
|
||||
|
@ -42,7 +42,7 @@ namespace Spectre.Console
|
||||
{
|
||||
if (clear)
|
||||
{
|
||||
_console.Render(_live.RestoreCursor());
|
||||
_console.Write(_live.RestoreCursor());
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -62,7 +62,7 @@ namespace Spectre.Console
|
||||
_stopwatch.Start();
|
||||
}
|
||||
|
||||
var renderContext = new RenderContext(_console.Profile.Encoding, _console.Profile.Capabilities.Legacy);
|
||||
var renderContext = new RenderContext(_console.Profile.Capabilities);
|
||||
|
||||
var delta = _stopwatch.Elapsed - _lastUpdate;
|
||||
_lastUpdate = _stopwatch.Elapsed;
|
||||
|
@ -32,7 +32,7 @@ namespace Spectre.Console
|
||||
var width = Math.Min(Width ?? maxWidth, maxWidth);
|
||||
var completed = Math.Min(MaxValue, Math.Max(0, Value));
|
||||
|
||||
var token = !context.Unicode || context.LegacyConsole ? AsciiBar : UnicodeBar;
|
||||
var token = !context.Unicode ? AsciiBar : UnicodeBar;
|
||||
var style = completed >= MaxValue ? FinishedStyle : CompletedStyle;
|
||||
|
||||
var bars = Math.Max(0, (int)(width * (completed / MaxValue)));
|
||||
|
67
src/Spectre.Console/Widgets/Prompt/ConfirmationPrompt.cs
Normal file
67
src/Spectre.Console/Widgets/Prompt/ConfirmationPrompt.cs
Normal file
@ -0,0 +1,67 @@
|
||||
namespace Spectre.Console
|
||||
{
|
||||
/// <summary>
|
||||
/// A prompt that is answered with a yes or no.
|
||||
/// </summary>
|
||||
public sealed class ConfirmationPrompt : IPrompt<bool>
|
||||
{
|
||||
private readonly string _prompt;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the character that represents "yes".
|
||||
/// </summary>
|
||||
public char Yes { get; set; } = 'y';
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the character that represents "no".
|
||||
/// </summary>
|
||||
public char No { get; set; } = 'n';
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether "yes" is the default answer.
|
||||
/// </summary>
|
||||
public bool DefaultValue { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the message for invalid choices.
|
||||
/// </summary>
|
||||
public string InvalidChoiceMessage { get; set; } = "[red]Please select one of the available options[/]";
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not
|
||||
/// choices should be shown.
|
||||
/// </summary>
|
||||
public bool ShowChoices { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a value indicating whether or not
|
||||
/// default values should be shown.
|
||||
/// </summary>
|
||||
public bool ShowDefaultValue { get; set; } = true;
|
||||
|
||||
/// <summary>
|
||||
/// Initializes a new instance of the <see cref="ConfirmationPrompt"/> class.
|
||||
/// </summary>
|
||||
/// <param name="prompt">The prompt markup text.</param>
|
||||
public ConfirmationPrompt(string prompt)
|
||||
{
|
||||
_prompt = prompt ?? throw new System.ArgumentNullException(nameof(prompt));
|
||||
}
|
||||
|
||||
/// <inheritdoc/>
|
||||
public bool Show(IAnsiConsole console)
|
||||
{
|
||||
var prompt = new TextPrompt<char>(_prompt)
|
||||
.InvalidChoiceMessage(InvalidChoiceMessage)
|
||||
.ValidationErrorMessage(InvalidChoiceMessage)
|
||||
.ShowChoices(ShowChoices)
|
||||
.ShowDefaultValue(ShowDefaultValue)
|
||||
.DefaultValue(DefaultValue ? Yes : No)
|
||||
.AddChoice(Yes)
|
||||
.AddChoice(No);
|
||||
|
||||
var result = prompt.Show(console);
|
||||
return result == Yes;
|
||||
}
|
||||
}
|
||||
}
|
@ -33,12 +33,12 @@ namespace Spectre.Console
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
_console.Render(_live.RestoreCursor());
|
||||
_console.Write(_live.RestoreCursor());
|
||||
}
|
||||
|
||||
public void Redraw()
|
||||
{
|
||||
_console.Render(new ControlSequence(string.Empty));
|
||||
_console.Write(new ControlSequence(string.Empty));
|
||||
}
|
||||
|
||||
public bool Update(ConsoleKey key)
|
||||
|
@ -59,10 +59,10 @@ namespace Spectre.Console
|
||||
|
||||
// Get the title and make sure it fits.
|
||||
var title = GetTitleSegments(context, Title, maxWidth - extraLength);
|
||||
if (Segment.CellCount(context, title) > maxWidth - extraLength)
|
||||
if (Segment.CellCount(title) > maxWidth - extraLength)
|
||||
{
|
||||
// Truncate the title
|
||||
title = Segment.TruncateWithEllipsis(title, context, maxWidth - extraLength);
|
||||
title = Segment.TruncateWithEllipsis(title, maxWidth - extraLength);
|
||||
if (!title.Any())
|
||||
{
|
||||
// We couldn't fit the title at all.
|
||||
@ -83,7 +83,7 @@ namespace Spectre.Console
|
||||
|
||||
private IEnumerable<Segment> GetLineWithoutTitle(RenderContext context, int maxWidth)
|
||||
{
|
||||
var border = Border.GetSafeBorder(context.LegacyConsole || !context.Unicode);
|
||||
var border = Border.GetSafeBorder(safe: !context.Unicode);
|
||||
var text = border.GetPart(BoxBorderPart.Top).Repeat(maxWidth);
|
||||
|
||||
return new[]
|
||||
@ -102,9 +102,9 @@ namespace Spectre.Console
|
||||
|
||||
private (Segment Left, Segment Right) GetLineSegments(RenderContext context, int width, IEnumerable<Segment> title)
|
||||
{
|
||||
var titleLength = Segment.CellCount(context, title);
|
||||
var titleLength = Segment.CellCount(title);
|
||||
|
||||
var border = Border.GetSafeBorder(context.LegacyConsole || !context.Unicode);
|
||||
var border = Border.GetSafeBorder(safe: !context.Unicode);
|
||||
var borderPart = border.GetPart(BoxBorderPart.Top);
|
||||
|
||||
var alignment = Alignment ?? Justify.Center;
|
||||
@ -112,7 +112,7 @@ namespace Spectre.Console
|
||||
{
|
||||
var left = new Segment(borderPart.Repeat(TitlePadding) + new string(' ', TitleSpacing), Style ?? Style.Plain);
|
||||
|
||||
var rightLength = width - titleLength - left.CellCount(context) - TitleSpacing;
|
||||
var rightLength = width - titleLength - left.CellCount() - TitleSpacing;
|
||||
var right = new Segment(new string(' ', TitleSpacing) + borderPart.Repeat(rightLength), Style ?? Style.Plain);
|
||||
|
||||
return (left, right);
|
||||
@ -122,7 +122,7 @@ namespace Spectre.Console
|
||||
var leftLength = ((width - titleLength) / 2) - TitleSpacing;
|
||||
var left = new Segment(borderPart.Repeat(leftLength) + new string(' ', TitleSpacing), Style ?? Style.Plain);
|
||||
|
||||
var rightLength = width - titleLength - left.CellCount(context) - TitleSpacing;
|
||||
var rightLength = width - titleLength - left.CellCount() - TitleSpacing;
|
||||
var right = new Segment(new string(' ', TitleSpacing) + borderPart.Repeat(rightLength), Style ?? Style.Plain);
|
||||
|
||||
return (left, right);
|
||||
@ -131,7 +131,7 @@ namespace Spectre.Console
|
||||
{
|
||||
var right = new Segment(new string(' ', TitleSpacing) + borderPart.Repeat(TitlePadding), Style ?? Style.Plain);
|
||||
|
||||
var leftLength = width - titleLength - right.CellCount(context) - TitleSpacing;
|
||||
var leftLength = width - titleLength - right.CellCount() - TitleSpacing;
|
||||
var left = new Segment(borderPart.Repeat(leftLength) + new string(' ', TitleSpacing), Style ?? Style.Plain);
|
||||
|
||||
return (left, right);
|
||||
|
@ -33,7 +33,7 @@ namespace Spectre.Console
|
||||
var justification = context.Columns[columnIndex].Alignment;
|
||||
var childContext = context.Options.WithJustification(justification);
|
||||
|
||||
var lines = Segment.SplitLines(context.Options, cell.Render(childContext, rowWidth));
|
||||
var lines = Segment.SplitLines(cell.Render(childContext, rowWidth));
|
||||
cellHeight = Math.Max(cellHeight, lines.Count);
|
||||
cells.Add(lines);
|
||||
}
|
||||
@ -41,7 +41,7 @@ namespace Spectre.Console
|
||||
// Show top of header?
|
||||
if (isFirstRow && context.ShowBorder)
|
||||
{
|
||||
var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
||||
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.Top, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
||||
result.Add(new Segment(separator, context.BorderStyle));
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
@ -52,7 +52,7 @@ namespace Spectre.Console
|
||||
var textBorder = context.Border.GetColumnRow(TablePart.FooterSeparator, columnWidths, context.Columns);
|
||||
if (!string.IsNullOrEmpty(textBorder))
|
||||
{
|
||||
var separator = Aligner.Align(context.Options, textBorder, context.Alignment, context.MaxWidth);
|
||||
var separator = Aligner.Align(textBorder, context.Alignment, context.MaxWidth);
|
||||
result.Add(new Segment(separator, context.BorderStyle));
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
@ -89,7 +89,7 @@ namespace Spectre.Console
|
||||
rowResult.AddRange(cell[cellRowIndex]);
|
||||
|
||||
// Pad cell content right
|
||||
var length = cell[cellRowIndex].Sum(segment => segment.CellCount(context.Options));
|
||||
var length = cell[cellRowIndex].Sum(segment => segment.CellCount());
|
||||
if (length < columnWidths[cellIndex])
|
||||
{
|
||||
rowResult.Add(new Segment(new string(' ', columnWidths[cellIndex] - length)));
|
||||
@ -123,9 +123,9 @@ namespace Spectre.Console
|
||||
Aligner.Align(context.Options, rowResult, context.Alignment, context.MaxWidth);
|
||||
|
||||
// Is the row larger than the allowed max width?
|
||||
if (Segment.CellCount(context.Options, rowResult) > context.MaxWidth)
|
||||
if (Segment.CellCount(rowResult) > context.MaxWidth)
|
||||
{
|
||||
result.AddRange(Segment.Truncate(context.Options, rowResult, context.MaxWidth));
|
||||
result.AddRange(Segment.Truncate(rowResult, context.MaxWidth));
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -138,7 +138,7 @@ namespace Spectre.Console
|
||||
// Show header separator?
|
||||
if (isFirstRow && context.ShowBorder && context.ShowHeaders && context.HasRows)
|
||||
{
|
||||
var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
||||
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.HeaderSeparator, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
||||
result.Add(new Segment(separator, context.BorderStyle));
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
@ -146,7 +146,7 @@ namespace Spectre.Console
|
||||
// Show bottom of footer?
|
||||
if (isLastRow && context.ShowBorder)
|
||||
{
|
||||
var separator = Aligner.Align(context.Options, context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
||||
var separator = Aligner.Align(context.Border.GetColumnRow(TablePart.Bottom, columnWidths, context.Columns), context.Alignment, context.MaxWidth);
|
||||
result.Add(new Segment(separator, context.BorderStyle));
|
||||
result.Add(Segment.LineBreak);
|
||||
}
|
||||
|
@ -47,7 +47,7 @@ namespace Spectre.Console
|
||||
ShowBorder = _table.Border.Visible;
|
||||
HasRows = Rows.Any(row => !row.IsHeader && !row.IsFooter);
|
||||
HasFooters = Rows.Any(column => column.IsFooter);
|
||||
Border = table.Border.GetSafeBorder((options.LegacyConsole || !options.Unicode) && table.UseSafeBorder);
|
||||
Border = table.Border.GetSafeBorder(!options.Unicode && table.UseSafeBorder);
|
||||
BorderStyle = table.BorderStyle ?? Style.Plain;
|
||||
|
||||
TableWidth = tableWidth;
|
||||
|
@ -91,7 +91,7 @@ namespace Spectre.Console
|
||||
}
|
||||
|
||||
var prefix = levels.Skip(1).ToList();
|
||||
var renderableLines = Segment.SplitLines(context, current.Renderable.Render(context, maxWidth - Segment.CellCount(context, prefix)));
|
||||
var renderableLines = Segment.SplitLines(current.Renderable.Render(context, maxWidth - Segment.CellCount(prefix)));
|
||||
|
||||
foreach (var (_, isFirstLine, _, line) in renderableLines.Enumerate())
|
||||
{
|
||||
@ -124,7 +124,7 @@ namespace Spectre.Console
|
||||
|
||||
private Segment GetGuide(RenderContext context, TreeGuidePart part)
|
||||
{
|
||||
var guide = Guide.GetSafeTreeGuide(context.LegacyConsole || !context.Unicode);
|
||||
var guide = Guide.GetSafeTreeGuide(safe: !context.Unicode);
|
||||
return new Segment(guide.GetPart(part), Style ?? Style.Plain);
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user