summaryrefslogtreecommitdiff
path: root/src/key_state.zig
blob: 19177cfaa307efa50884f1cfb614d3f2f252b6d8 (plain) (blame)
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});
        },
    }
}