mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2024-11-22 07:30:19 +00:00
LibLine: Support wrapping lines in actual_rendered_string_metrics
This will allow us to use this API to split an input to visible lines of a specified width.
This commit is contained in:
parent
6f28c8deb0
commit
299ca10fd5
Notes:
sideshowbarker
2024-07-17 09:37:30 +09:00
Author: https://github.com/LucasChollet Commit: https://github.com/SerenityOS/serenity/commit/299ca10fd5 Pull-request: https://github.com/SerenityOS/serenity/pull/15976 Issue: https://github.com/SerenityOS/serenity/issues/15242 Reviewed-by: https://github.com/alimpfard
3 changed files with 42 additions and 8 deletions
|
@ -1779,7 +1779,7 @@ enum VTState {
|
|||
BracketArgsSemi = 7,
|
||||
Title = 9,
|
||||
};
|
||||
static VTState actual_rendered_string_length_step(StringMetrics& metrics, size_t index, StringMetrics::LineMetrics& current_line, u32 c, u32 next_c, VTState state, Optional<Style::Mask> const& mask);
|
||||
static VTState actual_rendered_string_length_step(StringMetrics& metrics, size_t index, StringMetrics::LineMetrics& current_line, u32 c, u32 next_c, VTState state, Optional<Style::Mask> const& mask, Optional<size_t> const& maximum_line_width = {}, Optional<size_t&> last_return = {});
|
||||
|
||||
enum class MaskedSelectionDecision {
|
||||
Skip,
|
||||
|
@ -1813,12 +1813,13 @@ static MaskedSelectionDecision resolve_masked_selection(Optional<Style::Mask>& m
|
|||
return MaskedSelectionDecision::Continue;
|
||||
}
|
||||
|
||||
StringMetrics Editor::actual_rendered_string_metrics(StringView string, RedBlackTree<u32, Optional<Style::Mask>> const& masks)
|
||||
StringMetrics Editor::actual_rendered_string_metrics(StringView string, RedBlackTree<u32, Optional<Style::Mask>> const& masks, Optional<size_t> maximum_line_width)
|
||||
{
|
||||
StringMetrics metrics;
|
||||
StringMetrics::LineMetrics current_line;
|
||||
VTState state { Free };
|
||||
Utf8View view { string };
|
||||
size_t last_return {};
|
||||
auto it = view.begin();
|
||||
Optional<Style::Mask> mask;
|
||||
size_t i = 0;
|
||||
|
@ -1835,7 +1836,7 @@ StringMetrics Editor::actual_rendered_string_metrics(StringView string, RedBlack
|
|||
continue;
|
||||
|
||||
auto next_c = it_copy == view.end() ? 0 : *it_copy;
|
||||
state = actual_rendered_string_length_step(metrics, view.iterator_offset(it), current_line, c, next_c, state, mask);
|
||||
state = actual_rendered_string_length_step(metrics, view.iterator_offset(it), current_line, c, next_c, state, mask, maximum_line_width, last_return);
|
||||
if (!mask_it.is_end() && mask_it.key() <= i) {
|
||||
auto mask_it_peek = mask_it;
|
||||
++mask_it_peek;
|
||||
|
@ -1890,8 +1891,31 @@ StringMetrics Editor::actual_rendered_string_metrics(Utf32View const& view, RedB
|
|||
return metrics;
|
||||
}
|
||||
|
||||
VTState actual_rendered_string_length_step(StringMetrics& metrics, size_t index, StringMetrics::LineMetrics& current_line, u32 c, u32 next_c, VTState state, Optional<Style::Mask> const& mask)
|
||||
VTState actual_rendered_string_length_step(StringMetrics& metrics, size_t index, StringMetrics::LineMetrics& current_line, u32 c, u32 next_c, VTState state, Optional<Style::Mask> const& mask, Optional<size_t> const& maximum_line_width, Optional<size_t&> last_return)
|
||||
{
|
||||
auto const save_line = [&metrics, ¤t_line, &last_return, &index]() {
|
||||
if (last_return.has_value()) {
|
||||
auto const last_index = index - 1;
|
||||
current_line.bit_length = last_index - *last_return + 1;
|
||||
last_return.value() = last_index + 1;
|
||||
}
|
||||
metrics.line_metrics.append(current_line);
|
||||
|
||||
current_line.masked_chars = {};
|
||||
current_line.length = 0;
|
||||
current_line.visible_length = 0;
|
||||
current_line.bit_length = {};
|
||||
};
|
||||
|
||||
// FIXME: current_line.visible_length can go above maximum_line_width when using masks
|
||||
if (maximum_line_width.has_value() && maximum_line_width.value() >= current_line.visible_length)
|
||||
save_line();
|
||||
|
||||
ScopeGuard bit_length_update { [&last_return, ¤t_line, &index]() {
|
||||
if (last_return.has_value())
|
||||
current_line.bit_length = index - *last_return + 1;
|
||||
} };
|
||||
|
||||
switch (state) {
|
||||
case Free: {
|
||||
if (c == '\x1b') { // escape
|
||||
|
@ -1900,14 +1924,19 @@ VTState actual_rendered_string_length_step(StringMetrics& metrics, size_t index,
|
|||
if (c == '\r') { // carriage return
|
||||
current_line.masked_chars = {};
|
||||
current_line.length = 0;
|
||||
current_line.visible_length = 0;
|
||||
if (!metrics.line_metrics.is_empty())
|
||||
metrics.line_metrics.last() = { {}, 0 };
|
||||
return state;
|
||||
}
|
||||
if (c == '\n') { // return
|
||||
metrics.line_metrics.append(current_line);
|
||||
current_line.masked_chars = {};
|
||||
current_line.length = 0;
|
||||
save_line();
|
||||
return state;
|
||||
}
|
||||
if (c == '\t') {
|
||||
// Tabs are a special case, because their width is variable.
|
||||
++current_line.length;
|
||||
current_line.visible_length += (8 - (current_line.visible_length % 8));
|
||||
return state;
|
||||
}
|
||||
auto is_control = is_ascii_control(c);
|
||||
|
@ -1920,12 +1949,15 @@ VTState actual_rendered_string_length_step(StringMetrics& metrics, size_t index,
|
|||
// FIXME: This will not support anything sophisticated
|
||||
if (mask.has_value()) {
|
||||
current_line.length += mask->replacement_view.length();
|
||||
current_line.visible_length += mask->replacement_view.length();
|
||||
metrics.total_length += mask->replacement_view.length();
|
||||
} else if (is_control) {
|
||||
current_line.length += current_line.masked_chars.last().masked_length;
|
||||
current_line.visible_length += current_line.masked_chars.last().masked_length;
|
||||
metrics.total_length += current_line.masked_chars.last().masked_length;
|
||||
} else {
|
||||
++current_line.length;
|
||||
++current_line.visible_length;
|
||||
++metrics.total_length;
|
||||
}
|
||||
return state;
|
||||
|
|
|
@ -160,7 +160,7 @@ public:
|
|||
void register_key_input_callback(Vector<Key> keys, Function<bool(Editor&)> callback) { m_callback_machine.register_key_input_callback(move(keys), move(callback)); }
|
||||
void register_key_input_callback(Key key, Function<bool(Editor&)> callback) { register_key_input_callback(Vector<Key> { key }, move(callback)); }
|
||||
|
||||
static StringMetrics actual_rendered_string_metrics(StringView, RedBlackTree<u32, Optional<Style::Mask>> const& masks = {});
|
||||
static StringMetrics actual_rendered_string_metrics(StringView, RedBlackTree<u32, Optional<Style::Mask>> const& masks = {}, Optional<size_t> maximum_line_width = {});
|
||||
static StringMetrics actual_rendered_string_metrics(Utf32View const&, RedBlackTree<u32, Optional<Style::Mask>> const& masks = {});
|
||||
|
||||
Function<Vector<CompletionSuggestion>(Editor const&)> on_tab_complete;
|
||||
|
|
|
@ -20,6 +20,8 @@ struct StringMetrics {
|
|||
struct LineMetrics {
|
||||
Vector<MaskedChar> masked_chars;
|
||||
size_t length { 0 };
|
||||
size_t visible_length { 0 };
|
||||
Optional<size_t> bit_length { 0 };
|
||||
|
||||
size_t total_length() const { return length; }
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue