mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-04-02 07:15:31 -04:00
commit
3da8dc123f
8 changed files with 179 additions and 106 deletions
|
|
@ -75,6 +75,8 @@
|
||||||
* Improved performance on compositors that does not release shm
|
* Improved performance on compositors that does not release shm
|
||||||
buffers immediately, e.g. KWin
|
buffers immediately, e.g. KWin
|
||||||
(https://codeberg.org/dnkl/foot/issues/478).
|
(https://codeberg.org/dnkl/foot/issues/478).
|
||||||
|
* `ctrl + w` (_extend-to-word-boundary_) can now be used across lines
|
||||||
|
(https://codeberg.org/dnkl/foot/issues/421).
|
||||||
|
|
||||||
|
|
||||||
### Deprecated
|
### Deprecated
|
||||||
|
|
@ -153,6 +155,7 @@
|
||||||
* PTY not being drained when the client application terminates.
|
* PTY not being drained when the client application terminates.
|
||||||
* `auto_left_margin` not being limited to `cub1`
|
* `auto_left_margin` not being limited to `cub1`
|
||||||
(https://codeberg.org/dnkl/foot/issues/441).
|
(https://codeberg.org/dnkl/foot/issues/441).
|
||||||
|
* Crash in scrollback search mode when searching beyond the last output.
|
||||||
|
|
||||||
|
|
||||||
### Contributors
|
### Contributors
|
||||||
|
|
|
||||||
73
extract.c
73
extract.c
|
|
@ -11,6 +11,7 @@ struct extraction_context {
|
||||||
size_t idx;
|
size_t idx;
|
||||||
size_t empty_count;
|
size_t empty_count;
|
||||||
size_t newline_count;
|
size_t newline_count;
|
||||||
|
bool strip_trailing_empty;
|
||||||
bool failed;
|
bool failed;
|
||||||
const struct row *last_row;
|
const struct row *last_row;
|
||||||
const struct cell *last_cell;
|
const struct cell *last_cell;
|
||||||
|
|
@ -18,7 +19,7 @@ struct extraction_context {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct extraction_context *
|
struct extraction_context *
|
||||||
extract_begin(enum selection_kind kind)
|
extract_begin(enum selection_kind kind, bool strip_trailing_empty)
|
||||||
{
|
{
|
||||||
struct extraction_context *ctx = malloc(sizeof(*ctx));
|
struct extraction_context *ctx = malloc(sizeof(*ctx));
|
||||||
if (unlikely(ctx == NULL)) {
|
if (unlikely(ctx == NULL)) {
|
||||||
|
|
@ -28,6 +29,7 @@ extract_begin(enum selection_kind kind)
|
||||||
|
|
||||||
*ctx = (struct extraction_context){
|
*ctx = (struct extraction_context){
|
||||||
.selection_kind = kind,
|
.selection_kind = kind,
|
||||||
|
.strip_trailing_empty = strip_trailing_empty,
|
||||||
};
|
};
|
||||||
return ctx;
|
return ctx;
|
||||||
}
|
}
|
||||||
|
|
@ -51,10 +53,8 @@ ensure_size(struct extraction_context *ctx, size_t additional_chars)
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
extract_finish(struct extraction_context *ctx, char **text, size_t *len)
|
extract_finish_wide(struct extraction_context *ctx, wchar_t **text, size_t *len)
|
||||||
{
|
{
|
||||||
bool ret = false;
|
|
||||||
|
|
||||||
if (text == NULL)
|
if (text == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -63,12 +63,24 @@ extract_finish(struct extraction_context *ctx, char **text, size_t *len)
|
||||||
*len = 0;
|
*len = 0;
|
||||||
|
|
||||||
if (ctx->failed)
|
if (ctx->failed)
|
||||||
goto out;
|
goto err;
|
||||||
|
|
||||||
|
if (!ctx->strip_trailing_empty) {
|
||||||
|
/* Insert pending newlines, and replace empty cells with spaces */
|
||||||
|
if (!ensure_size(ctx, ctx->newline_count + ctx->empty_count))
|
||||||
|
goto err;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ctx->newline_count; i++)
|
||||||
|
ctx->buf[ctx->idx++] = L'\n';
|
||||||
|
|
||||||
|
for (size_t i = 0; i < ctx->empty_count; i++)
|
||||||
|
ctx->buf[ctx->idx++] = L' ';
|
||||||
|
}
|
||||||
|
|
||||||
if (ctx->idx == 0) {
|
if (ctx->idx == 0) {
|
||||||
/* Selection of empty cells only */
|
/* Selection of empty cells only */
|
||||||
if (!ensure_size(ctx, 1))
|
if (!ensure_size(ctx, 1))
|
||||||
goto out;
|
goto err;
|
||||||
ctx->buf[ctx->idx++] = L'\0';
|
ctx->buf[ctx->idx++] = L'\0';
|
||||||
} else {
|
} else {
|
||||||
xassert(ctx->idx > 0);
|
xassert(ctx->idx > 0);
|
||||||
|
|
@ -77,12 +89,38 @@ extract_finish(struct extraction_context *ctx, char **text, size_t *len)
|
||||||
ctx->buf[ctx->idx - 1] = L'\0';
|
ctx->buf[ctx->idx - 1] = L'\0';
|
||||||
else {
|
else {
|
||||||
if (!ensure_size(ctx, 1))
|
if (!ensure_size(ctx, 1))
|
||||||
goto out;
|
goto err;
|
||||||
ctx->buf[ctx->idx++] = L'\0';
|
ctx->buf[ctx->idx++] = L'\0';
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t _len = wcstombs(NULL, ctx->buf, 0);
|
*text = ctx->buf;
|
||||||
|
if (len != NULL)
|
||||||
|
*len = ctx->idx - 1;
|
||||||
|
free(ctx);
|
||||||
|
return true;
|
||||||
|
|
||||||
|
err:
|
||||||
|
free(ctx->buf);
|
||||||
|
free(ctx);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
extract_finish(struct extraction_context *ctx, char **text, size_t *len)
|
||||||
|
{
|
||||||
|
if (text == NULL)
|
||||||
|
return false;
|
||||||
|
if (len != NULL)
|
||||||
|
*len = 0;
|
||||||
|
|
||||||
|
wchar_t *wtext;
|
||||||
|
if (!extract_finish_wide(ctx, &wtext, NULL))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool ret = false;
|
||||||
|
|
||||||
|
size_t _len = wcstombs(NULL, wtext, 0);
|
||||||
if (_len == (size_t)-1) {
|
if (_len == (size_t)-1) {
|
||||||
LOG_ERRNO("failed to convert selection to UTF-8");
|
LOG_ERRNO("failed to convert selection to UTF-8");
|
||||||
goto out;
|
goto out;
|
||||||
|
|
@ -94,7 +132,7 @@ extract_finish(struct extraction_context *ctx, char **text, size_t *len)
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
wcstombs(*text, ctx->buf, _len + 1);
|
wcstombs(*text, wtext, _len + 1);
|
||||||
|
|
||||||
if (len != NULL)
|
if (len != NULL)
|
||||||
*len = _len;
|
*len = _len;
|
||||||
|
|
@ -102,8 +140,7 @@ extract_finish(struct extraction_context *ctx, char **text, size_t *len)
|
||||||
ret = true;
|
ret = true;
|
||||||
|
|
||||||
out:
|
out:
|
||||||
free(ctx->buf);
|
free(wtext);
|
||||||
free(ctx);
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -130,6 +167,13 @@ extract_one(const struct terminal *term, const struct row *row,
|
||||||
/* Don't emit newline just yet - only if there are
|
/* Don't emit newline just yet - only if there are
|
||||||
* non-empty cells following it */
|
* non-empty cells following it */
|
||||||
ctx->newline_count++;
|
ctx->newline_count++;
|
||||||
|
|
||||||
|
if (!ctx->strip_trailing_empty) {
|
||||||
|
if (!ensure_size(ctx, ctx->empty_count))
|
||||||
|
goto err;
|
||||||
|
for (size_t i = 0; i < ctx->empty_count; i++)
|
||||||
|
ctx->buf[ctx->idx++] = L' ';
|
||||||
|
}
|
||||||
ctx->empty_count = 0;
|
ctx->empty_count = 0;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -138,6 +182,13 @@ extract_one(const struct terminal *term, const struct row *row,
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
ctx->buf[ctx->idx++] = L'\n';
|
ctx->buf[ctx->idx++] = L'\n';
|
||||||
|
|
||||||
|
if (!ctx->strip_trailing_empty) {
|
||||||
|
if (!ensure_size(ctx, ctx->empty_count))
|
||||||
|
goto err;
|
||||||
|
for (size_t i = 0; i < ctx->empty_count; i++)
|
||||||
|
ctx->buf[ctx->idx++] = L' ';
|
||||||
|
}
|
||||||
ctx->empty_count = 0;
|
ctx->empty_count = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,12 +2,14 @@
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <wchar.h>
|
||||||
|
|
||||||
#include "terminal.h"
|
#include "terminal.h"
|
||||||
|
|
||||||
struct extraction_context;
|
struct extraction_context;
|
||||||
|
|
||||||
struct extraction_context *extract_begin(enum selection_kind kind);
|
struct extraction_context *extract_begin(
|
||||||
|
enum selection_kind kind, bool strip_trailing_empty);
|
||||||
|
|
||||||
bool extract_one(
|
bool extract_one(
|
||||||
const struct terminal *term, const struct row *row, const struct cell *cell,
|
const struct terminal *term, const struct row *row, const struct cell *cell,
|
||||||
|
|
@ -15,3 +17,5 @@ bool extract_one(
|
||||||
|
|
||||||
bool extract_finish(
|
bool extract_finish(
|
||||||
struct extraction_context *context, char **text, size_t *len);
|
struct extraction_context *context, char **text, size_t *len);
|
||||||
|
bool extract_finish_wide(
|
||||||
|
struct extraction_context *context, wchar_t **text, size_t *len);
|
||||||
|
|
|
||||||
|
|
@ -106,7 +106,7 @@ render_worker_thread(void *_ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct extraction_context *
|
struct extraction_context *
|
||||||
extract_begin(enum selection_kind kind)
|
extract_begin(enum selection_kind kind, bool strip_trailing_empty)
|
||||||
{
|
{
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
164
search.c
164
search.c
|
|
@ -11,6 +11,7 @@
|
||||||
#define LOG_ENABLE_DBG 0
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
#include "extract.h"
|
||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
|
|
@ -77,6 +78,16 @@ search_ensure_size(struct terminal *term, size_t wanted_size)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
has_wrapped_around(const struct terminal *term, int abs_row_no)
|
||||||
|
{
|
||||||
|
int scrollback_start = term->grid->offset + term->rows;
|
||||||
|
int rebased_row = abs_row_no - scrollback_start + term->grid->num_rows;
|
||||||
|
rebased_row &= term->grid->num_rows - 1;
|
||||||
|
|
||||||
|
return rebased_row == 0;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
search_cancel_keep_selection(struct terminal *term)
|
search_cancel_keep_selection(struct terminal *term)
|
||||||
{
|
{
|
||||||
|
|
@ -327,13 +338,12 @@ search_find_next(struct terminal *term)
|
||||||
|
|
||||||
for (size_t i = 0; i < term->search.len;) {
|
for (size_t i = 0; i < term->search.len;) {
|
||||||
if (end_col >= term->cols) {
|
if (end_col >= term->cols) {
|
||||||
if (end_row + 1 > grid_row_absolute(term->grid, term->grid->offset + term->rows - 1)) {
|
end_row = (end_row + 1) & (term->grid->num_rows - 1);
|
||||||
/* Don't continue past end of the world */
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
end_row++;
|
|
||||||
end_col = 0;
|
end_col = 0;
|
||||||
|
|
||||||
|
if (has_wrapped_around(term, end_row))
|
||||||
|
break;
|
||||||
|
|
||||||
row = term->grid->rows[end_row];
|
row = term->grid->rows[end_row];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -428,91 +438,85 @@ search_match_to_end_of_word(struct terminal *term, bool spaces_only)
|
||||||
if (term->search.match_len == 0)
|
if (term->search.match_len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
xassert(term->search.match.row != -1);
|
xassert(term->selection.end.row != -1);
|
||||||
xassert(term->search.match.col != -1);
|
|
||||||
|
|
||||||
int end_row = term->search.match.row;
|
const bool move_cursor = term->search.cursor == term->search.len;
|
||||||
int end_col = term->search.match.col;
|
|
||||||
size_t len = term->search.match_len;
|
|
||||||
|
|
||||||
/* Calculate end coord - note: assumed to be valid */
|
const struct coord old_end = term->selection.end;
|
||||||
for (size_t i = 0; i < len; i++) {
|
struct coord new_end = old_end;
|
||||||
for (size_t j = 0; j < wcwidth(term->search.buf[i]); j++) {
|
struct row *row = NULL;
|
||||||
if (++end_col >= term->cols) {
|
|
||||||
end_row = (end_row + 1) & (term->grid->num_rows - 1);
|
|
||||||
end_col = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tll(wchar_t) new_chars = tll_init();
|
#define newline(coord) __extension__ \
|
||||||
|
({ \
|
||||||
|
bool wrapped_around = false; \
|
||||||
|
if (++(coord).col >= term->cols) { \
|
||||||
|
(coord).row = ((coord).row + 1) & (term->grid->num_rows - 1); \
|
||||||
|
(coord).col = 0; \
|
||||||
|
row = term->grid->rows[(coord).row]; \
|
||||||
|
if (has_wrapped_around(term, (coord.row))) \
|
||||||
|
wrapped_around = true; \
|
||||||
|
} \
|
||||||
|
wrapped_around; \
|
||||||
|
})
|
||||||
|
|
||||||
/* Always append at least one character *if* possible */
|
/* First character to consider is the *next* character */
|
||||||
bool first = true;
|
if (newline(new_end))
|
||||||
|
|
||||||
for (size_t r = 0;
|
|
||||||
r < term->grid->num_rows;
|
|
||||||
end_row = (end_row + 1) & (term->grid->num_rows - 1), r++)
|
|
||||||
{
|
|
||||||
const struct row *row = term->grid->rows[end_row];
|
|
||||||
if (row == NULL)
|
|
||||||
break;
|
|
||||||
|
|
||||||
bool done = false;
|
|
||||||
for (; end_col < term->cols; end_col++) {
|
|
||||||
wchar_t wc = row->cells[end_col].wc;
|
|
||||||
if (wc >= CELL_SPACER)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
const struct composed *composed = NULL;
|
|
||||||
if (wc >= CELL_COMB_CHARS_LO &&
|
|
||||||
wc < (CELL_COMB_CHARS_LO + term->composed_count))
|
|
||||||
{
|
|
||||||
composed = &term->composed[wc - CELL_COMB_CHARS_LO];
|
|
||||||
wc = composed->base;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (wc == 0 || (!first && !isword(wc, spaces_only, term->conf->word_delimiters))) {
|
|
||||||
done = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
first = false;
|
|
||||||
tll_push_back(new_chars, wc);
|
|
||||||
|
|
||||||
if (composed != NULL) {
|
|
||||||
for (size_t i = 0; i < composed->count; i++)
|
|
||||||
tll_push_back(new_chars, composed->combining[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (done)
|
|
||||||
break;
|
|
||||||
|
|
||||||
end_col = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (tll_length(new_chars) == 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!search_ensure_size(term, term->search.len + tll_length(new_chars)))
|
xassert(term->grid->rows[new_end.row] != NULL);
|
||||||
|
|
||||||
|
/* Find next word boundary */
|
||||||
|
new_end.row -= term->grid->view;
|
||||||
|
selection_find_word_boundary_right(term, &new_end, spaces_only);
|
||||||
|
new_end.row += term->grid->view;
|
||||||
|
|
||||||
|
struct coord pos = old_end;
|
||||||
|
row = term->grid->rows[pos.row];
|
||||||
|
|
||||||
|
struct extraction_context *ctx = extract_begin(SELECTION_NONE, false);
|
||||||
|
if (ctx == NULL)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* Keep cursor at the end, but don't move it if not */
|
do {
|
||||||
bool move_cursor = term->search.cursor == term->search.len;
|
if (newline(pos))
|
||||||
|
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);
|
||||||
|
|
||||||
|
wchar_t *new_text;
|
||||||
|
size_t new_len;
|
||||||
|
|
||||||
|
if (!extract_finish_wide(ctx, &new_text, &new_len))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!search_ensure_size(term, term->search.len + new_len))
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < new_len; i++) {
|
||||||
|
if (new_text[i] == L'\n') {
|
||||||
|
/* extract() adds newlines, which we never match against */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
term->search.buf[term->search.len++] = new_text[i];
|
||||||
|
}
|
||||||
|
|
||||||
/* Append newly found characters to the search buffer */
|
|
||||||
tll_foreach(new_chars, it)
|
|
||||||
term->search.buf[term->search.len++] = it->item;
|
|
||||||
term->search.buf[term->search.len] = L'\0';
|
term->search.buf[term->search.len] = L'\0';
|
||||||
|
free(new_text);
|
||||||
|
|
||||||
if (move_cursor)
|
if (move_cursor)
|
||||||
term->search.cursor += tll_length(new_chars);
|
term->search.cursor = term->search.len;
|
||||||
|
|
||||||
tll_free(new_chars);
|
|
||||||
|
|
||||||
|
/* search_update_selection() expected end coordinate to be *exclusive* */
|
||||||
|
newline(new_end);
|
||||||
search_update_selection(
|
search_update_selection(
|
||||||
term, term->search.match.row, term->search.match.col, end_row, end_col);
|
term, term->search.match.row, term->search.match.col,
|
||||||
|
new_end.row, new_end.col);
|
||||||
|
|
||||||
|
term->search.match_len = term->search.len;
|
||||||
|
|
||||||
|
#undef newline
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t
|
||||||
|
|
@ -755,12 +759,14 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_EXTEND_WORD:
|
case BIND_ACTION_SEARCH_EXTEND_WORD:
|
||||||
search_match_to_end_of_word(term, false);
|
search_match_to_end_of_word(term, false);
|
||||||
*update_search_result = *redraw = true;
|
*update_search_result = false;
|
||||||
|
*redraw = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_EXTEND_WORD_WS:
|
case BIND_ACTION_SEARCH_EXTEND_WORD_WS:
|
||||||
search_match_to_end_of_word(term, true);
|
search_match_to_end_of_word(term, true);
|
||||||
*update_search_result = *redraw = true;
|
*update_search_result = false;
|
||||||
|
*redraw = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_CLIPBOARD_PASTE:
|
case BIND_ACTION_SEARCH_CLIPBOARD_PASTE:
|
||||||
|
|
|
||||||
30
selection.c
30
selection.c
|
|
@ -215,7 +215,7 @@ selection_to_text(const struct terminal *term)
|
||||||
if (term->selection.end.row == -1)
|
if (term->selection.end.row == -1)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
struct extraction_context *ctx = extract_begin(term->selection.kind);
|
struct extraction_context *ctx = extract_begin(term->selection.kind, true);
|
||||||
if (ctx == NULL)
|
if (ctx == NULL)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
|
@ -227,9 +227,9 @@ selection_to_text(const struct terminal *term)
|
||||||
return extract_finish(ctx, &text, NULL) ? text : NULL;
|
return extract_finish(ctx, &text, NULL) ? text : NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
find_word_boundary_left(struct terminal *term, struct coord *pos,
|
selection_find_word_boundary_left(struct terminal *term, struct coord *pos,
|
||||||
bool spaces_only)
|
bool spaces_only)
|
||||||
{
|
{
|
||||||
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
||||||
wchar_t c = r->cells[pos->col].wc;
|
wchar_t c = r->cells[pos->col].wc;
|
||||||
|
|
@ -299,9 +299,9 @@ find_word_boundary_left(struct terminal *term, struct coord *pos,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
void
|
||||||
find_word_boundary_right(struct terminal *term, struct coord *pos,
|
selection_find_word_boundary_right(struct terminal *term, struct coord *pos,
|
||||||
bool spaces_only)
|
bool spaces_only)
|
||||||
{
|
{
|
||||||
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
const struct row *r = grid_row_in_view(term->grid, pos->row);
|
||||||
wchar_t c = r->cells[pos->col].wc;
|
wchar_t c = r->cells[pos->col].wc;
|
||||||
|
|
@ -403,8 +403,8 @@ selection_start(struct terminal *term, int col, int row,
|
||||||
|
|
||||||
case SELECTION_WORD_WISE: {
|
case SELECTION_WORD_WISE: {
|
||||||
struct coord start = {col, row}, end = {col, row};
|
struct coord start = {col, row}, end = {col, row};
|
||||||
find_word_boundary_left(term, &start, spaces_only);
|
selection_find_word_boundary_left(term, &start, spaces_only);
|
||||||
find_word_boundary_right(term, &end, spaces_only);
|
selection_find_word_boundary_right(term, &end, spaces_only);
|
||||||
|
|
||||||
term->selection.start = (struct coord){
|
term->selection.start = (struct coord){
|
||||||
start.col, term->grid->view + start.row};
|
start.col, term->grid->view + start.row};
|
||||||
|
|
@ -694,14 +694,16 @@ selection_update(struct terminal *term, int col, int row)
|
||||||
switch (term->selection.direction) {
|
switch (term->selection.direction) {
|
||||||
case SELECTION_LEFT: {
|
case SELECTION_LEFT: {
|
||||||
struct coord end = {col, row};
|
struct coord end = {col, row};
|
||||||
find_word_boundary_left(term, &end, term->selection.spaces_only);
|
selection_find_word_boundary_left(
|
||||||
|
term, &end, term->selection.spaces_only);
|
||||||
new_end = (struct coord){end.col, term->grid->view + end.row};
|
new_end = (struct coord){end.col, term->grid->view + end.row};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case SELECTION_RIGHT: {
|
case SELECTION_RIGHT: {
|
||||||
struct coord end = {col, row};
|
struct coord end = {col, row};
|
||||||
find_word_boundary_right(term, &end, term->selection.spaces_only);
|
selection_find_word_boundary_right(
|
||||||
|
term, &end, term->selection.spaces_only);
|
||||||
new_end = (struct coord){end.col, term->grid->view + end.row};
|
new_end = (struct coord){end.col, term->grid->view + end.row};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -840,8 +842,10 @@ selection_extend_normal(struct terminal *term, int col, int row,
|
||||||
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
|
struct coord pivot_start = {new_start.col, new_start.row - term->grid->view};
|
||||||
struct coord pivot_end = pivot_start;
|
struct coord pivot_end = pivot_start;
|
||||||
|
|
||||||
find_word_boundary_left(term, &pivot_start, term->selection.spaces_only);
|
selection_find_word_boundary_left(
|
||||||
find_word_boundary_right(term, &pivot_end, term->selection.spaces_only);
|
term, &pivot_start, term->selection.spaces_only);
|
||||||
|
selection_find_word_boundary_right(
|
||||||
|
term, &pivot_end, term->selection.spaces_only);
|
||||||
|
|
||||||
term->selection.pivot.start =
|
term->selection.pivot.start =
|
||||||
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
|
(struct coord){pivot_start.col, term->grid->view + pivot_start.row};
|
||||||
|
|
|
||||||
|
|
@ -74,3 +74,8 @@ void selection_start_scroll_timer(
|
||||||
struct terminal *term, int interval_ns,
|
struct terminal *term, int interval_ns,
|
||||||
enum selection_scroll_direction direction, int col);
|
enum selection_scroll_direction direction, int col);
|
||||||
void selection_stop_scroll_timer(struct terminal *term);
|
void selection_stop_scroll_timer(struct terminal *term);
|
||||||
|
|
||||||
|
void selection_find_word_boundary_left(
|
||||||
|
struct terminal *term, struct coord *pos, bool spaces_only);
|
||||||
|
void selection_find_word_boundary_right(
|
||||||
|
struct terminal *term, struct coord *pos, bool spaces_only);
|
||||||
|
|
|
||||||
|
|
@ -2900,7 +2900,7 @@ static bool
|
||||||
rows_to_text(const struct terminal *term, int start, int end,
|
rows_to_text(const struct terminal *term, int start, int end,
|
||||||
char **text, size_t *len)
|
char **text, size_t *len)
|
||||||
{
|
{
|
||||||
struct extraction_context *ctx = extract_begin(SELECTION_NONE);
|
struct extraction_context *ctx = extract_begin(SELECTION_NONE, true);
|
||||||
if (ctx == NULL)
|
if (ctx == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue