mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-18 22:05:25 -05:00
render: search: glyph_offset is in *cells*, cursor position in *characters*
When calculating the offset into the search string, from where to start rendering, take into account that the cursor position is in *characters*, and the glyph-offset is in *cells*.
This commit is contained in:
parent
5ffa65a2e3
commit
b4a0f5b13b
2 changed files with 70 additions and 18 deletions
82
render.c
82
render.c
|
|
@ -2117,8 +2117,19 @@ render_search_box(struct terminal *term)
|
||||||
{
|
{
|
||||||
assert(term->window->search_sub_surface != NULL);
|
assert(term->window->search_sub_surface != NULL);
|
||||||
|
|
||||||
const size_t wanted_visible_chars = max(
|
/*
|
||||||
20, wcswidth(term->search.buf, term->search.len));
|
* We treat the search box pretty much like a row of cells. That
|
||||||
|
* is, a glyph is either 1 or 2 (or more) “cells” wide.
|
||||||
|
*
|
||||||
|
* The search ‘length’, and ‘cursor’ (position) is in
|
||||||
|
* *characters*, not cells. This means we need to translate from
|
||||||
|
* character cound to cell count when calculating the length of
|
||||||
|
* the search box, where in the search string we should start
|
||||||
|
* rendering etc.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const size_t total_cells = wcswidth(term->search.buf, term->search.len);
|
||||||
|
const size_t wanted_visible_cells = max(20, total_cells);
|
||||||
|
|
||||||
assert(term->scale >= 1);
|
assert(term->scale >= 1);
|
||||||
const int scale = term->scale;
|
const int scale = term->scale;
|
||||||
|
|
@ -2128,12 +2139,12 @@ render_search_box(struct terminal *term)
|
||||||
const size_t width = term->width - 2 * margin;
|
const size_t width = term->width - 2 * margin;
|
||||||
const size_t visible_width = min(
|
const size_t visible_width = min(
|
||||||
term->width - 2 * margin,
|
term->width - 2 * margin,
|
||||||
2 * margin + wanted_visible_chars * term->cell_width);
|
2 * margin + wanted_visible_cells * term->cell_width);
|
||||||
const size_t height = min(
|
const size_t height = min(
|
||||||
term->height - 2 * margin,
|
term->height - 2 * margin,
|
||||||
2 * margin + 1 * term->cell_height);
|
2 * margin + 1 * term->cell_height);
|
||||||
|
|
||||||
const size_t visible_chars = (visible_width - 2 * margin) / term->cell_width;
|
const size_t visible_cells = (visible_width - 2 * margin) / term->cell_width;
|
||||||
size_t glyph_offset = term->render.search_glyph_offset;
|
size_t glyph_offset = term->render.search_glyph_offset;
|
||||||
|
|
||||||
unsigned long cookie = shm_cookie_search(term);
|
unsigned long cookie = shm_cookie_search(term);
|
||||||
|
|
@ -2158,32 +2169,66 @@ render_search_box(struct terminal *term)
|
||||||
int y = margin;
|
int y = margin;
|
||||||
pixman_color_t fg = color_hex_to_pixman(term->colors.table[0]);
|
pixman_color_t fg = color_hex_to_pixman(term->colors.table[0]);
|
||||||
|
|
||||||
/* Ensure cursor is visible */
|
/*
|
||||||
if (term->search.cursor < glyph_offset)
|
* Ensure cursor is visible
|
||||||
term->render.search_glyph_offset = glyph_offset = term->search.cursor;
|
*
|
||||||
else if (term->search.cursor > glyph_offset + visible_chars) {
|
* First, we need to map the cursor character position to a cell
|
||||||
term->render.search_glyph_offset = glyph_offset =
|
* position. Then we can ensure the cursor is within the rendered
|
||||||
term->search.cursor - min(term->search.cursor, visible_chars);
|
* part of the search string.
|
||||||
|
*/
|
||||||
|
for (size_t i = 0, cell_idx = 0;
|
||||||
|
i <= term->search.cursor;
|
||||||
|
cell_idx += max(1, wcwidth(term->search.buf[i])), i++)
|
||||||
|
{
|
||||||
|
if (i != term->search.cursor)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if (cell_idx < glyph_offset)
|
||||||
|
term->render.search_glyph_offset = glyph_offset = cell_idx;
|
||||||
|
else if (cell_idx > glyph_offset + visible_cells) {
|
||||||
|
term->render.search_glyph_offset = glyph_offset =
|
||||||
|
cell_idx - min(cell_idx, visible_cells);
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Move offset if there is free space available */
|
/* Move offset if there is free space available */
|
||||||
if (term->search.len - glyph_offset < visible_chars)
|
if (total_cells - glyph_offset < visible_cells)
|
||||||
term->render.search_glyph_offset = glyph_offset =
|
term->render.search_glyph_offset = glyph_offset =
|
||||||
term->search.len - min(term->search.len, visible_chars);
|
total_cells - min(total_cells, visible_cells);
|
||||||
|
|
||||||
/* Text (what the user entered - *not* match(es)) */
|
/*
|
||||||
for (size_t i = glyph_offset;
|
* Render the search string, starting at ‘glyph_offset’. Note that
|
||||||
i < term->search.len && i - glyph_offset < visible_chars;
|
* glyph_offset is in cells, not characters
|
||||||
i++)
|
*/
|
||||||
|
for (size_t i = 0,
|
||||||
|
cell_idx = 0,
|
||||||
|
width = max(1, wcwidth(term->search.buf[i])),
|
||||||
|
next_cell_idx = width;
|
||||||
|
i < term->search.len;
|
||||||
|
i++,
|
||||||
|
cell_idx = next_cell_idx,
|
||||||
|
width = max(1, wcwidth(term->search.buf[i])),
|
||||||
|
next_cell_idx += width)
|
||||||
{
|
{
|
||||||
if (i == term->search.cursor)
|
if (i == term->search.cursor)
|
||||||
draw_bar(term, buf->pix[0], font, &fg, x, y);
|
draw_bar(term, buf->pix[0], font, &fg, x, y);
|
||||||
|
|
||||||
|
if (next_cell_idx >= glyph_offset && next_cell_idx - glyph_offset > visible_cells)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (cell_idx < glyph_offset) {
|
||||||
|
cell_idx = next_cell_idx;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
const struct fcft_glyph *glyph = fcft_glyph_rasterize(
|
const struct fcft_glyph *glyph = fcft_glyph_rasterize(
|
||||||
font, term->search.buf[i], term->font_subpixel);
|
font, term->search.buf[i], term->font_subpixel);
|
||||||
|
|
||||||
if (glyph == NULL)
|
if (glyph == NULL) {
|
||||||
|
cell_idx = next_cell_idx;
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (unlikely(pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)) {
|
if (unlikely(pixman_image_get_format(glyph->pix) == PIXMAN_a8r8g8b8)) {
|
||||||
/* Glyph surface is a pre-rendered image (typically a color emoji...) */
|
/* Glyph surface is a pre-rendered image (typically a color emoji...) */
|
||||||
|
|
@ -2200,7 +2245,8 @@ render_search_box(struct terminal *term)
|
||||||
pixman_image_unref(src);
|
pixman_image_unref(src);
|
||||||
}
|
}
|
||||||
|
|
||||||
x += max(1, wcwidth(term->search.buf[i])) * term->cell_width;
|
x += width * term->cell_width;
|
||||||
|
cell_idx = next_cell_idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (term->search.cursor >= term->search.len)
|
if (term->search.cursor >= term->search.len)
|
||||||
|
|
|
||||||
6
search.c
6
search.c
|
|
@ -18,6 +18,7 @@
|
||||||
#include "selection.h"
|
#include "selection.h"
|
||||||
#include "shm.h"
|
#include "shm.h"
|
||||||
#include "util.h"
|
#include "util.h"
|
||||||
|
#include "xmalloc.h"
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Ensures a "new" viewport doesn't contain any unallocated rows.
|
* Ensures a "new" viewport doesn't contain any unallocated rows.
|
||||||
|
|
@ -124,6 +125,11 @@ search_begin(struct terminal *term)
|
||||||
term->search.view_followed_offset = term->grid->view == term->grid->offset;
|
term->search.view_followed_offset = term->grid->view == term->grid->offset;
|
||||||
term->is_searching = true;
|
term->is_searching = true;
|
||||||
|
|
||||||
|
term->search.len = 0;
|
||||||
|
term->search.sz = 64;
|
||||||
|
term->search.buf = xmalloc(term->search.sz * sizeof(term->search.buf[0]));
|
||||||
|
term->search.buf[0] = L'\0';
|
||||||
|
|
||||||
term_xcursor_update(term);
|
term_xcursor_update(term);
|
||||||
render_refresh_search(term);
|
render_refresh_search(term);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue