summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buffer.c4
-rw-r--r--menu.c40
-rw-r--r--session.c37
-rw-r--r--ted.c1
-rw-r--r--ted.h1
5 files changed, 72 insertions, 11 deletions
diff --git a/buffer.c b/buffer.c
index 28ec364..b016d9e 100644
--- a/buffer.c
+++ b/buffer.c
@@ -1249,6 +1249,8 @@ static Status buffer_insert_lines(TextBuffer *buffer, u32 where, u32 number) {
// inserts the given text, returning the position of the end of the text
BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 str) {
+ buffer_pos_validate(buffer, &pos);
+
if (buffer->view_only)
return pos;
if (str.len > U32_MAX) {
@@ -1480,6 +1482,8 @@ void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars_)
if (nchars_ > U32_MAX) nchars_ = U32_MAX;
u32 nchars = (u32)nchars_;
+ buffer_pos_validate(buffer, &pos);
+
// Correct nchars in case it goes past the end of the file.
// Why do we need to correct it?
// When generating undo events, we allocate nchars characters of memory (see buffer_edit below).
diff --git a/menu.c b/menu.c
index 79b597e..54f05df 100644
--- a/menu.c
+++ b/menu.c
@@ -29,6 +29,7 @@ static void menu_close(Ted *ted) {
case MENU_COMMAND_SELECTOR:
buffer_clear(&ted->line_buffer);
buffer_clear(&ted->argument_buffer);
+ free(ted->command_selector.entries);
break;
}
ted->menu = MENU_NONE;
@@ -70,10 +71,10 @@ static void menu_open(Ted *ted, Menu menu) {
case MENU_GOTO_LINE:
ted_switch_to_buffer(ted, &ted->line_buffer);
break;
- case MENU_COMMAND_SELECTOR:
+ case MENU_COMMAND_SELECTOR: {
ted_switch_to_buffer(ted, &ted->line_buffer);
buffer_insert_char_at_cursor(&ted->argument_buffer, '1');
- break;
+ } break;
}
}
@@ -244,6 +245,36 @@ static void menu_update(Ted *ted) {
line_buffer->line_buffer_submitted = false;
free(contents);
} break;
+ case MENU_COMMAND_SELECTOR: {
+ Selector *selector = &ted->command_selector;
+ SelectorEntry *entries = selector->entries = calloc(arr_count(command_names), sizeof *selector->entries);
+ if (entries) {
+ for (size_t i = 0; i < arr_count(command_names); ++i) {
+ if (command_names[i].cmd != CMD_UNKNOWN) {
+ char const *name = command_names[i].name;
+ entries[i].name = name;
+ entries[i].color = COLOR_TEXT;
+ }
+ }
+ selector->n_entries = arr_count(command_names);
+ }
+
+ char *chosen_command = selector_update(ted, &ted->command_selector);
+ if (chosen_command) {
+ Command c = command_from_str(chosen_command);
+ char *argument = str32_to_utf8_cstr(buffer_get_line(&ted->argument_buffer, 0)), *endp = NULL;
+ long long arg = strtoll(argument, &endp, 0);
+
+ if (*endp == '\0') {
+ menu_close(ted);
+ command_execute(ted, c, arg);
+ }
+
+ free(argument);
+ free(chosen_command);
+ }
+ free(selector->entries); selector->entries = NULL; selector->n_entries = 0;
+ } break;
}
}
@@ -277,7 +308,7 @@ static void menu_render(Ted *ted) {
float menu_x1, menu_y1, menu_x2, menu_y2;
rect_coords(bounds, &menu_x1, &menu_y1, &menu_x2, &menu_y2);
- if (menu == MENU_OPEN || menu == MENU_SAVE_AS || menu == MENU_GOTO_DEFINITION) {
+ if (menu == MENU_OPEN || menu == MENU_SAVE_AS || menu == MENU_GOTO_DEFINITION || menu == MENU_COMMAND_SELECTOR) {
// menu rectangle & border
gl_geometry_rect(bounds, colors[COLOR_MENU_BG]);
gl_geometry_rect_border(bounds, settings->border_thickness, colors[COLOR_BORDER]);
@@ -345,5 +376,8 @@ static void menu_render(Ted *ted) {
// line buffer
buffer_render(&ted->line_buffer, rect4(x1, y1, x2, y2));
} break;
+ case MENU_COMMAND_SELECTOR:
+ selector_render(ted, &ted->command_selector);
+ break;
}
}
diff --git a/session.c b/session.c
index cbd84b0..4895f34 100644
--- a/session.c
+++ b/session.c
@@ -93,8 +93,8 @@ static void session_read_buffer(Ted *ted, FILE *fp) {
static void session_write_file(Ted *ted, FILE *fp) {
fwrite(SESSION_VERSION, 1, sizeof SESSION_VERSION, fp);
- write_u16(fp, (u16)(ted->active_node - ted->nodes)); // active node idx
- write_u16(fp, (u16)(ted->active_buffer - ted->buffers)); // active buffer idx
+ write_u16(fp, ted->active_node ? (u16)(ted->active_node - ted->nodes) : U16_MAX); // active node idx
+ write_u16(fp, ted->active_buffer ? (u16)(ted->active_buffer - ted->buffers) : U16_MAX); // active buffer idx
u16 nnodes = 0;
for (u16 i = 0; i < TED_MAX_NODES; ++i)
@@ -121,8 +121,8 @@ static void session_read_file(Ted *ted, FILE *fp) {
return; // wrong version
}
- u16 active_node_idx = clamp_u16(read_u16(fp), 0, TED_MAX_NODES);
- u16 active_buffer_idx = clamp_u16(read_u16(fp), 0, TED_MAX_BUFFERS);
+ u16 active_node_idx = read_u16(fp);
+ u16 active_buffer_idx = read_u16(fp);
u16 nnodes = clamp_u16(read_u16(fp), 0, TED_MAX_NODES);
for (u16 i = 0; i < nnodes; ++i) {
@@ -134,10 +134,31 @@ static void session_read_file(Ted *ted, FILE *fp) {
session_read_buffer(ted, fp);
}
- if (ted->nodes_used[active_node_idx])
- ted->active_node = &ted->nodes[active_node_idx];
- if (ted->buffers_used[active_buffer_idx])
- ted->active_buffer = &ted->buffers[active_buffer_idx];
+ if (active_node_idx == U16_MAX) {
+ ted->active_node = NULL;
+ } else {
+ active_node_idx = clamp_u16(active_node_idx, 0, TED_MAX_NODES);
+ if (ted->nodes_used[active_node_idx])
+ ted->active_node = &ted->nodes[active_node_idx];
+ }
+
+ if (active_buffer_idx == U16_MAX) {
+ ted->active_buffer = NULL;
+ } else {
+ active_buffer_idx = clamp_u16(active_buffer_idx, 0, TED_MAX_BUFFERS);
+ if (ted->buffers_used[active_buffer_idx])
+ ted->active_buffer = &ted->buffers[active_buffer_idx];
+ }
+
+ if (nbuffers && !ted->active_buffer) {
+ // set active buffer to something
+ for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) {
+ if (ted->buffers_used[i]) {
+ ted_switch_to_buffer(ted, &ted->buffers[i]);
+ break;
+ }
+ }
+ }
}
static void session_write(Ted *ted) {
diff --git a/ted.c b/ted.c
index 2c8fb92..8b6c657 100644
--- a/ted.c
+++ b/ted.c
@@ -1,5 +1,6 @@
static void menu_open(Ted *ted, Menu menu);
static void find_update(Ted *ted, bool force);
+static Command command_from_str(char const *str);
// this is a macro so we get -Wformat warnings
#define ted_seterr(ted, ...) \
diff --git a/ted.h b/ted.h
index cb2f35c..f67a27c 100644
--- a/ted.h
+++ b/ted.h
@@ -254,6 +254,7 @@ typedef struct Ted {
Menu menu;
FileSelector file_selector;
Selector tag_selector; // for "go to definition of..." menu
+ Selector command_selector;
TextBuffer line_buffer; // general-purpose line buffer for inputs -- used for menus
TextBuffer find_buffer; // use for "find" term in find/find+replace
TextBuffer replace_buffer; // "replace" for find+replace