summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLeo Tenenbaum <pommicket@gmail.com>2021-01-18 16:37:51 -0500
committerLeo Tenenbaum <pommicket@gmail.com>2021-01-18 16:37:51 -0500
commita3adbe5ea6015a76a3df84ee5942b89fbb762947 (patch)
tree712d0fdfaf23818ebf2b361306dbb9d4452e6540
parent37102a766e1913cd0548a981e5c601852ae47963 (diff)
opening files kinda working
-rw-r--r--buffer.c149
-rw-r--r--command.c28
-rw-r--r--command.h5
-rw-r--r--main.c75
-rw-r--r--menu.c34
-rw-r--r--string32.c41
-rw-r--r--ted-base.c13
-rw-r--r--ted.cfg1
-rw-r--r--ted.h9
-rw-r--r--util.c9
10 files changed, 247 insertions, 117 deletions
diff --git a/buffer.c b/buffer.c
index 4bf8c2b..235a59f 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1,11 +1,5 @@
// Text buffers - These store the contents of a file.
-void buffer_create(TextBuffer *buffer, Ted *ted) {
- util_zero_memory(buffer, sizeof *buffer);
- buffer->store_undo_events = true;
- buffer->ted = ted;
-}
-
// this is a macro so we get -Wformat warnings
#define buffer_seterr(buffer, ...) \
snprintf(buffer->error, sizeof buffer->error - 1, __VA_ARGS__)
@@ -73,6 +67,27 @@ static void *buffer_realloc(TextBuffer *buffer, void *p, size_t new_size) {
return ret;
}
+static char *buffer_strdup(TextBuffer *buffer, char const *src) {
+ char *dup = str_dup(src);
+ if (!dup) buffer_out_of_mem(buffer);
+ return dup;
+}
+
+void buffer_create(TextBuffer *buffer, Ted *ted) {
+ util_zero_memory(buffer, sizeof *buffer);
+ buffer->store_undo_events = true;
+ buffer->ted = ted;
+}
+
+void line_buffer_create(TextBuffer *buffer, Ted *ted) {
+ buffer_create(buffer, ted);
+ buffer->is_line_buffer = true;
+ if ((buffer->lines = buffer_calloc(buffer, 1, sizeof *buffer->lines))) {
+ buffer->nlines = 1;
+ buffer->lines_capacity = 1;
+ }
+}
+
// ensures that `p` refers to a valid position.
static void buffer_pos_validate(TextBuffer *buffer, BufferPos *p) {
if (p->line >= buffer->nlines)
@@ -417,7 +432,7 @@ static void buffer_line_free(Line *line) {
free(line->str);
}
-// Free a buffer. Once a buffer is freed, it can be used again for other purposes.
+// Free a buffer. Once a buffer is freed, you can call buffer_create on it again.
// Does not free the pointer `buffer` (buffer might not have even been allocated with malloc)
void buffer_free(TextBuffer *buffer) {
Line *lines = buffer->lines;
@@ -426,6 +441,7 @@ void buffer_free(TextBuffer *buffer) {
buffer_line_free(&lines[i]);
}
free(lines);
+ free(buffer->filename);
arr_foreach_ptr(buffer->undo_history, BufferEdit, edit)
buffer_edit_free(edit);
@@ -434,24 +450,27 @@ void buffer_free(TextBuffer *buffer) {
arr_free(buffer->undo_history);
arr_free(buffer->redo_history);
+ util_zero_memory(buffer, sizeof *buffer);
+}
+// clear contents, undo history, etc. of a buffer
+void buffer_clear(TextBuffer *buffer) {
+ bool is_line_buffer = buffer->is_line_buffer;
Ted *ted = buffer->ted;
-
- // zero buffer, except for error
char error[sizeof buffer->error];
memcpy(error, buffer->error, sizeof error);
- memset(buffer, 0, sizeof *buffer);
- memcpy(buffer->error, error, sizeof error);
-
- buffer_create(buffer, ted);
+ buffer_free(buffer);
+ if (is_line_buffer) {
+ line_buffer_create(buffer, ted);
+ } else {
+ buffer_create(buffer, ted);
+ }
}
-
-// filename must be around for at least as long as the buffer is.
void buffer_load_file(TextBuffer *buffer, char const *filename) {
- buffer_free(buffer);
+ buffer_clear(buffer);
- buffer->filename = filename;
+ buffer->filename = buffer_strdup(buffer, filename);
FILE *fp = fopen(filename, "rb");
if (fp) {
fseek(fp, 0, SEEK_END);
@@ -518,7 +537,7 @@ void buffer_load_file(TextBuffer *buffer, char const *filename) {
success = false;
}
if (!success) {
- buffer_free(buffer);
+ buffer_clear(buffer);
}
} else {
buffer_seterr(buffer, "File %s does not exist.", filename);
@@ -526,35 +545,50 @@ void buffer_load_file(TextBuffer *buffer, char const *filename) {
}
void buffer_new_file(TextBuffer *buffer, char const *filename) {
- buffer_free(buffer);
+ buffer_clear(buffer);
- buffer->filename = filename;
+ buffer->filename = buffer_strdup(buffer, filename);
buffer->lines_capacity = 4;
buffer->lines = buffer_calloc(buffer, buffer->lines_capacity, sizeof *buffer->lines);
buffer->nlines = 1;
}
bool buffer_save(TextBuffer *buffer) {
- FILE *out = fopen(buffer->filename, "wb");
- if (out) {
- bool success = true;
- for (Line *line = buffer->lines, *end = line + buffer->nlines; line != end; ++line) {
- mbstate_t state = {0};
- for (char32_t *p = line->str, *p_end = p + line->len; p != p_end; ++p) {
- char utf8[MB_LEN_MAX] = {0};
- size_t bytes = c32rtomb(utf8, *p, &state);
- fwrite(utf8, 1, bytes, out);
- }
+ if (buffer->filename) {
+ FILE *out = fopen(buffer->filename, "wb");
+ if (out) {
+ bool success = true;
+ for (Line *line = buffer->lines, *end = line + buffer->nlines; line != end; ++line) {
+ mbstate_t state = {0};
+ for (char32_t *p = line->str, *p_end = p + line->len; p != p_end; ++p) {
+ char utf8[MB_LEN_MAX] = {0};
+ size_t bytes = c32rtomb(utf8, *p, &state);
+ fwrite(utf8, 1, bytes, out);
+ }
- if (line != end-1) {
- putc('\n', out);
+ if (line != end-1) {
+ putc('\n', out);
+ }
}
+ if (ferror(out)) success = false;
+ if (fclose(out) != 0) success = false;
+ return success;
+ } else {
+ buffer_seterr(buffer, "Couldn't create file %s.", buffer->filename);
+ return false;
}
- if (ferror(out)) success = false;
- if (fclose(out) != 0) success = false;
- return success;
} else {
- buffer_seterr(buffer, "Couldn't create file %s.", buffer->filename);
+ // user tried to save line buffer. whatever
+ return true;
+ }
+}
+
+// save, but with a different file name
+bool buffer_save_as(TextBuffer *buffer, char const *new_filename) {
+ free(buffer->filename);
+ if ((buffer->filename = buffer_strdup(buffer, new_filename))) {
+ return buffer_save(buffer);
+ } else {
return false;
}
}
@@ -1073,7 +1107,9 @@ void buffer_cursor_move_to_end_of_file(TextBuffer *buffer) {
}
// insert `number` empty lines starting at index `where`.
-static void buffer_insert_lines(TextBuffer *buffer, u32 where, u32 number) {
+static Status buffer_insert_lines(TextBuffer *buffer, u32 where, u32 number) {
+ assert(!buffer->is_line_buffer);
+
u32 old_nlines = buffer->nlines;
u32 new_nlines = old_nlines + number;
if (buffer_lines_set_min_capacity(buffer, new_nlines)) {
@@ -1085,7 +1121,9 @@ static void buffer_insert_lines(TextBuffer *buffer, u32 where, u32 number) {
// zero new lines
util_zero_memory(buffer->lines + where, number * sizeof *buffer->lines);
buffer->nlines = new_nlines;
+ return true;
}
+ return false;
}
// inserts the given text, returning the position of the end of the text
@@ -1096,6 +1134,16 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32
return ret;
}
+ if (buffer->is_line_buffer) {
+ // remove all the newlines from str.
+ str32_remove_all_instances_of_char(&str, U'\n');
+ }
+
+ if (str.len == 0) {
+ // no text to insert
+ return pos;
+ }
+
if (buffer->store_undo_events) {
BufferEdit *last_edit = arr_lastp(buffer->undo_history);
i64 where_in_last_edit = last_edit ? buffer_pos_diff(buffer, last_edit->pos, pos) : -1;
@@ -1121,16 +1169,17 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32
// so we need to go through them one by one
u32 n_added_lines = (u32)str32_count_char(str, U'\n');
if (n_added_lines) {
- buffer_insert_lines(buffer, line_idx + 1, n_added_lines);
- line = &buffer->lines[line_idx]; // fix pointer
- // move any text past the cursor on this line to the last added line.
- Line *last_line = &buffer->lines[line_idx + n_added_lines];
- u32 chars_moved = line->len - index;
- if (chars_moved) {
- if (buffer_line_set_min_capacity(buffer, last_line, chars_moved)) {
- memcpy(last_line->str, line->str + index, chars_moved * sizeof(char32_t));
- line->len -= chars_moved;
- last_line->len += chars_moved;
+ if (buffer_insert_lines(buffer, line_idx + 1, n_added_lines)) {
+ line = &buffer->lines[line_idx]; // fix pointer
+ // move any text past the cursor on this line to the last added line.
+ Line *last_line = &buffer->lines[line_idx + n_added_lines];
+ u32 chars_moved = line->len - index;
+ if (chars_moved) {
+ if (buffer_line_set_min_capacity(buffer, last_line, chars_moved)) {
+ memcpy(last_line->str, line->str + index, chars_moved * sizeof(char32_t));
+ line->len -= chars_moved;
+ last_line->len += chars_moved;
+ }
}
}
}
@@ -1635,10 +1684,11 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
};
- { // header
+ if (!buffer->is_line_buffer) { // header
glColor3f(1,1,1);
float x = x1, y = y1;
- text_render_with_state(font, &text_state, buffer->filename, x, y);
+ if (buffer->filename)
+ text_render_with_state(font, &text_state, buffer->filename, x, y);
#if DEBUG
// show checksum
char checksum[32] = {0};
@@ -1799,4 +1849,3 @@ void buffer_render(TextBuffer *buffer, float x1, float y1, float x2, float y2) {
}
}
}
-
diff --git a/command.c b/command.c
index 6a6b331..684d30a 100644
--- a/command.c
+++ b/command.c
@@ -115,7 +115,7 @@ void command_execute(Ted *ted, Command c, i64 argument) {
break;
case CMD_OPEN:
- ted_menu_open(ted, MENU_OPEN);
+ menu_open(ted, MENU_OPEN);
break;
case CMD_SAVE:
if (buffer) buffer_save(buffer);
@@ -144,11 +144,35 @@ void command_execute(Ted *ted, Command c, i64 argument) {
case CMD_ESCAPE:
if (ted->menu) {
- ted_menu_close(ted, true);
+ menu_close(ted, true);
} else if (buffer) {
buffer_disable_selection(buffer);
}
break;
+ case CMD_SUBMIT_LINE_BUFFER:
+ if (buffer->is_line_buffer) {
+ switch (ted->menu) {
+ case MENU_NONE:
+ assert(0);
+ break;
+ case MENU_OPEN: {
+ TextBuffer *open_to = &ted->main_buffer;
+ String32 filename32 = {.str = buffer->lines[0].str, .len = buffer->lines[0].len};
+
+ char *filename_cstr = str32_to_utf8_cstr(filename32);
+ if (filename_cstr) {
+ buffer_load_file(open_to, filename_cstr);
+ buffer = open_to;
+ if (buffer_haserr(open_to)) {
+ // @TODO: something better
+ }
+ free(filename_cstr);
+ menu_close(ted, true);
+ }
+ } break;
+ }
+ }
+ break;
}
if (buffer && buffer_haserr(buffer)) {
diff --git a/command.h b/command.h
index 6410c3e..50821b5 100644
--- a/command.h
+++ b/command.h
@@ -44,6 +44,8 @@ ENUM_U16 {
CMD_ESCAPE, // by default this is the escape key. closes menus, etc.
+ CMD_SUBMIT_LINE_BUFFER, // submit "line buffer" value -- the line buffer is where you type file names when opening files, etc.
+
CMD_COUNT
} ENUM_U16_END(Command);
@@ -87,6 +89,7 @@ static CommandName const command_names[CMD_COUNT] = {
{"redo", CMD_REDO},
{"increase-text-size", CMD_TEXT_SIZE_INCREASE},
{"decrease-text-size", CMD_TEXT_SIZE_DECREASE},
- {"escape", CMD_ESCAPE}
+ {"escape", CMD_ESCAPE},
+ {"submit-line-buffer", CMD_SUBMIT_LINE_BUFFER}
};
diff --git a/main.c b/main.c
index 75362bd..3a42e87 100644
--- a/main.c
+++ b/main.c
@@ -15,7 +15,6 @@ no_warn_end
#include <shellapi.h>
#endif
-#define TED_PATH_MAX 256
#include "text.h"
#include "util.c"
@@ -178,12 +177,17 @@ int main(int argc, char **argv) {
ted_load_font(ted);
if (ted_haserr(ted))
- die("Error loadng font: %s", ted_geterr(ted));
+ die("Error loading font: %s", ted_geterr(ted));
+ {
+ TextBuffer *lbuffer = &ted->line_buffer;
+ line_buffer_create(lbuffer, ted);
+ if (buffer_haserr(lbuffer))
+ die("Error creating line buffer: %s", buffer_geterr(lbuffer));
+ }
- TextBuffer text_buffer;
{
- TextBuffer *buffer = &text_buffer;
+ TextBuffer *buffer = &ted->main_buffer;
buffer_create(buffer, ted);
ted->active_buffer = buffer;
@@ -216,15 +220,6 @@ int main(int argc, char **argv) {
Uint32 time_at_last_frame = SDL_GetTicks();
bool quit = false;
- bool ctrl_down = false;
- bool shift_down = false;
- bool alt_down = false;
- {
- char appdata[MAX_PATH] = {0};
- if (SHGetSpecialFolderPathA(NULL, appdata, CSIDL_LOCAL_APPDATA, false)) {
- debug_println("%s", appdata);
- }
- }
while (!quit) {
#if DEBUG
//printf("\033[H\033[2J");
@@ -241,12 +236,15 @@ int main(int argc, char **argv) {
SDL_Event event;
Uint8 const *keyboard_state = SDL_GetKeyboardState(NULL);
+ bool ctrl_down = keyboard_state[SDL_SCANCODE_LCTRL] || keyboard_state[SDL_SCANCODE_RCTRL];
+ bool shift_down = keyboard_state[SDL_SCANCODE_LSHIFT] || keyboard_state[SDL_SCANCODE_RSHIFT];
+ bool alt_down = keyboard_state[SDL_SCANCODE_LALT] || keyboard_state[SDL_SCANCODE_RALT];
+
while (SDL_PollEvent(&event)) {
TextBuffer *buffer = ted->active_buffer;
u32 key_modifier = (u32)ctrl_down << KEY_MODIFIER_CTRL_BIT
| (u32)shift_down << KEY_MODIFIER_SHIFT_BIT
| (u32)alt_down << KEY_MODIFIER_ALT_BIT;
- // @TODO: make a function to handle text buffer events
switch (event.type) {
case SDL_QUIT:
quit = true;
@@ -295,18 +293,6 @@ int main(int argc, char **argv) {
break;
case SDL_KEYDOWN: {
SDL_Scancode scancode = event.key.keysym.scancode;
- switch (scancode) {
- case SDL_SCANCODE_LCTRL:
- case SDL_SCANCODE_RCTRL:
- ctrl_down = true; break;
- case SDL_SCANCODE_LSHIFT:
- case SDL_SCANCODE_RSHIFT:
- shift_down = true; break;
- case SDL_SCANCODE_LALT:
- case SDL_SCANCODE_RALT:
- alt_down = true; break;
- default: break;
- }
SDL_Keymod modifier = event.key.keysym.mod;
u32 key_combo = (u32)scancode << 3 |
(u32)((modifier & (KMOD_LCTRL|KMOD_RCTRL)) != 0) << KEY_MODIFIER_CTRL_BIT |
@@ -314,33 +300,24 @@ int main(int argc, char **argv) {
(u32)((modifier & (KMOD_LALT|KMOD_RALT)) != 0) << KEY_MODIFIER_ALT_BIT;
if (key_combo < KEY_COMBO_COUNT) {
KeyAction *action = &ted->key_actions[key_combo];
+ bool was_in_line_buffer = buffer && buffer->is_line_buffer;
if (action->command) {
command_execute(ted, action->command, action->argument);
- } else if (buffer) switch (event.key.keysym.sym) {
- case SDLK_RETURN:
- buffer_insert_char_at_cursor(buffer, U'\n');
+ }
+
+ if (buffer) {
+ switch (key_combo) {
+ case SDL_SCANCODE_RETURN << 3:
+ if (!was_in_line_buffer) // make sure return to submit line buffer doesn't get added to newly-active buffer
+ buffer_insert_char_at_cursor(buffer, U'\n');
break;
- case SDLK_TAB:
+ case SDL_SCANCODE_TAB << 3:
buffer_insert_char_at_cursor(buffer, U'\t');
break;
+ }
}
}
} break;
- case SDL_KEYUP: {
- SDL_Scancode scancode = event.key.keysym.scancode;
- switch (scancode) {
- case SDL_SCANCODE_LCTRL:
- case SDL_SCANCODE_RCTRL:
- ctrl_down = false; break;
- case SDL_SCANCODE_LSHIFT:
- case SDL_SCANCODE_RSHIFT:
- shift_down = false; break;
- case SDL_SCANCODE_LALT:
- case SDL_SCANCODE_RALT:
- alt_down = false; break;
- default: break;
- }
- } break;
case SDL_TEXTINPUT: {
char *text = event.text.text;
if (buffer
@@ -400,7 +377,7 @@ int main(int argc, char **argv) {
{
float x1 = 50, y1 = 50, x2 = window_width-50, y2 = window_height-50;
- buffer_render(&text_buffer, x1, y1, x2, y2);
+ buffer_render(&ted->main_buffer, x1, y1, x2, y2);
if (text_has_err()) {
die("Text error: %s\n", text_get_err());
break;
@@ -413,7 +390,8 @@ int main(int argc, char **argv) {
}
#if DEBUG
- buffer_check_valid(&text_buffer);
+ buffer_check_valid(&ted->main_buffer);
+ buffer_check_valid(&ted->line_buffer);
#endif
SDL_GL_SwapWindow(window);
@@ -422,7 +400,8 @@ int main(int argc, char **argv) {
SDL_GL_DeleteContext(glctx);
SDL_DestroyWindow(window);
SDL_Quit();
- buffer_free(&text_buffer);
+ buffer_free(&ted->main_buffer);
+ buffer_free(&ted->line_buffer);
text_font_free(ted->font);
free(ted);
#if _WIN32
diff --git a/menu.c b/menu.c
index 6862d0e..9ef2245 100644
--- a/menu.c
+++ b/menu.c
@@ -1,3 +1,23 @@
+static void menu_open(Ted *ted, Menu menu) {
+ ted->menu = menu;
+ ted->prev_active_buffer = ted->active_buffer;
+ ted->active_buffer = NULL;
+
+ switch (menu) {
+ case MENU_NONE: assert(0); break;
+ case MENU_OPEN:
+ ted->active_buffer = &ted->line_buffer;
+ break;
+ }
+}
+
+static void menu_close(Ted *ted, bool restore_prev_active_buffer) {
+ ted->menu = MENU_NONE;
+ if (restore_prev_active_buffer) ted->active_buffer = ted->prev_active_buffer;
+ ted->prev_active_buffer = NULL;
+
+ buffer_clear(&ted->line_buffer);
+}
static void menu_render(Ted *ted, Menu menu) {
Settings *settings = &ted->settings;
@@ -22,6 +42,7 @@ static void menu_render(Ted *ted, Menu menu) {
float menu_y1 = padding;
float menu_y2 = window_height - padding;
Rect menu_rect = rect4(menu_x1, menu_y1, menu_x2, menu_y2);
+ float inner_padding = 10;
// menu rectangle & border
glBegin(GL_QUADS);
@@ -30,6 +51,14 @@ static void menu_render(Ted *ted, Menu menu) {
gl_color_rgba(colors[COLOR_BORDER]);
rect_render_border(menu_rect, settings->border_thickness);
glEnd();
+
+ float line_buffer_height = char_height * 1.5f;
+ float line_buffer_x1 = menu_x1 + inner_padding,
+ line_buffer_y1 = menu_y1 + inner_padding,
+ line_buffer_x2 = menu_x2 - inner_padding,
+ line_buffer_y2 = line_buffer_y1 + line_buffer_height;
+
+ buffer_render(&ted->line_buffer, line_buffer_x1, line_buffer_y1, line_buffer_x2, line_buffer_y2);
char **files = fs_list_directory(directory);
if (files) {
@@ -38,8 +67,8 @@ static void menu_render(Ted *ted, Menu menu) {
qsort(files, nfiles, sizeof *files, str_qsort_case_insensitive_cmp);
{ // render file names
- float x = menu_x1 + 10, y = menu_y1 + char_height * 0.75f + 10;
- TextRenderState text_render_state = {.min_x = menu_x1, .max_x = menu_x2, .min_y = menu_y1, .max_y = menu_y2};
+ float x = menu_x1 + inner_padding, y = menu_y1 + line_buffer_height + inner_padding;
+ TextRenderState text_render_state = {.min_x = menu_x1, .max_x = menu_x2, .min_y = menu_y1, .max_y = menu_y2, .render = true};
gl_color_rgba(colors[COLOR_TEXT]);
for (u32 i = 0; i < nfiles; ++i) {
text_render_with_state(font, &text_render_state, files[i], x, y);
@@ -50,6 +79,5 @@ static void menu_render(Ted *ted, Menu menu) {
for (u32 i = 0; i < nfiles; ++i) free(files[i]);
free(files);
}
-
}
}
diff --git a/string32.c b/string32.c
index 7bd20b4..35aa1a2 100644
--- a/string32.c
+++ b/string32.c
@@ -48,6 +48,29 @@ String32 str32_from_utf8(char const *utf8) {
return string;
}
+// returns a null-terminated UTF-8 string
+// the string returned should be free'd
+// this will return NULL on failure
+static char *str32_to_utf8_cstr(String32 s) {
+ char *utf8 = calloc(4 * s.len + 1, 1); // each codepoint takes up at most 4 bytes in UTF-8, + we need a terminating null byte
+ if (utf8) {
+ char *p = utf8;
+ mbstate_t mbstate; memset(&mbstate, 0, sizeof mbstate);
+ for (size_t i = 0; i < s.len; ++i) {
+ size_t bytes = c32rtomb(p, s.str[i], &mbstate);
+ if (bytes == (size_t)-1) {
+ // invalid UTF-32 character
+ free(utf8);
+ return NULL;
+ } else {
+ p += bytes;
+ }
+ }
+ *p = '\0';
+ }
+ return utf8;
+}
+
// returns the index of the given character in the string, or the length of the string if it's not found.
size_t str32chr(String32 s, char32_t c) {
for (size_t i = 0; i < s.len; ++i) {
@@ -65,3 +88,21 @@ size_t str32_count_char(String32 s, char32_t c) {
}
return total;
}
+
+// returns number of characters deleted from s
+size_t str32_remove_all_instances_of_char(String32 *s, char32_t c) {
+ bool increment = true;
+ char32_t *str = s->str;
+ size_t ndeleted = 0;
+ for (size_t i = 0; i < s->len; i += increment, increment = true) {
+ if (str[i] == c) {
+ --s->len;
+ if (i < s->len) {
+ str[i] = str[i+1];
+ }
+ ++ndeleted;
+ increment = false;
+ }
+ }
+ return ndeleted;
+}
diff --git a/ted-base.c b/ted-base.c
index ab6ec98..e00a70a 100644
--- a/ted-base.c
+++ b/ted-base.c
@@ -80,14 +80,5 @@ static void ted_load_font(Ted *ted) {
}
}
-static void ted_menu_open(Ted *ted, Menu menu) {
- ted->menu = menu;
- ted->prev_active_buffer = ted->active_buffer;
- ted->active_buffer = NULL;
-}
-
-static void ted_menu_close(Ted *ted, bool restore_prev_active_buffer) {
- ted->menu = MENU_NONE;
- if (restore_prev_active_buffer) ted->active_buffer = ted->prev_active_buffer;
- ted->prev_active_buffer = NULL;
-}
+static void menu_open(Ted *ted, Menu menu);
+static void menu_close(Ted *ted, bool restore_prev_active_buffer);
diff --git a/ted.cfg b/ted.cfg
index c2e00df..11bfabc 100644
--- a/ted.cfg
+++ b/ted.cfg
@@ -61,6 +61,7 @@ Ctrl++ = 3 :increase-text-size
Ctrl+- = 3 :decrease-text-size
Escape = :escape
+Return = :submit-line-buffer
[colors]
border = #a77
diff --git a/ted.h b/ted.h
index 5cc5f4e..b0e325b 100644
--- a/ted.h
+++ b/ted.h
@@ -1,3 +1,5 @@
+#define TED_PATH_MAX 256
+
#define TEXT_SIZE_MIN 6
#define TEXT_SIZE_MAX 70
@@ -22,7 +24,7 @@ typedef struct {
#define KEY_MODIFIER_ALT (1<<KEY_MODIFIER_ALT_BIT)
// ctrl+alt+c is encoded as SDL_SCANCODE_C << 3 | KEY_MODIFIER_CTRL | KEY_MODIFIER_ALT
-typedef struct {
+typedef struct KeyAction {
u32 line_number; // config line number where this was set
Command command; // this will be 0 (COMMAND_UNKNOWN) if there's no action for the key
i64 argument;
@@ -50,11 +52,12 @@ typedef struct BufferEdit {
} BufferEdit;
typedef struct {
- char const *filename;
+ char *filename; // NULL if this buffer doesn't correspond to a file (e.g. line buffers)
struct Ted *ted; // we keep a back-pointer to the ted instance so we don't have to pass it in to every buffer function
double scroll_x, scroll_y; // number of characters scrolled in the x/y direction
BufferPos cursor_pos;
BufferPos selection_pos; // if selection is true, the text between selection_pos and cursor_pos is selected.
+ bool is_line_buffer; // "line buffers" are buffers which can only have one line of text (used for inputs)
bool selection;
bool store_undo_events; // set to false to disable undo events
float x1, y1, x2, y2;
@@ -80,6 +83,8 @@ typedef struct Ted {
Settings settings;
float window_width, window_height;
Menu menu;
+ TextBuffer line_buffer; // general-purpose line buffer for inputs -- used for menus
+ TextBuffer main_buffer;
KeyAction key_actions[KEY_COMBO_COUNT];
char error[256];
} Ted;
diff --git a/util.c b/util.c
index 5bde9b6..1d6bb79 100644
--- a/util.c
+++ b/util.c
@@ -46,6 +46,15 @@ static bool streq(char const *a, char const *b) {
return strcmp(a, b) == 0;
}
+// duplicates a null-terminated string. the returned string should be passed to free()
+static char *str_dup(char const *src) {
+ size_t len = strlen(src);
+ char *ret = malloc(len + 1);
+ if (ret)
+ memcpy(ret, src, len + 1);
+ return ret;
+}
+
// like snprintf, but not screwed up on windows
#define str_printf(str, size, ...) (str)[(size) - 1] = '\0', snprintf((str), (size) - 1, __VA_ARGS__)
// like snprintf, but the size is taken to be the length of the array str.