summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-01-04 20:15:45 -0500
committerpommicket <pommicket@gmail.com>2023-01-04 20:15:55 -0500
commit808b9a13cb5c71c28db6c842b78ef7f1743283cd (patch)
tree1f57a266294c9fc99673981403361c2d5507d1ba
parentd9cc57e9ff1725e6e63973705adbf218d6961d17 (diff)
the great "filename to path" rename
-rw-r--r--buffer.c116
-rw-r--r--command.c7
-rw-r--r--ide-autocomplete.c7
-rw-r--r--main.c10
-rw-r--r--menu.c2
-rw-r--r--node.c3
-rw-r--r--session.c8
-rw-r--r--ted.c22
-rw-r--r--ted.h16
9 files changed, 108 insertions, 83 deletions
diff --git a/buffer.c b/buffer.c
index bcb8345..719c24e 100644
--- a/buffer.c
+++ b/buffer.c
@@ -4,7 +4,7 @@
#include "ted.h"
-
+#define BUFFER_UNTITLED "Untitled" // what to call untitled buffers
// this is a macro so we get -Wformat warnings
#define buffer_error(buffer, ...) \
@@ -60,15 +60,12 @@ bool buffer_empty(TextBuffer *buffer) {
return buffer->nlines == 1 && buffer->lines[0].len == 0;
}
-bool buffer_is_untitled(TextBuffer *buffer) {
- if (buffer->filename)
- return streq(buffer->filename, TED_UNTITLED);
- else
- return false;
+bool buffer_is_named_file(TextBuffer *buffer) {
+ return buffer->path != NULL;
}
-bool buffer_is_named_file(TextBuffer *buffer) {
- return buffer->filename && !buffer_is_untitled(buffer);
+const char *buffer_display_filename(TextBuffer *buffer) {
+ return buffer->path ? path_filename(buffer->path) : BUFFER_UNTITLED;
}
// add this edit to the undo history
@@ -170,7 +167,7 @@ bool buffer_pos_valid(TextBuffer *buffer, BufferPos p) {
// are there any unsaved changes?
bool buffer_unsaved_changes(TextBuffer *buffer) {
- if (buffer_is_untitled(buffer) && buffer_empty(buffer))
+ if (!buffer->path && buffer_empty(buffer))
return false; // don't worry about empty untitled buffers
return arr_len(buffer->undo_history) != buffer->undo_history_write_pos;
}
@@ -220,14 +217,15 @@ static Font *buffer_font(TextBuffer *buffer) {
// what programming language is this?
Language buffer_language(TextBuffer *buffer) {
+ if (!buffer->path)
+ return LANG_NONE;
+
// @TODO(optimization): cache this?
// (we're calling buffer_lsp on every edit and that calls this)
if (buffer->manual_language >= 1 && buffer->manual_language <= LANG_COUNT)
return (Language)(buffer->manual_language - 1);
const Settings *settings = buffer->ted->default_settings; // important we don't use buffer_settings here since that would cause a loop!
- const char *filename = buffer->filename;
- if (!filename)
- return LANG_NONE;
+ const char *filename = path_filename(buffer->path);
size_t filename_len = strlen(filename);
int match_score = 0;
@@ -257,11 +255,15 @@ Language buffer_language(TextBuffer *buffer) {
return match;
}
-// set filename = NULL to default to buffer->filename
-static void buffer_send_lsp_did_close(TextBuffer *buffer, LSP *lsp, const char *filename) {
+// set path = NULL to default to buffer->path
+static void buffer_send_lsp_did_close(TextBuffer *buffer, LSP *lsp, const char *path) {
+ if (path && !path_is_absolute(path)) {
+ assert(0);
+ return;
+ }
LSPRequest did_close = {.type = LSP_REQUEST_DID_CLOSE};
did_close.data.close = (LSPRequestDidClose){
- .document = lsp_document_id(lsp, filename ? filename : buffer->filename)
+ .document = lsp_document_id(lsp, path ? path : buffer->path)
};
lsp_send_request(lsp, &did_close);
buffer->lsp_opened_in = 0;
@@ -276,7 +278,7 @@ static void buffer_send_lsp_did_open(TextBuffer *buffer, LSP *lsp, char *buffer_
LSPRequest request = {.type = LSP_REQUEST_DID_OPEN};
LSPRequestDidOpen *open = &request.data.open;
open->file_contents = buffer_contents;
- open->document = lsp_document_id(lsp, buffer->filename);
+ open->document = lsp_document_id(lsp, buffer->path);
open->language = buffer_language(buffer);
lsp_send_request(lsp, &request);
buffer->lsp_opened_in = lsp->id;
@@ -289,7 +291,7 @@ LSP *buffer_lsp(TextBuffer *buffer) {
return NULL;
if (buffer->view_only)
return NULL; // we don't really want to start up an LSP in /usr/include
- LSP *true_lsp = ted_get_lsp(buffer->ted, buffer->filename, buffer_language(buffer));
+ LSP *true_lsp = ted_get_lsp(buffer->ted, buffer->path, buffer_language(buffer));
LSP *curr_lsp = ted_get_lsp_by_id(buffer->ted, buffer->lsp_opened_in);
if (true_lsp != curr_lsp) {
if (curr_lsp)
@@ -303,7 +305,7 @@ LSP *buffer_lsp(TextBuffer *buffer) {
Settings *buffer_settings(TextBuffer *buffer) {
- return ted_get_settings(buffer->ted, buffer->filename, buffer_language(buffer));
+ return ted_get_settings(buffer->ted, buffer->path, buffer_language(buffer));
}
@@ -723,7 +725,7 @@ void buffer_free(TextBuffer *buffer) {
buffer_line_free(&lines[i]);
}
free(lines);
- free(buffer->filename);
+ free(buffer->path);
arr_foreach_ptr(buffer->undo_history, BufferEdit, edit)
buffer_edit_free(edit);
@@ -1434,7 +1436,7 @@ static Status buffer_insert_lines(TextBuffer *buffer, u32 where, u32 number) {
LSPDocumentID buffer_lsp_document_id(TextBuffer *buffer) {
LSP *lsp = buffer_lsp(buffer);
- return lsp ? lsp_document_id(lsp, buffer->filename) : 0;
+ return lsp ? lsp_document_id(lsp, buffer->path) : 0;
}
// LSP uses UTF-16 indices because Microsoft fucking loves UTF-16 and won't let it die
@@ -1499,7 +1501,7 @@ static void buffer_send_lsp_did_change(LSP *lsp, TextBuffer *buffer, BufferPos p
event.range.start = buffer_pos_to_lsp_position(buffer, pos);
BufferPos pos_end = buffer_pos_advance(buffer, pos, nchars_deleted);
event.range.end = buffer_pos_to_lsp_position(buffer, pos_end);
- lsp_document_changed(lsp, buffer->filename, event);
+ lsp_document_changed(lsp, buffer->path, event);
}
// inserts the given text, returning the position of the end of the text
@@ -2322,8 +2324,8 @@ Status buffer_load_file(TextBuffer *buffer, const char *path) {
}
if (success) {
- char *filename_copy = buffer_strdup(buffer, path);
- if (!filename_copy) success = false;
+ char *path_copy = buffer_strdup(buffer, path);
+ if (!path_copy) success = false;
if (success) {
// everything is good
buffer_clear(buffer);
@@ -2332,7 +2334,7 @@ Status buffer_load_file(TextBuffer *buffer, const char *path) {
buffer->frame_earliest_line_modified = 0;
buffer->frame_latest_line_modified = nlines - 1;
buffer->lines_capacity = lines_capacity;
- buffer->filename = filename_copy;
+ buffer->path = path_copy;
buffer->last_write_time = modified_time;
if (!(fs_path_permission(path) & FS_PERMISSION_WRITE)) {
// can't write to this file; make the buffer view only.
@@ -2363,12 +2365,12 @@ Status buffer_load_file(TextBuffer *buffer, const char *path) {
// Reloads the file loaded in the buffer.
// Note that this clears undo history, etc.
void buffer_reload(TextBuffer *buffer) {
- if (buffer->filename && !buffer_is_untitled(buffer)) {
+ if (buffer_is_named_file(buffer)) {
BufferPos cursor_pos = buffer->cursor_pos;
float x1 = buffer->x1, y1 = buffer->y1, x2 = buffer->x2, y2 = buffer->y2;
double scroll_x = buffer->scroll_x; double scroll_y = buffer->scroll_y;
- char *filename = str_dup(buffer->filename);
- if (buffer_load_file(buffer, filename)) {
+ char *path = str_dup(buffer->path);
+ if (buffer_load_file(buffer, path)) {
buffer->x1 = x1; buffer->y1 = y1; buffer->x2 = x2; buffer->y2 = y2;
buffer->cursor_pos = cursor_pos;
buffer->scroll_x = scroll_x;
@@ -2376,7 +2378,7 @@ void buffer_reload(TextBuffer *buffer) {
buffer_validate_cursor(buffer);
buffer_correct_scroll(buffer);
}
- free(filename);
+ free(path);
}
}
@@ -2384,31 +2386,34 @@ void buffer_reload(TextBuffer *buffer) {
bool buffer_externally_changed(TextBuffer *buffer) {
if (!buffer_is_named_file(buffer))
return false;
- return buffer->last_write_time != timespec_to_seconds(time_last_modified(buffer->filename));
+ return buffer->last_write_time != timespec_to_seconds(time_last_modified(buffer->path));
}
-void buffer_new_file(TextBuffer *buffer, const char *filename) {
+void buffer_new_file(TextBuffer *buffer, const char *path) {
+ if (path && !path_is_absolute(path)) {
+ buffer_error(buffer, "Cannot create %s: path is not absolute", path);
+ return;
+ }
+
buffer_clear(buffer);
- if (filename)
- buffer->filename = buffer_strdup(buffer, filename);
+ if (path)
+ buffer->path = buffer_strdup(buffer, path);
buffer->lines_capacity = 4;
buffer->lines = buffer_calloc(buffer, buffer->lines_capacity, sizeof *buffer->lines);
buffer->nlines = 1;
}
-// Save the buffer to its current filename. This will rewrite the entire file, regardless of
-// whether there are any unsaved changes.
bool buffer_save(TextBuffer *buffer) {
const Settings *settings = buffer_settings(buffer);
- if (!buffer->is_line_buffer && buffer->filename) {
+ if (buffer_is_named_file(buffer)) {
if (buffer->view_only) {
buffer_error(buffer, "Can't save view-only file.");
return false;
}
- FILE *out = fopen(buffer->filename, "wb");
+ FILE *out = fopen(buffer->path, "wb");
if (out) {
if (settings->auto_add_newline) {
Line *last_line = &buffer->lines[buffer->nlines - 1];
@@ -2427,7 +2432,7 @@ bool buffer_save(TextBuffer *buffer) {
size_t bytes = unicode_utf32_to_utf8(utf8, *p);
if (bytes != (size_t)-1) {
if (fwrite(utf8, 1, bytes, out) != bytes) {
- buffer_error(buffer, "Couldn't write to %s.", buffer->filename);
+ buffer_error(buffer, "Couldn't write to %s.", buffer->path);
}
}
}
@@ -2438,24 +2443,24 @@ bool buffer_save(TextBuffer *buffer) {
}
if (ferror(out)) {
if (!buffer_has_error(buffer))
- buffer_error(buffer, "Couldn't write to %s.", buffer->filename);
+ buffer_error(buffer, "Couldn't write to %s.", buffer->path);
}
if (fclose(out) != 0) {
if (!buffer_has_error(buffer))
- buffer_error(buffer, "Couldn't close file %s.", buffer->filename);
+ buffer_error(buffer, "Couldn't close file %s.", buffer->path);
}
- buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->filename));
+ buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->path));
bool success = !buffer_has_error(buffer);
if (success) {
buffer->undo_history_write_pos = arr_len(buffer->undo_history);
- const char *name = buffer->filename ? path_filename(buffer->filename) : TED_UNTITLED;
- if (streq(name, "ted.cfg") && buffer_settings(buffer)->auto_reload_config) {
+ if (buffer->path && streq(path_filename(buffer->path), "ted.cfg")
+ && buffer_settings(buffer)->auto_reload_config) {
ted_load_configs(buffer->ted, true);
}
}
return success;
} else {
- buffer_error(buffer, "Couldn't open file %s for writing: %s.", buffer->filename, strerror(errno));
+ buffer_error(buffer, "Couldn't open file %s for writing: %s.", buffer->path, strerror(errno));
return false;
}
} else {
@@ -2464,26 +2469,31 @@ bool buffer_save(TextBuffer *buffer) {
}
}
-// save, but with a different file name
-bool buffer_save_as(TextBuffer *buffer, const char *new_filename) {
+bool buffer_save_as(TextBuffer *buffer, const char *new_path) {
+ if (!path_is_absolute(new_path)) {
+ assert(0);
+ buffer_error(buffer, "New path %s is not absolute.", new_path);
+ return false;
+ }
+
LSP *lsp = buffer_lsp(buffer);
- char *prev_filename = buffer->filename;
- buffer->filename = buffer_strdup(buffer, new_filename);
+ char *prev_path = buffer->path;
+ buffer->path = buffer_strdup(buffer, new_path);
- if (buffer->filename && buffer_save(buffer)) {
+ if (buffer->path && buffer_save(buffer)) {
buffer->view_only = false;
- // ensure whole file is syntax highlighted when saving with a different
+ // ensure whole file is re-highlighted when saving with a different
// file extension
buffer->frame_earliest_line_modified = 0;
buffer->frame_latest_line_modified = buffer->nlines - 1;
if (lsp)
- buffer_send_lsp_did_close(buffer, lsp, prev_filename);
+ buffer_send_lsp_did_close(buffer, lsp, prev_path);
// we'll send a didOpen the next time buffer_lsp is called.
- free(prev_filename);
+ free(prev_path);
return true;
} else {
- free(buffer->filename);
- buffer->filename = prev_filename;
+ free(buffer->path);
+ buffer->path = prev_path;
return false;
}
}
diff --git a/command.c b/command.c
index ff1bc3f..bf76b74 100644
--- a/command.c
+++ b/command.c
@@ -341,7 +341,7 @@ void command_execute(Ted *ted, Command c, i64 argument) {
case CMD_SAVE:
ted->last_save_time = ted->frame_time;
if (buffer) {
- if (buffer_is_untitled(buffer)) {
+ if (!buffer->path) {
command_execute(ted, CMD_SAVE_AS, 1);
return;
}
@@ -374,7 +374,8 @@ void command_execute(Ted *ted, Command c, i64 argument) {
if (buffers_used[i]) {
buffer = &ted->buffers[i];
if (buffer_unsaved_changes(buffer)) {
- strbuf_catf(ted->warn_unsaved_names, "%s%s", first ? "" : ", ", path_filename(buffer->filename));
+ const char *path = buffer_display_filename(buffer);
+ strbuf_catf(ted->warn_unsaved_names, "%s%s", first ? "" : ", ", path);
first = false;
}
}
@@ -484,7 +485,7 @@ void command_execute(Ted *ted, Command c, i64 argument) {
if (argument != 2 && buffer_unsaved_changes(buffer)) {
// there are unsaved changes!
ted->warn_unsaved = CMD_TAB_CLOSE;
- strbuf_printf(ted->warn_unsaved_names, "%s", path_filename(buffer->filename));
+ strbuf_printf(ted->warn_unsaved_names, "%s", buffer_display_filename(buffer));
menu_open(ted, MENU_WARN_UNSAVED);
} else {
node_tab_close(ted, node, node->active_tab);
diff --git a/ide-autocomplete.c b/ide-autocomplete.c
index 39ee076..9f70758 100644
--- a/ide-autocomplete.c
+++ b/ide-autocomplete.c
@@ -112,6 +112,9 @@ static void autocomplete_no_suggestions(Ted *ted) {
}
static void autocomplete_send_completion_request(Ted *ted, TextBuffer *buffer, BufferPos pos, uint32_t trigger) {
+ if (!buffer->path)
+ return; // no can do
+
LSP *lsp = buffer_lsp(buffer);
Autocomplete *ac = &ted->autocomplete;
@@ -129,7 +132,7 @@ static void autocomplete_send_completion_request(Ted *ted, TextBuffer *buffer, B
request.data.completion = (LSPRequestCompletion) {
.position = {
- .document = lsp_document_id(lsp, buffer->filename),
+ .document = lsp_document_id(lsp, buffer->path),
.pos = buffer_pos_to_lsp_position(buffer, pos)
},
.context = {
@@ -295,7 +298,7 @@ void autocomplete_open(Ted *ted, uint32_t trigger) {
if (ac->open) return;
if (!ted->active_buffer) return;
TextBuffer *buffer = ted->active_buffer;
- if (!buffer->filename) return;
+ if (!buffer->path) return;
if (buffer->view_only) return;
ted->cursor_error_time = 0;
diff --git a/main.c b/main.c
index 7a9b507..29223d4 100644
--- a/main.c
+++ b/main.c
@@ -17,15 +17,17 @@
- some way of opening + closing all C files in directory for clangd
textDocument/references to work?
- maybe it can be done with the clangd config instead.
+ - does vscode have the same problem?
- more documentation generally (development.md or something?)
-- rename buffer->filename to buffer->path
- - make buffer->path NULL for untitled buffers & fix resulting mess
- rust-analyzer bug reports:
- bad json can give "Unexpected error: client exited without proper shutdown sequence"
- containerName not always given
- clangd bug report:
- textDocumemt/definition on ted.h declarations just gives you the declaration
FUTURE FEATURES:
+- write first to <path>.tmp then rename to <path>.
+ this prevents freak occurences, e.g. power outage during file write,
+ from losing (all) data.
- better handling of backspace with space indentation
- CSS highlighting
- styles ([color] sections)
@@ -770,7 +772,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->filename;
+ const char *buffer_path = buffer->path;
assert(*buffer_path);
char *last_sep = strrchr(buffer_path, PATH_SEPARATOR);
if (last_sep) {
@@ -791,7 +793,7 @@ int main(int argc, char **argv) {
if (buffer_settings(active_buffer)->auto_reload)
buffer_reload(active_buffer);
else {
- strbuf_cpy(ted->ask_reload, active_buffer->filename);
+ strbuf_cpy(ted->ask_reload, buffer_display_filename(active_buffer));
menu_open(ted, MENU_ASK_RELOAD);
}
}
diff --git a/menu.c b/menu.c
index 84e58ca..ae024b2 100644
--- a/menu.c
+++ b/menu.c
@@ -199,7 +199,7 @@ void menu_update(Ted *ted) {
case POPUP_NO:
menu_close(ted);
if (buffer)
- buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->filename));
+ buffer->last_write_time = timespec_to_seconds(time_last_modified(buffer->path));
break;
case POPUP_CANCEL: assert(0); break;
}
diff --git a/node.c b/node.c
index 0eb529a..29f08b9 100644
--- a/node.c
+++ b/node.c
@@ -293,8 +293,7 @@ void node_frame(Ted *ted, Node *node, Rect r) {
for (u16 i = 0; i < ntabs; ++i) {
TextBuffer *buffer = &ted->buffers[node->tabs[i]];
char tab_title[256];
- const char *path = buffer->filename;
- const char *filename = path ? path_filename(path) : TED_UNTITLED;
+ const char *filename = buffer_display_filename(buffer);
Rect tab_rect = rect(Vec2(r.pos.x + tab_width * i, r.pos.y), Vec2(tab_width, tab_bar_height));
if (i > 0) {
diff --git a/session.c b/session.c
index 4d01fe9..a4c7744 100644
--- a/session.c
+++ b/session.c
@@ -206,8 +206,8 @@ static void session_write_buffer(Ted *ted, FILE *fp, u16 buffer_idx) {
write_u16(fp, buffer_idx);
TextBuffer *buffer = &ted->buffers[buffer_idx];
// some info about the buffer that should be restored
- if (buffer->filename && !buffer_is_untitled(buffer))
- write_cstr(fp, buffer->filename);
+ if (buffer_is_named_file(buffer))
+ write_cstr(fp, buffer->path);
else
write_char(fp, 0);
write_double(fp, buffer->scroll_x);
@@ -233,9 +233,9 @@ static void session_read_buffer(Ted *ted, FILE *fp) {
if (!buffer_has_error(buffer)) {
if (*filename) {
if (!buffer_load_file(buffer, filename))
- buffer_new_file(buffer, TED_UNTITLED);
+ buffer_new_file(buffer, NULL);
} else {
- buffer_new_file(buffer, TED_UNTITLED);
+ buffer_new_file(buffer, NULL);
}
buffer->scroll_x = read_double(fp);
buffer->scroll_y = read_double(fp);
diff --git a/ted.c b/ted.c
index ea585b9..987193e 100644
--- a/ted.c
+++ b/ted.c
@@ -110,7 +110,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) {
- return ted_get_root_dir_of(ted, buffer->filename);
+ return ted_get_root_dir_of(ted, buffer->path);
} else {
return ted_get_root_dir_of(ted, ted->cwd);
}
@@ -407,11 +407,13 @@ static Status ted_open_buffer(Ted *ted, u16 *buffer_idx, u16 *tab) {
}
TextBuffer *ted_get_buffer_with_file(Ted *ted, const char *path) {
+ if (!path) return NULL;
+
bool *buffers_used = ted->buffers_used;
TextBuffer *buffers = ted->buffers;
for (u16 i = 0; i < TED_MAX_BUFFERS; ++i) {
if (buffers_used[i]) {
- if (buffers[i].filename && paths_eq(path, buffers[i].filename)) {
+ if (buffers[i].path && paths_eq(path, buffers[i].path)) {
return &buffers[i];
}
}
@@ -432,7 +434,7 @@ bool ted_open_file(Ted *ted, const char *filename) {
// not open; we need to load it
u16 buffer_idx, tab_idx;
- if (ted->active_buffer && buffer_is_untitled(ted->active_buffer) && buffer_empty(ted->active_buffer)) {
+ if (ted->active_buffer && !ted->active_buffer->path && buffer_empty(ted->active_buffer)) {
// the active buffer is just an empty untitled buffer. open it here.
return buffer_load_file(ted->active_buffer, path);
} else if (ted_open_buffer(ted, &buffer_idx, &tab_idx)) {
@@ -456,10 +458,14 @@ bool ted_new_file(Ted *ted, const char *filename) {
if (filename)
ted_path_full(ted, filename, path, sizeof path);
else
- strbuf_cpy(path, TED_UNTITLED);
- if (ted_open_buffer(ted, &buffer_idx, &tab_idx)) {
- TextBuffer *buffer = &ted->buffers[buffer_idx];
- buffer_new_file(buffer, path);
+ *path = '\0';
+ TextBuffer *buffer = ted_get_buffer_with_file(ted, path);
+ if (buffer) {
+ ted_switch_to_buffer(ted, buffer);
+ return true;
+ } else if (ted_open_buffer(ted, &buffer_idx, &tab_idx)) {
+ buffer = &ted->buffers[buffer_idx];
+ buffer_new_file(buffer, *path ? path : NULL);
if (!buffer_has_error(buffer)) {
return true;
} else {
@@ -481,7 +487,7 @@ bool ted_save_all(Ted *ted) {
if (buffers_used[i]) {
TextBuffer *buffer = &ted->buffers[i];
if (buffer_unsaved_changes(buffer)) {
- if (buffer->filename && buffer_is_untitled(buffer)) {
+ if (!buffer->path) {
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.
diff --git a/ted.h b/ted.h
index 7793f14..3c137db 100644
--- a/ted.h
+++ b/ted.h
@@ -19,7 +19,6 @@
#define TED_VERSION "2.0"
#define TED_VERSION_FULL "ted v. " TED_VERSION
#define TED_PATH_MAX 256
-#define TED_UNTITLED "Untitled" // what to call untitled buffers
#define TED_CFG "ted.cfg" // config filename
#define TEXT_SIZE_MIN 6
@@ -255,10 +254,10 @@ typedef struct {
// a buffer - this includes line buffers, unnamed buffers, the build buffer, etc.
typedef struct {
- char *filename; // NULL if this buffer doesn't correspond to a file (e.g. line buffers)
+ char *path; // NULL if this buffer is untitled or 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
- double last_write_time; // last write time to filename.
+ double last_write_time; // last write time to `path`.
i16 manual_language; // 1 + the language the buffer has been manually set to, or 0 if it hasn't been manually set to anything
BufferPos cursor_pos;
BufferPos selection_pos; // if selection is true, the text between selection_pos and cursor_pos is selected.
@@ -669,8 +668,8 @@ void buffer_clear_error(TextBuffer *buffer);
void buffer_clear_undo_redo(TextBuffer *buffer);
// is this buffer empty?
bool buffer_empty(TextBuffer *buffer);
-// is this buffer normal (i.e. not a line buffer or build buffer), but untitled?
-bool buffer_is_untitled(TextBuffer *buffer);
+// returns the buffer's filename (not full path), or "Untitled" if this buffer is untitled.
+const char *buffer_display_filename(TextBuffer *buffer);
// does this buffer contained a named file (i.e. not a line buffer, not the build buffer, not untitled)
bool buffer_is_named_file(TextBuffer *buffer);
// create a new empty buffer with no file name
@@ -928,8 +927,13 @@ void buffer_paste(TextBuffer *buffer);
bool buffer_load_file(TextBuffer *buffer, const char *path);
void buffer_reload(TextBuffer *buffer);
bool buffer_externally_changed(TextBuffer *buffer);
-void buffer_new_file(TextBuffer *buffer, const char *filename);
+// Clear `buffer`, and set its path to `path`.
+// if `path` is NULL, this will turn `buffer` into an untitled buffer.
+void buffer_new_file(TextBuffer *buffer, const char *path);
+// Save the buffer to its current filename. This will rewrite the entire file,
+// even if there are no unsaved changes.
bool buffer_save(TextBuffer *buffer);
+// save, but with a different path
bool buffer_save_as(TextBuffer *buffer, const char *new_filename);
u32 buffer_first_rendered_line(TextBuffer *buffer);
u32 buffer_last_rendered_line(TextBuffer *buffer);