Add a -marker <marker_text> switch support to the wrap highlighter

This makes wrapped lines very explicit.

Fixes #2065
This commit is contained in:
Maxime Coste 2018-05-26 22:22:00 +10:00
parent f55c811282
commit f1c1de834a
2 changed files with 39 additions and 17 deletions

View File

@ -75,6 +75,10 @@ existing highlighters ids.
*-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.
*-marker <marker_text>*:::
prefix wrapped lines with *marker_text*; if *-indent* was given,
the marker_text is displayed into the indentation if possible.
== General highlighters == General highlighters
*fill* <face>:: *fill* <face>::

View File

@ -639,9 +639,10 @@ HighlighterAndId create_column_highlighter(HighlighterParameters params)
struct WrapHighlighter : Highlighter struct WrapHighlighter : Highlighter
{ {
WrapHighlighter(ColumnCount max_width, bool word_wrap, bool preserve_indent) WrapHighlighter(ColumnCount max_width, bool word_wrap, bool preserve_indent, String marker)
: Highlighter{HighlightPass::Wrap}, m_max_width{max_width}, : Highlighter{HighlightPass::Wrap}, m_max_width{max_width},
m_word_wrap{word_wrap}, m_preserve_indent{preserve_indent} {} m_word_wrap{word_wrap}, m_preserve_indent{preserve_indent},
m_marker{std::move(marker)} {}
static constexpr StringView ms_id = "wrap"; static constexpr StringView ms_id = "wrap";
@ -658,14 +659,14 @@ struct WrapHighlighter : Highlighter
const auto& cursor = context.context.selections().main().cursor(); const auto& cursor = context.context.selections().main().cursor();
const int tabstop = context.context.options()["tabstop"].get<int>(); const int tabstop = context.context.options()["tabstop"].get<int>();
const LineCount win_height = context.context.window().dimensions().line; const LineCount win_height = context.context.window().dimensions().line;
const ColumnCount marker_len = m_marker.column_length();
const Face face_marker = context.context.faces()["StatusLineInfo"];
for (auto it = display_buffer.lines().begin(); for (auto it = display_buffer.lines().begin();
it != display_buffer.lines().end(); ++it) it != display_buffer.lines().end(); ++it)
{ {
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; const 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))
@ -688,10 +689,17 @@ 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) ColumnCount prefix_len = 0;
if (marker_len != 0 and marker_len < wrap_column)
{ {
auto it = new_line.insert(new_line.begin(), {buffer, coord, coord}); new_line.insert(new_line.begin(), {m_marker, face_marker});
it->replace(String{' ', indent}); prefix_len = marker_len;
}
if (indent > marker_len and indent < wrap_column)
{
auto it = new_line.insert(new_line.begin() + (marker_len > 0), {buffer, coord, coord});
it->replace(String{' ', indent - marker_len});
prefix_len = indent;
} }
if (it+1 - display_buffer.lines().begin() == win_height) if (it+1 - display_buffer.lines().begin() == win_height)
@ -709,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 - indent, tabstop, coord); coord = next_split_coord(buffer, wrap_column - prefix_len, tabstop, coord);
atom_it = it->begin(); atom_it = it->begin();
} }
} }
@ -752,6 +760,8 @@ struct WrapHighlighter : Highlighter
setup.scroll_offset.column = 0; setup.scroll_offset.column = 0;
setup.full_lines = true; setup.full_lines = true;
const ColumnCount marker_len = m_marker.column_length();
for (auto buf_line = setup.window_pos.line, win_line = 0_line; for (auto buf_line = setup.window_pos.line, win_line = 0_line;
win_line < win_height or buf_line <= cursor.line; win_line < win_height or buf_line <= cursor.line;
++buf_line, ++setup.window_range.line) ++buf_line, ++setup.window_range.line)
@ -759,16 +769,20 @@ struct WrapHighlighter : Highlighter
if (buf_line >= buffer.line_count()) if (buf_line >= buffer.line_count())
break; break;
ColumnCount indent = m_preserve_indent ? line_indent(buffer, tabstop, buf_line) : 0_col; const 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; ColumnCount prefix_len = 0;
if (marker_len < wrap_column)
prefix_len = marker_len;
if (indent > marker_len and indent < wrap_column)
prefix_len = indent;
if (buf_line == cursor.line) if (buf_line == cursor.line)
{ {
BufferCoord coord{buf_line}; BufferCoord coord{buf_line};
for (LineCount count = 0; true; ++count) for (LineCount count = 0; true; ++count)
{ {
auto split_coord = next_split_coord(buffer, wrap_column - (coord.column == 0 ? 0_col : indent), auto split_coord = next_split_coord(buffer, wrap_column - (coord.column != 0 ? prefix_len : 0_col),
tabstop, coord); tabstop, coord);
if (split_coord.column > cursor.column) if (split_coord.column > cursor.column)
{ {
@ -784,7 +798,7 @@ struct WrapHighlighter : Highlighter
} }
kak_assert(setup.cursor_pos.column >= 0 and setup.cursor_pos.column < setup.window_range.column); kak_assert(setup.cursor_pos.column >= 0 and setup.cursor_pos.column < setup.window_range.column);
} }
const auto wrap_count = line_wrap_count(buf_line, indent); const auto wrap_count = line_wrap_count(buf_line, prefix_len);
win_line += wrap_count + 1; win_line += wrap_count + 1;
// scroll window to keep cursor visible, and update range as lines gets removed // scroll window to keep cursor visible, and update range as lines gets removed
@ -844,7 +858,8 @@ struct WrapHighlighter : Highlighter
static const ParameterDesc param_desc{ static const ParameterDesc param_desc{
{ { "word", { false, "" } }, { { "word", { false, "" } },
{ "indent", { false, "" } }, { "indent", { false, "" } },
{ "width", { true, "" } } }, { "width", { true, "" } },
{ "marker", { true, "" } } },
ParameterDesc::Flags::None, 0, 0 ParameterDesc::Flags::None, 0, 0
}; };
ParametersParser parser(params, param_desc); ParametersParser parser(params, param_desc);
@ -854,12 +869,14 @@ struct WrapHighlighter : Highlighter
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"))}; (bool)parser.get_switch("indent"),
parser.get_switch("marker").value_or("").str())};
} }
const bool m_word_wrap; const bool m_word_wrap;
const bool m_preserve_indent; const bool m_preserve_indent;
const ColumnCount m_max_width; const ColumnCount m_max_width;
const String m_marker;
}; };
constexpr StringView WrapHighlighter::ms_id; constexpr StringView WrapHighlighter::ms_id;
@ -2079,9 +2096,10 @@ void register_highlighters()
registry.insert({ registry.insert({
"wrap", "wrap",
{ WrapHighlighter::create, { WrapHighlighter::create,
"Parameters: [-word] [-indent] [-width <max_width>]\n" "Parameters: [-word] [-indent] [-width <max_width>] [-marker <marker_text>\n"
"Wrap lines to window width, or max_width if given and window is wider,\n" "Wrap lines to window width, or max_width if given and window is wider,\n"
"wrap at word boundaries instead of codepoint boundaries if -word is given\n" "wrap at word boundaries instead of codepoint boundaries if -word is given\n"
"insert marker_text at start of wrapped lines if given\n"
"preserve line indent in wrapped parts if -indent is given\n"} }); "preserve line indent in wrapped parts if -indent is given\n"} });
registry.insert({ registry.insert({
"ref", "ref",