Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions src/Directory.Packages.props
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,9 @@
<PackageVersion Include="RabbitMQ.Client" Version="7.0.0" />
<PackageVersion Include="RavenDB.Client" Version="7.0.0" />
<PackageVersion Include="Snapshooter.Xunit" Version="0.5.4" />
<PackageVersion Include="Spectre.Console.Json" Version="0.52.0" />
<PackageVersion Include="Spectre.Console" Version="0.52.0" />
<PackageVersion Include="Spectre.Console.Testing" Version="0.52.0" />
<PackageVersion Include="Spectre.Console.Json" Version="0.55.2" />
<PackageVersion Include="Spectre.Console" Version="0.55.2" />
<PackageVersion Include="Spectre.Console.Testing" Version="0.55.2" />
<PackageVersion Include="sqlite-net-pcl" Version="1.9.172" />
<PackageVersion Include="SQLitePCLRaw.bundle_green" Version="2.1.11" />
<PackageVersion Include="Squadron.AzureStorage" Version="1.0.1" />
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ private static async Task<int> ExecuteAsync(
Opt<ApiPathOption>.Instance,
ct);

if (!pathResult.StartsWith('/'))
{
throw new ExitException($"The path '{pathResult.EscapeMarkup()}' is invalid. It must start with '/'.");
}

var path = pathResult.Split("/", TrimEntries | RemoveEmptyEntries);

var kind = GetApiKind(parseResult);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,7 @@ private Table CreateTable()

ctx.UpdateTarget(new Rows(
title,
CreateTable()
.Centered()
.AddRows(SelectedIndex, Items.Select(CreateRow)),
Align.Center(CreateTable().AddRows(SelectedIndex, Items.Select(CreateRow))),
Align.Center(new Rows(columns))));

ctx.Refresh();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ internal sealed class ActivityTree : Renderable
private readonly List<ActivityEntry> _rootEntries = [];
private readonly Spinner _spinner = Spinner.Known.Default;

public bool EmitLivePadding { get; set; } = true;

public ActivityEntry AddRoot(string text)
{
lock (_lock)
Expand Down Expand Up @@ -92,13 +94,15 @@ protected override IEnumerable<Segment> Render(RenderOptions options, int maxWid
RenderEntry(segments, root, parentPrefix: "", NodePosition.Root, options, maxWidth);
}

// Workaround for a Spectre.Console bug: LiveRenderable.PositionCursor emits
// `CSI 0 A` when the rendered shape is one line tall, and most terminals treat
// that as `CSI 1 A` (move cursor up one row) per ECMA-48 default-parameter
// handling. The result is that a single-line tree drifts up one row on every
// refresh and overwrites previously-printed output. Forcing the shape to be at
// least two lines tall keeps Spectre on the `CursorUp(n>=1)` path.
segments.Add(Segment.LineBreak);
// Workaround for a Spectre.Console bug (issue #2076): LiveRenderable.PositionCursor
// emits `CSI 0 A` when the rendered shape is one line tall, and most terminals treat
// that as `CSI 1 A` (move cursor up one row) per ECMA-48 default-parameter handling.
// Forcing the shape to be at least two lines tall keeps Spectre on the
// `CursorUp(n>=1)` path. Only needed while the tree is rendered through Live.
if (EmitLivePadding)
{
segments.Add(Segment.LineBreak);
}

return segments;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ private async Task RunAsync()
{
await _console
.Live(_tree)
.AutoClear(false)
.AutoClear(true)
.Overflow(VerticalOverflow.Visible)
.StartAsync(async ctx =>
{
Expand All @@ -73,10 +73,11 @@ await _console
ctx.Refresh();
});

// ActivityTree pads its output with a trailing blank line to work around a
// Spectre.Console bug (see ActivityTree.Render). After Live completes, Spectre
// has left the cursor one row below that padding. Step back onto the padded
// row so subsequent output overwrites it instead of leaving a visible gap.
_console.Cursor.Move(CursorDirection.Up, 1);
// Live cleared its rendered region. Re-emit the final tree state as a plain
// renderable so it lands in scrollback as normal output. This avoids relying
// on cursor math to merge live output with subsequent stdout/stderr writes,
// which was the source of rendering bleed on Windows terminals.
_tree.EmitLivePadding = false;
_console.Write(_tree);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,20 @@ public void Write(IRenderable renderable)
+ "Check the documentation of the command to see all options");
}

public void WriteAnsi(Action<AnsiWriter> action)
{
if (IsHumanReadable)
{
_hasWrittenOutput = true;
outConsole.WriteAnsi(action);
return;
}

throw new ExitException(
"Console runs in non interactive mode, yet a user interaction was attempted. "
+ "Check the documentation of the command to see all options");
}

public Profile Profile => outConsole.Profile;

public IAnsiConsoleCursor Cursor => outConsole.Cursor;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -476,6 +476,28 @@ Creating API 'my-api'
""");
}

[Theory]
[InlineData("products")]
[InlineData("C:/Program Files/Git/test")]
public async Task Create_Should_ReturnError_When_PathDoesNotStartWithSlash(string path)
{
// arrange
SetupSessionWithWorkspace();

// act
var result = await ExecuteCommandAsync(
"api",
"create",
"--name",
ApiName,
"--path",
path);

// assert
result.AssertError(
$"The path '{path}' is invalid. It must start with '/'.");
}

[Fact]
public async Task Create_Should_ReturnSuccess_When_KindNotProvided()
{
Expand Down
Loading