Wrap: Add -indent switch support that wraps preserving line indent

This commit is contained in:
Maxime Coste 2017-11-02 01:26:00 +08:00
parent 6bc408e9b9
commit 6f2088cbc4
2 changed files with 44 additions and 10 deletions

View File

@ -94,6 +94,9 @@ add-highlighter window regex //\h*(TODO:)[^\n]* 0:cyan 1:yellow,red
*-word*::: *-word*:::
wrap at word boundaries instead of codepoint boundaries. wrap at word boundaries instead of codepoint boundaries.
*-indent*:::
preserve line indent when wrapping.
*-width <max_width>*::: *-width <max_width>*:::
wrap text at *max_width* if the window is wider. wrap text at *max_width* if the window is wider.

View File

@ -654,8 +654,9 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params)
struct WrapHighlighter : Highlighter struct WrapHighlighter : Highlighter
{ {
WrapHighlighter(ColumnCount max_width, bool word_wrap) WrapHighlighter(ColumnCount max_width, bool word_wrap, bool preserve_indent)
: Highlighter{HighlightPass::Wrap}, m_max_width{max_width}, m_word_wrap{word_wrap} {} : Highlighter{HighlightPass::Wrap}, m_max_width{max_width},
m_word_wrap{word_wrap}, m_preserve_indent{preserve_indent} {}
void do_highlight(const Context& context, HighlightPass pass, void do_highlight(const Context& context, HighlightPass pass,
DisplayBuffer& display_buffer, BufferRange) override DisplayBuffer& display_buffer, BufferRange) override
@ -673,6 +674,9 @@ struct WrapHighlighter : Highlighter
{ {
const LineCount buf_line = it->range().begin.line; const LineCount buf_line = it->range().begin.line;
const ByteCount line_length = buffer[buf_line].length(); const ByteCount line_length = buffer[buf_line].length();
ColumnCount indent = m_preserve_indent ? line_indent(buffer, tabstop, buf_line) : 0_col;
if (indent >= wrap_column) // do not preserve indent when its bigger than wrap column
indent = 0;
auto coord = next_split_coord(buffer, wrap_column, tabstop, buf_line); auto coord = next_split_coord(buffer, wrap_column, tabstop, buf_line);
if (buffer.is_valid(coord) and not buffer.is_end(coord)) if (buffer.is_valid(coord) and not buffer.is_end(coord))
@ -695,9 +699,12 @@ struct WrapHighlighter : Highlighter
DisplayLine new_line{ AtomList{ atom_it, line.end() } }; DisplayLine new_line{ AtomList{ atom_it, line.end() } };
line.erase(atom_it, line.end()); line.erase(atom_it, line.end());
if (indent != 0)
new_line.insert(new_line.begin(), DisplayAtom{String{' ', indent}});
if (it+1 - display_buffer.lines().begin() == win_height) if (it+1 - display_buffer.lines().begin() == win_height)
{ {
if (cursor >= new_line.begin()->begin()) // strip first lines if cursor is not visible if (cursor >= new_line.range().begin) // strip first lines if cursor is not visible
{ {
display_buffer.lines().erase(display_buffer.lines().begin(), display_buffer.lines().begin()+1); display_buffer.lines().erase(display_buffer.lines().begin(), display_buffer.lines().begin()+1);
--it; --it;
@ -710,7 +717,7 @@ struct WrapHighlighter : Highlighter
} }
it = display_buffer.lines().insert(it+1, new_line); it = display_buffer.lines().insert(it+1, new_line);
coord = next_split_coord(buffer, wrap_column, tabstop, coord); coord = next_split_coord(buffer, wrap_column - indent, tabstop, coord);
atom_it = it->begin(); atom_it = it->begin();
} }
} }
@ -727,13 +734,14 @@ struct WrapHighlighter : Highlighter
const auto& cursor = context.selections().main().cursor(); const auto& cursor = context.selections().main().cursor();
const int tabstop = context.options()["tabstop"].get<int>(); const int tabstop = context.options()["tabstop"].get<int>();
auto line_wrap_count = [&](LineCount line) { auto line_wrap_count = [&](LineCount line, ColumnCount indent) {
LineCount count = 0; LineCount count = 0;
BufferCoord coord{line}; BufferCoord coord{line};
const ByteCount line_length = buffer[line].length(); const ByteCount line_length = buffer[line].length();
while (true) while (true)
{ {
coord = next_split_coord(buffer, wrap_column, tabstop, coord); coord = next_split_coord(buffer, wrap_column - (coord.column == 0 ? 0_col : indent),
tabstop, coord);
if (coord.column == line_length) if (coord.column == line_length)
break; break;
++count; ++count;
@ -756,7 +764,11 @@ struct WrapHighlighter : Highlighter
if (buf_line >= buffer.line_count()) if (buf_line >= buffer.line_count())
break; break;
const auto wrap_count = line_wrap_count(buf_line); ColumnCount indent = m_preserve_indent ? line_indent(buffer, tabstop, buf_line) : 0_col;
if (indent >= wrap_column) // do not preserve indent when its bigger than wrap column
indent = 0;
const auto wrap_count = line_wrap_count(buf_line, indent);
setup.window_range.line -= wrap_count; setup.window_range.line -= wrap_count;
if (win_line < setup.cursor_pos.line) if (win_line < setup.cursor_pos.line)
@ -767,10 +779,14 @@ struct WrapHighlighter : Highlighter
BufferCoord coord{buf_line}; BufferCoord coord{buf_line};
while (true) while (true)
{ {
auto split_coord = next_split_coord(buffer, wrap_column, tabstop, coord); auto split_coord = next_split_coord(buffer, wrap_column - (coord.column == 0 ? 0_col : indent),
tabstop, coord);
if (split_coord.column > cursor.column) if (split_coord.column > cursor.column)
{ {
setup.cursor_pos.column = get_column(buffer, tabstop, cursor) - get_column(buffer, tabstop, coord); setup.cursor_pos.column = get_column(buffer, tabstop, cursor) - get_column(buffer, tabstop, coord);
if (coord.column != 0)
setup.cursor_pos.column += indent;
break; break;
} }
++setup.cursor_pos.line; ++setup.cursor_pos.line;
@ -786,7 +802,7 @@ struct WrapHighlighter : Highlighter
while (setup.window_pos.line < cursor.line and while (setup.window_pos.line < cursor.line and
setup.cursor_pos.line >= win_height - setup.scroll_offset.line) setup.cursor_pos.line >= win_height - setup.scroll_offset.line)
{ {
auto removed_lines = 1 + line_wrap_count(setup.window_pos.line++); auto removed_lines = 1 + line_wrap_count(setup.window_pos.line++, indent);
setup.cursor_pos.line -= removed_lines; setup.cursor_pos.line -= removed_lines;
win_line -= removed_lines; win_line -= removed_lines;
// removed one line from the range, added removed_lines potential ones // removed one line from the range, added removed_lines potential ones
@ -807,6 +823,9 @@ struct WrapHighlighter : Highlighter
auto column = get_column(buffer, tabstop, coord); auto column = get_column(buffer, tabstop, coord);
auto col = get_byte_to_column( auto col = get_byte_to_column(
buffer, tabstop, {coord.line, column + wrap_column}); buffer, tabstop, {coord.line, column + wrap_column});
if (col == coord.column) // Can happen if we try to wrap on a tab char
col = buffer.char_next(coord).column;
BufferCoord split_coord{coord.line, col}; BufferCoord split_coord{coord.line, col};
if (m_word_wrap) if (m_word_wrap)
@ -823,10 +842,20 @@ struct WrapHighlighter : Highlighter
return split_coord; return split_coord;
}; };
ColumnCount line_indent(const Buffer& buffer, int tabstop, LineCount line) const
{
StringView l = buffer[line];
auto col = 0_byte;
while (is_horizontal_blank(l[col]))
++col;
return get_column(buffer, tabstop, {line, col});
}
static HighlighterAndId create(HighlighterParameters params) static HighlighterAndId create(HighlighterParameters params)
{ {
static const ParameterDesc param_desc{ static const ParameterDesc param_desc{
{ { "word", { false, "" } }, { { "word", { false, "" } },
{ "indent", { false, "" } },
{ "width", { true, "" } } }, { "width", { true, "" } } },
ParameterDesc::Flags::None, 0, 0 ParameterDesc::Flags::None, 0, 0
}; };
@ -836,10 +865,12 @@ struct WrapHighlighter : Highlighter
if (auto width = parser.get_switch("width")) if (auto width = parser.get_switch("width"))
max_width = str_to_int(*width); max_width = str_to_int(*width);
return {"wrap", std::make_unique<WrapHighlighter>(max_width, (bool)parser.get_switch("word"))}; return {"wrap", std::make_unique<WrapHighlighter>(max_width, (bool)parser.get_switch("word"),
(bool)parser.get_switch("indent"))};
} }
const bool m_word_wrap; const bool m_word_wrap;
const bool m_preserve_indent;
const ColumnCount m_max_width; const ColumnCount m_max_width;
}; };