summaryrefslogtreecommitdiff
path: root/src/command_manager.hh
blob: affec4e3bdb53174af71222e2eb9ed2f8e7c21a4 (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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
#ifndef command_manager_hh_INCLUDED
#define command_manager_hh_INCLUDED

#include "coord.hh"
#include "completion.hh"
#include "array_view.hh"
#include "shell_manager.hh"
#include "parameters_parser.hh"
#include "string.hh"
#include "optional.hh"
#include "utils.hh"
#include "hash_map.hh"

#include <functional>
#include <initializer_list>

namespace Kakoune
{

class Context;
using CommandParameters = ConstArrayView<String>;
using CommandFunc = std::function<void (const ParametersParser& parser,
                                        Context& context,
                                        const ShellContext& shell_context)>;

using CommandCompleter = std::function<Completions (const Context& context,
                                                    CompletionFlags,
                                                    CommandParameters,
                                                    size_t, ByteCount)>;

using CommandHelper = std::function<String (const Context& context, CommandParameters)>;

enum class CommandFlags
{
    None   = 0,
    Hidden = 1,
};
constexpr bool with_bit_ops(Meta::Type<CommandFlags>) { return true; }

struct CommandInfo { String name, info; };

struct Token
{
    enum class Type
    {
        Raw,
        RawQuoted,
        RawEval,
        ShellExpand,
        RegisterExpand,
        OptionExpand,
        ValExpand,
        ArgExpand,
        FileExpand,
        CommandSeparator
    };

    Type type;
    ByteCount pos;
    BufferCoord coord;
    String content;
};

struct Reader
{
public:
    Reader(StringView s) : str{s}, pos{s.begin()}, line_start{s.begin()}, line{} {}

    Codepoint operator*() const;
    Codepoint peek_next() const;
    Reader& operator++();
    void next_byte();

    explicit operator bool() const { return pos < str.end(); }
    StringView substr_from(const char* start) const { return {start, pos}; }
    BufferCoord coord() const { return {line, (int)(pos - line_start)}; }

    StringView str;
    const char* pos;
    const char* line_start;
    LineCount line;
};

class CommandParser
{
public:
    CommandParser(StringView command_line);
    Optional<Token> read_token(bool throw_on_unterminated);

    const char* pos() const { return m_reader.pos; }
    BufferCoord coord() const { return m_reader.coord(); }
    bool done() const { return not m_reader; }

private:
    Reader m_reader;
};

class CommandManager : public Singleton<CommandManager>
{
public:
    void execute(StringView command_line, Context& context,
                 const ShellContext& shell_context = ShellContext{});

    void execute_single_command(CommandParameters params,
                                Context& context,
                                const ShellContext& shell_context,
                                BufferCoord pos = {});


    Completions complete(const Context& context, CompletionFlags flags,
                         StringView command_line, ByteCount cursor_pos);

    Completions complete(const Context& context, CompletionFlags flags,
                         CommandParameters params,
                         size_t token_to_complete, ByteCount pos_in_token);

    Optional<CommandInfo> command_info(const Context& context,
                                       StringView command_line) const;

    bool command_defined(StringView command_name) const;

    void register_command(String command_name, CommandFunc func,
                          String docstring,
                          ParameterDesc param_desc,
                          CommandFlags flags = CommandFlags::None,
                          CommandHelper helper = CommandHelper(),
                          CommandCompleter completer = CommandCompleter());

    Completions complete_command_name(const Context& context, StringView query) const;

    void clear_last_complete_command() { m_last_complete_command = String{}; }

    bool module_defined(StringView module_name) const;

    void register_module(String module_name, String commands);

    void load_module(StringView module_name, Context& context);

    Completions complete_module_name(StringView query) const;

private:
    struct Command
    {
        CommandFunc func;
        String docstring;
        ParameterDesc param_desc;
        CommandFlags flags;
        CommandHelper helper;
        CommandCompleter completer;
    };
    using CommandMap = HashMap<String, Command, MemoryDomain::Commands>;
    CommandMap m_commands;
    String m_last_complete_command;
    int m_command_depth = 0;

    struct Module
    {
        bool loaded;
        String commands;
    };
    using ModuleMap = HashMap<String, Module, MemoryDomain::Commands>;
    ModuleMap m_modules;

    CommandMap::const_iterator find_command(const Context& context,
                                            StringView name) const;
};

String expand(StringView str, const Context& context,
              const ShellContext& shell_context = ShellContext{});

String expand(StringView str, const Context& context,
              const ShellContext& shell_context,
              const FunctionRef<String (String)>& postprocess);

}

#endif // command_manager_hh_INCLUDED