1 #ifndef parameters_parser_hh_INCLUDED 2 #define parameters_parser_hh_INCLUDED 3 4 #include "exception.hh" 5 #include "hash_map.hh" 6 #include "meta.hh" 7 #include "array_view.hh" 8 #include "optional.hh" 9 #include "flags.hh" 10 #include "string.hh" 11 #include "string_utils.hh" 12 13 namespace Kakoune 14 { 15 16 using ParameterList = ConstArrayView<String>; 17 18 struct parameter_error : public runtime_error 19 { 20 using runtime_error::runtime_error; 21 }; 22 23 struct unknown_option : public parameter_error 24 { unknown_optionKakoune::unknown_option25 unknown_option(StringView name) 26 : parameter_error(format("unknown option '{}'", name)) {} 27 }; 28 29 struct missing_option_value: public parameter_error 30 { missing_option_valueKakoune::missing_option_value31 missing_option_value(StringView name) 32 : parameter_error(format("missing value for option '{}'", name)) {} 33 }; 34 35 struct wrong_argument_count : public parameter_error 36 { wrong_argument_countKakoune::wrong_argument_count37 wrong_argument_count() : parameter_error("wrong argument count") {} 38 }; 39 40 struct SwitchDesc 41 { 42 bool takes_arg; 43 String description; 44 }; 45 46 using SwitchMap = HashMap<String, SwitchDesc, MemoryDomain::Commands>; 47 48 String generate_switches_doc(const SwitchMap& opts); 49 50 struct ParameterDesc 51 { 52 enum class Flags 53 { 54 None = 0, 55 SwitchesOnlyAtStart = 0b0001, 56 SwitchesAsPositional = 0b0010, 57 IgnoreUnknownSwitches = 0b0100 58 }; with_bit_ops(Meta::Type<Flags>)59 friend constexpr bool with_bit_ops(Meta::Type<Flags>) { return true; } 60 61 SwitchMap switches; 62 Flags flags = Flags::None; 63 size_t min_positionals = 0; 64 size_t max_positionals = -1; 65 }; 66 67 // ParametersParser provides tools to parse command parameters. 68 // There are 3 types of parameters: 69 // * unnamed options, which are accessed by position (ignoring named ones) 70 // * named boolean options, which are enabled using '-name' syntax 71 // * named string options, which are defined using '-name value' syntax 72 struct ParametersParser 73 { 74 // the options defines named options, if they map to true, then 75 // they are understood as string options, else they are understood as 76 // boolean option. 77 ParametersParser(ParameterList params, const ParameterDesc& desc); 78 79 // Return a valid optional if the switch was given, with 80 // a non empty StringView value if the switch took an argument. 81 Optional<StringView> get_switch(StringView name) const; 82 83 struct iterator : std::iterator<std::forward_iterator_tag, String> 84 { iteratorKakoune::ParametersParser::iterator85 iterator(const ParametersParser& parser, size_t index) 86 : m_parser(parser), m_index(index) {} 87 operator *Kakoune::ParametersParser::iterator88 const String& operator*() const { return m_parser[m_index]; } operator ->Kakoune::ParametersParser::iterator89 const String* operator->() const { return &m_parser[m_index]; } 90 operator ++Kakoune::ParametersParser::iterator91 iterator& operator++() { ++m_index; return *this; } operator ++Kakoune::ParametersParser::iterator92 iterator operator++(int) { auto copy = *this; ++m_index; return copy; } 93 operator ==Kakoune::ParametersParser::iterator94 bool operator==(const iterator& other) const 95 { 96 kak_assert(&m_parser == &other.m_parser); 97 return m_index == other.m_index; 98 } 99 operator !=Kakoune::ParametersParser::iterator100 bool operator!=(const iterator& other) const 101 { 102 return not (*this == other); 103 } 104 105 private: 106 const ParametersParser& m_parser; 107 size_t m_index; 108 }; 109 110 // positional parameters count positional_countKakoune::ParametersParser111 size_t positional_count() const { return m_positional_indices.size(); } 112 113 // access positional parameter by index operator []Kakoune::ParametersParser114 const String& operator[] (size_t index) const 115 { 116 kak_assert(index < positional_count()); 117 return m_params[m_positional_indices[index]]; 118 } 119 positionals_fromKakoune::ParametersParser120 ConstArrayView<String> positionals_from(size_t first) const 121 { 122 // kak_assert(m_desc.flags & (ParameterDesc::Flags::SwitchesOnlyAtStart | ParameterDesc::Flags::SwitchesAsPositional)); 123 return m_params.subrange(first < m_positional_indices.size() ? m_positional_indices[first] : -1); 124 } 125 beginKakoune::ParametersParser126 iterator begin() const { return iterator(*this, 0); } endKakoune::ParametersParser127 iterator end() const { return iterator(*this, m_positional_indices.size()); } 128 129 private: 130 ParameterList m_params; 131 Vector<size_t, MemoryDomain::Commands> m_positional_indices; 132 HashMap<String, StringView> m_switches; 133 }; 134 135 } 136 137 #endif // parameters_parser_hh_INCLUDED 138