tAdd basic file loading and writing functionality - ledit - Text editor (WIP) | |
git clone git://lumidify.org/ledit.git (fast, but not encrypted) | |
git clone https://lumidify.org/git/ledit.git (encrypted, but very slow) | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit 86dd70c41a66c874b49092caa1986ecedd36f254 | |
parent 36a12616e748e39265af475dbaee5e8356cc984a | |
Author: lumidify <[email protected]> | |
Date: Wed, 22 Sep 2021 20:17:12 +0200 | |
Add basic file loading and writing functionality | |
Diffstat: | |
M buffer.c | 103 +++++++++++++++++++++++++++++… | |
M buffer.h | 8 ++++++-- | |
M commands.c | 9 +++++++-- | |
M ledit.c | 13 ++++++++++++- | |
4 files changed, 122 insertions(+), 11 deletions(-) | |
--- | |
diff --git a/buffer.c b/buffer.c | |
t@@ -1,8 +1,10 @@ | |
/* FIXME: shrink buffers when text length less than a fourth of the size */ | |
/* FIXME: also cache PangoLayouts since keeping them around isn't really of mu… | |
+#include <stdio.h> | |
#include <string.h> | |
#include <assert.h> | |
+#include <limits.h> | |
#include <X11/Xlib.h> | |
#include <X11/Xutil.h> | |
t@@ -44,6 +46,7 @@ ledit_create_buffer(ledit_common_state *state) { | |
ledit_buffer *buffer = ledit_malloc(sizeof(ledit_buffer)); | |
buffer->state = state; | |
buffer->lines = NULL; | |
+ buffer->filename = NULL; | |
buffer->lines_num = 0; | |
buffer->lines_cap = 0; | |
buffer->cur_line = 0; | |
t@@ -62,6 +65,84 @@ ledit_create_buffer(ledit_common_state *state) { | |
return buffer; | |
} | |
+/* FIXME: don't generate extra blank line at end! */ | |
+/* WARNING: errstr must be copied as soon as possible! */ | |
+int | |
+ledit_load_file_into_buffer(ledit_buffer *buffer, char *filename, int line, ch… | |
+ long len; | |
+ int off = 0; | |
+ ledit_line *ll; | |
+ char *file_contents; | |
+ FILE *file; | |
+ | |
+ file = fopen(filename, "r"); | |
+ if (!file) goto error; | |
+ if (fseek(file, 0, SEEK_END)) goto errorclose; | |
+ len = ftell(file); | |
+ if (len < 0) goto errorclose; | |
+ if (fseek(file, 0, SEEK_SET)) goto errorclose; | |
+ | |
+ ll = ledit_get_line(buffer, line); | |
+ file_contents = ledit_malloc(len + 2); | |
+ /* mimic nvi (or at least the openbsd version) - if the line | |
+ is empty, insert directly, otherwise insert after the line */ | |
+ if (ll->len > 0) { | |
+ off = 1; | |
+ file_contents[0] = '\n'; | |
+ } | |
+ clearerr(file); | |
+ fread(file_contents + off, 1, (size_t)len, file); | |
+ if (ferror(file)) goto errorclose; | |
+ file_contents[len + off] = '\0'; | |
+ /* don't generate extra newline at end */ | |
+ if (len + off > 1 && file_contents[len + off - 1 == '\n']) { | |
+ file_contents[len + off - 1] = '\0'; | |
+ len--; | |
+ } | |
+ if (fclose(file)) goto error; | |
+ | |
+ ledit_insert_text_with_newlines( | |
+ buffer, line, ll->len, file_contents, len + off, NULL, NULL | |
+ ); | |
+ free(file_contents); | |
+ return 0; | |
+error: | |
+ if (*errstr) | |
+ *errstr = strerror(errno); | |
+ return 1; | |
+errorclose: | |
+ if (*errstr) | |
+ *errstr = strerror(errno); | |
+ fclose(file); | |
+ return 1; | |
+} | |
+ | |
+/* FIXME: allow to write only certain lines */ | |
+int | |
+ledit_write_buffer_to_file(ledit_buffer *buffer, char *filename, char **errstr… | |
+ FILE *file; | |
+ ledit_line *ll; | |
+ file = fopen(filename, "w"); | |
+ if (!file) goto error; | |
+ clearerr(file); | |
+ for (int i = 0; i < buffer->lines_num; i++) { | |
+ ll = ledit_get_line(buffer, i); | |
+ ledit_normalize_line(ll); | |
+ if (fprintf(file, "%s\n", ll->text) < 0) goto errorclose; | |
+ } | |
+ if (fclose(file)) goto error; | |
+ return 0; | |
+error: | |
+ if (*errstr) | |
+ *errstr = strerror(errno); | |
+ return 1; | |
+errorclose: | |
+ if (*errstr) | |
+ *errstr = strerror(errno); | |
+ fclose(file); | |
+ return 1; | |
+} | |
+ | |
void | |
ledit_destroy_buffer(ledit_buffer *buffer) { | |
ledit_line *l; | |
t@@ -71,6 +152,7 @@ ledit_destroy_buffer(ledit_buffer *buffer) { | |
free(l->text); | |
} | |
free(buffer->lines); | |
+ if (buffer->filename) free(buffer->filename); | |
free(buffer); | |
} | |
t@@ -84,6 +166,7 @@ ledit_normalize_line(ledit_line *line) { | |
); | |
line->gap = line->len; | |
} | |
+ /* FIXME: check if enough space, just to be sure */ | |
line->text[line->len] = '\0'; | |
} | |
t@@ -338,8 +421,8 @@ ledit_insert_text_final(ledit_buffer *buffer, int line_ind… | |
/* FIXME: this isn't optimized like the standard version, but whatever */ | |
static char * | |
-strchr_len(char *text, char c, int len) { | |
- for (int i = 0; i < len; i++) { | |
+strchr_len(char *text, char c, long len) { | |
+ for (long i = 0; i < len; i++) { | |
if (text[i] == c) | |
return text + i; | |
} | |
t@@ -347,11 +430,18 @@ strchr_len(char *text, char c, int len) { | |
} | |
/* FIXME: make these functions that call recalc* also be final as described ab… | |
+/* FIXME: Sort out integer types. | |
+ -> len is long here mainly because that's what ftell(3) returns and it sort… | |
+ makes sense since a file can be very long (although ledit probably won't wo… | |
+ with such long files anyways). The individual lines have to use int anyways | |
+ because of pango. | |
+ Maybe len isn't needed anyways? It might be possible to enforce that text | |
+ just always has to be null-terminated. */ | |
void | |
ledit_insert_text_with_newlines( | |
ledit_buffer *buffer, | |
int line_index, int index, | |
- char *text, int len, | |
+ char *text, long len, | |
int *end_line_ret, int *end_char_ret) { | |
int end; | |
ledit_insert_text_with_newlines_base( | |
t@@ -366,15 +456,16 @@ ledit_insert_text_with_newlines( | |
ledit_recalc_from_line(buffer, line_index); | |
} | |
+/* FIXME: Check for integer overflow when casting to int */ | |
void | |
ledit_insert_text_with_newlines_base( | |
ledit_buffer *buffer, | |
int line_index, int index, | |
- char *text, int len, | |
+ char *text, long len, | |
int *end_line_ret, int *end_char_ret) { | |
if (len == -1) | |
len = strlen(text); | |
- int rem_len = len; | |
+ long rem_len = len; | |
char *cur, *last = text; | |
int cur_line = line_index; | |
int cur_index = index; | |
t@@ -384,8 +475,8 @@ ledit_insert_text_with_newlines_base( | |
ledit_insert_text_base(buffer, cur_line, cur_index, last, cur … | |
cur_index = 0; | |
cur_line++; | |
- last = cur + 1; | |
rem_len -= cur - last + 1; | |
+ last = cur + 1; | |
} | |
/* FIXME: check how legal this casting between pointers and ints is */ | |
ledit_insert_text_base(buffer, cur_line, cur_index, last, text + len -… | |
diff --git a/buffer.h b/buffer.h | |
t@@ -25,9 +25,11 @@ typedef struct { | |
char h_dirty; /* whether height needs to be recalculated still */ | |
} ledit_line; | |
+/* TODO: advisory lock on file? also check if modification date changed before… | |
struct ledit_buffer { | |
ledit_common_state *state; /* general state, e.g. display, window, etc… | |
ledit_line *lines; /* array of lines */ | |
+ char *filename; | |
int lines_cap; /* number of lines allocated in array */ | |
int lines_num; /* number of used lines */ | |
int cur_line; /* current line */ | |
t@@ -44,6 +46,8 @@ struct ledit_buffer { | |
}; | |
ledit_buffer *ledit_create_buffer(ledit_common_state *state); | |
+int ledit_load_file_into_buffer(ledit_buffer *buffer, char *filename, int line… | |
+int ledit_write_buffer_to_file(ledit_buffer *buffer, char *filename, char **er… | |
void ledit_destroy_buffer(ledit_buffer *buffer); | |
void ledit_normalize_line(ledit_line *line); | |
void ledit_set_line_selection(ledit_buffer *buffer, int line, int start_byte, … | |
t@@ -80,7 +84,7 @@ void ledit_insert_text_base(ledit_buffer *buffer, int line_i… | |
void ledit_insert_text_with_newlines_base( | |
ledit_buffer *buffer, | |
int line_index, int index, | |
- char *text, int len, | |
+ char *text, long len, | |
int *end_line_ret, int *end_char_ret | |
); | |
void ledit_append_line_base(ledit_buffer *buffer, int line_index, int text_ind… | |
t@@ -105,7 +109,7 @@ void ledit_insert_text(ledit_buffer *buffer, int line_inde… | |
void ledit_insert_text_with_newlines( | |
ledit_buffer *buffer, | |
int line_index, int index, | |
- char *text, int len, | |
+ char *text, long len, | |
int *end_line_ret, int *end_char_ret | |
); | |
void ledit_append_line(ledit_buffer *buffer, int line_index, int text_index); | |
diff --git a/commands.c b/commands.c | |
t@@ -1,5 +1,6 @@ | |
/* FIXME: Parse commands properly and allow combinations of commands */ | |
#include <ctype.h> | |
+#include <stdlib.h> | |
#include <X11/Xlib.h> | |
#include <X11/Xutil.h> | |
#include <pango/pangoxft.h> | |
t@@ -16,7 +17,10 @@ handle_write(ledit_buffer *buffer, char *cmd, int l1, int l… | |
(void)cmd; | |
(void)l1; | |
(void)l2; | |
- printf("write\n"); | |
+ /* FIXME: Implement properly; handle error */ | |
+ char *errstr; | |
+ if (buffer->filename) | |
+ ledit_write_buffer_to_file(buffer, buffer->filename, &errstr); | |
return 0; | |
} | |
t@@ -26,7 +30,8 @@ handle_quit(ledit_buffer *buffer, char *cmd, int l1, int l2)… | |
(void)cmd; | |
(void)l1; | |
(void)l2; | |
- printf("quit\n"); | |
+ /* FIXME: Implement */ | |
+ exit(1); | |
return 0; | |
} | |
diff --git a/ledit.c b/ledit.c | |
t@@ -37,6 +37,7 @@ | |
#include "cache.h" | |
#include "util.h" | |
#include "undo.h" | |
+#include "commands.h" | |
enum key_type { | |
KEY_NONE = 0, | |
t@@ -1021,7 +1022,17 @@ setup(int argc, char *argv[]) { | |
buffer = ledit_create_buffer(&state); | |
/* FIXME: move this to create_buffer */ | |
ledit_init_undo_stack(buffer); | |
- set_mode(INSERT); | |
+ /* FIXME: Support multiple buffers/files */ | |
+ if (argc > 1) { | |
+ char *load_err; | |
+ if (ledit_load_file_into_buffer(buffer, argv[1], 0, &load_err)… | |
+ fprintf(stderr, "Error opening file '%s': %s\n", argv[… | |
+ exit(1); | |
+ } | |
+ buffer->filename = ledit_strdup(argv[1]); | |
+ } | |
+ set_mode(NORMAL); | |
+ ledit_set_line_cursor_attrs(buffer, buffer->cur_line, buffer->cur_inde… | |
key_stack.len = key_stack.alloc = 0; | |
key_stack.stack = NULL; |