poe

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

чување 0cfd22f6599c25287aa248f21e2912bbf71df67d
родитељ 127f482c975b16843dbc1d0d9b6eda79571e3c5e
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sun, 27 Feb 2022 19:19:59 +0100

poe.c: Sort functions

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

Diffstat:
Mconfig.def.h | 4++--
Mconfig.h | 4++--
Mpoe.c | 2612++++++++++++++++++++++++++++++++++++++++----------------------------------------
измењених датотека: 3, додавања: 1310(+), брисања: 1310(-)

diff --git a/config.def.h b/config.def.h @@ -71,16 +71,16 @@ int cancel_close(struct DrawState* state); int cancel_msgstr(struct DrawState* state); int cancel_search(struct DrawState* state); int copy_msgid_to_input(struct DrawState* state); -int edit_page_up(struct DrawState* state); int edit_page_down(struct DrawState* state); +int edit_page_up(struct DrawState* state); int erase_backwards(struct DrawState* state); int erase_forward(struct DrawState* state); int erase_prev_word(struct DrawState* state); int erase_search_backwards(struct DrawState* state); int erase_search_forward(struct DrawState* state); int erase_search_prev_word(struct DrawState* state); -int erase_search_to_start(struct DrawState* state); int erase_search_to_end(struct DrawState* state); +int erase_search_to_start(struct DrawState* state); int erase_to_end(struct DrawState* state); int erase_to_start(struct DrawState* state); int exit_program(struct DrawState* state); diff --git a/config.h b/config.h @@ -71,16 +71,16 @@ int cancel_close(struct DrawState* state); int cancel_msgstr(struct DrawState* state); int cancel_search(struct DrawState* state); int copy_msgid_to_input(struct DrawState* state); -int edit_page_up(struct DrawState* state); int edit_page_down(struct DrawState* state); +int edit_page_up(struct DrawState* state); int erase_backwards(struct DrawState* state); int erase_forward(struct DrawState* state); int erase_prev_word(struct DrawState* state); int erase_search_backwards(struct DrawState* state); int erase_search_forward(struct DrawState* state); int erase_search_prev_word(struct DrawState* state); -int erase_search_to_start(struct DrawState* state); int erase_search_to_end(struct DrawState* state); +int erase_search_to_start(struct DrawState* state); int erase_to_end(struct DrawState* state); int erase_to_start(struct DrawState* state); int exit_program(struct DrawState* state); diff --git a/poe.c b/poe.c @@ -46,60 +46,6 @@ void overwrite_paste_callback(struct DrawState* state, struct tb_event* ev); int print_error(const int code, const char* msg, ...); void quit_callback(struct DrawState* state, struct tb_event* ev); -int -print_error(const int code, const char* msg, ...) -{ - char buf[MAXBUFLINE]; - va_list args; - va_start(args, msg); - vsnprintf(buf, sizeof(buf), msg, args); - va_end(args); - fprintf(stderr, "%s: %s\n", program_name, buf); - return code; -} - -int -write_file(struct DrawState* state) -{ - int result = save_file(state->entries, state->real_msgid_count, - state->filename, state->nplurals); - switch (result) - { - case SAVE_ERR_CANT_ALLOC: - strcpy(state->error, errors[ERR_CANT_ALLOC]); - state->running = 0; - break; - case SAVE_ERR_CANT_OPEN_FILE: - strcpy(state->error, errors[ERR_CANT_SAVE]); - state->running = 0; - break; - case SAVE_ERR_CANT_MOVE_FILE: - strcpy(state->error, strerror(errno)); - state->running = 0; - break; - default: - *state->error = 0; - state->dirty = 0; - } - return 0; -} - -void -overwrite_copy_msgid_callback(struct DrawState* state, struct tb_event* ev) -{ - if (ev->ch == 'y') - copy_msgid_to_input(state); - state->prompt_callback = NULL; -} - -void -overwrite_paste_callback(struct DrawState* state, struct tb_event* ev) -{ - if (ev->ch == 'y') - paste_paste_buffer_to_input(state); - state->prompt_callback = NULL; -} - void cancel_callback(struct DrawState* state, struct tb_event* ev) { @@ -111,151 +57,318 @@ cancel_callback(struct DrawState* state, struct tb_event* ev) } void -quit_callback(struct DrawState* state, struct tb_event* ev) +goto_msgid(struct DrawState* state, const size_t msgid_number) { - if (ev->ch == 'y') - write_file(state); - state->prompt_callback = NULL; - state->running = 0; + state->msgid_number = msgid_number; + 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 + = MAX(1, state->msgid_count - (state->maxy - 2)); + else + state->first_shown_msgid + = MAX(1, state->msgid_number - (state->maxy - 1) / 2); } -int -cancel_close(struct DrawState* state) +void +handle_key_event(struct tb_event* ev, struct DrawState* state) { - *state->error = 0; + const struct Key* current = NULL; + if (state->in_prompt) { - state->in_prompt = 0; - *state->prompt = 0; + if (ev->ch == 'y' || ev->ch == 'n') + { + if (state->prompt_callback) + state->prompt_callback(state, ev); + state->in_prompt = 0; + *state->prompt = 0; + } + else if (ev->key == TB_KEY_ESC) + cancel_close(state); + return; } - else if (state->show_help) - state->show_help = 0; - else if (state->show_edit) - cancel_msgstr(state); - else if (state->show_search) - cancel_search(state); - else - strcpy(state->error, errors[ERR_EXIT_KEY]); - return 0; -} + /* Remember to also edit the following condition if you reassign motion + * keys */ + if (ev->key != TB_KEY_ARROW_DOWN && ev->key != TB_KEY_ARROW_UP + && state->show_edit) + state->saved_column = -1; -int -exit_program(struct DrawState* state) -{ - if (state->show_edit) - { - strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); - return 0; - } - if (state->dirty) + for (int key = 0; key < LEN(top_level_keys); key++) { - state->in_prompt = 1; - strcpy(state->prompt, prompt_dirty); - state->prompt_callback = quit_callback; + current = top_level_keys + key; + if (((current->ev.key == ev->key) && !ev->ch) + || (current->ev.ch && (current->ev.ch == ev->ch))) + if (current->callback && !current->callback(state)) + return; } - else - state->running = 0; - *state->error = 0; - return 0; -} - -struct BufferLine* -load_info(struct DrawState* state) -{ - struct PoEntry* first = &state->entries[0]; - struct PoEntry* current = &state->entries[state->msgid_number - 1]; - size_t msgid_num_lines = u32_lines_in_string(current->msgid, 0, 0); - size_t msgid_plural_num_lines - = u32_lines_in_string(current->msgid_plural, 0, 0); - size_t num_lines = 0; - struct BufferLine* newbuf = NULL; - struct BufferLine* pnewbuf = NULL; - - for (size_t i = 0; i < state->info_rows_count; i++) - free_bufferline(state->info_buffer + i); - free(state->info_buffer); - - state->info_rows_maxlen = 0; - if (current->msgid) - num_lines += msgid_num_lines + 1; - if (current->msgid_plural) + if (state->show_help) { - num_lines += msgid_plural_num_lines + 1; - if (first->plural_forms) - num_lines += 3; + strcpy(state->error, errors[ERR_DLG_OPEN]); + return; } - if (current->comments) - num_lines += current->comment_lines + 1; - if (current->trans_comments) - num_lines += current->trans_comment_lines + 1; - if (current->ref_comments) - num_lines += current->ref_comment_lines + 1; - newbuf = calloc(num_lines, sizeof(struct BufferLine)); - if (!newbuf) - return NULL; - - pnewbuf = newbuf; - for (size_t i = 0; i < num_lines; i++) + else if (state->show_edit) { - init_bufferline(pnewbuf); - uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); - if (!newtext) - return NULL; - pnewbuf->text = newtext; - pnewbuf++; + for (int key = 0; key < LEN(edit_keys); key++) + { + current = edit_keys + key; + if (((current->ev.key == ev->key) && !ev->ch) + || (current->ev.ch + && (current->ev.ch == ev->ch))) + if (current->callback + && !current->callback(state)) + return; + } + if (ev->ch) + { + insert_char(state, ev->ch); + return; + } } - - state->info_rows_count = num_lines; - - pnewbuf = newbuf; - size_t newlen = 0; - const uint32_t* pumsgid = NULL; - if (current->msgid) + else if (state->show_search) { - pumsgid = current->msgid; - newlen = u32_u8_strncpy(pnewbuf->text, "msgid:", MAXBUFLINE); - pnewbuf->length = newlen; - if (newlen > state->info_rows_maxlen) - state->info_rows_maxlen = newlen; - pnewbuf->fg = EDIT_MSGID_HEADING_FG; - pnewbuf->bg = EDIT_MSGID_HEADING_BG; - pnewbuf++; - while (*pumsgid) + for (int key = 0; key < LEN(search_keys); key++) { - size_t len = 0; - const uint32_t* old_pumsgid = pumsgid; - - len = u32_next_line(current->msgid, &pumsgid, 0, 0); - u32_strncpy(pnewbuf->text, old_pumsgid, - MIN(len + 1, MAXBUFLINE)); - newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE); - pnewbuf->length = newlen; - if (newlen > state->info_rows_maxlen) - state->info_rows_maxlen = newlen; - pnewbuf++; + current = search_keys + key; + if (((current->ev.key == ev->key) && !ev->ch) + || (current->ev.ch + && (current->ev.ch == ev->ch))) + if (current->callback + && !current->callback(state)) + return; + } + if (ev->ch) + { + insert_search_char(state, ev->ch); + return; } } - if (current->msgid_plural) + else { - newlen = u32_u8_strncpy(pnewbuf->text, - "msgid_plural:", MAXBUFLINE); - pnewbuf->length = newlen; - if (newlen > state->info_rows_maxlen) - state->info_rows_maxlen = newlen; - pnewbuf->fg = EDIT_MSGID_HEADING_FG; - pnewbuf->bg = EDIT_MSGID_HEADING_BG; - pnewbuf++; - pumsgid = current->msgid_plural; - while (*pumsgid) + for (int key = 0; key < LEN(main_keys); key++) { - size_t len = 0; - const uint32_t* old_pumsgid = pumsgid; + current = main_keys + key; + if (((current->ev.key == ev->key) && !ev->ch) + || (current->ev.ch + && (current->ev.ch == ev->ch))) + if (current->callback + && !current->callback(state)) + return; + } + } - len = u32_next_line(current->msgid_plural, &pumsgid, 0, - 0); - u32_strncpy(pnewbuf->text, old_pumsgid, + strcpy(state->error, errors[ERR_UNKNOWN_KEY]); +} + +void +insert_char(struct DrawState* state, uint32_t ch) +{ + if (state->edit_info_focused) + return; + struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; + size_t len = buffer_line->length; + if (state->input_column < MAXBUFLINE - 1) + { + size_t i = len + 1; + int add_null = buffer_line->text[state->input_column] == 0; + while (i < MAXBUFLINE - 2 && i > state->input_column) + { + buffer_line->text[i] = buffer_line->text[i - 1]; + i--; + } + buffer_line->text[state->input_column++] = ch; + buffer_line->length++; + if (state->input_column == MAXBUFLINE) + state->input_column = MAXBUFLINE - 1; + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); + if (state->input_display_column - state->input_first_shown_column + > state->edit_width - 4) + { + state->input_first_shown_column + = state->input_display_column + - state->edit_width + 4; + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); + } + if (add_null) + buffer_line->text[state->input_column] = 0; + } + state->dirty = 1; +} + +void +insert_search_char(struct DrawState* state, uint32_t ch) +{ + size_t len = u32_strlen(state->search); + if (state->search_column < MAXSEARCH - 1) + { + size_t i = len + 1; + int add_null = state->search[state->search_column] == 0; + while (i < MAXSEARCH - 2 && i > state->search_column) + { + state->search[i] = state->search[i - 1]; + i--; + } + state->search[state->search_column++] = ch; + if (state->search_column == MAXSEARCH) + state->search_column = MAXSEARCH - 1; + state->search_display_column = display_length(state, + state->search, state->search_column); + if (state->search_display_column + - state->search_first_shown_column + > state->search_width - 4) + { + state->search_first_shown_column + = state->search_display_column + - state->search_width + 4; + state->search_display_column = display_length(state, + state->search, state->search_column); + } + if (add_null) + state->search[state->search_column] = 0; + + next_match(state); + } +} + +struct DrawState* +join_lines(struct DrawState* state, size_t first_line, int forward) +{ + state->input_column = state->input_buffer[first_line].length; + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); + u32_strncat(state->input_buffer[first_line].text, + state->input_buffer[first_line + 1].text, MAXBUFLINE); + state->input_buffer[first_line].length + = u32_strlen(state->input_buffer[first_line].text); + if (!forward) + { + state->input_row--; + if (state->input_row < 0) + state->input_row = 0; + } + for (size_t i = first_line + 1; i < state->input_rows_count - 1; i++) + { + u32_strncpy(state->input_buffer[i].text, + state->input_buffer[i + 1].text, MAXBUFLINE); + state->input_buffer[i].length + = state->input_buffer[i + 1].length; + } + free_bufferline(state->input_buffer + state->input_rows_count - 1); + state->input_rows_count--; + struct BufferLine* newbuf = realloc(state->input_buffer, + state->input_rows_count * sizeof(struct BufferLine)); + if (!newbuf) + return NULL; + state->input_buffer = newbuf; + state->dirty = 1; + + return state; +} + +struct BufferLine* +load_info(struct DrawState* state) +{ + struct PoEntry* first = &state->entries[0]; + struct PoEntry* current = &state->entries[state->msgid_number - 1]; + size_t msgid_num_lines = u32_lines_in_string(current->msgid, 0, 0); + size_t msgid_plural_num_lines + = u32_lines_in_string(current->msgid_plural, 0, 0); + size_t num_lines = 0; + struct BufferLine* newbuf = NULL; + struct BufferLine* pnewbuf = NULL; + + for (size_t i = 0; i < state->info_rows_count; i++) + free_bufferline(state->info_buffer + i); + free(state->info_buffer); + + state->info_rows_maxlen = 0; + + if (current->msgid) + num_lines += msgid_num_lines + 1; + if (current->msgid_plural) + { + num_lines += msgid_plural_num_lines + 1; + if (first->plural_forms) + num_lines += 3; + } + if (current->comments) + num_lines += current->comment_lines + 1; + if (current->trans_comments) + num_lines += current->trans_comment_lines + 1; + if (current->ref_comments) + num_lines += current->ref_comment_lines + 1; + newbuf = calloc(num_lines, sizeof(struct BufferLine)); + if (!newbuf) + return NULL; + + pnewbuf = newbuf; + for (size_t i = 0; i < num_lines; i++) + { + init_bufferline(pnewbuf); + uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + if (!newtext) + return NULL; + pnewbuf->text = newtext; + pnewbuf++; + } + + state->info_rows_count = num_lines; + + pnewbuf = newbuf; + size_t newlen = 0; + const uint32_t* pumsgid = NULL; + if (current->msgid) + { + pumsgid = current->msgid; + newlen = u32_u8_strncpy(pnewbuf->text, "msgid:", MAXBUFLINE); + pnewbuf->length = newlen; + if (newlen > state->info_rows_maxlen) + state->info_rows_maxlen = newlen; + pnewbuf->fg = EDIT_MSGID_HEADING_FG; + pnewbuf->bg = EDIT_MSGID_HEADING_BG; + pnewbuf++; + while (*pumsgid) + { + size_t len = 0; + const uint32_t* old_pumsgid = pumsgid; + + len = u32_next_line(current->msgid, &pumsgid, 0, 0); + u32_strncpy(pnewbuf->text, old_pumsgid, + MIN(len + 1, MAXBUFLINE)); + newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE); + pnewbuf->length = newlen; + if (newlen > state->info_rows_maxlen) + state->info_rows_maxlen = newlen; + pnewbuf++; + } + } + if (current->msgid_plural) + { + newlen = u32_u8_strncpy(pnewbuf->text, + "msgid_plural:", MAXBUFLINE); + pnewbuf->length = newlen; + if (newlen > state->info_rows_maxlen) + state->info_rows_maxlen = newlen; + pnewbuf->fg = EDIT_MSGID_HEADING_FG; + pnewbuf->bg = EDIT_MSGID_HEADING_BG; + pnewbuf++; + pumsgid = current->msgid_plural; + while (*pumsgid) + { + size_t len = 0; + const uint32_t* old_pumsgid = pumsgid; + + len = u32_next_line(current->msgid_plural, &pumsgid, 0, + 0); + u32_strncpy(pnewbuf->text, old_pumsgid, MIN(len + 1, MAXBUFLINE)); newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE); pnewbuf->length = newlen; @@ -416,61 +529,61 @@ load_msgstr(struct DrawState* state) return state->input_buffer; } +void +overwrite_copy_msgid_callback(struct DrawState* state, struct tb_event* ev) +{ + if (ev->ch == 'y') + copy_msgid_to_input(state); + state->prompt_callback = NULL; +} + +void +overwrite_paste_callback(struct DrawState* state, struct tb_event* ev) +{ + if (ev->ch == 'y') + paste_paste_buffer_to_input(state); + state->prompt_callback = NULL; +} + int -save_msgstr(struct DrawState* state) +print_error(const int code, const char* msg, ...) { - uint32_t* to_save = NULL; - size_t to_save_size = 0; - struct PoEntry* current = NULL; + char buf[MAXBUFLINE]; + va_list args; + va_start(args, msg); + vsnprintf(buf, sizeof(buf), msg, args); + va_end(args); + fprintf(stderr, "%s: %s\n", program_name, buf); + return code; +} - state->show_edit = 0; - state->edit_info_focused = 0; +void +quit_callback(struct DrawState* state, struct tb_event* ev) +{ + if (ev->ch == 'y') + write_file(state); + state->prompt_callback = NULL; + state->running = 0; +} - if (state->input_buffer) +int +cancel_close(struct DrawState* state) +{ + *state->error = 0; + if (state->in_prompt) { - to_save_size = state->input_rows_count * MAXMSGLINE; - to_save = calloc(to_save_size, sizeof(uint32_t)); - if (!to_save) - { - strcpy(state->error, errors[ERR_CANT_ALLOC]); - return 0; - } - struct BufferLine* pinput_buffer = NULL; - for (size_t i = 0; i < state->input_rows_count; i++) - { - pinput_buffer = state->input_buffer + i; - if (i == 0) - u32_strncpy(to_save, pinput_buffer->text, - to_save_size * sizeof(uint32_t)); - else - { - u32_strncat(to_save, (uint32_t*)L"\\n", - to_save_size * sizeof(uint32_t)); - u32_strncat(to_save, pinput_buffer->text, - to_save_size * sizeof(uint32_t)); - } - free_bufferline(pinput_buffer); - } + state->in_prompt = 0; + *state->prompt = 0; } - free(state->input_buffer); - state->input_buffer = NULL; - state->input_rows_count = 0; - for (size_t 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->info_rows_count = 0; - state->info_buffer = NULL; - u32_encode_tabs(to_save, to_save_size * sizeof(uint32_t)); - current = &state->entries[state->msgid_number - 1]; - u32_match_msgid_ending(current->msgid, to_save, - to_save_size * sizeof(uint32_t)); - u32_set_msgstr(current, to_save, state->msgstr_index, 0, state); - update_warning(current->msgid, to_save, &current->warning); - state->input_changed_fuzzy = UNCHANGED; + else if (state->show_help) + state->show_help = 0; + else if (state->show_edit) + cancel_msgstr(state); + else if (state->show_search) + cancel_search(state); + else + strcpy(state->error, errors[ERR_EXIT_KEY]); - tb_hide_cursor(); - free(to_save); return 0; } @@ -517,37 +630,6 @@ cancel_msgstr(struct DrawState* state) } int -show_help(struct DrawState* state) -{ - state->show_help = 1; - *state->error = 0; - return 0; -} - -int -show_search(struct DrawState* state) -{ - state->show_search = 1; - state->search_column = 0; - state->search_display_column = 0; - state->search_first_shown_column = 0; - if (!state->search) - state->search = calloc(MAXSEARCH, sizeof(uint32_t)); - *state->search = 0; - tb_set_cursor((state->maxx - state->search_width + 2) / 2, - state->maxy - 1 - SEARCH_HEIGHT + 1); - return 0; -} - -int -hide_search(struct DrawState* state) -{ - state->show_search = 0; - tb_hide_cursor(); - return 0; -} - -int cancel_search(struct DrawState* state) { state->show_search = 0; @@ -557,180 +639,203 @@ cancel_search(struct DrawState* state) } int -move_search_start(struct DrawState* state) +copy_msgid_to_input(struct DrawState* state) { - state->search_column = 0; - state->search_display_column = 0; - state->search_first_shown_column = 0; - return 0; -} + if (state->edit_info_focused) + return 0; -int -move_search_left(struct DrawState* state) -{ - if (state->search_column == 0) + if (!state->in_prompt && *state->input_buffer->text) + { + state->in_prompt = 1; + strcpy(state->prompt, prompt_overwrite); + state->prompt_callback = overwrite_copy_msgid_callback; return 0; + } - if (state->search[state->search_column - 1] == '\t') - state->search_display_column = display_length(state, - state->search, state->search_column - 1); - else - state->search_display_column--; - state->search_column--; + if (state->msgid_number == 1) + { + strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); + return 0; + } - if (state->search_display_column < state->search_first_shown_column) - state->search_first_shown_column = state->search_display_column; - return 0; -} + struct PoEntry* current = &state->entries[state->msgid_number - 1]; + size_t msgid_num_lines = u32_lines_in_string(current->msgid, 0, 0); + size_t lines_to_init = state->input_rows_count < msgid_num_lines + ? msgid_num_lines - state->input_rows_count + : 0; + size_t lines_to_free = state->input_rows_count > msgid_num_lines + ? state->input_rows_count - msgid_num_lines + : 0; + for (size_t i = 0; i < lines_to_free; i++) + free_bufferline( + state->input_buffer + state->input_rows_count - i - 1); + struct BufferLine* newbuf = realloc(state->input_buffer, + msgid_num_lines * sizeof(struct BufferLine)); + const uint32_t* pmsgid = current->msgid; -int -move_search_right(struct DrawState* state) -{ - size_t len = u32_strlen(state->search); - if (state->search_column == len) + if (!newbuf) return 0; - if (state->search[state->search_column] == '\t') - state->search_display_column = display_length(state, - state->search, state->search_column + 1); - else - state->search_display_column++; - state->search_column++; + struct BufferLine* pbuffer = NULL; + for (size_t i = 0; i < lines_to_init; i++) + { + pbuffer = newbuf + msgid_num_lines - 1 - i; + init_bufferline(pbuffer); + uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + if (!newtext) + return 0; + pbuffer->text = newtext; + } + + pbuffer = newbuf; + while (pmsgid && *pmsgid) + { + size_t len = 0; + size_t newlen = 0; + const uint32_t* old_pmsgid = pmsgid; + len = u32_next_line(current->msgid, &pmsgid, 0, 0); + u32_strncpy(pbuffer->text, old_pmsgid, MIN(len + 1, MAXBUFLINE)); + newlen = u32_decode_tabs(pbuffer->text, MAXBUFLINE); + pbuffer->length = newlen; + pbuffer++; + } + + state->input_rows_count = msgid_num_lines; + state->input_buffer = newbuf; + state->dirty = 1; - if (state->search_display_column - state->search_first_shown_column - > state->search_width - 4) - state->search_first_shown_column = state->search_display_column - - state->search_width + 4; return 0; } int -move_search_end(struct DrawState* state) +edit_page_down(struct DrawState* state) { - size_t len = u32_strlen(state->search); - state->search_column = len; - size_t dlen - = display_length(state, state->search, state->search_column); - state->search_display_column = dlen; - if (dlen > state->search_width - 4) - state->search_first_shown_column - = dlen - state->search_width + 4; - else - state->search_first_shown_column = 0; - return 0; + if (state->edit_info_focused) + { + if (state->info_first_shown_row + (EDIT_HEIGHT - 3) / 2 + < state->info_rows_count - 1) + 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; + move_list_down(state); + state->msgstr_index = 0; + return show_edit(state); } -void -insert_search_char(struct DrawState* state, uint32_t ch) +int +edit_page_up(struct DrawState* state) { - size_t len = u32_strlen(state->search); - if (state->search_column < MAXSEARCH - 1) + if (state->edit_info_focused) { - size_t i = len + 1; - int add_null = state->search[state->search_column] == 0; - while (i < MAXSEARCH - 2 && i > state->search_column) - { - state->search[i] = state->search[i - 1]; - i--; - } - state->search[state->search_column++] = ch; - if (state->search_column == MAXSEARCH) - state->search_column = MAXSEARCH - 1; - state->search_display_column = display_length(state, - state->search, state->search_column); - if (state->search_display_column - - state->search_first_shown_column - > state->search_width - 4) - { - state->search_first_shown_column - = state->search_display_column - - state->search_width + 4; - state->search_display_column = display_length(state, - state->search, state->search_column); - } - if (add_null) - state->search[state->search_column] = 0; - - next_match(state); + if (state->info_first_shown_row > (EDIT_HEIGHT - 3) / 2) + state->info_first_shown_row -= (EDIT_HEIGHT - 3) / 2; + else + move_start(state); + return 0; } + + if (state->dirty) + save_msgstr(state); + else /* No need to call cancel_msgstr */ + state->dirty = state->dirty_before_edit; + move_list_up(state); + state->msgstr_index = 0; + return show_edit(state); } int -erase_search_backwards(struct DrawState* state) +erase_backwards(struct DrawState* state) { - if (state->search_column > 0) + struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; + if (state->edit_info_focused) + return 0; + + if (state->input_column > 0) { - size_t i = state->search_column; + size_t i = state->input_column; do { - state->search[i - 1] = state->search[i]; + buffer_line->text[i - 1] = buffer_line->text[i]; i++; - } while (state->search[i]); - state->search[i - 1] = 0; - state->search_column--; - if (state->search_column < state->search_first_shown_column) + } while (buffer_line->text[i]); + buffer_line->text[i - 1] = 0; + buffer_line->length--; + state->input_column--; + if (state->input_first_shown_column > 0) { - if (state->search_column > state->search_width - 4) - state->search_first_shown_column - = state->search_column - - state->search_width + 4; - else - state->search_first_shown_column = 0; + const struct BufferLine* current_line + = &state->input_buffer[state->input_row]; + if (display_length(state, current_line->text, + current_line->length) + >= state->edit_width - 4) + state->input_first_shown_column--; } - state->search_display_column = display_length(state, - state->search, state->search_column); - - return next_match(state); + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); + if (state->input_display_column + < state->input_first_shown_column) + state->input_first_shown_column + = state->input_display_column; + state->dirty = 1; + } + else if (state->input_row > 0) + { + move_up(state); + move_end(state); + erase_forward(state); } return 0; } int -erase_search_forward(struct DrawState* state) +erase_forward(struct DrawState* state) { - if (state->search[state->search_column]) + struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; + if (state->edit_info_focused) + return 0; + + if (buffer_line->text[state->input_column]) { - size_t i = state->search_column; - while (i < MAXSEARCH - 2 && state->search[i + 1]) + size_t i = state->input_column; + while (i < MAXBUFLINE - 2 && buffer_line->text[i + 1]) { - state->search[i] = state->search[i + 1]; + buffer_line->text[i] = buffer_line->text[i + 1]; i++; } - state->search[i] = 0; - - return next_match(state); + buffer_line->text[i] = 0; + buffer_line->length--; + state->dirty = 1; + } + else if (state->input_row < state->input_rows_count - 1) + { + if (!join_lines(state, state->input_row, 1)) + { + strcpy(state->error, errors[ERR_CANT_ALLOC]); + state->running = 0; + } } return 0; } int -erase_search_to_start(struct DrawState* state) +erase_prev_word(struct DrawState* state) { - size_t i = state->search_column; - size_t len = u32_strlen(state->search); - do + if (state->edit_info_focused) { - state->search[i - state->search_column] = state->search[i]; - i++; - } while (state->search[i]); - state->search[len - state->search_column] = 0; - move_search_start(state); - return next_match(state); -} + strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); + return 0; + } -int -erase_search_to_end(struct DrawState* state) -{ - state->search[state->search_column] = 0; - move_search_end(state); - return next_match(state); -} + int i = state->input_column; + size_t len = state->input_buffer[state->input_row].length; -int -move_search_prev_word(struct DrawState* state) -{ - int i = state->search_column; - uint32_t* pline = state->search; + uint32_t* pline = state->input_buffer[state->input_row].text; if (i > 0 && u32_is_word_boundary(pline[i - 1], 0)) i--; @@ -740,45 +845,66 @@ move_search_prev_word(struct DrawState* state) && !u32_is_word_boundary(pline[i - 1], 0)) i--; - state->search_column = i; - state->search_display_column - = display_length(state, state->search, state->search_column); + int d = state->input_column - i; - if (state->search_column < state->search_first_shown_column) - { - if (state->search_column > state->search_width - 4) - state->search_first_shown_column = state->search_column - - state->search_width + 4; - else - state->search_first_shown_column = 0; - } - state->search_display_column - = display_length(state, state->search, state->search_column); + for (int j = i; j < len - d; j++) + pline[j] = pline[j + d]; + + len -= d; + state->input_buffer[state->input_row].length = len; + pline[len] = 0; + state->input_column = i; + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); + state->dirty = 1; return 0; } int -move_search_next_word(struct DrawState* state) +erase_search_backwards(struct DrawState* state) { - int i = state->search_column; - uint32_t* pline = state->search; - size_t len = u32_strlen(state->search); - - while (i < len && !u32_is_word_boundary(pline[i], 0)) - i++; - while (i < len && u32_is_word_boundary(pline[i], 0)) - i++; - state->search_column = i; - state->search_display_column - = display_length(state, state->search, state->search_column); - - if (state->search_display_column - state->search_first_shown_column - > state->search_width - 4) + if (state->search_column > 0) { - state->search_first_shown_column = state->search_display_column - - state->search_width + 4; + size_t i = state->search_column; + do + { + state->search[i - 1] = state->search[i]; + i++; + } while (state->search[i]); + state->search[i - 1] = 0; + state->search_column--; + if (state->search_column < state->search_first_shown_column) + { + if (state->search_column > state->search_width - 4) + state->search_first_shown_column + = state->search_column + - state->search_width + 4; + else + state->search_first_shown_column = 0; + } state->search_display_column = display_length(state, state->search, state->search_column); + + return next_match(state); + } + return 0; +} + +int +erase_search_forward(struct DrawState* state) +{ + if (state->search[state->search_column]) + { + size_t i = state->search_column; + while (i < MAXSEARCH - 2 && state->search[i + 1]) + { + state->search[i] = state->search[i + 1]; + i++; + } + state->search[i] = 0; + + return next_match(state); } return 0; } @@ -825,569 +951,399 @@ erase_search_prev_word(struct DrawState* state) } int -copy_msgid_to_input(struct DrawState* state) +erase_search_to_end(struct DrawState* state) +{ + state->search[state->search_column] = 0; + move_search_end(state); + return next_match(state); +} + +int +erase_search_to_start(struct DrawState* state) +{ + size_t i = state->search_column; + size_t len = u32_strlen(state->search); + do + { + state->search[i - state->search_column] = state->search[i]; + i++; + } while (state->search[i]); + state->search[len - state->search_column] = 0; + move_search_start(state); + return next_match(state); +} + +int +erase_to_end(struct DrawState* state) { if (state->edit_info_focused) return 0; + struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; + buffer_line->text[state->input_column] = 0; + buffer_line->length = state->input_column; + move_end(state); + state->dirty = 1; + return 0; +} - if (!state->in_prompt && *state->input_buffer->text) +int +erase_to_start(struct DrawState* state) +{ + if (state->edit_info_focused) { - state->in_prompt = 1; - strcpy(state->prompt, prompt_overwrite); - state->prompt_callback = overwrite_copy_msgid_callback; + strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); return 0; } - if (state->msgid_number == 1) + size_t i = state->input_column; + struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; + size_t len = buffer_line->length; + do { - strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); + buffer_line->text[i - state->input_column] + = buffer_line->text[i]; + i++; + } while (buffer_line->text[i]); + buffer_line->text[len - state->input_column] = 0; + buffer_line->length = len - state->input_column; + move_start(state); + state->dirty = 1; + return 0; +} + +int +exit_program(struct DrawState* state) +{ + if (state->show_edit) + { + strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); return 0; } + if (state->dirty) + { + state->in_prompt = 1; + strcpy(state->prompt, prompt_dirty); + state->prompt_callback = quit_callback; + } + else + state->running = 0; + *state->error = 0; + return 0; +} - struct PoEntry* current = &state->entries[state->msgid_number - 1]; - size_t msgid_num_lines = u32_lines_in_string(current->msgid, 0, 0); - size_t lines_to_init = state->input_rows_count < msgid_num_lines - ? msgid_num_lines - state->input_rows_count - : 0; - size_t lines_to_free = state->input_rows_count > msgid_num_lines - ? state->input_rows_count - msgid_num_lines - : 0; - for (size_t i = 0; i < lines_to_free; i++) - free_bufferline( - state->input_buffer + state->input_rows_count - i - 1); - struct BufferLine* newbuf = realloc(state->input_buffer, - msgid_num_lines * sizeof(struct BufferLine)); - const uint32_t* pmsgid = current->msgid; +int +hide_search(struct DrawState* state) +{ + state->show_search = 0; + tb_hide_cursor(); + return 0; +} +int +insert_line(struct DrawState* state) +{ + if (state->edit_info_focused) + return 0; + state->input_rows_count++; + struct BufferLine* newbuf = realloc(state->input_buffer, + state->input_rows_count * sizeof(struct BufferLine)); if (!newbuf) + { + strcpy(state->error, errors[ERR_CANT_ALLOC]); + state->running = 0; return 0; + } - struct BufferLine* pbuffer = NULL; - for (size_t i = 0; i < lines_to_init; i++) + state->input_buffer = newbuf; + init_bufferline(&state->input_buffer[state->input_rows_count - 1]); + uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + if (!newtext) { - pbuffer = newbuf + msgid_num_lines - 1 - i; - init_bufferline(pbuffer); - uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); - if (!newtext) - return 0; - pbuffer->text = newtext; + strcpy(state->error, errors[ERR_CANT_ALLOC]); + state->running = 0; + return 0; } - - pbuffer = newbuf; - while (pmsgid && *pmsgid) + state->input_buffer[state->input_rows_count - 1].text = newtext; + for (size_t i = state->input_rows_count - 1; i > state->input_row + 1; + i--) { - size_t len = 0; - size_t newlen = 0; - const uint32_t* old_pmsgid = pmsgid; - len = u32_next_line(current->msgid, &pmsgid, 0, 0); - u32_strncpy(pbuffer->text, old_pmsgid, MIN(len + 1, MAXBUFLINE)); - newlen = u32_decode_tabs(pbuffer->text, MAXBUFLINE); - pbuffer->length = newlen; - pbuffer++; + u32_strncpy(state->input_buffer[i].text, + state->input_buffer[i - 1].text, MAXBUFLINE); + state->input_buffer[i].length + = state->input_buffer[i - 1].length; } + u32_strncpy(state->input_buffer[state->input_row + 1].text, + state->input_buffer[state->input_row].text + state->input_column, + MAXBUFLINE); + state->input_buffer[state->input_row + 1].length + = u32_strlen(state->input_buffer[state->input_row + 1].text); + state->input_buffer[state->input_row].text[state->input_column] = 0; + state->input_buffer[state->input_row].length + = u32_strlen(state->input_buffer[state->input_row].text); - state->input_rows_count = msgid_num_lines; - state->input_buffer = newbuf; - state->dirty = 1; + state->input_row++; + if (state->input_row + > state->input_first_shown_row + (EDIT_HEIGHT - 3) / 2) + state->input_first_shown_row + = state->input_row - (EDIT_HEIGHT - 3) / 2; + move_start(state); + state->dirty = 1; return 0; } int -yank_msgstr_to_paste_buffer(struct DrawState* state) +insert_search_space(struct DrawState* state) { - if (state->edit_info_focused) - return 0; + insert_search_char(state, (uint32_t)L' '); + return 0; +} - if (state->msgid_number == 1) - { - strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); - return 0; - } +int +insert_search_tab(struct DrawState* state) +{ + insert_search_char(state, (uint32_t)L'\t'); + return 0; +} - struct PoEntry* current = &state->entries[state->msgid_number - 1]; - size_t msgstr_num_lines = 0; - size_t lines_to_init = 0; - size_t lines_to_free = 0; - struct BufferLine* newbuf = NULL; - const uint32_t* pmsgstr = NULL; - struct BufferLine* pbuffer = NULL; +int +insert_space(struct DrawState* state) +{ + insert_char(state, (uint32_t)L' '); + return 0; +} - if (!current->msgstr || !*(current->msgstr + state->msgstr_index)) +int +insert_tab(struct DrawState* state) +{ + insert_char(state, (uint32_t)L'\t'); + return 0; +} + +int +move_end(struct DrawState* state) +{ + if (state->edit_info_focused) { - for (size_t i = 0; i < state->paste_rows_count; i++) - free_bufferline(state->paste_buffer + i); - free(state->paste_buffer); - state->paste_buffer = NULL; - state->paste_rows_count = 0; + if (state->info_rows_count > (EDIT_HEIGHT - 3) / 2) + state->info_first_shown_row = state->info_rows_count + - (EDIT_HEIGHT - 3) / 2; + state->info_first_shown_column = 0; return 0; } - msgstr_num_lines - = u32_lines_in_string(*(current->msgstr + state->msgstr_index), - 0, 0); - lines_to_init = state->paste_rows_count < msgstr_num_lines - ? msgstr_num_lines - state->paste_rows_count - : 0; - lines_to_free = state->paste_rows_count > msgstr_num_lines - ? state->paste_rows_count - msgstr_num_lines - : 0; - - for (size_t i = 0; i < lines_to_free; i++) - free_bufferline( - state->paste_buffer + state->paste_rows_count - i - 1); - if (!state->paste_buffer) - newbuf = calloc(msgstr_num_lines, sizeof(struct BufferLine)); + size_t len = state->input_buffer[state->input_row].length; + state->input_column = len; + size_t dlen = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); + state->input_display_column = dlen; + if (dlen > state->edit_width - 4) + state->input_first_shown_column = dlen - state->edit_width + 4; else - newbuf = realloc(state->paste_buffer, - msgstr_num_lines * sizeof(struct BufferLine)); - pmsgstr = *(current->msgstr + state->msgstr_index); - - if (!newbuf) - return 0; - - for (size_t i = 0; i < lines_to_init; i++) - { - pbuffer = newbuf + msgstr_num_lines - 1 - i; - init_bufferline(pbuffer); - uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); - if (!newtext) - return 0; - pbuffer->text = newtext; - } + state->input_first_shown_column = 0; + return 0; +} - pbuffer = newbuf; - while (*pmsgstr) +int +move_down(struct DrawState* state) +{ + if (state->edit_info_focused) { - size_t len = 0; - size_t newlen = 0; - const uint32_t* old_pmsgstr = pmsgstr; - - len = u32_next_line(*(current->msgstr + state->msgstr_index), - &pmsgstr, 0, 0); - u32_strncpy(pbuffer->text, old_pmsgstr, - MIN(len + 1, MAXBUFLINE)); - newlen = u32_decode_tabs(pbuffer->text, MAXBUFLINE); - pbuffer->length = newlen; - pbuffer++; + if (state->info_first_shown_row + (EDIT_HEIGHT - 3) / 2 + < state->info_rows_count) + state->info_first_shown_row++; + return 0; } - state->paste_rows_count = msgstr_num_lines; - state->paste_buffer = newbuf; - + if (state->input_row < state->input_rows_count - 1) + state->input_row++; + if (state->input_first_shown_row + (EDIT_HEIGHT - 3) / 2 + < state->input_row) + state->input_first_shown_row + = state->input_row - (EDIT_HEIGHT - 3) / 2; + if (state->saved_column == -1) + state->saved_column = state->input_display_column; + size_t dlen = display_length(state, + state->input_buffer[state->input_row].text, + state->input_buffer[state->input_row].length); + if (dlen < state->saved_column) + state->input_display_column = dlen; + else + state->input_display_column = state->saved_column; + state->input_column = input_length(state, + state->input_buffer[state->input_row].text, + state->input_display_column); + if (state->input_first_shown_column > state->input_display_column) + state->input_first_shown_column = state->input_display_column; + if (state->input_first_shown_column + state->edit_width - 4 + < state->input_display_column) + state->input_first_shown_column + = state->input_display_column - state->edit_width + 4; + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); return 0; } int -paste_paste_buffer_to_input(struct DrawState* state) +move_left(struct DrawState* state) { if (state->edit_info_focused) - return 0; - - if (!state->in_prompt && *state->input_buffer->text) { - state->in_prompt = 1; - strcpy(state->prompt, prompt_overwrite); - state->prompt_callback = overwrite_paste_callback; + if (state->info_first_shown_column > 0) + state->info_first_shown_column--; return 0; } - if (state->msgid_number == 1) - { - strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); + if (state->input_column == 0) return 0; - } - size_t lines_to_init = 0; - size_t lines_to_free = 0; - struct BufferLine* pinput = NULL; - struct BufferLine* newbuf = NULL; - struct BufferLine* ppaste = NULL; + if (state->input_buffer[state->input_row].text[state->input_column - 1] + == '\t') + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column - 1); + else + state->input_display_column--; + state->input_column--; - if (!state->paste_buffer || !(*state->paste_buffer).text - || !*(*state->paste_buffer).text) - { - /* leave one row */ - for (size_t i = 1; i < state->input_rows_count; i++) - free_bufferline(state->input_buffer + i); - state->input_buffer = realloc(state->input_buffer, - sizeof(struct BufferLine)); - *(state->input_buffer->text) = 0; - state->input_column = 0; - state->input_display_column = 0; - state->input_first_shown_column = 0; - state->input_first_shown_row = 0; - state->input_row = 0; - state->input_rows_count = 1; - state->dirty = 1; - return 0; - } - - lines_to_init = state->input_rows_count < state->paste_rows_count - ? state->paste_rows_count - state->input_rows_count - : 0; - lines_to_free = state->input_rows_count > state->paste_rows_count - ? state->input_rows_count - state->paste_rows_count - : 0; - - for (size_t i = 0; i < lines_to_free; i++) - free_bufferline( - state->input_buffer + state->input_rows_count - i - 1); - newbuf = realloc(state->input_buffer, - state->paste_rows_count * sizeof(struct BufferLine)); - ppaste = state->paste_buffer; - - if (!newbuf) - return 0; + if (state->input_display_column < state->input_first_shown_column) + state->input_first_shown_column = state->input_display_column; + return 0; +} - for (size_t i = 0; i < lines_to_init; i++) +int +move_list_down(struct DrawState* state) +{ + if (state->msgid_number < state->msgid_count) { - pinput = newbuf + state->paste_rows_count - 1 - i; - init_bufferline(pinput); - uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); - if (!newtext) - return 0; - pinput->text = newtext; + *state->error = 0; + state->msgid_number++; + if (state->msgid_number - state->first_shown_msgid + > state->maxy - 2) + state->first_shown_msgid++; } - - if (ppaste) - for (size_t i = 0; i < state->paste_rows_count; i++) - { - pinput = newbuf + i; - u32_strncpy(pinput->text, ppaste->text, - MIN(ppaste->length + 1, MAXBUFLINE)); - pinput->length = ppaste->length; - ppaste++; - } - - state->input_rows_count = state->paste_rows_count; - state->input_buffer = newbuf; - state->dirty = 1; - return 0; } -void -goto_msgid(struct DrawState* state, const size_t msgid_number) +int +move_list_end(struct DrawState* state) { - state->msgid_number = msgid_number; - 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 - = MAX(1, state->msgid_count - (state->maxy - 2)); - else - state->first_shown_msgid - = MAX(1, state->msgid_number - (state->maxy - 1) / 2); + *state->error = 0; + state->msgid_number = state->msgid_count; + state->first_shown_msgid = state->msgid_count > 0 + ? MAX(1, state->msgid_number - (state->maxy - 2)) + : 0; + return 0; } int -next_match(struct DrawState* state) +move_list_page_down(struct DrawState* state) { - if (state->msgid_count == 0 || !state->search || !*state->search) - return 0; - - *state->error = 0; - struct PoEntry* current = NULL; - for (size_t e = state->msgid_number; e < state->msgid_count; e++) + *state->error = 0; + if (state->msgid_number < state->msgid_count - state->maxy - 2) { - 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))) - { - goto_msgid(state, e + 1); - return 0; - } + state->msgid_number += state->maxy - 2; + if (state->msgid_number - state->first_shown_msgid + > state->maxy - 2) + state->first_shown_msgid + = state->msgid_number - (state->maxy - 2); } + else + return move_list_end(state); return 0; } int -prev_match(struct DrawState* state) +move_list_page_up(struct DrawState* state) { - if (state->msgid_count == 0 || !state->search || !*state->search) - return 0; - - *state->error = 0; - struct PoEntry* current = NULL; - for (size_t e = state->msgid_number - 1; e > 0; e--) + *state->error = 0; + if (state->msgid_number > state->maxy - 2) { - 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))) - { - goto_msgid(state, e); - return 0; - } + state->msgid_number -= state->maxy - 2; + if (state->msgid_number < state->first_shown_msgid) + state->first_shown_msgid = state->msgid_number; } + else + return move_list_start(state); return 0; } int -next_untranslated(struct DrawState* state) +move_list_start(struct DrawState* state) { - if (state->msgid_count == 0) - return 0; - - *state->error = 0; - - struct PoEntry* current = NULL; - for (size_t e = state->msgid_number; e < state->msgid_count; e++) - { - current = state->entries + e; - if (!current->msgstr || !*current->msgstr - || u32_strlen(*current->msgstr) == 0) - { - int 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) - { - state->msgstr_index = 0; - show_edit(state); - } - - return 0; - } - } + *state->error = 0; + state->msgid_number = state->msgid_count > 0 ? 1 : 0; + state->first_shown_msgid = state->msgid_number; return 0; } int -next_fuzzy(struct DrawState* state) +move_list_up(struct DrawState* state) { - if (state->msgid_count == 0) - return 0; - - *state->error = 0; - - struct PoEntry* current = NULL; - for (size_t e = state->msgid_number; e < state->msgid_count; e++) + if (state->msgid_number > 1) { - current = state->entries + e; - if (current->flags & FL_FUZZY) - { - int 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) - { - state->msgstr_index = 0; - show_edit(state); - } - - return 0; - } + *state->error = 0; + state->msgid_number--; + if (state->msgid_number < state->first_shown_msgid) + state->first_shown_msgid--; } return 0; } int -show_edit(struct DrawState* state) +move_next_word(struct DrawState* state) { - if (!load_msgstr(state) || !load_info(state)) + if (state->edit_info_focused) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); - state->running = 0; + strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); return 0; } - 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; - state->input_row = 0; - state->input_first_shown_row = 0; - state->input_first_shown_column = 0; - state->info_first_shown_row = 0; - state->info_first_shown_column = 0; - move_start(state); - *state->error = 0; + int i = state->input_column; + uint32_t* pline = state->input_buffer[state->input_row].text; + size_t len = state->input_buffer[state->input_row].length; + + while (i < len && !u32_is_word_boundary(pline[i], 0)) + i++; + while (i < len && u32_is_word_boundary(pline[i], 0)) + i++; + state->input_column = i; + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); + if (state->input_display_column - state->input_first_shown_column + > state->edit_width - 4) + state->input_first_shown_column + = state->input_display_column - state->edit_width + 4; return 0; } int -move_up(struct DrawState* state) +move_prev_word(struct DrawState* state) { if (state->edit_info_focused) { - if (state->info_first_shown_row > 0) - state->info_first_shown_row--; + strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); return 0; } - if (state->input_row > 0) - state->input_row--; - if (state->input_first_shown_row > state->input_row) - state->input_first_shown_row = state->input_row; - if (state->saved_column == -1) - state->saved_column = state->input_display_column; - size_t dlen = display_length(state, - state->input_buffer[state->input_row].text, - state->input_buffer[state->input_row].length); - if (dlen < state->saved_column) - state->input_display_column = dlen; - else - state->input_display_column = state->saved_column; - state->input_column = input_length(state, - state->input_buffer[state->input_row].text, - state->input_display_column); - if (state->input_first_shown_column > state->input_display_column) - state->input_first_shown_column = state->input_display_column; - if (state->input_first_shown_column + state->edit_width - 4 - < state->input_display_column) - state->input_first_shown_column - = state->input_display_column - state->edit_width + 4; - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); - return 0; -} + int i = state->input_column; + uint32_t* pline = state->input_buffer[state->input_row].text; -int -move_down(struct DrawState* state) -{ - if (state->edit_info_focused) - { - if (state->info_first_shown_row + (EDIT_HEIGHT - 3) / 2 - < state->info_rows_count) - state->info_first_shown_row++; - return 0; - } + if (i > 0 && u32_is_word_boundary(pline[i - 1], 0)) + i--; + while (i > 0 && u32_is_word_boundary(pline[i], 0)) + i--; + while (i > 0 && !u32_is_word_boundary(pline[i], 0) + && !u32_is_word_boundary(pline[i - 1], 0)) + i--; - if (state->input_row < state->input_rows_count - 1) - state->input_row++; - if (state->input_first_shown_row + (EDIT_HEIGHT - 3) / 2 - < state->input_row) - state->input_first_shown_row - = state->input_row - (EDIT_HEIGHT - 3) / 2; - if (state->saved_column == -1) - state->saved_column = state->input_display_column; - size_t dlen = display_length(state, - state->input_buffer[state->input_row].text, - state->input_buffer[state->input_row].length); - if (dlen < state->saved_column) - state->input_display_column = dlen; - else - state->input_display_column = state->saved_column; - state->input_column = input_length(state, - state->input_buffer[state->input_row].text, - state->input_display_column); - if (state->input_first_shown_column > state->input_display_column) - state->input_first_shown_column = state->input_display_column; - if (state->input_first_shown_column + state->edit_width - 4 - < state->input_display_column) - state->input_first_shown_column - = state->input_display_column - state->edit_width + 4; + state->input_column = i; state->input_display_column = display_length(state, state->input_buffer[state->input_row].text, state->input_column); - return 0; -} - -int -edit_page_up(struct DrawState* state) -{ - if (state->edit_info_focused) - { - if (state->info_first_shown_row > (EDIT_HEIGHT - 3) / 2) - state->info_first_shown_row -= (EDIT_HEIGHT - 3) / 2; - else - move_start(state); - return 0; - } - - if (state->dirty) - save_msgstr(state); - else /* No need to call cancel_msgstr */ - state->dirty = state->dirty_before_edit; - move_list_up(state); - state->msgstr_index = 0; - return show_edit(state); -} - -int -edit_page_down(struct DrawState* state) -{ - if (state->edit_info_focused) - { - if (state->info_first_shown_row + (EDIT_HEIGHT - 3) / 2 - < state->info_rows_count - 1) - 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; - move_list_down(state); - state->msgstr_index = 0; - return show_edit(state); -} - -int -move_start(struct DrawState* state) -{ - if (state->edit_info_focused) - { - state->info_first_shown_row = 0; - state->info_first_shown_column = 0; - return 0; - } - - state->input_column = 0; - state->input_display_column = 0; - state->input_first_shown_column = 0; - return 0; -} - -int -move_left(struct DrawState* state) -{ - if (state->edit_info_focused) - { - if (state->info_first_shown_column > 0) - state->info_first_shown_column--; - return 0; - } - - if (state->input_column == 0) - return 0; - - if (state->input_buffer[state->input_row].text[state->input_column - 1] - == '\t') - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column - 1); - else - state->input_display_column--; - state->input_column--; - if (state->input_display_column < state->input_first_shown_column) state->input_first_shown_column = state->input_display_column; return 0; @@ -1425,75 +1381,70 @@ move_right(struct DrawState* state) } int -move_prev_word(struct DrawState* state) +move_search_end(struct DrawState* state) { - if (state->edit_info_focused) - { - strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); - return 0; - } + size_t len = u32_strlen(state->search); + state->search_column = len; + size_t dlen + = display_length(state, state->search, state->search_column); + state->search_display_column = dlen; + if (dlen > state->search_width - 4) + state->search_first_shown_column + = dlen - state->search_width + 4; + else + state->search_first_shown_column = 0; + return 0; +} - int i = state->input_column; - uint32_t* pline = state->input_buffer[state->input_row].text; +int +move_search_left(struct DrawState* state) +{ + if (state->search_column == 0) + return 0; - if (i > 0 && u32_is_word_boundary(pline[i - 1], 0)) - i--; - while (i > 0 && u32_is_word_boundary(pline[i], 0)) - i--; - while (i > 0 && !u32_is_word_boundary(pline[i], 0) - && !u32_is_word_boundary(pline[i - 1], 0)) - i--; + if (state->search[state->search_column - 1] == '\t') + state->search_display_column = display_length(state, + state->search, state->search_column - 1); + else + state->search_display_column--; + state->search_column--; - state->input_column = i; - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); - if (state->input_display_column < state->input_first_shown_column) - state->input_first_shown_column = state->input_display_column; + if (state->search_display_column < state->search_first_shown_column) + state->search_first_shown_column = state->search_display_column; return 0; } int -move_next_word(struct DrawState* state) +move_search_next_word(struct DrawState* state) { - if (state->edit_info_focused) - { - strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); - return 0; - } - - int i = state->input_column; - uint32_t* pline = state->input_buffer[state->input_row].text; - size_t len = state->input_buffer[state->input_row].length; + int i = state->search_column; + uint32_t* pline = state->search; + size_t len = u32_strlen(state->search); while (i < len && !u32_is_word_boundary(pline[i], 0)) i++; while (i < len && u32_is_word_boundary(pline[i], 0)) i++; - state->input_column = i; - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); - if (state->input_display_column - state->input_first_shown_column - > state->edit_width - 4) - state->input_first_shown_column - = state->input_display_column - state->edit_width + 4; + state->search_column = i; + state->search_display_column + = display_length(state, state->search, state->search_column); + + if (state->search_display_column - state->search_first_shown_column + > state->search_width - 4) + { + state->search_first_shown_column = state->search_display_column + - state->search_width + 4; + state->search_display_column = display_length(state, + state->search, state->search_column); + } return 0; } int -erase_prev_word(struct DrawState* state) +move_search_prev_word(struct DrawState* state) { - if (state->edit_info_focused) - { - strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); - return 0; - } - - int i = state->input_column; - size_t len = state->input_buffer[state->input_row].length; - - uint32_t* pline = state->input_buffer[state->input_row].text; + int i = state->search_column; + uint32_t* pline = state->search; if (i > 0 && u32_is_word_boundary(pline[i - 1], 0)) i--; @@ -1503,151 +1454,165 @@ erase_prev_word(struct DrawState* state) && !u32_is_word_boundary(pline[i - 1], 0)) i--; - int d = state->input_column - i; - - for (int j = i; j < len - d; j++) - pline[j] = pline[j + d]; + state->search_column = i; + state->search_display_column + = display_length(state, state->search, state->search_column); - len -= d; - state->input_buffer[state->input_row].length = len; - pline[len] = 0; - state->input_column = i; - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); - state->dirty = 1; + if (state->search_column < state->search_first_shown_column) + { + if (state->search_column > state->search_width - 4) + state->search_first_shown_column = state->search_column + - state->search_width + 4; + else + state->search_first_shown_column = 0; + } + state->search_display_column + = display_length(state, state->search, state->search_column); return 0; } int -insert_space(struct DrawState* state) +move_search_right(struct DrawState* state) { - insert_char(state, (uint32_t)L' '); - return 0; -} + size_t len = u32_strlen(state->search); + if (state->search_column == len) + return 0; -int -insert_tab(struct DrawState* state) -{ - insert_char(state, (uint32_t)L'\t'); - return 0; -} + if (state->search[state->search_column] == '\t') + state->search_display_column = display_length(state, + state->search, state->search_column + 1); + else + state->search_display_column++; + state->search_column++; -int -insert_search_space(struct DrawState* state) -{ - insert_search_char(state, (uint32_t)L' '); + if (state->search_display_column - state->search_first_shown_column + > state->search_width - 4) + state->search_first_shown_column = state->search_display_column + - state->search_width + 4; return 0; } int -insert_search_tab(struct DrawState* state) +move_search_start(struct DrawState* state) { - insert_search_char(state, (uint32_t)L'\t'); + state->search_column = 0; + state->search_display_column = 0; + state->search_first_shown_column = 0; return 0; } int -move_end(struct DrawState* state) +move_start(struct DrawState* state) { if (state->edit_info_focused) { - if (state->info_rows_count > (EDIT_HEIGHT - 3) / 2) - state->info_first_shown_row = state->info_rows_count - - (EDIT_HEIGHT - 3) / 2; + state->info_first_shown_row = 0; state->info_first_shown_column = 0; return 0; } - size_t len = state->input_buffer[state->input_row].length; - state->input_column = len; - size_t dlen = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); - state->input_display_column = dlen; - if (dlen > state->edit_width - 4) - state->input_first_shown_column = dlen - state->edit_width + 4; - else - state->input_first_shown_column = 0; - return 0; -} - -int -move_list_up(struct DrawState* state) -{ - if (state->msgid_number > 1) - { - *state->error = 0; - state->msgid_number--; - if (state->msgid_number < state->first_shown_msgid) - state->first_shown_msgid--; - } + state->input_column = 0; + state->input_display_column = 0; + state->input_first_shown_column = 0; return 0; } int -move_list_down(struct DrawState* state) +move_up(struct DrawState* state) { - if (state->msgid_number < state->msgid_count) + if (state->edit_info_focused) { - *state->error = 0; - state->msgid_number++; - if (state->msgid_number - state->first_shown_msgid - > state->maxy - 2) - state->first_shown_msgid++; + if (state->info_first_shown_row > 0) + state->info_first_shown_row--; + return 0; } - return 0; -} -int -move_list_start(struct DrawState* state) -{ - *state->error = 0; - state->msgid_number = state->msgid_count > 0 ? 1 : 0; - state->first_shown_msgid = state->msgid_number; + if (state->input_row > 0) + state->input_row--; + if (state->input_first_shown_row > state->input_row) + state->input_first_shown_row = state->input_row; + if (state->saved_column == -1) + state->saved_column = state->input_display_column; + size_t dlen = display_length(state, + state->input_buffer[state->input_row].text, + state->input_buffer[state->input_row].length); + if (dlen < state->saved_column) + state->input_display_column = dlen; + else + state->input_display_column = state->saved_column; + state->input_column = input_length(state, + state->input_buffer[state->input_row].text, + state->input_display_column); + if (state->input_first_shown_column > state->input_display_column) + state->input_first_shown_column = state->input_display_column; + if (state->input_first_shown_column + state->edit_width - 4 + < state->input_display_column) + state->input_first_shown_column + = state->input_display_column - state->edit_width + 4; + state->input_display_column = display_length(state, + state->input_buffer[state->input_row].text, + state->input_column); return 0; } int -move_list_end(struct DrawState* state) +next_fuzzy(struct DrawState* state) { - *state->error = 0; - state->msgid_number = state->msgid_count; - state->first_shown_msgid = state->msgid_count > 0 - ? MAX(1, state->msgid_number - (state->maxy - 2)) - : 0; - return 0; -} + if (state->msgid_count == 0) + return 0; -int -move_list_page_up(struct DrawState* state) -{ *state->error = 0; - if (state->msgid_number > state->maxy - 2) + + struct PoEntry* current = NULL; + for (size_t e = state->msgid_number; e < state->msgid_count; e++) { - state->msgid_number -= state->maxy - 2; - if (state->msgid_number < state->first_shown_msgid) - state->first_shown_msgid = state->msgid_number; + current = state->entries + e; + if (current->flags & FL_FUZZY) + { + int 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) + { + state->msgstr_index = 0; + show_edit(state); + } + + return 0; + } } - else - return move_list_start(state); return 0; } int -move_list_page_down(struct DrawState* state) +next_match(struct DrawState* state) { - *state->error = 0; - if (state->msgid_number < state->msgid_count - state->maxy - 2) + if (state->msgid_count == 0 || !state->search || !*state->search) + return 0; + + *state->error = 0; + struct PoEntry* current = NULL; + for (size_t e = state->msgid_number; e < state->msgid_count; e++) { - state->msgid_number += state->maxy - 2; - if (state->msgid_number - state->first_shown_msgid - > state->maxy - 2) - state->first_shown_msgid - = state->msgid_number - (state->maxy - 2); + 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))) + { + goto_msgid(state, e + 1); + return 0; + } } - else - return move_list_end(state); return 0; } @@ -1665,387 +1630,422 @@ next_plural(struct DrawState* state) } int -prev_plural(struct DrawState* state) +next_untranslated(struct DrawState* state) { - if (state->edit_info_focused) + if (state->msgid_count == 0) return 0; - save_msgstr(state); - if (state->msgstr_index > 0) - state->msgstr_index--; - show_edit(state); + + *state->error = 0; + + struct PoEntry* current = NULL; + for (size_t e = state->msgid_number; e < state->msgid_count; e++) + { + current = state->entries + e; + if (!current->msgstr || !*current->msgstr + || u32_strlen(*current->msgstr) == 0) + { + int 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) + { + state->msgstr_index = 0; + show_edit(state); + } + + return 0; + } + } return 0; } int -toggle_fuzzy(struct DrawState* state) +paste_paste_buffer_to_input(struct DrawState* state) { + if (state->edit_info_focused) + return 0; + + if (!state->in_prompt && *state->input_buffer->text) + { + state->in_prompt = 1; + strcpy(state->prompt, prompt_overwrite); + state->prompt_callback = overwrite_paste_callback; + return 0; + } + if (state->msgid_number == 1) { strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); return 0; } - if (state->msgid_count > 0) - { - state->entries[state->msgid_number - 1].flags ^= FL_FUZZY; - if (state->entries[state->msgid_number - 1].flags & FL_FUZZY) - { - state->fuzzy_count++; - if (state->input_changed_fuzzy == CLEARED) - state->input_changed_fuzzy = UNCHANGED; - else - state->input_changed_fuzzy = SET; - } - else - { - state->fuzzy_count--; - if (state->input_changed_fuzzy == SET) - state->input_changed_fuzzy = UNCHANGED; - else - state->input_changed_fuzzy = CLEARED; - } - state->dirty = 1; + + size_t lines_to_init = 0; + size_t lines_to_free = 0; + struct BufferLine* pinput = NULL; + struct BufferLine* newbuf = NULL; + struct BufferLine* ppaste = NULL; + + if (!state->paste_buffer || !(*state->paste_buffer).text + || !*(*state->paste_buffer).text) + { + /* leave one row */ + for (size_t i = 1; i < state->input_rows_count; i++) + free_bufferline(state->input_buffer + i); + state->input_buffer = realloc(state->input_buffer, + sizeof(struct BufferLine)); + *(state->input_buffer->text) = 0; + state->input_column = 0; + state->input_display_column = 0; + state->input_first_shown_column = 0; + state->input_first_shown_row = 0; + state->input_row = 0; + state->input_rows_count = 1; + state->dirty = 1; + return 0; } - return 0; -} -int -toggle_info_focused(struct DrawState* state) -{ - state->edit_info_focused = !state->edit_info_focused; - return 0; -} + lines_to_init = state->input_rows_count < state->paste_rows_count + ? state->paste_rows_count - state->input_rows_count + : 0; + lines_to_free = state->input_rows_count > state->paste_rows_count + ? state->input_rows_count - state->paste_rows_count + : 0; -void -insert_char(struct DrawState* state, uint32_t ch) -{ - if (state->edit_info_focused) - return; - struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; - size_t len = buffer_line->length; - if (state->input_column < MAXBUFLINE - 1) + for (size_t i = 0; i < lines_to_free; i++) + free_bufferline( + state->input_buffer + state->input_rows_count - i - 1); + newbuf = realloc(state->input_buffer, + state->paste_rows_count * sizeof(struct BufferLine)); + ppaste = state->paste_buffer; + + if (!newbuf) + return 0; + + for (size_t i = 0; i < lines_to_init; i++) { - size_t i = len + 1; - int add_null = buffer_line->text[state->input_column] == 0; - while (i < MAXBUFLINE - 2 && i > state->input_column) - { - buffer_line->text[i] = buffer_line->text[i - 1]; - i--; - } - buffer_line->text[state->input_column++] = ch; - buffer_line->length++; - if (state->input_column == MAXBUFLINE) - state->input_column = MAXBUFLINE - 1; - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); - if (state->input_display_column - state->input_first_shown_column - > state->edit_width - 4) + pinput = newbuf + state->paste_rows_count - 1 - i; + init_bufferline(pinput); + uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + if (!newtext) + return 0; + pinput->text = newtext; + } + + if (ppaste) + for (size_t i = 0; i < state->paste_rows_count; i++) { - state->input_first_shown_column - = state->input_display_column - - state->edit_width + 4; - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); + pinput = newbuf + i; + u32_strncpy(pinput->text, ppaste->text, + MIN(ppaste->length + 1, MAXBUFLINE)); + pinput->length = ppaste->length; + ppaste++; } - if (add_null) - buffer_line->text[state->input_column] = 0; - } - state->dirty = 1; + + state->input_rows_count = state->paste_rows_count; + state->input_buffer = newbuf; + state->dirty = 1; + + return 0; } int -erase_backwards(struct DrawState* state) +prev_match(struct DrawState* state) { - struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; - if (state->edit_info_focused) + if (state->msgid_count == 0 || !state->search || !*state->search) return 0; - if (state->input_column > 0) + *state->error = 0; + struct PoEntry* current = NULL; + for (size_t e = state->msgid_number - 1; e > 0; e--) { - size_t i = state->input_column; - do - { - buffer_line->text[i - 1] = buffer_line->text[i]; - i++; - } while (buffer_line->text[i]); - buffer_line->text[i - 1] = 0; - buffer_line->length--; - state->input_column--; - if (state->input_first_shown_column > 0) + 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))) { - const struct BufferLine* current_line - = &state->input_buffer[state->input_row]; - if (display_length(state, current_line->text, - current_line->length) - >= state->edit_width - 4) - state->input_first_shown_column--; + goto_msgid(state, e); + return 0; } - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); - if (state->input_display_column - < state->input_first_shown_column) - state->input_first_shown_column - = state->input_display_column; - state->dirty = 1; - } - else if (state->input_row > 0) - { - move_up(state); - move_end(state); - erase_forward(state); } return 0; } int -erase_forward(struct DrawState* state) +prev_plural(struct DrawState* state) { - struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; if (state->edit_info_focused) return 0; + save_msgstr(state); + if (state->msgstr_index > 0) + state->msgstr_index--; + show_edit(state); + return 0; +} - if (buffer_line->text[state->input_column]) +int +save_msgstr(struct DrawState* state) +{ + uint32_t* to_save = NULL; + size_t to_save_size = 0; + struct PoEntry* current = NULL; + + state->show_edit = 0; + state->edit_info_focused = 0; + + if (state->input_buffer) { - size_t i = state->input_column; - while (i < MAXBUFLINE - 2 && buffer_line->text[i + 1]) + to_save_size = state->input_rows_count * MAXMSGLINE; + to_save = calloc(to_save_size, sizeof(uint32_t)); + if (!to_save) { - buffer_line->text[i] = buffer_line->text[i + 1]; - i++; + strcpy(state->error, errors[ERR_CANT_ALLOC]); + return 0; } - buffer_line->text[i] = 0; - buffer_line->length--; - state->dirty = 1; - } - else if (state->input_row < state->input_rows_count - 1) - { - if (!join_lines(state, state->input_row, 1)) + struct BufferLine* pinput_buffer = NULL; + for (size_t i = 0; i < state->input_rows_count; i++) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); - state->running = 0; + pinput_buffer = state->input_buffer + i; + if (i == 0) + u32_strncpy(to_save, pinput_buffer->text, + to_save_size * sizeof(uint32_t)); + else + { + u32_strncat(to_save, (uint32_t*)L"\\n", + to_save_size * sizeof(uint32_t)); + u32_strncat(to_save, pinput_buffer->text, + to_save_size * sizeof(uint32_t)); + } + free_bufferline(pinput_buffer); } } + free(state->input_buffer); + state->input_buffer = NULL; + state->input_rows_count = 0; + for (size_t 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->info_rows_count = 0; + state->info_buffer = NULL; + u32_encode_tabs(to_save, to_save_size * sizeof(uint32_t)); + current = &state->entries[state->msgid_number - 1]; + u32_match_msgid_ending(current->msgid, to_save, + to_save_size * sizeof(uint32_t)); + u32_set_msgstr(current, to_save, state->msgstr_index, 0, state); + update_warning(current->msgid, to_save, &current->warning); + state->input_changed_fuzzy = UNCHANGED; + + tb_hide_cursor(); + free(to_save); return 0; } int -erase_to_start(struct DrawState* state) +show_edit(struct DrawState* state) { - if (state->edit_info_focused) + if (!load_msgstr(state) || !load_info(state)) { - strcpy(state->error, errors[ERR_DLG_OPEN_QUIT]); + strcpy(state->error, errors[ERR_CANT_ALLOC]); + state->running = 0; return 0; } - size_t i = state->input_column; - struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; - size_t len = buffer_line->length; - do - { - buffer_line->text[i - state->input_column] - = buffer_line->text[i]; - i++; - } while (buffer_line->text[i]); - buffer_line->text[len - state->input_column] = 0; - buffer_line->length = len - state->input_column; - move_start(state); - state->dirty = 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; + state->input_row = 0; + state->input_first_shown_row = 0; + state->input_first_shown_column = 0; + state->info_first_shown_row = 0; + state->info_first_shown_column = 0; + move_start(state); + *state->error = 0; return 0; } int -erase_to_end(struct DrawState* state) +show_help(struct DrawState* state) { - if (state->edit_info_focused) - return 0; - struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; - buffer_line->text[state->input_column] = 0; - buffer_line->length = state->input_column; - move_end(state); - state->dirty = 1; + state->show_help = 1; + *state->error = 0; return 0; } int -insert_line(struct DrawState* state) +show_search(struct DrawState* state) { - if (state->edit_info_focused) - return 0; - state->input_rows_count++; - struct BufferLine* newbuf = realloc(state->input_buffer, - state->input_rows_count * sizeof(struct BufferLine)); - if (!newbuf) - { - strcpy(state->error, errors[ERR_CANT_ALLOC]); - state->running = 0; - return 0; - } + state->show_search = 1; + state->search_column = 0; + state->search_display_column = 0; + state->search_first_shown_column = 0; + if (!state->search) + state->search = calloc(MAXSEARCH, sizeof(uint32_t)); + *state->search = 0; + tb_set_cursor((state->maxx - state->search_width + 2) / 2, + state->maxy - 1 - SEARCH_HEIGHT + 1); + return 0; +} - state->input_buffer = newbuf; - init_bufferline(&state->input_buffer[state->input_rows_count - 1]); - uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); - if (!newtext) +int +toggle_fuzzy(struct DrawState* state) +{ + if (state->msgid_number == 1) { - strcpy(state->error, errors[ERR_CANT_ALLOC]); - state->running = 0; + strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); return 0; } - state->input_buffer[state->input_rows_count - 1].text = newtext; - for (size_t i = state->input_rows_count - 1; i > state->input_row + 1; - i--) + if (state->msgid_count > 0) { - u32_strncpy(state->input_buffer[i].text, - state->input_buffer[i - 1].text, MAXBUFLINE); - state->input_buffer[i].length - = state->input_buffer[i - 1].length; + state->entries[state->msgid_number - 1].flags ^= FL_FUZZY; + if (state->entries[state->msgid_number - 1].flags & FL_FUZZY) + { + state->fuzzy_count++; + if (state->input_changed_fuzzy == CLEARED) + state->input_changed_fuzzy = UNCHANGED; + else + state->input_changed_fuzzy = SET; + } + else + { + state->fuzzy_count--; + if (state->input_changed_fuzzy == SET) + state->input_changed_fuzzy = UNCHANGED; + else + state->input_changed_fuzzy = CLEARED; + } + state->dirty = 1; } - u32_strncpy(state->input_buffer[state->input_row + 1].text, - state->input_buffer[state->input_row].text + state->input_column, - MAXBUFLINE); - state->input_buffer[state->input_row + 1].length - = u32_strlen(state->input_buffer[state->input_row + 1].text); - state->input_buffer[state->input_row].text[state->input_column] = 0; - state->input_buffer[state->input_row].length - = u32_strlen(state->input_buffer[state->input_row].text); - - state->input_row++; - if (state->input_row - > state->input_first_shown_row + (EDIT_HEIGHT - 3) / 2) - state->input_first_shown_row - = state->input_row - (EDIT_HEIGHT - 3) / 2; - move_start(state); - state->dirty = 1; - return 0; } -struct DrawState* -join_lines(struct DrawState* state, size_t first_line, int forward) +int +toggle_info_focused(struct DrawState* state) { - state->input_column = state->input_buffer[first_line].length; - state->input_display_column = display_length(state, - state->input_buffer[state->input_row].text, - state->input_column); - u32_strncat(state->input_buffer[first_line].text, - state->input_buffer[first_line + 1].text, MAXBUFLINE); - state->input_buffer[first_line].length - = u32_strlen(state->input_buffer[first_line].text); - if (!forward) - { - state->input_row--; - if (state->input_row < 0) - state->input_row = 0; - } - for (size_t i = first_line + 1; i < state->input_rows_count - 1; i++) - { - u32_strncpy(state->input_buffer[i].text, - state->input_buffer[i + 1].text, MAXBUFLINE); - state->input_buffer[i].length - = state->input_buffer[i + 1].length; - } - free_bufferline(state->input_buffer + state->input_rows_count - 1); - state->input_rows_count--; - struct BufferLine* newbuf = realloc(state->input_buffer, - state->input_rows_count * sizeof(struct BufferLine)); - if (!newbuf) - return NULL; - state->input_buffer = newbuf; - state->dirty = 1; - - return state; + state->edit_info_focused = !state->edit_info_focused; + return 0; } -void -handle_key_event(struct tb_event* ev, struct DrawState* state) +int +yank_msgstr_to_paste_buffer(struct DrawState* state) { - const struct Key* current = NULL; + if (state->edit_info_focused) + return 0; - if (state->in_prompt) + if (state->msgid_number == 1) { - if (ev->ch == 'y' || ev->ch == 'n') - { - if (state->prompt_callback) - state->prompt_callback(state, ev); - state->in_prompt = 0; - *state->prompt = 0; - } - else if (ev->key == TB_KEY_ESC) - cancel_close(state); - return; + strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); + return 0; } - /* Remember to also edit the following condition if you reassign motion - * keys */ - if (ev->key != TB_KEY_ARROW_DOWN && ev->key != TB_KEY_ARROW_UP - && state->show_edit) - state->saved_column = -1; + struct PoEntry* current = &state->entries[state->msgid_number - 1]; + size_t msgstr_num_lines = 0; + size_t lines_to_init = 0; + size_t lines_to_free = 0; + struct BufferLine* newbuf = NULL; + const uint32_t* pmsgstr = NULL; + struct BufferLine* pbuffer = NULL; - for (int key = 0; key < LEN(top_level_keys); key++) + if (!current->msgstr || !*(current->msgstr + state->msgstr_index)) { - current = top_level_keys + key; - if (((current->ev.key == ev->key) && !ev->ch) - || (current->ev.ch && (current->ev.ch == ev->ch))) - if (current->callback && !current->callback(state)) - return; + for (size_t i = 0; i < state->paste_rows_count; i++) + free_bufferline(state->paste_buffer + i); + free(state->paste_buffer); + state->paste_buffer = NULL; + state->paste_rows_count = 0; + return 0; } - if (state->show_help) - { - strcpy(state->error, errors[ERR_DLG_OPEN]); - return; - } - else if (state->show_edit) + msgstr_num_lines + = u32_lines_in_string(*(current->msgstr + state->msgstr_index), + 0, 0); + lines_to_init = state->paste_rows_count < msgstr_num_lines + ? msgstr_num_lines - state->paste_rows_count + : 0; + lines_to_free = state->paste_rows_count > msgstr_num_lines + ? state->paste_rows_count - msgstr_num_lines + : 0; + + for (size_t i = 0; i < lines_to_free; i++) + free_bufferline( + state->paste_buffer + state->paste_rows_count - i - 1); + if (!state->paste_buffer) + newbuf = calloc(msgstr_num_lines, sizeof(struct BufferLine)); + else + newbuf = realloc(state->paste_buffer, + msgstr_num_lines * sizeof(struct BufferLine)); + pmsgstr = *(current->msgstr + state->msgstr_index); + + if (!newbuf) + return 0; + + for (size_t i = 0; i < lines_to_init; i++) { - for (int key = 0; key < LEN(edit_keys); key++) - { - current = edit_keys + key; - if (((current->ev.key == ev->key) && !ev->ch) - || (current->ev.ch - && (current->ev.ch == ev->ch))) - if (current->callback - && !current->callback(state)) - return; - } - if (ev->ch) - { - insert_char(state, ev->ch); - return; - } + pbuffer = newbuf + msgstr_num_lines - 1 - i; + init_bufferline(pbuffer); + uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + if (!newtext) + return 0; + pbuffer->text = newtext; } - else if (state->show_search) + + pbuffer = newbuf; + while (*pmsgstr) { - for (int key = 0; key < LEN(search_keys); key++) - { - current = search_keys + key; - if (((current->ev.key == ev->key) && !ev->ch) - || (current->ev.ch - && (current->ev.ch == ev->ch))) - if (current->callback - && !current->callback(state)) - return; - } - if (ev->ch) - { - insert_search_char(state, ev->ch); - return; - } + size_t len = 0; + size_t newlen = 0; + const uint32_t* old_pmsgstr = pmsgstr; + + len = u32_next_line(*(current->msgstr + state->msgstr_index), + &pmsgstr, 0, 0); + u32_strncpy(pbuffer->text, old_pmsgstr, + MIN(len + 1, MAXBUFLINE)); + newlen = u32_decode_tabs(pbuffer->text, MAXBUFLINE); + pbuffer->length = newlen; + pbuffer++; } - else + + state->paste_rows_count = msgstr_num_lines; + state->paste_buffer = newbuf; + + return 0; +} + +int +write_file(struct DrawState* state) +{ + int result = save_file(state->entries, state->real_msgid_count, + state->filename, state->nplurals); + switch (result) { - for (int key = 0; key < LEN(main_keys); key++) - { - current = main_keys + key; - if (((current->ev.key == ev->key) && !ev->ch) - || (current->ev.ch - && (current->ev.ch == ev->ch))) - if (current->callback - && !current->callback(state)) - return; - } + case SAVE_ERR_CANT_ALLOC: + strcpy(state->error, errors[ERR_CANT_ALLOC]); + state->running = 0; + break; + case SAVE_ERR_CANT_OPEN_FILE: + strcpy(state->error, errors[ERR_CANT_SAVE]); + state->running = 0; + break; + case SAVE_ERR_CANT_MOVE_FILE: + strcpy(state->error, strerror(errno)); + state->running = 0; + break; + default: + *state->error = 0; + state->dirty = 0; } - - strcpy(state->error, errors[ERR_UNKNOWN_KEY]); + return 0; } int