чување 137a5bc48e28f2d2877a34b833e42d2260f8c9c7
родитељ fdf233f7a344430928fbdf6231ede94c9a1f654e
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Mon, 21 Feb 2022 15:06:48 +0100
Fix goto line #0, moving up in empty file; only recalculate screen sizes on resize event; allow creating files
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | TODO | | | 16 | ++++++++-------- |
| A | build-command.sh | | | 1 | + |
| M | sled.c | | | 152 | ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------- |
измењених датотека: 3, додавања: 125(+), брисања: 44(-)
diff --git a/TODO b/TODO
@@ -1,22 +1,22 @@
TODO
====
- [ ] Fix goto line #0
+ [ ] Copy/paste?
- [ ] Fix moving up in empty file
+ [ ] Add vi H/L
- [ ] Copy/paste?
+ [ ] Add vi V
- [ ] Allow creating files (error out if directory not writeable, only
+ [x] Allow creating files (error out if directory not writeable, only
create file when saving)
- [ ] Add handling of terminal resize event
+ [x] Add handling of terminal resize event
- [ ] Add vi H/L
+ [/] Test for binary when opening? (Why?)
- [ ] Add vi V
+ [x] Fix goto line #0
- [ ] Test for binary when opening?
+ [x] Fix moving up in empty file
[x] Write operation; create backup files
diff --git a/build-command.sh b/build-command.sh
@@ -0,0 +1 @@
+SLED_CC='gcc -ggdb -fsanitize=address -fno-omit-frame-pointer -lrt -static-libgcc' redo rebuild -j10
diff --git a/sled.c b/sled.c
@@ -131,6 +131,8 @@ go_to_line_callback(struct DrawState* state)
strcpy(state->error, errors[ERR_INVALID_NUM]);
else if (lineno + 1 > state->rows_count)
move_bottom(state);
+ else if (lineno < 1)
+ move_top(state);
else
{
state->row = lineno - 1;
@@ -173,6 +175,25 @@ quit_callback(struct DrawState* state, struct tb_event* ev)
}
int
+create_file(struct DrawState* state)
+{
+ struct BufferLine* newchunk = NULL;
+
+ newchunk = calloc(ALLOC_DELTA, sizeof(struct BufferLine));
+ if (!newchunk)
+ return LOAD_ERR_CANT_ALLOC;
+ for (size_t row = 0; row < ALLOC_DELTA; row++)
+ init_bufferline(newchunk + row);
+ state->buffer = newchunk;
+ state->buffer_size = ALLOC_DELTA;
+ state->rows_count = 1;
+ state->row = 0;
+ state->dirty = 1;
+
+ return LOAD_ERR_NONE;
+}
+
+int
load_file(struct DrawState* state, long* lineno, long* col)
{
struct BufferLine* newchunk = NULL;
@@ -183,6 +204,8 @@ load_file(struct DrawState* state, long* lineno, long* col)
newchunk = calloc(ALLOC_DELTA, sizeof(struct BufferLine));
if (!newchunk)
return LOAD_ERR_CANT_ALLOC;
+ for (size_t row = 0; row < ALLOC_DELTA; row++)
+ init_bufferline(newchunk + row);
strcpy(state->action, actions[ACT_READING]);
redraw_status(state);
@@ -233,6 +256,21 @@ load_file(struct DrawState* state, long* lineno, long* col)
fclose(input);
*state->action = 0;
+ if (state->rows_count == 0)
+ {
+ line = state->buffer;
+ if (!line->text)
+ {
+ uint32_t* newtext = NULL;
+ newtext = calloc(MAXBUFLINE, sizeof(uint32_t));
+ if (!newtext)
+ return LOAD_ERR_CANT_ALLOC;
+ line->length = 0;
+ line->text = newtext;
+ }
+ state->rows_count++;
+ }
+
return LOAD_ERR_NONE;
}
@@ -242,6 +280,7 @@ save_file(struct DrawState* state)
FILE* output = NULL;
char* buf = NULL;
char* backup_filename = NULL;
+ struct stat st;
if (!(buf = calloc(MAXBUFLINE, 1)))
return SAVE_ERR_CANT_ALLOC;
@@ -251,19 +290,26 @@ save_file(struct DrawState* state)
strcpy(state->action, actions[ACT_WRITING]);
redraw_status(state);
- strcpy(backup_filename, state->filename);
- strcat(backup_filename, "~");
- rename(state->filename, backup_filename);
+ if (stat(state->filename, &st) != -1)
+ {
+ strcpy(backup_filename, state->filename);
+ strcat(backup_filename, "~");
+ rename(state->filename, backup_filename);
+ }
if (!(output = fopen(state->filename, "wt")))
return SAVE_ERR_CANT_OPEN_FILE;
+ if (state->rows_count == 1 && state->buffer[0].length == 0)
+ goto save_file_cleanup;
+
for (size_t row = 0; row < state->rows_count; row++)
{
unicode_string_to_u8(buf, state->buffer[row].text, MAXBUFLINE);
fprintf(output, "%s\n", buf);
}
+save_file_cleanup:
fclose(output);
free(backup_filename);
free(buf);
@@ -364,8 +410,9 @@ paste_paste_buffer_to_input(struct DrawState* state)
int
move_up(struct DrawState* state)
{
- if (state->row > 0)
- state->row--;
+ if (state->row == 0)
+ return 0;
+ state->row--;
if (state->first_shown_row > state->row)
state->first_shown_row = state->row;
if (state->saved_column == -1)
@@ -600,9 +647,10 @@ move_bottom(struct DrawState* state)
int
move_end(struct DrawState* state)
{
- size_t len = state->buffer[state->row].length;
+ size_t len;
size_t dlen;
+ len = state->buffer[state->row].length;
state->column = len;
dlen = display_length(state, state->buffer[state->row].text,
state->column);
@@ -622,7 +670,6 @@ move_end(struct DrawState* state)
int
move_page_up(struct DrawState* state)
{
- *state->error = 0;
if (state->row > state->maxy - 2)
{
state->row -= state->maxy - 2;
@@ -642,11 +689,10 @@ move_page_up(struct DrawState* state)
int
move_page_down(struct DrawState* state)
{
- *state->error = 0;
- if (state->row < state->rows_count - state->maxy - 2)
+ if (state->row + state->maxy - 2 < state->rows_count)
{
state->row += state->maxy - 2;
- if (state->row - state->first_shown_row > state->maxy - 2)
+ if (state->row > state->first_shown_row + state->maxy - 2)
state->first_shown_row = state->row - (state->maxy - 2);
}
else
@@ -914,8 +960,10 @@ insert_line(struct DrawState* state)
return 0;
}
state->buffer = newchunk;
+ for (size_t row = state->buffer_size - ALLOC_DELTA;
+ row < state->buffer_size; row++)
+ init_bufferline(line);
line = state->buffer + state->buffer_size - ALLOC_DELTA;
- init_bufferline(line);
}
if (!line->text)
{
@@ -930,12 +978,11 @@ insert_line(struct DrawState* state)
state->rows_count++;
for (size_t i = state->rows_count - 1; i > state->row + 1; i--)
{
- u32_strncpy(state->buffer[i].text, state->buffer[i - 1].text,
- MAXBUFLINE);
+ u32_strcpy(state->buffer[i].text, state->buffer[i - 1].text);
state->buffer[i].length = state->buffer[i - 1].length;
}
- u32_strncpy(state->buffer[state->row + 1].text,
- state->buffer[state->row].text + state->column, MAXBUFLINE);
+ u32_strcpy(state->buffer[state->row + 1].text,
+ state->buffer[state->row].text + state->column);
state->buffer[state->row + 1].length
= u32_strlen(state->buffer[state->row + 1].text);
state->buffer[state->row].text[state->column] = 0;
@@ -1564,6 +1611,10 @@ main(int argc, char** argv)
struct DrawState state;
char filename[MAXPATH];
struct stat st;
+ long lineno = 1;
+ long col = 1;
+ int result;
+ int recalculate_size = 1;
*error = 0;
*action = 0;
@@ -1592,35 +1643,63 @@ main(int argc, char** argv)
return print_error(EINVAL, "No filename given");
}
- if (stat(filename, &st) == -1
- || access(filename, F_OK | R_OK | W_OK) == -1)
+ init_drawstate(&state, error, action, filename, prompt);
+
+ result = stat(filename, &st);
+ if (result == -1)
{
- perror(program_name);
- return errno;
+ char dirname[MAXPATH];
+ char* slash = NULL;
+
+ if (errno != ENOENT)
+ goto file_error;
+
+ strcpy(dirname, filename);
+ if ((slash = strrchr(dirname, '/')))
+ *slash = 0;
+ else
+ {
+ *dirname = '.';
+ *(dirname + 1) = 0;
+ }
+
+ result = access(dirname, F_OK | R_OK | W_OK);
+ if (result == -1)
+ goto file_error;
+
+ result = create_file(&state);
+ switch (result)
+ {
+ case LOAD_ERR_CANT_ALLOC:
+ return print_error(result,
+ "Allocation failed (out of memory?)");
+ default:;
+ }
+ goto init_termbox;
}
+ if (access(filename, F_OK | R_OK | W_OK) == -1)
+ goto file_error;
+
if (!S_ISREG(st.st_mode))
return print_error(EINVAL, "Is not a regular file");
- init_drawstate(&state, error, action, filename, prompt);
-
- long lineno = 1;
- long col = 1;
- int result = load_file(&state, &lineno, &col);
+ result = load_file(&state, &lineno, &col);
switch (result)
{
case LOAD_ERR_CANT_ALLOC:
return print_error(result, "Allocation failed (out of memory?)");
case LOAD_ERR_CANT_OPEN_FILE:
return print_error(result, "Cannot open file `%s'", filename);
- case LOAD_ERR_NONE:
- if (*error)
- return print_error(1, error);
- break;
- default:
- return print_error(1, "Unknown error (%d)", result);
+ default:;
}
+ goto init_termbox;
+
+file_error:
+ perror(program_name);
+ return errno;
+init_termbox:
tb_init();
*error = 0;
state.maxx = 0;
@@ -1629,20 +1708,21 @@ main(int argc, char** argv)
{
tb_clear();
- int maxx = tb_width();
- if (maxx != state.maxx)
+ if (recalculate_size)
{
- state.maxx = maxx;
+ state.maxx = tb_width();
state.help_width = calculate_help_width(&state);
state.input_dialog_width
= calculate_input_dialog_width(&state);
+ state.maxy = tb_height();
}
- state.maxy = tb_height();
-
if (!draw(&state))
strcpy(state.error, errors[ERR_CANT_ALLOC]);
tb_present();
- if (tb_poll_event(&ev) == TB_OK && ev.type == TB_EVENT_KEY)
+ result = tb_poll_event(&ev);
+ if (result == TB_OK && ev.type == TB_EVENT_RESIZE)
+ recalculate_size = 1;
+ else if (result == TB_OK && ev.type == TB_EVENT_KEY)
handle_key_event(&ev, &state);
}
tb_shutdown();