poe

Уређивач .po фајлова
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 86009e3391213808265968589078d47da34ddb69
родитељ f5dcf0b4db24a51c1cab5dc7c4350147677c5fe9
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Fri,  9 Jul 2021 18:29:17 +0200

Finalized search support

Signed-off-by: Страхиња Радић <contact@strahinja.org>

Diffstat:
MTODO | 6+++---
Mconfig.def.h | 2++
Mconfig.h | 2++
Mdraw.c | 109++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------------------
Mdraw.h | 6++++--
Mpoe.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); }