From 44d3e498a122052752ef965d22c292302e5e8e7d Mon Sep 17 00:00:00 2001 From: Patrick Cleavelin Date: Thu, 4 Jan 2024 22:31:15 -0600 Subject: [PATCH] always store absolute file paths don't re-open already loaded buffers --- src/core/core.odin | 2 ++ src/core/file_buffer.odin | 19 ++++++++++++++-- src/main.odin | 13 ++++++++++- src/ui/buffer_list_window.odin | 4 +++- src/ui/grep_window.odin | 41 +++++++++++++++++++++++++--------- 5 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/core/core.odin b/src/core/core.odin index 3eaa033..d8bf620 100644 --- a/src/core/core.odin +++ b/src/core/core.odin @@ -45,6 +45,8 @@ State :: struct { screen_width: int, font: raylib.Font, + directory: string, + source_font_width: int, source_font_height: int, line_number_padding: int, diff --git a/src/core/file_buffer.odin b/src/core/file_buffer.odin index 95a86bc..91eeea3 100644 --- a/src/core/file_buffer.odin +++ b/src/core/file_buffer.odin @@ -1,6 +1,7 @@ package core; import "core:os" +import "core:path/filepath" import "core:mem" import "core:fmt" import "core:math" @@ -45,6 +46,7 @@ Glyph :: struct #packed { FileBuffer :: struct { allocator: mem.Allocator, + directory: string, file_path: string, top_line: int, cursor: Cursor, @@ -561,7 +563,7 @@ new_virtual_file_buffer :: proc(allocator: mem.Allocator) -> FileBuffer { return buffer; } -new_file_buffer :: proc(allocator: mem.Allocator, file_path: string) -> (FileBuffer, Error) { +new_file_buffer :: proc(allocator: mem.Allocator, file_path: string, base_dir: string = "") -> (FileBuffer, Error) { context.allocator = allocator; fd, err := os.open(file_path); @@ -570,13 +572,26 @@ new_file_buffer :: proc(allocator: mem.Allocator, file_path: string) -> (FileBuf } defer os.close(fd); + fi, fstat_err := os.fstat(fd); + if fstat_err > 0 { + return FileBuffer{}, make_error(ErrorType.FileIOError, fmt.aprintf("failed to get file info: errno=%x", fstat_err)); + } + + dir: string; + if base_dir != "" { + dir = base_dir; + } else { + dir = filepath.dir(fi.fullpath); + } + if original_content, success := os.read_entire_file_from_handle(fd); success { width := 256; height := 256; buffer := FileBuffer { allocator = allocator, - file_path = file_path, + directory = dir, + file_path = fi.fullpath, original_content = slice.clone_to_dynamic(original_content), added_content = make([dynamic]u8, 0, 1024*1024), diff --git a/src/main.odin b/src/main.odin index a6ddd27..ebfdaa3 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1,6 +1,7 @@ package main import "core:os" +import "core:path/filepath" import "core:math" import "core:strings" import "core:runtime" @@ -190,12 +191,14 @@ main :: proc() { source_font_height = 16, input_map = core.new_input_map(), window = nil, + + directory = os.get_current_directory(), }; state.current_input_map = &state.input_map; register_default_input_actions(&state.input_map); for arg in os.args[1:] { - buffer, err := core.new_file_buffer(context.allocator, arg); + buffer, err := core.new_file_buffer(context.allocator, arg, state.directory); if err.type != .None { fmt.println("Failed to create file buffer:", err); continue; @@ -300,6 +303,14 @@ main :: proc() { theme.get_palette_raylib_color(.Background1)); } + relative_file_path, _ := filepath.rel(state.directory, buffer.file_path) + raylib.DrawTextEx( + state.font, + raylib.TextFormat("%s", relative_file_path), + raylib.Vector2 { 8 + 4 + 6 * f32(state.source_font_width), f32(state.screen_height - state.source_font_height) }, + f32(state.source_font_height), + 0, + theme.get_palette_raylib_color(.Foreground1)); raylib.DrawTextEx( state.font, line_info_text, diff --git a/src/ui/buffer_list_window.odin b/src/ui/buffer_list_window.odin index 12869c5..346c0fb 100644 --- a/src/ui/buffer_list_window.odin +++ b/src/ui/buffer_list_window.odin @@ -1,6 +1,7 @@ package ui; import "core:math" +import "core:path/filepath" import "vendor:raylib" import "../core" @@ -87,7 +88,8 @@ draw_buffer_list_window :: proc(win: ^core.Window, state: ^core.State) { for _, index in state.buffers { buffer := &state.buffers[index]; - text := raylib.TextFormat("%s:%d", buffer.file_path, buffer.cursor.line+1); + relative_file_path, _ := filepath.rel(state.directory, buffer.file_path) + text := raylib.TextFormat("%s:%d", relative_file_path, buffer.cursor.line+1); text_width := raylib.MeasureTextEx(state.font, text, f32(state.source_font_height), 0); if index == win.selected_buffer { diff --git a/src/ui/grep_window.odin b/src/ui/grep_window.odin index 5ced435..3f5c016 100644 --- a/src/ui/grep_window.odin +++ b/src/ui/grep_window.odin @@ -27,6 +27,8 @@ foreign rg { drop_match_array :: proc(match_array: ExternMatchArray) --- } +import "core:os" +import "core:path/filepath" import "core:math" import "core:fmt" import "core:runtime" @@ -50,7 +52,7 @@ transmute_extern_matches :: proc(extern_matches: ExternMatchArray, dest: ^[dynam path: string = ""; if match.path_ptr != nil && match.path_len > 0 { - path = strings.string_from_ptr(match.path_ptr, match.path_len); + path, _ = filepath.abs(strings.string_from_ptr(match.path_ptr, match.path_len)); } text: string = ""; @@ -88,14 +90,32 @@ create_grep_window :: proc() -> ^GrepWindow { win := cast(^GrepWindow)(state.window); if win.matches != nil && len(win.matches) > 0 { - buffer, err := core.new_file_buffer(context.allocator, strings.clone(win.matches[win.selected_match].path)); - if err.type != .None { - fmt.println("Failed to create file buffer:", err); - } else { - runtime.append(&state.buffers, buffer); - state.current_buffer = len(state.buffers)-1; + should_create_buffer := true; + for buffer, index in state.buffers { + if strings.compare(buffer.file_path, win.matches[win.selected_match].path) == 0 { + state.current_buffer = index; + should_create_buffer = false; + break; + } + } - buffer := &state.buffers[state.current_buffer]; + buffer: ^core.FileBuffer = nil; + err := core.no_error(); + + if should_create_buffer { + new_buffer, err := core.new_file_buffer(context.allocator, strings.clone(win.matches[win.selected_match].path)); + if err.type != .None { + fmt.println("Failed to open/create file buffer:", err); + } else { + runtime.append(&state.buffers, new_buffer); + state.current_buffer = len(state.buffers)-1; + buffer = &state.buffers[state.current_buffer]; + } + } else { + buffer = &state.buffers[state.current_buffer]; + } + + if buffer != nil { buffer.cursor.line = win.matches[win.selected_match].line-1; buffer.cursor.col = 0; buffer.glyph_buffer_height = math.min(256, int((state.screen_height - state.source_font_height*2) / state.source_font_height)) + 1; @@ -198,7 +218,7 @@ grep_files :: proc(win: ^core.Window, state: ^core.State) { } pattern := strings.clone_to_cstring(strings.to_string(builder)); - win.extern_matches = rg_search(pattern, "./src"); + win.extern_matches = rg_search(pattern, strings.clone_to_cstring(state.directory)); transmute_extern_matches(win.extern_matches, &win.matches); } @@ -241,7 +261,8 @@ draw_grep_window :: proc(win: ^core.Window, state: ^core.State) { show_line_numbers = false); for match, index in win.matches { - text := raylib.TextFormat("%s:%d:%d: %s", match.path, match.line, match.col, match.text); + relative_file_path, _ := filepath.rel(state.directory, match.path) + text := raylib.TextFormat("%s:%d:%d: %s", relative_file_path, match.line, match.col, match.text); text_width := raylib.MeasureTextEx(state.font, text, f32(state.source_font_height), 0); if index == win.selected_match {