poe

Уређивач .po фајлова
git clone https://git.sr.ht/~strahinja/poe
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување f6f9901bb8fca08022cf698e6fc267fc3c9d15dc
родитељ 9f5ea057100f4dd7471d0c5b48e86da92a7466bd
Аутор: Страхиња Радић <sr@strahinja.org>
Датум:   Fri, 20 Feb 2026 14:05:01 +0100

Remove dirty_before_edit, introduce edit_dirty; fix related logic

Diffstat:
MTODO | 4++--
Mdraw.c | 7++++---
Mdraw.h | 9+++++----
Mpo.h | 3+--
Mpoe.c | 250++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Mpoe.h | 7+++++++
Mutil.c | 11+++++------
измењених датотека: 7, додавања: 203(+), брисања: 88(-)

diff --git a/TODO b/TODO @@ -1,14 +1,14 @@ TODO ==== -[~] Tidy up basic logic everywhere (based on sled) +[x] Tidy up basic logic everywhere (based on sled) [x] Check cleanness against sled, function-by-function [x] draw.c [x] poe.c [x] po.c [x] util.c [x] Investigate insert_char - [ ] Revise dirty <-> dirty_before_edit and the interaction with keys + [x] Revise dirty <-> dirty_before_edit and the interaction with keys [x] Copy join_lines from sled's simple_join_lines [x] str* -> memccpy [x] Tidy up return codes and error handling diff --git a/draw.c b/draw.c @@ -70,7 +70,7 @@ const char* flag_strings[] = { [FL_FUZZY] = "fuzzy"}; const char* first_entry_msgid = "*** SPECIAL: file info ***"; const char* prompt_dirty = "File changed, save [y/n/ESC]?"; -const char* prompt_cancel_dirty = "Entry changed, save [y/n/ESC]?"; +const char* prompt_edit_dirty = "Entry changed, save [y/n/ESC]?"; const char* prompt_overwrite = "Not empty, overwrite? [y/n/ESC]?"; /* clang-format on */ @@ -622,7 +622,7 @@ format_filename(char* result, ssize_t result_size, const char* format, pbase = u8_basename(state->filename); basename = strndup(pbase, strlen(pbase) + 1); - dirty = (state->show_edit && state->dirty_before_edit) || state->dirty; + dirty = state->edit_dirty || state->dirty; if ((ssize_t)(u8_strlen(basename) + 2) >= seg_size) { if (dirty) @@ -743,9 +743,10 @@ init_drawstate(struct DrawState* state, char* filename, char* prompt) state->prompt_callback = NULL; state->running = 1; state->dirty = 0; - state->dirty_before_edit = 0; + state->edit_dirty = 0; state->fuzzy_before_edit = 0; state->in_prompt = 0; + state->reshow_edit = 0; state->show_edit = 0; state->show_help = 0; state->edit_info_focused = 0; diff --git a/draw.h b/draw.h @@ -100,8 +100,8 @@ struct DrawState { struct Coord coord; /* buffer coordinates */ struct Coord first_shown; /* display coordinates */ struct Coord input_first_shown; /* display coordinates */ - ssize_t input_rows_count; /* buffer parameter */ - int input_display_column; /* display coordinate */ + ssize_t input_rows_count; /* buffer parameter */ + int input_display_column; /* display coordinate */ FlagChange input_changed_fuzzy; int saved_column; /* display coordinate */ struct BufferLine* info_buffer; /* information pane above @@ -122,10 +122,11 @@ struct DrawState { int nplurals; int (*prompt_callback)(struct DrawState*, struct tb_event*); int running; - int dirty; - int dirty_before_edit; + int dirty; /* tracking changes in the file */ + int edit_dirty; /* tracking changes in the edit box */ ssize_t fuzzy_before_edit; int in_prompt; + int reshow_edit; int show_edit; int show_help; int edit_info_focused; diff --git a/po.h b/po.h @@ -102,8 +102,7 @@ int set_nplurals(struct DrawState* state, struct PoEntry* entry); int set_plural_forms(struct DrawState* state, struct PoEntry* entry, const char* plural_forms, int append); int u32_add_comment(struct PoEntry* entry, const uint32_t* comment); -int u32_add_extr_comment(struct PoEntry* entry, - const uint32_t* extr_comment); +int u32_add_extr_comment(struct PoEntry* entry, const uint32_t* extr_comment); int u32_set_msgid(struct DrawState* state, struct PoEntry* entry, const uint32_t* msgid, ssize_t msgid_size, int append); int u32_set_msgid_plural(struct DrawState* state, struct PoEntry* entry, diff --git a/poe.c b/poe.c @@ -41,17 +41,23 @@ extern const char* errors[]; extern const char* actions[]; extern const char* prompt_dirty; -extern const char* prompt_cancel_dirty; +extern const char* prompt_edit_dirty; extern const char* prompt_overwrite; static int cancel_callback(struct DrawState* state, struct tb_event* ev) { assert((state != NULL) && (ev != NULL)); - if (ev->ch == 'y') + if (strchr("Yy", ev->ch)) + { + state->reshow_edit = 0; save_msgstr(state); - else + } + else /* not saving */ + { + state->edit_dirty = 0; cancel_msgstr(state); + } state->prompt_callback = NULL; return 0; } @@ -83,12 +89,10 @@ cancel_msgstr(struct DrawState* state) ssize_t i; assert(state != NULL); - if (!state->in_prompt - && (state->dirty - || (state->show_edit && state->dirty_before_edit))) + if (state->edit_dirty) { state->in_prompt = 1; - MEMCCPY(state->prompt, prompt_cancel_dirty, LINE_DEFAULT, temp); + MEMCCPY(state->prompt, prompt_edit_dirty, LINE_DEFAULT, temp); state->prompt_callback = cancel_callback; return 0; } @@ -107,7 +111,6 @@ cancel_msgstr(struct DrawState* state) free(state->info_buffer); state->info_buffer = NULL; state->info_rows_count = 0; - state->dirty = state->dirty_before_edit; state->fuzzy_count = state->fuzzy_before_edit; switch (state->input_changed_fuzzy) { @@ -205,14 +208,14 @@ copy_msgid_to_input(struct DrawState* state) len = u32_next_line(current->msgid, &pmsgid, 0, 0); u32_strncpy(pbuffer->text, old_pmsgid, MIN(len + 1, LINE_DEFAULT)); - newlen = u32_decode_tabs(state, pbuffer->text, LINE_DEFAULT); + newlen = u32_decode_tabs(state, pbuffer->text, LINE_DEFAULT); pbuffer->length = newlen; pbuffer++; } state->input_rows_count = msgid_num_lines; state->input_buffer = newbuf; - state->dirty = 1; + state->edit_dirty = 1; return 0; } @@ -317,6 +320,7 @@ dirname(char* dir, char* path, const ssize_t dir_size) static int edit_page_down(struct DrawState* state) { + char* temp = NULL; assert(state != NULL); if (state->edit_info_focused) { @@ -325,18 +329,36 @@ edit_page_down(struct DrawState* state) state->info_first_shown.row += (EDIT_HEIGHT - 3) / 2; return 0; } - if (state->dirty) - save_msgstr(state); - else /* No need to call cancel_msgstr */ - state->dirty = state->dirty_before_edit; + if (state->edit_dirty) + { + state->in_prompt = 1; + MEMCCPY(state->prompt, prompt_edit_dirty, LINE_DEFAULT, temp); + state->prompt_callback = edit_page_down_callback; + return 0; + } move_list_down(state); state->msgstr_index = 0; + state->reshow_edit = state->show_edit; return show_edit(state); } static int +edit_page_down_callback(struct DrawState* state, struct tb_event* ev) +{ + assert((state != NULL) && (ev != NULL)); + if (strchr("Yy", ev->ch)) + { + state->reshow_edit = state->show_edit; + save_msgstr(state); + } + state->edit_dirty = 0; + return edit_page_down(state); +} + +static int edit_page_up(struct DrawState* state) { + char* temp = NULL; assert(state != NULL); if (state->edit_info_focused) { @@ -346,16 +368,32 @@ edit_page_up(struct DrawState* state) move_start(state); return 0; } - if (state->dirty) - save_msgstr(state); - else /* No need to call cancel_msgstr */ - state->dirty = state->dirty_before_edit; + if (state->edit_dirty) + { + state->in_prompt = 1; + MEMCCPY(state->prompt, prompt_edit_dirty, LINE_DEFAULT, temp); + state->prompt_callback = edit_page_up_callback; + return 0; + } move_list_up(state); state->msgstr_index = 0; return show_edit(state); } static int +edit_page_up_callback(struct DrawState* state, struct tb_event* ev) +{ + assert((state != NULL) && (ev != NULL)); + if (strchr("Yy", ev->ch)) + { + state->reshow_edit = state->show_edit; + save_msgstr(state); + } + state->edit_dirty = 0; + return edit_page_up(state); +} + +static int erase_backwards(struct DrawState* state) { struct BufferLine* buffer_line; @@ -380,7 +418,7 @@ erase_backwards(struct DrawState* state) buffer_line->text[i - 1] = 0; buffer_line->length--; position_to(state, state->coord.row, state->coord.col - 1); - state->dirty = 1; + state->edit_dirty = 1; } else if (state->coord.row > 0) { @@ -416,7 +454,7 @@ erase_forward(struct DrawState* state) } buffer_line->text[i] = 0; buffer_line->length--; - state->dirty = 1; + state->edit_dirty = 1; } else if (state->coord.row < state->input_rows_count - 1) { @@ -469,7 +507,7 @@ erase_prev_word(struct DrawState* state) state->coord.col); if (state->input_display_column < state->input_first_shown.col) state->input_first_shown.col = state->input_display_column; - state->dirty = 1; + state->edit_dirty = 1; return 0; } @@ -588,7 +626,7 @@ erase_to_end(struct DrawState* state) buffer_line->text[state->coord.col] = 0; buffer_line->length = state->coord.col; move_end(state); - state->dirty = 1; + state->edit_dirty = 1; return 0; } @@ -619,7 +657,7 @@ erase_to_start(struct DrawState* state) buffer_line->text[len - state->coord.col] = 0; buffer_line->length = len - state->coord.col; move_start(state); - state->dirty = 1; + state->edit_dirty = 1; return 0; } @@ -629,7 +667,13 @@ exit_program(struct DrawState* state) char* temp = NULL; assert(state != NULL); - if (state->dirty || (state->show_edit && state->dirty_before_edit)) + if (state->edit_dirty) + { + state->in_prompt = 1; + MEMCCPY(state->prompt, prompt_edit_dirty, LINE_DEFAULT, temp); + state->prompt_callback = quit_callback; + } + else if (state->dirty) { state->in_prompt = 1; MEMCCPY(state->prompt, prompt_dirty, LINE_DEFAULT, temp); @@ -852,7 +896,7 @@ insert_char(struct DrawState* state, uint32_t ch) position_to(state, state->coord.row, state->coord.col + 1); if (add_null) buffer_line->text[state->coord.col] = 0; - state->dirty = 1; + state->edit_dirty = 1; return 0; insert_char_alloc_error: @@ -922,7 +966,7 @@ insert_line(struct DrawState* state) state->input_first_shown.row = state->coord.row - (EDIT_HEIGHT - 3) / 2; move_start(state); - state->dirty = 1; + state->edit_dirty = 1; return 0; insert_line_alloc_error: @@ -1027,7 +1071,7 @@ join_lines(struct DrawState* state) } free_bufferline(&state->input_buffer[state->input_rows_count - 1]); state->input_rows_count--; - state->dirty = 1; + state->edit_dirty = 1; return 0; join_lines_alloc_error: @@ -1226,7 +1270,7 @@ load_info_msgid(struct DrawState* state, struct BufferLine** lines) ENSURE_SIZE((*lines)->text, ptext, (*lines)->size, size, size, load_info_msgid_alloc_error, uint32_t); U32_MEMCCPY((*lines)->text, old_pumsgid, len + 1, ptext); - llen = u32_decode_tabs(state, (*lines)->text, len + 1); + llen = u32_decode_tabs(state, (*lines)->text, len + 1); (*lines)->length = llen; if (llen > state->info_maxlen) state->info_maxlen = llen; @@ -1695,35 +1739,32 @@ static int next_fuzzy(struct DrawState* state) { struct PoEntry* current = NULL; + char* temp = NULL; ssize_t e; - int saved_show_edit; assert(state != NULL); if (state->msgid_count == 0) return 1; + if (state->edit_dirty) + { + state->in_prompt = 1; + MEMCCPY(state->prompt, prompt_edit_dirty, LINE_DEFAULT, temp); + state->prompt_callback = next_fuzzy_callback; + return 0; + } + for (e = state->msgid_number; e < state->msgid_count; e++) { - current = state->entries + e; + current = &state->entries[e]; if (current->flags & FL_FUZZY) { - saved_show_edit = state->show_edit; - if (saved_show_edit) - { - if (state->dirty) - save_msgstr(state); - else /* No need to call cancel_msgstr */ - state->dirty = state->dirty_before_edit; - } - goto_msgid(state, e + 1); - - if (saved_show_edit) + if (state->show_edit) { state->msgstr_index = 0; show_edit(state); } - return 0; } } @@ -1731,6 +1772,19 @@ next_fuzzy(struct DrawState* state) } static int +next_fuzzy_callback(struct DrawState* state, struct tb_event* ev) +{ + assert((state != NULL) && (ev != NULL)); + if (strchr("Yy", ev->ch)) + { + state->reshow_edit = state->show_edit; + save_msgstr(state); + } + state->edit_dirty = 0; + return next_fuzzy(state); +} + +static int next_match(struct DrawState* state) { struct PoEntry* current = NULL; @@ -1762,14 +1816,21 @@ static int next_plural(struct DrawState* state) { struct PoEntry* current = NULL; + char* temp = NULL; assert((state != NULL) && (state->entries != NULL)); if (state->edit_info_focused) { state->error = ERR_DLG_FOCUS_EDIT; return 1; } + if (state->edit_dirty) + { + state->in_prompt = 1; + MEMCCPY(state->prompt, prompt_edit_dirty, LINE_DEFAULT, temp); + state->prompt_callback = next_plural_callback; + return 0; + } current = &state->entries[state->msgid_number - 1]; - save_msgstr(state); if (state->msgstr_index + 1 < current->msgstr_count) state->msgstr_index++; show_edit(state); @@ -1777,43 +1838,68 @@ next_plural(struct DrawState* state) } static int +next_plural_callback(struct DrawState* state, struct tb_event* ev) +{ + assert((state != NULL) && (ev != NULL)); + if (strchr("Yy", ev->ch)) + { + state->reshow_edit = state->show_edit; + save_msgstr(state); + } + state->edit_dirty = 0; + return next_plural(state); +} + +static int next_untranslated(struct DrawState* state) { struct PoEntry* current = NULL; + char* temp = NULL; ssize_t e; - int saved_show_edit; + assert((state != NULL) && (state->entries != NULL)); if (state->msgid_count == 0) return 1; + + if (state->edit_dirty) + { + state->in_prompt = 1; + MEMCCPY(state->prompt, prompt_edit_dirty, LINE_DEFAULT, temp); + state->prompt_callback = next_untranslated_callback; + return 0; + } + for (e = state->msgid_number; e < state->msgid_count; e++) { current = state->entries + e; if (!current->msgstr || !*current->msgstr || u32_strlen(*current->msgstr) == 0) { - saved_show_edit = state->show_edit; - if (saved_show_edit) - { - if (state->dirty) - save_msgstr(state); - else /* No need to call cancel_msgstr */ - state->dirty = state->dirty_before_edit; - } - goto_msgid(state, e + 1); - - if (saved_show_edit) + if (state->show_edit) { state->msgstr_index = 0; show_edit(state); } - return 0; } } return 0; } +static int +next_untranslated_callback(struct DrawState* state, struct tb_event* ev) +{ + assert((state != NULL) && (ev != NULL)); + if (strchr("Yy", ev->ch)) + { + state->reshow_edit = state->show_edit; + save_msgstr(state); + } + state->edit_dirty = 0; + return next_untranslated(state); +} + static size_t next_msgid(struct DrawState* state, const int delta) { @@ -1900,7 +1986,7 @@ paste_paste_buffer_to_input(struct DrawState* state) state->input_display_column = 0; init_coord(&state->input_first_shown, 0, 0); state->input_rows_count = 1; - state->dirty = 1; + state->edit_dirty = 1; return 0; } @@ -1943,7 +2029,7 @@ paste_paste_buffer_to_input(struct DrawState* state) state->input_rows_count = state->paste_count; state->input_buffer = newbuf; - state->dirty = 1; + state->edit_dirty = 1; return 0; paste_paste_buffer_alloc_error: @@ -2106,19 +2192,39 @@ prev_msgid(struct DrawState* state, const int delta) static int prev_plural(struct DrawState* state) { + char* temp = NULL; assert(state != NULL); if (state->edit_info_focused) { state->error = ERR_DLG_FOCUS_EDIT; return 1; } - save_msgstr(state); + if (state->edit_dirty) + { + state->in_prompt = 1; + MEMCCPY(state->prompt, prompt_edit_dirty, LINE_DEFAULT, temp); + state->prompt_callback = prev_plural_callback; + return 0; + } if (state->msgstr_index > 0) state->msgstr_index--; show_edit(state); return 0; } +static int +prev_plural_callback(struct DrawState* state, struct tb_event* ev) +{ + assert((state != NULL) && (ev != NULL)); + if (strchr("Yy", ev->ch)) + { + state->reshow_edit = state->show_edit; + save_msgstr(state); + } + state->edit_dirty = 0; + return prev_plural(state); +} + int print_error(const int code, const char* msg, ...) { @@ -2145,7 +2251,7 @@ quit_callback(struct DrawState* state, struct tb_event* ev) { int result = 0; assert((state != NULL) && (ev != NULL)); - if (ev->ch == 'y') + if (strchr("Yy", ev->ch)) result = write_file(state); state->prompt_callback = NULL; state->running = 0; @@ -2179,7 +2285,10 @@ save_msgstr(struct DrawState* state) ssize_t i; assert(state != NULL); - state->show_edit = 0; + if (state->reshow_edit) + state->reshow_edit = 0; + else + state->show_edit = 0; state->edit_info_focused = 0; if (state->input_buffer) @@ -2218,16 +2327,16 @@ save_msgstr(struct DrawState* state) for (i = 0; i < state->info_rows_count; i++) free_bufferline(&state->info_buffer[i]); free(state->info_buffer); - state->dirty = (state->dirty_before_edit || state->dirty); - // state->dirty_before_edit = 0; + state->dirty = 1; + state->edit_dirty = 0; state->info_rows_count = 0; state->info_buffer = NULL; - if (u32_encode_tabs(state, to_save, to_save_size * sizeof(uint32_t)) < - 0) + if (u32_encode_tabs(state, to_save, to_save_size * sizeof(uint32_t)) < 0) goto save_msgstr_error; current = &state->entries[state->msgid_number - 1]; if (u32_match_msgid_ending(state, current->msgid, to_save, - to_save_size * sizeof(uint32_t)) < 0) + to_save_size * sizeof(uint32_t)) + < 0) goto save_msgstr_error; u32_set_msgstr(state, current, to_save, state->msgstr_index, 0); update_warning(current->msgid, to_save, &current->warning); @@ -2281,8 +2390,6 @@ show_edit(struct DrawState* state) return 1; } - state->dirty_before_edit = state->dirty; - state->dirty = 0; state->fuzzy_before_edit = state->fuzzy_count; state->input_changed_fuzzy = UNCHANGED; state->show_edit = 1; @@ -2347,7 +2454,7 @@ toggle_fuzzy(struct DrawState* state) else state->input_changed_fuzzy = CLEARED; } - state->dirty = 1; + state->edit_dirty = 1; } return 0; } @@ -2454,8 +2561,9 @@ write_file(struct DrawState* state) state->running = 0; return result; } - state->error = ERR_NONE; - state->dirty = 0; + state->error = ERR_NONE; + state->edit_dirty = 0; + state->dirty = 0; return 0; } diff --git a/poe.h b/poe.h @@ -10,7 +10,9 @@ static int copy_msgid_to_input(struct DrawState* state); int cp(const char* from, const char* to); static char* dirname(char* dir, char* path, const ssize_t dir_size); static int edit_page_down(struct DrawState* state); +static int edit_page_down_callback(struct DrawState* state, struct tb_event* ev); static int edit_page_up(struct DrawState* state); +static int edit_page_up_callback(struct DrawState* state, struct tb_event* ev); static int erase_backwards(struct DrawState* state); static int erase_forward(struct DrawState* state); static int erase_prev_word(struct DrawState* state); @@ -65,9 +67,13 @@ static int move_search_start(struct DrawState* state); static int move_start(struct DrawState* state); static int move_up(struct DrawState* state); static int next_fuzzy(struct DrawState* state); +static int next_fuzzy_callback(struct DrawState* state, struct tb_event* ev); static int next_match(struct DrawState* state); static int next_plural(struct DrawState* state); +static int next_plural_callback(struct DrawState* state, struct tb_event* ev); static int next_untranslated(struct DrawState* state); +static int next_untranslated_callback(struct DrawState* state, + struct tb_event* ev); static size_t next_msgid(struct DrawState* state, const int delta); static int overwrite_copy_msgid_callback(struct DrawState* state, struct tb_event* ev); @@ -79,6 +85,7 @@ static void position_to(struct DrawState* state, const int row, static int prev_match(struct DrawState* state); static size_t prev_msgid(struct DrawState* state, const int delta); static int prev_plural(struct DrawState* state); +static int prev_plural_callback(struct DrawState* state, struct tb_event* ev); int print_error(const int code, const char* msg, ...); static int quit_callback(struct DrawState* state, struct tb_event* ev); int redraw_status(struct DrawState* state); diff --git a/util.c b/util.c @@ -85,13 +85,13 @@ u32_match_msgid_ending(struct DrawState* state, const uint32_t* msgid, ssize_t msgid_len = 0; assert((state != NULL) && (msgstr != NULL)); + if (!msgid) + return 0; + buf = calloc(max + 1, sizeof(uint32_t)); if (!buf) goto u32_match_msgid_ending_alloc_error; - if (!msgid) - return 0; - buf_len = u32_strncpy(buf, msgstr, (max + 1) * sizeof(uint32_t)); msgid_len = u32_strlen(msgid); @@ -109,8 +109,7 @@ u32_match_msgid_ending(struct DrawState* state, const uint32_t* msgid, else if (match_msgstr_ending && msgid_len > 0 && u32_strstr(space_dot, msgid + msgid_len - 1)) { - if (!(buf_len > 0 - && u32_strstr(space_dot, buf + buf_len - 1))) + if (!(buf_len > 0 && u32_strstr(space_dot, buf + buf_len - 1))) { buf_len++; buf[buf_len - 1] = msgid[msgid_len - 1]; @@ -131,7 +130,7 @@ u32_match_msgid_ending(struct DrawState* state, const uint32_t* msgid, } u32_strncpy(msgstr, buf, max); - + free(buf); return buf_len; u32_match_msgid_ending_alloc_error: