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:
Daniel Eklöf 2019-08-27 17:23:28 +02:00
parent 2d7ca416f0
commit 61cabdac13
No known key found for this signature in database
GPG key ID: 5BBD4992C116573F
6 changed files with 160 additions and 10 deletions

18
input.c
View file

@ -18,11 +18,12 @@
#define LOG_MODULE "input" #define LOG_MODULE "input"
#define LOG_ENABLE_DBG 0 #define LOG_ENABLE_DBG 0
#include "log.h" #include "log.h"
#include "terminal.h"
#include "render.h"
#include "keymap.h"
#include "commands.h" #include "commands.h"
#include "keymap.h"
#include "render.h"
#include "search.h"
#include "selection.h" #include "selection.h"
#include "terminal.h"
#include "vt.h" #include "vt.h"
static void 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 significant = ctrl | alt | shift | meta;
xkb_mod_mask_t effective_mods = mods & ~consumed & significant; 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 #if 0
for (size_t i = 0; i < 32; i++) { for (size_t i = 0; i < 32; i++) {
if (mods & (1 << 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); selection_from_clipboard(term, serial);
found_map = true; 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++) { for (size_t i = 0; i < sizeof(key_map) / sizeof(key_map[0]) && !found_map; i++) {

View file

@ -90,6 +90,7 @@ executable(
'main.c', 'main.c',
'osc.c', 'osc.h', 'osc.c', 'osc.h',
'render.c', 'render.h', 'render.c', 'render.h',
'search.c', 'search.h',
'selection.c', 'selection.h', 'selection.c', 'selection.h',
'shm.c', 'shm.h', 'shm.c', 'shm.h',
'slave.c', 'slave.h', 'slave.c', 'slave.h',

View file

@ -204,6 +204,11 @@ render_cell(struct terminal *term, pixman_image_t *pix,
bg = color_hex_to_pixman(term->cursor_color.cursor); 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); struct font *font = attrs_to_font(term, &cell->attrs);
const struct glyph *glyph = font_glyph_for_wc(font, cell->wc); 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 */ /* Non-block cursors */
if (has_cursor && !block_cursor) { if (has_cursor && !block_cursor) {
pixman_color_t cursor_color = term->cursor_color.text >> 31 pixman_color_t cursor_color;
? color_hex_to_pixman(term->cursor_color.cursor) if (term->cursor_color.text >> 31) {
: fg; 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) if (term->cursor_style == CURSOR_BAR)
draw_bar(term, pix, &cursor_color, x, y); draw_bar(term, pix, &cursor_color, x, y);
@ -435,9 +444,10 @@ grid_render(struct terminal *term)
term_damage_view(term); term_damage_view(term);
/* If we resized the window, or is flashing, or just stopped flashing */ /* 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) { if (term->render.last_buf != buf ||
LOG_DBG("new buffer"); 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 */ /* Fill area outside the cell grid with the default background color */
int rmargin = term->x_margin + term->cols * term->cell_width; int rmargin = term->x_margin + term->cols * term->cell_width;
int bmargin = term->y_margin + term->rows * term->cell_height; 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; int bmargin_height = term->height - bmargin;
uint32_t _bg = !term->reverse ? term->colors.bg : term->colors.fg; 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); 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_image_fill_rectangles(
PIXMAN_OP_SRC, pix, &bg, 4, PIXMAN_OP_SRC, pix, &bg, 4,
(pixman_rectangle16_t[]){ (pixman_rectangle16_t[]){
@ -469,6 +481,7 @@ grid_render(struct terminal *term)
term->render.last_buf = buf; term->render.last_buf = buf;
term->render.was_flashing = term->flash.active; term->render.was_flashing = term->flash.active;
term->render.was_searching = term->is_searching;
} }
tll_foreach(term->grid->scroll_damage, it) { tll_foreach(term->grid->scroll_damage, it) {
@ -626,6 +639,7 @@ grid_render(struct terminal *term)
if (term->flash.active) { if (term->flash.active) {
/* Note: alpha is pre-computed in each color component */ /* Note: alpha is pre-computed in each color component */
/* TODO: dim while searching */
pixman_image_fill_rectangles( pixman_image_fill_rectangles(
PIXMAN_OP_OVER, pix, PIXMAN_OP_OVER, pix,
&(pixman_color_t){.red=0x7fff, .green=0x7fff, .blue=0, .alpha=0x7fff}, &(pixman_color_t){.red=0x7fff, .green=0x7fff, .blue=0, .alpha=0x7fff},

107
search.c Normal file
View 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
View 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);

View file

@ -331,6 +331,13 @@ struct terminal {
struct primary primary; struct primary primary;
} selection; } selection;
bool is_searching;
struct {
wchar_t *buf;
size_t len;
size_t sz;
} search;
struct grid normal; struct grid normal;
struct grid alt; struct grid alt;
struct grid *grid; struct grid *grid;
@ -368,6 +375,7 @@ struct terminal {
struct buffer *last_buf; /* Buffer we rendered to last time */ struct buffer *last_buf; /* Buffer we rendered to last time */
bool was_flashing; /* Flash was active last time we rendered */ bool was_flashing; /* Flash was active last time we rendered */
bool was_searching;
} render; } render;
}; };