summaryrefslogtreecommitdiff
path: root/src/parameters_parser.hh
blob: 8cbaf0fd2f55084a0644702a4f173b2a35ff16a9 (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
#ifndef parameters_parser_hh_INCLUDED
#define parameters_parser_hh_INCLUDED

#include "exception.hh"
#include "hash_map.hh"
#include "meta.hh"
#include "array_view.hh"
#include "optional.hh"
#include "string.hh"
#include "string_utils.hh"

namespace Kakoune
{

using ParameterList = ConstArrayView<String>;

struct parameter_error : public runtime_error
{
    using runtime_error::runtime_error;
};

struct unknown_option : public parameter_error
{
    unknown_option(StringView name)
        : parameter_error(format("unknown option '{}'", name)) {}
};

struct missing_option_value: public parameter_error
{
    missing_option_value(StringView name)
        : parameter_error(format("missing value for option '{}'", name)) {}
};

struct wrong_argument_count : public parameter_error
{
    wrong_argument_count() : parameter_error("wrong argument count") {}
};

struct SwitchDesc
{
    bool takes_arg;
    String description;
};

using SwitchMap = HashMap<String, SwitchDesc, MemoryDomain::Commands>;

String generate_switches_doc(const SwitchMap& opts);

struct ParameterDesc
{
    enum class Flags
    {
        None = 0,
        SwitchesOnlyAtStart = 1,
        SwitchesAsPositional = 2,
    };
    friend constexpr bool with_bit_ops(Meta::Type<Flags>) { return true; }

    SwitchMap switches;
    Flags flags = Flags::None;
    size_t min_positionals = 0;
    size_t max_positionals = -1;
};

// ParametersParser provides tools to parse command parameters.
// There are 3 types of parameters:
//  * unnamed options, which are accessed by position (ignoring named ones)
//  * named boolean options, which are enabled using '-name' syntax
//  * named string options,  which are defined using '-name value' syntax
struct ParametersParser
{
    // the options defines named options, if they map to true, then
    // they are understood as string options, else they are understood as
    // boolean option.
    ParametersParser(ParameterList params, const ParameterDesc& desc);

    // Return a valid optional if the switch was given, with
    // a non empty StringView value if the switch took an argument.
    Optional<StringView> get_switch(StringView name) const;

    struct iterator : std::iterator<std::forward_iterator_tag, String>
    {
        iterator(const ParametersParser& parser, size_t index)
            : m_parser(parser), m_index(index) {}

        const String& operator*() const { return m_parser[m_index]; }
        const String* operator->() const { return &m_parser[m_index]; }

        iterator& operator++() { ++m_index; return *this; }
        iterator operator++(int) { auto copy = *this; ++m_index; return copy; }

        bool operator==(const iterator& other) const
        {
            kak_assert(&m_parser == &other.m_parser);
            return m_index == other.m_index;
        }

        bool operator!=(const iterator& other) const
        {
            return not (*this == other);
        }

    private:
        const ParametersParser& m_parser;
        size_t                  m_index;
    };

    // positional parameters count
    size_t positional_count() const { return m_positional_indices.size(); }

    // access positional parameter by index
    const String& operator[] (size_t index) const
    {
        kak_assert(index < positional_count());
        return m_params[m_positional_indices[index]];
    }

    iterator begin() const { return iterator(*this, 0); }
    iterator end() const { return iterator(*this, m_positional_indices.size()); }

private:
    ParameterList m_params;
    Vector<size_t, MemoryDomain::Commands> m_positional_indices;
    const ParameterDesc& m_desc;
};

}

#endif // parameters_parser_hh_INCLUDED