mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-12-25 15:39:55 +00:00
LibLine: Correctly track the completion start and end
To achieve this, the API was tweaked a bit to allow for easier tracking of completions. This API change is non-disruptive to any application that does not use anchored styles.
This commit is contained in:
parent
5358608a94
commit
0751592a18
Notes:
sideshowbarker
2024-07-19 06:17:42 +09:00
Author: https://github.com/alimpfard Commit: https://github.com/SerenityOS/serenity/commit/0751592a183 Pull-request: https://github.com/SerenityOS/serenity/pull/2315
3 changed files with 29 additions and 7 deletions
|
@ -445,7 +445,7 @@ String Editor::get_line(const String& prompt)
|
||||||
// reverse tab can count as regular tab here
|
// reverse tab can count as regular tab here
|
||||||
m_times_tab_pressed++;
|
m_times_tab_pressed++;
|
||||||
|
|
||||||
int token_start = m_cursor - 1 - m_last_shown_suggestion_display_length;
|
int token_start = m_cursor;
|
||||||
|
|
||||||
// ask for completions only on the first tab
|
// ask for completions only on the first tab
|
||||||
// and scan for the largest common prefix to display
|
// and scan for the largest common prefix to display
|
||||||
|
@ -523,7 +523,8 @@ String Editor::get_line(const String& prompt)
|
||||||
m_refresh_needed = true;
|
m_refresh_needed = true;
|
||||||
}
|
}
|
||||||
m_last_shown_suggestion = m_suggestions[m_next_suggestion_index];
|
m_last_shown_suggestion = m_suggestions[m_next_suggestion_index];
|
||||||
m_last_shown_suggestion.token_start_index = token_start - m_next_suggestion_invariant_offset - m_last_shown_suggestion.trailing_trivia.length();
|
m_last_shown_suggestion.token_start_index = token_start - m_next_suggestion_invariant_offset - m_next_suggestion_static_offset;
|
||||||
|
dbg() << "Last shown suggestion token start index: " << m_last_shown_suggestion.token_start_index << " Token Start " << token_start << " invariant offset " << m_next_suggestion_invariant_offset;
|
||||||
m_last_shown_suggestion_display_length = m_last_shown_suggestion.text.length();
|
m_last_shown_suggestion_display_length = m_last_shown_suggestion.text.length();
|
||||||
m_last_shown_suggestion_was_complete = true;
|
m_last_shown_suggestion_was_complete = true;
|
||||||
if (m_times_tab_pressed == 1) {
|
if (m_times_tab_pressed == 1) {
|
||||||
|
@ -537,7 +538,8 @@ String Editor::get_line(const String& prompt)
|
||||||
m_times_tab_pressed = 0;
|
m_times_tab_pressed = 0;
|
||||||
// add in the trivia of the last selected suggestion
|
// add in the trivia of the last selected suggestion
|
||||||
insert(m_last_shown_suggestion.trailing_trivia);
|
insert(m_last_shown_suggestion.trailing_trivia);
|
||||||
m_last_shown_suggestion_display_length += m_last_shown_suggestion.trailing_trivia.length();
|
m_last_shown_suggestion_display_length = 0;
|
||||||
|
readjust_anchored_styles(m_last_shown_suggestion.token_start_index, ModificationKind::ForcedOverlapRemoval);
|
||||||
stylize({ m_last_shown_suggestion.token_start_index, m_cursor, Span::Mode::CodepointOriented }, m_last_shown_suggestion.style);
|
stylize({ m_last_shown_suggestion.token_start_index, m_cursor, Span::Mode::CodepointOriented }, m_last_shown_suggestion.style);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -659,6 +661,8 @@ String Editor::get_line(const String& prompt)
|
||||||
|
|
||||||
if (m_times_tab_pressed) {
|
if (m_times_tab_pressed) {
|
||||||
// Apply the style of the last suggestion
|
// Apply the style of the last suggestion
|
||||||
|
dbg() << "Last shown suggestion token start index: " << m_last_shown_suggestion.token_start_index << " invariant offset " << m_next_suggestion_invariant_offset << " static offset " << m_next_suggestion_static_offset;
|
||||||
|
readjust_anchored_styles(m_last_shown_suggestion.token_start_index, ModificationKind::ForcedOverlapRemoval);
|
||||||
stylize({ m_last_shown_suggestion.token_start_index, m_cursor, Span::Mode::CodepointOriented }, m_last_shown_suggestion.style);
|
stylize({ m_last_shown_suggestion.token_start_index, m_cursor, Span::Mode::CodepointOriented }, m_last_shown_suggestion.style);
|
||||||
// we probably have some suggestions drawn
|
// we probably have some suggestions drawn
|
||||||
// let's clean them up
|
// let's clean them up
|
||||||
|
@ -1415,9 +1419,16 @@ void Editor::readjust_anchored_styles(size_t hint_index, ModificationKind modifi
|
||||||
};
|
};
|
||||||
Vector<Anchor> anchors_to_relocate;
|
Vector<Anchor> anchors_to_relocate;
|
||||||
auto index_shift = modification == ModificationKind::Insertion ? 1 : -1;
|
auto index_shift = modification == ModificationKind::Insertion ? 1 : -1;
|
||||||
|
auto forced_removal = modification == ModificationKind::ForcedOverlapRemoval;
|
||||||
|
|
||||||
for (auto& start_entry : m_anchored_spans_starting) {
|
for (auto& start_entry : m_anchored_spans_starting) {
|
||||||
for (auto& end_entry : start_entry.value) {
|
for (auto& end_entry : start_entry.value) {
|
||||||
|
if (forced_removal) {
|
||||||
|
if (start_entry.key <= hint_index && end_entry.key >= hint_index) {
|
||||||
|
// remove any overlapping regions
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
if (start_entry.key >= hint_index) {
|
if (start_entry.key >= hint_index) {
|
||||||
if (start_entry.key == hint_index && end_entry.key == hint_index + 1 && modification == ModificationKind::Removal) {
|
if (start_entry.key == hint_index && end_entry.key == hint_index + 1 && modification == ModificationKind::Removal) {
|
||||||
// remove the anchor, as all its text was wiped
|
// remove the anchor, as all its text was wiped
|
||||||
|
@ -1443,5 +1454,4 @@ void Editor::readjust_anchored_styles(size_t hint_index, ModificationKind modifi
|
||||||
stylize(relocation.new_span, relocation.style);
|
stylize(relocation.new_span, relocation.style);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -169,9 +169,17 @@ public:
|
||||||
void stylize(const Span&, const Style&);
|
void stylize(const Span&, const Style&);
|
||||||
void strip_styles(bool strip_anchored = false);
|
void strip_styles(bool strip_anchored = false);
|
||||||
|
|
||||||
void suggest(size_t invariant_offset = 0, size_t index = 0) const
|
// Invariant Offset is an offset into the suggested data, hinting the editor what parts of the suggestion will not change
|
||||||
|
// Static Offset is an offset into the token, signifying where the suggestions start
|
||||||
|
// e.g.
|
||||||
|
// foobar<suggestion initiated>, on_tab_complete returns "barx", "bary", "barz"
|
||||||
|
// ^ ^
|
||||||
|
// +-|- static offset: the suggestions start here
|
||||||
|
// +- invariant offset: the suggestions do not change up to here
|
||||||
|
void suggest(size_t invariant_offset = 0, size_t static_offset = 0) const
|
||||||
{
|
{
|
||||||
m_next_suggestion_index = index;
|
m_next_suggestion_index = 0;
|
||||||
|
m_next_suggestion_static_offset = static_offset;
|
||||||
m_next_suggestion_invariant_offset = invariant_offset;
|
m_next_suggestion_invariant_offset = invariant_offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -207,6 +215,7 @@ private:
|
||||||
enum class ModificationKind {
|
enum class ModificationKind {
|
||||||
Insertion,
|
Insertion,
|
||||||
Removal,
|
Removal,
|
||||||
|
ForcedOverlapRemoval,
|
||||||
};
|
};
|
||||||
void readjust_anchored_styles(size_t hint_index, ModificationKind);
|
void readjust_anchored_styles(size_t hint_index, ModificationKind);
|
||||||
|
|
||||||
|
@ -322,6 +331,7 @@ private:
|
||||||
bool m_last_shown_suggestion_was_complete { false };
|
bool m_last_shown_suggestion_was_complete { false };
|
||||||
mutable size_t m_next_suggestion_index { 0 };
|
mutable size_t m_next_suggestion_index { 0 };
|
||||||
mutable size_t m_next_suggestion_invariant_offset { 0 };
|
mutable size_t m_next_suggestion_invariant_offset { 0 };
|
||||||
|
mutable size_t m_next_suggestion_static_offset { 0 };
|
||||||
size_t m_largest_common_suggestion_prefix_length { 0 };
|
size_t m_largest_common_suggestion_prefix_length { 0 };
|
||||||
size_t m_last_displayed_suggestion_index { 0 };
|
size_t m_last_displayed_suggestion_index { 0 };
|
||||||
|
|
||||||
|
|
|
@ -1540,6 +1540,7 @@ Vector<Line::CompletionSuggestion> Shell::complete(const Line::Editor& editor)
|
||||||
}
|
}
|
||||||
|
|
||||||
String path;
|
String path;
|
||||||
|
String original_token = token;
|
||||||
|
|
||||||
ssize_t last_slash = token.length() - 1;
|
ssize_t last_slash = token.length() - 1;
|
||||||
while (last_slash >= 0 && token[last_slash] != '/')
|
while (last_slash >= 0 && token[last_slash] != '/')
|
||||||
|
@ -1563,7 +1564,8 @@ Vector<Line::CompletionSuggestion> Shell::complete(const Line::Editor& editor)
|
||||||
// e. in `cd /foo/bar', 'bar' is the invariant
|
// e. in `cd /foo/bar', 'bar' is the invariant
|
||||||
// since we are not suggesting anything starting with
|
// since we are not suggesting anything starting with
|
||||||
// `/foo/', but rather just `bar...'
|
// `/foo/', but rather just `bar...'
|
||||||
editor.suggest(escape_token(token).length(), 0);
|
auto token_length = escape_token(token).length();
|
||||||
|
editor.suggest(token_length, original_token.length() - token_length);
|
||||||
|
|
||||||
// only suggest dot-files if path starts with a dot
|
// only suggest dot-files if path starts with a dot
|
||||||
Core::DirIterator files(path,
|
Core::DirIterator files(path,
|
||||||
|
|
Loading…
Reference in a new issue