summaryrefslogtreecommitdiff
path: root/src/input_handler.hh
blob: 036633dc22f38f196f6273761e63f8094a0f3d49 (plain)
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
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
#ifndef input_handler_hh_INCLUDED
#define input_handler_hh_INCLUDED

#include "completion.hh"
#include "context.hh"
#include "face.hh"
#include "normal.hh"
#include "keys.hh"
#include "string.hh"
#include "utils.hh"
#include "user_interface.hh"
#include "safe_ptr.hh"

namespace Kakoune
{

enum class MenuEvent
{
    Select,
    Abort,
    Validate
};
using MenuCallback = std::function<void (int, MenuEvent, Context&)>;

enum class PromptEvent
{
    Change,
    Abort,
    Validate
};
using PromptCallback = std::function<void (StringView, PromptEvent, Context&)>;
using KeyCallback = std::function<void (Key, Context&)>;

class InputMode;
class DisplayLine;
enum class InsertMode : unsigned;
enum class KeymapMode : char;

class InputHandler : public SafeCountable
{
public:
    InputHandler(SelectionList selections,
                 Context::Flags flags = Context::Flags::None,
                 String name = "");
    ~InputHandler();

    // switch to insert mode
    void insert(InsertMode mode);
    // repeat last insert mode key sequence
    void repeat_last_insert();

    // enter prompt mode, callback is called on each change,
    // abort or validation with corresponding PromptEvent value
    // returns to normal mode after validation if callback does
    // not change the mode itself
    void prompt(StringView prompt, String initstr,
                Face prompt_face, Completer completer,
                PromptCallback callback);
    void set_prompt_face(Face prompt_face);

    // enter menu mode, callback is called on each selection change,
    // abort or validation with corresponding MenuEvent value
    // returns to normal mode after validation if callback does
    // not change the mode itself
    void menu(ConstArrayView<DisplayLine> choices, MenuCallback callback);

    // execute callback on next keypress and returns to normal mode
    // if callback does not change the mode itself
    void on_next_key(KeymapMode mode, KeyCallback callback);

    // process the given key
    void handle_key(Key key);

    void start_recording(char reg);
    bool is_recording() const;
    void stop_recording();
    char recording_reg() const { return m_recording_reg; }

    void reset_normal_mode();

    Context& context() { return m_context; }
    const Context& context() const { return m_context; }

    DisplayLine mode_line() const;

private:
    Context m_context;

    friend class InputMode;
    Vector<std::unique_ptr<InputMode>> m_mode_stack;

    InputMode& current_mode() const { return *m_mode_stack.back(); }

    void push_mode(InputMode* new_mode);
    std::unique_ptr<InputMode> pop_mode(InputMode* current_mode);

    struct Insertion{ InsertMode mode; Vector<Key> keys; };
    Insertion m_last_insert = {InsertMode::Insert, {}};

    char   m_recording_reg = 0;
    String m_recorded_keys;

    int    m_handle_key_level = 0;
};

enum class AutoInfo
{
    None = 0,
    Command = 1 << 0,
    OnKey   = 1 << 1,
    Normal  = 1 << 2
};

template<>
struct WithBitOps<AutoInfo> : std::true_type {};

constexpr Array<EnumDesc<AutoInfo>, 3> enum_desc(AutoInfo)
{
    return { {
        { AutoInfo::Command, "command"},
        { AutoInfo::OnKey, "onkey"},
        { AutoInfo::Normal, "normal" }
    } };
}

bool show_auto_info_ifn(StringView title, StringView info, AutoInfo mask, const Context& context);

template<typename Cmd>
void on_next_key_with_autoinfo(const Context& context, KeymapMode keymap_mode, Cmd cmd,
                               StringView title, StringView info)
{
    const bool hide = show_auto_info_ifn(title, info, AutoInfo::OnKey, context);
    context.input_handler().on_next_key(
        keymap_mode, [hide,cmd](Key key, Context& context) mutable {
            if (hide)
                context.ui().info_hide();
            cmd(key, context);
    });
}
}

#endif // input_handler_hh_INCLUDED