Speed up wrapping at word boundaries.

Previously, when wrapping lines at word boundaries, we would iterate forwards
for "wrap-width" characters, then iterate backwards until we found a word-break,
which was horribly slow.

Now we record the last word-boundary we saw as we iterate forwards, getting a
result in one pass.

Fixes #2339.
This commit is contained in:
Tim Allen 2018-08-28 17:34:18 +10:00
parent 373858f9bf
commit 82c01c5dd3

View File

@ -822,6 +822,8 @@ struct WrapHighlighter : Highlighter
StringView content = buffer[line]; StringView content = buffer[line];
SplitPos pos = current; SplitPos pos = current;
SplitPos last_boundary = {0, 0};
while (pos.byte < content.length() and pos.column < target_column) while (pos.byte < content.length() and pos.column < target_column)
{ {
if (content[pos.byte] == '\t') if (content[pos.byte] == '\t')
@ -831,32 +833,30 @@ struct WrapHighlighter : Highlighter
break; break;
pos.column = next_column; pos.column = next_column;
++pos.byte; ++pos.byte;
last_boundary = pos;
} }
else else
{ {
const char* it = &content[pos.byte]; const char* it = &content[pos.byte];
const ColumnCount width = codepoint_width(utf8::read_codepoint(it, content.end())); const Codepoint cp = utf8::read_codepoint(it, content.end());
const ColumnCount width = codepoint_width(cp);
if (pos.column + width > target_column and pos.byte != current.byte) // the target column was in the char if (pos.column + width > target_column and pos.byte != current.byte) // the target column was in the char
{
if (!is_word<WORD>(cp))
last_boundary = pos;
break; break;
}
pos.column += width; pos.column += width;
pos.byte = (int)(it - content.begin()); pos.byte = (int)(it - content.begin());
if (!is_word<WORD>(cp))
last_boundary = pos;
} }
} }
if (m_word_wrap and pos.byte < content.length()) // find a word boundary before current position if (m_word_wrap and pos.byte < content.length()) // find a word boundary before current position
{ if (last_boundary.byte > 0)
utf8::iterator<const char*> it{&content[pos.byte], content}; pos = last_boundary;
while (it != content.begin() and is_word<WORD>(*it))
--it;
if (it != content.begin() and it != &content[pos.byte] and
(it+1) > &content[current.byte])
{
const ByteCount word_split = (it+1).base() - content.begin();
pos.column -= content.substr(word_split, pos.byte - word_split).column_length();
pos.byte = word_split;
}
}
return pos; return pos;
}; };