1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
|
const std = @import("std");
const Buffer = @import("Buffer.zig");
const Editor = @import("Editor.zig");
const Key = @import("key.zig").Key;
const search = @import("search.zig").search;
pub const Error = error{
MalformedConfig,
MisformedTerminalResponse,
StreamTooLong,
} ||
std.mem.Allocator.Error ||
std.fmt.ParseIntError ||
std.fs.File.OpenError ||
std.fs.File.ReadError ||
std.fs.File.WriteError ||
std.os.SchedYieldError;
pub const KeyState = fn(*Editor, *Buffer, Key) Error!void;
pub fn mgState(editor: *Editor, buf: *Buffer, key: Key) Error!void {
editor.current_state = defaultState;
editor.clearStatusMessage();
switch (key) {
// ========== <*> ==========
Key.char('g') => try buf.goToLine(editor),
else => try editor.setStatusMessage("Unknown chord: M-g {}", .{key}),
}
}
pub fn cxState(editor: *Editor, buf: *Buffer, key: Key) Error!void {
editor.current_state = defaultState;
editor.clearStatusMessage();
switch (key) {
// ========== C-<*> ==========
Key.ctrl('b') => try editor.switchBuffer(),
Key.ctrl('c') => try editor.saveBuffersExit(),
Key.ctrl('f') => try editor.openFile(),
Key.ctrl('g') => {},
Key.ctrl('s') => try buf.save(editor),
// ========== <*> ==========
Key.char('k') => _ = try editor.killCurrentBuffer(),
else => try editor.setStatusMessage("Unknown chord: C-x {}", .{key}),
}
}
pub fn defaultState(editor: *Editor, buf: *Buffer, key: Key) Error!void {
switch (key) {
// ========== M-C-<*> ==========
Key.metaCtrl('d'), Key.backspace => try buf.backwardDeleteChar(),
// ========== M-<*> ==========
Key.meta('g') => {
editor.current_state = mgState;
try editor.setStatusMessage("M-g-", .{});
},
Key.meta('v'), Key.page_up => buf.pageUp(editor.screenrows),
// ========== C-<*> ==========
Key.ctrl('a'), Key.home => buf.moveBeginningOfLine(),
Key.ctrl('b'), Key.left => buf.backwardChar(),
Key.ctrl('d'), Key.delete => try buf.deleteChar(),
Key.ctrl('e'), Key.end => buf.moveEndOfLine(),
Key.ctrl('f'), Key.right => buf.forwardChar(),
Key.ctrl('g') => editor.clearStatusMessage(),
// TODO: C-h help
// line feed
Key.ctrl('j') => try buf.insertNewline(),
Key.ctrl('k') => try buf.killLine(),
Key.ctrl('l') => {
try editor.refreshWindowSize();
buf.recenterTopBottom(editor.screenrows);
},
// carriage return
Key.ctrl('m') => try buf.insertNewline(),
Key.ctrl('n'), Key.down => buf.nextLine(),
Key.ctrl('p'), Key.up => buf.previousLine(),
Key.ctrl('s') => try search(editor, buf),
// TODO: C-q quotedInsert
Key.ctrl('v'), Key.page_down => buf.pageDown(editor.screenrows),
Key.ctrl('x') => {
editor.current_state = cxState;
try editor.setStatusMessage("C-x-", .{});
},
// ========== <*> ==========
else => {
if (@enumToInt(key) <= @enumToInt(Key.max_char)) {
const char = @intCast(u8, @enumToInt(key));
if (std.ascii.isGraph(char) or std.ascii.isSpace(char)) {
try buf.insertChar(char);
return;
}
}
try editor.setStatusMessage("Unknown key: {}", .{key});
},
}
}
|