From 4cb74623bbfd489b46edfadde5529e07a0dc557a Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Sat, 12 Dec 2015 11:45:45 +0000 Subject: [PATCH] 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. --- rc/clang.kak | 6 +++--- rc/git-tools.kak | 10 +++++----- src/commands.cc | 6 +++--- src/highlighters.cc | 37 ++++++++++++++++++++++++++++++++++--- src/option_manager.hh | 7 +++++++ src/option_types.hh | 39 +++++++++++++++++++++++++++++++++++++++ 6 files changed, 91 insertions(+), 14 deletions(-) diff --git a/rc/clang.kak b/rc/clang.kak index 8bd24d52..eff8e2f3 100644 --- a/rc/clang.kak +++ b/rc/clang.kak @@ -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||${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 } } diff --git a/rc/git-tools.kak b/rc/git-tools.kak index f81339b6..8aeb7741 100644 --- a/rc/git-tools.kak +++ b/rc/git-tools.kak @@ -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]+)? @@.*/ { diff --git a/src/commands.cc b/src/commands.cc index d468dc59..dcee70cd 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -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 = ®.declare_option>(parser[1], docstring, {}, flags); else if (parser[0] == "str-list") opt = ®.declare_option>(parser[1], docstring, {}, flags); - else if (parser[0] == "line-flag-list") - opt = ®.declare_option>(parser[1], docstring, {}, flags); + else if (parser[0] == "line-flags") + opt = ®.declare_option>(parser[1], docstring, {}, flags); else throw runtime_error(format("unknown type {}", parser[0])); diff --git a/src/highlighters.cc b/src/highlighters.cc index 68f0bdb5..28e36660 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -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>(); + GlobalScope::instance().options()[option_name].get>(); auto func = [=](const Context& context, HighlightFlags flags, DisplayBuffer& display_buffer, BufferRange) { - auto& lines_opt = context.options()[option_name]; - auto& lines = lines_opt.get>(); + auto& line_flags = context.options()[option_name].get_mutable>(); + 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); diff --git a/src/option_manager.hh b/src/option_manager.hh index 8e21808c..6c4dce18 100644 --- a/src/option_manager.hh +++ b/src/option_manager.hh @@ -44,6 +44,7 @@ public: virtual ~Option() = default; template const T& get() const; + template T& get_mutable(); template void set(const T& val, bool notify=true); template 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 const T& Option::get() const return typed_opt->get(); } +template T& Option::get_mutable() +{ + return const_cast(get()); +} + template void Option::set(const T& val, bool notify) { auto* typed_opt = dynamic_cast*>(this); diff --git a/src/option_types.hh b/src/option_types.hh index 12f5e4fd..73a8bcfb 100644 --- a/src/option_types.hh +++ b/src/option_types.hh @@ -223,6 +223,45 @@ constexpr Array, 3> enum_desc(DebugFlags) } }; } +template +struct TimestampedList +{ + size_t timestamp; + Vector list; +}; + +template +inline bool operator==(const TimestampedList& lhs, const TimestampedList& rhs) +{ + return lhs.timestamp == rhs.timestamp and lhs.list == rhs.list; +} + +template +inline bool operator!=(const TimestampedList& lhs, const TimestampedList& rhs) +{ + return not (lhs == rhs); +} + +template +inline String option_to_string(const TimestampedList& opt) +{ + return format("{}:{}", opt.timestamp, option_to_string(opt.list)); +} + +template +inline void option_from_string(StringView str, TimestampedList& opt) +{ + auto it = find(str, ':'); + opt.timestamp = str_to_int({str.begin(), it}); + option_from_string({it+1, str.end()}, opt.list); +} + +template +inline bool option_add(TimestampedList& opt, StringView str) +{ + return option_add(opt.list, str); +} + } #endif // option_types_hh_INCLUDED