From 61cabdac13986e6cb2ba69e81d5934f55d92a1a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20Ekl=C3=B6f?= Date: Tue, 27 Aug 2019 17:23:28 +0200 Subject: [PATCH] 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. --- input.c | 18 +++++++-- meson.build | 1 + render.c | 28 ++++++++++---- search.c | 107 ++++++++++++++++++++++++++++++++++++++++++++++++++++ search.h | 8 ++++ terminal.h | 8 ++++ 6 files changed, 160 insertions(+), 10 deletions(-) create mode 100644 search.c create mode 100644 search.h diff --git a/input.c b/input.c index dc48b44d..4384cead 100644 --- a/input.c +++ b/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++) { diff --git a/meson.build b/meson.build index edf354b2..01a85cc8 100644 --- a/meson.build +++ b/meson.build @@ -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', diff --git a/render.c b/render.c index 84c86232..990726d8 100644 --- a/render.c +++ b/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}, diff --git a/search.c b/search.c new file mode 100644 index 00000000..55c67bb0 --- /dev/null +++ b/search.c @@ -0,0 +1,107 @@ +#include "search.h" + +#include +#include + +#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); +} diff --git a/search.h b/search.h new file mode 100644 index 00000000..4ea59c1f --- /dev/null +++ b/search.h @@ -0,0 +1,8 @@ +#pragma once + +#include +#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); diff --git a/terminal.h b/terminal.h index 6f373a14..fbd734bc 100644 --- a/terminal.h +++ b/terminal.h @@ -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; };