Introduce config options for overview border: overview-active-border and overview-select-border
This commit is contained in:
parent
3a4814e1fa
commit
05ee680778
8 changed files with 21028 additions and 21338 deletions
2
config.h
2
config.h
|
|
@ -495,6 +495,8 @@ struct config {
|
||||||
uint32_t active_bg;
|
uint32_t active_bg;
|
||||||
uint32_t active_fg;
|
uint32_t active_fg;
|
||||||
uint32_t unread_fg;
|
uint32_t unread_fg;
|
||||||
|
uint32_t overview_active_border; /* ring around the currently-active tab in the overview */
|
||||||
|
uint32_t overview_select_border; /* ring around keyboard/hover-selected tab in the overview */
|
||||||
} colors;
|
} colors;
|
||||||
} tabs;
|
} tabs;
|
||||||
|
|
||||||
|
|
|
||||||
2
foot.ini
2
foot.ini
|
|
@ -193,6 +193,8 @@ height=26
|
||||||
# inherit-cwd=no (new tabs open in the active tab's cwd; requires OSC 7 shell support)
|
# inherit-cwd=no (new tabs open in the active tab's cwd; requires OSC 7 shell support)
|
||||||
# unread-indicator=● (string drawn before label when tab has unseen output; empty disables)
|
# unread-indicator=● (string drawn before label when tab has unseen output; empty disables)
|
||||||
# unread-color=fabd2f (color of the unread-indicator)
|
# unread-color=fabd2f (color of the unread-indicator)
|
||||||
|
# overview-active-border=fabd2f (ring around the currently-active tab in tab overview)
|
||||||
|
# overview-select-border=ffffff (ring around the keyboard/hover-selected tab in tab overview)
|
||||||
|
|
||||||
[csd]
|
[csd]
|
||||||
# preferred=server
|
# preferred=server
|
||||||
|
|
|
||||||
469
search.c
469
search.c
|
|
@ -8,7 +8,6 @@
|
||||||
|
|
||||||
#define LOG_MODULE "search"
|
#define LOG_MODULE "search"
|
||||||
#define LOG_ENABLE_DBG 0
|
#define LOG_ENABLE_DBG 0
|
||||||
#include "log.h"
|
|
||||||
#include "char32.h"
|
#include "char32.h"
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
#include "config.h"
|
#include "config.h"
|
||||||
|
|
@ -16,6 +15,7 @@
|
||||||
#include "grid.h"
|
#include "grid.h"
|
||||||
#include "input.h"
|
#include "input.h"
|
||||||
#include "key-binding.h"
|
#include "key-binding.h"
|
||||||
|
#include "log.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "quirks.h"
|
#include "quirks.h"
|
||||||
#include "render.h"
|
#include "render.h"
|
||||||
|
|
@ -40,9 +40,7 @@
|
||||||
* row, and if it is NULL, we move the viewport *backward* until the
|
* row, and if it is NULL, we move the viewport *backward* until the
|
||||||
* last row is non-NULL.
|
* last row is non-NULL.
|
||||||
*/
|
*/
|
||||||
static int
|
static int ensure_view_is_allocated(struct terminal *term, int new_view) {
|
||||||
ensure_view_is_allocated(struct terminal *term, int new_view)
|
|
||||||
{
|
|
||||||
struct grid *grid = term->grid;
|
struct grid *grid = term->grid;
|
||||||
int view_end = (new_view + term->rows - 1) & (grid->num_rows - 1);
|
int view_end = (new_view + term->rows - 1) & (grid->num_rows - 1);
|
||||||
|
|
||||||
|
|
@ -68,12 +66,11 @@ ensure_view_is_allocated(struct terminal *term, int new_view)
|
||||||
return new_view;
|
return new_view;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_ensure_size(struct terminal *term, size_t wanted_size) {
|
||||||
search_ensure_size(struct terminal *term, size_t wanted_size)
|
|
||||||
{
|
|
||||||
while (wanted_size >= term->search.sz) {
|
while (wanted_size >= term->search.sz) {
|
||||||
size_t new_sz = term->search.sz == 0 ? 64 : term->search.sz * 2;
|
size_t new_sz = term->search.sz == 0 ? 64 : term->search.sz * 2;
|
||||||
char32_t *new_buf = realloc(term->search.buf, new_sz * sizeof(term->search.buf[0]));
|
char32_t *new_buf =
|
||||||
|
realloc(term->search.buf, new_sz * sizeof(term->search.buf[0]));
|
||||||
|
|
||||||
if (new_buf == NULL) {
|
if (new_buf == NULL) {
|
||||||
LOG_ERRNO("failed to resize search buffer");
|
LOG_ERRNO("failed to resize search buffer");
|
||||||
|
|
@ -87,23 +84,21 @@ search_ensure_size(struct terminal *term, size_t wanted_size)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool has_wrapped_around_left(const struct terminal *term,
|
||||||
has_wrapped_around_left(const struct terminal *term, int abs_row_no)
|
int abs_row_no) {
|
||||||
{
|
|
||||||
int rebased_row = grid_row_abs_to_sb(term->grid, term->rows, 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;
|
return rebased_row == term->grid->num_rows - 1 ||
|
||||||
|
term->grid->rows[abs_row_no] == NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool has_wrapped_around_right(const struct terminal *term,
|
||||||
has_wrapped_around_right(const struct terminal *term, int abs_row_no)
|
int abs_row_no) {
|
||||||
{
|
|
||||||
int rebased_row = grid_row_abs_to_sb(term->grid, term->rows, abs_row_no);
|
int rebased_row = grid_row_abs_to_sb(term->grid, term->rows, abs_row_no);
|
||||||
return rebased_row == 0;
|
return rebased_row == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void search_history_push(struct terminal *term, const char32_t *buf,
|
||||||
search_history_push(struct terminal *term, const char32_t *buf, size_t len)
|
size_t len) {
|
||||||
{
|
|
||||||
if (len == 0)
|
if (len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -127,9 +122,7 @@ search_history_push(struct terminal *term, const char32_t *buf, size_t len)
|
||||||
term->search.history_tail = e;
|
term->search.history_tail = e;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void search_cancel_keep_selection(struct terminal *term) {
|
||||||
search_cancel_keep_selection(struct terminal *term)
|
|
||||||
{
|
|
||||||
struct wl_window *win = term->window;
|
struct wl_window *win = term->window;
|
||||||
wayl_win_subsurface_destroy(&win->search);
|
wayl_win_subsurface_destroy(&win->search);
|
||||||
|
|
||||||
|
|
@ -174,9 +167,7 @@ search_cancel_keep_selection(struct terminal *term)
|
||||||
render_refresh(term);
|
render_refresh(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void search_begin(struct terminal *term) {
|
||||||
search_begin(struct terminal *term)
|
|
||||||
{
|
|
||||||
LOG_DBG("search: begin");
|
LOG_DBG("search: begin");
|
||||||
|
|
||||||
search_cancel_keep_selection(term);
|
search_cancel_keep_selection(term);
|
||||||
|
|
@ -189,8 +180,8 @@ search_begin(struct terminal *term)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* On-demand instantiate wayland surface */
|
/* On-demand instantiate wayland surface */
|
||||||
bool ret = wayl_win_subsurface_new(
|
bool ret =
|
||||||
term->window, &term->window->search, false);
|
wayl_win_subsurface_new(term->window, &term->window->search, false);
|
||||||
xassert(ret);
|
xassert(ret);
|
||||||
|
|
||||||
const struct grid *grid = term->grid;
|
const struct grid *grid = term->grid;
|
||||||
|
|
@ -207,9 +198,7 @@ search_begin(struct terminal *term)
|
||||||
render_refresh_search(term);
|
render_refresh_search(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void search_cancel(struct terminal *term) {
|
||||||
search_cancel(struct terminal *term)
|
|
||||||
{
|
|
||||||
if (!term->is_searching)
|
if (!term->is_searching)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -217,17 +206,14 @@ search_cancel(struct terminal *term)
|
||||||
selection_cancel(term);
|
selection_cancel(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void search_selection_cancelled(struct terminal *term) {
|
||||||
search_selection_cancelled(struct terminal *term)
|
|
||||||
{
|
|
||||||
term->search.match = (struct coord){-1, -1};
|
term->search.match = (struct coord){-1, -1};
|
||||||
term->search.match_len = 0;
|
term->search.match_len = 0;
|
||||||
render_refresh_search(term);
|
render_refresh_search(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void search_update_selection(struct terminal *term,
|
||||||
search_update_selection(struct terminal *term, const struct range *match)
|
const struct range *match) {
|
||||||
{
|
|
||||||
struct grid *grid = term->grid;
|
struct grid *grid = term->grid;
|
||||||
int start_row = match->start.row;
|
int start_row = match->start.row;
|
||||||
int start_col = match->start.col;
|
int start_col = match->start.col;
|
||||||
|
|
@ -292,13 +278,11 @@ search_update_selection(struct terminal *term, const struct range *match)
|
||||||
start_col != term->search.match.col ||
|
start_col != term->search.match.col ||
|
||||||
|
|
||||||
/* Pointer leave events trigger selection_finalize() :/ */
|
/* Pointer leave events trigger selection_finalize() :/ */
|
||||||
!term->selection.ongoing)
|
!term->selection.ongoing) {
|
||||||
{
|
|
||||||
int selection_row = start_row - grid->view + grid->num_rows;
|
int selection_row = start_row - grid->view + grid->num_rows;
|
||||||
selection_row &= grid->num_rows - 1;
|
selection_row &= grid->num_rows - 1;
|
||||||
|
|
||||||
selection_start(
|
selection_start(term, start_col, selection_row, SELECTION_CHAR_WISE, false);
|
||||||
term, start_col, selection_row, SELECTION_CHAR_WISE, false);
|
|
||||||
|
|
||||||
term->search.match.row = start_row;
|
term->search.match.row = start_row;
|
||||||
term->search.match.col = start_col;
|
term->search.match.col = start_col;
|
||||||
|
|
@ -312,20 +296,20 @@ search_update_selection(struct terminal *term, const struct range *match)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_is_case_sensitive(const struct terminal *term) {
|
||||||
search_is_case_sensitive(const struct terminal *term)
|
|
||||||
{
|
|
||||||
switch (term->search.case_mode) {
|
switch (term->search.case_mode) {
|
||||||
case SEARCH_CASE_SENSITIVE: return true;
|
case SEARCH_CASE_SENSITIVE:
|
||||||
case SEARCH_CASE_INSENSITIVE: return false;
|
return true;
|
||||||
case SEARCH_CASE_SMART: return hasc32upper(term->search.buf);
|
case SEARCH_CASE_INSENSITIVE:
|
||||||
|
return false;
|
||||||
|
case SEARCH_CASE_SMART:
|
||||||
|
return hasc32upper(term->search.buf);
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_cell_is_word(const struct terminal *term,
|
||||||
search_cell_is_word(const struct terminal *term, const struct cell *cell)
|
const struct cell *cell) {
|
||||||
{
|
|
||||||
char32_t base = cell->wc;
|
char32_t base = cell->wc;
|
||||||
if (base >= CELL_COMB_CHARS_LO && base <= CELL_COMB_CHARS_HI) {
|
if (base >= CELL_COMB_CHARS_LO && base <= CELL_COMB_CHARS_HI) {
|
||||||
const struct composed *c =
|
const struct composed *c =
|
||||||
|
|
@ -340,10 +324,8 @@ search_cell_is_word(const struct terminal *term, const struct cell *cell)
|
||||||
/* True if the cell *immediately before* (col-1, row), wrapping back a
|
/* True if the cell *immediately before* (col-1, row), wrapping back a
|
||||||
* row if needed, is a word character. Returns false at scrollback
|
* row if needed, is a word character. Returns false at scrollback
|
||||||
* boundaries (treat boundary as non-word). */
|
* boundaries (treat boundary as non-word). */
|
||||||
static bool
|
static bool search_neighbor_is_word(const struct terminal *term, int row,
|
||||||
search_neighbor_is_word(const struct terminal *term, int row, int col,
|
int col, bool look_right) {
|
||||||
bool look_right)
|
|
||||||
{
|
|
||||||
const struct grid *grid = term->grid;
|
const struct grid *grid = term->grid;
|
||||||
int r = row, c = col;
|
int r = row, c = col;
|
||||||
|
|
||||||
|
|
@ -381,10 +363,8 @@ struct row_text {
|
||||||
int *byte_to_col;
|
int *byte_to_col;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool
|
static bool extract_row_text(const struct terminal *term, const struct row *row,
|
||||||
extract_row_text(const struct terminal *term, const struct row *row,
|
struct row_text *out) {
|
||||||
struct row_text *out)
|
|
||||||
{
|
|
||||||
out->utf8 = NULL;
|
out->utf8 = NULL;
|
||||||
out->len = 0;
|
out->len = 0;
|
||||||
out->byte_to_col = NULL;
|
out->byte_to_col = NULL;
|
||||||
|
|
@ -451,9 +431,7 @@ extract_row_text(const struct terminal *term, const struct row *row,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void free_row_text(struct row_text *rt) {
|
||||||
free_row_text(struct row_text *rt)
|
|
||||||
{
|
|
||||||
free(rt->utf8);
|
free(rt->utf8);
|
||||||
free(rt->byte_to_col);
|
free(rt->byte_to_col);
|
||||||
rt->utf8 = NULL;
|
rt->utf8 = NULL;
|
||||||
|
|
@ -461,9 +439,7 @@ free_row_text(struct row_text *rt)
|
||||||
rt->len = 0;
|
rt->len = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_compile_regex(struct terminal *term) {
|
||||||
search_compile_regex(struct terminal *term)
|
|
||||||
{
|
|
||||||
/* Free any previously compiled regex */
|
/* Free any previously compiled regex */
|
||||||
if (term->search.regex_compiled != NULL) {
|
if (term->search.regex_compiled != NULL) {
|
||||||
regfree(term->search.regex_compiled);
|
regfree(term->search.regex_compiled);
|
||||||
|
|
@ -507,10 +483,9 @@ search_compile_regex(struct terminal *term)
|
||||||
|
|
||||||
/* Find one regex match on a single row. Returns true if found and
|
/* Find one regex match on a single row. Returns true if found and
|
||||||
* fills [start_col, end_col]. */
|
* fills [start_col, end_col]. */
|
||||||
static bool
|
static bool regex_find_in_row(const struct terminal *term,
|
||||||
regex_find_in_row(const struct terminal *term, const struct row *row,
|
const struct row *row, int min_col, int max_col,
|
||||||
int min_col, int max_col, int *out_start, int *out_end)
|
int *out_start, int *out_end) {
|
||||||
{
|
|
||||||
if (!term->search.regex_valid || row == NULL)
|
if (!term->search.regex_valid || row == NULL)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
|
@ -530,7 +505,6 @@ regex_find_in_row(const struct terminal *term, const struct row *row,
|
||||||
scan_from > 0 ? REG_NOTBOL : 0) != 0)
|
scan_from > 0 ? REG_NOTBOL : 0) != 0)
|
||||||
break;
|
break;
|
||||||
if (m.rm_so == m.rm_eo) {
|
if (m.rm_so == m.rm_eo) {
|
||||||
/* Zero-width — advance one byte to avoid infinite loop */
|
|
||||||
scan_from++;
|
scan_from++;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -541,8 +515,8 @@ regex_find_in_row(const struct terminal *term, const struct row *row,
|
||||||
if (s_col >= min_col && s_col <= max_col) {
|
if (s_col >= min_col && s_col <= max_col) {
|
||||||
if (term->search.whole_word) {
|
if (term->search.whole_word) {
|
||||||
if ((s_col > 0 && search_cell_is_word(term, &row->cells[s_col - 1])) ||
|
if ((s_col > 0 && search_cell_is_word(term, &row->cells[s_col - 1])) ||
|
||||||
(e_col + 1 < term->cols && search_cell_is_word(term, &row->cells[e_col + 1])))
|
(e_col + 1 < term->cols &&
|
||||||
{
|
search_cell_is_word(term, &row->cells[e_col + 1]))) {
|
||||||
scan_from += m.rm_eo;
|
scan_from += m.rm_eo;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
@ -562,18 +536,17 @@ regex_find_in_row(const struct terminal *term, const struct row *row,
|
||||||
|
|
||||||
/* Walk rows in the requested direction, returning the first regex
|
/* Walk rows in the requested direction, returning the first regex
|
||||||
* match found within the [start, end] range. */
|
* match found within the [start, end] range. */
|
||||||
static bool
|
static bool regex_find_next(const struct terminal *term,
|
||||||
regex_find_next(const struct terminal *term, enum search_direction direction,
|
enum search_direction direction,
|
||||||
struct coord abs_start, struct coord abs_end,
|
struct coord abs_start, struct coord abs_end,
|
||||||
struct range *match)
|
struct range *match) {
|
||||||
{
|
|
||||||
const struct grid *grid = term->grid;
|
const struct grid *grid = term->grid;
|
||||||
const bool backward = direction != SEARCH_FORWARD;
|
const bool backward = direction != SEARCH_FORWARD;
|
||||||
|
|
||||||
int row_no = abs_start.row;
|
int row_no = abs_start.row;
|
||||||
int from_col = abs_start.col;
|
int from_col = abs_start.col;
|
||||||
int to_col = (row_no == abs_end.row) ? abs_end.col :
|
int to_col =
|
||||||
(backward ? 0 : term->cols - 1);
|
(row_no == abs_end.row) ? abs_end.col : (backward ? 0 : term->cols - 1);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
const struct row *row = grid->rows[row_no];
|
const struct row *row = grid->rows[row_no];
|
||||||
|
|
@ -606,16 +579,14 @@ regex_find_next(const struct terminal *term, enum search_direction direction,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t matches_cell(const struct terminal *term,
|
||||||
matches_cell(const struct terminal *term, const struct cell *cell, size_t search_ofs)
|
const struct cell *cell, size_t search_ofs) {
|
||||||
{
|
|
||||||
assert(search_ofs < term->search.len);
|
assert(search_ofs < term->search.len);
|
||||||
|
|
||||||
char32_t base = cell->wc;
|
char32_t base = cell->wc;
|
||||||
const struct composed *composed = NULL;
|
const struct composed *composed = NULL;
|
||||||
|
|
||||||
if (base >= CELL_COMB_CHARS_LO && base <= CELL_COMB_CHARS_HI)
|
if (base >= CELL_COMB_CHARS_LO && base <= CELL_COMB_CHARS_HI) {
|
||||||
{
|
|
||||||
composed = composed_lookup(term->composed, base - CELL_COMB_CHARS_LO);
|
composed = composed_lookup(term->composed, base - CELL_COMB_CHARS_LO);
|
||||||
base = composed->chars[0];
|
base = composed->chars[0];
|
||||||
}
|
}
|
||||||
|
|
@ -644,10 +615,9 @@ matches_cell(const struct terminal *term, const struct cell *cell, size_t search
|
||||||
return composed != NULL ? composed->count : 1;
|
return composed != NULL ? composed->count : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool find_next(struct terminal *term, enum search_direction direction,
|
||||||
find_next(struct terminal *term, enum search_direction direction,
|
struct coord abs_start, struct coord abs_end,
|
||||||
struct coord abs_start, struct coord abs_end, struct range *match)
|
struct range *match) {
|
||||||
{
|
|
||||||
#define ROW_DEC(_r) ((_r) = ((_r) - 1 + grid->num_rows) & (grid->num_rows - 1))
|
#define ROW_DEC(_r) ((_r) = ((_r) - 1 + grid->num_rows) & (grid->num_rows - 1))
|
||||||
#define ROW_INC(_r) ((_r) = ((_r) + 1) & (grid->num_rows - 1))
|
#define ROW_INC(_r) ((_r) = ((_r) + 1) & (grid->num_rows - 1))
|
||||||
|
|
||||||
|
|
@ -670,8 +640,7 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
xassert(abs_end.col >= 0);
|
xassert(abs_end.col >= 0);
|
||||||
xassert(abs_end.col < term->cols);
|
xassert(abs_end.col < term->cols);
|
||||||
|
|
||||||
for (int match_start_row = abs_start.row, match_start_col = abs_start.col;
|
for (int match_start_row = abs_start.row, match_start_col = abs_start.col;;
|
||||||
;
|
|
||||||
backward ? ROW_DEC(match_start_row) : ROW_INC(match_start_row)) {
|
backward ? ROW_DEC(match_start_row) : ROW_INC(match_start_row)) {
|
||||||
|
|
||||||
const struct row *row = grid->rows[match_start_row];
|
const struct row *row = grid->rows[match_start_row];
|
||||||
|
|
@ -681,14 +650,10 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (;
|
for (; backward ? match_start_col >= 0 : match_start_col < term->cols;
|
||||||
backward ? match_start_col >= 0 : match_start_col < term->cols;
|
backward ? match_start_col-- : match_start_col++) {
|
||||||
backward ? match_start_col-- : match_start_col++)
|
|
||||||
{
|
|
||||||
if (matches_cell(term, &row->cells[match_start_col], 0) < 0) {
|
if (matches_cell(term, &row->cells[match_start_col], 0) < 0) {
|
||||||
if (match_start_row == abs_end.row &&
|
if (match_start_row == abs_end.row && match_start_col == abs_end.col) {
|
||||||
match_start_col == abs_end.col)
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -699,8 +664,8 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
* rest of the search buffer matches.
|
* rest of the search buffer matches.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
LOG_DBG("search: initial match at row=%d, col=%d",
|
LOG_DBG("search: initial match at row=%d, col=%d", match_start_row,
|
||||||
match_start_row, match_start_col);
|
match_start_col);
|
||||||
|
|
||||||
int match_end_row = match_start_row;
|
int match_end_row = match_start_row;
|
||||||
int match_end_col = match_start_col;
|
int match_end_col = match_start_col;
|
||||||
|
|
@ -722,8 +687,8 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
ssize_t additional_chars = matches_cell(
|
ssize_t additional_chars =
|
||||||
term, &match_row->cells[match_end_col], i);
|
matches_cell(term, &match_row->cells[match_end_col], i);
|
||||||
if (additional_chars < 0)
|
if (additional_chars < 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
|
@ -732,8 +697,7 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
match_end_col++;
|
match_end_col++;
|
||||||
|
|
||||||
while (match_end_col < term->cols &&
|
while (match_end_col < term->cols &&
|
||||||
match_row->cells[match_end_col].wc > CELL_SPACER)
|
match_row->cells[match_end_col].wc > CELL_SPACER) {
|
||||||
{
|
|
||||||
match_end_col++;
|
match_end_col++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -741,9 +705,7 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
if (match_len != term->search.len) {
|
if (match_len != term->search.len) {
|
||||||
/* Didn't match (completely) */
|
/* Didn't match (completely) */
|
||||||
|
|
||||||
if (match_start_row == abs_end.row &&
|
if (match_start_row == abs_end.row && match_start_col == abs_end.col) {
|
||||||
match_start_col == abs_end.col)
|
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -752,14 +714,12 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
|
|
||||||
if (term->search.whole_word) {
|
if (term->search.whole_word) {
|
||||||
/* Reject if neighbour cells are word-chars */
|
/* Reject if neighbour cells are word-chars */
|
||||||
if (search_neighbor_is_word(
|
if (search_neighbor_is_word(term, match_start_row, match_start_col,
|
||||||
term, match_start_row, match_start_col, false) ||
|
false) ||
|
||||||
search_neighbor_is_word(
|
search_neighbor_is_word(term, match_end_row, match_end_col - 1,
|
||||||
term, match_end_row, match_end_col - 1, true))
|
true)) {
|
||||||
{
|
|
||||||
if (match_start_row == abs_end.row &&
|
if (match_start_row == abs_end.row &&
|
||||||
match_start_col == abs_end.col)
|
match_start_col == abs_end.col) {
|
||||||
{
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -785,9 +745,7 @@ find_next(struct terminal *term, enum search_direction direction,
|
||||||
|
|
||||||
/* Count total matches across the whole grid, capped at
|
/* Count total matches across the whole grid, capped at
|
||||||
* SEARCH_COUNT_CAP. Returns the cap if we hit it. */
|
* SEARCH_COUNT_CAP. Returns the cap if we hit it. */
|
||||||
static size_t
|
static size_t search_count_all(struct terminal *term) {
|
||||||
search_count_all(struct terminal *term)
|
|
||||||
{
|
|
||||||
if (term->search.len == 0)
|
if (term->search.len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (term->search.regex && !term->search.regex_valid)
|
if (term->search.regex && !term->search.regex_valid)
|
||||||
|
|
@ -798,8 +756,8 @@ search_count_all(struct terminal *term)
|
||||||
/* Start at the very top of the scrollback (oldest row) */
|
/* Start at the very top of the scrollback (oldest row) */
|
||||||
int oldest = (grid->offset + term->rows) & (grid->num_rows - 1);
|
int oldest = (grid->offset + term->rows) & (grid->num_rows - 1);
|
||||||
|
|
||||||
struct coord pos = { 0, oldest };
|
struct coord pos = {0, oldest};
|
||||||
struct coord end = { term->cols - 1, oldest };
|
struct coord end = {term->cols - 1, oldest};
|
||||||
/* end.row should be the row *before* oldest, i.e. the newest */
|
/* end.row should be the row *before* oldest, i.e. the newest */
|
||||||
end.row = (oldest - 1 + grid->num_rows) & (grid->num_rows - 1);
|
end.row = (oldest - 1 + grid->num_rows) & (grid->num_rows - 1);
|
||||||
|
|
||||||
|
|
@ -829,9 +787,7 @@ search_count_all(struct terminal *term)
|
||||||
|
|
||||||
/* Recompute current_idx by counting matches from the top of the
|
/* Recompute current_idx by counting matches from the top of the
|
||||||
* scrollback up to (and including) the current match position. */
|
* scrollback up to (and including) the current match position. */
|
||||||
static size_t
|
static size_t search_compute_current_idx(struct terminal *term) {
|
||||||
search_compute_current_idx(struct terminal *term)
|
|
||||||
{
|
|
||||||
if (term->search.match_len == 0 || term->search.len == 0)
|
if (term->search.match_len == 0 || term->search.len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
if (term->search.regex && !term->search.regex_valid)
|
if (term->search.regex && !term->search.regex_valid)
|
||||||
|
|
@ -841,10 +797,10 @@ search_compute_current_idx(struct terminal *term)
|
||||||
int oldest = (grid->offset + term->rows) & (grid->num_rows - 1);
|
int oldest = (grid->offset + term->rows) & (grid->num_rows - 1);
|
||||||
|
|
||||||
/* Sentinel "newest cell" - we'll abort when we pass our own match */
|
/* Sentinel "newest cell" - we'll abort when we pass our own match */
|
||||||
struct coord newest = { term->cols - 1,
|
struct coord newest = {term->cols - 1,
|
||||||
(oldest - 1 + grid->num_rows) & (grid->num_rows - 1) };
|
(oldest - 1 + grid->num_rows) & (grid->num_rows - 1)};
|
||||||
|
|
||||||
struct coord pos = { 0, oldest };
|
struct coord pos = {0, oldest};
|
||||||
|
|
||||||
size_t idx = 0;
|
size_t idx = 0;
|
||||||
while (idx < SEARCH_COUNT_CAP) {
|
while (idx < SEARCH_COUNT_CAP) {
|
||||||
|
|
@ -870,9 +826,8 @@ search_compute_current_idx(struct terminal *term)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void search_find_next(struct terminal *term,
|
||||||
search_find_next(struct terminal *term, enum search_direction direction)
|
enum search_direction direction) {
|
||||||
{
|
|
||||||
struct grid *grid = term->grid;
|
struct grid *grid = term->grid;
|
||||||
|
|
||||||
/* Recompile regex if active (cheap when len==0; no-op otherwise) */
|
/* Recompile regex if active (cheap when len==0; no-op otherwise) */
|
||||||
|
|
@ -941,12 +896,10 @@ search_find_next(struct terminal *term, enum search_direction direction)
|
||||||
xassert(start.col < term->cols);
|
xassert(start.col < term->cols);
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_DBG(
|
LOG_DBG("update: %s: starting at row=%d col=%d "
|
||||||
"update: %s: starting at row=%d col=%d "
|
|
||||||
"(offset = %d, view = %d)",
|
"(offset = %d, view = %d)",
|
||||||
direction != SEARCH_FORWARD ? "backward" : "forward",
|
direction != SEARCH_FORWARD ? "backward" : "forward", start.row,
|
||||||
start.row, start.col,
|
start.col, grid->offset, grid->view);
|
||||||
grid->offset, grid->view);
|
|
||||||
|
|
||||||
struct coord end = start;
|
struct coord end = start;
|
||||||
switch (direction) {
|
switch (direction) {
|
||||||
|
|
@ -980,29 +933,24 @@ search_find_next(struct terminal *term, enum search_direction direction)
|
||||||
term->search.wrapped = false;
|
term->search.wrapped = false;
|
||||||
|
|
||||||
if (found) {
|
if (found) {
|
||||||
LOG_DBG("primary match found at %dx%d",
|
LOG_DBG("primary match found at %dx%d", match.start.row, match.start.col);
|
||||||
match.start.row, match.start.col);
|
|
||||||
|
|
||||||
/* Detect wrap: if we had a prior match and the new match is in
|
/* Detect wrap: if we had a prior match and the new match is in
|
||||||
* the "wrong" direction relative to it, we wrapped. */
|
* the "wrong" direction relative to it, we wrapped. */
|
||||||
if (prev_match_len > 0 &&
|
if (prev_match_len > 0 && direction != SEARCH_BACKWARD_SAME_POSITION) {
|
||||||
direction != SEARCH_BACKWARD_SAME_POSITION)
|
|
||||||
{
|
|
||||||
int oldest = (grid->offset + term->rows) & (grid->num_rows - 1);
|
int oldest = (grid->offset + term->rows) & (grid->num_rows - 1);
|
||||||
int prev_rebased = (prev_match.row - oldest + grid->num_rows)
|
int prev_rebased =
|
||||||
& (grid->num_rows - 1);
|
(prev_match.row - oldest + grid->num_rows) & (grid->num_rows - 1);
|
||||||
int new_rebased = (match.start.row - oldest + grid->num_rows)
|
int new_rebased =
|
||||||
& (grid->num_rows - 1);
|
(match.start.row - oldest + grid->num_rows) & (grid->num_rows - 1);
|
||||||
|
|
||||||
if (direction == SEARCH_FORWARD) {
|
if (direction == SEARCH_FORWARD) {
|
||||||
if (new_rebased < prev_rebased ||
|
if (new_rebased < prev_rebased ||
|
||||||
(new_rebased == prev_rebased &&
|
(new_rebased == prev_rebased && match.start.col <= prev_match.col))
|
||||||
match.start.col <= prev_match.col))
|
|
||||||
term->search.wrapped = true;
|
term->search.wrapped = true;
|
||||||
} else {
|
} else {
|
||||||
if (new_rebased > prev_rebased ||
|
if (new_rebased > prev_rebased ||
|
||||||
(new_rebased == prev_rebased &&
|
(new_rebased == prev_rebased && match.start.col >= prev_match.col))
|
||||||
match.start.col >= prev_match.col))
|
|
||||||
term->search.wrapped = true;
|
term->search.wrapped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1023,18 +971,14 @@ search_find_next(struct terminal *term, enum search_direction direction)
|
||||||
#undef ROW_DEC
|
#undef ROW_DEC
|
||||||
}
|
}
|
||||||
|
|
||||||
struct search_match_iterator
|
struct search_match_iterator search_matches_new_iter(struct terminal *term) {
|
||||||
search_matches_new_iter(struct terminal *term)
|
|
||||||
{
|
|
||||||
return (struct search_match_iterator){
|
return (struct search_match_iterator){
|
||||||
.term = term,
|
.term = term,
|
||||||
.start = {0, 0},
|
.start = {0, 0},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
struct range
|
struct range search_matches_next(struct search_match_iterator *iter) {
|
||||||
search_matches_next(struct search_match_iterator *iter)
|
|
||||||
{
|
|
||||||
struct terminal *term = iter->term;
|
struct terminal *term = iter->term;
|
||||||
struct grid *grid = term->grid;
|
struct grid *grid = term->grid;
|
||||||
|
|
||||||
|
|
@ -1052,19 +996,18 @@ search_matches_next(struct search_match_iterator *iter)
|
||||||
struct coord abs_start = iter->start;
|
struct coord abs_start = iter->start;
|
||||||
abs_start.row = grid_row_absolute_in_view(grid, abs_start.row);
|
abs_start.row = grid_row_absolute_in_view(grid, abs_start.row);
|
||||||
|
|
||||||
struct coord abs_end = {
|
struct coord abs_end = {term->cols - 1,
|
||||||
term->cols - 1,
|
|
||||||
grid_row_absolute_in_view(grid, term->rows - 1)};
|
grid_row_absolute_in_view(grid, term->rows - 1)};
|
||||||
|
|
||||||
/* BUG: matches *starting* outside the view, but ending *inside*, aren't matched */
|
/* BUG: matches *starting* outside the view, but ending *inside*, aren't
|
||||||
|
* matched */
|
||||||
struct range match;
|
struct range match;
|
||||||
bool found = find_next(term, SEARCH_FORWARD, abs_start, abs_end, &match);
|
bool found = find_next(term, SEARCH_FORWARD, abs_start, abs_end, &match);
|
||||||
if (!found)
|
if (!found)
|
||||||
goto no_match;
|
goto no_match;
|
||||||
|
|
||||||
LOG_DBG("match at (absolute coordinates) %dx%d-%dx%d",
|
LOG_DBG("match at (absolute coordinates) %dx%d-%dx%d", match.start.row,
|
||||||
match.start.row, match.start.col,
|
match.start.col, match.end.row, match.end.col);
|
||||||
match.end.row, match.end.col);
|
|
||||||
|
|
||||||
/* Convert absolute row numbers back to view relative */
|
/* Convert absolute row numbers back to view relative */
|
||||||
match.start.row = match.start.row - grid->view + grid->num_rows;
|
match.start.row = match.start.row - grid->view + grid->num_rows;
|
||||||
|
|
@ -1073,13 +1016,13 @@ search_matches_next(struct search_match_iterator *iter)
|
||||||
match.end.row &= grid->num_rows - 1;
|
match.end.row &= grid->num_rows - 1;
|
||||||
|
|
||||||
LOG_DBG("match at (view-local coordinates) %dx%d-%dx%d, view=%d",
|
LOG_DBG("match at (view-local coordinates) %dx%d-%dx%d, view=%d",
|
||||||
match.start.row, match.start.col,
|
match.start.row, match.start.col, match.end.row, match.end.col,
|
||||||
match.end.row, match.end.col, grid->view);
|
grid->view);
|
||||||
|
|
||||||
/* Assert match end comes *after* the match start */
|
/* Assert match end comes *after* the match start */
|
||||||
xassert(match.end.row > match.start.row ||
|
xassert(
|
||||||
(match.end.row == match.start.row &&
|
match.end.row > match.start.row ||
|
||||||
match.end.col >= match.start.col));
|
(match.end.row == match.start.row && match.end.col >= match.start.col));
|
||||||
|
|
||||||
/* Assert the match starts at, or after, the iterator position */
|
/* Assert the match starts at, or after, the iterator position */
|
||||||
xassert(match.start.row > iter->start.row ||
|
xassert(match.start.row > iter->start.row ||
|
||||||
|
|
@ -1107,9 +1050,7 @@ no_match:
|
||||||
return (struct range){{-1, -1}, {-1, -1}};
|
return (struct range){{-1, -1}, {-1, -1}};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void add_wchars(struct terminal *term, char32_t *src, size_t count) {
|
||||||
add_wchars(struct terminal *term, char32_t *src, size_t count)
|
|
||||||
{
|
|
||||||
/* Strip non-printable characters */
|
/* Strip non-printable characters */
|
||||||
for (size_t i = 0, j = 0, orig_count = count; i < orig_count; i++) {
|
for (size_t i = 0, j = 0, orig_count = count; i < orig_count; i++) {
|
||||||
if (isc32print(src[i]))
|
if (isc32print(src[i]))
|
||||||
|
|
@ -1134,9 +1075,7 @@ add_wchars(struct terminal *term, char32_t *src, size_t count)
|
||||||
term->search.buf[term->search.len] = U'\0';
|
term->search.buf[term->search.len] = U'\0';
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void search_add_chars(struct terminal *term, const char *src, size_t count) {
|
||||||
search_add_chars(struct terminal *term, const char *src, size_t count)
|
|
||||||
{
|
|
||||||
size_t chars = mbsntoc32(NULL, src, count, 0);
|
size_t chars = mbsntoc32(NULL, src, count, 0);
|
||||||
if (chars == (size_t)-1) {
|
if (chars == (size_t)-1) {
|
||||||
LOG_ERRNO("failed to convert %.*s to Unicode", (int)count, src);
|
LOG_ERRNO("failed to convert %.*s to Unicode", (int)count, src);
|
||||||
|
|
@ -1148,12 +1087,10 @@ search_add_chars(struct terminal *term, const char *src, size_t count)
|
||||||
add_wchars(term, c32s, chars);
|
add_wchars(term, c32s, chars);
|
||||||
}
|
}
|
||||||
|
|
||||||
enum extend_direction {SEARCH_EXTEND_LEFT, SEARCH_EXTEND_RIGHT};
|
enum extend_direction { SEARCH_EXTEND_LEFT, SEARCH_EXTEND_RIGHT };
|
||||||
|
|
||||||
static bool
|
static bool coord_advance_left(const struct terminal *term, struct coord *pos,
|
||||||
coord_advance_left(const struct terminal *term, struct coord *pos,
|
const struct row **row) {
|
||||||
const struct row **row)
|
|
||||||
{
|
|
||||||
const struct grid *grid = term->grid;
|
const struct grid *grid = term->grid;
|
||||||
struct coord new_pos = *pos;
|
struct coord new_pos = *pos;
|
||||||
|
|
||||||
|
|
@ -1172,10 +1109,8 @@ coord_advance_left(const struct terminal *term, struct coord *pos,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool coord_advance_right(const struct terminal *term, struct coord *pos,
|
||||||
coord_advance_right(const struct terminal *term, struct coord *pos,
|
const struct row **row) {
|
||||||
const struct row **row)
|
|
||||||
{
|
|
||||||
const struct grid *grid = term->grid;
|
const struct grid *grid = term->grid;
|
||||||
struct coord new_pos = *pos;
|
struct coord new_pos = *pos;
|
||||||
|
|
||||||
|
|
@ -1194,15 +1129,14 @@ coord_advance_right(const struct terminal *term, struct coord *pos,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_char(const struct terminal *term,
|
||||||
search_extend_find_char(const struct terminal *term, struct coord *target,
|
struct coord *target,
|
||||||
enum extend_direction direction)
|
enum extend_direction direction) {
|
||||||
{
|
|
||||||
if (term->search.match_len == 0)
|
if (term->search.match_len == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct coord pos = direction == SEARCH_EXTEND_LEFT
|
struct coord pos = direction == SEARCH_EXTEND_LEFT ? selection_get_start(term)
|
||||||
? selection_get_start(term) : selection_get_end(term);
|
: selection_get_end(term);
|
||||||
xassert(pos.row >= 0);
|
xassert(pos.row >= 0);
|
||||||
xassert(pos.row < term->grid->num_rows);
|
xassert(pos.row < term->grid->num_rows);
|
||||||
|
|
||||||
|
|
@ -1233,28 +1167,24 @@ search_extend_find_char(const struct terminal *term, struct coord *target,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_char_left(const struct terminal *term,
|
||||||
search_extend_find_char_left(const struct terminal *term, struct coord *target)
|
struct coord *target) {
|
||||||
{
|
|
||||||
return search_extend_find_char(term, target, SEARCH_EXTEND_LEFT);
|
return search_extend_find_char(term, target, SEARCH_EXTEND_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_char_right(const struct terminal *term,
|
||||||
search_extend_find_char_right(const struct terminal *term, struct coord *target)
|
struct coord *target) {
|
||||||
{
|
|
||||||
return search_extend_find_char(term, target, SEARCH_EXTEND_RIGHT);
|
return search_extend_find_char(term, target, SEARCH_EXTEND_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_word(const struct terminal *term,
|
||||||
search_extend_find_word(const struct terminal *term, bool spaces_only,
|
bool spaces_only, struct coord *target,
|
||||||
struct coord *target, enum extend_direction direction)
|
enum extend_direction direction) {
|
||||||
{
|
|
||||||
if (term->search.match_len == 0)
|
if (term->search.match_len == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct grid *grid = term->grid;
|
struct grid *grid = term->grid;
|
||||||
struct coord pos = direction == SEARCH_EXTEND_LEFT
|
struct coord pos = direction == SEARCH_EXTEND_LEFT ? selection_get_start(term)
|
||||||
? selection_get_start(term)
|
|
||||||
: selection_get_end(term);
|
: selection_get_end(term);
|
||||||
|
|
||||||
xassert(pos.row >= 0);
|
xassert(pos.row >= 0);
|
||||||
|
|
@ -1294,29 +1224,27 @@ search_extend_find_word(const struct terminal *term, bool spaces_only,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_word_left(const struct terminal *term,
|
||||||
search_extend_find_word_left(const struct terminal *term, bool spaces_only,
|
bool spaces_only,
|
||||||
struct coord *target)
|
struct coord *target) {
|
||||||
{
|
|
||||||
return search_extend_find_word(term, spaces_only, target, SEARCH_EXTEND_LEFT);
|
return search_extend_find_word(term, spaces_only, target, SEARCH_EXTEND_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_word_right(const struct terminal *term,
|
||||||
search_extend_find_word_right(const struct terminal *term, bool spaces_only,
|
bool spaces_only,
|
||||||
struct coord *target)
|
struct coord *target) {
|
||||||
{
|
return search_extend_find_word(term, spaces_only, target,
|
||||||
return search_extend_find_word(term, spaces_only, target, SEARCH_EXTEND_RIGHT);
|
SEARCH_EXTEND_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_line(const struct terminal *term,
|
||||||
search_extend_find_line(const struct terminal *term, struct coord *target,
|
struct coord *target,
|
||||||
enum extend_direction direction)
|
enum extend_direction direction) {
|
||||||
{
|
|
||||||
if (term->search.match_len == 0)
|
if (term->search.match_len == 0)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
struct coord pos = direction == SEARCH_EXTEND_LEFT
|
struct coord pos = direction == SEARCH_EXTEND_LEFT ? selection_get_start(term)
|
||||||
? selection_get_start(term) : selection_get_end(term);
|
: selection_get_end(term);
|
||||||
|
|
||||||
xassert(pos.row >= 0);
|
xassert(pos.row >= 0);
|
||||||
xassert(pos.row < term->grid->num_rows);
|
xassert(pos.row < term->grid->num_rows);
|
||||||
|
|
@ -1343,21 +1271,18 @@ search_extend_find_line(const struct terminal *term, struct coord *target,
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_line_up(const struct terminal *term,
|
||||||
search_extend_find_line_up(const struct terminal *term, struct coord *target)
|
struct coord *target) {
|
||||||
{
|
|
||||||
return search_extend_find_line(term, target, SEARCH_EXTEND_LEFT);
|
return search_extend_find_line(term, target, SEARCH_EXTEND_LEFT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool search_extend_find_line_down(const struct terminal *term,
|
||||||
search_extend_find_line_down(const struct terminal *term, struct coord *target)
|
struct coord *target) {
|
||||||
{
|
|
||||||
return search_extend_find_line(term, target, SEARCH_EXTEND_RIGHT);
|
return search_extend_find_line(term, target, SEARCH_EXTEND_RIGHT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void search_extend_left(struct terminal *term,
|
||||||
search_extend_left(struct terminal *term, const struct coord *target)
|
const struct coord *target) {
|
||||||
{
|
|
||||||
if (term->search.match_len == 0)
|
if (term->search.match_len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1403,8 +1328,7 @@ search_extend_left(struct terminal *term, const struct coord *target)
|
||||||
|
|
||||||
xassert(actually_copied <= new_len);
|
xassert(actually_copied <= new_len);
|
||||||
if (actually_copied < new_len) {
|
if (actually_copied < new_len) {
|
||||||
memmove(
|
memmove(&term->search.buf[actually_copied], &term->search.buf[new_len],
|
||||||
&term->search.buf[actually_copied], &term->search.buf[new_len],
|
|
||||||
(term->search.len - actually_copied) * sizeof(term->search.buf[0]));
|
(term->search.len - actually_copied) * sizeof(term->search.buf[0]));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1420,9 +1344,8 @@ search_extend_left(struct terminal *term, const struct coord *target)
|
||||||
term->search.match_len = term->search.len;
|
term->search.match_len = term->search.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void search_extend_right(struct terminal *term,
|
||||||
search_extend_right(struct terminal *term, const struct coord *target)
|
const struct coord *target) {
|
||||||
{
|
|
||||||
if (term->search.match_len == 0)
|
if (term->search.match_len == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
|
@ -1471,9 +1394,7 @@ search_extend_right(struct terminal *term, const struct coord *target)
|
||||||
term->search.match_len = term->search.len;
|
term->search.match_len = term->search.len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t distance_next_word(const struct terminal *term) {
|
||||||
distance_next_word(const struct terminal *term)
|
|
||||||
{
|
|
||||||
size_t cursor = term->search.cursor;
|
size_t cursor = term->search.cursor;
|
||||||
|
|
||||||
/* First eat non-whitespace. This is the word we're skipping past */
|
/* First eat non-whitespace. This is the word we're skipping past */
|
||||||
|
|
@ -1482,7 +1403,8 @@ distance_next_word(const struct terminal *term)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
xassert(cursor == term->search.len || isc32space(term->search.buf[cursor - 1]));
|
xassert(cursor == term->search.len ||
|
||||||
|
isc32space(term->search.buf[cursor - 1]));
|
||||||
|
|
||||||
/* Now skip past whitespace, so that we end up at the beginning of
|
/* Now skip past whitespace, so that we end up at the beginning of
|
||||||
* the next word */
|
* the next word */
|
||||||
|
|
@ -1491,7 +1413,8 @@ distance_next_word(const struct terminal *term)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
xassert(cursor == term->search.len || !isc32space(term->search.buf[cursor - 1]));
|
xassert(cursor == term->search.len ||
|
||||||
|
!isc32space(term->search.buf[cursor - 1]));
|
||||||
|
|
||||||
if (cursor < term->search.len && !isc32space(term->search.buf[cursor]))
|
if (cursor < term->search.len && !isc32space(term->search.buf[cursor]))
|
||||||
cursor--;
|
cursor--;
|
||||||
|
|
@ -1499,9 +1422,7 @@ distance_next_word(const struct terminal *term)
|
||||||
return cursor - term->search.cursor;
|
return cursor - term->search.cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
static size_t
|
static size_t distance_prev_word(const struct terminal *term) {
|
||||||
distance_prev_word(const struct terminal *term)
|
|
||||||
{
|
|
||||||
int cursor = term->search.cursor;
|
int cursor = term->search.cursor;
|
||||||
|
|
||||||
/* First, eat whitespace prefix */
|
/* First, eat whitespace prefix */
|
||||||
|
|
@ -1525,16 +1446,12 @@ distance_prev_word(const struct terminal *term)
|
||||||
return term->search.cursor - cursor;
|
return term->search.cursor - cursor;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void from_clipboard_cb(char *text, size_t size, void *user) {
|
||||||
from_clipboard_cb(char *text, size_t size, void *user)
|
|
||||||
{
|
|
||||||
struct terminal *term = user;
|
struct terminal *term = user;
|
||||||
search_add_chars(term, text, size);
|
search_add_chars(term, text, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void from_clipboard_done(void *user) {
|
||||||
from_clipboard_done(void *user)
|
|
||||||
{
|
|
||||||
struct terminal *term = user;
|
struct terminal *term = user;
|
||||||
|
|
||||||
LOG_DBG("search: buffer: %ls", (const wchar_t *)term->search.buf);
|
LOG_DBG("search: buffer: %ls", (const wchar_t *)term->search.buf);
|
||||||
|
|
@ -1542,12 +1459,10 @@ from_clipboard_done(void *user)
|
||||||
render_refresh_search(term);
|
render_refresh_search(term);
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool execute_binding(struct seat *seat, struct terminal *term,
|
||||||
execute_binding(struct seat *seat, struct terminal *term,
|
|
||||||
const struct key_binding *binding, uint32_t serial,
|
const struct key_binding *binding, uint32_t serial,
|
||||||
bool *update_search_result, enum search_direction *direction,
|
bool *update_search_result,
|
||||||
bool *redraw)
|
enum search_direction *direction, bool *redraw) {
|
||||||
{
|
|
||||||
*update_search_result = *redraw = false;
|
*update_search_result = *redraw = false;
|
||||||
const enum bind_action_search action = binding->action;
|
const enum bind_action_search action = binding->action;
|
||||||
|
|
||||||
|
|
@ -1617,8 +1532,7 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
if (term->search.view_followed_offset)
|
if (term->search.view_followed_offset)
|
||||||
grid->view = grid->offset;
|
grid->view = grid->offset;
|
||||||
else {
|
else {
|
||||||
grid->view = ensure_view_is_allocated(
|
grid->view = ensure_view_is_allocated(term, term->search.original_view);
|
||||||
term, term->search.original_view);
|
|
||||||
}
|
}
|
||||||
term_damage_view(term);
|
term_damage_view(term);
|
||||||
search_cancel(term);
|
search_cancel(term);
|
||||||
|
|
@ -1705,8 +1619,7 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_DELETE_PREV:
|
case BIND_ACTION_SEARCH_DELETE_PREV:
|
||||||
if (term->search.cursor > 0) {
|
if (term->search.cursor > 0) {
|
||||||
memmove(
|
memmove(&term->search.buf[term->search.cursor - 1],
|
||||||
&term->search.buf[term->search.cursor - 1],
|
|
||||||
&term->search.buf[term->search.cursor],
|
&term->search.buf[term->search.cursor],
|
||||||
(term->search.len - term->search.cursor) * sizeof(char32_t));
|
(term->search.len - term->search.cursor) * sizeof(char32_t));
|
||||||
term->search.cursor--;
|
term->search.cursor--;
|
||||||
|
|
@ -1721,8 +1634,7 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
size_t new_cursor = old_cursor - diff;
|
size_t new_cursor = old_cursor - diff;
|
||||||
|
|
||||||
if (diff > 0) {
|
if (diff > 0) {
|
||||||
memmove(&term->search.buf[new_cursor],
|
memmove(&term->search.buf[new_cursor], &term->search.buf[old_cursor],
|
||||||
&term->search.buf[old_cursor],
|
|
||||||
(term->search.len - old_cursor) * sizeof(char32_t));
|
(term->search.len - old_cursor) * sizeof(char32_t));
|
||||||
|
|
||||||
term->search.len -= diff;
|
term->search.len -= diff;
|
||||||
|
|
@ -1734,8 +1646,7 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_DELETE_NEXT:
|
case BIND_ACTION_SEARCH_DELETE_NEXT:
|
||||||
if (term->search.cursor < term->search.len) {
|
if (term->search.cursor < term->search.len) {
|
||||||
memmove(
|
memmove(&term->search.buf[term->search.cursor],
|
||||||
&term->search.buf[term->search.cursor],
|
|
||||||
&term->search.buf[term->search.cursor + 1],
|
&term->search.buf[term->search.cursor + 1],
|
||||||
(term->search.len - term->search.cursor - 1) * sizeof(char32_t));
|
(term->search.len - term->search.cursor - 1) * sizeof(char32_t));
|
||||||
term->search.buf[--term->search.len] = U'\0';
|
term->search.buf[--term->search.len] = U'\0';
|
||||||
|
|
@ -1748,8 +1659,7 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
size_t cursor = term->search.cursor;
|
size_t cursor = term->search.cursor;
|
||||||
|
|
||||||
if (diff > 0) {
|
if (diff > 0) {
|
||||||
memmove(&term->search.buf[cursor],
|
memmove(&term->search.buf[cursor], &term->search.buf[cursor + diff],
|
||||||
&term->search.buf[cursor + diff],
|
|
||||||
(term->search.len - (cursor + diff)) * sizeof(char32_t));
|
(term->search.len - (cursor + diff)) * sizeof(char32_t));
|
||||||
|
|
||||||
term->search.len -= diff;
|
term->search.len -= diff;
|
||||||
|
|
@ -1760,10 +1670,8 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_DELETE_TO_START: {
|
case BIND_ACTION_SEARCH_DELETE_TO_START: {
|
||||||
if (term->search.cursor > 0) {
|
if (term->search.cursor > 0) {
|
||||||
memmove(&term->search.buf[0],
|
memmove(&term->search.buf[0], &term->search.buf[term->search.cursor],
|
||||||
&term->search.buf[term->search.cursor],
|
(term->search.len - term->search.cursor) * sizeof(char32_t));
|
||||||
(term->search.len - term->search.cursor)
|
|
||||||
* sizeof(char32_t));
|
|
||||||
|
|
||||||
term->search.len -= term->search.cursor;
|
term->search.len -= term->search.cursor;
|
||||||
term->search.cursor = 0;
|
term->search.cursor = 0;
|
||||||
|
|
@ -1862,14 +1770,14 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
}
|
}
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_CLIPBOARD_PASTE:
|
case BIND_ACTION_SEARCH_CLIPBOARD_PASTE:
|
||||||
text_from_clipboard(
|
text_from_clipboard(seat, term, false, &from_clipboard_cb,
|
||||||
seat, term, false, &from_clipboard_cb, &from_clipboard_done, term);
|
&from_clipboard_done, term);
|
||||||
*update_search_result = *redraw = true;
|
*update_search_result = *redraw = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_PRIMARY_PASTE:
|
case BIND_ACTION_SEARCH_PRIMARY_PASTE:
|
||||||
text_from_primary(
|
text_from_primary(seat, term, false, &from_clipboard_cb,
|
||||||
seat, term, false, &from_clipboard_cb, &from_clipboard_done, term);
|
&from_clipboard_done, term);
|
||||||
*update_search_result = *redraw = true;
|
*update_search_result = *redraw = true;
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
|
@ -1932,7 +1840,6 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
|
|
||||||
case BIND_ACTION_SEARCH_COMMIT_LINE: {
|
case BIND_ACTION_SEARCH_COMMIT_LINE: {
|
||||||
if (term->search.match_len == 0) {
|
if (term->search.match_len == 0) {
|
||||||
/* No match — fall back to plain commit */
|
|
||||||
selection_finalize(seat, term, serial);
|
selection_finalize(seat, term, serial);
|
||||||
search_cancel_keep_selection(term);
|
search_cancel_keep_selection(term);
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -1966,17 +1873,16 @@ execute_binding(struct seat *seat, struct terminal *term,
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void search_input(struct seat *seat, struct terminal *term,
|
||||||
search_input(struct seat *seat, struct terminal *term,
|
|
||||||
const struct key_binding_set *bindings, uint32_t key,
|
const struct key_binding_set *bindings, uint32_t key,
|
||||||
xkb_keysym_t sym, xkb_mod_mask_t mods, xkb_mod_mask_t consumed,
|
xkb_keysym_t sym, xkb_mod_mask_t mods,
|
||||||
const xkb_keysym_t *raw_syms, size_t raw_count,
|
xkb_mod_mask_t consumed, const xkb_keysym_t *raw_syms,
|
||||||
uint32_t serial)
|
size_t raw_count, uint32_t serial) {
|
||||||
{
|
LOG_DBG("search: input: sym=%d/0x%x, mods=0x%08x, consumed=0x%08x", sym, sym,
|
||||||
LOG_DBG("search: input: sym=%d/0x%x, mods=0x%08x, consumed=0x%08x",
|
mods, consumed);
|
||||||
sym, sym, mods, consumed);
|
|
||||||
|
|
||||||
enum xkb_compose_status compose_status = seat->kbd.xkb_compose_state != NULL
|
enum xkb_compose_status compose_status =
|
||||||
|
seat->kbd.xkb_compose_state != NULL
|
||||||
? xkb_compose_state_get_status(seat->kbd.xkb_compose_state)
|
? xkb_compose_state_get_status(seat->kbd.xkb_compose_state)
|
||||||
: XKB_COMPOSE_NOTHING;
|
: XKB_COMPOSE_NOTHING;
|
||||||
|
|
||||||
|
|
@ -1997,10 +1903,8 @@ search_input(struct seat *seat, struct terminal *term,
|
||||||
|
|
||||||
for (size_t i = 0; i < raw_count; i++) {
|
for (size_t i = 0; i < raw_count; i++) {
|
||||||
if (bind->k.sym == raw_syms[i]) {
|
if (bind->k.sym == raw_syms[i]) {
|
||||||
if (execute_binding(seat, term, bind, serial,
|
if (execute_binding(seat, term, bind, serial, &update_search_result,
|
||||||
&update_search_result, &search_direction,
|
&search_direction, &redraw)) {
|
||||||
&redraw))
|
|
||||||
{
|
|
||||||
goto update_search;
|
goto update_search;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -2012,13 +1916,10 @@ search_input(struct seat *seat, struct terminal *term,
|
||||||
tll_foreach(bindings->search, it) {
|
tll_foreach(bindings->search, it) {
|
||||||
const struct key_binding *bind = &it->item;
|
const struct key_binding *bind = &it->item;
|
||||||
|
|
||||||
if (bind->k.sym == sym &&
|
if (bind->k.sym == sym && bind->mods == (mods & ~consumed)) {
|
||||||
bind->mods == (mods & ~consumed)) {
|
|
||||||
|
|
||||||
if (execute_binding(seat, term, bind, serial,
|
if (execute_binding(seat, term, bind, serial, &update_search_result,
|
||||||
&update_search_result, &search_direction,
|
&search_direction, &redraw)) {
|
||||||
&redraw))
|
|
||||||
{
|
|
||||||
goto update_search;
|
goto update_search;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -2034,10 +1935,8 @@ search_input(struct seat *seat, struct terminal *term,
|
||||||
|
|
||||||
tll_foreach(bind->k.key_codes, code) {
|
tll_foreach(bind->k.key_codes, code) {
|
||||||
if (code->item == key) {
|
if (code->item == key) {
|
||||||
if (execute_binding(seat, term, bind, serial,
|
if (execute_binding(seat, term, bind, serial, &update_search_result,
|
||||||
&update_search_result, &search_direction,
|
&search_direction, &redraw)) {
|
||||||
&redraw))
|
|
||||||
{
|
|
||||||
goto update_search;
|
goto update_search;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
|
|
@ -2049,15 +1948,15 @@ search_input(struct seat *seat, struct terminal *term,
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
if (compose_status == XKB_COMPOSE_COMPOSED) {
|
if (compose_status == XKB_COMPOSE_COMPOSED) {
|
||||||
count = xkb_compose_state_get_utf8(
|
count = xkb_compose_state_get_utf8(seat->kbd.xkb_compose_state, (char *)buf,
|
||||||
seat->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
|
sizeof(buf));
|
||||||
xkb_compose_state_reset(seat->kbd.xkb_compose_state);
|
xkb_compose_state_reset(seat->kbd.xkb_compose_state);
|
||||||
} else if (compose_status == XKB_COMPOSE_CANCELLED ||
|
} else if (compose_status == XKB_COMPOSE_CANCELLED ||
|
||||||
compose_status == XKB_COMPOSE_COMPOSING) {
|
compose_status == XKB_COMPOSE_COMPOSING) {
|
||||||
count = 0;
|
count = 0;
|
||||||
} else {
|
} else {
|
||||||
count = xkb_state_key_get_utf8(
|
count = xkb_state_key_get_utf8(seat->kbd.xkb_state, key, (char *)buf,
|
||||||
seat->kbd.xkb_state, key, (char *)buf, sizeof(buf));
|
sizeof(buf));
|
||||||
}
|
}
|
||||||
|
|
||||||
update_search_result = redraw = count > 0;
|
update_search_result = redraw = count > 0;
|
||||||
|
|
|
||||||
1575
terminal.c
1575
terminal.c
File diff suppressed because it is too large
Load diff
Loading…
Add table
Add a link
Reference in a new issue