sled

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

чување 7838a238c0c2881c9255d54f60d4b9743393407e
родитељ 09af6e83d20285dfb10b80561efada734e9de5f3
Аутор: Страхиња Радић <contact@strahinja.org>
Датум:   Sat, 22 Jun 2024 20:46:10 +0200

New function: wrap_para (C-J); use ssize_t instead of size_t

Diffstat:
Mconfig.def.h | 2++
Mdraw.c | 47++++++++++++++++++++++++++---------------------
Mdraw.h | 31++++++++++++++++---------------
Msled.c | 440+++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------------------
Msled.h | 4+++-
Mutil.c | 15+++++++++++++++
Mutil.h | 10++++++----
измењених датотека: 7, додавања: 387(+), брисања: 162(-)

diff --git a/config.def.h b/config.def.h @@ -88,6 +88,8 @@ static const struct Key global_keys[] = { .callback = move_end }, { .ev = { .key = TB_KEY_CTRL_F, .mod = TB_MOD_CTRL }, .callback = move_page_down }, + { .ev = { .key = TB_KEY_CTRL_J, .mod = TB_MOD_CTRL }, + .callback = wrap_para }, { .ev = { .key = TB_KEY_CTRL_K, .mod = TB_MOD_CTRL }, .callback = erase_to_end }, { .ev = { .key = TB_KEY_CTRL_L, .mod = TB_MOD_CTRL }, diff --git a/draw.c b/draw.c @@ -68,10 +68,12 @@ const char* errors[] = { [ERR_CANT_OPEN] = "Cannot read file", [ERR_CANT_COPY] = "Cannot create the backup file", [ERR_INPUT_NONNUM] = "Input must be numerical", - [ERR_INVALID_NUM] = "Invalid input"}; + [ERR_INVALID_NUM] = "Invalid input", + [ERR_NOT_IMP] = "Function not implemented/configured"}; const char* actions[] = { [ACT_WRITING] = "Writing...", - [ACT_READING] = "Reading..." + [ACT_READING] = "Reading...", + [ACT_WRAPPING] = "Wrapping..." }; const char* go_to_dialog_title = "Go to line"; const char* replace_dialog_title = "Replace with"; @@ -94,12 +96,15 @@ assign_coord(struct Coord* dest, const struct Coord src) /* Calculates buffer length from a display length. * max_index = the display index up to which the length is calculated */ -size_t -buffer_length(uint32_t* buffer, const size_t max_index) +ssize_t +buffer_length(uint32_t* buffer, const ssize_t max_index) { - size_t len = 0; + ssize_t len = 0; uint32_t* pbuf = buffer; - size_t i = 0; + ssize_t i = 0; + + if (!pbuf) + return 0; for (i = 0; *pbuf && len < max_index; i++) { @@ -129,16 +134,16 @@ calculate_input_dialog_width(const struct DrawState* state) /* Calculates display length of a buffer line. * max_index = the buffer index up to which the length is calculated */ -size_t -display_length(uint32_t* buffer, const size_t max_index) +ssize_t +display_length(uint32_t* buffer, const ssize_t max_index) { - size_t len = 0; + ssize_t len = 0; uint32_t* pbuf = buffer; if (!buffer) return len; - for (size_t i = 0; *pbuf && i < max_index; i++) + for (ssize_t i = 0; *pbuf && i < max_index; i++) { pbuf = buffer + i; if (*pbuf == '\t') @@ -322,7 +327,7 @@ draw_screen(const struct DrawState* state) max_screen_lines = state->maxy - 1; i = state->first_shown.row; - while (((size_t)i < state->rows_count) && (cy < max_screen_lines)) + while (((ssize_t)i < state->rows_count) && (cy < max_screen_lines)) { current = state->buffer + i; @@ -368,7 +373,7 @@ int draw_status(const struct DrawState* state) { char* buf = NULL; - size_t seg_size; + ssize_t seg_size; int current_start = 0; const struct StatusSegment* pseg; @@ -422,7 +427,7 @@ draw_status(const struct DrawState* state) seg_size = state->maxx - 1 - current_start; if (draw_string(current_start, state->maxy - 1, pseg->fg, pseg->bg, buf, - MIN(seg_size, strlen(buf) + 2), + MIN(seg_size, (ssize_t)(strlen(buf) + 2)), last ? seg_size + 1 : seg_size, 1, 1, pseg->alignment, 0, 1, NULL, 0, 0, 0, 0, 0, 0)) @@ -472,8 +477,8 @@ draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg, } void -format_filename(char* result, size_t result_size, const char* format, - const size_t seg_size, const struct DrawState* state) +format_filename(char* result, ssize_t result_size, const char* format, + const ssize_t seg_size, const struct DrawState* state) { char* basename = NULL; if (!result || seg_size < 4) @@ -481,7 +486,7 @@ format_filename(char* result, size_t result_size, const char* format, basename = strdup(u8_basename(state->filename)); - if (u8_strlen(basename) + 2 >= seg_size) + if ((ssize_t)(u8_strlen(basename) + 2) >= seg_size) { if (state->dirty) basename[seg_size - 4] = 0; @@ -497,8 +502,8 @@ format_filename(char* result, size_t result_size, const char* format, } void -format_mode(char* result, size_t result_size, const char* format, - const size_t seg_size, const struct DrawState* state) +format_mode(char* result, ssize_t result_size, const char* format, + const ssize_t seg_size, const struct DrawState* state) { const char* mode_label = mode_labels[UNKNOWN_MODE]; UNUSED(seg_size); @@ -526,8 +531,8 @@ format_print: } void -format_position(char* result, size_t result_size, const char* format, - const size_t seg_size, const struct DrawState* state) +format_position(char* result, ssize_t result_size, const char* format, + const ssize_t seg_size, const struct DrawState* state) { UNUSED(seg_size); if (!result) @@ -555,7 +560,7 @@ free_bufferline(struct BufferLine* bl, const int free_text) void free_drawstate(struct DrawState* state, int skip_paste_free) { - size_t row = 0; + ssize_t row = 0; for (row = 0; row < state->buffer_size; row++) free_bufferline(state->buffer + row, 1); free(state->backup_filename); diff --git a/draw.h b/draw.h @@ -2,6 +2,7 @@ * any later version. Copyright (C) 2022-2024 Страхиња Радић. * See the file LICENSE for exact copyright and license details. */ #include <stddef.h> +#include <sys/types.h> #include <termios.h> #include <unistd.h> #include <wchar.h> @@ -42,8 +43,8 @@ struct Coord { struct BufferLine { uint32_t* text; - size_t length; /* both in uint32_t units */ - size_t size; + ssize_t length; /* both in uint32_t units */ + ssize_t size; uint16_t fg; uint16_t bg; }; @@ -60,21 +61,21 @@ struct DrawState { uint32_t* search; int chain_dialog; /* show input dialogs in sequence? */ struct BufferLine* buffer; - size_t buffer_size; /* buffer parameter */ + ssize_t buffer_size; /* buffer parameter */ struct Coord coord; /* buffer coordinates */ struct Coord first_shown; /* display coordinates */ int input_first_shown_column; /* display coordinate */ int input_display_column; /* display coordinate */ int input_column; /* buffer coordinates */ char* input_title; - size_t rows_count; /* buffer parameter */ + ssize_t rows_count; /* buffer parameter */ int display_column; /* display coordinate */ int saved_column; /* display coordinate */ int help_width; /* display parameter */ int input_dialog_width; /* display parameter */ struct BufferLine* paste; - size_t paste_count; - size_t paste_size; + ssize_t paste_count; + ssize_t paste_size; int (*prompt_callback)(struct DrawState*, struct tb_event*); int (*input_callback)(struct DrawState*); int (*input_update_callback)(struct DrawState*); @@ -97,7 +98,7 @@ struct Key { struct StatusSegment { const char* format; - void (*callback)(char*, size_t, const char*, const size_t, + void (*callback)(char*, ssize_t, const char*, const ssize_t, const struct DrawState*); uint16_t fg; uint16_t bg; @@ -105,10 +106,10 @@ struct StatusSegment { }; void assign_coord(struct Coord* dest, const struct Coord src); -size_t buffer_length(uint32_t* buffer, const size_t max_index); +ssize_t buffer_length(uint32_t* buffer, const ssize_t max_index); int calculate_help_width(const struct DrawState* state); int calculate_input_dialog_width(const struct DrawState* state); -size_t display_length(uint32_t* buffer, const size_t max_index); +ssize_t display_length(uint32_t* buffer, const ssize_t max_index); int draw(const struct DrawState* state); void draw_box(const int startx, const int endx, const int starty, const int endy, const uint16_t fg, const uint16_t bg); @@ -124,12 +125,12 @@ int draw_string(const int x, const int y, const uint16_t fg, const uint16_t bg, const int ds, const int fill, const uint32_t* srch, const uint16_t sfg, const uint16_t sbg, const int ssi, const int sei, const uint16_t slfg, const uint16_t slbg); -void format_filename(char* result, size_t result_size, const char* format, - const size_t seg_size, const struct DrawState* state); -void format_mode(char* result, size_t result_size, const char* format, - const size_t seg_size, const struct DrawState* state); -void format_position(char* result, size_t result_size, const char* format, - const size_t seg_size, const struct DrawState* state); +void format_filename(char* result, ssize_t result_size, const char* format, + const ssize_t seg_size, const struct DrawState* state); +void format_mode(char* result, ssize_t result_size, const char* format, + const ssize_t seg_size, const struct DrawState* state); +void format_position(char* result, ssize_t result_size, const char* format, + const ssize_t seg_size, const struct DrawState* state); void free_bufferline(struct BufferLine* bl, const int free_text); void free_drawstate(struct DrawState* state, int skip_paste_free); void init_bufferline(struct BufferLine* bl); diff --git a/sled.c b/sled.c @@ -179,7 +179,7 @@ create_file(struct DrawState* state) state->running = 0; return LOAD_ERR_CANT_ALLOC; } - for (size_t row = 0; row < ALLOC_DELTA; row++) + for (ssize_t row = 0; row < ALLOC_DELTA; row++) { init_bufferline(newchunk + row); newtext = calloc(LINE_DEFAULT, sizeof(uint32_t)); @@ -211,7 +211,7 @@ cut_to_paste(struct DrawState* state) } static char* -dirname(char* dir, char* path, const size_t dir_size) +dirname(char* dir, char* path, const ssize_t dir_size) { char* p = NULL; @@ -247,17 +247,17 @@ do_search_replace(struct DrawState* state) uint32_t* buf = NULL; uint32_t* temp = NULL; /* minimum size is LINE_DEFAULT to avoid 0-allocation */ - size_t bufsize = LINE_DEFAULT; /* size in uint32_t units */ - size_t buflen = 0; - size_t old_buflen = 0; - size_t search_len = u32_strlen(state->search); - size_t input_len = u32_strlen(state->input); - size_t after_len = 0; - int start_row = 0; - int end_row = state->rows_count; - uint32_t* before = NULL; - uint32_t* found = NULL; - uint32_t* after = NULL; + ssize_t bufsize = LINE_DEFAULT; /* size in uint32_t units */ + ssize_t buflen = 0; + ssize_t old_buflen = 0; + ssize_t search_len = u32_strlen(state->search); + ssize_t input_len = u32_strlen(state->input); + ssize_t after_len = 0; + int start_row = 0; + int end_row = state->rows_count; + uint32_t* before = NULL; + uint32_t* found = NULL; + uint32_t* after = NULL; if (SEL_NOT_EMPTY(state)) get_selection(&start_row, NULL, &end_row, NULL, state); @@ -359,7 +359,7 @@ erase_backwards(struct DrawState* state) if (state->coord.col > 0) { - size_t i = state->coord.col; + ssize_t i = state->coord.col; do { buffer_line->text[i - 1] = buffer_line->text[i]; @@ -394,7 +394,7 @@ erase_forward(struct DrawState* state) if (buffer_line->text[state->coord.col]) { - size_t i = state->coord.col; + ssize_t i = state->coord.col; while (i + 2 < buffer_line->size && buffer_line->text[i + 1]) { buffer_line->text[i] = buffer_line->text[i + 1]; @@ -404,7 +404,7 @@ erase_forward(struct DrawState* state) buffer_line->length--; state->dirty = 1; } - else if ((size_t)(state->coord.row + 1) < state->rows_count) + else if ((state->coord.row + 1) < state->rows_count) simple_join_lines(state); return 0; } @@ -420,7 +420,7 @@ erase_line(struct DrawState* state) return 0; } free(state->buffer[state->coord.row].text); - for (size_t row = state->coord.row; row < state->rows_count - 1; row++) + for (ssize_t row = state->coord.row; row < state->rows_count - 1; row++) { current = state->buffer + row; current->text = state->buffer[row + 1].text; @@ -428,7 +428,7 @@ erase_line(struct DrawState* state) current->length = state->buffer[row + 1].length; } free_bufferline(&state->buffer[state->rows_count - 1], 0); - if ((size_t)(state->coord.row + 1) == state->rows_count) + if ((state->coord.row + 1) == state->rows_count) state->coord.row--; position_to(state, state->coord.row, 0); state->rows_count--; @@ -455,7 +455,7 @@ erase_prev_word(struct DrawState* state) d = state->coord.col - i; - for (size_t j = i; j + d < current->length; j++) + for (ssize_t j = i; j + d < current->length; j++) current->text[j] = current->text[j + d]; current->length -= d; @@ -475,11 +475,11 @@ erase_selection(struct DrawState* state) int ssr = 0; int ssc = 0; /* Selection end row/col */ - int ser = 0; - int sec = 0; - uint32_t* buf = NULL; - size_t bufsize = state->buffer[ser].size; - uint32_t* temp = NULL; + int ser = 0; + int sec = 0; + uint32_t* buf = NULL; + ssize_t bufsize = state->buffer[ser].size; + uint32_t* temp = NULL; buf = calloc(bufsize, sizeof(uint32_t)); if (!buf) @@ -496,7 +496,7 @@ erase_selection(struct DrawState* state) if (ssr != ser) { - for (size_t row = 0; ser + row + 1 < state->rows_count; + for (ssize_t row = 0; ser + row + 1 < state->rows_count; row++) { U32_MEMCCPY(state->buffer[ssr + row + 1].text, @@ -505,7 +505,7 @@ erase_selection(struct DrawState* state) state->buffer[ssr + row + 1].length = state->buffer[ser + row + 1].length; } - for (size_t row = state->rows_count - (ser - ssr); + for (ssize_t row = state->rows_count - (ser - ssr); row < state->rows_count; row++) { *state->buffer[row].text = 0; @@ -542,9 +542,9 @@ erase_to_end(struct DrawState* state) static int erase_to_start(struct DrawState* state) { - size_t i = state->coord.col; + ssize_t i = state->coord.col; struct BufferLine* buffer_line = &state->buffer[state->coord.row]; - size_t len = buffer_line->length; + ssize_t len = buffer_line->length; if (SEL_NOT_EMPTY(state)) { @@ -636,8 +636,8 @@ get_selection(int* ssr, int* ssc, int* ser, int* sec, static int go_to_line_callback(struct DrawState* state) { - size_t lineno = 0; - size_t len = 0; + ssize_t lineno = 0; + ssize_t len = 0; char* u8_input = NULL; char* temp = NULL; @@ -846,7 +846,7 @@ input_erase_backwards(struct DrawState* state) { if (state->input_column > 0) { - size_t i = state->input_column; + ssize_t i = state->input_column; do { state->input[i - 1] = state->input[i]; @@ -865,7 +865,7 @@ input_erase_forward(struct DrawState* state) { if (state->input) { - size_t i = state->input_column; + ssize_t i = state->input_column; while (i + 2 < MAXINPUT && state->input[i + 1]) { state->input[i] = state->input[i + 1]; @@ -893,8 +893,8 @@ input_erase_to_end(struct DrawState* state) static int input_erase_to_start(struct DrawState* state) { - size_t i = state->input_column; - size_t len = u32_strlen(state->input); + ssize_t i = state->input_column; + ssize_t len = u32_strlen(state->input); do { @@ -911,12 +911,12 @@ input_erase_to_start(struct DrawState* state) static int input_insert_char(struct DrawState* state, uint32_t ch) { - size_t len = u32_strlen(state->input); + ssize_t len = u32_strlen(state->input); if (state->input_column + 1 < MAXINPUT) { - size_t i = len + 1; + ssize_t i = len + 1; int add_null = state->input[state->input_column] == 0; - while (i + 2 < MAXINPUT && i > (size_t)state->input_column) + while (i + 2 < MAXINPUT && i > state->input_column) { state->input[i] = state->input[i - 1]; i--; @@ -964,11 +964,11 @@ input_move_next_word(struct DrawState* state) { int i = state->input_column; uint32_t* pline = state->input; - size_t len = u32_strlen(state->input); + ssize_t len = u32_strlen(state->input); - while ((size_t)i < len && !u32_is_word_boundary(pline[i], 0)) + while (i < len && !u32_is_word_boundary(pline[i], 0)) i++; - while ((size_t)i < len && u32_is_word_boundary(pline[i], 0)) + while (i < len && u32_is_word_boundary(pline[i], 0)) i++; input_position_to(state, i); return 0; @@ -1008,10 +1008,10 @@ input_move_start(struct DrawState* state) static void input_position_to(struct DrawState* state, const int column) { - size_t len = u32_strlen(state->input); + ssize_t len = u32_strlen(state->input); state->input_column = column; - if ((size_t)state->input_column > len) + if (state->input_column > len) state->input_column = len; state->input_display_column = display_length(state->input, state->input_column); @@ -1027,10 +1027,9 @@ static int insert_char(struct DrawState* state, uint32_t ch) { struct BufferLine* buffer_line = NULL; - size_t i; - int add_null; - size_t len; - size_t size; + ssize_t i; + ssize_t len; + ssize_t size; uint32_t* ptext = NULL; ENSURE_SIZE(state->buffer[state->coord.row].text, ptext, @@ -1047,23 +1046,21 @@ insert_char(struct DrawState* state, uint32_t ch) } buffer_line = &state->buffer[state->coord.row]; - add_null = buffer_line->text[state->coord.col] == 0; len = buffer_line->length; size = buffer_line->size; - i = len + 1; + i = len; if (!IN(state->mode, M_OVERWRITE)) - while (i + 1 < size && i > (size_t)state->coord.col) + while (i + 1 < size && i > state->coord.col) { buffer_line->text[i] = buffer_line->text[i - 1]; i--; } buffer_line->text[state->coord.col] = ch; - if ((size_t)state->coord.col == len || !IN(state->mode, M_OVERWRITE)) + if (state->coord.col == len || !IN(state->mode, M_OVERWRITE)) buffer_line->length++; position_to(state, state->coord.row, state->coord.col + 1); - if (add_null) - buffer_line->text[state->coord.col] = 0; + buffer_line->text[buffer_line->length] = 0; #ifdef ENABLE_WRAP while (state->display_column >= WRAP_WIDTH) @@ -1178,7 +1175,7 @@ join_lines(struct DrawState* state) ser = state->coord.row; } - if ((size_t)(ssr + 1) == state->rows_count) + if ((ssr + 1) == state->rows_count) return 0; for (int row = ssr; row <= ser; row++) @@ -1224,8 +1221,8 @@ load_file(struct DrawState* state) struct BufferLine* line = NULL; FILE* input = NULL; char* input_line = NULL; - size_t input_size = limits[L_LINE_MAX]; - size_t input_len = 0; + ssize_t input_size = limits[L_LINE_MAX]; + ssize_t input_len = 0; uint32_t* newtext = NULL; uint32_t* ptext = NULL; char* temp = NULL; @@ -1242,7 +1239,7 @@ load_file(struct DrawState* state) state->running = 0; goto load_file_alloc_error; } - for (size_t row = 0; row < ALLOC_DELTA; row++) + for (ssize_t row = 0; row < ALLOC_DELTA; row++) { init_bufferline(newchunk + row); newtext = calloc(LINE_DEFAULT, sizeof(uint32_t)); @@ -1287,7 +1284,7 @@ load_file(struct DrawState* state) goto load_file_alloc_error; } state->buffer = newchunk; - for (size_t row = state->buffer_size - ALLOC_DELTA; + for (ssize_t row = state->buffer_size - ALLOC_DELTA; row < state->buffer_size; row++) { init_bufferline(state->buffer + row); @@ -1360,11 +1357,11 @@ move_next_word(struct DrawState* state) { int i = state->coord.col; uint32_t* pline = state->buffer[state->coord.row].text; - size_t len = state->buffer[state->coord.row].length; + ssize_t len = state->buffer[state->coord.row].length; - while ((size_t)i < len && !u32_is_word_boundary(pline[i], 0)) + while (i < len && !u32_is_word_boundary(pline[i], 0)) i++; - while ((size_t)i < len && u32_is_word_boundary(pline[i], 0)) + while (i < len && u32_is_word_boundary(pline[i], 0)) i++; position_to(state, state->coord.row, i); return 0; @@ -1373,7 +1370,7 @@ move_next_word(struct DrawState* state) static int move_page_down(struct DrawState* state) { - if ((size_t)(state->coord.row + state->maxy) < state->rows_count + 2) + if ((state->coord.row + state->maxy) < state->rows_count + 2) position_to(state, state->coord.row + state->maxy - 2, state->coord.col); else @@ -1419,11 +1416,11 @@ move_right(struct DrawState* state) static int move_screen_bottom(struct DrawState* state) { - if (state->rows_count + 2 < (size_t)state->maxy) + if (state->rows_count + 2 < state->maxy) position_to(state, state->rows_count - 1, state->coord.col); else { - if ((size_t)(state->first_shown.row + state->maxy) + if ((state->first_shown.row + state->maxy) < state->rows_count + 2) position_to(state, state->first_shown.row + state->maxy - 2, @@ -1435,12 +1432,12 @@ move_screen_bottom(struct DrawState* state) static int move_screen_middle(struct DrawState* state) { - if (state->rows_count + 2 < (size_t)state->maxy) + if (state->rows_count + 2 < state->maxy) position_to(state, state->rows_count / 2, state->coord.col); else { int row = state->first_shown.row + (state->maxy - 2) / 2; - if (state->rows_count < (size_t)(row + (state->maxy - 2) / 2)) + if (state->rows_count < (row + (state->maxy - 2) / 2)) row = state->rows_count - (state->maxy - 2) / 2; position_to(state, row, state->coord.col); } @@ -1481,17 +1478,17 @@ next_match(struct DrawState* state) { struct BufferLine* current = NULL; const uint32_t* found = NULL; - size_t idelta; + ssize_t idelta; if (!state->search || !*state->search) return 0; *state->error = 0; - for (size_t row = state->coord.row; row < state->rows_count; row++) + for (ssize_t row = state->coord.row; row < state->rows_count; row++) { current = state->buffer + row; found = current->text; - if (row == (size_t)state->coord.row) + if (row == state->coord.row) found += state->coord.col + 1; found = u32_strstr(found, state->search); if (found) @@ -1514,11 +1511,11 @@ paste_from_paste(struct DrawState* state) { uint32_t* newtext = NULL; uint32_t* ptext = NULL; - size_t newsize = 0; + ssize_t newsize = 0; struct BufferLine* line = NULL; struct BufferLine* newbuf = NULL; uint32_t* rest = NULL; - size_t rest_size = 0; + ssize_t rest_size = 0; struct Coord newpos; char* temp = NULL; @@ -1536,13 +1533,13 @@ paste_from_paste(struct DrawState* state) { if (state->rows_count + state->paste_count > state->buffer_size) { - size_t old_size = state->buffer_size; + ssize_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 = old_size; row < state->buffer_size; + for (ssize_t row = old_size; row < state->buffer_size; row++) { init_bufferline(newbuf + row); @@ -1599,7 +1596,7 @@ paste_from_paste(struct DrawState* state) U32_SAFE_COPY(line->text, ptext, line->size, newtext, newsize, paste_from_paste_cleanup); line->length = u32_strlen(line->text); - for (size_t row = state->rows_count - state->coord.row + for (ssize_t row = state->rows_count - state->coord.row - (state->paste_count - 2) - 1; row > 0; row--) { @@ -1617,7 +1614,7 @@ paste_from_paste(struct DrawState* state) U32_SAFE_COPY(line->text, ptext, line->size, newtext, newsize, paste_from_paste_cleanup); line->length = u32_strlen(line->text); - for (size_t row = 1; row < state->paste_count - 1; row++) + for (ssize_t row = 1; row < state->paste_count - 1; row++) { line = state->buffer + state->coord.row + row; U32_SAFE_COPY(line->text, ptext, line->size, @@ -1662,12 +1659,12 @@ paste_from_paste_cleanup: static void position_to(struct DrawState* state, const int row, const int column) { - size_t dlen; + ssize_t dlen; if (row != state->coord.row) { state->coord.row = row; - if ((size_t)(state->coord.row + 1) > state->rows_count) + if ((state->coord.row + 1) > state->rows_count) state->coord.row = state->rows_count - 1; if (state->first_shown.row > state->coord.row) state->first_shown.row = state->coord.row; @@ -1693,7 +1690,7 @@ position_to(struct DrawState* state, const int row, const int column) = state->buffer[state->coord.row].length; dlen = display_length(state->buffer[state->coord.row].text, state->coord.col); - if (dlen < (size_t)state->saved_column) + if (dlen < state->saved_column) state->display_column = dlen; else state->display_column = state->saved_column; @@ -1712,10 +1709,10 @@ position_to(struct DrawState* state, const int row, const int column) else state->coord.col = 0; } - else if ((size_t)state->coord.col + else if (state->coord.col > state->buffer[state->coord.row].length) { - if ((size_t)(state->coord.row + 1) < state->rows_count) + if ((state->coord.row + 1) < state->rows_count) { state->coord.row++; state->coord.col = 0; @@ -1740,6 +1737,24 @@ position_to(struct DrawState* state, const int row, const int column) } static int +position_to_selection_end(struct DrawState* state) +{ + if (SEL_NOT_EMPTY(state)) + { + int ser = 0; + int sec = 0; + + get_selection(NULL, NULL, &ser, &sec, state); + + state->saved_column + = display_length(state->buffer[ser].text, sec); + position_to(state, ser, sec); + state->saved_column = state->display_column; + } + return 0; +} + +static int position_to_selection_start(struct DrawState* state) { if (SEL_NOT_EMPTY(state)) @@ -1762,8 +1777,8 @@ prev_match(struct DrawState* state) { struct BufferLine* current = NULL; const uint32_t* found = NULL; - size_t idelta; - size_t row; + ssize_t idelta; + ssize_t row; if (!state->search || !*state->search) return 0; @@ -1771,14 +1786,14 @@ prev_match(struct DrawState* state) *state->error = 0; row = state->coord.row; - while (row >= 0) + while (1) { const uint32_t* save_found; current = state->buffer + row; found = current->text; if (!found) return 0; - if (row == (size_t)state->coord.row) + if (row == state->coord.row) found += state->coord.col; else found += current->length; @@ -1896,10 +1911,10 @@ reread_or_callback(struct DrawState* state) static int save_file(struct DrawState* state) { - FILE* output = NULL; - char* buf = NULL; - char* pbuf = NULL; - size_t bufsize = LINE_DEFAULT; + FILE* output = NULL; + char* buf = NULL; + char* pbuf = NULL; + ssize_t bufsize = LINE_DEFAULT; #ifdef CREATE_BACKUPS struct stat st; #endif @@ -2009,7 +2024,7 @@ save_skip_backup_symlink: if (state->rows_count == 1 && state->buffer[0].length == 0) goto save_file_cleanup; - for (size_t row = 0; row < state->rows_count; row++) + for (ssize_t row = 0; row < state->rows_count; row++) { ENSURE_SIZE(buf, pbuf, bufsize, UTF8REPMAX * state->buffer[row].length + 1, @@ -2229,7 +2244,7 @@ simple_insert_line(struct DrawState* state) return; } state->buffer = newchunk; - for (size_t row = state->buffer_size - ALLOC_DELTA; + for (ssize_t row = state->buffer_size - ALLOC_DELTA; row < state->buffer_size; row++) { line = state->buffer + row; @@ -2240,23 +2255,25 @@ simple_insert_line(struct DrawState* state) } } state->rows_count++; - for (size_t i = state->rows_count - 1; - i > (size_t)(state->coord.row + 1); i--) + for (ssize_t i = state->rows_count - 1; i > (state->coord.row + 1); i--) { U32_SAFE_COPY(state->buffer[i].text, ptext, state->buffer[i].size, state->buffer[i - 1].text, state->buffer[i - 1].size, simple_insert_line_error); - state->buffer[i].length = u32_strlen(state->buffer[i].text); + state->buffer[i].length = state->buffer[i - 1].length; } U32_SAFE_COPY(state->buffer[state->coord.row + 1].text, ptext, state->buffer[state->coord.row + 1].size, state->buffer[state->coord.row].text + state->coord.col, state->buffer[state->coord.row].size, simple_insert_line_error); + state->buffer[state->coord.row + 1].length - = u32_strlen(state->buffer[state->coord.row + 1].text); + = state->buffer[state->coord.row].length - state->coord.col; + state->buffer[state->coord.row].text[state->coord.col] = 0; state->buffer[state->coord.row].length = state->coord.col; - state->dirty = 1; + + state->dirty = 1; return; simple_insert_line_error: @@ -2266,29 +2283,24 @@ simple_insert_line_error: static void simple_join_lines(struct DrawState* state) { - size_t first_line = state->coord.row; - uint32_t* ptext = NULL; + struct BufferLine* first_line = NULL; + struct BufferLine* next_line = NULL; + uint32_t* ptext = NULL; - if (first_line == state->rows_count - 1) + if ((state->coord.row + 1) == state->rows_count) return; - ENSURE_SIZE(state->buffer[first_line].text, ptext, - state->buffer[first_line].size, - state->buffer[first_line].length - + state->buffer[first_line + 1].length + 1, - state->buffer[first_line].length - + state->buffer[first_line + 1].length + 1, + first_line = &state->buffer[state->coord.row]; + next_line = &state->buffer[state->coord.row + 1]; + ENSURE_SIZE(first_line->text, ptext, first_line->size, + first_line->length + next_line->length + 1, + first_line->length + next_line->length + LINE_ALLOC_DELTA, simple_join_lines_error, uint32_t); - U32_MEMCCPY((state->buffer[first_line].text - + state->buffer[first_line].length), - state->buffer[first_line + 1].text, - state->buffer[first_line].size - - state->buffer[first_line + 1].length, - ptext); - state->buffer[first_line].length - = u32_strlen(state->buffer[first_line].text); - //+= state->buffer[first_line + 1].length; - for (size_t i = first_line + 1; i < state->rows_count - 1; i++) + U32_MEMCCPY((first_line->text + first_line->length), next_line->text, + next_line->length + 1, ptext); + first_line->length = u32_strlen(first_line->text); + /* i <- i+1 */ + for (ssize_t i = state->coord.row + 1; i + 1 < state->rows_count; i++) { U32_SAFE_COPY(state->buffer[i].text, ptext, state->buffer[i].size, state->buffer[i + 1].text, @@ -2314,7 +2326,7 @@ simple_yank(struct DrawState* state) int ser = 0; int sec = 0; struct BufferLine* newbuf = NULL; - size_t initialize_start; + ssize_t initialize_start; uint32_t* ptext = NULL; if (!SEL_NOT_EMPTY(state)) @@ -2348,7 +2360,7 @@ simple_yank(struct DrawState* state) } else newbuf = state->paste; - for (size_t row = initialize_start; row < state->paste_size; row++) + for (ssize_t row = initialize_start; row < state->paste_size; row++) { init_bufferline(newbuf + row); ENSURE_SIZE(newbuf[row].text, ptext, newbuf[row].size, @@ -2359,20 +2371,20 @@ simple_yank(struct DrawState* state) if (state->paste_count == 1) { U32_SAFE_COPY(state->paste[0].text, ptext, state->paste[0].size, - state->buffer[ssr].text + ssc, (size_t)(sec - ssc + 1), + state->buffer[ssr].text + ssc, (sec - ssc + 1), simple_yank_alloc_error); state->paste[0].length = sec - ssc; } else { - size_t first_line_len = state->buffer[ssr].length - ssc; + ssize_t first_line_len = state->buffer[ssr].length - ssc; U32_SAFE_COPY(state->paste[0].text, ptext, state->paste[0].size, state->buffer[ssr].text + ssc, first_line_len + 1, simple_yank_alloc_error); state->paste[0].length = first_line_len; - for (size_t row = 1; row < state->paste_count - 1; row++) + for (ssize_t row = 1; row < state->paste_count - 1; row++) { U32_SAFE_COPY(state->paste[row].text, ptext, state->paste[row].size, @@ -2385,7 +2397,7 @@ simple_yank(struct DrawState* state) U32_SAFE_COPY(state->paste[state->paste_count - 1].text, ptext, state->paste[state->paste_count - 1].size, - state->buffer[ser].text, (size_t)(sec + 1), + state->buffer[ser].text, (sec + 1), simple_yank_alloc_error); state->paste[state->paste_count - 1].length = sec; } @@ -2440,6 +2452,192 @@ toggle_selection(struct DrawState* state) return 0; } +/* + * Not ideal (todo). In extreme cases (files generated by the testsuite, with a + * huge block of full lines with no spaces), becomes unresponsive and has to be + * killed. But in most "normal" cases, behaves acceptably. + */ +static int +wrap_para(struct DrawState* state) +{ + char* temp = NULL; +#ifdef ENABLE_WRAP + struct BufferLine* current = NULL; + struct BufferLine* next = NULL; + uint32_t* ptext = NULL; + int sel = SEL_NOT_EMPTY(state); + int start_row; + int end_row; + int cur_row; + int bcol; + int dlen; + int col; + + MEMCCPY(state->action, actions[ACT_WRAPPING], LINE_DEFAULT, temp); + redraw_status(state); + + if (sel) + get_selection(&start_row, NULL, &end_row, NULL, state); + else + { + start_row = state->coord.row; + end_row = start_row; + for (cur_row = start_row; cur_row > 0; cur_row--) + if (state->buffer[cur_row - 1].length == 0 + || !u32_has_nonblanks( + state->buffer[cur_row - 1].text)) + { + start_row = cur_row; + break; + } + if (cur_row == 0) + start_row = cur_row; + for (cur_row = state->coord.row; cur_row < state->rows_count; + cur_row++) + if (state->buffer[cur_row].length == 0 + || !u32_has_nonblanks( + state->buffer[cur_row].text)) + { + end_row = cur_row - 1; + break; + } + } + + cur_row = start_row; +wrap_next_line: + state->coord.col = 0; + current = &state->buffer[cur_row]; + next = &state->buffer[cur_row + 1]; + bcol = buffer_length(current->text, WRAP_WIDTH); + state->coord.row = cur_row; + + dlen = display_length(current->text, current->length); + while (dlen < WRAP_WIDTH && u32_has_nonblanks(next->text)) + { + /* Insert space to avoid joining ending and beginning words */ + if (!u32_is_word_boundary(current->text[current->length - 1], 1)) + { + ENSURE_SIZE(current->text, ptext, current->size, + current->length + 2, current->length + 2, + wrap_alloc_error, uint32_t); + current->length++; + current->text[current->length - 1] = L' '; + current->text[current->length] = 0; + } + + simple_join_lines(state); + + if (sel) + { + state->sel_end.row--; + state->sel_end.col + = state->buffer[state->sel_end.row].length; + } + end_row--; + dlen = display_length(current->text, current->length); + } + + while (dlen >= WRAP_WIDTH) + { + bcol = buffer_length(current->text, WRAP_WIDTH); + while (bcol > 0 + && !u32_is_word_boundary(current->text[bcol - 1], 1)) + bcol--; + if (bcol == 0) + break; + ENSURE_SIZE(current->text, ptext, current->size, + current->length + 1, current->length + LINE_ALLOC_DELTA, + wrap_alloc_error, uint32_t); + state->coord.col = bcol - 1; + + simple_insert_line(state); + + cur_row++; + state->coord.row++; + current = &state->buffer[cur_row]; + + /* Remove the space between the two words at split */ + if (u32_is_word_boundary(current->text[0], 1)) + { + *current->text = 0; + for (col = 0; col < current->length; col++) + current->text[col] = current->text[col + 1]; + current->length--; + } + + if (sel) + { + state->sel_end.row++; + state->sel_end.col + = state->buffer[state->sel_end.row].length; + } + end_row++; + if (cur_row == state->rows_count) + break; + + /* If the line in block is < WRAP_WIDTH, join it with next */ + next = &state->buffer[cur_row + 1]; + if (u32_has_nonblanks(next->text) + && display_length(current->text, current->length) + < WRAP_WIDTH) + { + /* Add space if needed to avoid joining words */ + if (!u32_is_word_boundary(current->text[current->length + - 1], + 1)) + { + ENSURE_SIZE(current->text, ptext, current->size, + current->length + 2, + current->length + 2, wrap_alloc_error, + uint32_t); + current->length++; + current->text[current->length - 1] = L' '; + current->text[current->length] = 0; + } + + simple_join_lines(state); + + if (sel) + { + state->sel_end.row--; + state->sel_end.col + = state->buffer[state->sel_end.row] + .length; + } + end_row--; + } + + if (cur_row == MIN((end_row + 1), state->rows_count)) + break; + + bcol = buffer_length(current->text, WRAP_WIDTH); + while (bcol > 0 + && !u32_is_word_boundary(current->text[bcol - 1], 1)) + bcol--; + if (bcol == 0) + break; + dlen = display_length(current->text, current->length); + } + cur_row++; + if (cur_row < MIN((end_row + 1), state->rows_count)) + goto wrap_next_line; + + if (sel) + position_to_selection_end(state); + else + position_to(state, cur_row, 0); + + *state->action = 0; + +#else + MEMCCPY(state->error, errors[ERR_NOT_IMP], LINE_DEFAULT, temp); +#endif + return 0; + +wrap_alloc_error: + return 1; +} + static int write_file(struct DrawState* state) { @@ -2498,8 +2696,8 @@ main(int argc, char** argv) char action[LINE_DEFAULT]; char prompt[LINE_DEFAULT]; struct DrawState state; - char* filename = NULL; - size_t filename_size = 0; + char* filename = NULL; + ssize_t filename_size = 0; struct stat st; int result; int dir_access; diff --git a/sled.h b/sled.h @@ -7,7 +7,7 @@ static int clear_selection(struct DrawState* state); static int cp(const char* from, const char* to); static int create_file(struct DrawState* dstate); static int cut_to_paste(struct DrawState* state); -static char* dirname(char* dir, char* path, const size_t path_size); +static char* dirname(char* dir, char* path, const ssize_t path_size); static int do_search_replace(struct DrawState* state); static int enter_command_mode(struct DrawState* state); static int enter_insert_mode(struct DrawState* state); @@ -64,6 +64,7 @@ static int next_match(struct DrawState* state); static int paste_from_paste(struct DrawState* state); static void position_to(struct DrawState* state, const int row, const int column); +static int position_to_selection_end(struct DrawState* state); static int position_to_selection_start(struct DrawState* state); static int prev_match(struct DrawState* state); static int print_error(const int code, const char* msg, ...); @@ -87,5 +88,6 @@ static void simple_yank(struct DrawState* state); static int suspend_program(struct DrawState* state); static int toggle_overwrite(struct DrawState* state); static int toggle_selection(struct DrawState* state); +static int wrap_para(struct DrawState* state); static int write_file(struct DrawState* state); static int yank_to_paste(struct DrawState* state); diff --git a/util.c b/util.c @@ -62,6 +62,21 @@ unicode_string_to_u8(char* s, const uint32_t* us, const size_t max) return added; } +int +u32_has_nonblanks(const uint32_t* s) +{ + const uint32_t* ps = s; + if (!s) + return 0; + while (*ps) + { + if (!u32_is_word_boundary(*ps, 1)) + return 1; + ps++; + } + return 0; +} + uint32_t* u32_memccpy(uint32_t* dst, const uint32_t* src, uint32_t c, size_t len) { diff --git a/util.h b/util.h @@ -74,7 +74,7 @@ * - Make sure the size of the destination string is large enough to copy, and * copy * - Sizes are in bytes - * - We explicitly use fromsize in u8_strncpy, because we ensured that tosize is + * - We explicitly use fromsize in MEMCCPY, because we ensured that tosize is * at least as big, and to allow a subset of from to be copied */ #define U8_SAFE_COPY(to, temp, tosize, from, fromsize, label) \ @@ -87,7 +87,7 @@ * - Make sure the size of the destination string is large enough to copy, and * copy * - Sizes are in uint32_t units - * - We explicitly use fromsize in u32_strncpy, because we ensured that tosize + * - We explicitly use fromsize in U32_MEMCCPY, because we ensured that tosize * is at least as big, and to allow a subset of from to be copied */ #define U32_SAFE_COPY(to, temp, tosize, from, fromsize, label) \ @@ -109,15 +109,17 @@ enum { ERR_CANT_OPEN, ERR_CANT_COPY, ERR_INPUT_NONNUM, - ERR_INVALID_NUM + ERR_INVALID_NUM, + ERR_NOT_IMP }; -enum { ACT_WRITING, ACT_READING }; +enum { ACT_WRITING, ACT_READING, ACT_WRAPPING }; #define TB_KEY_CTRL_SPACE 0x00 size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max); size_t unicode_string_to_u8(char* s, const uint32_t* us, const size_t max); +int u32_has_nonblanks(const uint32_t* s); uint32_t* u32_memccpy(uint32_t* dst, const uint32_t* src, uint32_t c, size_t len); uint32_t* u32_u8_memccpy(uint32_t* dst, const char* src, uint32_t c, size_t len);