di 0.1.0
Loading...
Searching...
No Matches
option.h
Go to the documentation of this file.
1#pragma once
2
3#include "di/cli/value_type.h"
4#include "di/cli/zsh.h"
10#include "di/format/prelude.h"
11#include "di/function/prelude.h"
12#include "di/meta/language.h"
13#include "di/parser/prelude.h"
14#include "di/reflect/reflect.h"
16#include "di/vocab/prelude.h"
18
19namespace di::cli::detail {
20class Option {
21private:
22 using Parse = Result<> (*)(void*, Optional<TransparentStringView>);
23 using GetValues = Vector<Tuple<String, StringView>> (*)();
24 using DefaultValue = String (*)();
25
26 template<auto member>
27 constexpr static auto concrete_parse(void* output_untyped, Optional<TransparentStringView> input) -> Result<> {
28 using Base = meta::MemberPointerClass<decltype(member)>;
29 using Value = meta::MemberPointerValue<decltype(member)>;
30
31 auto output = static_cast<Base*>(output_untyped);
32 if constexpr (concepts::SameAs<Value, bool>) {
33 if (!input) {
34 (*output).*member = true;
35 return {};
36 }
37 (*output).*member = DI_TRY(parser::parse<Value>(*input));
38 return {};
39 } else {
40 DI_ASSERT(input);
41 if constexpr (concepts::Optional<Value>) {
42 (*output).*member = DI_TRY(parser::parse<meta::OptionalValue<Value>>(*input));
43 } else {
44 (*output).*member = DI_TRY(parser::parse<Value>(*input));
45 }
46 return {};
47 }
48 }
49
50public:
51 Option() = default;
52
53 template<auto member>
54 constexpr explicit Option(Constexpr<member>, Optional<char> short_name = {},
55 Optional<TransparentStringView> long_name = {}, StringView description = {},
56 bool required = false, Optional<StringView> value_name = {},
57 Optional<ValueType> value_type = {}, bool is_help = false)
58 : m_parse(concrete_parse<member>)
59 , m_get_values(detail::concrete_get_values<meta::MemberPointerValue<decltype(member)>>)
60 , m_default_value(detail::concrete_default_value<member>)
61 , m_short_name(short_name)
62 , m_long_name(long_name)
63 , m_description(description)
64 , m_value_name(value_name)
65 , m_value_type(value_type.value_or(default_value_type<meta::MemberPointerValue<decltype(member)>>))
66 , m_required(required)
67 , m_is_help(is_help)
68 , m_boolean(di::SameAs<meta::MemberPointerValue<decltype(member)>, bool>) {}
69
70 constexpr auto parse(void* base, Optional<TransparentStringView> input) const {
71 DI_ASSERT(m_parse);
72 return m_parse(base, input);
73 }
74 constexpr auto short_name() const { return m_short_name; }
75 constexpr auto long_name() const { return m_long_name; }
76 constexpr auto description() const { return m_description; }
77 constexpr auto required() const { return m_required; }
78 constexpr auto boolean() const { return m_boolean; }
79 constexpr auto is_help() const { return m_is_help; }
80
81 constexpr auto long_display_name() const {
82 auto result = di::TransparentString {};
83 result += di::single('-');
84 result += di::single('-');
85 result += m_long_name.value();
86 return result;
87 }
88
89 constexpr auto short_display_name() const {
90 auto result = di::TransparentString {};
91 result += di::single('-');
92 result += di::single(m_short_name.value());
93 return result;
94 }
95
96 constexpr auto display_name() const {
97 if (long_name()) {
98 return long_display_name();
99 }
100 if (short_name()) {
101 return short_display_name();
102 }
103 return di::TransparentString {};
104 }
105
106 constexpr auto value_name() const -> String {
107 if (m_value_name) {
108 return m_value_name.value().to_owned();
109 }
110 if (!m_long_name) {
111 return "VALUE"_s;
112 }
113 auto result = String {};
114 for (auto c : m_long_name.value()) {
115 if (c == '-') {
116 result.push_back(U'_');
117 } else if (c >= 'a' && c <= 'z') {
118 result.push_back(c & ~0x20);
119 } else {
120 result.push_back(c);
121 }
122 }
123 return result;
124 }
125
126 constexpr auto default_value() const -> String { return m_default_value(); }
127 constexpr auto value_type() const -> ValueType { return m_value_type; }
128 constexpr auto values() const -> Vector<Tuple<String, StringView>> { return m_get_values(); }
129
130 constexpr auto zsh_completion_specs() const -> Vector<String> {
131 auto prefixes = Vector<TransparentString> {};
132 if (short_name()) {
133 prefixes.push_back(short_display_name());
134 }
135 if (long_name()) {
136 prefixes.push_back(long_display_name());
137 }
138
139 return prefixes | transform([&](TransparentString const& prefix) {
140 auto value_char = boolean() ? ""_sv : prefix.starts_with("--"_tsv) ? "="_sv : "+"_sv;
141 auto value_spec = ""_s;
142 if (!boolean()) {
143 auto values = this->values();
144 value_spec =
145 format(":{}:{}"_sv, value_name(), zsh::value_completions(m_value_type, values.span()));
146 }
147 return format("{}{}[{}]{}"_sv, prefix, value_char, zsh::escape_description(description()),
148 value_spec);
149 }) |
151 }
152
153private:
154 Parse m_parse { nullptr };
155 GetValues m_get_values { nullptr };
156 DefaultValue m_default_value { nullptr };
157 Optional<char> m_short_name;
158 Optional<TransparentStringView> m_long_name;
159 StringView m_description;
160 Optional<StringView> m_value_name;
161 ValueType m_value_type { ValueType::Unknown };
162 bool m_required { false };
163 bool m_is_help { false };
164 bool m_boolean { false };
165};
166}
#define DI_ASSERT(...)
Definition assert_bool.h:7
#define DI_TRY(...)
Definition monad_try.h:13
constexpr auto escape_description(StringView input) -> String
Definition zsh.h:19
constexpr auto value_completions(ValueType value_type, Span< Tuple< String, StringView > > values) -> String
Definition zsh.h:140
ValueType
Definition value_type.h:11
@ Unknown
Definition value_type.h:12
constexpr auto default_value_type
Definition value_type.h:82
string::StringViewImpl< string::Utf8Encoding > StringView
Definition string_view.h:12
string::StringImpl< string::TransparentEncoding > TransparentString
Definition string.h:12
string::StringImpl< string::Utf8Encoding > String
Definition string.h:11
constexpr auto transform
Definition transform.h:59
Type< detail::MemberPointerValueHelper< RemoveCV< T > > > MemberPointerValue
Definition language.h:184
meta::RemoveCVRef< T >::Value OptionalValue
Definition vocab.h:82
Type< detail::MemberPointerClassHelper< RemoveCV< T > > > MemberPointerClass
Definition language.h:195
constexpr auto parse
Definition parse.h:23
Expected< T, Error > Result
Definition result.h:8
constexpr auto format
Definition format.h:7
constexpr auto to(Con &&container, Args &&... args)
Definition to.h:25
constexpr auto parse
Definition parse.h:23