diff --git a/README.asciidoc b/README.asciidoc index 43d21c4f..a6141346 100644 --- a/README.asciidoc +++ b/README.asciidoc @@ -718,6 +718,7 @@ using ``, followed, by: * *w* : word completion (current buffer) * *W* : word completion (all buffers) * *l* : line completion (current buffer) + * *L* : line completion (all buffers) Completion candidates can be selected using `` and ``. diff --git a/src/input_handler.cc b/src/input_handler.cc index a891ccc8..6fa41d6f 100644 --- a/src/input_handler.cc +++ b/src/input_handler.cc @@ -1224,12 +1224,15 @@ public: if (key.key == 'W') m_completer.explicit_word_all_complete(); if (key.key == 'l') - m_completer.explicit_line_complete(); + m_completer.explicit_line_buffer_complete(); + if (key.key == 'L') + m_completer.explicit_line_all_complete(); }, "enter completion type", "f: filename\n" "w: word (current buffer)\n" "W: word (all buffers)\n" - "l: line\n"); + "l: line (current buffer)\n" + "L: line (all buffers)\n"); update_completions = false; } else if (key == ctrl('o')) diff --git a/src/insert_completer.cc b/src/insert_completer.cc index 3e56c90d..d4e81eda 100644 --- a/src/insert_completer.cc +++ b/src/insert_completer.cc @@ -33,7 +33,7 @@ String option_to_string(const InsertCompleterDesc& opt) case InsertCompleterDesc::Option: return "option=" + (opt.param ? *opt.param : ""); case InsertCompleterDesc::Line: - return "line"; + return "line=" + (opt.param ? *opt.param : ""); } kak_assert(false); return ""; @@ -63,11 +63,15 @@ void option_from_string(StringView str, InsertCompleterDesc& opt) opt.param = Optional{}; return; } - else if (str == "line") + else if (str.substr(0_byte, 5_byte) == "line=") { - opt.mode = InsertCompleterDesc::Line; - opt.param = Optional{}; - return; + auto param = str.substr(5_byte); + if (param == "all" or param == "buffer") + { + opt.mode = InsertCompleterDesc::Line; + opt.param = param.str(); + return; + } } throw runtime_error(format("invalid completer description: '{}'", str)); } @@ -342,6 +346,7 @@ InsertCompletion complete_option(const SelectionList& sels, return {}; } +template InsertCompletion complete_line(const SelectionList& sels, const OptionManager& options) { const Buffer& buffer = sels.buffer(); @@ -352,18 +357,37 @@ InsertCompletion complete_line(const SelectionList& sels, const OptionManager& o StringView prefix = buffer[cursor_pos.line].substr(0_byte, cursor_pos.column); InsertCompletion::CandidateList candidates; - for (LineCount l = 0_line; l < buffer.line_count(); ++l) - { - if (l == cursor_pos.line) - continue; - ByteCount len = buffer[l].length(); - if (len > cursor_pos.column and std::equal(prefix.begin(), prefix.end(), buffer[l].begin())) + + auto add_candidates = [&](const Buffer& buf) { + for (LineCount l = 0_line; l < buf.line_count(); ++l) { - StringView candidate = buffer[l].substr(0_byte, len-1); - candidates.push_back({candidate.str(), "", - expand_tabs(candidate, tabstop, column)}); + // perf: it's unlikely the user intends to search among >10 candidates anyway + if (candidates.size() == 100) + break; + if (buf.name() == buffer.name() && l == cursor_pos.line) + continue; + ByteCount len = buf[l].length(); + if (len > cursor_pos.column and std::equal(prefix.begin(), prefix.end(), buf[l].begin())) + { + StringView candidate = buf[l].substr(0_byte, len-1); + candidates.push_back({candidate.str(), "", + expand_tabs(candidate, tabstop, column)}); + } + } + }; + + add_candidates(buffer); + + if (other_buffers) + { + for (const auto& buf : BufferManager::instance()) + { + if (buf.get() == &buffer or buf->flags() & Buffer::Flags::Debug) + continue; + add_candidates(*buf); } } + if (candidates.empty()) return {}; std::sort(candidates.begin(), candidates.end()); @@ -500,7 +524,12 @@ bool InsertCompleter::setup_ifn() try_complete(complete_word)) return true; if (completer.mode == InsertCompleterDesc::Line and - try_complete(complete_line)) + *completer.param == "buffer" and + try_complete(complete_line)) + return true; + if (completer.mode == InsertCompleterDesc::Line and + *completer.param == "all" and + try_complete(complete_line)) return true; } return false; @@ -584,10 +613,16 @@ void InsertCompleter::explicit_word_all_complete() m_explicit_completer = complete_word; } -void InsertCompleter::explicit_line_complete() +void InsertCompleter::explicit_line_buffer_complete() { - try_complete(complete_line); - m_explicit_completer = complete_line; + try_complete(complete_line); + m_explicit_completer = complete_line; +} + +void InsertCompleter::explicit_line_all_complete() +{ + try_complete(complete_line); + m_explicit_completer = complete_line; } } diff --git a/src/insert_completer.hh b/src/insert_completer.hh index e9c73d3f..a47a4267 100644 --- a/src/insert_completer.hh +++ b/src/insert_completer.hh @@ -88,7 +88,8 @@ public: void explicit_file_complete(); void explicit_word_buffer_complete(); void explicit_word_all_complete(); - void explicit_line_complete(); + void explicit_line_buffer_complete(); + void explicit_line_all_complete(); private: bool setup_ifn();