Add support for a -codepoint switch to the select command

This commit is contained in:
Maxime Coste 2019-11-12 21:20:59 +11:00
parent 5fae16faef
commit 7a8f57f97b
11 changed files with 78 additions and 34 deletions

View File

@ -338,9 +338,18 @@ but not really useful in that context.
set register *name* to *content*, each content parameter is assigned to set register *name* to *content*, each content parameter is assigned to
a different string in the register. (See <<registers#,`:doc registers`>>) a different string in the register. (See <<registers#,`:doc registers`>>)
*select* <anchor_line>.<anchor_column>,<cursor_line>.<cursor_column>...:: *select* [<switches>] <anchor_line>.<anchor_column>,<cursor_line>.<cursor_column>...::
replace the current selections with the ones described in the arguments replace the current selections with the ones described in the arguments
*-timestamp* <timestamp>:::
specify which buffer timestamp those coordinates apply to. Uses current
buffer timestamp if not specified.
*-codepoint*::
provided columns are to be interpreted as codepoint counts, not byte counts.
This is only valid if *-timestamp* matches the current buffer timestamp (or
is not specified).
*debug* {info,buffers,options,memory,shared-strings,profile-hash-maps,faces,mappings}:: *debug* {info,buffers,options,memory,shared-strings,profile-hash-maps,faces,mappings}::
print some debug information in the *\*debug** buffer print some debug information in the *\*debug** buffer

View File

@ -2331,7 +2331,10 @@ const CommandDesc select_cmd = {
"\n" "\n"
"selection_desc format is <anchor_line>.<anchor_column>,<cursor_line>.<cursor_column>", "selection_desc format is <anchor_line>.<anchor_column>,<cursor_line>.<cursor_column>",
ParameterDesc{ ParameterDesc{
{{"timestamp", {true, "specify buffer timestamp at which those selections are valid"}}}, {
{"timestamp", {true, "specify buffer timestamp at which those selections are valid"}},
{"codepoint", {false, "columns are specified in codepoints, not bytes"}}
},
ParameterDesc::Flags::SwitchesOnlyAtStart, 1 ParameterDesc::Flags::SwitchesOnlyAtStart, 1
}, },
CommandFlags::None, CommandFlags::None,
@ -2341,7 +2344,7 @@ const CommandDesc select_cmd = {
{ {
auto& buffer = context.buffer(); auto& buffer = context.buffer();
const size_t timestamp = parser.get_switch("timestamp").map(str_to_int_ifp).cast<size_t>().value_or(buffer.timestamp()); const size_t timestamp = parser.get_switch("timestamp").map(str_to_int_ifp).cast<size_t>().value_or(buffer.timestamp());
context.selections_write_only() = selection_list_from_strings(buffer, parser.positionals_from(0), timestamp, 0); context.selections_write_only() = selection_list_from_strings(buffer, (bool)parser.get_switch("codepoint"), parser.positionals_from(0), timestamp, 0);
} }
}; };

View File

@ -252,11 +252,11 @@ static const EnvVarDesc builtin_env_vars[] = { {
}, { }, {
"selections_desc", false, "selections_desc", false,
[](StringView name, const Context& context, Quoting quoting) [](StringView name, const Context& context, Quoting quoting)
{ return selection_list_to_string<false>(context.selections()); } { return selection_list_to_string(false, context.selections()); }
}, { }, {
"selections_char_desc", false, "selections_char_desc", false,
[](StringView name, const Context& context, Quoting quoting) [](StringView name, const Context& context, Quoting quoting)
{ return selection_list_to_string<true>(context.selections()); } { return selection_list_to_string(true, context.selections()); }
}, { }, {
"selection_length", false, "selection_length", false,
[](StringView name, const Context& context, Quoting quoting) -> String [](StringView name, const Context& context, Quoting quoting) -> String
@ -797,7 +797,7 @@ int run_server(StringView session, StringView server_init,
kak_assert(local_client); kak_assert(local_client);
const String client_name = local_client->context().name(); const String client_name = local_client->context().name();
const String buffer_name = local_client->context().buffer().name(); const String buffer_name = local_client->context().buffer().name();
const String selections = selection_list_to_string<false>(local_client->context().selections()); const String selections = selection_list_to_string(false, local_client->context().selections());
ClientManager::instance().remove_client(*local_client, true, 0); ClientManager::instance().remove_client(*local_client, true, 0);
client_manager.clear_client_trash(); client_manager.clear_client_trash();

View File

@ -1774,7 +1774,7 @@ SelectionList read_selections_from_register(char reg, Context& context)
const size_t timestamp = str_to_int(desc[1]); const size_t timestamp = str_to_int(desc[1]);
size_t main = str_to_int(desc[2]); size_t main = str_to_int(desc[2]);
return selection_list_from_strings(buffer, content | skip(1), timestamp, main); return selection_list_from_strings(buffer, false, content | skip(1), timestamp, main);
} }
enum class CombineOp enum class CombineOp

View File

@ -489,7 +489,25 @@ String selection_to_string_char(const Buffer& buffer, const Selection& selection
cursor.line + 1, buffer[cursor.line].char_count_to(cursor.column) + 1); cursor.line + 1, buffer[cursor.line].char_count_to(cursor.column) + 1);
} }
Selection selection_from_string(StringView desc) String selection_list_to_string(bool char_columns, const SelectionList& selections)
{
auto& buffer = selections.buffer();
kak_assert(selections.timestamp() == buffer.timestamp());
auto to_string = [&](const Selection& selection) {
return char_columns ? selection_to_string_char(buffer, selection)
: selection_to_string(selection);
};
auto beg = &*selections.begin(), end = &*selections.end();
auto main = beg + selections.main_index();
using View = ConstArrayView<Selection>;
return join(concatenated(View{main, end}, View{beg, main}) |
transform(to_string), ' ', false);
}
template<typename ComputeCoord>
Selection selection_from_string_impl(StringView desc, ComputeCoord compute_coord)
{ {
auto comma = find(desc, ','); auto comma = find(desc, ',');
auto dot_anchor = find(StringView{desc.begin(), comma}, '.'); auto dot_anchor = find(StringView{desc.begin(), comma}, '.');
@ -498,11 +516,12 @@ Selection selection_from_string(StringView desc)
if (comma == desc.end() or dot_anchor == comma or dot_cursor == desc.end()) if (comma == desc.end() or dot_anchor == comma or dot_cursor == desc.end())
throw runtime_error(format("'{}' does not follow <line>.<column>,<line>.<column> format", desc)); throw runtime_error(format("'{}' does not follow <line>.<column>,<line>.<column> format", desc));
BufferCoord anchor{str_to_int({desc.begin(), dot_anchor}) - 1,
str_to_int({dot_anchor+1, comma}) - 1};
BufferCoord cursor{str_to_int({comma+1, dot_cursor}) - 1, auto anchor = compute_coord(str_to_int({desc.begin(), dot_anchor}) - 1,
str_to_int({dot_cursor+1, desc.end()}) - 1}; str_to_int({dot_anchor+1, comma}) - 1);
auto cursor = compute_coord(str_to_int({comma+1, dot_cursor}) - 1,
str_to_int({dot_cursor+1, desc.end()}) - 1);
if (anchor.line < 0 or anchor.column < 0 or if (anchor.line < 0 or anchor.column < 0 or
cursor.line < 0 or cursor.column < 0) cursor.line < 0 or cursor.column < 0)
@ -511,4 +530,22 @@ Selection selection_from_string(StringView desc)
return Selection{anchor, cursor}; return Selection{anchor, cursor};
} }
Selection selection_from_string(StringView desc)
{
return selection_from_string_impl(desc, [](int line, int column) {
return BufferCoord{line, column};
});
}
Selection selection_from_string_char(const Buffer& buffer, StringView desc)
{
return selection_from_string_impl(desc, [&](int line, int column) {
if (line < 0 or buffer.line_count() <= line or
column < 0 or buffer[line].char_length() <= column)
throw runtime_error(format("coordinate {}.{} does exist in buffer", line, column));
return BufferCoord{line, buffer[line].byte_count_to(CharCount{column})};
});
}
} }

