From 8cfcfb6309c0399c3e5e491695086d4723bfbc72 Mon Sep 17 00:00:00 2001 From: pommicket Date: Sun, 27 Aug 2023 19:30:07 -0400 Subject: disambiguate between files with the same name --- buffer.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++---- command.c | 7 ++++--- main.c | 2 +- node.c | 12 ++++++++++-- ted.h | 7 +++++-- 5 files changed, 70 insertions(+), 12 deletions(-) diff --git a/buffer.c b/buffer.c index 7ad8921..94cebff 100644 --- a/buffer.c +++ b/buffer.c @@ -6,8 +6,6 @@ #include -#define BUFFER_UNTITLED "Untitled" // what to call untitled buffers - /// A single line in a buffer typedef struct Line Line; @@ -252,8 +250,56 @@ const char *buffer_get_path(TextBuffer *buffer) { return buffer->path; } -const char *buffer_display_filename(TextBuffer *buffer) { - return buffer->path ? path_filename(buffer->path) : BUFFER_UNTITLED; +void buffer_display_filename(TextBuffer *buffer, char *filename, size_t filename_size) { + if (!buffer->path) { + str_cpy(filename, filename_size, "Untitled"); + return; + } + + // this stuff here is to disambiguate between files, so if you have + // two files open called + // /foo/bar/x/a.c + // and /abc/def/x/a.c + // their display names will be "bar/x/a.c" and "def/x/a.c" + + int suffix_needed = 0; + Ted *ted = buffer->ted; + int buffer_path_len = (int)strlen(buffer->path); + arr_foreach_ptr(ted->buffers, const TextBufferPtr, p_other) { + TextBuffer *other = *p_other; + if (!other->path) continue; + if (streq(other->path, buffer->path)) continue; + + int other_path_len = (int)strlen(other->path); + if (str_has_suffix(buffer->path, other->path)) { + // special case + suffix_needed = other_path_len + 1; + continue; + } + + // find longest common suffix of buffer->path, other->path + for (int i = 1; i <= buffer_path_len && i <= other_path_len; ++i) { + if (i > suffix_needed) + suffix_needed = i; + if (buffer->path[buffer_path_len - i] != other->path[other_path_len - i]) { + break; + } + } + } + + // go to last path separator + while (suffix_needed < buffer_path_len && + buffer->path[buffer_path_len - suffix_needed] != PATH_SEPARATOR) { + ++suffix_needed; + } + + // don't actually include the path separator + if (suffix_needed > 0) + --suffix_needed; + + assert(suffix_needed > 0 && suffix_needed <= buffer_path_len); + + str_cpy(filename, filename_size, &buffer->path[buffer_path_len - suffix_needed]); } // add this edit to the undo history diff --git a/command.c b/command.c index b6b5324..07d3856 100644 --- a/command.c +++ b/command.c @@ -452,8 +452,9 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen arr_foreach_ptr(ted->buffers, TextBufferPtr, pbuffer) { buffer = *pbuffer; if (buffer_unsaved_changes(buffer)) { - const char *path = buffer_display_filename(buffer); - strbuf_catf(ted->warn_unsaved_names, "%s%s", first ? "" : ", ", path); + char name[TED_PATH_MAX]; + buffer_display_filename(buffer, name, sizeof name); + strbuf_catf(ted->warn_unsaved_names, "%s%s", first ? "" : ", ", name); first = false; } } @@ -579,7 +580,7 @@ void command_execute_ex(Ted *ted, Command c, const CommandArgument *full_argumen if (argument != 2 && buffer_unsaved_changes(buffer)) { // there are unsaved changes! ted->warn_unsaved = CMD_TAB_CLOSE; - strbuf_printf(ted->warn_unsaved_names, "%s", buffer_display_filename(buffer)); + buffer_display_filename(buffer, ted->warn_unsaved_names, sizeof ted->warn_unsaved_names); menu_open(ted, MENU_WARN_UNSAVED); } else { node_tab_close(ted, node, tab_idx); diff --git a/main.c b/main.c index 642639e..86d3b86 100644 --- a/main.c +++ b/main.c @@ -818,7 +818,7 @@ int main(int argc, char **argv) { if (buffer_settings(active_buffer)->auto_reload) buffer_reload(active_buffer); else { - strbuf_cpy(ted->ask_reload, buffer_display_filename(active_buffer)); + buffer_display_filename(active_buffer, ted->ask_reload, sizeof ted->ask_reload); menu_open(ted, MENU_ASK_RELOAD); } } diff --git a/node.c b/node.c index 3d8d4b4..ee99883 100644 --- a/node.c +++ b/node.c @@ -371,7 +371,8 @@ void node_frame(Ted *ted, Node *node, Rect r) { for (u16 i = 0; i < ntabs; ++i) { TextBuffer *buffer = node->tabs[i]; char tab_title[256]; - const char *filename = buffer_display_filename(buffer); + char filename[TED_PATH_MAX]; + buffer_display_filename(buffer, filename, sizeof filename); Rect tab_rect = rect_xywh(r.pos.x + tab_width * i, r.pos.y, tab_width, tab_bar_height); if (i > 0) { @@ -398,9 +399,16 @@ void node_frame(Ted *ted, Node *node, Rect r) { else strbuf_printf(tab_title, "%s", filename); } + float title_width = text_get_size_vec2(font, tab_title).x; + float title_xpos = tab_rect.pos.x; + if (title_width > tab_rect.size.x) { + // full tab title doesn't fit in tab -- only show the right end of it + title_xpos = tab_rect.pos.x + tab_rect.size.x - title_width; + } + text_state.min_x = rect_x1(tab_rect); text_state.max_x = rect_x2(tab_rect); settings_color_floats(settings, COLOR_TEXT, text_state.color); - text_state.x = tab_rect.pos.x; + text_state.x = title_xpos; text_state.y = tab_rect.pos.y; text_state_break_kerning(&text_state); text_utf8_with_state(font, &text_state, tab_title); diff --git a/ted.h b/ted.h index 77f556b..d35fd74 100644 --- a/ted.h +++ b/ted.h @@ -386,8 +386,11 @@ u32 buffer_last_line_on_screen(TextBuffer *buffer); Rect buffer_rect(TextBuffer *buffer); /// is this buffer empty? bool buffer_empty(TextBuffer *buffer); -/// returns the buffer's filename (not full path), or "Untitled" if this buffer is untitled. -const char *buffer_display_filename(TextBuffer *buffer); +/// returns the buffer's display filename (not full path) into `filename` +/// +/// if the buffer is an untitled buffer, returns "Untitled". +/// `filename` is guaranteed to be null-terminated after calling this. +void buffer_display_filename(TextBuffer *buffer, char *filename, size_t filename_size); /// 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); /// does this buffer have unsaved changes? -- cgit v1.2.3