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
|
||||
{
|
||||
|
||||
StringView option_type_name(Meta::Type<TimestampedList<LineAndSpec>>)
|
||||
{
|
||||
return "line-specs";
|
||||
}
|
||||
|
||||
StringView option_type_name(Meta::Type<TimestampedList<RangeAndString>>)
|
||||
{
|
||||
return "range-specs";
|
||||
}
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
|
@ -1289,6 +1279,21 @@ const CommandDesc set_option_cmd = {
|
|||
}
|
||||
};
|
||||
|
||||
Completions complete_option(const Context& context, CompletionFlags,
|
||||
CommandParameters params, size_t token_to_complete,
|
||||
ByteCount pos_in_token)
|
||||
{
|
||||
if (token_to_complete == 0)
|
||||
{
|
||||
static constexpr auto scopes = { "buffer", "window", "current" };
|
||||
return { 0_byte, params[0].length(), complete(params[0], pos_in_token, scopes) };
|
||||
}
|
||||
else if (token_to_complete == 1)
|
||||
return { 0_byte, params[1].length(),
|
||||
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) };
|
||||
return Completions{};
|
||||
}
|
||||
|
||||
const CommandDesc unset_option_cmd = {
|
||||
"unset-option",
|
||||
"unset",
|
||||
|
@ -1298,20 +1303,7 @@ const CommandDesc unset_option_cmd = {
|
|||
ParameterDesc{ {}, ParameterDesc::Flags::None, 2, 2 },
|
||||
CommandFlags::None,
|
||||
option_doc_helper,
|
||||
[](const Context& context, CompletionFlags,
|
||||
CommandParameters params, size_t token_to_complete,
|
||||
ByteCount pos_in_token) -> Completions
|
||||
{
|
||||
if (token_to_complete == 0)
|
||||
{
|
||||
static constexpr auto scopes = { "buffer", "window", "current" };
|
||||
return { 0_byte, params[0].length(), complete(params[0], pos_in_token, scopes) };
|
||||
}
|
||||
else if (token_to_complete == 1)
|
||||
return { 0_byte, params[1].length(),
|
||||
GlobalScope::instance().option_registry().complete_option_name(params[1], pos_in_token) };
|
||||
return Completions{};
|
||||
},
|
||||
complete_option,
|
||||
[](const ParametersParser& parser, Context& context, const ShellContext&)
|
||||
{
|
||||
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 = {
|
||||
"declare-option",
|
||||
"decl",
|
||||
|
@ -2142,6 +2152,7 @@ void register_commands()
|
|||
register_command(source_cmd);
|
||||
register_command(set_option_cmd);
|
||||
register_command(unset_option_cmd);
|
||||
register_command(update_option_cmd);
|
||||
register_command(declare_option_cmd);
|
||||
register_command(map_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
|
||||
{
|
||||
FlagLinesHighlighter(String option_name, String default_face)
|
||||
|
@ -1184,8 +1225,6 @@ struct FlagLinesHighlighter : Highlighter
|
|||
m_option_name{std::move(option_name)},
|
||||
m_default_face{std::move(default_face)} {}
|
||||
|
||||
using LineAndSpecList = TimestampedList<LineAndSpec>;
|
||||
|
||||
static HighlighterAndId create(HighlighterParameters params)
|
||||
{
|
||||
if (params.size() != 2)
|
||||
|
@ -1207,7 +1246,7 @@ private:
|
|||
{
|
||||
auto& line_flags = context.options()[m_option_name].get_mutable<LineAndSpecList>();
|
||||
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);
|
||||
Vector<DisplayLine> display_lines;
|
||||
|
@ -1257,7 +1296,7 @@ private:
|
|||
{
|
||||
auto& line_flags = context.options()[m_option_name].get_mutable<LineAndSpecList>();
|
||||
auto& buffer = context.buffer();
|
||||
update_line_flags_ifn(buffer, line_flags);
|
||||
update_line_specs_ifn(buffer, line_flags);
|
||||
|
||||
ColumnCount width = 0;
|
||||
try
|
||||
|
@ -1274,42 +1313,6 @@ private:
|
|||
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_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_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())
|
||||
return;
|
||||
|
@ -1373,6 +1376,11 @@ static void update_ranges_ifn(const Buffer& buffer, TimestampedList<RangeAndStri
|
|||
range_and_faces.prefix = buffer.timestamp();
|
||||
}
|
||||
|
||||
void option_update(RangeAndStringList& opt, const Context& context)
|
||||
{
|
||||
update_ranges_ifn(context.buffer(), opt);
|
||||
}
|
||||
|
||||
struct RangesHighlighter : Highlighter
|
||||
{
|
||||
RangesHighlighter(String option_name)
|
||||
|
@ -1386,7 +1394,7 @@ struct RangesHighlighter : Highlighter
|
|||
|
||||
const String& option_name = params[0];
|
||||
// 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)};
|
||||
}
|
||||
|
@ -1395,7 +1403,7 @@ private:
|
|||
void do_highlight(const Context& context, HighlightPass, DisplayBuffer& display_buffer, BufferRange) override
|
||||
{
|
||||
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);
|
||||
|
||||
for (auto& range : range_and_faces.list)
|
||||
|
@ -1428,7 +1436,7 @@ struct ReplaceRangesHighlighter : Highlighter
|
|||
|
||||
const String& option_name = params[0];
|
||||
// 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)};
|
||||
}
|
||||
|
@ -1437,7 +1445,7 @@ private:
|
|||
void do_highlight(const Context& context, HighlightPass, DisplayBuffer& display_buffer, BufferRange) override
|
||||
{
|
||||
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);
|
||||
|
||||
for (auto& range : range_and_faces.list)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
|
||||
#include "color.hh"
|
||||
#include "highlighter.hh"
|
||||
#include "option.hh"
|
||||
|
||||
namespace Kakoune
|
||||
{
|
||||
|
@ -19,7 +20,22 @@ String option_to_string(InclusiveBufferRange range);
|
|||
void option_from_string(StringView str, InclusiveBufferRange& opt);
|
||||
|
||||
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 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 Context;
|
||||
|
||||
enum class OptionFlags
|
||||
{
|
||||
|
@ -52,6 +53,7 @@ public:
|
|||
virtual String get_as_string() const = 0;
|
||||
virtual void set_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;
|
||||
OptionManager& manager() const { return m_manager; }
|
||||
|
@ -140,6 +142,10 @@ public:
|
|||
if (option_add(m_value, str))
|
||||
m_manager.on_option_changed(*this);
|
||||
}
|
||||
void update(const Context& context) override
|
||||
{
|
||||
option_update(m_value, context);
|
||||
}
|
||||
private:
|
||||
virtual void validate(const T& value) const {}
|
||||
T m_value;
|
||||
|
|
|
@ -218,6 +218,11 @@ inline bool option_add(WorstMatch, StringView)
|
|||
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>
|
||||
inline void option_from_string(StringView str, LineAndColumn<EffectiveType, LineType, ColumnType>& opt)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue
Block a user