mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-05 04:06:08 -05:00
Merge branch 'search-extend-selection'
This commit is contained in:
commit
e36d95a4c8
8 changed files with 620 additions and 117 deletions
17
CHANGELOG.md
17
CHANGELOG.md
|
|
@ -60,9 +60,24 @@
|
|||
row ([#1364][1364]).
|
||||
* Support for DECSET/DECRST/DECRQM 2027 (_Grapheme cluster
|
||||
processing_).
|
||||
* New search mode key bindings (along with their defaults)
|
||||
([#419][419]):
|
||||
- `extend-char` (shift+right)
|
||||
- `extend-line-down` (shift+down)
|
||||
- `extend-backward-char` (shift+left)
|
||||
- `extend-backward-to-word-boundary` (ctrl+shift+left)
|
||||
- `extend-backward-to-next-whitespace` (none)
|
||||
- `extend-line-up` (shift+up)
|
||||
- `scrollback-up-page` (shift+page-up)
|
||||
- `scrollback-up-half-page` (none)
|
||||
- `scrollback-up-line` (none)
|
||||
- `scrollback-down-page` (shift+page-down)
|
||||
- `scrollback-down-half-page` (none)
|
||||
- `scrollback-down-line` (none)
|
||||
|
||||
[1077]: https://codeberg.org/dnkl/foot/issues/1077
|
||||
[1364]: https://codeberg.org/dnkl/foot/issues/1364
|
||||
[419]: https://codeberg.org/dnkl/foot/issues/419
|
||||
|
||||
|
||||
### Changed
|
||||
|
|
@ -111,6 +126,8 @@
|
|||
turned off and then back on again) ([#1498][1498]).
|
||||
* Transparency in margins (padding) not being disabled in fullscreen
|
||||
mode ([#1503][1503]).
|
||||
* Crash when a scrollback search match is in the last column.
|
||||
* Scrollback search: grapheme clusters not matching correctly.
|
||||
|
||||
[1436]: https://codeberg.org/dnkl/foot/issues/1436
|
||||
[1464]: https://codeberg.org/dnkl/foot/issues/1464
|
||||
|
|
|
|||
33
config.c
33
config.c
|
|
@ -134,6 +134,14 @@ static const char *const binding_action_map[] = {
|
|||
|
||||
static const char *const search_binding_action_map[] = {
|
||||
[BIND_ACTION_SEARCH_NONE] = NULL,
|
||||
[BIND_ACTION_SEARCH_SCROLLBACK_UP_PAGE] = "scrollback-up-page",
|
||||
[BIND_ACTION_SEARCH_SCROLLBACK_UP_HALF_PAGE] = "scrollback-up-half-page",
|
||||
[BIND_ACTION_SEARCH_SCROLLBACK_UP_LINE] = "scrollback-up-line",
|
||||
[BIND_ACTION_SEARCH_SCROLLBACK_DOWN_PAGE] = "scrollback-down-page",
|
||||
[BIND_ACTION_SEARCH_SCROLLBACK_DOWN_HALF_PAGE] = "scrollback-down-half-page",
|
||||
[BIND_ACTION_SEARCH_SCROLLBACK_DOWN_LINE] = "scrollback-down-line",
|
||||
[BIND_ACTION_SEARCH_SCROLLBACK_HOME] = "scrollback-home",
|
||||
[BIND_ACTION_SEARCH_SCROLLBACK_END] = "scrollback-end",
|
||||
[BIND_ACTION_SEARCH_CANCEL] = "cancel",
|
||||
[BIND_ACTION_SEARCH_COMMIT] = "commit",
|
||||
[BIND_ACTION_SEARCH_FIND_PREV] = "find-prev",
|
||||
|
|
@ -148,8 +156,14 @@ static const char *const search_binding_action_map[] = {
|
|||
[BIND_ACTION_SEARCH_DELETE_PREV_WORD] = "delete-prev-word",
|
||||
[BIND_ACTION_SEARCH_DELETE_NEXT] = "delete-next",
|
||||
[BIND_ACTION_SEARCH_DELETE_NEXT_WORD] = "delete-next-word",
|
||||
[BIND_ACTION_SEARCH_EXTEND_CHAR] = "extend-char",
|
||||
[BIND_ACTION_SEARCH_EXTEND_WORD] = "extend-to-word-boundary",
|
||||
[BIND_ACTION_SEARCH_EXTEND_WORD_WS] = "extend-to-next-whitespace",
|
||||
[BIND_ACTION_SEARCH_EXTEND_LINE_DOWN] = "extend-line-down",
|
||||
[BIND_ACTION_SEARCH_EXTEND_BACKWARD_CHAR] = "extend-backward-char",
|
||||
[BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD] = "extend-backward-to-word-boundary",
|
||||
[BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD_WS] = "extend-backward-to-next-whitespace",
|
||||
[BIND_ACTION_SEARCH_EXTEND_LINE_UP] = "extend-line-up",
|
||||
[BIND_ACTION_SEARCH_CLIPBOARD_PASTE] = "clipboard-paste",
|
||||
[BIND_ACTION_SEARCH_PRIMARY_PASTE] = "primary-paste",
|
||||
[BIND_ACTION_SEARCH_UNICODE_INPUT] = "unicode-input",
|
||||
|
|
@ -2774,11 +2788,12 @@ get_server_socket_path(void)
|
|||
return xasprintf("%s/foot-%s.sock", xdg_runtime, wayland_display);
|
||||
}
|
||||
|
||||
#define m_none {0}
|
||||
#define m_alt {.alt = true}
|
||||
#define m_ctrl {.ctrl = true}
|
||||
#define m_shift {.shift = true}
|
||||
#define m_ctrl_shift {.ctrl = true, .shift = true}
|
||||
#define m_none {0}
|
||||
#define m_alt {.alt = true}
|
||||
#define m_ctrl {.ctrl = true}
|
||||
#define m_shift {.shift = true}
|
||||
#define m_ctrl_shift {.ctrl = true, .shift = true}
|
||||
#define m_ctrl_shift_alt {.ctrl = true, .shift = true, .alt = true}
|
||||
|
||||
static void
|
||||
add_default_key_bindings(struct config *conf)
|
||||
|
|
@ -2816,6 +2831,8 @@ static void
|
|||
add_default_search_bindings(struct config *conf)
|
||||
{
|
||||
static const struct config_key_binding bindings[] = {
|
||||
{BIND_ACTION_SEARCH_SCROLLBACK_UP_PAGE, m_shift, {{XKB_KEY_Prior}}},
|
||||
{BIND_ACTION_SEARCH_SCROLLBACK_DOWN_PAGE, m_shift, {{XKB_KEY_Next}}},
|
||||
{BIND_ACTION_SEARCH_CANCEL, m_ctrl, {{XKB_KEY_c}}},
|
||||
{BIND_ACTION_SEARCH_CANCEL, m_ctrl, {{XKB_KEY_g}}},
|
||||
{BIND_ACTION_SEARCH_CANCEL, m_none, {{XKB_KEY_Escape}}},
|
||||
|
|
@ -2840,8 +2857,14 @@ add_default_search_bindings(struct config *conf)
|
|||
{BIND_ACTION_SEARCH_DELETE_NEXT, m_none, {{XKB_KEY_Delete}}},
|
||||
{BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_ctrl, {{XKB_KEY_Delete}}},
|
||||
{BIND_ACTION_SEARCH_DELETE_NEXT_WORD, m_alt, {{XKB_KEY_d}}},
|
||||
{BIND_ACTION_SEARCH_EXTEND_CHAR, m_shift, {{XKB_KEY_Right}}},
|
||||
{BIND_ACTION_SEARCH_EXTEND_WORD, m_ctrl, {{XKB_KEY_w}}},
|
||||
{BIND_ACTION_SEARCH_EXTEND_WORD, m_ctrl_shift, {{XKB_KEY_Right}}},
|
||||
{BIND_ACTION_SEARCH_EXTEND_WORD_WS, m_ctrl_shift, {{XKB_KEY_w}}},
|
||||
{BIND_ACTION_SEARCH_EXTEND_LINE_DOWN, m_shift, {{XKB_KEY_Down}}},
|
||||
{BIND_ACTION_SEARCH_EXTEND_BACKWARD_CHAR, m_shift, {{XKB_KEY_Left}}},
|
||||
{BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD, m_ctrl_shift, {{XKB_KEY_Left}}},
|
||||
{BIND_ACTION_SEARCH_EXTEND_LINE_UP, m_shift, {{XKB_KEY_Up}}},
|
||||
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_v}}},
|
||||
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl_shift, {{XKB_KEY_v}}},
|
||||
{BIND_ACTION_SEARCH_CLIPBOARD_PASTE, m_ctrl, {{XKB_KEY_y}}},
|
||||
|
|
|
|||
|
|
@ -945,13 +945,35 @@ scrollback search mode. The syntax is exactly the same as the regular
|
|||
Deletes the **word after** the cursor. Default: _Mod1+d
|
||||
Control+Delete_.
|
||||
|
||||
*extend-char*
|
||||
Extend current selection to the right, by one character. Default:
|
||||
_Shift+Right_.
|
||||
|
||||
*extend-to-word-boundary*
|
||||
Extend current selection to the next word boundary. Default:
|
||||
_Control+w_.
|
||||
Extend current selection to the right, to the next word
|
||||
boundary. Default: _Control+w Control+Shift+Right_.
|
||||
|
||||
*extend-to-next-whitespace*
|
||||
Extend the current selection to the next whitespace. Default:
|
||||
_Control+Shift+w_.
|
||||
Extend the current selection to the right, to the next
|
||||
whitespace. Default: _Control+Shift+w_.
|
||||
|
||||
*extend-line-down*
|
||||
Extend current selection down one line. Default: _Shift+Down_.
|
||||
|
||||
*extend-backward-char*
|
||||
Extend current selection to the left, by one character. Default:
|
||||
_Shift+Left_.
|
||||
|
||||
*extend-backward-to-word-boundary*
|
||||
Extend current selection to the left, to the next word
|
||||
boundary. Default: _Control+Shift+Left_.
|
||||
|
||||
*extend-backward-to-next-whitespace*
|
||||
Extend the current selection to the left, to the next
|
||||
whitespace. Default: _none_.
|
||||
|
||||
*extend-line-up*
|
||||
Extend current selection up one line. Default: _Shift+Up_.
|
||||
|
||||
*clipboard-paste*
|
||||
Paste from the _clipboard_ into the search buffer. Default:
|
||||
|
|
@ -965,6 +987,31 @@ scrollback search mode. The syntax is exactly the same as the regular
|
|||
Unicode input mode. See _key-bindings.unicode-input_ for
|
||||
details. Default: _none_.
|
||||
|
||||
*scrollback-up-page*
|
||||
Scrolls up/back one page in history. Default: _Shift+Page\_Up_.
|
||||
|
||||
*scrollback-up-half-page*
|
||||
Scrolls up/back half of a page in history. Default: _none_.
|
||||
|
||||
*scrollback-up-line*
|
||||
Scrolls up/back a single line in history. Default: _none_.
|
||||
|
||||
*scrollback-down-page*
|
||||
Scroll down/forward one page in history. Default:
|
||||
_Shift+Page\_Down_.
|
||||
|
||||
*scrollback-down-half-page*
|
||||
Scroll down/forward half of a page in history. Default: _none_.
|
||||
|
||||
*scrollback-down-line*
|
||||
Scroll down/forward a single line in history. Default: _none_.
|
||||
|
||||
*scrollback-home*
|
||||
Scroll to the beginning of the scrollback. Default: _none_.
|
||||
|
||||
*scrollback-end*
|
||||
Scroll to the end (bottom) of the scrollback. Default: _none_.
|
||||
|
||||
# SECTION: url-bindings
|
||||
|
||||
This section lets you override the default key bindings used in URL
|
||||
|
|
|
|||
18
foot.ini
18
foot.ini
|
|
@ -139,6 +139,8 @@
|
|||
# scrollback-down-page=Shift+Page_Down
|
||||
# scrollback-down-half-page=none
|
||||
# scrollback-down-line=none
|
||||
# scrollback-home=none
|
||||
# scrollback-end=none
|
||||
# clipboard-copy=Control+Shift+c XF86Copy
|
||||
# clipboard-paste=Control+Shift+v XF86Paste
|
||||
# primary-paste=Shift+Insert
|
||||
|
|
@ -176,11 +178,25 @@
|
|||
# delete-prev-word=Mod1+BackSpace Control+BackSpace
|
||||
# delete-next=Delete
|
||||
# delete-next-word=Mod1+d Control+Delete
|
||||
# extend-to-word-boundary=Control+w
|
||||
# extend-char=Shift+Right
|
||||
# extend-to-word-boundary=Control+w Control+Shift+Right
|
||||
# extend-to-next-whitespace=Control+Shift+w
|
||||
# extend-line-down=Shift+Down
|
||||
# extend-backward-char=Shift+Left
|
||||
# extend-backward-to-word-boundary=Control+Shift+Left
|
||||
# extend-backward-to-next-whitespace=none
|
||||
# extend-line-up=Shift+Up
|
||||
# clipboard-paste=Control+v Control+Shift+v Control+y XF86Paste
|
||||
# primary-paste=Shift+Insert
|
||||
# unicode-input=none
|
||||
# scrollback-up-page=Shift+Page_Up
|
||||
# scrollback-up-half-page=none
|
||||
# scrollback-up-line=none
|
||||
# scrollback-down-page=Shift+Page_Down
|
||||
# scrollback-down-half-page=none
|
||||
# scrollback-down-line=none
|
||||
# scrollback-home=none
|
||||
# scrollback-end=none
|
||||
|
||||
[url-bindings]
|
||||
# cancel=Control+g Control+c Control+d Escape
|
||||
|
|
|
|||
|
|
@ -58,6 +58,14 @@ enum bind_action_normal {
|
|||
|
||||
enum bind_action_search {
|
||||
BIND_ACTION_SEARCH_NONE,
|
||||
BIND_ACTION_SEARCH_SCROLLBACK_UP_PAGE,
|
||||
BIND_ACTION_SEARCH_SCROLLBACK_UP_HALF_PAGE,
|
||||
BIND_ACTION_SEARCH_SCROLLBACK_UP_LINE,
|
||||
BIND_ACTION_SEARCH_SCROLLBACK_DOWN_PAGE,
|
||||
BIND_ACTION_SEARCH_SCROLLBACK_DOWN_HALF_PAGE,
|
||||
BIND_ACTION_SEARCH_SCROLLBACK_DOWN_LINE,
|
||||
BIND_ACTION_SEARCH_SCROLLBACK_HOME,
|
||||
BIND_ACTION_SEARCH_SCROLLBACK_END,
|
||||
BIND_ACTION_SEARCH_CANCEL,
|
||||
BIND_ACTION_SEARCH_COMMIT,
|
||||
BIND_ACTION_SEARCH_FIND_PREV,
|
||||
|
|
@ -72,8 +80,14 @@ enum bind_action_search {
|
|||
BIND_ACTION_SEARCH_DELETE_PREV_WORD,
|
||||
BIND_ACTION_SEARCH_DELETE_NEXT,
|
||||
BIND_ACTION_SEARCH_DELETE_NEXT_WORD,
|
||||
BIND_ACTION_SEARCH_EXTEND_CHAR,
|
||||
BIND_ACTION_SEARCH_EXTEND_WORD,
|
||||
BIND_ACTION_SEARCH_EXTEND_WORD_WS,
|
||||
BIND_ACTION_SEARCH_EXTEND_LINE_DOWN,
|
||||
BIND_ACTION_SEARCH_EXTEND_BACKWARD_CHAR,
|
||||
BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD,
|
||||
BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD_WS,
|
||||
BIND_ACTION_SEARCH_EXTEND_LINE_UP,
|
||||
BIND_ACTION_SEARCH_CLIPBOARD_PASTE,
|
||||
BIND_ACTION_SEARCH_PRIMARY_PASTE,
|
||||
BIND_ACTION_SEARCH_UNICODE_INPUT,
|
||||
|
|
|
|||
494
search.c
494
search.c
|
|
@ -9,6 +9,7 @@
|
|||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "char32.h"
|
||||
#include "commands.h"
|
||||
#include "config.h"
|
||||
#include "extract.h"
|
||||
#include "grid.h"
|
||||
|
|
@ -82,7 +83,14 @@ search_ensure_size(struct terminal *term, size_t wanted_size)
|
|||
}
|
||||
|
||||
static bool
|
||||
has_wrapped_around(const struct terminal *term, int abs_row_no)
|
||||
has_wrapped_around_left(const struct terminal *term, int abs_row_no)
|
||||
{
|
||||
int rebased_row = grid_row_abs_to_sb(term->grid, term->rows, abs_row_no);
|
||||
return rebased_row == term->grid->num_rows - 1 || term->grid->rows[abs_row_no] == NULL;
|
||||
}
|
||||
|
||||
static bool
|
||||
has_wrapped_around_right(const struct terminal *term, int abs_row_no)
|
||||
{
|
||||
int rebased_row = grid_row_abs_to_sb(term->grid, term->rows, abs_row_no);
|
||||
return rebased_row == 0;
|
||||
|
|
@ -235,13 +243,19 @@ search_update_selection(struct terminal *term, const struct range *match)
|
|||
}
|
||||
|
||||
if (start_row != term->search.match.row ||
|
||||
start_col != term->search.match.col)
|
||||
start_col != term->search.match.col ||
|
||||
|
||||
/* Pointer leave events trigger selection_finalize() :/ */
|
||||
!term->selection.ongoing)
|
||||
{
|
||||
int selection_row = start_row - grid->view + grid->num_rows;
|
||||
selection_row &= grid->num_rows - 1;
|
||||
|
||||
selection_start(
|
||||
term, start_col, selection_row, SELECTION_CHAR_WISE, false);
|
||||
|
||||
term->search.match.row = start_row;
|
||||
term->search.match.col = start_col;
|
||||
}
|
||||
|
||||
/* Update selection endpoint */
|
||||
|
|
@ -273,16 +287,16 @@ matches_cell(const struct terminal *term, const struct cell *cell, size_t search
|
|||
return -1;
|
||||
|
||||
if (composed != NULL) {
|
||||
if (search_ofs + 1 + composed->count > term->search.len)
|
||||
if (search_ofs + composed->count > term->search.len)
|
||||
return -1;
|
||||
|
||||
for (size_t j = 1; j < composed->count; j++) {
|
||||
if (composed->chars[j] != term->search.buf[search_ofs + 1 + j])
|
||||
if (composed->chars[j] != term->search.buf[search_ofs + j])
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return composed != NULL ? 1 + composed->count : 1;
|
||||
return composed != NULL ? composed->count : 1;
|
||||
}
|
||||
|
||||
static bool
|
||||
|
|
@ -369,8 +383,11 @@ find_next(struct terminal *term, enum search_direction direction,
|
|||
match_len += additional_chars;
|
||||
match_end_col++;
|
||||
|
||||
while (match_row->cells[match_end_col].wc > CELL_SPACER)
|
||||
while (match_end_col < term->cols &&
|
||||
match_row->cells[match_end_col].wc > CELL_SPACER)
|
||||
{
|
||||
match_end_col++;
|
||||
}
|
||||
}
|
||||
|
||||
if (match_len != term->search.len) {
|
||||
|
|
@ -546,6 +563,7 @@ search_matches_next(struct search_match_iterator *iter)
|
|||
term->cols - 1,
|
||||
grid_row_absolute_in_view(grid, term->rows - 1)};
|
||||
|
||||
/* BUG: matches *starting* outside the view, but ending *inside*, aren't matched */
|
||||
struct range match;
|
||||
bool found = find_next(term, SEARCH_FORWARD, abs_start, abs_end, &match);
|
||||
if (!found)
|
||||
|
|
@ -565,11 +583,6 @@ search_matches_next(struct search_match_iterator *iter)
|
|||
match.start.row, match.start.col,
|
||||
match.end.row, match.end.col, grid->view);
|
||||
|
||||
xassert(match.start.row >= 0);
|
||||
xassert(match.start.row < term->rows);
|
||||
xassert(match.end.row >= 0);
|
||||
xassert(match.end.row < term->rows);
|
||||
|
||||
/* Assert match end comes *after* the match start */
|
||||
xassert(match.end.row > match.start.row ||
|
||||
(match.end.row == match.start.row &&
|
||||
|
|
@ -642,67 +655,299 @@ search_add_chars(struct terminal *term, const char *src, size_t count)
|
|||
add_wchars(term, c32s, chars);
|
||||
}
|
||||
|
||||
enum extend_direction {SEARCH_EXTEND_LEFT, SEARCH_EXTEND_RIGHT};
|
||||
|
||||
static bool
|
||||
coord_advance_left(const struct terminal *term, struct coord *pos,
|
||||
const struct row **row)
|
||||
{
|
||||
const struct grid *grid = term->grid;
|
||||
struct coord new_pos = *pos;
|
||||
|
||||
if (--new_pos.col < 0) {
|
||||
new_pos.row = (new_pos.row - 1 + grid->num_rows) & (grid->num_rows - 1);
|
||||
new_pos.col = term->cols - 1;
|
||||
|
||||
if (has_wrapped_around_left(term, new_pos.row))
|
||||
return false;
|
||||
|
||||
if (row != NULL)
|
||||
*row = grid->rows[new_pos.row];
|
||||
}
|
||||
|
||||
*pos = new_pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
coord_advance_right(const struct terminal *term, struct coord *pos,
|
||||
const struct row **row)
|
||||
{
|
||||
const struct grid *grid = term->grid;
|
||||
struct coord new_pos = *pos;
|
||||
|
||||
if (++new_pos.col >= term->cols) {
|
||||
new_pos.row = (new_pos.row + 1) & (grid->num_rows - 1);
|
||||
new_pos.col = 0;
|
||||
|
||||
if (has_wrapped_around_right(term, new_pos.row))
|
||||
return false;
|
||||
|
||||
if (row != NULL)
|
||||
*row = grid->rows[new_pos.row];
|
||||
}
|
||||
|
||||
*pos = new_pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_char(const struct terminal *term, struct coord *target,
|
||||
enum extend_direction direction)
|
||||
{
|
||||
if (term->search.match_len == 0)
|
||||
return false;
|
||||
|
||||
struct coord pos = direction == SEARCH_EXTEND_LEFT
|
||||
? selection_get_start(term) : selection_get_end(term);
|
||||
xassert(pos.row >= 0);
|
||||
xassert(pos.row < term->grid->num_rows);
|
||||
|
||||
*target = pos;
|
||||
|
||||
const struct row *row = term->grid->rows[pos.row];
|
||||
|
||||
while (true) {
|
||||
switch (direction) {
|
||||
case SEARCH_EXTEND_LEFT:
|
||||
if (!coord_advance_left(term, &pos, &row))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case SEARCH_EXTEND_RIGHT:
|
||||
if (!coord_advance_right(term, &pos, &row))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
const char32_t wc = row->cells[pos.col].wc;
|
||||
|
||||
if (wc >= CELL_SPACER || wc == U'\0')
|
||||
continue;
|
||||
|
||||
*target = pos;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_char_left(const struct terminal *term, struct coord *target)
|
||||
{
|
||||
return search_extend_find_char(term, target, SEARCH_EXTEND_LEFT);
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_char_right(const struct terminal *term, struct coord *target)
|
||||
{
|
||||
return search_extend_find_char(term, target, SEARCH_EXTEND_RIGHT);
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_word(const struct terminal *term, bool spaces_only,
|
||||
struct coord *target, enum extend_direction direction)
|
||||
{
|
||||
if (term->search.match_len == 0)
|
||||
return false;
|
||||
|
||||
struct grid *grid = term->grid;
|
||||
struct coord pos = direction == SEARCH_EXTEND_LEFT
|
||||
? selection_get_start(term)
|
||||
: selection_get_end(term);
|
||||
|
||||
xassert(pos.row >= 0);
|
||||
xassert(pos.row < grid->num_rows);
|
||||
|
||||
*target = pos;
|
||||
|
||||
/* First character to consider is the *next* character */
|
||||
switch (direction) {
|
||||
case SEARCH_EXTEND_LEFT:
|
||||
if (!coord_advance_left(term, &pos, NULL))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case SEARCH_EXTEND_RIGHT:
|
||||
if (!coord_advance_right(term, &pos, NULL))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
xassert(pos.row >= 0);
|
||||
xassert(pos.row < grid->num_rows);
|
||||
xassert(grid->rows[pos.row] != NULL);
|
||||
|
||||
/* Find next word boundary */
|
||||
switch (direction) {
|
||||
case SEARCH_EXTEND_LEFT:
|
||||
selection_find_word_boundary_left(term, &pos, spaces_only);
|
||||
break;
|
||||
|
||||
case SEARCH_EXTEND_RIGHT:
|
||||
selection_find_word_boundary_right(term, &pos, spaces_only, false);
|
||||
break;
|
||||
}
|
||||
|
||||
*target = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_word_left(const struct terminal *term, bool spaces_only,
|
||||
struct coord *target)
|
||||
{
|
||||
return search_extend_find_word(term, spaces_only, target, SEARCH_EXTEND_LEFT);
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_word_right(const struct terminal *term, bool spaces_only,
|
||||
struct coord *target)
|
||||
{
|
||||
return search_extend_find_word(term, spaces_only, target, SEARCH_EXTEND_RIGHT);
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_line(const struct terminal *term, struct coord *target,
|
||||
enum extend_direction direction)
|
||||
{
|
||||
if (term->search.match_len == 0)
|
||||
return false;
|
||||
|
||||
struct coord pos = direction == SEARCH_EXTEND_LEFT
|
||||
? selection_get_start(term) : selection_get_end(term);
|
||||
|
||||
xassert(pos.row >= 0);
|
||||
xassert(pos.row < term->grid->num_rows);
|
||||
|
||||
*target = pos;
|
||||
|
||||
const struct grid *grid = term->grid;
|
||||
|
||||
switch (direction) {
|
||||
case SEARCH_EXTEND_LEFT:
|
||||
pos.row = (pos.row - 1 + grid->num_rows) & (grid->num_rows - 1);
|
||||
if (has_wrapped_around_left(term, pos.row))
|
||||
return false;
|
||||
break;
|
||||
|
||||
case SEARCH_EXTEND_RIGHT:
|
||||
pos.row = (pos.row + 1) & (grid->num_rows - 1);
|
||||
if (has_wrapped_around_right(term, pos.row))
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
*target = pos;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_line_up(const struct terminal *term, struct coord *target)
|
||||
{
|
||||
return search_extend_find_line(term, target, SEARCH_EXTEND_LEFT);
|
||||
}
|
||||
|
||||
static bool
|
||||
search_extend_find_line_down(const struct terminal *term, struct coord *target)
|
||||
{
|
||||
return search_extend_find_line(term, target, SEARCH_EXTEND_RIGHT);
|
||||
}
|
||||
|
||||
static void
|
||||
search_match_to_end_of_word(struct terminal *term, bool spaces_only)
|
||||
search_extend_left(struct terminal *term, const struct coord *target)
|
||||
{
|
||||
if (term->search.match_len == 0)
|
||||
return;
|
||||
|
||||
xassert(term->selection.coords.end.row >= 0);
|
||||
const struct coord last_coord = selection_get_start(term);
|
||||
struct coord pos = *target;
|
||||
const struct row *row = term->grid->rows[pos.row];
|
||||
|
||||
struct grid *grid = term->grid;
|
||||
const bool move_cursor = term->search.cursor == term->search.len;
|
||||
const bool move_cursor = term->search.cursor != 0;
|
||||
|
||||
struct coord old_end = selection_get_end(term);
|
||||
struct coord new_end = old_end;
|
||||
struct row *row = NULL;
|
||||
|
||||
xassert(new_end.row >= 0);
|
||||
xassert(new_end.row < grid->num_rows);
|
||||
|
||||
/* Advances a coordinate by one column, to the right. Returns
|
||||
* false if we’ve reached the scrollback wrap-around */
|
||||
#define advance_pos(coord) __extension__ \
|
||||
({ \
|
||||
bool wrapped_around = false; \
|
||||
if (++(coord).col >= term->cols) { \
|
||||
(coord).row = ((coord).row + 1) & (grid->num_rows - 1); \
|
||||
(coord).col = 0; \
|
||||
row = grid->rows[(coord).row]; \
|
||||
if (has_wrapped_around(term, (coord.row))) \
|
||||
wrapped_around = true; \
|
||||
} \
|
||||
!wrapped_around; \
|
||||
})
|
||||
|
||||
/* First character to consider is the *next* character */
|
||||
if (!advance_pos(new_end))
|
||||
struct extraction_context *ctx = extract_begin(SELECTION_NONE, false);
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
xassert(new_end.row >= 0);
|
||||
xassert(new_end.row < grid->num_rows);
|
||||
xassert(grid->rows[new_end.row] != NULL);
|
||||
while (pos.col != last_coord.col || pos.row != last_coord.row) {
|
||||
if (!extract_one(term, row, &row->cells[pos.col], pos.col, ctx))
|
||||
break;
|
||||
if (!coord_advance_right(term, &pos, &row))
|
||||
break;
|
||||
}
|
||||
|
||||
/* Find next word boundary */
|
||||
new_end.row -= grid->view + grid->num_rows;
|
||||
new_end.row &= grid->num_rows - 1;
|
||||
selection_find_word_boundary_right(term, &new_end, spaces_only, false);
|
||||
new_end.row += grid->view;
|
||||
new_end.row &= grid->num_rows - 1;
|
||||
char32_t *new_text;
|
||||
size_t new_len;
|
||||
|
||||
struct coord pos = old_end;
|
||||
row = grid->rows[pos.row];
|
||||
if (!extract_finish_wide(ctx, &new_text, &new_len))
|
||||
return;
|
||||
|
||||
if (!search_ensure_size(term, term->search.len + new_len))
|
||||
return;
|
||||
|
||||
memmove(&term->search.buf[new_len], &term->search.buf[0],
|
||||
term->search.len * sizeof(term->search.buf[0]));
|
||||
|
||||
size_t actually_copied = 0;
|
||||
for (size_t i = 0; i < new_len; i++) {
|
||||
if (new_text[i] == U'\n') {
|
||||
/* extract() adds newlines, which we never match against */
|
||||
continue;
|
||||
}
|
||||
|
||||
term->search.buf[actually_copied++] = new_text[i];
|
||||
term->search.len++;
|
||||
}
|
||||
|
||||
xassert(actually_copied <= new_len);
|
||||
if (actually_copied < new_len) {
|
||||
memmove(
|
||||
&term->search.buf[actually_copied], &term->search.buf[new_len],
|
||||
(term->search.len - actually_copied) * sizeof(term->search.buf[0]));
|
||||
}
|
||||
|
||||
term->search.buf[term->search.len] = U'\0';
|
||||
free(new_text);
|
||||
|
||||
if (move_cursor)
|
||||
term->search.cursor += actually_copied;
|
||||
|
||||
struct range match = {.start = *target, .end = selection_get_end(term)};
|
||||
search_update_selection(term, &match);
|
||||
|
||||
term->search.match_len = term->search.len;
|
||||
}
|
||||
|
||||
static void
|
||||
search_extend_right(struct terminal *term, const struct coord *target)
|
||||
{
|
||||
if (term->search.match_len == 0)
|
||||
return;
|
||||
|
||||
struct coord pos = selection_get_end(term);
|
||||
const struct row *row = term->grid->rows[pos.row];
|
||||
|
||||
const bool move_cursor = term->search.cursor == term->search.len;
|
||||
|
||||
struct extraction_context *ctx = extract_begin(SELECTION_NONE, false);
|
||||
if (ctx == NULL)
|
||||
return;
|
||||
|
||||
do {
|
||||
if (!advance_pos(pos))
|
||||
if (!coord_advance_right(term, &pos, &row))
|
||||
break;
|
||||
if (!extract_one(term, row, &row->cells[pos.col], pos.col, ctx))
|
||||
break;
|
||||
} while (pos.col != new_end.col || pos.row != new_end.row);
|
||||
} while (pos.col != target->col || pos.row != target->row);
|
||||
|
||||
char32_t *new_text;
|
||||
size_t new_len;
|
||||
|
|
@ -728,12 +973,9 @@ search_match_to_end_of_word(struct terminal *term, bool spaces_only)
|
|||
if (move_cursor)
|
||||
term->search.cursor = term->search.len;
|
||||
|
||||
struct range match = {.start = term->search.match, .end = new_end};
|
||||
struct range match = {.start = term->search.match, .end = *target};
|
||||
search_update_selection(term, &match);
|
||||
|
||||
term->search.match_len = term->search.len;
|
||||
|
||||
#undef advance_pos
|
||||
}
|
||||
|
||||
static size_t
|
||||
|
|
@ -822,6 +1064,62 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
case BIND_ACTION_SEARCH_NONE:
|
||||
return false;
|
||||
|
||||
case BIND_ACTION_SEARCH_SCROLLBACK_UP_PAGE:
|
||||
if (term->grid == &term->normal) {
|
||||
cmd_scrollback_up(term, term->rows);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case BIND_ACTION_SEARCH_SCROLLBACK_UP_HALF_PAGE:
|
||||
if (term->grid == &term->normal) {
|
||||
cmd_scrollback_up(term, max(term->rows / 2, 1));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SEARCH_SCROLLBACK_UP_LINE:
|
||||
if (term->grid == &term->normal) {
|
||||
cmd_scrollback_up(term, 1);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SEARCH_SCROLLBACK_DOWN_PAGE:
|
||||
if (term->grid == &term->normal) {
|
||||
cmd_scrollback_down(term, term->rows);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
||||
case BIND_ACTION_SEARCH_SCROLLBACK_DOWN_HALF_PAGE:
|
||||
if (term->grid == &term->normal) {
|
||||
cmd_scrollback_down(term, max(term->rows / 2, 1));
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SEARCH_SCROLLBACK_DOWN_LINE:
|
||||
if (term->grid == &term->normal) {
|
||||
cmd_scrollback_down(term, 1);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SEARCH_SCROLLBACK_HOME:
|
||||
if (term->grid == &term->normal) {
|
||||
cmd_scrollback_up(term, term->grid->num_rows);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SEARCH_SCROLLBACK_END:
|
||||
if (term->grid == &term->normal) {
|
||||
cmd_scrollback_down(term, term->grid->num_rows);
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case BIND_ACTION_SEARCH_CANCEL:
|
||||
if (term->search.view_followed_offset)
|
||||
grid->view = grid->offset;
|
||||
|
|
@ -967,17 +1265,85 @@ execute_binding(struct seat *seat, struct terminal *term,
|
|||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_EXTEND_WORD:
|
||||
search_match_to_end_of_word(term, false);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
case BIND_ACTION_SEARCH_EXTEND_CHAR: {
|
||||
struct coord target;
|
||||
if (search_extend_find_char_right(term, &target)) {
|
||||
search_extend_right(term, &target);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_EXTEND_WORD_WS:
|
||||
search_match_to_end_of_word(term, true);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
case BIND_ACTION_SEARCH_EXTEND_WORD: {
|
||||
struct coord target;
|
||||
if (search_extend_find_word_right(term, false, &target)) {
|
||||
search_extend_right(term, &target);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_EXTEND_WORD_WS: {
|
||||
struct coord target;
|
||||
if (search_extend_find_word_right(term, true, &target)) {
|
||||
search_extend_right(term, &target);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_EXTEND_LINE_DOWN: {
|
||||
struct coord target;
|
||||
if (search_extend_find_line_down(term, &target)) {
|
||||
search_extend_right(term, &target);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_EXTEND_BACKWARD_CHAR: {
|
||||
struct coord target;
|
||||
if (search_extend_find_char_left(term, &target)) {
|
||||
search_extend_left(term, &target);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD: {
|
||||
struct coord target;
|
||||
if (search_extend_find_word_left(term, false, &target)) {
|
||||
search_extend_left(term, &target);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_EXTEND_BACKWARD_WORD_WS: {
|
||||
struct coord target;
|
||||
if (search_extend_find_word_left(term, true, &target)) {
|
||||
search_extend_left(term, &target);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_EXTEND_LINE_UP: {
|
||||
struct coord target;
|
||||
if (search_extend_find_line_up(term, &target)) {
|
||||
search_extend_left(term, &target);
|
||||
*update_search_result = false;
|
||||
*redraw = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
case BIND_ACTION_SEARCH_CLIPBOARD_PASTE:
|
||||
text_from_clipboard(
|
||||
|
|
|
|||
102
selection.c
102
selection.c
|
|
@ -340,16 +340,19 @@ selection_to_text(const struct terminal *term)
|
|||
return extract_finish(ctx, &text, NULL) ? text : NULL;
|
||||
}
|
||||
|
||||
/* Coordinates are in *absolute* row numbers (NOT view local) */
|
||||
void
|
||||
selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
||||
selection_find_word_boundary_left(const struct terminal *term, struct coord *pos,
|
||||
bool spaces_only)
|
||||
{
|
||||
xassert(pos->row >= 0);
|
||||
xassert(pos->row < term->rows);
|
||||
const struct grid *grid = term->grid;
|
||||
|
||||
xassert(pos->col >= 0);
|
||||
xassert(pos->col < term->cols);
|
||||
xassert(pos->row >= 0);
|
||||
pos->row &= grid->num_rows - 1;
|
||||
|
||||
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
||||
const struct row *r = grid->rows[pos->row];
|
||||
char32_t c = r->cells[pos->col].wc;
|
||||
|
||||
while (c >= CELL_SPACER) {
|
||||
|
|
@ -373,15 +376,22 @@ selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
|||
int next_col = pos->col - 1;
|
||||
int next_row = pos->row;
|
||||
|
||||
const struct row *row = grid_row_in_view(term->grid, next_row);
|
||||
const struct row *row = grid->rows[next_row];
|
||||
|
||||
/* Linewrap */
|
||||
if (next_col < 0) {
|
||||
next_col = term->cols - 1;
|
||||
if (--next_row < 0)
|
||||
break;
|
||||
|
||||
row = grid_row_in_view(term->grid, next_row);
|
||||
next_row = (next_row - 1 + grid->num_rows) & (grid->num_rows - 1);
|
||||
|
||||
if (grid_row_abs_to_sb(grid, term->rows, next_row) == term->grid->num_rows - 1 ||
|
||||
grid->rows[next_row] == NULL)
|
||||
{
|
||||
/* Scrollback wrap-around */
|
||||
break;
|
||||
}
|
||||
|
||||
row = grid->rows[next_row];
|
||||
|
||||
if (row->linebreak) {
|
||||
/* Hard linebreak, treat as space. I.e. break selection */
|
||||
|
|
@ -418,17 +428,20 @@ selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
|||
}
|
||||
}
|
||||
|
||||
/* Coordinates are in *absolute* row numbers (NOT view local) */
|
||||
void
|
||||
selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
||||
selection_find_word_boundary_right(const struct terminal *term, struct coord *pos,
|
||||
bool spaces_only,
|
||||
bool stop_on_space_to_word_boundary)
|
||||
{
|
||||
xassert(pos->row >= 0);
|
||||
xassert(pos->row < term->rows);
|
||||
const struct grid *grid = term->grid;
|
||||
|
||||
xassert(pos->col >= 0);
|
||||
xassert(pos->col < term->cols);
|
||||
xassert(pos->row >= 0);
|
||||
pos->row &= grid->num_rows - 1;
|
||||
|
||||
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
||||
const struct row *r = grid->rows[pos->row];
|
||||
char32_t c = r->cells[pos->col].wc;
|
||||
|
||||
while (c >= CELL_SPACER) {
|
||||
|
|
@ -453,7 +466,7 @@ selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
|||
int next_col = pos->col + 1;
|
||||
int next_row = pos->row;
|
||||
|
||||
const struct row *row = grid_row_in_view(term->grid, next_row);
|
||||
const struct row *row = term->grid->rows[next_row];
|
||||
|
||||
/* Linewrap */
|
||||
if (next_col >= term->cols) {
|
||||
|
|
@ -463,10 +476,14 @@ selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
|||
}
|
||||
|
||||
next_col = 0;
|
||||
if (++next_row >= term->rows)
|
||||
break;
|
||||
next_row = (next_row + 1) & (grid->num_rows - 1);
|
||||
|
||||
row = grid_row_in_view(term->grid, next_row);
|
||||
if (grid_row_abs_to_sb(grid, term->rows, next_row) == 0) {
|
||||
/* Scrollback wrap-around */
|
||||
break;
|
||||
}
|
||||
|
||||
row = grid->rows[next_row];
|
||||
}
|
||||
|
||||
c = row->cells[next_col].wc;
|
||||
|
|
@ -659,17 +676,26 @@ selection_start(struct terminal *term, int col, int row,
|
|||
break;
|
||||
|
||||
case SELECTION_WORD_WISE: {
|
||||
struct coord start = {col, row}, end = {col, row};
|
||||
struct coord start = {col, term->grid->view + row};
|
||||
struct coord end = {col, term->grid->view + row};
|
||||
selection_find_word_boundary_left(term, &start, spaces_only);
|
||||
selection_find_word_boundary_right(term, &end, spaces_only, true);
|
||||
|
||||
term->selection.coords.start = (struct coord){
|
||||
start.col, term->grid->view + start.row};
|
||||
term->selection.coords.start = start;
|
||||
|
||||
term->selection.pivot.start = term->selection.coords.start;
|
||||
term->selection.pivot.end = (struct coord){end.col, term->grid->view + end.row};
|
||||
term->selection.pivot.end = end;
|
||||
|
||||
selection_update(term, end.col, end.row);
|
||||
/*
|
||||
* FIXME: go through selection.c and make sure all public
|
||||
* functions use the *same* coordinate system...
|
||||
*
|
||||
* selection_find_word_boundary*() uses absolute row numbers,
|
||||
* while selection_update(), and pretty much all others, use
|
||||
* view-local.
|
||||
*/
|
||||
|
||||
selection_update(term, end.col, end.row - term->grid->view);
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
@ -1091,16 +1117,16 @@ selection_update(struct terminal *term, int col, int row)
|
|||
if (!term->selection.ongoing)
|
||||
return;
|
||||
|
||||
LOG_DBG("selection updated: start = %d,%d, end = %d,%d -> %d, %d",
|
||||
term->selection.coords.start.row, term->selection.coords.start.col,
|
||||
term->selection.coords.end.row, term->selection.coords.end.col,
|
||||
row, col);
|
||||
|
||||
xassert(term->grid->view + row != -1);
|
||||
|
||||
struct coord new_start = term->selection.coords.start;
|
||||
struct coord new_end = {col, term->grid->view + row};
|
||||
|
||||
LOG_DBG("selection updated: start = %d,%d, end = %d,%d -> %d, %d",
|
||||
term->selection.coords.start.row, term->selection.coords.start.col,
|
||||
term->selection.coords.end.row, term->selection.coords.end.col,
|
||||
new_end.row, new_end.col);
|
||||
|
||||
/* Adjust start point if the selection has changed 'direction' */
|
||||
if (!(new_end.row == new_start.row && new_end.col == new_start.col)) {
|
||||
enum selection_direction new_direction = term->selection.direction;
|
||||
|
|
@ -1160,21 +1186,17 @@ selection_update(struct terminal *term, int col, int row)
|
|||
|
||||
case SELECTION_WORD_WISE:
|
||||
switch (term->selection.direction) {
|
||||
case SELECTION_LEFT: {
|
||||
struct coord end = {col, row};
|
||||
case SELECTION_LEFT:
|
||||
new_end = (struct coord){col, term->grid->view + row};
|
||||
selection_find_word_boundary_left(
|
||||
term, &end, term->selection.spaces_only);
|
||||
new_end = (struct coord){end.col, term->grid->view + end.row};
|
||||
term, &new_end, term->selection.spaces_only);
|
||||
break;
|
||||
}
|
||||
|
||||
case SELECTION_RIGHT: {
|
||||
struct coord end = {col, row};
|
||||
case SELECTION_RIGHT:
|
||||
new_end = (struct coord){col, term->grid->view + row};
|
||||
selection_find_word_boundary_right(
|
||||
term, &end, term->selection.spaces_only, true);
|
||||
new_end = (struct coord){end.col, term->grid->view + end.row};
|
||||
term, &new_end, term->selection.spaces_only, true);
|
||||
break;
|
||||
}
|
||||
|
||||
case SELECTION_UNDIR:
|
||||
break;
|
||||
|
|
@ -1346,16 +1368,14 @@ selection_extend_normal(struct terminal *term, int col, int row,
|
|||
xassert(new_kind == SELECTION_CHAR_WISE ||
|
||||
new_kind == SELECTION_WORD_WISE);
|
||||
|
||||
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
|
||||
struct coord pivot_start = {new_start.col, new_start.row};
|
||||
struct coord pivot_end = pivot_start;
|
||||
|
||||
selection_find_word_boundary_left(term, &pivot_start, spaces_only);
|
||||
selection_find_word_boundary_right(term, &pivot_end, spaces_only, true);
|
||||
|
||||
term->selection.pivot.start =
|
||||
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
|
||||
term->selection.pivot.end =
|
||||
(struct coord){pivot_end.col, term->grid->view + pivot_end.row};
|
||||
term->selection.pivot.start = pivot_start;
|
||||
term->selection.pivot.end = pivot_end;
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -78,9 +78,9 @@ void selection_start_scroll_timer(
|
|||
void selection_stop_scroll_timer(struct terminal *term);
|
||||
|
||||
void selection_find_word_boundary_left(
|
||||
struct terminal *term, struct coord *pos, bool spaces_only);
|
||||
const struct terminal *term, struct coord *pos, bool spaces_only);
|
||||
void selection_find_word_boundary_right(
|
||||
struct terminal *term, struct coord *pos, bool spaces_only,
|
||||
const struct terminal *term, struct coord *pos, bool spaces_only,
|
||||
bool stop_on_space_to_word_boundary);
|
||||
|
||||
struct coord selection_get_start(const struct terminal *term);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue