Store the buffer timestamp in line flags options respect it for highlighting

Option content is auto updated to match current buffer, so that line flags
are updated according to buffer modifications.
This commit is contained in:
Maxime Coste 2015-12-12 11:45:45 +00:00
parent 70250fc1e3
commit 4cb74623bb
6 changed files with 91 additions and 14 deletions

View File

@ -2,7 +2,7 @@ decl str clang_options
decl -hidden str clang_tmp_dir
decl -hidden str-list clang_completions
decl -hidden line-flag-list clang_flags
decl -hidden line-flags clang_flags
decl -hidden str clang_errors
def clang-parse -params 0..1 -docstring "Parse the contents of the current buffer with clang" %{
@ -85,7 +85,7 @@ def clang-parse -params 0..1 -docstring "Parse the contents of the current buffe
sed -e "s|<stdin>|${kak_bufname}|g" < ${dir}/stderr > ${dir}/fifo
echo "set 'buffer=${kak_buffile}' clang_flags %{${flags}}
echo "set 'buffer=${kak_buffile}' clang_flags %{${kak_timestamp}:${flags}}
set 'buffer=${kak_buffile}' clang_errors '${errors}'" | kak -p ${kak_session}
) > /dev/null 2>&1 < /dev/null &
}
@ -131,7 +131,7 @@ def -allow-override -hidden clang-show-error-info %{ %sh{
} }
def clang-enable-diagnostics -docstring "Activate automatic diagnostics of the code by clang" %{
addhl flag_lines default clang_flags
addhl flag_lines default clang_flags'
hook window -group clang-diagnostics NormalIdle .* %{ clang-show-error-info }
}

View File

