summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--buffer.c114
-rw-r--r--build.c15
-rw-r--r--command.c20
-rw-r--r--find.c120
-rw-r--r--ide-autocomplete.c28
-rw-r--r--ide-rename-symbol.c12
-rw-r--r--ide-signature-help.c11
-rw-r--r--ide-usages.c4
-rw-r--r--main.c3
-rw-r--r--menu.c46
-rw-r--r--node.c2
-rw-r--r--session.c42
-rw-r--r--tags.c6
-rw-r--r--ted-internal.h99
-rw-r--r--ted.c19
-rw-r--r--ted.h20
-rw-r--r--ui.c4
17 files changed, 301 insertions, 264 deletions
diff --git a/buffer.c b/buffer.c
index f1e8047..3f94cf1 100644
--- a/buffer.c
+++ b/buffer.c
@@ -8,6 +8,12 @@
#define BUFFER_UNTITLED "Untitled" // what to call untitled buffers
+/// A single line in a buffer
+typedef struct Line Line;
+
+/// A single undoable edit to a buffer
+typedef struct BufferEdit BufferEdit;
+
struct Line {
SyntaxState syntax;
u32 len;
@@ -24,6 +30,87 @@ struct BufferEdit {
double time; // time at start of edit (i.e. the time just before the edit), in seconds since epoch
};
+struct TextBuffer {
+ /// NULL if this buffer is untitled or doesn't correspond to a file (e.g. line buffers)
+ char *path;
+ /// we keep a back-pointer to the ted instance so we don't have to pass it in to every buffer function
+ Ted *ted;
+ /// number of characters scrolled in the x direction (multiply by space width to get pixels)
+ double scroll_x;
+ /// number of characters scrolled in the y direction
+ double scroll_y;
+ /// last write time to \ref path
+ double last_write_time;
+ /// the language the buffer has been manually set to, or \ref LANG_NONE if it hasn't been set to anything
+ i64 manual_language;
+ /// position of cursor
+ BufferPos cursor_pos;
+ /// if \ref selection is true, the text between \ref selection_pos and \ref cursor_pos is selected.
+ BufferPos selection_pos;
+ /// "previous" position of cursor, for \ref CMD_PREVIOUS_POSITION
+ BufferPos prev_cursor_pos;
+ /// "line buffers" are buffers which can only have one line of text (used for inputs)
+ bool is_line_buffer;
+ /// is anything selected?
+ bool selection;
+ /// set to false to disable undo events
+ bool store_undo_events;
+ /// will the next undo event be chained with the ones after?
+ bool will_chain_edits;
+ /// will the next undo event be chained with the previous one?
+ bool chaining_edits;
+ /// view-only mode
+ bool view_only;
+ /// (line buffers only) set to true when submitted. you have to reset it to false.
+ bool line_buffer_submitted;
+ /// If set to true, buffer will be scrolled to the cursor position next frame.
+ /// This is to fix the problem that \ref x1, \ref y1, \ref x2, \ref y2 are not updated until the buffer is rendered.
+ bool center_cursor_next_frame;
+ /// x coordinate of left side of buffer
+ float x1;
+ /// y coordinate of top side of buffer
+ float y1;
+ /// x coordinate of right side of buffer
+ float x2;
+ /// y coordinate of bottom side of buffer
+ float y2;
+ /// number of lines in buffer
+ u32 nlines;
+ /// capacity of \ref lines
+ u32 lines_capacity;
+
+ /// cached settings index (into ted->all_settings), or -1 if has not been computed yet
+ i32 settings_idx;
+
+ /// which LSP this document is open in
+ LSPID lsp_opened_in;
+ /// determining which LSP to use for a buffer takes some work,
+ /// so we don't want to do it every single frame.
+ /// this keeps track of the last time we actually checked what the correct LSP is.
+ double last_lsp_check;
+
+ /// where in the undo history was the last write? used by \ref buffer_unsaved_changes
+ u32 undo_history_write_pos;
+ /// which lines are on screen? updated when \ref buffer_render is called.
+ u32 first_line_on_screen, last_line_on_screen;
+
+ /// to cache syntax highlighting properly, it is important to keep track of the
+ /// first and last line modified since last frame.
+ u32 frame_earliest_line_modified;
+ /// see \ref frame_earliest_line_modified.
+ u32 frame_latest_line_modified;
+
+ /// lines
+ Line *lines;
+ /// last error
+ char error[256];
+ /// dynamic array of undo history
+ BufferEdit *undo_history;
+ /// dynamic array of redo history
+ BufferEdit *redo_history;
+};
+
+
// this is a macro so we get -Wformat warnings
#define buffer_error(buffer, ...) \
snprintf(buffer->error, sizeof buffer->error - 1, __VA_ARGS__)
@@ -82,6 +169,17 @@ bool buffer_is_named_file(TextBuffer *buffer) {
return buffer->path != NULL;
}
+bool buffer_is_line_buffer(TextBuffer *buffer) {
+ return buffer->is_line_buffer;
+}
+
+bool line_buffer_is_submitted(TextBuffer *buffer) {
+ return buffer->is_line_buffer && buffer->line_buffer_submitted;
+}
+
+void line_buffer_clear_submitted(TextBuffer *buffer) {
+ buffer->line_buffer_submitted = false;
+}
bool buffer_is_view_only(TextBuffer *buffer) {
return buffer->view_only;
@@ -107,6 +205,10 @@ BufferPos buffer_cursor_pos(TextBuffer *buffer) {
return buffer->cursor_pos;
}
+bool buffer_has_selection(TextBuffer *buffer) {
+ return buffer->selection;
+}
+
bool buffer_selection_pos(TextBuffer *buffer, BufferPos *pos) {
if (buffer->selection) {
if (pos) *pos = buffer->selection_pos;
@@ -1107,7 +1209,10 @@ void buffer_scroll_to_cursor(TextBuffer *buffer) {
buffer_scroll_to_pos(buffer, buffer->cursor_pos);
}
-// scroll so that the cursor is in the center of the screen
+void buffer_set_manual_language(TextBuffer *buffer, u32 language) {
+ buffer->manual_language = language;
+}
+
void buffer_center_cursor(TextBuffer *buffer) {
double cursor_line = buffer->cursor_pos.line;
double cursor_col = buffer_index_to_xoff(buffer, (u32)cursor_line, buffer->cursor_pos.index)
@@ -1121,6 +1226,10 @@ void buffer_center_cursor(TextBuffer *buffer) {
buffer_correct_scroll(buffer);
}
+void buffer_center_cursor_next_frame(TextBuffer *buffer) {
+ buffer->center_cursor_next_frame = true;
+}
+
// move left (if `by` is negative) or right (if `by` is positive) by the specified amount.
// returns the signed number of characters successfully moved (it could be less in magnitude than `by` if the beginning of the file is reached)
static i64 buffer_pos_move_horizontally(TextBuffer *buffer, BufferPos *p, i64 by) {
@@ -1549,7 +1658,6 @@ void buffer_cursor_move_to_end_of_file(TextBuffer *buffer) {
static void buffer_lines_modified(TextBuffer *buffer, u32 first_line, u32 last_line) {
assert(last_line >= first_line);
- buffer->modified = true;
if (first_line < buffer->frame_earliest_line_modified)
buffer->frame_earliest_line_modified = first_line;
if (last_line > buffer->frame_latest_line_modified)
@@ -2606,8 +2714,6 @@ void buffer_redo(TextBuffer *buffer, i64 ntimes) {
// buffer_end_edit_chain(buffer)
// pressing ctrl+z will undo both the insertion of text1 and text2.
void buffer_start_edit_chain(TextBuffer *buffer) {
- assert(!buffer->chaining_edits);
- assert(!buffer->will_chain_edits);
buffer->will_chain_edits = true;
}
diff --git a/build.c b/build.c
index 7d6eed7..63658b9 100644
--- a/build.c
+++ b/build.c
@@ -52,7 +52,7 @@ static bool build_run_next_command_in_queue(Ted *ted) {
buffer_insert_text_at_cursor(build_buffer, str32(text, 2));
buffer_insert_utf8_at_cursor(build_buffer, command);
buffer_insert_char_at_cursor(build_buffer, '\n');
- build_buffer->view_only = true;
+ buffer_set_view_only(build_buffer, true);
free(command);
return true;
} else {
@@ -70,7 +70,7 @@ void build_setup_buffer(Ted *ted) {
// new empty build output buffer
TextBuffer *build_buffer = ted->build_buffer;
buffer_new_file(build_buffer, NULL);
- build_buffer->store_undo_events = false; // don't need undo events for build output buffer
+ buffer_set_undo_enabled(build_buffer, false); // don't need undo events for build output buffer
}
void build_queue_finish(Ted *ted) {
@@ -147,7 +147,7 @@ static void build_go_to_error(Ted *ted) {
// move cursor to error
buffer_cursor_move_to_pos(buffer, pos);
- buffer->center_cursor_next_frame = true;
+ buffer_center_cursor(buffer);
// move cursor to error in build output
TextBuffer *build_buffer = ted->build_buffer;
@@ -203,7 +203,7 @@ void build_check_for_errors(Ted *ted) {
TextBuffer *buffer = ted->build_buffer;
arr_clear(ted->build_errors);
- for (u32 line_idx = 0; line_idx < buffer->nlines; ++line_idx) {
+ for (u32 line_idx = 0; line_idx < buffer_line_count(buffer); ++line_idx) {
String32 line = buffer_get_line(buffer, line_idx);
if (line.len < 3) {
continue;
@@ -313,7 +313,7 @@ void build_frame(Ted *ted, float x1, float y1, float x2, float y2) {
assert(ted->build_shown);
char buf[256];
if (ted->building) {
- buffer->view_only = false; // disable view only temporarily so we can edit it
+ buffer_set_view_only(buffer, false); // disable view only temporarily so we can edit it
bool any_text_inserted = false;
while (1) {
char incomplete[4];
@@ -363,8 +363,7 @@ void build_frame(Ted *ted, float x1, float y1, float x2, float y2) {
if (any_text_inserted) {
// show bottom of output (only relevant if there are no build errors)
- buffer->cursor_pos = buffer_pos_end_of_file(buffer);
- buffer_scroll_to_cursor(buffer);
+ buffer_cursor_move_to_end_of_file(buffer);
}
ProcessExitInfo info = {0};
@@ -380,7 +379,7 @@ void build_frame(Ted *ted, float x1, float y1, float x2, float y2) {
build_check_for_errors(ted);
}
}
- buffer->view_only = true;
+ buffer_set_view_only(buffer, true);
}
buffer_render(buffer, rect4(x1, y1, x2, y2));
}
diff --git a/command.c b/command.c
index 4f14234..05b36cc 100644
--- a/command.c
+++ b/command.c
@@ -318,8 +318,8 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
}
break;
case CMD_COPY_PATH:
- if (buffer) {
- SDL_SetClipboardText(buffer->path);
+ if (buffer && buffer_is_named_file(buffer)) {
+ SDL_SetClipboardText(buffer_get_path(buffer));
} else {
SDL_SetClipboardText(ted->cwd);
}
@@ -335,7 +335,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
} else if (autocomplete_is_open(ted) || autocomplete_has_phantom(ted)) {
autocomplete_select_completion(ted);
} else if (buffer) {
- if (buffer->selection)
+ if (buffer_has_selection(buffer))
buffer_indent_selection(buffer);
else
buffer_insert_tab_at_cursor(buffer);
@@ -350,7 +350,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
ted_switch_to_buffer(ted, buffer);
buffer_select_all(buffer);
} else if (buffer) {
- if (buffer->selection)
+ if (buffer_has_selection(buffer))
buffer_dedent_selection(buffer);
else
buffer_dedent_cursor_line(buffer);
@@ -417,7 +417,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
case CMD_SAVE:
ted->last_save_time = ted->frame_time;
if (buffer) {
- if (!buffer->path) {
+ if (!buffer_is_named_file(buffer)) {
command_execute(ted, CMD_SAVE_AS, 1);
return;
}
@@ -426,7 +426,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
break;
case CMD_SAVE_AS:
ted->last_save_time = ted->frame_time;
- if (buffer && !buffer->is_line_buffer) {
+ if (buffer && !buffer_is_line_buffer(buffer)) {
menu_open(ted, MENU_SAVE_AS);
}
break;
@@ -465,11 +465,11 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
break;
case CMD_SET_LANGUAGE:
- if (buffer && !buffer->is_line_buffer) {
+ if (buffer && !buffer_is_line_buffer(buffer)) {
if (argument <= 0 || argument > LANG_USER_MAX || !language_is_valid((Language)argument))
- buffer->manual_language = 0;
+ buffer_set_manual_language(buffer, 0);
else
- buffer->manual_language = argument;
+ buffer_set_manual_language(buffer, (u32)argument);
}
break;
case CMD_AUTOCOMPLETE:
@@ -556,7 +556,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen
break;
case CMD_VIEW_ONLY:
- if (buffer) buffer->view_only = !buffer->view_only;
+ if (buffer) buffer_set_view_only(buffer, !buffer_is_view_only(buffer));
break;
case CMD_TAB_CLOSE: {
diff --git a/find.c b/find.c
index d89fa95..5d3bdb4 100644
--- a/find.c
+++ b/find.c
@@ -122,8 +122,8 @@ static WarnUnusedResult bool find_match(Ted *ted, BufferPos *pos, u32 *match_sta
pos->index = (u32)groups[1];
return true;
} else {
- pos->line += (u32)((i64)buffer->nlines + direction);
- pos->line %= buffer->nlines;
+ pos->line += (u32)((i64)buffer_line_count(buffer) + direction);
+ pos->line %= buffer_line_count(buffer);
if (direction == +1)
pos->index = 0;
else
@@ -143,14 +143,8 @@ static void find_search_line(Ted *ted, u32 line, FindResult **results) {
}
}
-// check if the search term needs to be recompiled
-void find_update(Ted *ted, bool force) {
- TextBuffer *find_buffer = ted->find_buffer;
+void find_redo_search(Ted *ted) {
u32 flags = find_compilation_flags(ted);
- if (!force
- && !find_buffer->modified // check if pattern has been modified,
- && ted->find_flags == flags) // or checkboxes have been (un)checked
- return;
ted->find_flags = flags;
TextBuffer *buffer = find_search_buffer(ted);
if (!buffer) return;
@@ -159,10 +153,10 @@ void find_update(Ted *ted, bool force) {
if (find_compile_pattern(ted)) {
BufferPos best_scroll_candidate = {U32_MAX, U32_MAX};
- BufferPos cursor_pos = buffer->cursor_pos;
+ BufferPos cursor_pos = buffer_cursor_pos(buffer);
// find all matches
arr_clear(ted->find_results);
- for (u32 line = 0; line < buffer->nlines; ++line) {
+ for (u32 line = 0, count = buffer_line_count(buffer); line < count; ++line) {
find_search_line(ted, line, &ted->find_results);
}
@@ -172,24 +166,24 @@ void find_update(Ted *ted, bool force) {
best_scroll_candidate = res->start;
}
- find_buffer->modified = false;
if (best_scroll_candidate.line != U32_MAX) // scroll to first match (if there is one)
buffer_scroll_to_pos(buffer, best_scroll_candidate);
- } else if (find_buffer->modified) {
- buffer_scroll_to_cursor(buffer);
}
}
// returns the index of the match we are "on", or U32_MAX for none.
static u32 find_match_idx(Ted *ted) {
- find_update(ted, false);
TextBuffer *buffer = find_search_buffer(ted);
if (!buffer) return U32_MAX;
arr_foreach_ptr(ted->find_results, FindResult, result) {
- if ((buffer_pos_eq(result->start, buffer->selection_pos)
- && buffer_pos_eq(result->end, buffer->cursor_pos))
- || buffer_pos_eq(result->start, buffer->cursor_pos))
- return (u32)(result - ted->find_results);
+ u32 index = (u32)(result - ted->find_results);
+ BufferPos cur_pos = buffer_cursor_pos(buffer), sel_pos = {0};
+ if (buffer_pos_eq(result->start, cur_pos))
+ return index;
+ if (buffer_selection_pos(buffer, &sel_pos)
+ && buffer_pos_eq(result->start, sel_pos)
+ && buffer_pos_eq(result->end, cur_pos))
+ return index;
}
return U32_MAX;
}
@@ -199,15 +193,20 @@ static void find_next_in_direction(Ted *ted, int direction) {
TextBuffer *buffer = find_search_buffer(ted);
if (!buffer) return;
- BufferPos pos = direction == +1 || !buffer->selection ? buffer->cursor_pos : buffer->selection_pos;
- u32 nlines = buffer->nlines;
+ BufferPos cursor_pos = buffer_cursor_pos(buffer);
+ BufferPos pos = cursor_pos;
+ if (direction == -1) {
+ // start from selection pos if there is one
+ buffer_selection_pos(buffer, &pos);
+ }
+ u32 nlines = buffer_line_count(buffer);
// we need to search the starting line twice, because we might start at a non-zero index
for (size_t nsearches = 0; nsearches < nlines + 1; ++nsearches) {
u32 match_start, match_end;
if (find_match(ted, &pos, &match_start, &match_end, direction)) {
- if (nsearches == 0 && match_start == buffer->cursor_pos.index) {
+ if (nsearches == 0 && match_start == cursor_pos.index) {
// if you click "next" and your cursor is on a match, it should go to the next
// one, not the one you're on
} else {
@@ -222,10 +221,9 @@ static void find_next_in_direction(Ted *ted, int direction) {
}
// returns true if successful.
-// this function zeroes but keeps around the old find result! make sure you call find_update(ted, true) after calling this function
+// this function zeroes but keeps around the old find result! make sure you call find_redo_search after calling this function
// one or more times!
static bool find_replace_match(Ted *ted, u32 match_idx) {
- find_update(ted, false);
if (!ted->find_code) return false;
bool success = false;
@@ -256,7 +254,7 @@ static bool find_replace_match(Ted *ted, u32 match_idx) {
flags, ted->find_match_data, NULL, replacement.str,
replacement.len, output_buffer, &output_size);
if (ret > 0) {
- buffer->selection = false; // stop selecting match
+ buffer_deselect(buffer); // stop selecting match
buffer_delete_chars_at_pos(buffer, match.start, len);
if (output_buffer)
buffer_insert_text_at_pos(buffer, match.start, str32(output_buffer, output_size));
@@ -288,7 +286,7 @@ void find_replace(Ted *ted) {
if (match_idx != U32_MAX) {
buffer_cursor_move_to_pos(buffer, ted->find_results[match_idx].start); // move to start of match
find_replace_match(ted, match_idx);
- find_update(ted, true);
+ find_redo_search(ted);
}
}
@@ -324,7 +322,7 @@ void find_replace_all(Ted *ted) {
break;
}
buffer_end_edit_chain(buffer);
- find_update(ted, true);
+ find_redo_search(ted);
}
}
}
@@ -395,7 +393,8 @@ void find_menu_frame(Ted *ted, Rect menu_bounds) {
find_replace_all(ted);
}
- find_update(ted, false);
+ if (ted->find_flags != find_compilation_flags(ted))
+ find_redo_search(ted);
arr_foreach_ptr(ted->find_results, FindResult, result) {
// highlight matches
BufferPos p1 = result->start, p2 = result->end;
@@ -479,7 +478,7 @@ void find_open(Ted *ted, bool replace) {
buffer_select_all(ted->active_buffer);
ted->find = true;
ted->replace = replace;
- find_update(ted, true);
+ find_redo_search(ted);
}
void find_close(Ted *ted) {
@@ -531,49 +530,50 @@ static void find_research_lines(Ted *ted, u32 line0, u32 line1) {
}
static void find_edit_notify(void *context, TextBuffer *buffer, const EditInfo *info) {
- (void)context;
- Ted *ted = buffer->ted;
+ Ted *ted = context;
if (!ted->find) {
return;
}
- if (buffer != find_search_buffer(ted))
- return;
-
- const u32 line = info->pos.line;
-
- if (info->chars_inserted) {
- const u32 newlines_inserted = info->newlines_inserted;
+ if (buffer == find_search_buffer(ted)) {
+ const u32 line = info->pos.line;
- if (newlines_inserted) {
- // update line numbers for find results after insertion.
- arr_foreach_ptr(ted->find_results, FindResult, res) {
- if (res->start.line > line) {
- res->start.line += newlines_inserted;
- res->end.line += newlines_inserted;
+ if (info->chars_inserted) {
+ const u32 newlines_inserted = info->newlines_inserted;
+
+ if (newlines_inserted) {
+ // update line numbers for find results after insertion.
+ arr_foreach_ptr(ted->find_results, FindResult, res) {
+ if (res->start.line > line) {
+ res->start.line += newlines_inserted;
+ res->end.line += newlines_inserted;
+ }
}
}
- }
-
- find_research_lines(ted, line, line + newlines_inserted);
-
- } else if (info->chars_deleted) {
- const u32 newlines_deleted = info->newlines_deleted;
-
- if (newlines_deleted) {
- // update line numbers for find results after deletion.
- arr_foreach_ptr(ted->find_results, FindResult, res) {
- if (res->start.line >= line + newlines_deleted) {
- res->start.line -= newlines_deleted;
- res->end.line -= newlines_deleted;
+
+ find_research_lines(ted, line, line + newlines_inserted);
+
+ } else if (info->chars_deleted) {
+ const u32 newlines_deleted = info->newlines_deleted;
+
+ if (newlines_deleted) {
+ // update line numbers for find results after deletion.
+ arr_foreach_ptr(ted->find_results, FindResult, res) {
+ if (res->start.line >= line + newlines_deleted) {
+ res->start.line -= newlines_deleted;
+ res->end.line -= newlines_deleted;
+ }
}
+
}
+ find_research_lines(ted, line, line);
}
-
- find_research_lines(ted, line, line);
+ } else if (buffer == ted->line_buffer) {
+ find_redo_search(ted);
+ buffer_scroll_to_cursor(buffer);
}
}
void find_init(Ted *ted) {
- ted_add_edit_notify(ted, find_edit_notify, NULL);
+ ted_add_edit_notify(ted, find_edit_notify, ted);
}
diff --git a/ide-autocomplete.c b/ide-autocomplete.c
index 42183ff..6f67506 100644
--- a/ide-autocomplete.c
+++ b/ide-autocomplete.c
@@ -94,8 +94,8 @@ static bool autocomplete_should_display_phantom(Ted *ted) {
TextBuffer *buffer = ted->active_buffer;
bool show = !ac->open
&& buffer
- && !buffer->view_only
- && !buffer->is_line_buffer
+ && !buffer_is_view_only(buffer)
+ && !buffer_is_line_buffer(buffer)
&& buffer_settings(buffer)->phantom_completions
&& is32_word(buffer_char_before_cursor(buffer))
&& !is32_word(buffer_char_at_cursor(buffer));
@@ -198,7 +198,7 @@ static void autocomplete_no_suggestions(Ted *ted) {
}
static void autocomplete_send_completion_request(Ted *ted, TextBuffer *buffer, BufferPos pos, uint32_t trigger, bool phantom) {
- if (!buffer->path)
+ if (!buffer_is_named_file(buffer))
return; // no can do
LSP *lsp = buffer_lsp(buffer);
@@ -218,7 +218,7 @@ static void autocomplete_send_completion_request(Ted *ted, TextBuffer *buffer, B
request.data.completion = (LSPRequestCompletion) {
.position = {
- .document = lsp_document_id(lsp, buffer->path),
+ .document = buffer_lsp_document_id(buffer),
.pos = buffer_pos_to_lsp_position(buffer, pos)
},
.context = {
@@ -245,7 +245,7 @@ static void autocomplete_find_completions(Ted *ted, uint32_t trigger, bool phant
TextBuffer *buffer = ted->active_buffer;
if (!buffer)
return;
- BufferPos pos = buffer->cursor_pos;
+ BufferPos pos = buffer_cursor_pos(buffer);
if (buffer_pos_eq(pos, ac->last_pos))
return; // no need to update completions.
ac->trigger = trigger;
@@ -451,11 +451,11 @@ void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response) {
void autocomplete_open(Ted *ted, uint32_t trigger) {
Autocomplete *ac = ted->autocomplete;
- if (ac->open) return;
TextBuffer *buffer = ted->active_buffer;
+ if (ac->open) return;
if (!buffer) return;
- if (!buffer->path) return;
- if (buffer->view_only) return;
+ if (!buffer_is_named_file(buffer)) return;
+ if (buffer_is_view_only(buffer)) return;
autocomplete_clear_phantom(ac);
const Settings *settings = buffer_settings(buffer);
bool regenerated = false;
@@ -542,7 +542,7 @@ void autocomplete_frame(Ted *ted) {
if (*word_at_cursor && str_has_prefix(ac->phantom, word_at_cursor)) {
const char *completion = ac->phantom + strlen(word_at_cursor);
if (*completion) {
- vec2 pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos);
+ vec2 pos = buffer_pos_to_pixels(buffer, buffer_cursor_pos(buffer));
#if 0
vec2 size = text_get_size_vec2(font, completion);
// this makes the text below the phantom less visible.
@@ -600,9 +600,9 @@ void autocomplete_frame(Ted *ted) {
menu_height = 200.f;
}
- vec2 cursor_pos = buffer_pos_to_pixels(buffer, buffer->cursor_pos);
- bool open_up = cursor_pos.y > 0.5f * (buffer->y1 + buffer->y2); // should the completion menu open upwards?
- bool open_left = cursor_pos.x > 0.5f * (buffer->x1 + buffer->x2);
+ vec2 cursor_pos = buffer_pos_to_pixels(buffer, buffer_cursor_pos(buffer));
+ bool open_up = cursor_pos.y > rect_ymid(buffer_rect(buffer)); // should the completion menu open upwards?
+ bool open_left = cursor_pos.x > rect_xmid(buffer_rect(buffer));
float x = cursor_pos.x, start_y = cursor_pos.y;
if (open_left) x -= menu_width;
if (open_up)
@@ -646,9 +646,9 @@ void autocomplete_frame(Ted *ted) {
// we've got some wacky calculations to figure out the
// bounding rect for the documentation
float doc_width = open_left ? ac->rect.pos.x - 2*padding
- : buffer->x2 - (ac->rect.pos.x + ac->rect.size.x + 2*padding);
+ : rect_x2(buffer_rect(buffer)) - (ac->rect.pos.x + ac->rect.size.x + 2*padding);
if (doc_width > 800) doc_width = 800;
- float doc_height = buffer->y2 - (ac->rect.pos.y + 2*padding);
+ float doc_height = rect_y2(buffer_rect(buffer)) - (ac->rect.pos.y + 2*padding);
if (doc_height > char_height * 20) doc_height = char_height * 20;
// if the rect is too small, there's no point in showing it
diff --git a/ide-rename-symbol.c b/ide-rename-symbol.c
index 344f401..cc8f176 100644
--- a/ide-rename-symbol.c
+++ b/ide-rename-symbol.c
@@ -25,7 +25,7 @@ void rename_symbol_at_cursor(Ted *ted, TextBuffer *buffer, const char *new_name)
// send the request
LSPRequest request = {.type = LSP_REQUEST_RENAME};
LSPRequestRename *data = &request.data.rename;
- data->position = buffer_pos_to_lsp_document_position(buffer, buffer->cursor_pos);
+ data->position = buffer_cursor_pos_as_lsp_document_position(buffer);
data->new_name = str_dup(new_name);
rs->request_id = lsp_send_request(lsp, &request);
}
@@ -46,7 +46,7 @@ static void rename_symbol_menu_open(Ted *ted) {
static void rename_symbol_menu_update(Ted *ted) {
TextBuffer *line_buffer = ted->line_buffer;
- if (line_buffer->line_buffer_submitted) {
+ if (line_buffer_is_submitted(line_buffer)) {
char *new_name = str32_to_utf8_cstr(buffer_get_line(line_buffer, 0));
rename_symbol_at_cursor(ted, ted->prev_active_buffer, new_name);
free(new_name);
@@ -71,7 +71,7 @@ static void rename_symbol_menu_render(Ted *ted) {
const float line_buffer_height = ted_line_buffer_height(ted);
u32 sym_start=0, sym_end=0;
- BufferPos cursor_pos = buffer->cursor_pos;
+ BufferPos cursor_pos = buffer_cursor_pos(buffer);
buffer_word_span_at_pos(buffer, cursor_pos, &sym_start, &sym_end);
BufferPos bpos0 = {
.line = cursor_pos.line,
@@ -149,10 +149,8 @@ void rename_symbol_process_lsp_response(Ted *ted, const LSPResponse *response) {
if (!ted_open_file(ted, path)) goto done;
TextBuffer *buffer = ted_get_buffer_with_file(ted, path);
- if (!buffer->will_chain_edits) {
- // chain all edits together so they can be undone with one ctrl+z
- buffer_start_edit_chain(buffer);
- }
+ // chain all edits together so they can be undone with one ctrl+z
+ buffer_start_edit_chain(buffer);
if (!buffer) {
// this should never happen since we just
diff --git a/ide-signature-help.c b/ide-signature-help.c
index ba6f216..5611c19 100644
--- a/ide-signature-help.c
+++ b/ide-signature-help.c
@@ -148,18 +148,19 @@ void signature_help_frame(Ted *ted) {
u32 *colors = settings->colors;
float border = settings->border_thickness;
- float width = buffer->x2 - buffer->x1;
+ Rect buf_rect = buffer_rect(buffer);
+ float width = buf_rect.size.x;
float height = FLT_MAX;
const float char_height = text_font_char_height(font);
// make sure signature help doesn't take up too much space
while (1) {
height = char_height * signature_count;
- if (height < (buffer->y2 - buffer->y1) * 0.25f)
+ if (height < buffer_rect(buffer).size.y * 0.25f)
break;
--signature_count;
if (signature_count == 0) return;
}
- float x = buffer->x1, y = buffer->y2 - height;
+ float x = buf_rect.pos.x, y = rect_y2(buf_rect) - height;
gl_geometry_rect(rect_xywh(x, y - border, width, border),
colors[COLOR_AUTOCOMPLETE_BORDER]);
gl_geometry_rect(rect_xywh(x, y, width, height),
@@ -173,8 +174,8 @@ void signature_help_frame(Ted *ted) {
state.y = y;
state.min_x = x;
state.min_y = y;
- state.max_x = buffer->x2;
- state.max_y = buffer->y2;
+ state.max_x = rect_x2(buf_rect);
+ state.max_y = rect_y2(buf_rect);
rgba_u32_to_floats(colors[COLOR_TEXT], state.color);
text_utf8_with_state(font, &state, signature->label_pre);
diff --git a/ide-usages.c b/ide-usages.c
index 435b7a2..4caa644 100644
--- a/ide-usages.c
+++ b/ide-usages.c
@@ -77,7 +77,7 @@ void usages_process_lsp_response(Ted *ted, const LSPResponse *response) {
char *line_text = NULL;
if (last_buffer) {
// read the line from the buffer
- if (line < last_buffer->nlines) {
+ if (line < buffer_line_count(last_buffer)) {
line_text = buffer_get_line_utf8(last_buffer, line);
}
} else if (last_file) {
@@ -122,7 +122,7 @@ void usages_process_lsp_response(Ted *ted, const LSPResponse *response) {
}
if (last_file)
fclose(last_file);
- buffer->view_only = true;
+ buffer_set_view_only(buffer, true);
// the build_dir doesn't really matter since we're using absolute paths
// but might as well set it to something reasonable.
diff --git a/main.c b/main.c
index ff41cc9..cdc0bb2 100644
--- a/main.c
+++ b/main.c
@@ -1,5 +1,6 @@
/*
TODO:
+- fix find
- public Node API
- public Selector/FileSelector API
@@ -798,7 +799,7 @@ int main(int argc, char **argv) {
TextBuffer *buffer = ted->active_buffer;
if (buffer) {
if (buffer_is_named_file(buffer)) {
- const char *buffer_path = buffer->path;
+ const char *buffer_path = buffer_get_path(buffer);
assert(*buffer_path);
char *last_sep = strrchr(buffer_path, PATH_SEPARATOR);
if (last_sep) {
diff --git a/menu.c b/menu.c
index c22f8f4..67b1fba 100644
--- a/menu.c
+++ b/menu.c
@@ -26,12 +26,7 @@ void menu_close(Ted *ted) {
}
ted_switch_to_buffer(ted, ted->prev_active_buffer);
- TextBuffer *buffer = ted->active_buffer;
ted->prev_active_buffer = NULL;
- if (buffer) {
- buffer->scroll_x = ted->prev_active_buffer_scroll.x;
- buffer->scroll_y = ted->prev_active_buffer_scroll.y;
- }
ted->menu_open_idx = 0;
ted->menu_context = NULL;
ted->selector_open = NULL;
@@ -62,9 +57,7 @@ void menu_open_with_context(Ted *ted, const char *menu_name, void *context) {
const MenuInfo *info = &ted->all_menus[menu_idx];
ted->menu_open_idx = menu_idx;
ted->menu_context = context;
- TextBuffer *prev_buf = ted->prev_active_buffer = ted->active_buffer;
- if (prev_buf)
- ted->prev_active_buffer_scroll = (dvec2) {prev_buf->scroll_x, prev_buf->scroll_y};
+ ted->prev_active_buffer = ted->active_buffer;
ted_switch_to_buffer(ted, NULL);
*ted->warn_overwrite = 0; // clear warn_overwrite
@@ -135,12 +128,18 @@ void menu_render(Ted *ted) {
info->render(ted);
}
+static void menu_edit_notify(void *context, TextBuffer *buffer, const EditInfo *info) {
+ (void)info;
+
+ Ted *ted = context;
+ if (buffer == ted->line_buffer && menu_is_open(ted, MENU_SHELL)) {
+ ted->shell_command_modified = true;
+ }
+
+}
+
void menu_shell_move(Ted *ted, int direction) {
TextBuffer *line_buffer = ted->line_buffer;
- if (line_buffer->modified) {
- // don't do it if the command has been edited
- return;
- }
i64 pos = ted->shell_history_pos;
pos += direction;
if (pos >= 0 && pos <= arr_len(ted->shell_history)) {
@@ -149,13 +148,13 @@ void menu_shell_move(Ted *ted, int direction) {
if (pos == arr_len(ted->shell_history)) {
// bottom of history; just clear line buffer
} else {
- line_buffer->store_undo_events = false;
+ buffer_set_undo_enabled(line_buffer, false);
buffer_insert_utf8_at_cursor(line_buffer, ted->shell_history[pos]);
- line_buffer->store_undo_events = true;
- line_buffer->modified = false;
+ buffer_set_undo_enabled(line_buffer, true);
+ ted->shell_command_modified = true;
}
// line_buffer->x/y1/2 are wrong (all 0), because of buffer_clear
- line_buffer->center_cursor_next_frame = true;
+ buffer_center_cursor_next_frame(line_buffer);
}
}
@@ -330,8 +329,6 @@ static void ask_reload_menu_update(Ted *ted) {
break;
case POPUP_NO:
menu_close(ted);
- if (buffer)
- buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->path));
break;
case POPUP_CANCEL: assert(0); break;
}
@@ -452,10 +449,10 @@ static void goto_line_menu_update(Ted *ted) {
TextBuffer *buffer = ted->prev_active_buffer;
if (*contents != '\0' && *end == '\0') {
if (line_number < 1) line_number = 1;
- if (line_number > (long)buffer->nlines) line_number = (long)buffer->nlines;
+ if (line_number > (long)buffer_line_count(buffer)) line_number = (long)buffer_line_count(buffer);
BufferPos pos = {(u32)line_number - 1, 0};
- if (line_buffer->line_buffer_submitted) {
+ if (line_buffer_is_submitted(line_buffer)) {
// let's go there!
menu_close(ted);
buffer_cursor_move_to_pos(buffer, pos);
@@ -465,7 +462,7 @@ static void goto_line_menu_update(Ted *ted) {
buffer_scroll_center_pos(buffer, pos);
}
}
- line_buffer->line_buffer_submitted = false;
+ line_buffer_clear_submitted(line_buffer);
free(contents);
}
@@ -506,13 +503,14 @@ static bool goto_line_menu_close(Ted *ted) {
static void shell_menu_open(Ted *ted) {
ted_switch_to_buffer(ted, ted->line_buffer);
ted->shell_history_pos = arr_len(ted->shell_history);
+ ted->shell_command_modified = false;
}
static void shell_menu_update(Ted *ted) {
TextBuffer *line_buffer = ted->line_buffer;
- if (line_buffer->line_buffer_submitted) {
+ if (line_buffer_is_submitted(line_buffer)) {
char *command = str32_to_utf8_cstr(buffer_get_line(line_buffer, 0));
- if (ted->shell_history_pos == arr_len(ted->shell_history) || line_buffer->modified) {
+ if (ted->shell_history_pos == arr_len(ted->shell_history) || ted->shell_command_modified) {
arr_add(ted->shell_history, command);
}
menu_close(ted);
@@ -562,6 +560,8 @@ void menu_init(Ted *ted) {
// dummy 0 entry so that nothing has index 0.
arr_add(ted->all_menus, (MenuInfo){0});
+ ted_add_edit_notify(ted, menu_edit_notify, ted);
+
MenuInfo save_as_menu = {
.open = save_as_menu_open,
.update = save_as_menu_update,
diff --git a/node.c b/node.c
index ccd9936..ae46a33 100644
--- a/node.c
+++ b/node.c
@@ -310,7 +310,7 @@ void node_frame(Ted *ted, Node *node, Rect r) {
{
if (buffer_unsaved_changes(buffer))
strbuf_printf(tab_title, "*%s*", filename);
- else if (buffer->view_only)
+ else if (buffer_is_view_only(buffer))
strbuf_printf(tab_title, "VIEW %s", filename);
else
strbuf_printf(tab_title, "%s", filename);
diff --git a/session.c b/session.c
index f84dd09..4176361 100644
--- a/session.c
+++ b/session.c
@@ -204,16 +204,18 @@ static Status session_read_node(Ted *ted, FILE *fp, Node *node) {
static void session_write_buffer(FILE *fp, TextBuffer *buffer) {
// some info about the buffer that should be restored
if (buffer_is_named_file(buffer))
- write_cstr(fp, buffer->path);
+ write_cstr(fp, buffer_get_path(buffer));
else
write_char(fp, 0);
- write_double(fp, buffer->scroll_x);
- write_double(fp, buffer->scroll_y);
- write_bool(fp, buffer->view_only);
- buffer_pos_write(buffer->cursor_pos, fp);
- write_bool(fp, buffer->selection);
- if (buffer->selection)
- buffer_pos_write(buffer->selection_pos, fp);
+ write_double(fp, buffer_get_scroll_columns(buffer));
+ write_double(fp, buffer_get_scroll_lines(buffer));
+ write_bool(fp, buffer_is_view_only(buffer));
+ buffer_pos_write(buffer_cursor_pos(buffer), fp);
+ BufferPos sel_pos = {0};
+ bool has_selection = buffer_selection_pos(buffer, &sel_pos);
+ write_bool(fp, has_selection);
+ if (has_selection)
+ buffer_pos_write(sel_pos, fp);
}
static bool session_read_buffer(Ted *ted, FILE *fp) {
@@ -227,19 +229,19 @@ static bool session_read_buffer(Ted *ted, FILE *fp) {
} else {
buffer_new_file(buffer, NULL);
}
- buffer->scroll_x = read_double(fp);
- buffer->scroll_y = read_double(fp);
- buffer->view_only = read_bool(fp);
- buffer->cursor_pos = buffer_pos_read(buffer, fp);
- buffer->selection = read_bool(fp);
- if (buffer->selection)
- buffer->selection_pos = buffer_pos_read(buffer, fp);
- buffer_pos_validate(buffer, &buffer->cursor_pos);
- buffer_pos_validate(buffer, &buffer->selection_pos);
- if (buffer->selection && buffer_pos_eq(buffer->cursor_pos, buffer->selection_pos)) {
- // this could happen if the file was changed on disk
- buffer->selection = false;
+ double scroll_x = read_double(fp);
+ double scroll_y = read_double(fp);
+ buffer_set_view_only(buffer, read_bool(fp));
+ BufferPos cursor_pos = buffer_pos_read(buffer, fp);
+ bool has_selection = read_bool(fp);
+ if (has_selection) {
+ buffer_cursor_move_to_pos(buffer, buffer_pos_read(buffer, fp));
+ buffer_select_to_pos(buffer, cursor_pos);
+ } else {
+ buffer_cursor_move_to_pos(buffer, cursor_pos);
}
+ buffer_scroll_to_pos(buffer, buffer_pos_start_of_file(buffer));
+ buffer_scroll(buffer, scroll_x, scroll_y);
}
return true;
}
diff --git a/tags.c b/tags.c
index fa87c49..5ada805 100644
--- a/tags.c
+++ b/tags.c
@@ -281,7 +281,7 @@ top:;
// the tags file gives us a (1-indexed) line number
BufferPos pos = {.line = (u32)line_number - 1, .index = 0};
buffer_cursor_move_to_pos(buffer, pos);
- buffer->center_cursor_next_frame = true;
+ buffer_center_cursor_next_frame(buffer);
success = true;
} else if (address[0] == '/') {
// the tags file gives us a pattern to look for
@@ -324,7 +324,7 @@ top:;
if (code) {
pcre2_match_data *match_data = pcre2_match_data_create(10, NULL);
if (match_data) {
- for (u32 line_idx = 0; line_idx < buffer->nlines; ++line_idx) {
+ for (u32 line_idx = 0, line_count = buffer_line_count(buffer); line_idx < line_count; ++line_idx) {
String32 line = buffer_get_line(buffer, line_idx);
int n = pcre2_match(code, line.str, line.len, 0, PCRE2_NOTEMPTY,
match_data, NULL);
@@ -334,7 +334,7 @@ top:;
PCRE2_SIZE index = ovector[0];
BufferPos pos = {line_idx, (u32)index};
buffer_cursor_move_to_pos(buffer, pos);
- buffer->center_cursor_next_frame = true;
+ buffer_center_cursor_next_frame(buffer);
success = true;
break;
}
diff --git a/ted-internal.h b/ted-internal.h
index c90499d..c986759 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -161,105 +161,16 @@ struct Settings {
KeyAction *key_actions;
};
-/// A single line in a buffer
-typedef struct Line Line;
-
/// This structure is used temporarily when loading settings
/// It's needed because we want more specific contexts to be dealt with last.
typedef struct ConfigPart ConfigPart;
-/// A single undoable edit to a buffer
-typedef struct BufferEdit BufferEdit;
-
typedef struct EditNotifyInfo {
EditNotify fn;
void *context;
EditNotifyID id;
} EditNotifyInfo;
-struct TextBuffer {
- /// NULL if this buffer is untitled or doesn't correspond to a file (e.g. line buffers)
- char *path;
- /// we keep a back-pointer to the ted instance so we don't have to pass it in to every buffer function
- Ted *ted;
- /// number of characters scrolled in the x direction (multiply by space width to get pixels)
- double scroll_x;
- /// number of characters scrolled in the y direction
- double scroll_y;
- /// last write time to \ref path
- double last_write_time;
- /// the language the buffer has been manually set to, or \ref LANG_NONE if it hasn't been set to anything
- i64 manual_language;
- /// position of cursor
- BufferPos cursor_pos;
- /// if \ref selection is true, the text between \ref selection_pos and \ref cursor_pos is selected.
- BufferPos selection_pos;
- /// "previous" position of cursor, for \ref CMD_PREVIOUS_POSITION
- BufferPos prev_cursor_pos;
- /// "line buffers" are buffers which can only have one line of text (used for inputs)
- bool is_line_buffer;
- /// is anything selected?
- bool selection;
- /// set to false to disable undo events
- bool store_undo_events;
- /// This is set to true whenever a change is made to the buffer, and never set to false by buffer_ functions.
- /// (Distinct from \ref buffer_unsaved_changes)
- bool modified;
- /// will the next undo event be chained with the ones after?
- bool will_chain_edits;
- /// will the next undo event be chained with the previous one?
- bool chaining_edits;
- /// view-only mode
- bool view_only;
- /// (line buffers only) set to true when submitted. you have to reset it to false.
- bool line_buffer_submitted;
- /// If set to true, buffer will be scrolled to the cursor position next frame.
- /// This is to fix the problem that \ref x1, \ref y1, \ref x2, \ref y2 are not updated until the buffer is rendered.
- bool center_cursor_next_frame;
- /// x coordinate of left side of buffer
- float x1;
- /// y coordinate of top side of buffer
- float y1;
- /// x coordinate of right side of buffer
- float x2;
- /// y coordinate of bottom side of buffer
- float y2;
- /// number of lines in buffer
- u32 nlines;
- /// capacity of \ref lines
- u32 lines_capacity;
-
- /// cached settings index (into ted->all_settings), or -1 if has not been computed yet
- i32 settings_idx;
-
- /// which LSP this document is open in
- LSPID lsp_opened_in;
- /// determining which LSP to use for a buffer takes some work,
- /// so we don't want to do it every single frame.
- /// this keeps track of the last time we actually checked what the correct LSP is.
- double last_lsp_check;
-
- /// where in the undo history was the last write? used by \ref buffer_unsaved_changes
- u32 undo_history_write_pos;
- /// which lines are on screen? updated when \ref buffer_render is called.
- u32 first_line_on_screen, last_line_on_screen;
-
- /// to cache syntax highlighting properly, it is important to keep track of the
- /// first and last line modified since last frame.
- u32 frame_earliest_line_modified;
- /// see \ref frame_earliest_line_modified.
- u32 frame_latest_line_modified;
-
- /// lines
- Line *lines;
- /// last error
- char error[256];
- /// dynamic array of undo history
- BufferEdit *undo_history;
- /// dynamic array of redo history
- BufferEdit *redo_history;
-};
-
/// an entry in a selector menu (e.g. the "open" menu)
typedef struct {
/// label
@@ -516,9 +427,6 @@ struct Ted {
/// build error we are currently "on"
u32 build_error;
- /// used by menus to keep track of the scroll position so we can return to it.
- dvec2 prev_active_buffer_scroll;
-
SDL_Cursor *cursor_arrow, *cursor_ibeam, *cursor_wait,
*cursor_resize_h, *cursor_resize_v, *cursor_hand, *cursor_move;
/// which cursor to use this frame
@@ -539,6 +447,8 @@ struct Ted {
char **shell_history;
/// for keeping track of where we are in the shell history.
u32 shell_history_pos;
+ /// has the shell command been modified (if so, we block up/down)
+ bool shell_command_modified;
// points to a selector if any is open, otherwise NULL.
Selector *selector_open;
@@ -628,6 +538,11 @@ void buffer_highlight_lsp_range(TextBuffer *buffer, LSPRange range, ColorSetting
/// process a mouse click.
/// returns true if the event was consumed.
bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times);
+/// next frame, scroll so that the cursor is in the center of the buffer's rectangle.
+///
+/// currently needed to avoid bad positioning when a buffer is created
+/// and buffer_center_cursor is called immediately after
+void buffer_center_cursor_next_frame(TextBuffer *buffer);
// === build.c ===
void build_frame(Ted *ted, float x1, float y1, float x2, float y2);
diff --git a/ted.c b/ted.c
index dcc2071..3dfe7ce 100644
--- a/ted.c
+++ b/ted.c
@@ -147,8 +147,9 @@ void ted_log(Ted *ted, const char *fmt, ...) {
void ted_error_from_buffer(Ted *ted, TextBuffer *buffer) {
- if (*buffer->error)
- ted_error(ted, "%s", buffer->error);
+ const char *err = buffer_get_error(buffer);
+ if (err)
+ ted_error(ted, "%s", err);
}
void ted_out_of_mem(Ted *ted) {
@@ -183,7 +184,7 @@ char *ted_get_root_dir_of(Ted *ted, const char *path) {
char *ted_get_root_dir(Ted *ted) {
TextBuffer *buffer = ted->active_buffer;
if (buffer && buffer_is_named_file(buffer)) {
- return ted_get_root_dir_of(ted, buffer->path);
+ return ted_get_root_dir_of(ted, buffer_get_path(buffer));
} else {
return ted_get_root_dir_of(ted, ted->cwd);
}
@@ -448,7 +449,7 @@ void ted_switch_to_buffer(Ted *ted, TextBuffer *buffer) {
autocomplete_close(ted);
if (buffer != search_buffer) {
if (ted->find)
- find_update(ted, true); // make sure find results are for this file
+ find_redo_search(ted); // make sure find results are for this file
}
if (ted_is_regular_buffer(ted, buffer)) {
@@ -568,7 +569,8 @@ TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path) {
arr_foreach_ptr(ted->buffers, TextBufferPtr, pbuffer) {
TextBuffer *buffer = *pbuffer;
- if (buffer->path && paths_eq(path, buffer->path)) {
+ const char *buf_path = buffer_get_path(buffer);
+ if (buf_path && paths_eq(path, buf_path)) {
return buffer;
}
}
@@ -594,7 +596,8 @@ bool ted_open_file(Ted *ted, const char *filename) {
// not open; we need to load it
u16 tab_idx;
TextBuffer *buffer = NULL;
- if (ted->active_buffer && !ted->active_buffer->path
+ if (ted->active_buffer
+ && !buffer_is_named_file(ted->active_buffer)
&& ted_is_regular_buffer(ted, ted->active_buffer)
&& buffer_empty(ted->active_buffer)) {
// the active buffer is just an empty untitled buffer. open it here.
@@ -643,7 +646,7 @@ bool ted_save_all(Ted *ted) {
arr_foreach_ptr(ted->buffers, TextBufferPtr, pbuffer) {
TextBuffer *buffer = *pbuffer;
if (buffer_unsaved_changes(buffer)) {
- if (!buffer->path) {
+ if (!buffer_is_named_file(buffer)) {
ted_switch_to_buffer(ted, buffer);
menu_open(ted, MENU_SAVE_AS);
success = false; // we haven't saved this buffer yet; we've just opened the "save as" menu.
@@ -764,7 +767,7 @@ void ted_go_to_lsp_document_position(Ted *ted, LSP *lsp, LSPDocumentPosition pos
TextBuffer *buffer = ted->active_buffer;
BufferPos pos = buffer_pos_from_lsp(buffer, position.pos);
buffer_cursor_move_to_pos(buffer, pos);
- buffer->center_cursor_next_frame = true;
+ buffer_center_cursor_next_frame(buffer);
} else {
ted_flash_error_cursor(ted);
}
diff --git a/ted.h b/ted.h
index a632d46..a670566 100644
--- a/ted.h
+++ b/ted.h
@@ -334,6 +334,8 @@ double buffer_get_scroll_lines(TextBuffer *buffer);
double buffer_last_write_time(TextBuffer *buffer);
/// get position of the cursor
BufferPos buffer_cursor_pos(TextBuffer *buffer);
+/// returns true if anything is selected
+bool buffer_has_selection(TextBuffer *buffer);
/// get position of non-cursor end of selection.
///
/// `pos` is allowed to be NULL.
@@ -347,6 +349,10 @@ const char *buffer_get_path(TextBuffer *buffer);
void buffer_clear_undo_redo(TextBuffer *buffer);
/// set whether undo history should be kept
void buffer_set_undo_enabled(TextBuffer *buffer, bool enabled);
+/// set manual language override for buffer.
+///
+/// passing `language = 0` goes back to automatic language detection.
+void buffer_set_manual_language(TextBuffer *buffer, u32 language);
/// first line which will appear on screen
u32 buffer_first_line_on_screen(TextBuffer *buffer);
/// last line which will appear on screen
@@ -361,6 +367,14 @@ const char *buffer_display_filename(TextBuffer *buffer);
bool buffer_is_named_file(TextBuffer *buffer);
/// does this buffer have unsaved changes?
bool buffer_unsaved_changes(TextBuffer *buffer);
+/// is this a line buffer?
+bool buffer_is_line_buffer(TextBuffer *buffer);
+/// has this line buffer been submitted?
+///
+/// returns false if `buffer` is not a line buffer.
+bool line_buffer_is_submitted(TextBuffer *buffer);
+/// clear submission status of line buffer.
+void line_buffer_clear_submitted(TextBuffer *buffer);
/// returns the character after position pos, or 0 if pos is invalid
char32_t buffer_char_at_pos(TextBuffer *buffer, BufferPos pos);
/// returns the character after the cursor
@@ -744,10 +758,8 @@ char *settings_get_root_dir(Settings *settings, const char *path);
// === find.c ===
/// which buffer will be searched?
TextBuffer *find_search_buffer(Ted *ted);
-/// update find results.
-///
-/// if `force` is true, the results will be updated even if the pattern & flags have not been changed.
-void find_update(Ted *ted, bool force);
+/// discard find results and perform search again.
+void find_redo_search(Ted *ted);
/// replace the match we are currently highlighting, or do nothing if there is no highlighted match
void find_replace(Ted *ted);
/// go to next find result
diff --git a/ui.c b/ui.c
index bca2614..b47694d 100644
--- a/ui.c
+++ b/ui.c
@@ -90,8 +90,8 @@ char *selector_update(Ted *ted, Selector *s) {
}
}
- if (line_buffer->line_buffer_submitted) {
- line_buffer->line_buffer_submitted = false;
+ if (line_buffer_is_submitted(line_buffer)) {
+ line_buffer_clear_submitted(line_buffer);
if (!ret) {
if (s->enable_cursor) {
// select this option