actually load files, port scrolling

plugins
Patrick Cleavelin 2023-12-22 23:19:08 -06:00
parent fdd9f35323
commit c74fa02e7b
1 changed files with 111 additions and 26 deletions

View File

@ -1,13 +1,48 @@
package main package main
import "core:os"
import "core:runtime"
import "core:fmt" import "core:fmt"
import "core:mem" import "core:mem"
import "core:slice"
import "vendor:raylib" import "vendor:raylib"
source_font_width :: 8; source_font_width :: 8;
source_font_height :: 16; source_font_height :: 16;
line_number_padding :: 4 * source_font_width; line_number_padding :: 4 * source_font_width;
ErrorType :: enum {
None,
FileIOError,
}
Error :: struct {
type: ErrorType,
loc: runtime.Source_Code_Location,
msg: string,
}
make_error :: proc(type: ErrorType, msg: string, loc := #caller_location) -> Error {
return Error {
type = type,
loc = loc,
msg = msg
}
}
no_error :: proc() -> Error {
return Error {
type = .None,
}
}
error :: proc{make_error, no_error};
ScrollDir :: enum {
Up,
Down,
}
ContentType :: enum { ContentType :: enum {
Original, Original,
Added, Added,
@ -77,37 +112,46 @@ iterate_file_buffer :: proc(it: ^FileBufferIter) -> (character: u8, idx: FileBuf
return; return;
} }
new_file_buffer :: proc(allocator: mem.Allocator, file_path: string) -> FileBuffer { new_file_buffer :: proc(allocator: mem.Allocator, file_path: string) -> (FileBuffer, Error) {
context.allocator = allocator; context.allocator = allocator;
width := 80; fd, err := os.open(file_path);
height := 24; if err != os.ERROR_NONE {
return FileBuffer{}, make_error(ErrorType.FileIOError, fmt.aprintf("failed to open file: errno=%x", err));
}
defer os.close(fd);
test_str := "This is a test string\nfor a file buffer\nThis is line 3\nThis is line 4\n\n\nThis is line 7 (with some gaps between 4)"; if original_content, success := os.read_entire_file_from_handle(fd); success {
width := 256;
height := 50;
buffer := FileBuffer { buffer := FileBuffer {
allocator = allocator, allocator = allocator,
file_path = file_path, file_path = file_path,
original_content = make([dynamic]u8, 0, len(test_str)), original_content = slice.clone_to_dynamic(original_content),
added_content = make([dynamic]u8, 0, 1024*1024), added_content = make([dynamic]u8, 0, 1024*1024),
content_slices = make([dynamic]ContentSlice, 0, 1024*1024), content_slices = make([dynamic]ContentSlice, 0, 1024*1024),
glyph_buffer_width = width, glyph_buffer_width = width,
glyph_buffer_height = height, glyph_buffer_height = height,
glyph_buffer = make([dynamic]Glyph, width*height, width*height), glyph_buffer = make([dynamic]Glyph, width*height, width*height),
input_buffer = make([dynamic]u8, 0, 1024), input_buffer = make([dynamic]u8, 0, 1024),
}; };
append(&buffer.original_content, test_str); append(&buffer.content_slices, ContentSlice { type = .Original, slice = buffer.original_content[:] });
append(&buffer.content_slices, ContentSlice { type = .Original, slice = buffer.original_content[:] });
return buffer; return buffer, error();
} else {
return FileBuffer{}, error(ErrorType.FileIOError, fmt.aprintf("failed to read from file"));
}
} }
update_glyph_buffer :: proc(buffer: ^FileBuffer) { update_glyph_buffer :: proc(buffer: ^FileBuffer) {
//mem.set(&buffer.glyph_buffer, 0, size_of(Glyph)*buffer.glyph_buffer_width*buffer.glyph_buffer_height); for &glyph in buffer.glyph_buffer {
glyph = Glyph{};
}
begin := buffer.top_line; begin := buffer.top_line;
rendered_col: int; rendered_col: int;
@ -117,8 +161,8 @@ update_glyph_buffer :: proc(buffer: ^FileBuffer) {
for character in iterate_file_buffer(&it) { for character in iterate_file_buffer(&it) {
if character == '\r' { continue; } if character == '\r' { continue; }
line := rendered_line - begin; screen_line := rendered_line - begin;
if rendered_line >= begin && line >= buffer.glyph_buffer_height { break; } if rendered_line >= begin && screen_line >= buffer.glyph_buffer_height { break; }
if character == '\n' { if character == '\n' {
rendered_col = 0; rendered_col = 0;
@ -127,7 +171,7 @@ update_glyph_buffer :: proc(buffer: ^FileBuffer) {
} }
if rendered_line >= begin && rendered_col < buffer.glyph_buffer_width { if rendered_line >= begin && rendered_col < buffer.glyph_buffer_width {
buffer.glyph_buffer[rendered_col + line * buffer.glyph_buffer_width] = Glyph { codepoint = character, color = 0 }; buffer.glyph_buffer[rendered_col + screen_line * buffer.glyph_buffer_width] = Glyph { codepoint = character, color = 0 };
} }
rendered_col += 1; rendered_col += 1;
@ -141,6 +185,9 @@ draw_file_buffer :: proc(buffer: ^FileBuffer, x: int, y: int, font: raylib.Font)
cursor_x := x + line_number_padding + buffer.cursor.col * source_font_width; cursor_x := x + line_number_padding + buffer.cursor.col * source_font_width;
cursor_y := y + buffer.cursor.line * source_font_height; cursor_y := y + buffer.cursor.line * source_font_height;
cursor_y -= begin * source_font_height;
raylib.DrawRectangle(i32(cursor_x), i32(cursor_y), source_font_width, source_font_height, raylib.BLUE);
for j in 0..<buffer.glyph_buffer_height { for j in 0..<buffer.glyph_buffer_height {
text_y := y + source_font_height * j; text_y := y + source_font_height * j;
@ -158,6 +205,34 @@ draw_file_buffer :: proc(buffer: ^FileBuffer, x: int, y: int, font: raylib.Font)
} }
} }
scroll_file_buffer :: proc(buffer: ^FileBuffer, dir: ScrollDir) {
switch dir {
case .Up:
{
if buffer.top_line > 0 {
buffer.top_line -= 20;
if buffer.top_line < 0 {
buffer.top_line = 0;
}
}
if buffer.cursor.line >= buffer.top_line + buffer.glyph_buffer_height - 4 {
buffer.cursor.line = buffer.top_line + buffer.glyph_buffer_height - 1 - 4;
}
}
case .Down:
{
buffer.top_line += 20;
// TODO: check if top_line has gone past end of document
if buffer.cursor.line < buffer.top_line + 4 {
buffer.cursor.line = buffer.top_line + 4;
}
}
}
}
main :: proc() { main :: proc() {
raylib.InitWindow(640, 480, "odin_editor - [back to basics]"); raylib.InitWindow(640, 480, "odin_editor - [back to basics]");
raylib.SetWindowState({ .WINDOW_RESIZABLE, .VSYNC_HINT }); raylib.SetWindowState({ .WINDOW_RESIZABLE, .VSYNC_HINT });
@ -166,8 +241,11 @@ main :: proc() {
font := raylib.LoadFont("../c_editor/Mx437_ToshibaSat_8x16.ttf"); font := raylib.LoadFont("../c_editor/Mx437_ToshibaSat_8x16.ttf");
fmt.println("Hello"); buffer, err := new_file_buffer(context.allocator, "./src/main.odin");
buffer := new_file_buffer(context.allocator, "./main.odin"); if err.type != .None {
fmt.println("Failed to create file buffer:", err);
os.exit(1);
}
update_glyph_buffer(&buffer); update_glyph_buffer(&buffer);
for !raylib.WindowShouldClose() { for !raylib.WindowShouldClose() {
@ -179,5 +257,12 @@ main :: proc() {
draw_file_buffer(&buffer, 0, 0, font); draw_file_buffer(&buffer, 0, 0, font);
} }
if raylib.IsKeyDown(.LEFT_CONTROL) && raylib.IsKeyDown(.U) {
scroll_file_buffer(&buffer, .Up);
}
if raylib.IsKeyDown(.LEFT_CONTROL) && raylib.IsKeyDown(.D) {
scroll_file_buffer(&buffer, .Down);
}
} }
} }