summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMaxime Coste <mawww@kakoune.org>2020-09-09 19:38:12 +1000
committerMaxime Coste <mawww@kakoune.org>2020-09-09 21:00:30 +1000
commitec3d7c31040afaee65afde15832d9b0ed6b2224d (patch)
tree3deb13723ff798c114a67315755fa2f42b155e95 /src
parent6f260c2ab2f118e7eaa3a9b8334ee63dad27bf2c (diff)
Add support for removing from options
`set -remove ...` will remove from the current option value, substracting from int, removing elements from vectors and maps.
Diffstat (limited to 'src')
-rw-r--r--src/commands.cc12
-rw-r--r--src/main.cc3
-rw-r--r--src/option.hh9
-rw-r--r--src/option_manager.hh7
-rw-r--r--src/option_types.hh70
5 files changed, 95 insertions, 6 deletions
diff --git a/src/commands.cc b/src/commands.cc
index 1e421aa4..7ca5a8ab 100644
--- a/src/commands.cc
+++ b/src/commands.cc
@@ -1539,7 +1539,8 @@ const CommandDesc set_option_cmd = {
"<scope> can be global, buffer, window, or current which refers to the narrowest "
"scope the option is set in",
ParameterDesc{
- { { "add", { false, "add to option rather than replacing it" } } },
+ { { "add", { false, "add to option rather than replacing it" } },
+ { "remove", { false, "remove from option rather than replacing it" } } },
ParameterDesc::Flags::SwitchesOnlyAtStart, 2, (size_t)-1
},
CommandFlags::None,
@@ -1571,9 +1572,16 @@ const CommandDesc set_option_cmd = {
},
[](const ParametersParser& parser, Context& context, const ShellContext&)
{
+ bool add = (bool)parser.get_switch("add");
+ bool remove = (bool)parser.get_switch("remove");
+ if (add and remove)
+ throw runtime_error("cannot add and remove at the same time");
+
Option& opt = get_options(parser[0], context, parser[1]).get_local_option(parser[1]);
- if (parser.get_switch("add"))
+ if (add)
opt.add_from_strings(parser.positionals_from(2));
+ else if (remove)
+ opt.remove_from_strings(parser.positionals_from(2));
else
opt.set_from_strings(parser.positionals_from(2));
}
diff --git a/src/main.cc b/src/main.cc
index e822daa7..af3d68ba 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -44,6 +44,9 @@ struct {
unsigned int version;
StringView notes;
} constexpr version_notes[] = { {
+ 0,
+ "» {+u}set-option -remove{} support\n"
+ }, {
20200901,
"» daemon mode does not fork anymore\n"
}, {
diff --git a/src/option.hh b/src/option.hh
index db8be775..a04b235c 100644
--- a/src/option.hh
+++ b/src/option.hh
@@ -43,6 +43,15 @@ option_add_from_strings(T& opt, ConstArrayView<String> strs)
return option_add(opt, strs[0]);
}
+template<typename T>
+decltype(option_add(std::declval<T>(), std::declval<String>()))
+option_remove_from_strings(T& opt, ConstArrayView<String> strs)
+{
+ if (strs.size() != 1)
+ throw runtime_error("expected a single value for option");
+ return option_remove(opt, strs[0]);
+}
+
template<typename P, typename T>
struct PrefixedList
{
diff --git a/src/option_manager.hh b/src/option_manager.hh
index 739ec6bd..e4dc230f 100644
--- a/src/option_manager.hh
+++ b/src/option_manager.hh
@@ -58,6 +58,7 @@ public:
virtual String get_desc_string() const = 0;
virtual void set_from_strings(ConstArrayView<String> strs) = 0;
virtual void add_from_strings(ConstArrayView<String> strs) = 0;
+ virtual void remove_from_strings(ConstArrayView<String> strs) = 0;
virtual void update(const Context& context) = 0;
virtual bool has_same_value(const Option& other) const = 0;
@@ -174,6 +175,12 @@ public:
m_manager.on_option_changed(*this);
}
+ void remove_from_strings(ConstArrayView<String> strs) override
+ {
+ if (option_remove_from_strings(m_value, strs))
+ m_manager.on_option_changed(*this);
+ }
+
void update(const Context& context) override
{
option_update(m_value, context);
diff --git a/src/option_types.hh b/src/option_types.hh
index c0f138ea..e576b295 100644
--- a/src/option_types.hh
+++ b/src/option_types.hh
@@ -48,6 +48,12 @@ inline bool option_add(int& opt, StringView str)
opt += val;
return val != 0;
}
+inline bool option_remove(int& opt, StringView str)
+{
+ auto val = str_to_int(str);
+ opt -= val;
+ return val != 0;
+}
constexpr StringView option_type_name(Meta::Type<int>) { return "int"; }
inline String option_to_string(size_t opt) { return to_string(opt); }
@@ -110,6 +116,21 @@ bool option_add_from_strings(Vector<T, domain>& opt, ConstArrayView<String> strs
return not vec.empty();
}
+template<typename T, MemoryDomain domain>
+bool option_remove_from_strings(Vector<T, domain>& opt, ConstArrayView<String> strs)
+{
+ bool did_remove = false;
+ for (auto&& val : strs | transform([](auto&& s) { return option_from_string(Meta::Type<T>{}, s); }))
+ {
+ auto it = find(opt, val);
+ if (it == opt.end())
+ continue;
+ opt.erase(it);
+ did_remove = true;
+ }
+ return did_remove;
+}
+
template<typename T, MemoryDomain D>
String option_type_name(Meta::Type<Vector<T, D>>)
{
@@ -140,10 +161,11 @@ String option_to_string(const HashMap<Key, Value, domain>& opt, Quoting quoting)
template<typename Key, typename Value, MemoryDomain domain>
bool option_add_from_strings(HashMap<Key, Value, domain>& opt, ConstArrayView<String> strs)
{
+ struct error : runtime_error { error(size_t) : runtime_error{"map option expects key=value"} {} };
+
bool changed = false;
for (auto&& str : strs)
{
- struct error : runtime_error { error(size_t) : runtime_error{"map option expects key=value"} {} };
auto key_value = str | split<StringView>('=', '\\')
| transform(unescape<'=', '\\'>)
| static_gather<error, 2>();
@@ -155,6 +177,27 @@ bool option_add_from_strings(HashMap<Key, Value, domain>& opt, ConstArrayView<St
}
template<typename Key, typename Value, MemoryDomain domain>
+bool option_remove_from_strings(HashMap<Key, Value, domain>& opt, ConstArrayView<String> strs)
+{
+ struct error : runtime_error { error(size_t) : runtime_error{"map option expects key=value"} {} };
+
+ bool changed = false;
+ for (auto&& str : strs)
+ {
+ auto key_value = str | split<StringView>('=', '\\')
+ | transform(unescape<'=', '\\'>)
+ | static_gather<error, 2>();
+
+ if (auto it = opt.find(key_value[0]); it != opt.end() and (key_value[1].empty() or key_value[1] == it->value))
+ {
+ opt.remove(it->key);
+ changed = true;
+ }
+ }
+ return changed;
+}
+
+template<typename Key, typename Value, MemoryDomain domain>
HashMap<Key, Value, domain> option_from_strings(Meta::Type<HashMap<Key, Value, domain>>, ConstArrayView<String> str)
{
HashMap<Key, Value, domain> res;
@@ -234,6 +277,11 @@ inline bool option_add(WorstMatch, StringView)
throw runtime_error("no add operation supported for this option type");
}
+inline bool option_remove(WorstMatch, StringView)
+{
+ throw runtime_error("no remove operation supported for this option type");
+}
+
class Context;
inline void option_update(WorstMatch, const Context&)
@@ -312,9 +360,17 @@ EnableIfWithoutBitOps<Enum, Enum> option_from_string(Meta::Type<Enum>, StringVie
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
EnableIfWithBitOps<Flags, bool> option_add(Flags& opt, StringView str)
{
- const Flags res = option_from_string(Meta::Type<Flags>{}, str);
- opt |= res;
- return res != (Flags)0;
+ const Flags old = opt;
+ opt |= option_from_string(Meta::Type<Flags>{}, str);
+ return opt != old;
+}
+
+template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
+EnableIfWithBitOps<Flags, bool> option_remove(Flags& opt, StringView str)
+{
+ const Flags old = opt;
+ opt &= ~option_from_string(Meta::Type<Flags>{}, str);
+ return opt != old;
}
template<typename P, typename T>
@@ -348,6 +404,12 @@ inline bool option_add_from_strings(PrefixedList<P, T>& opt, ConstArrayView<Stri
return option_add_from_strings(opt.list, str);
}
+template<typename P, typename T>
+inline bool option_remove_from_strings(PrefixedList<P, T>& opt, ConstArrayView<String> str)
+{
+ return option_remove_from_strings(opt.list, str);
+}
+
}
#endif // option_types_hh_INCLUDED