Add an update-option command to update range-descs/line-descs options
update-option will make the range-descs and line-descs option up to date with the latest buffer modfications, changing the ranges/lines to where they moved according the modifications since the timestamp on the option.
This commit is contained in:
parent
f014eb7052
commit
83d85df26e
|
@ -43,16 +43,6 @@
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
StringView option_type_name(Meta::Type<TimestampedList<LineAndSpec>>)
|
|
||||||
{
|
|
||||||
return "line-specs";
|
|
||||||
}
|
|
||||||
|
|
||||||
StringView option_type_name(Meta::Type<TimestampedList<RangeAndString>>)
|
|
||||||
{
|
|
||||||
return "range-specs";
|
|
||||||
}
|
|
||||||
|
|
||||||
namespace
|
namespace
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -1289,18 +1279,9 @@ const CommandDesc set_option_cmd = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const CommandDesc unset_option_cmd = {
|
Completions complete_option(const Context& context, CompletionFlags,
|
||||||
"unset-option",
|
|
||||||
"unset",
|
|
||||||
"unset-option <scope> <name>: remove <name> option from scope, falling back on parent scope value"
|
|
||||||
"<scope> can be buffer, window, or current which refers to the narrowest\n"
|
|
||||||
"scope the option is set in",
|
|
||||||
ParameterDesc{ {}, ParameterDesc::Flags::None, 2, 2 },
|
|
||||||
CommandFlags::None,
|
|
||||||
option_doc_helper,
|
|
||||||
[](const Context& context, CompletionFlags,
|
|
||||||
CommandParameters params, size_t token_to_complete,
|
CommandParameters params, size_t token_to_complete,
|
||||||
ByteCount pos_in_token) -> Completions
|
ByteCount pos_in_token)
|
||||||
{
|
{
|
||||||
if (token_to_complete == 0)
|
if (token_to_complete == 0)
|
||||||
{
|
{
|
||||||
|
@ -1311,7 +1292,18 @@ const CommandDesc unset_option_cmd = {
|
||||||
return { 0_byte, params[1].length(),
|
return { 0_byte, params[1].length(),
|
||||||
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) };
|
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) };
|
||||||
return Completions{};
|
return Completions{};
|
||||||
},
|
}
|
||||||
|
|
||||||
|
const CommandDesc unset_option_cmd = {
|
||||||
|
"unset-option",
|
||||||
|
"unset",
|
||||||
|
"unset-option <scope> <name>: remove <name> option from scope, falling back on parent scope value"
|
||||||
|
"<scope> can be buffer, window, or current which refers to the narrowest\n"
|
||||||
|
"scope the option is set in",
|
||||||
|
ParameterDesc{ {}, ParameterDesc::Flags::None, 2, 2 },
|
||||||
|
CommandFlags::None,
|
||||||
|
option_doc_helper,
|
||||||
|
complete_option,
|
||||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
||||||
{
|
{
|
||||||
auto& options = get_options(parser[0], context, parser[1]);
|
auto& options = get_options(parser[0], context, parser[1]);
|
||||||
|
@ -1321,6 +1313,24 @@ const CommandDesc unset_option_cmd = {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const CommandDesc update_option_cmd = {
|
||||||
|
"update-option",
|
||||||
|
nullptr,
|
||||||
|
"update-option <scope> <name>: update <name> option from scope\n"
|
||||||
|
"some option types, such as line-descs or range-descs can be updated to latest buffer timestamp\n"
|
||||||
|
"<scope> can be buffer, window, or current which refers to the narrowest\n"
|
||||||
|
"scope the option is set in",
|
||||||
|
ParameterDesc{ {}, ParameterDesc::Flags::None, 2, 2 },
|
||||||
|
CommandFlags::None,
|
||||||
|
option_doc_helper,
|
||||||
|
complete_option,
|
||||||
|
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
||||||
|
{
|
||||||
|
Option& opt = get_options(parser[0], context, parser[1]).get_local_option(parser[1]);
|
||||||
|
opt.update(context);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const CommandDesc declare_option_cmd = {
|
const CommandDesc declare_option_cmd = {
|
||||||
"declare-option",
|
"declare-option",
|
||||||
"decl",
|
"decl",
|
||||||
|
@ -2142,6 +2152,7 @@ void register_commands()
|
||||||
register_command(source_cmd);
|
register_command(source_cmd);
|
||||||
register_command(set_option_cmd);
|
register_command(set_option_cmd);
|
||||||
register_command(unset_option_cmd);
|
register_command(unset_option_cmd);
|
||||||
|
register_command(update_option_cmd);
|
||||||
register_command(declare_option_cmd);
|
register_command(declare_option_cmd);
|
||||||
register_command(map_key_cmd);
|
register_command(map_key_cmd);
|
||||||
register_command(unmap_key_cmd);
|
register_command(unmap_key_cmd);
|
||||||
|
|
|
@ -1177,6 +1177,47 @@ void expand_unprintable(const Context& context, HighlightPass, DisplayBuffer& di
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_line_specs_ifn(const Buffer& buffer, LineAndSpecList& line_flags)
|
||||||
|
{
|
||||||
|
if (line_flags.prefix == buffer.timestamp())
|
||||||
|
return;
|
||||||
|
|
||||||
|
auto& lines = line_flags.list;
|
||||||
|
|
||||||
|
std::sort(lines.begin(), lines.end(),
|
||||||
|
[](const LineAndSpec& lhs, const LineAndSpec& rhs)
|
||||||
|
{ return std::get<0>(lhs) < std::get<0>(rhs); });
|
||||||
|
|
||||||
|
auto modifs = compute_line_modifications(buffer, line_flags.prefix);
|
||||||
|
auto ins_pos = lines.begin();
|
||||||
|
for (auto it = lines.begin(); it != lines.end(); ++it)
|
||||||
|
{
|
||||||
|
auto& line = std::get<0>(*it); // that line is 1 based as it comes from user side
|
||||||
|
auto modif_it = std::upper_bound(modifs.begin(), modifs.end(), line-1,
|
||||||
|
[](const LineCount& l, const LineModification& c)
|
||||||
|
{ return l < c.old_line; });
|
||||||
|
if (modif_it != modifs.begin())
|
||||||
|
{
|
||||||
|
auto& prev = *(modif_it-1);
|
||||||
|
if (line-1 < prev.old_line + prev.num_removed)
|
||||||
|
continue; // line removed
|
||||||
|
|
||||||
|
line += prev.diff();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ins_pos != it)
|
||||||
|
*ins_pos = std::move(*it);
|
||||||
|
++ins_pos;
|
||||||
|
}
|
||||||
|
lines.erase(ins_pos, lines.end());
|
||||||
|
line_flags.prefix = buffer.timestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
void option_update(LineAndSpecList& opt, const Context& context)
|
||||||
|
{
|
||||||
|
update_line_specs_ifn(context.buffer(), opt);
|
||||||
|
}
|
||||||
|
|
||||||
struct FlagLinesHighlighter : Highlighter
|
struct FlagLinesHighlighter : Highlighter
|
||||||
{
|
{
|
||||||
FlagLinesHighlighter(String option_name, String default_face)
|
FlagLinesHighlighter(String option_name, String default_face)
|
||||||
|
@ -1184,8 +1225,6 @@ struct FlagLinesHighlighter : Highlighter
|
||||||
m_option_name{std::move(option_name)},
|
m_option_name{std::move(option_name)},
|
||||||
m_default_face{std::move(default_face)} {}
|
m_default_face{std::move(default_face)} {}
|
||||||
|
|
||||||
using LineAndSpecList = TimestampedList<LineAndSpec>;
|
|
||||||
|
|
||||||
static HighlighterAndId create(HighlighterParameters params)
|
static HighlighterAndId create(HighlighterParameters params)
|
||||||
{
|
{
|
||||||
if (params.size() != 2)
|
if (params.size() != 2)
|
||||||
|
@ -1207,7 +1246,7 @@ private:
|
||||||
{
|
{
|
||||||
auto& line_flags = context.options()[m_option_name].get_mutable<LineAndSpecList>();
|
auto& line_flags = context.options()[m_option_name].get_mutable<LineAndSpecList>();
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
update_line_flags_ifn(buffer, line_flags);
|
update_line_specs_ifn(buffer, line_flags);
|
||||||
|
|
||||||
auto def_face = get_face(m_default_face);
|
auto def_face = get_face(m_default_face);
|
||||||
Vector<DisplayLine> display_lines;
|
Vector<DisplayLine> display_lines;
|
||||||
|
@ -1257,7 +1296,7 @@ private:
|
||||||
{
|
{
|
||||||
auto& line_flags = context.options()[m_option_name].get_mutable<LineAndSpecList>();
|
auto& line_flags = context.options()[m_option_name].get_mutable<LineAndSpecList>();
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
update_line_flags_ifn(buffer, line_flags);
|
update_line_specs_ifn(buffer, line_flags);
|
||||||
|
|
||||||
ColumnCount width = 0;
|
ColumnCount width = 0;
|
||||||
try
|
try
|
||||||
|
@ -1274,42 +1313,6 @@ private:
|
||||||
setup.window_range.column -= width;
|
setup.window_range.column -= width;
|
||||||
}
|
}
|
||||||
|
|
||||||
void update_line_flags_ifn(const Buffer& buffer, LineAndSpecList& line_flags)
|
|
||||||
{
|
|
||||||
if (line_flags.prefix == buffer.timestamp())
|
|
||||||
return;
|
|
||||||
|
|
||||||
auto& lines = line_flags.list;
|
|
||||||
|
|
||||||
std::sort(lines.begin(), lines.end(),
|
|
||||||
[](const LineAndSpec& lhs, const LineAndSpec& rhs)
|
|
||||||
{ return std::get<0>(lhs) < std::get<0>(rhs); });
|
|
||||||
|
|
||||||
auto modifs = compute_line_modifications(buffer, line_flags.prefix);
|
|
||||||
auto ins_pos = lines.begin();
|
|
||||||
for (auto it = lines.begin(); it != lines.end(); ++it)
|
|
||||||
{
|
|
||||||
auto& line = std::get<0>(*it); // that line is 1 based as it comes from user side
|
|
||||||
auto modif_it = std::upper_bound(modifs.begin(), modifs.end(), line-1,
|
|
||||||
[](const LineCount& l, const LineModification& c)
|
|
||||||
{ return l < c.old_line; });
|
|
||||||
if (modif_it != modifs.begin())
|
|
||||||
{
|
|
||||||
auto& prev = *(modif_it-1);
|
|
||||||
if (line-1 < prev.old_line + prev.num_removed)
|
|
||||||
continue; // line removed
|
|
||||||
|
|
||||||
line += prev.diff();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ins_pos != it)
|
|
||||||
*ins_pos = std::move(*it);
|
|
||||||
++ins_pos;
|
|
||||||
}
|
|
||||||
lines.erase(ins_pos, lines.end());
|
|
||||||
line_flags.prefix = buffer.timestamp();
|
|
||||||
}
|
|
||||||
|
|
||||||
String m_option_name;
|
String m_option_name;
|
||||||
String m_default_face;
|
String m_default_face;
|
||||||
};
|
};
|
||||||
|
@ -1348,7 +1351,7 @@ void option_from_string(StringView str, InclusiveBufferRange& opt)
|
||||||
BufferCoord& get_first(RangeAndString& r) { return std::get<0>(r).first; }
|
BufferCoord& get_first(RangeAndString& r) { return std::get<0>(r).first; }
|
||||||
BufferCoord& get_last(RangeAndString& r) { return std::get<0>(r).last; }
|
BufferCoord& get_last(RangeAndString& r) { return std::get<0>(r).last; }
|
||||||
|
|
||||||
static void update_ranges_ifn(const Buffer& buffer, TimestampedList<RangeAndString>& range_and_faces)
|
static void update_ranges_ifn(const Buffer& buffer, RangeAndStringList& range_and_faces)
|
||||||
{
|
{
|
||||||
if (range_and_faces.prefix == buffer.timestamp())
|
if (range_and_faces.prefix == buffer.timestamp())
|
||||||
return;
|
return;
|
||||||
|
@ -1373,6 +1376,11 @@ static void update_ranges_ifn(const Buffer& buffer, TimestampedList<RangeAndStri
|
||||||
range_and_faces.prefix = buffer.timestamp();
|
range_and_faces.prefix = buffer.timestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void option_update(RangeAndStringList& opt, const Context& context)
|
||||||
|
{
|
||||||
|
update_ranges_ifn(context.buffer(), opt);
|
||||||
|
}
|
||||||
|
|
||||||
struct RangesHighlighter : Highlighter
|
struct RangesHighlighter : Highlighter
|
||||||
{
|
{
|
||||||
RangesHighlighter(String option_name)
|
RangesHighlighter(String option_name)
|
||||||
|
@ -1386,7 +1394,7 @@ struct RangesHighlighter : Highlighter
|
||||||
|
|
||||||
const String& option_name = params[0];
|
const String& option_name = params[0];
|
||||||
// throw if wrong option type
|
// throw if wrong option type
|
||||||
GlobalScope::instance().options()[option_name].get<TimestampedList<RangeAndString>>();
|
GlobalScope::instance().options()[option_name].get<RangeAndStringList>();
|
||||||
|
|
||||||
return {"hlranges_" + params[0], make_unique<RangesHighlighter>(option_name)};
|
return {"hlranges_" + params[0], make_unique<RangesHighlighter>(option_name)};
|
||||||
}
|
}
|
||||||
|
@ -1395,7 +1403,7 @@ private:
|
||||||
void do_highlight(const Context& context, HighlightPass, DisplayBuffer& display_buffer, BufferRange) override
|
void do_highlight(const Context& context, HighlightPass, DisplayBuffer& display_buffer, BufferRange) override
|
||||||
{
|
{
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
auto& range_and_faces = context.options()[m_option_name].get_mutable<TimestampedList<RangeAndString>>();
|
auto& range_and_faces = context.options()[m_option_name].get_mutable<RangeAndStringList>();
|
||||||
update_ranges_ifn(buffer, range_and_faces);
|
update_ranges_ifn(buffer, range_and_faces);
|
||||||
|
|
||||||
for (auto& range : range_and_faces.list)
|
for (auto& range : range_and_faces.list)
|
||||||
|
@ -1428,7 +1436,7 @@ struct ReplaceRangesHighlighter : Highlighter
|
||||||
|
|
||||||
const String& option_name = params[0];
|
const String& option_name = params[0];
|
||||||
// throw if wrong option type
|
// throw if wrong option type
|
||||||
GlobalScope::instance().options()[option_name].get<TimestampedList<RangeAndString>>();
|
GlobalScope::instance().options()[option_name].get<RangeAndStringList>();
|
||||||
|
|
||||||
return {"replace_ranges_" + params[0], make_unique<ReplaceRangesHighlighter>(option_name)};
|
return {"replace_ranges_" + params[0], make_unique<ReplaceRangesHighlighter>(option_name)};
|
||||||
}
|
}
|
||||||
|
@ -1437,7 +1445,7 @@ private:
|
||||||
void do_highlight(const Context& context, HighlightPass, DisplayBuffer& display_buffer, BufferRange) override
|
void do_highlight(const Context& context, HighlightPass, DisplayBuffer& display_buffer, BufferRange) override
|
||||||
{
|
{
|
||||||
auto& buffer = context.buffer();
|
auto& buffer = context.buffer();
|
||||||
auto& range_and_faces = context.options()[m_option_name].get_mutable<TimestampedList<RangeAndString>>();
|
auto& range_and_faces = context.options()[m_option_name].get_mutable<RangeAndStringList>();
|
||||||
update_ranges_ifn(buffer, range_and_faces);
|
update_ranges_ifn(buffer, range_and_faces);
|
||||||
|
|
||||||
for (auto& range : range_and_faces.list)
|
for (auto& range : range_and_faces.list)
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "color.hh"
|
#include "color.hh"
|
||||||
#include "highlighter.hh"
|
#include "highlighter.hh"
|
||||||
|
#include "option.hh"
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
{
|
{
|
||||||
|
@ -19,7 +20,22 @@ String option_to_string(InclusiveBufferRange range);
|
||||||
void option_from_string(StringView str, InclusiveBufferRange& opt);
|
void option_from_string(StringView str, InclusiveBufferRange& opt);
|
||||||
|
|
||||||
using LineAndSpec = std::tuple<LineCount, String>;
|
using LineAndSpec = std::tuple<LineCount, String>;
|
||||||
|
using LineAndSpecList = TimestampedList<LineAndSpec>;
|
||||||
|
|
||||||
|
constexpr StringView option_type_name(Meta::Type<LineAndSpecList>)
|
||||||
|
{
|
||||||
|
return "line-specs";
|
||||||
|
}
|
||||||
|
void option_update(LineAndSpecList& opt, const Context& context);
|
||||||
|
|
||||||
using RangeAndString = std::tuple<InclusiveBufferRange, String>;
|
using RangeAndString = std::tuple<InclusiveBufferRange, String>;
|
||||||
|
using RangeAndStringList = TimestampedList<RangeAndString>;
|
||||||
|
|
||||||
|
constexpr StringView option_type_name(Meta::Type<RangeAndStringList>)
|
||||||
|
{
|
||||||
|
return "range-specs";
|
||||||
|
}
|
||||||
|
void option_update(RangeAndStringList& opt, const Context& context);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,6 +14,7 @@ namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
class OptionManager;
|
class OptionManager;
|
||||||
|
class Context;
|
||||||
|
|
||||||
enum class OptionFlags
|
enum class OptionFlags
|
||||||
{
|
{
|
||||||
|
@ -52,6 +53,7 @@ public:
|
||||||
virtual String get_as_string() const = 0;
|
virtual String get_as_string() const = 0;
|
||||||
virtual void set_from_string(StringView str) = 0;
|
virtual void set_from_string(StringView str) = 0;
|
||||||
virtual void add_from_string(StringView str) = 0;
|
virtual void add_from_string(StringView str) = 0;
|
||||||
|
virtual void update(const Context& context) = 0;
|
||||||
|
|
||||||
virtual Option* clone(OptionManager& manager) const = 0;
|
virtual Option* clone(OptionManager& manager) const = 0;
|
||||||
OptionManager& manager() const { return m_manager; }
|
OptionManager& manager() const { return m_manager; }
|
||||||
|
@ -140,6 +142,10 @@ public:
|
||||||
if (option_add(m_value, str))
|
if (option_add(m_value, str))
|
||||||
m_manager.on_option_changed(*this);
|
m_manager.on_option_changed(*this);
|
||||||
}
|
}
|
||||||
|
void update(const Context& context) override
|
||||||
|
{
|
||||||
|
option_update(m_value, context);
|
||||||
|
}
|
||||||
private:
|
private:
|
||||||
virtual void validate(const T& value) const {}
|
virtual void validate(const T& value) const {}
|
||||||
T m_value;
|
T m_value;
|
||||||
|
|
|
@ -218,6 +218,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 void option_update(WorstMatch, const Context&)
|
||||||
|
{
|
||||||
|
throw runtime_error("no update operation supported for this option type");
|
||||||
|
}
|
||||||
|
|
||||||
template<typename EffectiveType, typename LineType, typename ColumnType>
|
template<typename EffectiveType, typename LineType, typename ColumnType>
|
||||||
inline void option_from_string(StringView str, LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
|
inline void option_from_string(StringView str, LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue
Block a user