View File

@ -157,34 +157,24 @@ private:
Vector<Selection> compute_modified_ranges(const Buffer& buffer, size_t timestamp); Vector<Selection> compute_modified_ranges(const Buffer& buffer, size_t timestamp);
Selection selection_from_string(StringView desc); Selection selection_from_string(StringView desc);
Selection selection_from_string_char(const Buffer& buffer, StringView desc);
String selection_to_string(const Selection& selection); String selection_to_string(const Selection& selection);
String selection_to_string_char(const Buffer& buffer, const Selection& selection); String selection_to_string_char(const Buffer& buffer, const Selection& selection);
template<bool char_columns> String selection_list_to_string(bool char_columns, const SelectionList& selections);
String selection_list_to_string(const SelectionList& selections)
template<typename StringArray>
SelectionList selection_list_from_strings(Buffer& buffer, bool char_columns, StringArray&& descs, size_t timestamp, size_t main)
{ {
auto& buffer = selections.buffer(); if ((char_columns and timestamp != buffer.timestamp()) or timestamp > buffer.timestamp())
kak_assert(selections.timestamp() == buffer.timestamp());
auto to_string = [&](const Selection& selection) {
return char_columns ? selection_to_string_char(buffer, selection)
: selection_to_string(selection);
};
auto beg = &*selections.begin(), end = &*selections.end();
auto main = beg + selections.main_index();
using View = ConstArrayView<Selection>;
return join(concatenated(View{main, end}, View{beg, main}) |
transform(to_string), ' ', false);
}
template<class StringArray>
SelectionList selection_list_from_strings(Buffer& buffer, StringArray&& descs, size_t timestamp, size_t main)
{
if (timestamp > buffer.timestamp())
throw runtime_error{format("invalid timestamp '{}'", timestamp)}; throw runtime_error{format("invalid timestamp '{}'", timestamp)};
auto sels = descs | transform(selection_from_string) | gather<Vector<Selection>>(); auto from_string = [&](StringView desc) {
return char_columns ? selection_from_string_char(buffer, desc)
: selection_from_string(desc);
};
auto sels = descs | transform(from_string) | gather<Vector<Selection>>();
if (sels.empty()) if (sels.empty())
throw runtime_error{"empty selection description"}; throw runtime_error{"empty selection description"};
if (main >= sels.size()) if (main >= sels.size())

View File

@ -0,0 +1 @@

View File

@ -0,0 +1 @@
😄😊😉😍😘😚😜😝😳😁😣😢😂😭😪😥😰😩

View File

@ -0,0 +1 @@
1.2,1.4

View File

@ -0,0 +1 @@
1.5,1.13

View File

@ -0,0 +1 @@
select -codepoint 1.2,1.4