@ -20,8 +20,8 @@ hook global WinSetOption filetype=(?!git-status).* %{
rmhl git-status-highlight
}
decl line-flag-list git_blame_flags
decl line-flag-list git_diff_flags
decl line-flags git_blame_flags
decl line-flags git_diff_flags
face GitBlame default,magenta
@ -62,7 +62,7 @@ def -params 1.. \
(
echo "eval -client '$kak_client' %{
try %{ addhl flag_lines GitBlame git_blame_flags }
set buffer=$kak_bufname git_blame_flags ''
set buffer=$kak_bufname git_blame_flags '$kak_timestamp'
}" | kak -p ${kak_session}
git blame "$@" --incremental ${kak_buffile} | awk -e '
function send_flags(text, flag, i) {
@ -75,7 +75,7 @@ def -params 1.. \
flag=flag ":" line+i "|default|" text
}
cmd = "kak -p " ENVIRON["kak_session"]
print "set -add buffer=" ENVIRON["kak_bufname"] " git_blame_flags %{" flag "}" | cmd
print "set -add buffer=" ENVIRON["kak_bufname"] " git_blame_flags %{:" flag "}" | cmd
close(cmd)
}
/^([0-9a-f]{40}) ([0-9]+) ([0-9]+) ([0-9]+)/ {
@ -97,7 +97,7 @@ def -params 1.. \
git diff -U0 $kak_buffile | awk -e '
BEGIN {
line=0
flags="0|red|."
flags=ENVIRON["kak_timestamp"]
}
/^---.*/ {}
/^@@ -[0-9]+(,[0-9]+)? \+[0-9]+(,[0-9]+)? @@.*/ {

View File

@ -1104,7 +1104,7 @@ const CommandDesc declare_option_cmd = {
" regex: regular expression\n"
" int-list: list of integers\n"
" str-list: list of character strings\n"
" line-flag-list: list of line flags\n",
" line-flags: list of line flags\n",
ParameterDesc{
{ { "hidden", { false, "do not display option name when completing" } },
{ "docstring", { true, "specify option description" } } },
@ -1136,8 +1136,8 @@ const CommandDesc declare_option_cmd = {
opt = &reg.declare_option<Vector<int, MemoryDomain::Options>>(parser[1], docstring, {}, flags);
else if (parser[0] == "str-list")
opt = &reg.declare_option<Vector<String, MemoryDomain::Options>>(parser[1], docstring, {}, flags);
else if (parser[0] == "line-flag-list")
opt = &reg.declare_option<Vector<LineAndFlag, MemoryDomain::Options>>(parser[1], docstring, {}, flags);
else if (parser[0] == "line-flags")
opt = &reg.declare_option<TimestampedList<LineAndFlag>>(parser[1], docstring, {}, flags);
else
throw runtime_error(format("unknown type {}", parser[0]));

View File

@ -904,13 +904,44 @@ HighlighterAndId create_flag_lines_highlighter(HighlighterParameters params)
get_face(default_face); // validate param
// throw if wrong option type
GlobalScope::instance().options()[option_name].get<Vector<LineAndFlag, MemoryDomain::Options>>();
GlobalScope::instance().options()[option_name].get<TimestampedList<LineAndFlag>>();
auto func = [=](const Context& context, HighlightFlags flags,
DisplayBuffer& display_buffer, BufferRange)
{
auto& lines_opt = context.options()[option_name];
auto& lines = lines_opt.get<Vector<LineAndFlag, MemoryDomain::Options>>();
auto& line_flags = context.options()[option_name].get_mutable<TimestampedList<LineAndFlag>>();
auto& lines = line_flags.list;
auto& buffer = context.buffer();
if (line_flags.timestamp != buffer.timestamp())
{
std::sort(lines.begin(), lines.end(),
[](const LineAndFlag& lhs, const LineAndFlag& rhs)
{ return std::get<0>(lhs) < std::get<0>(rhs); });
auto modifs = compute_line_modifications(buffer, line_flags.timestamp);
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;
}
line_flags.timestamp = buffer.timestamp();
}
auto def_face = get_face(default_face);

View File

@ -44,6 +44,7 @@ public:
virtual ~Option() = default;
template<typename T> const T& get() const;
template<typename T> T& get_mutable();
template<typename T> void set(const T& val, bool notify=true);
template<typename T> bool is_of_type() const;
@ -122,6 +123,7 @@ public:
}
}
const T& get() const { return m_value; }
T& get_mutable() { return m_value; }
String get_as_string() const override
{
@ -167,6 +169,11 @@ template<typename T> const T& Option::get() const
return typed_opt->get();
}
template<typename T> T& Option::get_mutable()
{
return const_cast<T&>(get<T>());
}
template<typename T> void Option::set(const T& val, bool notify)
{
auto* typed_opt = dynamic_cast<TypedOption<T>*>(this);

View File

@ -223,6 +223,45 @@ constexpr Array<EnumDesc<DebugFlags>, 3> enum_desc(DebugFlags)
} };
}
template<typename T>
struct TimestampedList
{
size_t timestamp;
Vector<T, MemoryDomain::Options> list;
};
template<typename T>
inline bool operator==(const TimestampedList<T>& lhs, const TimestampedList<T>& rhs)
{
return lhs.timestamp == rhs.timestamp and lhs.list == rhs.list;
}
template<typename T>
inline bool operator!=(const TimestampedList<T>& lhs, const TimestampedList<T>& rhs)
{
return not (lhs == rhs);
}
template<typename T>
inline String option_to_string(const TimestampedList<T>& opt)
{
return format("{}:{}", opt.timestamp, option_to_string(opt.list));
}
template<typename T>
inline void option_from_string(StringView str, TimestampedList<T>& opt)
{
auto it = find(str, ':');
opt.timestamp = str_to_int({str.begin(), it});
option_from_string({it+1, str.end()}, opt.list);
}
template<typename T>
inline bool option_add(TimestampedList<T>& opt, StringView str)
{
return option_add(opt.list, str);
}
}
#endif // option_types_hh_INCLUDED