From 52751610486867c897b22092c651deb0eff3c22f Mon Sep 17 00:00:00 2001 From: Grant Horner Date: Tue, 9 Dec 2025 19:25:40 -0500 Subject: [PATCH] implemented most of selection backspace --- odit.sublime-project | 6 +- src/main.odin | 157 ++++++++++++++++++++++++++++--------------- 2 files changed, 108 insertions(+), 55 deletions(-) diff --git a/odit.sublime-project b/odit.sublime-project index f6dcd49..9c95cc8 100644 --- a/odit.sublime-project +++ b/odit.sublime-project @@ -20,7 +20,9 @@ ], "folders": [ { - "path": "." - } + "path": ".", + "folder_exclude_patterns": ["*bin*"], + "binary_file_patterns": ["*.bin"] + }, ] } diff --git a/src/main.odin b/src/main.odin index 1009485..ec2d116 100644 --- a/src/main.odin +++ b/src/main.odin @@ -45,6 +45,11 @@ Selection :: struct { end: Position, } +Range :: struct { + start: int, + end: int, +} + window_width := 800 window_height := 600 font_size: f32 = 20.0 @@ -81,24 +86,34 @@ main :: proc() { for c := r.GetCharPressed(); c != rune(0); c = r.GetCharPressed() { chars, _ := utf8.encode_rune(c) char := chars[0] - inject_at(&lines[cursor.line], cursor.char, char) - cursor.char += 1 + // TODO: selection + if selection.active { + + } else { + inject_at(&lines[cursor.line], cursor.char, char) + cursor.char += 1 + } } move_cursor() if repeatable_key_pressed(.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()) { - for c, i in current_line()[cursor.char:] { - append(&bs, c) + // TODO: selection + if selection.active { + + } else { + 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()) { + for c, i in current_line()[cursor.char:] { + append(&bs, c) + } } + inject_at(&lines, cursor.line + 1, bs) + resize(current_line(), cursor.char) + cursor.line += 1 + cursor.char = 0 } - inject_at(&lines, cursor.line + 1, bs) - resize(current_line(), cursor.char) - cursor.line += 1 - cursor.char = 0 } if r.IsKeyDown(.LEFT_SUPER) && r.IsKeyPressed(.S) { @@ -114,30 +129,59 @@ main :: proc() { skip_backspace: if repeatable_key_pressed(.BACKSPACE) { if cursor.line == 0 && cursor.char == 0 do break skip_backspace - if cursor.char == 0 { - // join lines - old_len := len(lines[cursor.line - 1]) - append(&lines[cursor.line - 1], string(current_line()[:])) - line_to_remove := current_line()^ - defer delete(line_to_remove) - ordered_remove(&lines, cursor.line) - cursor.line -= 1 - cursor.char = old_len - } else { - if r.IsKeyDown(.LEFT_ALT) { - // delete by word - delete_to, found := find_previous_space(cursor.char, current_line()[:]) - if found { - remove_range(current_line(), delete_to, cursor.char) - cursor.char = delete_to - } else { - remove_range(current_line(), 0, cursor.char) - cursor.char = 0 + // TODO: selection + if selection.active { + earliest := selection_earliest() + latest := selection_latest() + earliest_line := &lines[earliest.line] + earliest_selection := get_selection_for_line(earliest_line[:], earliest.line) + remove_range(earliest_line, earliest_selection.start, earliest_selection.end) + if latest.line != earliest.line { + latest_line := &lines[latest.line] + latest_selection := get_selection_for_line(latest_line[:], latest.line) + append(earliest_line, string(latest_line[latest_selection.end:len(latest_line)])) + defer delete(latest_line^) + ordered_remove(&lines, latest.line) + cursor.line -= 1 + for i := earliest.line + 1; i < latest.line; i += 1 { + line_to_remove := lines[i] + defer delete(line_to_remove) + ordered_remove(&lines, i) + // NOTE(grant): Should we do this here? + if i < cursor.line { + cursor.line -= 1 + } } } else { - // delete single char - ordered_remove(&lines[cursor.line], cursor.char - 1) - cursor.char -= 1 + cursor.char -= earliest_selection.end - earliest_selection.start + } + selection.active = false + } else { + if cursor.char == 0 { + // join lines + old_len := len(lines[cursor.line - 1]) + append(&lines[cursor.line - 1], string(current_line()[:])) + line_to_remove := current_line()^ + defer delete(line_to_remove) + ordered_remove(&lines, cursor.line) + cursor.line -= 1 + cursor.char = old_len + } else { + if r.IsKeyDown(.LEFT_ALT) { + // delete by word + delete_to, found := find_previous_space(cursor.char, current_line()[:]) + if found { + remove_range(current_line(), delete_to, cursor.char) + cursor.char = delete_to + } else { + remove_range(current_line(), 0, cursor.char) + cursor.char = 0 + } + } else { + // delete single char + ordered_remove(&lines[cursor.line], cursor.char - 1) + cursor.char -= 1 + } } } } @@ -257,24 +301,10 @@ render_line_with_selection :: proc(line: []u8, line_index: int, font: r.Font) { earliest := selection_earliest() latest := selection_latest() - selection_begin: int - selection_end: int - if line_index == earliest.line && line_index == latest.line { - selection_begin = min(selection.start.char, selection.end.char) - selection_end = max(selection.start.char, selection.end.char) - } else if line_index == earliest.line { - selection_begin = earliest.char - selection_end = len(line) - } else if line_index == latest.line { - selection_begin = 0 - selection_end = latest.char - } else if earliest.line < line_index && line_index < latest.line { - selection_begin = 0 - selection_end = len(line) - } + selection_range := get_selection_for_line(line, line_index) - prefix := line[:selection_begin] - suffix := line[selection_end:] if selection_end < len(line) else []u8{} + prefix := line[:selection_range.start] + suffix := line[selection_range.end:] if selection_range.end < len(line) else []u8{} // need to copy these into separate buffers for zero value x: f32 = 0.0 if len(prefix) != 0 { @@ -286,10 +316,10 @@ render_line_with_selection :: proc(line: []u8, line_index: int, font: r.Font) { } selected_str: string - if selection_end < len(line) { - selected_str = string(line[selection_begin:selection_end]) + if selection_range.end < len(line) { + selected_str = string(line[selection_range.start:selection_range.end]) } else { - selected_str = string(line[selection_begin:]) + selected_str = string(line[selection_range.start:]) } cstr := strings.clone_to_cstring(selected_str, context.temp_allocator) if len(suffix) != 0 else strings.unsafe_string_to_cstring(selected_str) @@ -436,3 +466,24 @@ selection_latest :: proc() -> Position { return latest } + +get_selection_for_line :: proc(line: []u8, line_index: int) -> Range { + earliest := selection_earliest() + latest := selection_latest() + selection_begin: int + selection_end: int + if line_index == earliest.line && line_index == latest.line { + selection_begin = min(selection.start.char, selection.end.char) + selection_end = max(selection.start.char, selection.end.char) + } else if line_index == earliest.line { + selection_begin = earliest.char + selection_end = len(line) + } else if line_index == latest.line { + selection_begin = 0 + selection_end = latest.char + } else if earliest.line < line_index && line_index < latest.line { + selection_begin = 0 + selection_end = len(line) + } + return Range{start = selection_begin, end = selection_end} +}