FPS :: 60; MS_PER_FRAME :: 1000 / FPS; buffer: string; lines: [..]String_Builder; line_height: int; my_font: *Simp.Dynamic_Font; window_width := 800; window_height := 600; first_line := 0; cursor_x := 0; cursor_y := 0; White :: Vector4.{1, 1, 1, 1}; main :: () { args := get_command_line_arguments(); assert(args.count == 2, "The file name must be passed as a CLI argument"); window_name := ifx args.count == 1 then "edit" else args[1]; window := create_window(window_width, window_height, window_name); my_init_fonts(); Simp.set_render_target(window); should_quit := false; prev := get_time(); assert(read_file_lines(args[1]), "Must be able to read file!"); while !should_quit { reset_temporary_storage(); now := get_time(); dt := now - prev; prev = now; Input.update_window_events(); handle_window_resizes(window); for event : Input.events_this_frame { if event.type == .QUIT { should_quit = true; break; } if event.type == .KEYBOARD && event.key_pressed { if event.key_code == { case .ESCAPE; should_quit = true; case .ARROW_UP; #through; case .ARROW_DOWN; #through; case .ARROW_LEFT; #through; case .ARROW_RIGHT; handle_arrow(event.key_code); } } } Simp.clear_render_target(.0, .0, .0, 1); render_edit_buffer(); Simp.swap_buffers(window); now = get_time(); if now - prev < MS_PER_FRAME { sleep_milliseconds(xx (now - prev)); } } } render_edit_buffer :: () { num_lines_in_screen := window_height / line_height - 1; viewable_lines := array_view(lines, first_line, num_lines_in_screen); for line_buffer: viewable_lines { Simp.set_shader_for_text(); line := builder_to_line(*line_buffer); Simp.prepare_text(my_font, line); top_of_line := window_height - (it_index + 1) * line_height; Simp.draw_prepared_text(my_font, 5, top_of_line, White); if it_index == cursor_y { Simp.set_shader_for_color(); Simp.immediate_quad( 5., cast(float) top_of_line + line_height, 6., cast(float) top_of_line, White); } } } handle_window_resizes :: (window: Window_Type) { for Input.get_window_resizes() { Simp.update_window(it.window); if it.window == window { should_reinit := (it.width != window_width) || (it.height != window_height); window_width = it.width; window_height = it.height; if should_reinit { my_init_fonts(); } } } } handle_arrow :: (key_code: Input.Key_Code) { num_lines_in_screen := window_height / line_height - 1; viewable_lines := array_view(lines, first_line, num_lines_in_screen); max_chars := 30; if key_code == { case .ARROW_UP; cursor_y = ifx cursor_y == 0 then 0 else cursor_y - 1; case .ARROW_DOWN; cursor_y = ifx cursor_y == viewable_lines.count then viewable_lines.count else cursor_y + 1; case .ARROW_LEFT; cursor_x = ifx cursor_x == 0 then 0 else cursor_x - 1; case .ARROW_RIGHT; cursor_y = ifx cursor_x == max_chars then max_chars else cursor_x + 1; } } builder_to_line :: (using builder: *String_Builder) -> string { result_builder: String_Builder; result_builder.allocator = temporary_allocator; builder_str := builder_to_string(builder, do_reset = false,, temp); start := 0; for c: builder_str { if c == #char "\t" { s := string.{data=builder_str.data + start, count=(it_index + 1) - start}; append(*result_builder, s); start = it_index + 1; } } s := string.{data=builder_str.data + start, count=builder_str.count - start}; append(*result_builder, s); return builder_to_string(*result_builder,, temp); } get_time :: () -> s64 { val, ok := to_milliseconds(current_time_monotonic()); assert(ok, "Must be able to convert from apollo to milliseconds"); return val; } read_file_lines :: (file_path: string) -> bool { file_contents, ok := read_entire_file(file_path); if !ok return ok; for lines reset(*it); free(lines.data); lines = [..]String_Builder.{}; lines_temp := split(file_contents, "\n"); defer free(lines_temp.data); for line: lines_temp { builder: String_Builder; init_string_builder(*builder); append(*builder, line); array_add(*lines, builder); } return ok; } my_init_fonts :: () { line_height = 16; base_path := path_strip_filename(get_path_of_running_executable()); my_font = Simp.get_font_at_size("/home/grant/.local/share/fonts/otf/BerkeleyMono/", "BerkeleyMono-Regular.otf", line_height); // my_font = Simp.get_font_at_size(base_path, "Anonymous Pro.ttf", line_height); assert(my_font != null); } #import "Basic"; #import "File"; #import "Math"; #import "String"; #import "System"; #import "Window_Creation"; Input :: #import "Input"; Simp :: #import "Simp";