poe

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

чување 289d06d7f45a635bc76c3a776f96d32091fb1dc4
родитељ b4dd32975d80b47d0605bc6ef1fef90c44c0c86b
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sat,  3 Jul 2021 23:26:33 +0200

msgid -> info box; toggle info box focus with F6; when info box is focused, movement keys scroll the info area

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

Diffstat:
MTODO | 8++++----
Mconfig.def.h | 6+++++-
Mconfig.h | 6+++++-
Mdraw.c | 50++++++++++++++++++++++++++++++++++++++------------
Mdraw.h | 10++++++++--
Mpo.c | 6++++++
Mpoe.1.in | 1+
Mpoe.c | 276+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
измењених датотека: 8, додавања: 322(+), брисања: 41(-)

diff --git a/TODO b/TODO @@ -13,11 +13,11 @@ [ ] Yank/paste (entire current msgstr) - [ ] Multiline msgid display - [ ] Also msgid_plural + [~] Multiline msgid display + [x] Also msgid_plural [ ] Also Plural-Forms - [ ] (Multiline) comment display; ~key binding: "?"~ - [ ] Toggle msgid/msgstr focus with F6; when msgid is focused, + [x] (Multiline) comment display; ~key binding: "?"~ + [x] Toggle msgid/msgstr focus with F6; when msgid is focused, arrow keys scroll the msgid area [/] ~Edit dialog overhaul? Don't display as dialog, but full-screen so more information can be shown~ diff --git a/config.def.h b/config.def.h @@ -3,8 +3,12 @@ #define DLG_BG TB_WHITE #define EDIT_MSGID_FG TB_BLACK | TB_BOLD #define EDIT_MSGID_BG TB_WHITE -#define EDIT_MSGSTR_FG TB_YELLOW | TB_BOLD +#define EDIT_MSGID_FOCUS_FG TB_BLACK +#define EDIT_MSGID_FOCUS_BG TB_WHITE +#define EDIT_MSGSTR_FG TB_BLACK | TB_BOLD #define EDIT_MSGSTR_BG TB_BLACK +#define EDIT_MSGSTR_FOCUS_FG TB_YELLOW | TB_BOLD +#define EDIT_MSGSTR_FOCUS_BG TB_BLACK #define ERROR_FG TB_WHITE | TB_BOLD #define ERROR_BG TB_RED #define FLAG_FG TB_YELLOW | TB_BOLD diff --git a/config.h b/config.h @@ -3,8 +3,12 @@ #define DLG_BG TB_WHITE #define EDIT_MSGID_FG TB_BLACK | TB_BOLD #define EDIT_MSGID_BG TB_WHITE -#define EDIT_MSGSTR_FG TB_YELLOW | TB_BOLD +#define EDIT_MSGID_FOCUS_FG TB_BLACK +#define EDIT_MSGID_FOCUS_BG TB_WHITE +#define EDIT_MSGSTR_FG TB_BLACK | TB_BOLD #define EDIT_MSGSTR_BG TB_BLACK +#define EDIT_MSGSTR_FOCUS_FG TB_YELLOW | TB_BOLD +#define EDIT_MSGSTR_FOCUS_BG TB_BLACK #define ERROR_FG TB_WHITE | TB_BOLD #define ERROR_BG TB_RED #define FLAG_FG TB_YELLOW | TB_BOLD diff --git a/draw.c b/draw.c @@ -245,15 +245,38 @@ draw_editbox(const struct DrawState* state) strlen(editbox_title)+2, 1, 1, CENTER)) return NULL; - draw_rect(startx+1, endx-1, starty+1, endy-h/2-1, - EDIT_MSGID_FG, EDIT_MSGID_BG); - u32_draw_string(startx+1, starty+1, EDIT_MSGID_FG, EDIT_MSGID_BG, - state->entries[state->msgid_number-1].msgid, w-2, - w-2, 1, 1, LEFT); + uint16_t fg = state->edit_info_focused ? EDIT_MSGID_FOCUS_FG : + EDIT_MSGID_FG; + uint16_t bg = state->edit_info_focused ? EDIT_MSGID_FOCUS_BG : + EDIT_MSGID_BG; + + draw_rect(startx+1, endx-1, starty+1, endy-h/2-1, fg, bg); + for (size_t i = 0; i < (h-3)/2+1 && state->info_first_shown_row + i < + state->info_rows_count; i++) + { + struct BufferLine* curline = &state->info_buffer[ + state->info_first_shown_row+i]; + if (!curline || !curline->text) + return NULL; + if (curline->length > state->info_first_shown_column) + u32_draw_string(startx+1, starty+1+i, fg, + bg, curline->text + + state->info_first_shown_column, + w-3, w-3, 1, 1, LEFT); + } + /* + *u32_draw_string(startx+1, starty+1, EDIT_MSGID_FG, EDIT_MSGID_BG, + * state->entries[state->msgid_number-1].msgid, w-2, + * w-2, 1, 1, LEFT); + */ + - draw_rect(startx+1, endx-1, endy-h/2-1, endy-2, - EDIT_MSGSTR_FG, EDIT_MSGSTR_BG); + fg = state->edit_info_focused ? EDIT_MSGSTR_FG : + EDIT_MSGSTR_FOCUS_FG; + bg = state->edit_info_focused ? EDIT_MSGSTR_BG : + EDIT_MSGSTR_FOCUS_BG; + draw_rect(startx+1, endx-1, endy-h/2-1, endy-2, fg, bg); for (size_t i = 0; i < (h-3)/2+1 && state->input_first_shown_row + i < state->input_rows_count; i++) { @@ -263,15 +286,18 @@ draw_editbox(const struct DrawState* state) return NULL; if (curline->length > state->input_first_shown_column) u32_draw_string(startx+1, endy-h/2-1+i, - EDIT_MSGSTR_FG, EDIT_MSGSTR_BG, curline->text + + fg, bg, curline->text + state->input_first_shown_column, w-3, w-3, 1, 1, LEFT); } - tb_set_cursor(startx+2+state->input_display_column - - state->input_first_shown_column, - endy-h/2-1 + state->input_row - - state->input_first_shown_row); + if (state->edit_info_focused) + tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR); + else + tb_set_cursor(startx+2+state->input_display_column - + state->input_first_shown_column, endy-h/2-1 + + state->input_row - + state->input_first_shown_row); char sbuf[MAXBUFLINE]; if (entry->msgstr_count > 1) diff --git a/draw.h b/draw.h @@ -31,7 +31,7 @@ struct DrawState { char* error; char* prompt; char* filename; - struct BufferLine* input_buffer; + struct BufferLine* input_buffer; /* edit box */ int input_column; int input_row; int input_first_shown_column; @@ -39,6 +39,11 @@ struct DrawState { int input_rows_count; int input_display_column; int saved_column; + struct BufferLine* info_buffer; /* information pane above + * edit box */ + int info_first_shown_column; + int info_first_shown_row; + int info_rows_count; struct PoEntry* entries; void (*prompt_callback)(struct DrawState*, struct tb_event*); int running; @@ -46,12 +51,13 @@ struct DrawState { int in_prompt; int show_help; int show_edit; + int edit_info_focused; int maxx; int maxy; size_t msgid_number; size_t msgid_count; size_t msgid_size; - int msgstr_index; /* with msgstr[] */ + int msgstr_index; /* with msgstr[] */ size_t first_shown_msgid; }; diff --git a/po.c b/po.c @@ -417,6 +417,12 @@ parse_po_line(const char* line, struct PoEntry** entries, size_t* entries_size, else if (*pline) return PARSE_ERR_SYNTAX; } + else + { + *ptoken++ = *pline++; + (*col)++; + } + break; case '"': /* skip beginning and end quote */ if (ptoken == token || *(pline+1) == 0) diff --git a/poe.1.in b/poe.1.in @@ -94,6 +94,7 @@ _ \fCC-P\fP@Show previous plural form of msgstr \fCC-N\fP@Show next plural form of msgstr \fCEscape\fP@Cancel changes and close dialog +\fCF6\fP@Toggle focus between info box and edit box \fCC-Z\fP@Toggle fuzzy flag \fCC-A\fP or \fCHome\fP@Go to start of line \fCC-E\fP or \fCEnd\fP@Go to end of line diff --git a/poe.c b/poe.c @@ -91,6 +91,7 @@ quit_callback(struct DrawState* state, struct tb_event* ev) } } +struct BufferLine* load_info(struct DrawState* state); struct BufferLine* load_msgstr(struct DrawState* state); void save_msgstr(struct DrawState* state); void move_up(struct DrawState* state); @@ -117,6 +118,141 @@ struct DrawState* insert_line(struct DrawState* state); struct DrawState* join_lines(struct DrawState* state, size_t first_line); struct BufferLine* +load_info(struct DrawState* state) +{ + struct PoEntry* current = &state->entries[state->msgid_number-1]; + size_t msgid_num_lines = u32_lines_in_string(current->msgid); + size_t msgid_plural_num_lines = u32_lines_in_string( + current->msgid_plural); + size_t num_lines = 0; + struct BufferLine* newbuf = NULL; + struct BufferLine* pnewbuf = NULL; + + if (current->msgid) + num_lines += 1 + msgid_num_lines + 1; + num_lines += 3; /* Plural-Forms */ + if (current->msgid_plural) + num_lines += 1 + msgid_plural_num_lines + 1; + if (current->comments) + num_lines += 1 + current->comment_lines + 1; + if (current->ref_comments) + num_lines += 1 + 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; + uint32_t* pumsgid = NULL; + if (current->msgid) + { + pumsgid = current->msgid; + newlen = u32_u8_strncpy(pnewbuf->text, "msgid:", + MAXBUFLINE); + pnewbuf->length = newlen; + pnewbuf++; + for (size_t i = 0; i < msgid_num_lines; i++) + { + size_t len = u32_line_length(pumsgid); + newlen = 0; + u32_strncpy(pnewbuf->text, pumsgid, MIN(len+1, + MAXBUFLINE)); + newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE); + pnewbuf->length = newlen; + pumsgid += len+(pumsgid[len] ? 2 : 0); + pnewbuf++; + } + pnewbuf->text[0] = 0; + pnewbuf->length = 0; + pnewbuf++; + } + /* TODO: Parse first msgid for Plural-Forms */ + newlen = u32_u8_strncpy(pnewbuf->text, "Plural-Forms:", MAXBUFLINE); + pnewbuf->length = newlen; + pnewbuf++; + newlen = u32_u8_strncpy(pnewbuf->text, "<Reserved>", MAXBUFLINE); + pnewbuf->length = newlen; + pnewbuf++; + pnewbuf->text[0] = 0; + pnewbuf->length = 0; + pnewbuf++; + if (current->msgid_plural) + { + newlen = u32_u8_strncpy(pnewbuf->text, "msgid_plural:", + MAXBUFLINE); + pnewbuf->length = newlen; + pnewbuf++; + pumsgid = current->msgid_plural; + for (size_t i = 0; i < msgid_plural_num_lines; i++) + { + size_t len = u32_line_length(pumsgid); + newlen = 0; + u32_strncpy(pnewbuf->text, pumsgid, MIN(len+1, + MAXBUFLINE)); + newlen = u32_decode_tabs(pnewbuf->text, MAXBUFLINE); + pnewbuf->length = newlen; + pumsgid += len+(pumsgid[len] ? 2 : 0); + pnewbuf++; + } + pnewbuf->text[0] = 0; + pnewbuf->length = 0; + pnewbuf++; + } + if (current->comments) + { + newlen = u32_u8_strncpy(pnewbuf->text, "Comments:", + MAXBUFLINE); + pnewbuf->length = newlen; + pnewbuf++; + for (size_t i = 0; i < current->comment_lines; i++) + { + uint32_t* comment = current->comments[i]; + size_t len = u32_strlen(comment); + newlen = u32_strncpy(pnewbuf->text, comment, + MIN(len+1, MAXBUFLINE)); + pnewbuf->length = newlen; + pnewbuf++; + } + pnewbuf->text[0] = 0; + pnewbuf->length = 0; + pnewbuf++; + } + if (current->ref_comments) + { + newlen = u32_u8_strncpy(pnewbuf->text, "References:", + MAXBUFLINE); + pnewbuf->length = newlen; + pnewbuf++; + for (size_t i = 0; i < current->ref_comment_lines; i++) + { + char* ref_comment = current->ref_comments[i]; + size_t len = strlen(ref_comment); + newlen = u32_u8_strncpy(pnewbuf->text, ref_comment, + MIN(len+1, MAXBUFLINE)); + pnewbuf->length = newlen; + pnewbuf++; + } + } + + state->info_buffer = newbuf; + + return state->info_buffer; +} + +struct BufferLine* load_msgstr(struct DrawState* state) { int msgstr_index = state->msgstr_index; @@ -195,6 +331,11 @@ save_msgstr(struct DrawState* state) } free(state->input_buffer); state->input_buffer = NULL; + if (state->info_buffer) + for (size_t i = 0; i < state->info_rows_count; i++) + free_bufferline(state->info_buffer+i); + free(state->info_buffer); + state->info_buffer = NULL; u32_encode_tabs(to_save, MAXBUFLINE); u32_set_msgstr(&state->entries[state->msgid_number-1], to_save, state->msgstr_index, 0); @@ -209,11 +350,23 @@ cancel_msgstr(struct DrawState* state) free_bufferline(state->input_buffer+i); free(state->input_buffer); state->input_buffer = NULL; + if (state->info_buffer) + for (size_t i = 0; i < state->info_rows_count; i++) + free_bufferline(state->info_buffer+i); + free(state->info_buffer); + state->info_buffer = NULL; } void move_up(struct DrawState* state) { + if (state->edit_info_focused) + { + if (state->info_first_shown_row > 0) + state->info_first_shown_row--; + return; + } + if (state->input_row > 0) state->input_row--; if (state->input_first_shown_row > state->input_row) @@ -239,6 +392,14 @@ move_up(struct DrawState* state) void move_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++; + return; + } + if (state->input_row < state->input_rows_count-1) state->input_row++; if (state->input_first_shown_row + (EDIT_HEIGHT-3)/2 < @@ -266,6 +427,13 @@ move_down(struct DrawState* state) void move_start(struct DrawState* state) { + if (state->edit_info_focused) + { + state->info_first_shown_row = 0; + state->info_first_shown_column = 0; + return; + } + state->input_column = 0; state->input_display_column = 0; state->input_first_shown_column = 0; @@ -313,6 +481,14 @@ move_right(struct DrawState* state) void move_end(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-1 - + (EDIT_HEIGHT-3)/2; + state->info_first_shown_column = 0; + return; + } size_t len = state->input_buffer[state->input_row].length; state->input_column = len; @@ -399,20 +575,26 @@ move_list_page_down(struct DrawState* state) void next_plural(struct DrawState* state) { + if (state->edit_info_focused) + return; struct PoEntry* current = &state->entries[state->msgid_number-1]; save_msgstr(state); if (state->msgstr_index + 1 < current->msgstr_count) state->msgstr_index++; load_msgstr(state); + load_info(state); } void prev_plural(struct DrawState* state) { + if (state->edit_info_focused) + return; save_msgstr(state); if (state->msgstr_index > 0) state->msgstr_index--; load_msgstr(state); + load_info(state); } void @@ -472,6 +654,8 @@ input_length(const struct DrawState* state, const size_t max_index) 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) @@ -501,6 +685,8 @@ insert_char(struct DrawState* state, uint32_t ch) void erase_to_start(struct DrawState* state) { + if (state->edit_info_focused) + return; size_t i = state->input_column; struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; size_t len = buffer_line->length; @@ -519,6 +705,8 @@ erase_to_start(struct DrawState* state) void erase_to_end(struct DrawState* state) { + if (state->edit_info_focused) + return; struct BufferLine* buffer_line = &state->input_buffer[state->input_row]; buffer_line->text[state->input_column] = 0; buffer_line->length = state->input_column; @@ -528,6 +716,8 @@ erase_to_end(struct DrawState* state) struct DrawState* insert_line(struct DrawState* state) { + if (state->edit_info_focused) + return state; state->input_rows_count++; struct BufferLine* newbuf = realloc( state->input_buffer, state->input_rows_count * @@ -625,8 +815,9 @@ handle_editbox_key_event(struct tb_event* ev, struct DrawState* state) move_right(state); else if (ev->key == TB_KEY_ARROW_UP) move_up(state); - else if (ev->key == TB_KEY_BACKSPACE - || ev->key == TB_KEY_BACKSPACE2) + else if ((ev->key == TB_KEY_BACKSPACE + || ev->key == TB_KEY_BACKSPACE2) + && !state->edit_info_focused) { if (state->input_column > 0) { @@ -675,7 +866,7 @@ handle_editbox_key_event(struct tb_event* ev, struct DrawState* state) erase_to_start(state); else if (ev->key == TB_KEY_CTRL_Z) toggle_fuzzy(state); - else if (ev->key == TB_KEY_DELETE) + else if (ev->key == TB_KEY_DELETE && !state->edit_info_focused) { if (buffer_line->text[state->input_column]) { @@ -706,32 +897,65 @@ handle_editbox_key_event(struct tb_event* ev, struct DrawState* state) cancel_msgstr(state); tb_set_cursor(TB_HIDE_CURSOR, TB_HIDE_CURSOR); } + else if (ev->key == TB_KEY_F6) + state->edit_info_focused = !state->edit_info_focused; else if (ev->key == TB_KEY_HOME || ev->key == TB_KEY_CTRL_A) move_start(state); else if (ev->key == TB_KEY_PGDN || ev->key == TB_KEY_CTRL_F) { - save_msgstr(state); - move_list_down(state); - state->msgstr_index = 0; - load_msgstr(state); - state->input_row = 0; - state->input_first_shown_row = 0; - move_start(state); - state->error[0] = 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; + /* + *else + * move_end(state); + */ + } + else + { + save_msgstr(state); + move_list_down(state); + state->msgstr_index = 0; + load_msgstr(state); + load_info(state); + 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] = 0; + } } else if (ev->key == TB_KEY_PGUP || ev->key == TB_KEY_CTRL_B) { - save_msgstr(state); - move_list_up(state); - state->msgstr_index = 0; - load_msgstr(state); - state->input_row = 0; - state->input_first_shown_row = 0; - move_start(state); - state->error[0] = 0; + 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); + } + else + { + save_msgstr(state); + move_list_up(state); + state->msgstr_index = 0; + load_msgstr(state); + load_info(state); + 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] = 0; + } } else if (ev->key == TB_KEY_SPACE) insert_char(state, ' '); @@ -809,11 +1033,14 @@ handle_key_event(struct tb_event* ev, struct DrawState* state) else { state->msgstr_index = 0; - if (load_msgstr(state)) + if (load_msgstr(state) && load_info(state)) { 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] = 0; } @@ -940,15 +1167,22 @@ main(int argc, char** argv) state.input_buffer = NULL; state.input_column = 0; state.input_first_shown_column = 0; + state.input_first_shown_row = 0; + state.input_rows_count = 0; state.input_display_column = 0; state.saved_column = -1; + state.info_buffer = NULL; + state.info_first_shown_column = 0; + state.info_first_shown_row = 0; + state.info_rows_count = 0; state.prompt = prompt; state.prompt_callback = NULL; state.running = 1; state.dirty = 0; state.in_prompt = 0; - state.show_edit = 0; state.show_help = 0; + state.show_edit = 0; + state.edit_info_focused = 0; state.msgid_number = state.msgid_count > 0 ? 1 : 0; state.msgstr_index = 0; state.first_shown_msgid = state.msgid_number;