mirror of
https://codeberg.org/dnkl/foot.git
synced 2026-02-04 04:06:06 -05:00
search: wip: re-direct input while searching, and build a search buffer
This adds a new state, 'is_searching'. While active, input is re-directed, and stored in a search buffer. In the future, we'll use this buffer and search for its content in the scrollback buffer, and move the view and create a selection on matches. When rendering in 'is_searching', everything is dimmed. In the future, we'll render the current search buffer on-top of the dimmed "regular" terminal output.
This commit is contained in:
parent
2d7ca416f0
commit
61cabdac13
6 changed files with 160 additions and 10 deletions
18
input.c
18
input.c
|
|
@ -18,11 +18,12 @@
|
|||
#define LOG_MODULE "input"
|
||||
#define LOG_ENABLE_DBG 0
|
||||
#include "log.h"
|
||||
#include "terminal.h"
|
||||
#include "render.h"
|
||||
#include "keymap.h"
|
||||
#include "commands.h"
|
||||
#include "keymap.h"
|
||||
#include "render.h"
|
||||
#include "search.h"
|
||||
#include "selection.h"
|
||||
#include "terminal.h"
|
||||
#include "vt.h"
|
||||
|
||||
static void
|
||||
|
|
@ -178,6 +179,12 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
xkb_mod_mask_t significant = ctrl | alt | shift | meta;
|
||||
xkb_mod_mask_t effective_mods = mods & ~consumed & significant;
|
||||
|
||||
if (term->is_searching) {
|
||||
start_repeater(term, key - 8);
|
||||
search_input(term, key, sym, effective_mods);
|
||||
return;
|
||||
}
|
||||
|
||||
#if 0
|
||||
for (size_t i = 0; i < 32; i++) {
|
||||
if (mods & (1 << i)) {
|
||||
|
|
@ -220,6 +227,11 @@ keyboard_key(void *data, struct wl_keyboard *wl_keyboard, uint32_t serial,
|
|||
selection_from_clipboard(term, serial);
|
||||
found_map = true;
|
||||
}
|
||||
|
||||
else if (sym == XKB_KEY_R) {
|
||||
search_begin(term);
|
||||
found_map = true;
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < sizeof(key_map) / sizeof(key_map[0]) && !found_map; i++) {
|
||||
|
|
|
|||
|
|
@ -90,6 +90,7 @@ executable(
|
|||
'main.c',
|
||||
'osc.c', 'osc.h',
|
||||
'render.c', 'render.h',
|
||||
'search.c', 'search.h',
|
||||
'selection.c', 'selection.h',
|
||||
'shm.c', 'shm.h',
|
||||
'slave.c', 'slave.h',
|
||||
|
|
|
|||
28
render.c
28
render.c
|
|
@ -204,6 +204,11 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
|||
bg = color_hex_to_pixman(term->cursor_color.cursor);
|
||||
}
|
||||
|
||||
if (term->is_searching) {
|
||||
pixman_color_dim(&fg);
|
||||
pixman_color_dim(&bg);
|
||||
}
|
||||
|
||||
struct font *font = attrs_to_font(term, &cell->attrs);
|
||||
const struct glyph *glyph = font_glyph_for_wc(font, cell->wc);
|
||||
|
||||
|
|
@ -216,9 +221,13 @@ render_cell(struct terminal *term, pixman_image_t *pix,
|
|||
|
||||
/* Non-block cursors */
|
||||
if (has_cursor && !block_cursor) {
|
||||
pixman_color_t cursor_color = term->cursor_color.text >> 31
|
||||
? color_hex_to_pixman(term->cursor_color.cursor)
|
||||
: fg;
|
||||
pixman_color_t cursor_color;
|
||||
if (term->cursor_color.text >> 31) {
|
||||
cursor_color = color_hex_to_pixman(term->cursor_color.cursor);
|
||||
if (term->is_searching)
|
||||
pixman_color_dim(&cursor_color);
|
||||
} else
|
||||
cursor_color = fg;
|
||||
|
||||
if (term->cursor_style == CURSOR_BAR)
|
||||
draw_bar(term, pix, &cursor_color, x, y);
|
||||
|
|
@ -435,9 +444,10 @@ grid_render(struct terminal *term)
|
|||
term_damage_view(term);
|
||||
|
||||
/* If we resized the window, or is flashing, or just stopped flashing */
|
||||
if (term->render.last_buf != buf || term->flash.active || term->render.was_flashing) {
|
||||
LOG_DBG("new buffer");
|
||||
|
||||
if (term->render.last_buf != buf ||
|
||||
term->flash.active || term->render.was_flashing ||
|
||||
term->is_searching != term->render.was_searching)
|
||||
{
|
||||
/* Fill area outside the cell grid with the default background color */
|
||||
int rmargin = term->x_margin + term->cols * term->cell_width;
|
||||
int bmargin = term->y_margin + term->rows * term->cell_height;
|
||||
|
|
@ -445,8 +455,10 @@ grid_render(struct terminal *term)
|
|||
int bmargin_height = term->height - bmargin;
|
||||
|
||||
uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg;
|
||||
|
||||
pixman_color_t bg = color_hex_to_pixman_with_alpha(_bg, term->colors.alpha);
|
||||
if (term->is_searching)
|
||||
pixman_color_dim(&bg);
|
||||
|
||||
pixman_image_fill_rectangles(
|
||||
PIXMAN_OP_SRC, pix, &bg, 4,
|
||||
(pixman_rectangle16_t[]){
|
||||
|
|
@ -469,6 +481,7 @@ grid_render(struct terminal *term)
|
|||
|
||||
term->render.last_buf = buf;
|
||||
term->render.was_flashing = term->flash.active;
|
||||
term->render.was_searching = term->is_searching;
|
||||
}
|
||||
|
||||
tll_foreach(term->grid->scroll_damage, it) {
|
||||
|
|
@ -626,6 +639,7 @@ grid_render(struct terminal *term)
|
|||
|
||||
if (term->flash.active) {
|
||||
/* Note: alpha is pre-computed in each color component */
|
||||
/* TODO: dim while searching */
|
||||
pixman_image_fill_rectangles(
|
||||
PIXMAN_OP_OVER, pix,
|
||||
&(pixman_color_t){.red=0x7fff, .green=0x7fff, .blue=0, .alpha=0x7fff},
|
||||
|
|
|
|||
107
search.c
Normal file
107
search.c
Normal file
|
|
@ -0,0 +1,107 @@
|
|||
#include "search.h"
|
||||
|
||||
#include <wchar.h>
|
||||
#include <xkbcommon/xkbcommon-compose.h>
|
||||
|
||||
#define LOG_MODULE "search"
|
||||
#define LOG_ENABLE_DBG 1
|
||||
#include "log.h"
|
||||
#include "render.h"
|
||||
|
||||
void
|
||||
search_begin(struct terminal *term)
|
||||
{
|
||||
LOG_DBG("search: begin");
|
||||
|
||||
free(term->search.buf);
|
||||
term->search.buf = NULL;
|
||||
term->search.len = 0;
|
||||
term->search.sz = 0;
|
||||
term->is_searching = true;
|
||||
|
||||
render_refresh(term);
|
||||
}
|
||||
|
||||
void
|
||||
search_cancel(struct terminal *term)
|
||||
{
|
||||
LOG_DBG("search: cancel");
|
||||
|
||||
free(term->search.buf);
|
||||
term->search.buf = NULL;
|
||||
term->search.len = 0;
|
||||
term->search.sz = 0;
|
||||
term->is_searching = false;
|
||||
|
||||
render_refresh(term);
|
||||
}
|
||||
|
||||
void
|
||||
search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask_t mods)
|
||||
{
|
||||
LOG_DBG("search: input: sym=%d/0x%x, mods=0x%08x", sym, sym, mods);
|
||||
|
||||
const xkb_mod_mask_t ctrl = 1 << term->kbd.mod_ctrl;
|
||||
//const xkb_mod_mask_t alt = 1 << term->kbd.mod_alt;
|
||||
//const xkb_mod_mask_t shift = 1 << term->kbd.mod_shift;
|
||||
//const xkb_mod_mask_t meta = 1 << term->kbd.mod_meta;
|
||||
|
||||
enum xkb_compose_status compose_status = xkb_compose_state_get_status(
|
||||
term->kbd.xkb_compose_state);
|
||||
|
||||
if ((mods == 0 && sym == XKB_KEY_Escape) || (mods == ctrl && sym == XKB_KEY_g))
|
||||
search_cancel(term);
|
||||
|
||||
else if (mods == 0 && sym == XKB_KEY_BackSpace) {
|
||||
if (term->search.len > 0)
|
||||
term->search.buf[--term->search.len] = L'\0';
|
||||
}
|
||||
|
||||
else {
|
||||
uint8_t buf[64] = {0};
|
||||
int count = 0;
|
||||
|
||||
if (compose_status == XKB_COMPOSE_COMPOSED) {
|
||||
count = xkb_compose_state_get_utf8(
|
||||
term->kbd.xkb_compose_state, (char *)buf, sizeof(buf));
|
||||
xkb_compose_state_reset(term->kbd.xkb_compose_state);
|
||||
} else {
|
||||
count = xkb_state_key_get_utf8(
|
||||
term->kbd.xkb_state, key, (char *)buf, sizeof(buf));
|
||||
}
|
||||
|
||||
const char *src = (const char *)buf;
|
||||
mbstate_t ps = {0};
|
||||
size_t wchars = mbsnrtowcs(NULL, &src, count, 0, &ps);
|
||||
|
||||
if (wchars == -1) {
|
||||
LOG_ERRNO("failed to convert %.*s to wchars", count, buf);
|
||||
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;
|
||||
}
|
||||
|
||||
assert(term->search.len + wchars < term->search.sz);
|
||||
|
||||
memset(&ps, 0, sizeof(ps));
|
||||
mbsnrtowcs(&term->search.buf[term->search.len], &src, count,
|
||||
term->search.sz - term->search.len - 1, &ps);
|
||||
|
||||
term->search.len += wchars;
|
||||
term->search.buf[term->search.len] = L'\0';
|
||||
}
|
||||
|
||||
LOG_DBG("search: buffer: %S", term->search.buf);
|
||||
render_refresh(term);
|
||||
}
|
||||
8
search.h
Normal file
8
search.h
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
#include <xkbcommon/xkbcommon.h>
|
||||
#include "terminal.h"
|
||||
|
||||
void search_begin(struct terminal *term);
|
||||
void search_cancel(struct terminal *term);
|
||||
void search_input(struct terminal *term, uint32_t key, xkb_keysym_t sym, xkb_mod_mask_t mods);
|
||||
|
|
@ -331,6 +331,13 @@ struct terminal {
|
|||
struct primary primary;
|
||||
} selection;
|
||||
|
||||
bool is_searching;
|
||||
struct {
|
||||
wchar_t *buf;
|
||||
size_t len;
|
||||
size_t sz;
|
||||
} search;
|
||||
|
||||
struct grid normal;
|
||||
struct grid alt;
|
||||
struct grid *grid;
|
||||
|
|
@ -368,6 +375,7 @@ struct terminal {
|
|||
|
||||
struct buffer *last_buf; /* Buffer we rendered to last time */
|
||||
bool was_flashing; /* Flash was active last time we rendered */
|
||||
bool was_searching;
|
||||
} render;
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue