Add support for removing from options
`set -remove ...` will remove from the current option value, substracting from int, removing elements from vectors and maps.
This commit is contained in:
parent
6f260c2ab2
commit
ec3d7c3104
|
@ -3,6 +3,10 @@
|
||||||
This changelog contains major and/or breaking changes to Kakoune between
|
This changelog contains major and/or breaking changes to Kakoune between
|
||||||
released versions.
|
released versions.
|
||||||
|
|
||||||
|
== Development version
|
||||||
|
|
||||||
|
* `set-option -remove` support for substracting/removing from option values
|
||||||
|
|
||||||
== Kakoune 2020.09.01
|
== Kakoune 2020.09.01
|
||||||
|
|
||||||
* The `repl` and `send-text` aliases have been renamed respectively into
|
* The `repl` and `send-text` aliases have been renamed respectively into
|
||||||
|
|
|
@ -10,7 +10,7 @@ scripts.
|
||||||
Options can be modified using the `set-option` command:
|
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
|
<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
|
Multiple <values> can be given as separate arguments when the option is a
|
||||||
list or map.
|
list or map.
|
||||||
|
|
||||||
If `-add` is specified, the new value is *added* to the current one
|
If `-add` or `-remove` is specified, the new value is respectively *added*
|
||||||
instead of replacing it (the exact outcome depends on the type, see below).
|
to or *removed* from the current one instead of replacing it (the exact
|
||||||
|
outcome depends on the type, see below).
|
||||||
|
|
||||||
[[unset-option]]
|
[[unset-option]]
|
||||||
Options values can be unset in a specific scope with the `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*::
|
*int*::
|
||||||
an integer number.
|
an integer number.
|
||||||
`set -add` performs a math addition
|
|
||||||
|
`set -add` performs a math addition. +
|
||||||
|
`set -remove` performs a math substraction. +
|
||||||
|
|
||||||
*bool*::
|
*bool*::
|
||||||
a boolean value, yes/true or no/false
|
a boolean value, yes/true or no/false
|
||||||
|
@ -81,7 +84,10 @@ are exclusively available to built-in options.
|
||||||
|
|
||||||
*<type>-list*::
|
*<type>-list*::
|
||||||
a list, elements are specified as separate arguments to the command.
|
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
|
Only `int-list` and `str-list` options can be created with
|
||||||
`declare-option`.
|
`declare-option`.
|
||||||
|
|
||||||
|
@ -115,7 +121,8 @@ are exclusively available to built-in options.
|
||||||
its ranges get updated according to all the buffer modifications
|
its ranges get updated according to all the buffer modifications
|
||||||
that happened since its timestamp.
|
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`>>)
|
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
|
type, its lines get updated according to all the buffer modifications
|
||||||
that happened since its timestamp.
|
that happened since its timestamp.
|
||||||
See <<highlighters#specs-highlighters,`:doc highlighters specs-highlighters`>>)
|
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*::
|
*completions*::
|
||||||
a list of `<text>|<select cmd>|<menu text>` candidates,
|
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.
|
Markup can be used in the menu text.
|
||||||
(see <<faces#markup-strings,`:doc faces markup-strings`>>)
|
(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|...)*::
|
*enum(value1|value2|...)*::
|
||||||
an enum, taking one of the given values
|
an enum, taking one of the given values
|
||||||
|
@ -150,13 +160,21 @@ are exclusively available to built-in options.
|
||||||
*flags(value1|value2|...)*::
|
*flags(value1|value2|...)*::
|
||||||
a set of flags, taking a combination of the given values joined by a
|
a set of flags, taking a combination of the given values joined by a
|
||||||
'|' character.
|
'|' 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`
|
Cannot be used with `declare-option`
|
||||||
|
|
||||||
*<type>-to-<type>-map*::
|
*<type>-to-<type>-map*::
|
||||||
a list of `key=value` pairs.
|
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`.
|
Only `str-to-str-map` options can be created with `declare-option`.
|
||||||
|
|
||||||
== Builtin options
|
== Builtin options
|
||||||
|
|
|
@ -1539,7 +1539,8 @@ const CommandDesc set_option_cmd = {
|
||||||
"<scope> can be global, buffer, window, or current which refers to the narrowest "
|
"<scope> can be global, buffer, window, or current which refers to the narrowest "
|
||||||
"scope the option is set in",
|
"scope the option is set in",
|
||||||
ParameterDesc{
|
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
|
ParameterDesc::Flags::SwitchesOnlyAtStart, 2, (size_t)-1
|
||||||
},
|
},
|
||||||
CommandFlags::None,
|
CommandFlags::None,
|
||||||
|
@ -1571,9 +1572,16 @@ const CommandDesc set_option_cmd = {
|
||||||
},
|
},
|
||||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
[](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]);
|
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));
|
opt.add_from_strings(parser.positionals_from(2));
|
||||||
|
else if (remove)
|
||||||
|
opt.remove_from_strings(parser.positionals_from(2));
|
||||||
else
|
else
|
||||||
opt.set_from_strings(parser.positionals_from(2));
|
opt.set_from_strings(parser.positionals_from(2));
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,6 +44,9 @@ struct {
|
||||||
unsigned int version;
|
unsigned int version;
|
||||||
StringView notes;
|
StringView notes;
|
||||||
} constexpr version_notes[] = { {
|
} constexpr version_notes[] = { {
|
||||||
|
0,
|
||||||
|
"» {+u}set-option -remove{} support\n"
|
||||||
|
}, {
|
||||||
20200901,
|
20200901,
|
||||||
"» daemon mode does not fork anymore\n"
|
"» daemon mode does not fork anymore\n"
|
||||||
}, {
|
}, {
|
||||||
|
|
|
@ -43,6 +43,15 @@ option_add_from_strings(T& opt, ConstArrayView<String> strs)
|
||||||
return option_add(opt, strs[0]);
|
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>
|
template<typename P, typename T>
|
||||||
struct PrefixedList
|
struct PrefixedList
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,6 +58,7 @@ public:
|
||||||
virtual String get_desc_string() const = 0;
|
virtual String get_desc_string() const = 0;
|
||||||
virtual void set_from_strings(ConstArrayView<String> strs) = 0;
|
virtual void set_from_strings(ConstArrayView<String> strs) = 0;
|
||||||
virtual void add_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 void update(const Context& context) = 0;
|
||||||
|
|
||||||
virtual bool has_same_value(const Option& other) const = 0;
|
virtual bool has_same_value(const Option& other) const = 0;
|
||||||
|
@ -174,6 +175,12 @@ public:
|
||||||
m_manager.on_option_changed(*this);
|
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
|
void update(const Context& context) override
|
||||||
{
|
{
|
||||||
option_update(m_value, context);
|
option_update(m_value, context);
|
||||||
|
|
|
@ -48,6 +48,12 @@ inline bool option_add(int& opt, StringView str)
|
||||||
opt += val;
|
opt += val;
|
||||||
return val != 0;
|
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"; }
|
constexpr StringView option_type_name(Meta::Type<int>) { return "int"; }
|
||||||
|
|
||||||
inline String option_to_string(size_t opt) { return to_string(opt); }
|
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();
|
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>
|
template<typename T, MemoryDomain D>
|
||||||
String option_type_name(Meta::Type<Vector<T, 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>
|
template<typename Key, typename Value, MemoryDomain domain>
|
||||||
bool option_add_from_strings(HashMap<Key, Value, domain>& opt, ConstArrayView<String> strs)
|
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;
|
bool changed = false;
|
||||||
for (auto&& str : strs)
|
for (auto&& str : strs)
|
||||||
{
|
{
|
||||||
struct error : runtime_error { error(size_t) : runtime_error{"map option expects key=value"} {} };
|
|
||||||
auto key_value = str | split<StringView>('=', '\\')
|
auto key_value = str | split<StringView>('=', '\\')
|
||||||
| transform(unescape<'=', '\\'>)
|
| transform(unescape<'=', '\\'>)
|
||||||
| static_gather<error, 2>();
|
| static_gather<error, 2>();
|
||||||
|
@ -154,6 +176,27 @@ bool option_add_from_strings(HashMap<Key, Value, domain>& opt, ConstArrayView<St
|
||||||
return changed;
|
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>
|
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> 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");
|
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;
|
class Context;
|
||||||
|
|
||||||
inline void option_update(WorstMatch, const 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>{}))>
|
template<typename Flags, typename = decltype(enum_desc(Meta::Type<Flags>{}))>
|
||||||
EnableIfWithBitOps<Flags, bool> option_add(Flags& opt, StringView str)
|
EnableIfWithBitOps<Flags, bool> option_add(Flags& opt, StringView str)
|
||||||
{
|
{
|
||||||
const Flags res = option_from_string(Meta::Type<Flags>{}, str);
|
const Flags old = opt;
|
||||||
opt |= res;
|
opt |= option_from_string(Meta::Type<Flags>{}, str);
|
||||||
return res != (Flags)0;
|
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>
|
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);
|
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
|
#endif // option_types_hh_INCLUDED
|
||||||
|
|
Loading…
Reference in New Issue
Block a user