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