const es = @import("root"); const std = @import("std"); const Buffer = es.Buffer; const Editor = es.Editor; const Key = es.Key; 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.GetCwdError || std.os.RealPathError; pub const KeyState = fn (*Editor, *Buffer, Key) Error!void; 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 => { std.log.debug("Unknown chord: M-g {}", .{key}); try editor.setStatusMessage("Unknown chord: M-g {}", .{key}); }, } } fn mOState(editor: *Editor, buf: *Buffer, key: Key) Error!void { editor.current_state = defaultState; editor.clearStatusMessage(); switch (key) { // ========== <*> ========== Key.char('F') => buf.moveEndOfLine(), Key.char('H') => buf.moveBeginningOfLine(), else => { std.log.debug("Unknown chord: M-O {}", .{key}); try editor.setStatusMessage("Unknown chord: M-O {}", .{key}); }, } } fn cxState(editor: *Editor, buf: *Buffer, key: Key) Error!void { editor.current_state = defaultState; editor.clearStatusMessage(); switch (key) { // ========== C-<*> ========== Key.ctrl('b'), Key.char('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 => { std.log.debug("Unknown chord: C-x {}", .{key}); try editor.setStatusMessage("Unknown chord: C-x {}", .{key}); }, } } pub fn defaultState(editor: *Editor, buf: *Buffer, key: Key) Error!void { switch (key) { // ========== M-C-<*> ========== Key.meta(Key.ctrl('d')), Key.backspace => try buf.backwardDeleteChar(), // ========== M-<*> ========== Key.meta('g') => { editor.current_state = mgState; try editor.setStatusMessage("M-g-", .{}); }, Key.meta('O') => editor.current_state = mOState, 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 // tab Key.ctrl('i') => try buf.insertTab(), // 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 es.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; } } std.log.debug("Unknown key: {}", .{key}); try editor.setStatusMessage("Unknown key: {}", .{key}); }, } }