From 369c539a9432c9360a7518a725a8f966dedb88ac Mon Sep 17 00:00:00 2001 From: Grant Horner Date: Tue, 9 Dec 2025 08:11:53 -0500 Subject: [PATCH] implemented movement by paragraph --- src/main.odin | 101 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 77 insertions(+), 24 deletions(-) diff --git a/src/main.odin b/src/main.odin index 1b81e22..d48f712 100644 --- a/src/main.odin +++ b/src/main.odin @@ -1,3 +1,16 @@ +/* +- TODO implement movement up and down by paragraph +- TODO implement scrolling/viewport +- TODO implement deletion by word +- TODO implement selection +- TODO implement duplicate selection/line +- TODO implement move selection/line up/down +- TODO implement copy/cut/paste +- TODO implement search +- TODO implement file picker +- TODO implement "execute" command +*/ + package main import "core:fmt" @@ -24,21 +37,6 @@ text_height: f32 cursor: Cursor lines: [dynamic][dynamic]u8 -render_cursor :: proc(cursor: ^Cursor) { - x := cursor.char * int(font_size / 2) - y := i32(font_size) * i32(cursor.line) - r.DrawLine(i32(x), y, i32(x), y + i32(text_height), r.WHITE) - r.DrawLine(i32(x) + 1, y, i32(x) + 1, y + i32(text_height), r.WHITE) -} - -current_line :: proc() -> ^[dynamic]u8 { - return &lines[cursor.line] -} - -is_whitespace :: proc(c: u8) -> bool { - return c == ' ' || c == '\t' || c == '\n' -} - main :: proc() { r.InitWindow(800, 600, "odit") r.SetTargetFPS(60) @@ -65,7 +63,7 @@ main :: proc() { cursor.char += 1 } - if r.IsKeyPressed(r.KeyboardKey.RIGHT) { + if repeatable_key_pressed(r.KeyboardKey.RIGHT) { preferred_position := cursor.char + 1 if cursor.char == len(current_line()) && cursor.line != len(lines) - 1 { cursor.char = 0 @@ -89,13 +87,13 @@ main :: proc() { cursor.char = min(preferred_position, len(current_line())) } - if r.IsKeyPressed(r.KeyboardKey.LEFT) { + if repeatable_key_pressed(r.KeyboardKey.LEFT) { preferred_position := cursor.char - 1 if cursor.char == 0 && cursor.line != 0 { cursor.line -= 1 cursor.char = len(current_line()) } - if r.IsKeyDown(r.KeyboardKey.LEFT_ALT) && 0 <= cursor.char - 1 { + if r.IsKeyDown(r.KeyboardKey.LEFT_ALT) && 0 < cursor.char { seen_space := false #reverse for c, c_index in current_line()[:cursor.char - 1] { if is_whitespace(c) { @@ -111,19 +109,43 @@ main :: proc() { cursor.char = max(preferred_position, 0) } - if r.IsKeyPressed(r.KeyboardKey.UP) { - cursor.line -= 1 + if repeatable_key_pressed(r.KeyboardKey.UP) { + preferred_line := cursor.line - 1 + + if r.IsKeyDown(r.KeyboardKey.LEFT_ALT) && 0 < cursor.line { + #reverse for l, l_index in lines[:cursor.line] { + if len(l) == 0 || all_whitespace(l[:]) { + preferred_line = l_index + break + } + } + } + + cursor.line = max(0, preferred_line) if len(current_line()) < cursor.char { cursor.char = len(current_line()) } } - if r.IsKeyPressed(r.KeyboardKey.DOWN) { - cursor.line += 1 + + if repeatable_key_pressed(r.KeyboardKey.DOWN) { + preferred_line := cursor.line + 1 + + if r.IsKeyDown(r.KeyboardKey.LEFT_ALT) && cursor.line + 1 < len(lines) { + for l, l_index in lines[cursor.line + 1:] { + if len(l) == 0 || all_whitespace(l[:]) { + preferred_line = cursor.line + l_index + 1 + break + } + } + } + + cursor.line = min(preferred_line, len(lines)) if len(current_line()) < cursor.char { cursor.char = len(current_line()) } } - if r.IsKeyPressed(r.KeyboardKey.ENTER) { + + if repeatable_key_pressed(r.KeyboardKey.ENTER) { new_line_cap := len(current_line()) - cursor.char bs := make([dynamic]u8, 0, len(current_line()) == 0 ? 1 : new_line_cap * 2) if cursor.char < len(current_line()) { @@ -136,6 +158,7 @@ main :: proc() { cursor.line += 1 cursor.char = 0 } + if r.IsKeyDown(r.KeyboardKey.LEFT_SUPER) && r.IsKeyPressed(r.KeyboardKey.S) { builder := strings.builder_make() defer strings.builder_destroy(&builder) @@ -146,7 +169,8 @@ main :: proc() { os.write_entire_file("foo.txt", transmute([]u8)strings.to_string(builder)) fmt.println("Wrote file!") } - if r.IsKeyPressed(r.KeyboardKey.BACKSPACE) { + + if repeatable_key_pressed(r.KeyboardKey.BACKSPACE) { if cursor.line == 0 && cursor.char == 0 do continue if cursor.char == 0 { old_len := len(lines[cursor.line - 1]) @@ -189,3 +213,32 @@ main :: proc() { dirty = false } } + +render_cursor :: proc(cursor: ^Cursor) { + x := cursor.char * int(font_size / 2) + y := i32(font_size) * i32(cursor.line) + r.DrawLine(i32(x), y, i32(x), y + i32(text_height), r.WHITE) + r.DrawLine(i32(x) + 1, y, i32(x) + 1, y + i32(text_height), r.WHITE) +} + +current_line :: proc() -> ^[dynamic]u8 { + return &lines[cursor.line] +} + +is_whitespace :: proc(c: u8) -> bool { + return c == ' ' || c == '\t' || c == '\n' +} + +all_whitespace :: proc(cs: []u8) -> bool { + for c in cs { + if !is_whitespace(c) { + return false + } + } + + return true +} + +repeatable_key_pressed :: proc(k: r.KeyboardKey) -> bool { + return r.IsKeyPressed(k) || r.IsKeyPressedRepeat(k) +}