sled

Једноставни уређивач текста
Дневник | Датотеке | Референце | ПРОЧИТАЈМЕ | ЛИЦЕНЦА

чување 6ea2dd3f75174c680d0eaf08792222f2d823faea
родитељ 16e40914fc3cea52c854011cffbb0f517787d254
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Tue, 22 Feb 2022 20:16:49 +0100

WIP copy/paste

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

Diffstat:
Mconfig.def.h | 14+++++++++++---
Mconfig.h | 14+++++++++++---
Mdraw.c | 15++++++++-------
Mdraw.h | 7++++---
Msled.1.in | 6+++++-
Msled.c | 245+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
измењених датотека: 6, додавања: 209(+), брисања: 92(-)

diff --git a/config.def.h b/config.def.h @@ -69,11 +69,13 @@ int move_screen_top(struct DrawState* state); int move_start(struct DrawState* state); int move_top(struct DrawState* state); int move_up(struct DrawState* state); +int paste_from_paste(struct DrawState* state); int reread_or_callback(struct DrawState* state); int show_go_to_line(struct DrawState* state); int show_help(struct DrawState* state); int toggle_selection(struct DrawState* state); int write_file(struct DrawState* state); +int yank_to_paste(struct DrawState* state); /* clang-format off */ @@ -102,6 +104,8 @@ static const struct Key global_keys[] = { .callback = move_start }, { .ev = { .key = TB_KEY_CTRL_B }, .callback = move_page_up }, + { .ev = { .key = TB_KEY_CTRL_C }, + .callback = yank_to_paste }, { .ev = { .key = TB_KEY_CTRL_E }, .callback = move_end }, { .ev = { .key = TB_KEY_CTRL_F }, @@ -122,6 +126,8 @@ static const struct Key global_keys[] = { .callback = move_next_word }, { .ev = { .key = TB_KEY_CTRL_U }, .callback = erase_to_start }, + { .ev = { .key = TB_KEY_CTRL_V }, + .callback = paste_from_paste }, { .ev = { .key = TB_KEY_DELETE }, .callback = erase_forward }, { .ev = { .key = TB_KEY_F1 }, .callback = show_help }, @@ -167,7 +173,7 @@ static const struct Key input_dialog_keys[] = { /* Only when in insert mode */ static const struct Key insert_keys[] = { - { .ev = { .key = TB_KEY_CTRL_C }, + { .ev = { .key = TB_KEY_CTRL_M }, .callback = enter_command_mode }, { .ev = { .key = TB_KEY_ENTER }, .callback = insert_line }, @@ -178,7 +184,7 @@ static const struct Key insert_keys[] = { /* Only when in command mode */ static const struct Key command_keys[] = { - { .ev = { .key = TB_KEY_CTRL_C }, + { .ev = { .key = TB_KEY_CTRL_M }, .callback = enter_insert_mode }, { .ev = { .ch = ':' }, .callback = show_go_to_line }, { .ev = { .ch = '0' }, .callback = move_start }, @@ -192,10 +198,12 @@ static const struct Key command_keys[] = { { .ev = { .ch = 'L' }, .callback = move_screen_bottom }, { .ev = { .ch = 'l' }, .callback = move_right }, { .ev = { .ch = 'M' }, .callback = move_screen_middle }, + { .ev = { .ch = 'p' }, .callback = paste_from_paste }, { .ev = { .ch = 'q' }, .callback = exit_program }, { .ev = { .ch = 'v' }, .callback = toggle_selection }, { .ev = { .ch = 'W' }, .callback = move_prev_word }, - { .ev = { .ch = 'w' }, .callback = move_next_word } + { .ev = { .ch = 'w' }, .callback = move_next_word }, + { .ev = { .ch = 'y' }, .callback = yank_to_paste } }; /* clang-format on */ #endif /* SLED_C_GLOBALS */ diff --git a/config.h b/config.h @@ -69,11 +69,13 @@ int move_screen_top(struct DrawState* state); int move_start(struct DrawState* state); int move_top(struct DrawState* state); int move_up(struct DrawState* state); +int paste_from_paste(struct DrawState* state); int reread_or_callback(struct DrawState* state); int show_go_to_line(struct DrawState* state); int show_help(struct DrawState* state); int toggle_selection(struct DrawState* state); int write_file(struct DrawState* state); +int yank_to_paste(struct DrawState* state); /* clang-format off */ @@ -102,6 +104,8 @@ static const struct Key global_keys[] = { .callback = move_start }, { .ev = { .key = TB_KEY_CTRL_B }, .callback = move_page_up }, + { .ev = { .key = TB_KEY_CTRL_C }, + .callback = yank_to_paste }, { .ev = { .key = TB_KEY_CTRL_E }, .callback = move_end }, { .ev = { .key = TB_KEY_CTRL_F }, @@ -122,6 +126,8 @@ static const struct Key global_keys[] = { .callback = move_next_word }, { .ev = { .key = TB_KEY_CTRL_U }, .callback = erase_to_start }, + { .ev = { .key = TB_KEY_CTRL_V }, + .callback = paste_from_paste }, { .ev = { .key = TB_KEY_DELETE }, .callback = erase_forward }, { .ev = { .key = TB_KEY_F1 }, .callback = show_help }, @@ -167,7 +173,7 @@ static const struct Key input_dialog_keys[] = { /* Only when in insert mode */ static const struct Key insert_keys[] = { - { .ev = { .key = TB_KEY_CTRL_C }, + { .ev = { .key = TB_KEY_CTRL_M }, .callback = enter_command_mode }, { .ev = { .key = TB_KEY_ENTER }, .callback = insert_line }, @@ -178,7 +184,7 @@ static const struct Key insert_keys[] = { /* Only when in command mode */ static const struct Key command_keys[] = { - { .ev = { .key = TB_KEY_CTRL_C }, + { .ev = { .key = TB_KEY_CTRL_M }, .callback = enter_insert_mode }, { .ev = { .ch = ':' }, .callback = show_go_to_line }, { .ev = { .ch = '0' }, .callback = move_start }, @@ -192,10 +198,12 @@ static const struct Key command_keys[] = { { .ev = { .ch = 'L' }, .callback = move_screen_bottom }, { .ev = { .ch = 'l' }, .callback = move_right }, { .ev = { .ch = 'M' }, .callback = move_screen_middle }, + { .ev = { .ch = 'p' }, .callback = paste_from_paste }, { .ev = { .ch = 'q' }, .callback = exit_program }, { .ev = { .ch = 'v' }, .callback = toggle_selection }, { .ev = { .ch = 'W' }, .callback = move_prev_word }, - { .ev = { .ch = 'w' }, .callback = move_next_word } + { .ev = { .ch = 'w' }, .callback = move_next_word }, + { .ev = { .ch = 'y' }, .callback = yank_to_paste } }; /* clang-format on */ #endif /* SLED_C_GLOBALS */ diff --git a/draw.c b/draw.c @@ -111,8 +111,9 @@ init_drawstate(struct DrawState* state, char* error, char* action, state->saved_column = -1; state->help_width = calculate_help_width(state); state->input_dialog_width = calculate_input_dialog_width(state); - state->paste_buffer = NULL; - state->paste_rows_count = 0; + state->paste = NULL; + state->paste_count = 0; + state->paste_size = 0; state->prompt = prompt; state->prompt_callback = NULL; state->input_callback = NULL; @@ -137,9 +138,9 @@ free_drawstate(struct DrawState* state) for (row = 0; row < state->buffer_size; row++) free_bufferline(state->buffer + row); free(state->buffer); - for (row = 0; row < state->paste_rows_count; row++) - free_bufferline(state->paste_buffer + row); - free(state->paste_buffer); + for (row = 0; row < state->paste_size; row++) + free_bufferline(state->paste + row); + free(state->paste); free(state->input); } @@ -563,8 +564,8 @@ draw_help(const struct DrawState* state) draw_box(startx, endx, starty, endy, DLG_FG, DLG_BG); if (!draw_string(startx, starty, TITLE_FG, TITLE_BG, help_title, - strlen(help_title) + 2, w - 2, 1, 1, CENTER, 0, 0, NULL, 0, - 0, 0, 0, 0, 0)) + strlen(help_title) + 2, w, 1, 1, CENTER, 0, 0, NULL, 0, 0, + 0, 0, 0, 0)) return NULL; while (row < LEN(help)) { diff --git a/draw.h b/draw.h @@ -46,13 +46,14 @@ struct DrawState { int input_display_column; int input_column; char* input_title; - int rows_count; + size_t rows_count; int display_column; int saved_column; int help_width; int input_dialog_width; - struct BufferLine* paste_buffer; - int paste_rows_count; + struct BufferLine* paste; + size_t paste_count; + size_t paste_size; void (*prompt_callback)(struct DrawState*, struct tb_event*); void (*input_callback)(struct DrawState*); int running; diff --git a/sled.1.in b/sled.1.in @@ -90,12 +90,13 @@ _ \fCHome\fP or \fCC-A\fP@Go to start of line \fCPgUp\fP or \fCC-B\fP@Go to previous page \fCBackspace\fP@Erase character before cursor -\fCC-C\fP@Switch between command and insert mode +\fCC-C\fP@Yank to paste buffer \fCDelete\fP@Erase character under cursor \fCEnd\fP or \fCC-E\fP@Go to end of line \fCPgDown\fP or \fCC-F\fP@Go to next page \fCC-K\fP@Erase to end of line \fCC-L\fP@Show Go to line dialog +\fCC-M\fP@Switch between command and insert mode \fCC-O\fP@Reread (reopen) file \fCC-Q\fP@Quit \fCC-R\fP@Go to previous word @@ -103,6 +104,7 @@ _ \fCC-Space\fP@Toggle selection mode \fCC-T\fP@Go to next word \fCC-U\fP@Erase to start of line +\fCC-V\fP@Paste from paste buffer .TE . .sp 1 @@ -137,10 +139,12 @@ _ \fCL\fP@Go to last line on the screen \fCl\fP@Go to next character \fCM\fP@Go to middle line on the screen +\fCp\fP@Paste from paste buffer \fCq\fP@Quit \fCv\fP@Toggle selection mode \fCW\fP@Go to previous word \fCw\fP@Go to next word +\fCy\fP@Yank to paste buffer .TE . .sp 1 diff --git a/sled.c b/sled.c @@ -90,9 +90,9 @@ reread_file(struct DrawState* state) for (row = 0; row < state->buffer_size; row++) free_bufferline(state->buffer + row); free(state->buffer); - for (row = 0; row < state->paste_rows_count; row++) - free_bufferline(state->paste_buffer + row); - free(state->paste_buffer); + for (row = 0; row < state->paste_size; row++) + free_bufferline(state->paste + row); + free(state->paste); init_drawstate(state, state->error, state->action, state->filename, state->prompt); @@ -355,94 +355,189 @@ save_file_cleanup: return SAVE_ERR_NONE; } -struct DrawState* -paste_paste_buffer_to_input(struct DrawState* state) +int +yank_to_paste(struct DrawState* state) { - /* - if (state->edit_info_focused) - return state; + /* Selection start row/col */ + size_t ssr = 0; + size_t ssc = 0; + /* Selection end row/col */ + size_t ser = 0; + size_t sec = 0; + struct BufferLine* newbuf = NULL; + + if (!SEL_NOT_EMPTY(state)) + return 0; - if (!state->in_prompt && *state->input_buffer->text) + if (state->sel_start_row <= state->sel_end_row) { - state->in_prompt = 1; - strcpy(state->prompt, prompt_overwrite); - state->prompt_callback = overwrite_paste_callback; - return state; + ssr = state->sel_start_row; + ssc = state->sel_start_col; + ser = state->sel_end_row; + sec = state->sel_end_col; + } + else /* Swap */ + { + ssr = state->sel_end_row; + ssc = state->sel_end_col; + ser = state->sel_start_row; + sec = state->sel_start_col; } - if (state->msgid_number == 1) + state->paste_count = ser - ssr + 1; + if (!state->paste_size) { - strcpy(state->error, errors[ERR_ILLEGAL_ON_FIRST]); - return NULL; + state->paste_size = ALLOC_DELTA; + newbuf = calloc(state->paste_size, sizeof(struct BufferLine)); + } + else if (state->paste_count > state->paste_size) + { + state->paste_size += ALLOC_DELTA; + newbuf = realloc(state->paste, + state->paste_size * sizeof(struct BufferLine)); + } + else + newbuf = state->paste; + for (size_t row = state->paste_size - ALLOC_DELTA; + row < state->paste_size; row++) + { + uint32_t* newtext = NULL; + init_bufferline(newbuf + row); + newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + if (!newtext) + strcpy(state->error, errors[ERR_CANT_ALLOC]); + newbuf[row].text = newtext; + newbuf[row].length = 0; + } + state->paste = newbuf; + if (state->paste_count == 1) + state->paste[0].length = u32_strncpy(state->paste[0].text, + state->buffer[ssr].text + ssc, sec - ssc + 1); + else + { + state->paste[0].length = u32_strcpy(state->paste[0].text, + state->buffer[ssr].text + ssc); + for (size_t row = 1; row < state->paste_count - 1; row++) + state->paste[row].length + = u32_strcpy(state->paste[row].text, + state->buffer[ssr + row].text); + state->paste[state->paste_count - 1].length + = u32_strncpy(state->paste[state->paste_count - 1].text, + state->buffer[ser].text, sec + 1); } - size_t lines_to_init = 0; - size_t lines_to_free = 0; - struct BufferLine* pinput = NULL; + clear_selection(state); + + return 0; +} + +int +paste_from_paste(struct DrawState* state) +{ + /* Selection start row/col */ + size_t ssr = 0; + size_t ssc = 0; + /* Selection end row/col */ + size_t ser = 0; + size_t sec = 0; + uint32_t* newtext = NULL; + struct BufferLine* line = 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 state; - } - - 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 NULL; - for (size_t i = 0; i < lines_to_init; i++) + if (!state->paste_count) + return 0; + + if (SEL_NOT_EMPTY(state)) + { + position_to_selection_start(state); + erase_selection(state); + clear_selection(state); + } + + if (state->paste_count > 1) { - pinput = newbuf + state->paste_rows_count - 1 - i; - init_bufferline(pinput); - uint32_t* newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); - if (!newtext) - return NULL; - pinput->text = newtext; + if (state->rows_count + state->paste_count > state->buffer_size) + { + size_t old_size = state->buffer_size; + while (state->rows_count + state->paste_count + > state->buffer_size) + state->buffer_size += ALLOC_DELTA; + newbuf = realloc(state->buffer, + state->buffer_size * sizeof(struct BufferLine)); + for (size_t row = 0; + row < state->buffer_size - old_size; row++) + { + init_bufferline(newbuf + row); + newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + newbuf[row].text = newtext; + } + state->buffer = newbuf; + } + /* TODO: */ + for (size_t row = 0; row < state->rows_count - state->row; row++) + { + line = state->buffer + state->row + state->paste_count + + row; + line->length = u32_strcpy(line->text, + state->buffer[state->row + row].text); + } } - if (ppaste) - for (size_t i = 0; i < state->paste_rows_count; i++) + line = state->buffer + state->row; + newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + u32_strncpy(newtext, line->text, state->column + 1); + u32_strcat(newtext, state->paste[0].text); + + if (state->paste_count == 1) + { + u32_strcat(newtext, line->text + state->column); + line->length = u32_strcpy(line->text, newtext); + } + else + { + line->length = u32_strcpy(line->text, newtext); + for (size_t row = 1; row < state->paste_count - 1; row++) { - pinput = newbuf + i; - u32_strncpy(pinput->text, ppaste->text, - MIN(ppaste->length + 1, MAXBUFLINE)); - pinput->length = ppaste->length; - ppaste++; + line = state->buffer + state->row + row; + line->length = u32_strcpy(line->text, + state->paste[row].text); } - state->input_rows_count = state->paste_rows_count; - state->input_buffer = newbuf; - state->dirty = 1; -*/ - return state; + line = state->buffer + state->row + state->paste_count - 1; + u32_strcpy(newtext, state->paste[state->paste_count - 1].text); + u32_strcat(newtext, line->text); + line->length = u32_strcpy(line->text, newtext); + } + free(newtext); + /*for (size_t row = state->paste_size - ALLOC_DELTA; + row < state->paste_size; row++) + { + uint32_t* newtext = NULL; + init_bufferline(newbuf + row); + newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); + if (!newtext) + strcpy(state->error, errors[ERR_CANT_ALLOC]); + newbuf[row].text = newtext; + newbuf[row].length = 0; + } + state->paste = newbuf; + if (state->paste_count == 0) + state->paste[0].length = u32_strncpy(state->paste[0].text, + state->buffer[ssr].text + ssc, sec - ssc + 1); + else + { + state->paste[0].length = u32_strcpy(state->paste[0].text, + state->buffer[ssr].text + ssc); + for (size_t row = 1; row < state->paste_count - 1; row++) + state->paste[row].length + = u32_strcpy(state->paste[row].text, + state->buffer[ssr + row].text); + state->paste[state->paste_count - 1].length + = u32_strncpy(state->paste[state->paste_count - 1].text, + state->buffer[ser].text, sec + 1); + }*/ + + return 0; } int