diff --git a/src/buffer_utils.cc b/src/buffer_utils.cc index b6519d7d..4b6c3763 100644 --- a/src/buffer_utils.cc +++ b/src/buffer_utils.cc @@ -34,6 +34,11 @@ ColumnCount get_column(const Buffer& buffer, return col; } +ColumnCount column_length(const Buffer& buffer, ColumnCount tabstop, LineCount line) +{ + return get_column(buffer, tabstop, BufferCoord{line, ByteCount{INT_MAX}}); +} + ByteCount get_byte_to_column(const Buffer& buffer, ColumnCount tabstop, DisplayCoord coord) { auto line = buffer[coord.line]; diff --git a/src/buffer_utils.hh b/src/buffer_utils.hh index a635658b..586cbb1d 100644 --- a/src/buffer_utils.hh +++ b/src/buffer_utils.hh @@ -69,8 +69,8 @@ inline bool is_eow(const Buffer& buffer, BufferCoord coord) return is_word(*(it-1)) and not is_word(*it); } -ColumnCount get_column(const Buffer& buffer, - ColumnCount tabstop, BufferCoord coord); +ColumnCount get_column(const Buffer& buffer, ColumnCount tabstop, BufferCoord coord); +ColumnCount column_length(const Buffer& buffer, ColumnCount tabstop, LineCount line); ByteCount get_byte_to_column(const Buffer& buffer, ColumnCount tabstop, DisplayCoord coord); diff --git a/src/commands.cc b/src/commands.cc index cfacea99..27531aec 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -2349,7 +2349,8 @@ const CommandDesc select_cmd = { column_type = ColumnType::Codepoint; else if (parser.get_switch("display-column")) column_type = ColumnType::DisplayColumn; - context.selections_write_only() = selection_list_from_strings(buffer, column_type, parser.positionals_from(0), timestamp, 0); + ColumnCount tabstop = context.options()["tabstop"].get(); + context.selections_write_only() = selection_list_from_strings(buffer, column_type, parser.positionals_from(0), timestamp, 0, tabstop); } }; diff --git a/src/main.cc b/src/main.cc index fca72b3b..7af8c0cb 100644 --- a/src/main.cc +++ b/src/main.cc @@ -261,7 +261,9 @@ static const EnvVarDesc builtin_env_vars[] = { { }, { "selections_display_column_desc", false, [](StringView name, const Context& context, Quoting quoting) - { return selection_list_to_string(ColumnType::DisplayColumn, context.selections()); } + { return selection_list_to_string(ColumnType::DisplayColumn, + context.selections(), + context.options()["tabstop"].get()); } }, { "selection_length", false, [](StringView name, const Context& context, Quoting quoting) -> String diff --git a/src/selection.cc b/src/selection.cc index 0b29d3d2..0a0983a5 100644 --- a/src/selection.cc +++ b/src/selection.cc @@ -472,7 +472,7 @@ void SelectionList::erase() m_buffer->check_invariant(); } -String selection_to_string(ColumnType column_type, const Buffer& buffer, const Selection& selection) +String selection_to_string(ColumnType column_type, const Buffer& buffer, const Selection& selection, ColumnCount tabstop) { const auto& cursor = selection.cursor(); const auto& anchor = selection.anchor(); @@ -487,19 +487,20 @@ String selection_to_string(ColumnType column_type, const Buffer& buffer, const S anchor.line + 1, buffer[anchor.line].char_count_to(anchor.column) + 1, cursor.line + 1, buffer[cursor.line].char_count_to(cursor.column) + 1); case ColumnType::DisplayColumn: + kak_assert(tabstop != -1); return format("{}.{},{}.{}", - anchor.line + 1, buffer[anchor.line].column_count_to(anchor.column) + 1, - cursor.line + 1, buffer[cursor.line].column_count_to(cursor.column) + 1); + anchor.line + 1, get_column(buffer, tabstop, anchor) + 1, + cursor.line + 1, get_column(buffer, tabstop, cursor) + 1); } } -String selection_list_to_string(ColumnType column_type, const SelectionList& selections) +String selection_list_to_string(ColumnType column_type, const SelectionList& selections, ColumnCount tabstop) { auto& buffer = selections.buffer(); kak_assert(selections.timestamp() == buffer.timestamp()); auto to_string = [&](const Selection& selection) { - return selection_to_string(column_type, buffer, selection); + return selection_to_string(column_type, buffer, selection, tabstop); }; auto beg = &*selections.begin(), end = &*selections.end(); @@ -509,7 +510,7 @@ String selection_list_to_string(ColumnType column_type, const SelectionList& sel transform(to_string), ' ', false); } -Selection selection_from_string(ColumnType column_type, const Buffer& buffer, StringView desc) +Selection selection_from_string(ColumnType column_type, const Buffer& buffer, StringView desc, ColumnCount tabstop) { auto comma = find(desc, ','); auto dot_anchor = find(StringView{desc.begin(), comma}, '.'); @@ -520,7 +521,7 @@ Selection selection_from_string(ColumnType column_type, const Buffer& buffer, St auto compute_coord = [&](int line, int column) -> BufferCoord { if (line < 0 or column < 0) - throw runtime_error(format("coordinate {}.{} does exist in buffer", line, column)); + throw runtime_error(format("coordinate {}.{} does not exist in buffer", line + 1, column + 1)); switch (column_type) { @@ -528,12 +529,13 @@ Selection selection_from_string(ColumnType column_type, const Buffer& buffer, St case ColumnType::Byte: return {line, column}; case ColumnType::Codepoint: if (buffer.line_count() <= line or buffer[line].char_length() <= column) - throw runtime_error(format("coordinate {}.{} does exist in buffer", line, column)); + throw runtime_error(format("coordinate {}.{} does not exist in buffer", line + 1, column + 1)); return {line, buffer[line].byte_count_to(CharCount{column})}; case ColumnType::DisplayColumn: - if (buffer.line_count() <= line or buffer[line].column_length() <= column) - throw runtime_error(format("coordinate {}.{} does exist in buffer", line, column)); - return {line, buffer[line].byte_count_to(ColumnCount{column})}; + kak_assert(tabstop != -1); + if (buffer.line_count() <= line or column_length(buffer, tabstop, line) <= column) + throw runtime_error(format("coordinate {}.{} does not exist in buffer", line + 1, column + 1)); + return {line, get_byte_to_column(buffer, tabstop, DisplayCoord{line, ColumnCount{column}})}; } }; diff --git a/src/selection.hh b/src/selection.hh index a674e785..af56856e 100644 --- a/src/selection.hh +++ b/src/selection.hh @@ -163,19 +163,19 @@ enum class ColumnType DisplayColumn }; -Selection selection_from_string(ColumnType column_type, const Buffer& buffer, StringView desc); -String selection_to_string(ColumnType column_type, const Buffer& buffer, const Selection& selection); +Selection selection_from_string(ColumnType column_type, const Buffer& buffer, StringView desc, ColumnCount tabstop = -1); +String selection_to_string(ColumnType column_type, const Buffer& buffer, const Selection& selection, ColumnCount tabstop = -1); -String selection_list_to_string(ColumnType column_type, const SelectionList& selections); +String selection_list_to_string(ColumnType column_type, const SelectionList& selections, ColumnCount tabstop = -1); template -SelectionList selection_list_from_strings(Buffer& buffer, ColumnType column_type, StringArray&& descs, size_t timestamp, size_t main) +SelectionList selection_list_from_strings(Buffer& buffer, ColumnType column_type, StringArray&& descs, size_t timestamp, size_t main, ColumnCount tabstop = -1) { if ((column_type != ColumnType::Byte and timestamp != buffer.timestamp()) or timestamp > buffer.timestamp()) throw runtime_error{format("invalid timestamp '{}'", timestamp)}; auto from_string = [&](StringView desc) { - return selection_from_string(column_type, buffer, desc); + return selection_from_string(column_type, buffer, desc, tabstop); }; auto sels = descs | transform(from_string) | gather>();