summaryrefslogtreecommitdiff
path: root/buffer.c
diff options
context:
space:
mode:
Diffstat (limited to 'buffer.c')
-rw-r--r--buffer.c116
1 files changed, 63 insertions, 53 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;
}
}