Consider cursor width when updating selection

This fixes the handling of the right end of the selection. Currently the
right end is considered to be at the cursor position + 1. When using a
`block` or `underline` cursor this is arguably correct, because the
cursor has a width of 1 and spans from the current position to the next:
```
    x x [x x x̲] x
```

This is incorrect though (or at least very unintuitive), when using a
`line` cursor:
```
    x x [x x|x] x
```

This commit changes the strategy for determining the end of the
selection in the following way:

* If the current cursor as determined by `$fish_cursor_<bind_mode>` is
  set to `line`, then a cursor width of `0` is assumed.
* In all other cases, including `block` and `underscore` as well as when
  no value is set we retain the previous behavior of assuming a cursor
  width of `1`.
```
    x x [x x x̲] x
    x x [x x|]x x
```

This change should not affect many users, because the selection is
probably used most by vi-mode users, who are also likely to use a
block cursor.
This commit is contained in:
Michael Forster 2022-06-04 17:43:42 +02:00 committed by ridiculousfish
parent 1edcd8ab29
commit a7d943793e
2 changed files with 20 additions and 3 deletions

View File

@ -13,6 +13,9 @@
#define FISH_BIND_MODE_VAR L"fish_bind_mode"
#define DEFAULT_BIND_MODE L"default"
#define FISH_CURSOR_VAR_PREFIX L"fish_cursor_"
#define FISH_CURSOR_LINE L"line"
class event_queue_peeker_t;
class parser_t;

View File

@ -780,6 +780,8 @@ class reader_data_t : public std::enable_shared_from_this<reader_data_t> {
inputter(*parser_ref, conf.in),
history(std::move(hist)) {}
/// Returns the width of the current cursor in characters
size_t cursor_width();
void update_buff_pos(editable_line_t *el, maybe_t<size_t> new_pos = none_t());
void kill(editable_line_t *el, size_t begin_idx, size_t length, int mode, int newv);
@ -1046,6 +1048,18 @@ wcstring combine_command_and_autosuggestion(const wcstring &cmdline,
return full_line;
}
size_t reader_data_t::cursor_width() {
auto bind_mode = vars().get(FISH_BIND_MODE_VAR);
auto fish_cursor_var = FISH_CURSOR_VAR_PREFIX
+ (bind_mode ? bind_mode->as_string() : DEFAULT_BIND_MODE);
if (auto cursor = vars().get(fish_cursor_var)) {
if (cursor->as_string() == FISH_CURSOR_LINE) {
return 0;
}
}
return 1;
}
/// Update the cursor position.
void reader_data_t::update_buff_pos(editable_line_t *el, maybe_t<size_t> new_pos) {
if (new_pos) {
@ -1055,10 +1069,10 @@ void reader_data_t::update_buff_pos(editable_line_t *el, maybe_t<size_t> new_pos
if (el == &command_line && selection.has_value()) {
if (selection->begin <= buff_pos) {
selection->start = selection->begin;
selection->stop = buff_pos + 1;
selection->stop = buff_pos + cursor_width();
} else {
selection->start = buff_pos;
selection->stop = selection->begin + 1;
selection->stop = selection->begin + cursor_width();
}
}
}
@ -3964,7 +3978,7 @@ void reader_data_t::handle_readline_command(readline_cmd_t c, readline_loop_stat
size_t pos = command_line.position();
selection->begin = pos;
selection->start = pos;
selection->stop = pos + 1;
selection->stop = pos + cursor_width();
break;
}