Fix raw terminal line rendering

This commit is contained in:
slhx agent
2026-06-21 16:37:10 +02:00
parent 629605bcdc
commit f88f688726
+38 -1
View File
@@ -363,7 +363,17 @@ fn readEditorInputAlloc(allocator: std.mem.Allocator, stdin: *std.Io.Reader) !?[
fn renderLocalFrame(allocator: std.mem.Allocator, io: std.Io, stdout: std.Io.File, client: *tui.Client, path: []const u8, is_dir: bool, interactive: bool) !void { fn renderLocalFrame(allocator: std.mem.Allocator, io: std.Io, stdout: std.Io.File, client: *tui.Client, path: []const u8, is_dir: bool, interactive: bool) !void {
const frame = try client.render(allocator); const frame = try client.render(allocator);
defer allocator.free(frame); defer allocator.free(frame);
if (interactive) try stdout.writeStreamingAll(io, "\x1b[H\x1b[2J"); if (interactive) {
try stdout.writeStreamingAll(io, "\x1b[H\x1b[2J");
try writeTerminalText(allocator, io, stdout, frame);
try writeTerminalText(allocator, io, stdout, "\n\n");
try writeTerminalText(allocator, io, stdout, "mim opened: ");
try writeTerminalText(allocator, io, stdout, path);
try writeTerminalText(allocator, io, stdout, if (is_dir)
"\nDirectory browser. Space opens commands; o/Enter opens panel items where available; q quits when clean.\n"
else
"\nEditor starts in insert mode. Esc or Space n enters normal mode; Space commands work in normal mode; Space w saves; Space q quits when clean.\n");
} else {
try stdout.writeStreamingAll(io, frame); try stdout.writeStreamingAll(io, frame);
try stdout.writeStreamingAll(io, "\n\n"); try stdout.writeStreamingAll(io, "\n\n");
try stdout.writeStreamingAll(io, "mim opened: "); try stdout.writeStreamingAll(io, "mim opened: ");
@@ -373,6 +383,27 @@ fn renderLocalFrame(allocator: std.mem.Allocator, io: std.Io, stdout: std.Io.Fil
else else
"\nEditor starts in insert mode. Esc or Space n enters normal mode; Space commands work in normal mode; Space w saves; Space q quits when clean.\n"); "\nEditor starts in insert mode. Esc or Space n enters normal mode; Space commands work in normal mode; Space w saves; Space q quits when clean.\n");
} }
}
fn writeTerminalText(allocator: std.mem.Allocator, io: std.Io, stdout: std.Io.File, bytes: []const u8) !void {
const converted = try terminalCrlfAlloc(allocator, bytes);
defer allocator.free(converted);
try stdout.writeStreamingAll(io, converted);
}
fn terminalCrlfAlloc(allocator: std.mem.Allocator, bytes: []const u8) ![]u8 {
var out = std.ArrayList(u8).empty;
errdefer out.deinit(allocator);
var start: usize = 0;
for (bytes, 0..) |byte, i| {
if (byte != '\n') continue;
if (start < i) try out.appendSlice(allocator, bytes[start..i]);
try out.appendSlice(allocator, "\r\n");
start = i + 1;
}
if (start < bytes.len) try out.appendSlice(allocator, bytes[start..]);
return out.toOwnedSlice(allocator);
}
fn printLocalContext(allocator: std.mem.Allocator, io: std.Io, args: *std.process.Args.Iterator, stdout: std.Io.File) !void { fn printLocalContext(allocator: std.mem.Allocator, io: std.Io, args: *std.process.Args.Iterator, stdout: std.Io.File) !void {
const task = args.next(); const task = args.next();
@@ -568,3 +599,9 @@ test "regular: local editor client exposes save and dirty quit guards" {
client.clearQuit(); client.clearQuit();
try std.testing.expect(!client.requestedQuit()); try std.testing.expect(!client.requestedQuit());
} }
test "regular: raw terminal output converts newline to carriage-return newline" {
const converted = try terminalCrlfAlloc(std.testing.allocator, "a\nb\n");
defer std.testing.allocator.free(converted);
try std.testing.expectEqualStrings("a\r\nb\r\n", converted);
}