Fix terminal input mode and cursor rendering
This commit is contained in:
+38
-15
@@ -236,18 +236,12 @@ fn runLocalEditor(
|
||||
return;
|
||||
}
|
||||
|
||||
client.enterInsertMode();
|
||||
|
||||
var raw_terminal = try RawTerminal.enable(stdin_file.handle);
|
||||
defer raw_terminal.restore();
|
||||
|
||||
var stdin_buffer: [4096]u8 = undefined;
|
||||
var stdin_reader = stdin_file.readerStreaming(io, &stdin_buffer);
|
||||
const stdin = &stdin_reader.interface;
|
||||
|
||||
while (true) {
|
||||
try renderLocalFrame(allocator, io, stdout, client, path, is_dir, true);
|
||||
const raw = try readEditorInputAlloc(allocator, stdin);
|
||||
const raw = try readEditorInputFdAlloc(allocator, stdin_file.handle);
|
||||
defer if (raw) |bytes| allocator.free(bytes);
|
||||
if (raw == null) return;
|
||||
|
||||
@@ -276,9 +270,9 @@ fn runLocalEditor(
|
||||
} else |_| {}
|
||||
|
||||
if (client.requestedQuit()) {
|
||||
if (dirty) {
|
||||
if (dirty and !client.requestedDiscardQuit()) {
|
||||
client.clearQuit();
|
||||
client.setStatusMessage("dirty buffer: Space w saves, quit blocked");
|
||||
client.setStatusMessage("dirty buffer: Space w saves, Space Q discards");
|
||||
continue;
|
||||
}
|
||||
return;
|
||||
@@ -333,7 +327,31 @@ const RawTerminal = struct {
|
||||
}
|
||||
};
|
||||
|
||||
fn readEditorInputAlloc(allocator: std.mem.Allocator, stdin: *std.Io.Reader) !?[]u8 {
|
||||
fn readEditorInputFdAlloc(allocator: std.mem.Allocator, fd: std.posix.fd_t) !?[]u8 {
|
||||
var one: [1]u8 = undefined;
|
||||
const n = try std.posix.read(fd, &one);
|
||||
if (n == 0) return null;
|
||||
var bytes = std.ArrayList(u8).empty;
|
||||
errdefer bytes.deinit(allocator);
|
||||
try bytes.append(allocator, one[0]);
|
||||
if (one[0] != 0x1b) return try bytes.toOwnedSlice(allocator);
|
||||
|
||||
var fds = [_]std.posix.pollfd{.{ .fd = fd, .events = std.posix.POLL.IN, .revents = 0 }};
|
||||
const ready = std.posix.poll(&fds, 30) catch 0;
|
||||
if (ready == 0 or (fds[0].revents & std.posix.POLL.IN) == 0) return try bytes.toOwnedSlice(allocator);
|
||||
const second_n = try std.posix.read(fd, &one);
|
||||
if (second_n == 0) return try bytes.toOwnedSlice(allocator);
|
||||
try bytes.append(allocator, one[0]);
|
||||
if (one[0] == '[') {
|
||||
const third_ready = std.posix.poll(&fds, 30) catch 0;
|
||||
if (third_ready == 0 or (fds[0].revents & std.posix.POLL.IN) == 0) return try bytes.toOwnedSlice(allocator);
|
||||
const third_n = try std.posix.read(fd, &one);
|
||||
if (third_n != 0) try bytes.append(allocator, one[0]);
|
||||
}
|
||||
return try bytes.toOwnedSlice(allocator);
|
||||
}
|
||||
|
||||
fn readEditorInputAlloc(allocator: std.mem.Allocator, stdin: *std.Io.Reader, fd: std.posix.fd_t) !?[]u8 {
|
||||
const first = stdin.takeByte() catch |err| switch (err) {
|
||||
error.EndOfStream => return null,
|
||||
else => return err,
|
||||
@@ -343,9 +361,14 @@ fn readEditorInputAlloc(allocator: std.mem.Allocator, stdin: *std.Io.Reader) !?[
|
||||
try bytes.append(allocator, first);
|
||||
|
||||
if (first == 0x1b) {
|
||||
var fds = [_]std.posix.pollfd{.{ .fd = fd, .events = std.posix.POLL.IN, .revents = 0 }};
|
||||
const ready: usize = if (fd < 0) 1 else std.posix.poll(&fds, 30) catch 0;
|
||||
if (ready == 0 or (fd >= 0 and (fds[0].revents & std.posix.POLL.IN) == 0)) return try bytes.toOwnedSlice(allocator);
|
||||
const second = stdin.takeByte() catch return try bytes.toOwnedSlice(allocator);
|
||||
try bytes.append(allocator, second);
|
||||
if (second == '[') {
|
||||
const third_ready: usize = if (fd < 0) 1 else std.posix.poll(&fds, 30) catch 0;
|
||||
if (third_ready == 0 or (fd >= 0 and (fds[0].revents & std.posix.POLL.IN) == 0)) return try bytes.toOwnedSlice(allocator);
|
||||
const third = stdin.takeByte() catch return try bytes.toOwnedSlice(allocator);
|
||||
try bytes.append(allocator, third);
|
||||
}
|
||||
@@ -373,7 +396,7 @@ fn renderLocalFrame(allocator: std.mem.Allocator, io: std.Io, stdout: std.Io.Fil
|
||||
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");
|
||||
"\nEditor starts in normal mode. Press i to insert; Space commands work in normal mode; Space w saves; Space q quits when clean; Space Q discards dirty changes.\n");
|
||||
} else {
|
||||
try stdout.writeStreamingAll(io, frame);
|
||||
try stdout.writeStreamingAll(io, "\n\n");
|
||||
@@ -382,7 +405,7 @@ fn renderLocalFrame(allocator: std.mem.Allocator, io: std.Io, stdout: std.Io.Fil
|
||||
try stdout.writeStreamingAll(io, 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");
|
||||
"\nEditor starts in normal mode. Press i to insert; Space commands work in normal mode; Space w saves; Space q quits when clean; Space Q discards dirty changes.\n");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -545,17 +568,17 @@ test "regular: positional path opens file directory or new buffer" {
|
||||
|
||||
test "regular: local editor input reader preserves text utf8 and arrows" {
|
||||
var ascii = std.Io.Reader.fixed("a");
|
||||
const ascii_event = (try readEditorInputAlloc(std.testing.allocator, &ascii)).?;
|
||||
const ascii_event = (try readEditorInputAlloc(std.testing.allocator, &ascii, -1)).?;
|
||||
defer std.testing.allocator.free(ascii_event);
|
||||
try std.testing.expectEqualStrings("a", ascii_event);
|
||||
|
||||
var utf8 = std.Io.Reader.fixed("é");
|
||||
const utf8_event = (try readEditorInputAlloc(std.testing.allocator, &utf8)).?;
|
||||
const utf8_event = (try readEditorInputAlloc(std.testing.allocator, &utf8, -1)).?;
|
||||
defer std.testing.allocator.free(utf8_event);
|
||||
try std.testing.expectEqualStrings("é", utf8_event);
|
||||
|
||||
var arrow = std.Io.Reader.fixed("\x1b[D");
|
||||
const arrow_event = (try readEditorInputAlloc(std.testing.allocator, &arrow)).?;
|
||||
const arrow_event = (try readEditorInputAlloc(std.testing.allocator, &arrow, -1)).?;
|
||||
defer std.testing.allocator.free(arrow_event);
|
||||
try std.testing.expectEqualStrings("\x1b[D", arrow_event);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user