чување 86009e3391213808265968589078d47da34ddb69
родитељ f5dcf0b4db24a51c1cab5dc7c4350147677c5fe9
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Fri, 9 Jul 2021 18:29:17 +0200
Finalized search support
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | TODO | | | 6 | +++--- |
| M | config.def.h | | | 2 | ++ |
| M | config.h | | | 2 | ++ |
| M | draw.c | | | 109 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------- |
| M | draw.h | | | 6 | ++++-- |
| M | poe.c | | | 88 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
измењених датотека: 6, додавања: 177(+), брисања: 36(-)
diff --git a/TODO b/TODO
@@ -14,10 +14,10 @@
[ ] Handle #~ (Don't show; flag? But write to file)
- [~] Search (highlight=/, then navigate with next/prev)
+ [x] Search (highlight=/, then navigate with next/prev)
[x] Search input
- [ ] Search highlighting
- [ ] Go to prev/next match
+ [x] Search highlighting
+ [x] Go to prev/next match
[ ] Sort by flag/column?
diff --git a/config.def.h b/config.def.h
@@ -43,6 +43,8 @@
#define SEARCH_BG TB_WHITE
#define SEARCH_EDIT_FG TB_WHITE | TB_BOLD
#define SEARCH_EDIT_BG TB_BLACK
+#define SEARCH_HL_FG TB_WHITE | TB_BOLD
+#define SEARCH_HL_BG TB_GREEN
#define SHADOW_FG TB_BLACK
#define SHADOW_BG TB_BLACK | TB_BOLD
#define TITLE_FG TB_BLACK
diff --git a/config.h b/config.h
@@ -43,6 +43,8 @@
#define SEARCH_BG TB_WHITE
#define SEARCH_EDIT_FG TB_WHITE | TB_BOLD
#define SEARCH_EDIT_BG TB_BLACK
+#define SEARCH_HL_FG TB_WHITE | TB_BOLD
+#define SEARCH_HL_BG TB_GREEN
#define SHADOW_FG TB_BLACK
#define SHADOW_BG TB_BLACK | TB_BOLD
#define TITLE_FG TB_BLACK
diff --git a/draw.c b/draw.c
@@ -279,18 +279,23 @@ draw_box(const int startx, const int endx, const int starty, const int endy,
* counted from the start of the string; an "entry point" joining string
* index with screen
* fill - boolean; 1 = fill fc, 0 = don't fill fc
+ * srch - search string; if empty or NULL no highlighting happens
+ * sfg - fg color of search highlght
+ * sbg - bg color of search highlight
* */
const char*
draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
const char* s, const int mc, const int fc,
const int p_l, const int p_r,
- const Alignment align, const int ds, const int fill)
+ const Alignment align, const int ds, const int fill,
+ const uint32_t* srch, const uint16_t sfg, const uint16_t sbg)
{
uint32_t* us = calloc(strlen(s)+1, sizeof(uint32_t));
if (!us)
return NULL;
u8_string_to_unicode(us, s, mc);
- u32_draw_string(x, y, fg, bg, us, mc, fc, p_l, p_r, align, ds, fill);
+ u32_draw_string(x, y, fg, bg, us, mc, fc, p_l, p_r, align, ds, fill,
+ srch, sfg, sbg);
free(us);
return s;
}
@@ -303,12 +308,16 @@ draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
* counted from the start of the string; an "entry point" joining string
* index with screen
* fill - boolean; 1 = fill fc, 0 = don't fill fc
+ * srch - search string; if empty or NULL no highlighting happens
+ * sfg - fg color of search highlght
+ * sbg - bg color of search highlight
* */
void
u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
const uint32_t* s, const int mc, const int fc,
const int p_l, const int p_r,
- const Alignment align, const int ds, const int fill)
+ const Alignment align, const int ds, const int fill,
+ const uint32_t* srch, const uint16_t sfg, const uint16_t sbg)
{
/*
@@ -348,6 +357,13 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
const uint32_t* ps = s; /* pointer to current character in string;
* string index: ps-s */
+ uint16_t cfg = fg; /* current fg */
+ uint16_t cbg = bg; /* current bg */
+
+ int hctl = 0; /* highlight "characters to live", when this
+ * reaches zero the highlighting is turned
+ * off */
+
c = mc - p_l - p_r;
if (align == LEFT)
@@ -379,6 +395,16 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
* */
while (ps && *ps && sc < c)
{
+ if (srch && *srch && hctl == 0)
+ {
+ if (u32_starts_with(ps, srch))
+ {
+ hctl = u32_strlen(srch);
+ cfg = sfg;
+ cbg = sbg;
+ }
+ }
+
if (*ps == '\t')
{
if (ssc < ds)
@@ -396,8 +422,11 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
for (int j = 0; j < ssc-(ssc%ts)+ts-ds;
j++)
tb_change_cell(x+d+p_l+sc+j, y,
- ' ', fg, bg);
+ ' ', cfg, cbg);
sc += ssc+(ts - (ssc % ts))-ds;
+ hctl -= ssc+(ts - (ssc % ts))-ds;
+ if (hctl < 0)
+ hctl = 0;
}
/* else, just increase counter
*
@@ -424,25 +453,31 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
{
for (int j = 0; j < ds+c-ssc; j++)
tb_change_cell(x+d+p_l+sc+j,
- y, ' ', fg, bg);
+ y, ' ', cfg, cbg);
sc = c;
ssc = ds+c;
+ hctl = 0;
+ cfg = fg;
+ cbg = bg;
}
else /* ssc+(ts-(ssc%ts)) < ds+c */
{
/*
* \t
* [ :::::::::::|::: ]-----
- * | | | |
- * | | | ds+c
- * | | ssc+(ts-(ssc%ts))
- * | ssc
- * ds
+ * | | | |
+ * | | | ds+c
+ * | | ssc+(ts-(ssc%ts))
+ * | ssc
+ * ds
* */
for (int j = 0; j < ts-(ssc%ts); j++)
tb_change_cell(x+d+p_l+sc+j,
- y, ' ', fg, bg);
+ y, ' ', cfg, cbg);
sc += ts-(ssc%ts);
+ hctl -= ts-(ssc%ts);
+ if (hctl < 0)
+ hctl = 0;
ssc += ts-(ssc%ts);
}
}
@@ -453,11 +488,19 @@ u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
{
if (sc < c)
tb_change_cell(x+d+p_l+sc, y, *ps,
- fg, bg);
+ cfg, cbg);
sc++;
+ hctl--;
+ if (hctl < 0)
+ hctl = 0;
}
ssc++;
}
+ if (hctl == 0)
+ {
+ cfg = fg;
+ cbg = bg;
+ }
ps++;
}
@@ -489,12 +532,13 @@ draw_help(const struct DrawState* state)
draw_box(startx, endx, starty, endy, DLG_FG, DLG_BG);
if (!draw_string(startx, starty, TITLE_FG, TITLE_BG,
help_title, strlen(help_title)+2, w-2, 1, 1, CENTER,
- 0, 0))
+ 0, 0, NULL, 0, 0))
return NULL;
while (row < LEN(help))
{
if (!draw_string(startx+1, starty+1+row, DLG_FG, DLG_BG,
- help[row], w-2, w-2, 2, 2, LEFT, 0, 1))
+ help[row], w-2, w-2, 2, 2, LEFT, 0, 1,
+ NULL, 0, 0))
return NULL;
row++;
}
@@ -529,7 +573,7 @@ draw_editbox(const struct DrawState* state)
draw_box(startx, endx, starty, endy, DLG_FG, DLG_BG);
if (!draw_string(startx+1, starty, TITLE_FG, TITLE_BG,
editbox_title, strlen(editbox_title)+2, w-2, 1, 1,
- CENTER, 0, 0))
+ CENTER, 0, 0, NULL, 0, 0))
return NULL;
uint16_t fg = state->edit_info_focused ? EDIT_MSGID_FOCUS_FG :
@@ -553,15 +597,17 @@ draw_editbox(const struct DrawState* state)
curline->bg == 0 ? bg : curline->bg,
curline->text,
w-2, w-2, 1, 1, LEFT,
- state->info_first_shown_column, 1);
+ state->info_first_shown_column, 1,
+ NULL, 0, 0);
}
if (state->info_first_shown_row > 0)
u32_draw_string(endx-2, starty+1, fg, bg, (uint32_t*)L"\u2191",
- 1, 1, 0, 0, LEFT, 0, 0);
+ 1, 1, 0, 0, LEFT, 0, 0, NULL, 0, 0);
if (state->info_first_shown_row + (h-3)/2 < state->info_rows_count)
u32_draw_string(endx-2, starty+(h-3)/2, fg, bg,
- (uint32_t*)L"\u2193", 1, 1, 0, 0, LEFT, 0, 0);
+ (uint32_t*)L"\u2193", 1, 1, 0, 0, LEFT, 0, 0,
+ NULL, 0, 0);
fg = state->edit_info_focused ? EDIT_MSGSTR_FG :
EDIT_MSGSTR_FOCUS_FG;
@@ -582,7 +628,7 @@ draw_editbox(const struct DrawState* state)
u32_draw_string(startx+1, endy-h/2-1+i,
fg, bg, curline->text,
w-2, w-2, 1, 1, LEFT,
- state->input_first_shown_column, 1);
+ state->input_first_shown_column, 1, NULL, 0, 0);
}
if (state->edit_info_focused)
@@ -611,11 +657,12 @@ draw_editbox(const struct DrawState* state)
state->input_first_shown_row,
state->input_rows_count);
draw_string(startx+1, endy-2, DLG_FG, DLG_BG,
- sbuf, strlen(sbuf)+2, w-2, 1, 1, LEFT, 0, 0);
+ sbuf, strlen(sbuf)+2, w-2, 1, 1, LEFT, 0, 0,
+ NULL, 0, 0);
if (entry->flags != FL_NONE)
if (!draw_string(endx-MAXFLAGSBUF-4-5, endy-2, DLG_FG, DLG_BG,
flags_buf, MAXFLAGSBUF+4-1, MAXFLAGSBUF+4-1, 0,
- 0, LEFT, 0, 0))
+ 0, LEFT, 0, 0, NULL, 0, 0))
return NULL;
return state;
}
@@ -645,7 +692,7 @@ draw_search(const struct DrawState* state)
u32_draw_string(startx+1, starty+1,
SEARCH_EDIT_FG, SEARCH_EDIT_BG, state->search,
w-2, w-2, 1, 1, LEFT, state->search_first_shown_column,
- 1);
+ 1, NULL, 0, 0);
tb_set_cursor(startx+2+state->search_display_column -
state->search_first_shown_column,
starty+1);
@@ -667,14 +714,15 @@ draw_status(const struct DrawState* state)
{
if (!draw_string(0, state->maxy-1, PROMPT_FG, PROMPT_BG,
state->prompt, strlen(state->prompt)+2,
- state->maxx, 1, 1, CENTER, 0, 1))
+ state->maxx, 1, 1, CENTER, 0, 1, NULL, 0, 0))
return NULL;
}
else if (state->error && state->error[0])
{
if (!draw_string(0, state->maxy-1, ERROR_FG, ERROR_BG,
state->error, strlen(state->error)+2,
- state->maxx, 1, 1, CENTER, 0, 1))
+ state->maxx, 1, 1, CENTER, 0, 1, NULL,
+ 0, 0))
return NULL;
}
else
@@ -692,7 +740,8 @@ draw_status(const struct DrawState* state)
if (!draw_string(current_start, state->maxy-1, pseg->fg,
pseg->bg, buf,
MIN(seg_size, strlen(buf)+2), seg_size,
- 1, 1, pseg->alignment, 0, 1))
+ 1, 1, pseg->alignment, 0, 1, NULL,
+ 0, 0))
return NULL;
pseg++;
current_start += seg_size;
@@ -730,7 +779,7 @@ draw_list_visible(const struct DrawState* state)
if (!draw_string(0, cy, sel ? LIST_FLAGS_SEL_FG : LIST_FLAGS_FG,
sel ? LIST_FLAGS_SEL_BG : LIST_FLAGS_BG,
flags_buf, MAXFLAGSBUF-1+2, MAXFLAGSBUF-1+2,
- 2, 0, LEFT, 0, 1))
+ 2, 0, LEFT, 0, 1, NULL, 0, 0))
return NULL;
/* TODO: Highlight */
if (current->msgid)
@@ -740,7 +789,8 @@ draw_list_visible(const struct DrawState* state)
current->msgid,
state->maxx/2-MAXFLAGSBUF+1-2,
state->maxx/2-MAXFLAGSBUF+1-2, 2, 0,
- LEFT, 0, 1);
+ LEFT, 0, 1, state->search, SEARCH_HL_FG,
+ SEARCH_HL_BG);
else if (current == state->entries) /* special */
draw_string(MAXFLAGSBUF-1+2, cy, sel ?
LIST_MSGID_SPECIAL_SEL_FG :
@@ -750,7 +800,7 @@ draw_list_visible(const struct DrawState* state)
first_entry_msgid,
state->maxx/2-MAXFLAGSBUF+1-2,
state->maxx/2-MAXFLAGSBUF+1-2, 2, 0,
- LEFT, 0, 1);
+ LEFT, 0, 1, NULL, 0, 0);
/* don't use msgstr_index as then the entire list will shift
* when changing currently displayed plural form msgstr in an
@@ -765,7 +815,8 @@ draw_list_visible(const struct DrawState* state)
*(current->msgstr /*+
state->msgstr_index*/),
state->maxx/2, state->maxx/2, 2, 2,
- LEFT, 0, 1);
+ LEFT, 0, 1, state->search, SEARCH_HL_FG,
+ SEARCH_HL_BG);
i++;
cy++;
}
diff --git a/draw.h b/draw.h
@@ -102,11 +102,13 @@ void draw_box(const int startx, const int endx, const int starty,
const char* draw_string(const int x, const int y, const uint16_t fg, const
uint16_t bg, const char* s, const int max_cols, const int
fill_cols, const int padding_left, const int padding_right,
- const Alignment align, const int ds, const int fill);
+ const Alignment align, const int ds, const int fill,
+ const uint32_t* srch, const uint16_t sfg, const uint16_t sbg);
void u32_draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg,
const uint32_t* s, const int max_cols, const int fill_cols,
const int padding_left, const int padding_right,
- const Alignment align, const int ds, const int fill);
+ const Alignment align, const int ds, const int fill,
+ const uint32_t* srch, const uint16_t sfg, const uint16_t sbg);
const struct DrawState* draw_help(const struct DrawState* state);
const struct DrawState* draw_editbox(const struct DrawState* state);
const struct DrawState* draw_search(const struct DrawState* state);
diff --git a/poe.c b/poe.c
@@ -45,6 +45,8 @@ void erase_search_backwards(struct DrawState* state);
void erase_search_forward(struct DrawState* state);
void erase_search_to_start(struct DrawState* state);
void erase_search_to_end(struct DrawState* state);
+void next_match(struct DrawState* state);
+void prev_match(struct DrawState* state);
void next_untranslated(struct DrawState* state);
void next_fuzzy(struct DrawState* state);
void move_up(struct DrawState* state);
@@ -637,6 +639,78 @@ erase_search_to_end(struct DrawState* state)
}
void
+next_match(struct DrawState* state)
+{
+ if (state->msgid_count == 0 || !state->search || !*state->search)
+ return;
+
+ state->error[0] = 0;
+ struct PoEntry* current = NULL;
+ for (size_t e = state->msgid_number;
+ e < state->msgid_count; e++)
+ {
+ current = state->entries + e;
+ if ((current->msgid && *current->msgid &&
+ u32_strstr(current->msgid, state->search))
+ || (current->msgstr && *current->msgstr &&
+ **current->msgstr && u32_strstr(*current->msgstr,
+ state->search)))
+ {
+ /* TODO: Have this as a separate function */
+ state->msgid_number = e + 1;
+ if (state->msgid_number < (state->maxy-1)/2)
+ state->first_shown_msgid =
+ state->msgid_count > 0 ? 1 : 0;
+ else if (state->msgid_count - state->msgid_number <
+ (state->maxy-1)/2)
+ state->first_shown_msgid =
+ state->msgid_count - (state->maxy-2);
+ else
+ state->first_shown_msgid = state->msgid_number
+ - (state->maxy-1)/2;
+
+ return;
+ }
+ }
+}
+
+void
+prev_match(struct DrawState* state)
+{
+ if (state->msgid_count == 0 || !state->search || !*state->search)
+ return;
+
+ state->error[0] = 0;
+ struct PoEntry* current = NULL;
+ for (size_t e = state->msgid_number-1;
+ e > 0; e--)
+ {
+ current = state->entries + e-1;
+ if ((current->msgid && *current->msgid &&
+ u32_strstr(current->msgid, state->search))
+ || (current->msgstr && *current->msgstr &&
+ **current->msgstr && u32_strstr(*current->msgstr,
+ state->search)))
+ {
+ /* TODO: Have this as a separate function */
+ state->msgid_number = e;
+ if (state->msgid_number < (state->maxy-1)/2)
+ state->first_shown_msgid =
+ state->msgid_count > 0 ? 1 : 0;
+ else if (state->msgid_count - state->msgid_number <
+ (state->maxy-1)/2)
+ state->first_shown_msgid =
+ state->msgid_count - (state->maxy-2);
+ else
+ state->first_shown_msgid = state->msgid_number
+ - (state->maxy-1)/2;
+
+ return;
+ }
+ }
+}
+
+void
next_untranslated(struct DrawState* state)
{
if (state->msgid_count == 0)
@@ -1366,7 +1440,7 @@ handle_editbox_key_event(struct tb_event* ev, struct DrawState* state)
insert_char(state, ' ');
else if (ev->key == TB_KEY_TAB)
insert_char(state, '\t');
- else
+ else if (ev->ch != 0)
insert_char(state, ev->ch);
}
@@ -1492,6 +1566,12 @@ handle_key_event(struct tb_event* ev, struct DrawState* state)
state->show_help = 1;
state->error[0] = 0;
}
+ else if (ev->key == TB_KEY_F3
+ || ev->ch == 'n')
+ next_match(state);
+ else if (ev->key == TB_KEY_F4
+ || ev->ch == 'N')
+ prev_match(state);
else if (ev->key == TB_KEY_F7 || ev->ch == '/')
show_search(state);
else if (ev->key == TB_KEY_F8 || ev->ch == 'u')
@@ -1530,6 +1610,10 @@ handle_search_key_event(struct tb_event* ev, struct DrawState* state)
hide_search(state);
else if (ev->key == TB_KEY_ESC)
cancel_search(state);
+ else if (ev->key == TB_KEY_F3)
+ next_match(state);
+ else if (ev->key == TB_KEY_F4)
+ prev_match(state);
else if (ev->key == TB_KEY_HOME
|| ev->key == TB_KEY_CTRL_A)
move_search_start(state);
@@ -1537,7 +1621,7 @@ handle_search_key_event(struct tb_event* ev, struct DrawState* state)
insert_search_char(state, ' ');
else if (ev->key == TB_KEY_TAB)
insert_search_char(state, '\t');
- else
+ else if (ev->ch != 0)
insert_search_char(state, ev->ch);
}