summaryrefslogtreecommitdiff
path: root/src/Editor.zig
diff options
context:
space:
mode:
authorGravatar Uko Kokņevičs2022-01-02 05:25:20 +0200
committerGravatar Uko Kokņevičs2022-01-02 05:25:20 +0200
commit963d1fa7bd2d74c951859f27e4fb01eb71a77e8d (patch)
treef8f0d360a2ad48e76531668ae12378652d03affb /src/Editor.zig
parenthierarchy changes (diff)
downloades-963d1fa7bd2d74c951859f27e4fb01eb71a77e8d.tar.gz
es-963d1fa7bd2d74c951859f27e4fb01eb71a77e8d.tar.xz
es-963d1fa7bd2d74c951859f27e4fb01eb71a77e8d.zip
Improved input
Diffstat (limited to 'src/Editor.zig')
-rw-r--r--src/Editor.zig150
1 files changed, 6 insertions, 144 deletions
diff --git a/src/Editor.zig b/src/Editor.zig
index 4b563ad..99ec932 100644
--- a/src/Editor.zig
+++ b/src/Editor.zig
@@ -6,6 +6,7 @@ const ArrayList = std.ArrayList;
6const Buffer = es.Buffer; 6const Buffer = es.Buffer;
7const Editor = @This(); 7const Editor = @This();
8const Key = es.Key; 8const Key = es.Key;
9const KeyReader = es.KeyReader;
9const KeyState = es.key_state.KeyState; 10const KeyState = es.key_state.KeyState;
10const StringBuilder = es.StringBuilder; 11const StringBuilder = es.StringBuilder;
11const StringHashMap = std.StringHashMap; 12const StringHashMap = std.StringHashMap;
@@ -23,7 +24,7 @@ statusmsg_time: i64,
23 24
24current_state: KeyState, 25current_state: KeyState,
25 26
26key_buffer: ArrayList(Key), 27key_reader: KeyReader,
27should_exit: bool, 28should_exit: bool,
28 29
29pub fn init(allocator: Allocator) !Editor { 30pub fn init(allocator: Allocator) !Editor {
@@ -41,7 +42,7 @@ pub fn init(allocator: Allocator) !Editor {
41 42
42 .current_state = es.key_state.defaultState, 43 .current_state = es.key_state.defaultState,
43 44
44 .key_buffer = ArrayList(Key).init(allocator), 45 .key_reader = KeyReader.init(allocator),
45 .should_exit = false, 46 .should_exit = false,
46 }; 47 };
47 errdefer self.deinit(); 48 errdefer self.deinit();
@@ -66,7 +67,7 @@ pub fn deinit(self: *Editor) void {
66 self.allocator.free(statusmsg); 67 self.allocator.free(statusmsg);
67 } 68 }
68 69
69 self.key_buffer.deinit(); 70 self.key_reader.deinit();
70 71
71 self.* = undefined; 72 self.* = undefined;
72} 73}
@@ -195,7 +196,7 @@ pub fn openFile(self: *Editor) !void {
195} 196}
196 197
197pub fn processKeypress(self: *Editor) !void { 198pub fn processKeypress(self: *Editor) !void {
198 const key = try self.readKey(); 199 const key = try self.key_reader.readKey();
199 try self.current_state(self, self.buffer, key); 200 try self.current_state(self, self.buffer, key);
200} 201}
201 202
@@ -220,7 +221,7 @@ pub fn promptEx(
220 221
221 // TODO: Navigation 222 // TODO: Navigation
222 // TODO: Draw the cursor 223 // TODO: Draw the cursor
223 const key = try self.readKey(); 224 const key = try self.key_reader.readKey();
224 switch (key) { 225 switch (key) {
225 Key.delete, Key.backspace => _ = buf.popOrNull(), 226 Key.delete, Key.backspace => _ = buf.popOrNull(),
226 Key.ctrl('g') => { 227 Key.ctrl('g') => {
@@ -430,142 +431,3 @@ fn parseUnsignedOptDefault(comptime T: type, buf_opt: ?[]const u8, radix: u8, de
430 return default; 431 return default;
431 } 432 }
432} 433}
433
434fn readByte(reader: std.fs.File) !?u8 {
435 var buf = [_]u8{undefined};
436 if (1 != try reader.read(&buf)) {
437 return null;
438 } else {
439 return buf[0];
440 }
441}
442
443fn readByteBlocking(reader: std.fs.File) !u8 {
444 // No we do not care about possible EOF on stdin, don't run the editor with redirected stdin.
445 var char = try readByte(reader);
446 while (char == null) : (char = try readByte(reader)) {
447 std.os.sched_yield() catch {}; // :)
448 }
449
450 return char.?;
451}
452
453fn readKey(self: *Editor) !Key {
454 if (self.key_buffer.items.len > 0) {
455 return self.key_buffer.pop();
456 }
457
458 const std_in = std.io.getStdIn();
459
460 const char1 = try readByteBlocking(std_in);
461 if (char1 != '\x1b') {
462 return Key.char(char1);
463 }
464
465 // TODO: This is a bad way of parsing.
466 const char2 = (try readByte(std_in)) orelse { return Key.escape; };
467 if (char2 == '[') {
468 const char3 = (try readByte(std_in)) orelse { return Key.meta('['); };
469 if (char3 >= '0' and char3 <= '9') {
470 const char4 = (try readByte(std_in)) orelse {
471 std.log.err("Unknown terminal sequence '^[[{c}'", .{char3});
472 try self.key_buffer.append(Key.char(char3));
473 return Key.meta('[');
474 };
475
476 if (char4 == '~') {
477 return switch (char3) {
478 '1' => Key.home,
479 '3' => Key.delete,
480 '4' => Key.end,
481 '5' => Key.page_up,
482 '6' => Key.page_down,
483 '7' => Key.home,
484 '8' => Key.end,
485 else => {
486 std.log.err("Unknown terminal sequence '^[[{c}~'", .{char3});
487 try self.key_buffer.append(Key.char('~'));
488 try self.key_buffer.append(Key.char(char3));
489 return Key.meta('[');
490 },
491 };
492 } else if (char4 == ';' and char3 == '1') {
493 const char5 = (try readByte(std_in)) orelse {
494 std.log.err("Unknown terminal sequence '^[[1;'", .{});
495 try self.key_buffer.append(Key.char(';'));
496 try self.key_buffer.append(Key.char('1'));
497 return Key.meta('[');
498 };
499
500 if (char5 == '5') {
501 const char6 = (try readByte(std_in)) orelse {
502 std.log.err("Unknown terminal sequence '^[[1;5'", .{});
503 try self.key_buffer.append(Key.char('5'));
504 try self.key_buffer.append(Key.char(';'));
505 try self.key_buffer.append(Key.char('1'));
506 return Key.meta('[');
507 };
508
509 return switch (char6) {
510 'A' => Key.ctrl_up,
511 'B' => Key.ctrl_down,
512 'C' => Key.ctrl_right,
513 'D' => Key.ctrl_left,
514 'F' => Key.ctrl_end,
515 'H' => Key.ctrl_home,
516 else => {
517 std.log.err("Unknown terminal sequence '^[[1;5{c}'", .{char6});
518 try self.key_buffer.append(Key.char(char6));
519 try self.key_buffer.append(Key.char('5'));
520 try self.key_buffer.append(Key.char(';'));
521 try self.key_buffer.append(Key.char('1'));
522 return Key.meta('[');
523 },
524 };
525 } else {
526 std.log.err("Unknown terminal sequence '^[[1;{c}'", .{char5});
527 try self.key_buffer.append(Key.char(char5));
528 try self.key_buffer.append(Key.char(';'));
529 try self.key_buffer.append(Key.char('1'));
530 return Key.meta('[');
531 }
532 } else {
533 std.log.err("Unknown terminal sequence '^[[{c}{c}'", .{char3, char4});
534 try self.key_buffer.append(Key.char(char4));
535 try self.key_buffer.append(Key.char(char3));
536 return Key.meta('[');
537 }
538 } else {
539 return switch (char3) {
540 'A' => Key.up,
541 'B' => Key.down,
542 'C' => Key.right,
543 'D' => Key.left,
544 'F' => Key.end,
545 'H' => Key.home,
546 else => {
547 std.log.err("Unknown terminal sequence '^[[{c}'", .{char3});
548 try self.key_buffer.append(Key.char(char3));
549 return Key.meta('[');
550 },
551 };
552 }
553 } else if (char2 == 'O') {
554 const char3 = (try readByte(std_in)) orelse { return Key.meta('O'); };
555 return switch (char3) {
556 'F' => Key.end,
557 'H' => Key.home,
558 else => {
559 std.log.err("Unknown terminal sequence '^[O{c}'", .{char3});
560 try self.key_buffer.append(Key.char(char3));
561 return Key.meta('O');
562 },
563 };
564 } else {
565 return Key.meta(char2);
566 }
567}
568// C-<page up> = ^[[5;5~
569// C-<page down> = ^[[6;5
570
571// S- adds ;2, M- adds ;3, S-M- adds ;4, C- adds ;5, S-C- adds ;6, M-C- adds ;7, S-M-C- adds ;8