From 198529525c788f51babcd425ea7dcdb4d8125c04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:16:05 +0100 Subject: [PATCH 01/15] selection: break out isword() to a new file --- meson.build | 1 + misc.c | 24 ++++++++++++++++++++++++ misc.h | 6 ++++++ selection.c | 22 +--------------------- 4 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 misc.c create mode 100644 misc.h diff --git a/meson.build b/meson.build index 0603805b..5c662e9e 100644 --- a/meson.build +++ b/meson.build @@ -75,6 +75,7 @@ executable( 'input.c', 'input.h', 'log.c', 'log.h', 'main.c', + 'misc.c', 'misc.h', 'osc.c', 'osc.h', 'render.c', 'render.h', 'search.c', 'search.h', diff --git a/misc.c b/misc.c new file mode 100644 index 00000000..b8eb3296 --- /dev/null +++ b/misc.c @@ -0,0 +1,24 @@ +#include "misc.h" + +#include + +bool +isword(wchar_t wc, bool spaces_only) +{ + if (spaces_only) + return iswgraph(wc); + + switch (wc) { + default: return iswgraph(wc); + + case L'(': case L')': + case L'[': case L']': + case L'{': case L'}': + case L'<': case L'>': + case L'│': case L'|': + case L',': + case L'`': case L'"': case L'\'': + case L':': + return false; + } +} diff --git a/misc.h b/misc.h new file mode 100644 index 00000000..06dd3303 --- /dev/null +++ b/misc.h @@ -0,0 +1,6 @@ +#pragma once + +#include +#include + +bool isword(wchar_t wc, bool spaces_only); diff --git a/selection.c b/selection.c index b77dc64a..bbe990d7 100644 --- a/selection.c +++ b/selection.c @@ -15,6 +15,7 @@ #include "async.h" #include "grid.h" +#include "misc.h" #include "render.h" #include "vt.h" @@ -222,27 +223,6 @@ selection_cancel(struct terminal *term) } } -static bool -isword(wint_t c, bool spaces_only) -{ - if (spaces_only) - return !iswspace(c); - - switch (c) { - default: return !iswspace(c); - - case L'{': case L'}': - case L'[': case L']': - case L'(': case L')': - case L'`': - case L'\'': - case L'"': - case L',': case L'.': - case L':': case L';': - return false; - } -} - void selection_mark_word(struct terminal *term, int col, int row, bool spaces_only, uint32_t serial) From d94fc80966295d24613f7bfa49884d518d59caa3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:17:34 +0100 Subject: [PATCH 02/15] search: break out search buffer resize code to a new function --- search.c | 33 +++++++++++++++++++++------------ 1 file changed, 21 insertions(+), 12 deletions(-) diff --git a/search.c b/search.c index b10e75ac..1e46852e 100644 --- a/search.c +++ b/search.c @@ -17,6 +17,25 @@ #define max(x, y) ((x) > (y) ? (x) : (y)) +static bool +search_ensure_size(struct terminal *term, size_t wanted_size) +{ + while (wanted_size >= term->search.sz) { + size_t new_sz = term->search.sz == 0 ? 64 : term->search.sz * 2; + wchar_t *new_buf = realloc(term->search.buf, new_sz * sizeof(term->search.buf[0])); + + if (new_buf == NULL) { + LOG_ERRNO("failed to resize search buffer"); + return false; + } + + term->search.buf = new_buf; + term->search.sz = new_sz; + } + + return true; +} + static void search_cancel_keep_selection(struct terminal *term) { @@ -468,18 +487,8 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask return; } - while (term->search.len + wchars >= term->search.sz) { - size_t new_sz = term->search.sz == 0 ? 64 : term->search.sz * 2; - wchar_t *new_buf = realloc(term->search.buf, new_sz * sizeof(term->search.buf[0])); - - if (new_buf == NULL) { - LOG_ERRNO("failed to resize search buffer"); - return; - } - - term->search.buf = new_buf; - term->search.sz = new_sz; - } + if (!search_ensure_size(term, term->search.len + wchars)) + return; assert(term->search.len + wchars < term->search.sz); From 10cf7226179a8598239eda3be0566b515ecbb11a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:17:51 +0100 Subject: [PATCH 03/15] search: don't line-wrap unless we actually have a match on the next row When matching characters, we moved on to next row directly after matching the last character in a row. This was wrong since if that last character was the last matching character, we tried to create a selection that was on the wrong row. --- search.c | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/search.c b/search.c index 1e46852e..dec20c02 100644 --- a/search.c +++ b/search.c @@ -148,10 +148,7 @@ search_update(struct terminal *term) size_t match_len = 0; for (size_t i = 0; i < term->search.len; i++, match_len++) { - if (wcsncasecmp(&row->cells[end_col].wc, &term->search.buf[i], 1) != 0) - break; - - 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)) { /* Don't continue past end of the world */ break; @@ -161,6 +158,11 @@ search_update(struct terminal *term) end_col = 0; row = term->grid->rows[end_row]; } + + if (wcsncasecmp(&row->cells[end_col].wc, &term->search.buf[i], 1) != 0) + break; + + end_col++; } if (match_len != term->search.len) { From ac2eda885abde3540a7e2dafdc535de228d1f20f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:19:26 +0100 Subject: [PATCH 04/15] search: remove debug log --- search.c | 1 - 1 file changed, 1 deletion(-) diff --git a/search.c b/search.c index dec20c02..8db11bd3 100644 --- a/search.c +++ b/search.c @@ -278,7 +278,6 @@ distance_next_word(const struct terminal *term) break; } - LOG_INFO("cursor = %zu, iswspace() = %d", cursor, iswspace(term->search.buf[cursor - 1])); assert(cursor == term->search.len || !iswspace(term->search.buf[cursor - 1])); if (cursor < term->search.len && !iswspace(term->search.buf[cursor])) From f67733c0e3a4e4ba19e1c70bc36ee78af762868f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:19:55 +0100 Subject: [PATCH 05/15] search: discard canceled compose sequences --- search.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/search.c b/search.c index 8db11bd3..2489f9e7 100644 --- a/search.c +++ b/search.c @@ -466,6 +466,10 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask } } + else if (mods == ctrl && sym == XKB_KEY_w) { + search_match_to_end_of_word(term); + } + else { uint8_t buf[64] = {0}; int count = 0; From a34deabcc90fa252ad9165f79cd0e1a6dda7a0ba Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:21:03 +0100 Subject: [PATCH 06/15] Revert "search: discard canceled compose sequences" This reverts commit f67733c0e3a4e4ba19e1c70bc36ee78af762868f. --- search.c | 4 ---- 1 file changed, 4 deletions(-) diff --git a/search.c b/search.c index 2489f9e7..8db11bd3 100644 --- a/search.c +++ b/search.c @@ -466,10 +466,6 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask } } - else if (mods == ctrl && sym == XKB_KEY_w) { - search_match_to_end_of_word(term); - } - else { uint8_t buf[64] = {0}; int count = 0; From 694d84a9e903114d242fbc3ea0c845b8a35010f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:21:16 +0100 Subject: [PATCH 07/15] search: discard canceled compose sequences --- search.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/search.c b/search.c index 8db11bd3..72101030 100644 --- a/search.c +++ b/search.c @@ -474,6 +474,8 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask count = xkb_compose_state_get_utf8( term->wl->kbd.xkb_compose_state, (char *)buf, sizeof(buf)); xkb_compose_state_reset(term->wl->kbd.xkb_compose_state); + } else if (compose_status == XKB_COMPOSE_CANCELLED) { + count = 0; } else { count = xkb_state_key_get_utf8( term->wl->kbd.xkb_state, key, (char *)buf, sizeof(buf)); From b5a04dcaae5bd0ebffa6daf02a75a0900925a562 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:22:47 +0100 Subject: [PATCH 08/15] search: map ctrl+w to 'extend current selection to end of word' If the user has started a scrollback search and have some matching text, he can now press ctrl+w to extend that selection (and thus the search criteria too) to the end of the current word, or to the end of the next word if currently at a word separating character. --- search.c | 75 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 75 insertions(+) diff --git a/search.c b/search.c index 72101030..1ebeb646 100644 --- a/search.c +++ b/search.c @@ -11,6 +11,7 @@ #define LOG_ENABLE_DBG 0 #include "log.h" #include "grid.h" +#include "misc.h" #include "render.h" #include "selection.h" #include "shm.h" @@ -258,6 +259,77 @@ search_update(struct terminal *term) #undef ROW_DEC } +static void +search_match_to_end_of_word(struct terminal *term) +{ + if (term->search.match_len == 0) + return; + + assert(term->search.match.row != -1); + assert(term->search.match.col != -1); + + int start_row = term->search.match.row; + int start_col = term->search.match.col; + size_t len = term->search.match_len; + + /* Calculate end coord - note: assumed to be valid */ + for (size_t i = 0; i < len; i++) { + if (++start_col >= term->cols) + start_row = (start_row + 1) % term->grid->num_rows; + } + + tll(wchar_t) new_chars = tll_init(); + + /* Always append at least one character *if* possible */ + bool first = true; + + for (size_t r = 0; + r < term->grid->num_rows; + start_row = (start_row + 1) % term->grid->num_rows, r++) + { + const struct row *row = term->grid->rows[start_row]; + if (row == NULL) + break; + + bool done = false; + for (; start_col < term->cols; start_col++) { + wchar_t wc = row->cells[start_col].wc; + if (wc == 0 || (!first && !isword(wc, false))) { + done = true; + break; + } + + first = false; + tll_push_back(new_chars, wc); + } + + if (done) + break; + } + + if (tll_length(new_chars) == 0) + return; + + if (!search_ensure_size(term, term->search.len + tll_length(new_chars))) + return; + + bool move_cursor = term->search.cursor == term->search.len; + + tll_foreach(new_chars, it) + term->search.buf[term->search.len++] = it->item; + term->search.buf[term->search.len] = L'\0'; + + if (move_cursor) + term->search.cursor += tll_length(new_chars); + + tll_free(new_chars); + + /* TODO: split up search_update() into one part that searches for + * a match, and a second part that updates the view and sets the + * selction. Call the latter part here */ + search_update(term); +} + static size_t distance_next_word(const struct terminal *term) { @@ -466,6 +538,9 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask } } + else if (mods == ctrl && sym == XKB_KEY_w) + search_match_to_end_of_word(term); + else { uint8_t buf[64] = {0}; int count = 0; From b3287c07cd9d2644d6b087d449425bbd461608db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:23:56 +0100 Subject: [PATCH 09/15] README: describe ctrl+w while scrollback searching --- README.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.md b/README.md index 837a63a5..9385cd9a 100644 --- a/README.md +++ b/README.md @@ -118,6 +118,12 @@ available: Search _forward_ for next match +* ctrl+w + + Extend current selection (and thus the search criteria) to the end + of the word, or the next word if currently at a word separating + character. + * escape, ctrl+g Cancel the search From e003736e1195c48d4371e5bdc02883addd3850f4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:24:33 +0100 Subject: [PATCH 10/15] search: rename search_update() -> search_find_next() --- search.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/search.c b/search.c index 1ebeb646..2d600ac3 100644 --- a/search.c +++ b/search.c @@ -84,7 +84,7 @@ search_cancel(struct terminal *term) } static void -search_update(struct terminal *term) +search_find_next(struct terminal *term) { bool backward = term->search.direction == SEARCH_BACKWARD; term->search.direction = SEARCH_BACKWARD; @@ -327,7 +327,7 @@ search_match_to_end_of_word(struct terminal *term) /* TODO: split up search_update() into one part that searches for * a match, and a second part that updates the view and sets the * selction. Call the latter part here */ - search_update(term); + search_find_next(term); } static size_t @@ -584,7 +584,7 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask } LOG_DBG("search: buffer: %S", term->search.buf); - search_update(term); + search_find_next(term); render_refresh(term); render_search_box(term); } From 2a5da66e4e3020b91f52a411bab1617f9232c421 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:40:22 +0100 Subject: [PATCH 11/15] search: split up search_update() into two * search_find_next() searches the scrollback, continuing from the last match. The assumption is that the search buffer has changed. * search_update_selection() updates the selection and moves the view to ensure the selection is visible. Note that it doesn't verify the selection actually matches the search buffer. --- search.c | 139 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 71 insertions(+), 68 deletions(-) diff --git a/search.c b/search.c index 2d600ac3..8ade6c88 100644 --- a/search.c +++ b/search.c @@ -83,6 +83,74 @@ search_cancel(struct terminal *term) selection_cancel(term); } +static void +search_update_selection(struct terminal *term, + int start_row, int start_col, + int end_row, int end_col) +{ + int old_view = term->grid->view; + int new_view = start_row; + + /* Prevent scrolling in uninitialized rows */ + bool all_initialized = false; + do { + all_initialized = true; + + for (int i = 0; i < term->rows; i++) { + int row_no = (new_view + i) % term->grid->num_rows; + if (term->grid->rows[row_no] == NULL) { + all_initialized = false; + new_view--; + break; + } + } + } while (!all_initialized); + + /* Don't scroll past scrollback history */ + int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows; + if (end >= term->grid->offset) { + /* Not wrapped */ + if (new_view >= term->grid->offset && new_view <= end) + new_view = term->grid->offset; + } else { + if (new_view >= term->grid->offset || new_view <= end) + new_view = term->grid->offset; + } + + /* Update view */ + term->grid->view = new_view; + if (new_view != old_view) + term_damage_view(term); + + /* Selection endpoint is inclusive */ + assert(end_col > 0); + end_col--; + + /* Begin a new selection if the start coords changed */ + if (start_row != term->search.match.row || + start_col != term->search.match.col) + { + int selection_row = start_row - term->grid->view; + while (selection_row < 0) + selection_row += term->grid->num_rows; + + assert(selection_row >= 0 && + selection_row < term->grid->num_rows); + selection_start(term, start_col, selection_row); + } + + /* Update selection endpoint */ + { + int selection_row = end_row - term->grid->view; + while (selection_row < 0) + selection_row += term->grid->num_rows; + + assert(selection_row >= 0 && + selection_row < term->grid->num_rows); + selection_update(term, end_col, selection_row); + } +} + static void search_find_next(struct terminal *term) { @@ -175,70 +243,7 @@ search_find_next(struct terminal *term) * We matched the entire buffer. Move view to ensure the * match is visible, create a selection and return. */ - - int old_view = term->grid->view; - int new_view = start_row; - - /* Prevent scrolling in uninitialized rows */ - bool all_initialized = false; - do { - all_initialized = true; - - for (int i = 0; i < term->rows; i++) { - int row_no = (new_view + i) % term->grid->num_rows; - if (term->grid->rows[row_no] == NULL) { - all_initialized = false; - new_view--; - break; - } - } - } while (!all_initialized); - - /* Don't scroll past scrollback history */ - int end = (term->grid->offset + term->rows - 1) % term->grid->num_rows; - if (end >= term->grid->offset) { - /* Not wrapped */ - if (new_view >= term->grid->offset && new_view <= end) - new_view = term->grid->offset; - } else { - if (new_view >= term->grid->offset || new_view <= end) - new_view = term->grid->offset; - } - - /* Update view */ - term->grid->view = new_view; - if (new_view != old_view) - term_damage_view(term); - - /* Selection endpoint is inclusive */ - if (--end_col < 0) { - end_col = term->cols - 1; - start_row--; - } - - /* Begin a new selection if the start coords changed */ - if (start_row != term->search.match.row || - start_col != term->search.match.col) - { - int selection_row = start_row - term->grid->view; - while (selection_row < 0) - selection_row += term->grid->num_rows; - - assert(selection_row >= 0 && - selection_row < term->grid->num_rows); - selection_start(term, start_col, selection_row); - } - - /* Update selection endpoint */ - { - int selection_row = end_row - term->grid->view; - while (selection_row < 0) - selection_row += term->grid->num_rows; - - assert(selection_row >= 0 && - selection_row < term->grid->num_rows); - selection_update(term, end_col, selection_row); - } + search_update_selection(term, start_row, start_col, end_row, end_col); /* Update match state */ term->search.match.row = start_row; @@ -324,10 +329,8 @@ search_match_to_end_of_word(struct terminal *term) tll_free(new_chars); - /* TODO: split up search_update() into one part that searches for - * a match, and a second part that updates the view and sets the - * selction. Call the latter part here */ - search_find_next(term); + search_update_selection( + term, term->search.match.row, term->search.match.col, end_row, end_col); } static size_t From 867cac4207aea464803729339c014024389c5b81 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:42:43 +0100 Subject: [PATCH 12/15] search: search_match_to_end_of_word: rename start_{row,col} -> end_{row,col} --- search.c | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/search.c b/search.c index 8ade6c88..03eae348 100644 --- a/search.c +++ b/search.c @@ -273,14 +273,14 @@ search_match_to_end_of_word(struct terminal *term) assert(term->search.match.row != -1); assert(term->search.match.col != -1); - int start_row = term->search.match.row; - int start_col = term->search.match.col; + int end_row = term->search.match.row; + int end_col = term->search.match.col; size_t len = term->search.match_len; /* Calculate end coord - note: assumed to be valid */ for (size_t i = 0; i < len; i++) { - if (++start_col >= term->cols) - start_row = (start_row + 1) % term->grid->num_rows; + if (++end_col >= term->cols) + end_row = (end_row + 1) % term->grid->num_rows; } tll(wchar_t) new_chars = tll_init(); @@ -290,15 +290,15 @@ search_match_to_end_of_word(struct terminal *term) for (size_t r = 0; r < term->grid->num_rows; - start_row = (start_row + 1) % term->grid->num_rows, r++) + end_row = (end_row + 1) % term->grid->num_rows, r++) { - const struct row *row = term->grid->rows[start_row]; + const struct row *row = term->grid->rows[end_row]; if (row == NULL) break; bool done = false; - for (; start_col < term->cols; start_col++) { - wchar_t wc = row->cells[start_col].wc; + for (; end_col < term->cols; end_col++) { + wchar_t wc = row->cells[end_col].wc; if (wc == 0 || (!first && !isword(wc, false))) { done = true; break; @@ -318,8 +318,10 @@ search_match_to_end_of_word(struct terminal *term) if (!search_ensure_size(term, term->search.len + tll_length(new_chars))) return; + /* Keep cursor at the end, but don't move it if not */ bool move_cursor = term->search.cursor == term->search.len; + /* 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'; From 0982210af21ae53135e2bb139e4a69d25d316285 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:43:45 +0100 Subject: [PATCH 13/15] search: map ctrl+shift+w to match to end of word, spaces only This works just like ctrl+w, except that the only space separating characters are whitespaces. --- README.md | 5 +++++ search.c | 11 +++++++---- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 9385cd9a..caeb8e12 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,11 @@ available: of the word, or the next word if currently at a word separating character. +* ctrl+shiftw + + Same as ctrl+w, except that the only word + separating characters are whitespace characters. + * escape, ctrl+g Cancel the search diff --git a/search.c b/search.c index 03eae348..47793823 100644 --- a/search.c +++ b/search.c @@ -265,7 +265,7 @@ search_find_next(struct terminal *term) } static void -search_match_to_end_of_word(struct terminal *term) +search_match_to_end_of_word(struct terminal *term, bool spaces_only) { if (term->search.match_len == 0) return; @@ -299,7 +299,7 @@ search_match_to_end_of_word(struct terminal *term) bool done = false; for (; end_col < term->cols; end_col++) { wchar_t wc = row->cells[end_col].wc; - if (wc == 0 || (!first && !isword(wc, false))) { + if (wc == 0 || (!first && !isword(wc, spaces_only))) { done = true; break; } @@ -396,7 +396,7 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask const xkb_mod_mask_t ctrl = 1 << term->wl->kbd.mod_ctrl; const xkb_mod_mask_t alt = 1 << term->wl->kbd.mod_alt; - //const xkb_mod_mask_t shift = 1 << term->wl->kbd.mod_shift; + const xkb_mod_mask_t shift = 1 << term->wl->kbd.mod_shift; //const xkb_mod_mask_t meta = 1 << term->wl->kbd.mod_meta; enum xkb_compose_status compose_status = xkb_compose_state_get_status( @@ -544,7 +544,10 @@ search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask } else if (mods == ctrl && sym == XKB_KEY_w) - search_match_to_end_of_word(term); + search_match_to_end_of_word(term, false); + + else if (mods == (ctrl | shift) && sym == XKB_KEY_W) + search_match_to_end_of_word(term, true); else { uint8_t buf[64] = {0}; From 3c713899932f10a61fa9584c498396a2aaad0d4d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 19:58:33 +0100 Subject: [PATCH 14/15] render: don't allow negative coordinates of the search surface While the protocol allows this, it appears Sway offsets (moves) the parent surface when this happens, resulting in a window half without content. --- render.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/render.c b/render.c index d17108ec..ccae7d25 100644 --- a/render.c +++ b/render.c @@ -795,7 +795,8 @@ render_search_box(struct terminal *term) wl_subsurface_set_position( term->window->search_sub_surface, - term->width - width - margin, term->height - height - margin); + max(0, term->width - width - margin), + max(0, term->height - height - margin)); wl_surface_damage_buffer(term->window->search_surface, 0, 0, width, height); wl_surface_attach(term->window->search_surface, buf->wl_buf, 0, 0); From 008281757b007cfed3b1ebf22b7879d68820aaef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 3 Dec 2019 20:00:38 +0100 Subject: [PATCH 15/15] search: bug: re-initialize start-row when attempting a new match When we've already found a partial match (but *not* a complete match), and that match spanned multiple lines, then when we continued with the next start-column we re-used a know-wrong row pointer. --- search.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/search.c b/search.c index 47793823..3609f81c 100644 --- a/search.c +++ b/search.c @@ -194,14 +194,14 @@ search_find_next(struct terminal *term) r < term->grid->num_rows; backward ? ROW_DEC(start_row) : ROW_INC(start_row), r++) { - const struct row *row = term->grid->rows[start_row]; - if (row == NULL) - continue; - for (; backward ? start_col >= 0 : start_col < term->cols; backward ? start_col-- : start_col++) { + const struct row *row = term->grid->rows[start_row]; + if (row == NULL) + continue; + if (wcsncasecmp(&row->cells[start_col].wc, term->search.buf, 1) != 0) continue;