Add support for removing from options

`set -remove ...` will remove from the current option value, substracting
from int, removing elements from vectors and maps.
main
Maxime Coste 2020-09-09 19:38:12 +10:00
parent 6f260c2ab2
commit ec3d7c3104
7 changed files with 128 additions and 17 deletions

View File

@ -3,6 +3,10 @@
This changelog contains major and/or breaking changes to Kakoune between
released versions.
== Development version
* `set-option -remove` support for substracting/removing from option values
== Kakoune 2020.09.01
* The `repl` and `send-text` aliases have been renamed respectively into

View File

@ -10,7 +10,7 @@ scripts.
Options can be modified using the `set-option` command:
--------------------------------------------
set-option [-add] <scope> <name> <values>...
set-option [-add|-remove] <scope> <name> <values>...
--------------------------------------------
<scope> can be *global*, *buffer*, *window* or *current* (See
@ -20,8 +20,9 @@ which the option is already set.
Multiple <values> can be given as separate arguments when the option is a
list or map.
If `-add` is specified, the new value is *added* to the current one
instead of replacing it (the exact outcome depends on the type, see below).
If `-add` or `-remove` is specified, the new value is respectively *added*
to or *removed* from the current one instead of replacing it (the exact
outcome depends on the type, see below).
[[unset-option]]
Options values can be unset in a specific scope with the `unset-option`
@ -63,7 +64,9 @@ are exclusively available to built-in options.
*int*::
an integer number.
`set -add` performs a math addition
`set -add` performs a math addition. +
`set -remove` performs a math substraction. +
*bool*::
a boolean value, yes/true or no/false
@ -81,7 +84,10 @@ are exclusively available to built-in options.
*<type>-list*::
a list, elements are specified as separate arguments to the command.
`set -add` appends the new element to the list
`set -add` appends the new element to the list. +
`set -remove` removes each given element from the list. +
Only `int-list` and `str-list` options can be created with
`declare-option`.
@ -115,7 +121,8 @@ are exclusively available to built-in options.
its ranges get updated according to all the buffer modifications
that happened since its timestamp.
`set -add` appends the new pair to the list
`set -add` appends the new pairs to the list. +
`set -remove` removes the given pairs from the list. +
See <<highlighters#specs-highlighters,`:doc highlighters specs-highlighters`>>)
@ -126,7 +133,9 @@ are exclusively available to built-in options.
type, its lines get updated according to all the buffer modifications
that happened since its timestamp.
See <<highlighters#specs-highlighters,`:doc highlighters specs-highlighters`>>)
`set -add` appends the new spec to the list
`set -add` appends the new specs to the list. +
`set -remove` removes the given specs from the list. +
*completions*::
a list of `<text>|<select cmd>|<menu text>` candidates,
@ -141,7 +150,8 @@ are exclusively available to built-in options.
Markup can be used in the menu text.
(see <<faces#markup-strings,`:doc faces markup-strings`>>)
`set -add` adds a new completion to the list
`set -add` adds given completions to the list. +
`set -remove` removes given completions from the list. +
*enum(value1|value2|...)*::
an enum, taking one of the given values
@ -150,13 +160,21 @@ are exclusively available to built-in options.
*flags(value1|value2|...)*::
a set of flags, taking a combination of the given values joined by a
'|' character.
`set -add` adds the new flag to the combination
`set -add` adds the given flags to the combination. +
`set -remove` removes the given flags to the combination. +
Cannot be used with `declare-option`
*<type>-to-<type>-map*::
a list of `key=value` pairs.
`set -add` adds the new pair to the hashmap or replace an already
existing key.
`set -add` adds the given pair to the hashmap or replace an already
existing key. +
`set -remove` removes the given pair from the hashmap, if only the
key is provided it removes that entry regardless of the associated
value. +
Only `str-to-str-map` options can be created with `declare-option`.
== Builtin options

View File

@ -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));
}

View File

@ -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"
}, {

View File

@ -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
{

View File

@ -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);

View File

@ -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>();
@ -154,6 +176,27 @@ bool option_add_from_strings(HashMap<Key, Value, domain>& opt, ConstArrayView<St
return changed;
}
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)
{
@ -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