sled

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

чување 5e5e68678295fe862cc4f84f3f5149a5f9661337
родитељ 9996d67f2c653258ee68ce75c51d07865e7f8343
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sun, 20 Feb 2022 20:38:36 +0100

Fix: initialize all newly-allocated lines when reallocating; create backup files; draw status message with long operations

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

Diffstat:
MTODO | 14+-------------
Mconfig.def.h | 2++
Mconfig.h | 2++
Mdraw.c | 31++++++++++++++++++++++++++-----
Mdraw.h | 6++++--
Msled.c | 44+++++++++++++++++++++++++++++++-------------
Mutil.h | 5+++++
измењених датотека: 7, додавања: 71(+), брисања: 33(-)

diff --git a/TODO b/TODO @@ -1,8 +1,6 @@ TODO ==== - [~] Write operation; create backup files - [ ] Copy/paste? [ ] Allow creating files (error out if directory not writeable, only @@ -16,17 +14,7 @@ [ ] Test for binary when opening? - [x] Go to line # - - [x] Convert to termbox2? - - [x] Create a working base by migration from poe - [x] Implement "inverse vi mode" - [x] Selections! - [x] Initial support for selections - (DrawState.in_selection) - [x] Selections modify behavior of eg. Delete key - and inserting characters + [x] Write operation; create backup files < > Search? diff --git a/config.def.h b/config.def.h @@ -4,6 +4,8 @@ #define DLG_BG TB_WHITE #define ERROR_FG TB_WHITE | TB_BOLD #define ERROR_BG TB_RED +#define ACTION_FG TB_BLACK +#define ACTION_BG TB_WHITE #define INPUT_FG TB_BLACK #define INPUT_BG TB_WHITE #define INPUT_EDIT_FG TB_WHITE diff --git a/config.h b/config.h @@ -4,6 +4,8 @@ #define DLG_BG TB_WHITE #define ERROR_FG TB_WHITE | TB_BOLD #define ERROR_BG TB_RED +#define ACTION_FG TB_BLACK +#define ACTION_BG TB_WHITE #define INPUT_FG TB_BLACK #define INPUT_BG TB_WHITE #define INPUT_EDIT_FG TB_WHITE diff --git a/draw.c b/draw.c @@ -43,7 +43,7 @@ const char* mode_labels[] = { [PROMPT_MODE] = "PROMPT", [SELECTION_MODE] = "SELECTION" }; -const char* errors[] = { +const char* errors[] = { [ERR_UNKNOWN_KEY] = "Unknown key (press F1 for help)", [ERR_EXIT_KEY] = "Press C-Q to quit", [ERR_DLG_OPEN] = "Press Esc to close dialog or C-Q to quit", @@ -54,6 +54,10 @@ const char* errors[] = { [ERR_CANT_MOVE] = "Cannot move temporary file", [ERR_INPUT_NONNUM] = "Input must be numerical", [ERR_INVALID_NUM] = "Invalid input"}; +const char* actions[] = { + [ACT_WRITING] = "Writing...", + [ACT_READING] = "Reading..." +}; const char* go_to_dialog_title = "Go to line"; const char* search_dialog_title = "Search text"; const char* program_name = "sled"; @@ -86,10 +90,11 @@ free_bufferline(struct BufferLine* bl) } void -init_drawstate(struct DrawState* state, char* error, char* filename, - char* prompt) +init_drawstate(struct DrawState* state, char* error, char* action, + char* filename, char* prompt) { state->error = error; + state->action = action; state->filename = filename; state->input = NULL; state->buffer = NULL; @@ -652,7 +657,7 @@ draw_status(const struct DrawState* state) int current_start = 0; const struct StatusSegment* pseg = status_segments; - if (state->in_prompt && state->prompt[0]) + if (state->in_prompt && *state->prompt) { if (!draw_string(0, state->maxy - 1, PROMPT_FG, PROMPT_BG, state->prompt, strlen(state->prompt) + 2, @@ -660,7 +665,15 @@ draw_status(const struct DrawState* state) 0, 0)) return NULL; } - else if (state->error && state->error[0]) + else if (state->action && *state->action) + { + if (!draw_string(0, state->maxy - 1, ACTION_FG, ACTION_BG, + state->action, strlen(state->action) + 2, + state->maxx, 1, 1, CENTER, 0, 1, NULL, 0, 0, 0, 0, + 0, 0)) + return NULL; + } + else if (state->error && *state->error) { if (!draw_string(0, state->maxy - 1, ERROR_FG, ERROR_BG, state->error, strlen(state->error) + 2, state->maxx, @@ -696,6 +709,14 @@ draw_status(const struct DrawState* state) } const struct DrawState* +redraw_status(const struct DrawState* state) +{ + const struct DrawState* result = draw_status(state); + tb_present(); + return result; +} + +const struct DrawState* draw(const struct DrawState* state) { if (!state) diff --git a/draw.h b/draw.h @@ -33,6 +33,7 @@ struct BufferLine { struct DrawState { char* error; char* prompt; + char* action; char* filename; uint32_t* input; struct BufferLine* buffer; @@ -85,8 +86,8 @@ struct StatusSegment { void init_bufferline(struct BufferLine* bl); void free_bufferline(struct BufferLine* bl); -void init_drawstate(struct DrawState* state, char* error, char* filename, - char* prompt); +void init_drawstate(struct DrawState* state, char* error, char* action, + char* filename, char* prompt); void free_drawstate(struct DrawState* state); size_t display_length(const struct DrawState* state, uint32_t* buffer, const size_t max_index); @@ -115,4 +116,5 @@ void u32_draw_string(const int x, const int y, const uint16_t fg, const struct DrawState* draw_help(const struct DrawState* state); const struct DrawState* draw_screen(const struct DrawState* state); const struct DrawState* draw_status(const struct DrawState* state); +const struct DrawState* redraw_status(const struct DrawState* state); const struct DrawState* draw(const struct DrawState* state); diff --git a/sled.c b/sled.c @@ -38,6 +38,7 @@ enum { }; extern const char* errors[]; +extern const char* actions[]; extern const char* mode_labels[]; extern const char* go_to_dialog_title; extern const char* search_dialog_title; @@ -154,7 +155,8 @@ reread_file(struct DrawState* state) for (row = 0; row < state->paste_rows_count; row++) free_bufferline(state->paste_buffer + row); free(state->paste_buffer); - init_drawstate(state, state->error, state->filename, state->prompt); + init_drawstate(state, state->error, state->action, state->filename, + state->prompt); result = load_file(state, &lineno, &col); switch (result) @@ -246,6 +248,9 @@ load_file(struct DrawState* state, long* lineno, long* col) if (!newchunk) return LOAD_ERR_CANT_ALLOC; + strcpy(state->action, actions[ACT_READING]); + redraw_status(state); + state->buffer = newchunk; line = state->buffer; state->buffer_size = ALLOC_DELTA; @@ -269,17 +274,17 @@ load_file(struct DrawState* state, long* lineno, long* col) if (line == state->buffer + state->buffer_size) { state->buffer_size += ALLOC_DELTA; - /* TODO: Allocated here */ newchunk = realloc(state->buffer, state->buffer_size * sizeof(struct BufferLine)); if (!newchunk) return LOAD_ERR_CANT_ALLOC; state->buffer = newchunk; - init_bufferline(state->buffer + state->buffer_size - - ALLOC_DELTA); + for (size_t row = state->buffer_size - ALLOC_DELTA; + row < state->buffer_size; row++) + init_bufferline(state->buffer + row); line = state->buffer + state->buffer_size - ALLOC_DELTA; } - if (!line->text) /* TODO: Uninitialized value? */ + if (!line->text) { newtext = calloc(MAXBUFLINE, sizeof(uint32_t)); if (!newtext) @@ -290,6 +295,7 @@ load_file(struct DrawState* state, long* lineno, long* col) state->rows_count++; } fclose(input); + *state->action = 0; return LOAD_ERR_NONE; } @@ -297,13 +303,22 @@ load_file(struct DrawState* state, long* lineno, long* col) int save_file(struct DrawState* state) { - FILE* output = NULL; - char* buf = NULL; + FILE* output = NULL; + char* buf = NULL; + char* backup_filename = NULL; if (!(buf = calloc(MAXBUFLINE, 1))) return SAVE_ERR_CANT_ALLOC; + if (!(backup_filename = calloc(MAXPATH, 1))) + return SAVE_ERR_CANT_ALLOC; + + strcpy(state->action, actions[ACT_WRITING]); + redraw_status(state); + + strcpy(backup_filename, state->filename); + strcat(backup_filename, "~"); + rename(state->filename, backup_filename); - /* TODO: Create backup! */ if (!(output = fopen(state->filename, "wt"))) return SAVE_ERR_CANT_OPEN_FILE; @@ -314,7 +329,9 @@ save_file(struct DrawState* state) } fclose(output); + free(backup_filename); free(buf); + *state->action = 0; return SAVE_ERR_NONE; } @@ -1463,7 +1480,6 @@ erase_selection(struct DrawState* state) state->buffer[ssr + row + 1].length = state->buffer[ser + row + 1].length; } - /* TODO: Check! */ for (size_t row = state->rows_count - (ser - ssr); row < state->rows_count; row++) { @@ -1596,14 +1612,16 @@ main(int argc, char** argv) { struct tb_event ev; char error[MAXBUFLINE]; + char action[MAXBUFLINE]; char prompt[MAXBUFLINE]; struct DrawState state; char filename[MAXPATH]; struct stat st; - error[0] = 0; - prompt[0] = 0; - filename[0] = 0; + *error = 0; + *action = 0; + *prompt = 0; + *filename = 0; if (argc == 1) return print_error(1, "No filename given"); @@ -1630,7 +1648,7 @@ main(int argc, char** argv) if (!S_ISREG(st.st_mode)) return print_error(EINVAL, "Is not a regular file"); - init_drawstate(&state, error, filename, prompt); + init_drawstate(&state, error, action, filename, prompt); long lineno = 1; long col = 1; diff --git a/util.h b/util.h @@ -28,6 +28,11 @@ enum { ERR_INVALID_NUM }; +enum { + ACT_WRITING, + ACT_READING +}; + #define ALLOC_DELTA 50 #define MAXBUFLINE 4096 #define MAXDATEBUF 80