woo, copy and paste

memory-refactor
Patrick Cleaveliln 2025-07-10 03:52:57 +00:00
parent 5559441180
commit 8c352355de
5 changed files with 163 additions and 9 deletions

View File

@ -41,6 +41,9 @@ State :: struct {
current_buffer: int,
buffers: [dynamic]FileBuffer,
// TODO: make more than one register to plop stuff into
yank_register: Register,
log_buffer: FileBuffer,
current_input_map: ^InputActions,
@ -53,6 +56,11 @@ State :: struct {
panels: util.StaticList(Panel),
}
Register :: struct {
whole_line: bool,
data: []u8,
}
EditorCommand :: struct {
name: string,
description: string,
@ -127,6 +135,63 @@ current_buffer :: proc(state: ^State) -> ^FileBuffer {
return &state.buffers[state.current_buffer];
}
yank_whole_line :: proc(state: ^State) {
if state.yank_register.data != nil {
delete(state.yank_register.data)
state.yank_register.data = nil
}
if buffer := current_buffer(state); buffer != nil {
selection := new_selection(buffer, buffer.cursor)
length := selection_length(buffer, selection)
state.yank_register.whole_line = true
state.yank_register.data = make([]u8, length)
it := new_file_buffer_iter_with_cursor(buffer, selection.start)
index := 0
for !it.hit_end && index < length {
state.yank_register.data[index] = get_character_at_iter(it)
iterate_file_buffer(&it)
index += 1
}
}
}
yank_selection :: proc(state: ^State) {
if state.yank_register.data != nil {
delete(state.yank_register.data)
state.yank_register.data = nil
}
if buffer := current_buffer(state); buffer != nil && buffer.selection != nil {
selection := swap_selections(buffer.selection.?)
length := selection_length(buffer, selection)
state.yank_register.whole_line = false
state.yank_register.data = make([]u8, length)
it := new_file_buffer_iter_with_cursor(buffer, selection.start)
index := 0
for !it.hit_end && index < length {
state.yank_register.data[index] = get_character_at_iter(it)
iterate_file_buffer(&it)
index += 1
}
}
}
paste_register :: proc(state: ^State, register: Register) {
if buffer := current_buffer(state); buffer != nil && register.data != nil {
insert_content(buffer, register.data)
move_cursor_left(buffer)
}
}
reset_input_map_from_state_mode :: proc(state: ^State) {
reset_input_map_from_mode(state, state.mode)
}

View File

@ -644,15 +644,25 @@ new_selection_span :: proc(start: Cursor, end: Cursor) -> Selection {
};
}
new_selection :: proc{new_selection_zero_length, new_selection_span};
new_selection_current_line :: proc(buffer: ^FileBuffer, cursor: Cursor) -> Selection {
start := cursor
end := cursor
move_cursor_start_of_line(buffer, &start)
move_cursor_end_of_line(buffer, true, &end)
return {
start = start,
end = end,
}
}
new_selection :: proc{new_selection_zero_length, new_selection_span, new_selection_current_line};
swap_selections :: proc(selection: Selection) -> (swapped: Selection) {
swapped = selection
if selection.start.index.slice_index > selection.end.index.slice_index ||
(selection.start.index.slice_index == selection.end.index.slice_index
&& selection.start.index.content_index > selection.end.index.content_index)
{
if is_selection_inverted(selection) {
swapped.start = selection.end
swapped.end = selection.start
}
@ -660,6 +670,28 @@ swap_selections :: proc(selection: Selection) -> (swapped: Selection) {
return swapped
}
is_selection_inverted :: proc(selection: Selection) -> bool {
return selection.start.index.slice_index > selection.end.index.slice_index ||
(selection.start.index.slice_index == selection.end.index.slice_index
&& selection.start.index.content_index > selection.end.index.content_index)
}
selection_length :: proc(buffer: ^FileBuffer, selection: Selection) -> int {
selection := selection
it := new_file_buffer_iter_with_cursor(buffer, selection.start)
length := 0
for !it.hit_end && !is_selection_inverted(selection) {
iterate_file_buffer(&it);
selection.start = it.cursor
length += 1
}
return length
}
new_virtual_file_buffer :: proc(allocator: mem.Allocator) -> FileBuffer {
context.allocator = allocator;
width := 256;

View File

@ -179,6 +179,31 @@ register_default_visual_actions :: proc(input_map: ^core.InputActions) {
sdl2.StartTextInput();
}, "change selection");
}
// Copy-Paste
{
core.register_key_action(input_map, .Y, proc(state: ^State) {
core.yank_selection(state)
state.mode = .Normal;
core.reset_input_map(state)
core.current_buffer(state).selection = nil;
core.update_file_buffer_scroll(core.current_buffer(state))
}, "Yank Line");
core.register_key_action(input_map, .P, proc(state: ^State) {
if state.yank_register.whole_line {
core.insert_content(core.current_buffer(state), []u8{'\n'});
core.paste_register(state, state.yank_register)
core.insert_content(core.current_buffer(state), []u8{'\n'});
} else {
core.paste_register(state, state.yank_register)
}
core.reset_input_map(state)
}, "Paste");
}
}
register_default_text_input_actions :: proc(input_map: ^core.InputActions) {
@ -201,4 +226,31 @@ register_default_text_input_actions :: proc(input_map: ^core.InputActions) {
sdl2.StartTextInput();
}, "insert mode on newline");
// Copy-Paste
{
{
yank_actions := core.new_input_actions()
defer core.register_key_action(input_map, .Y, yank_actions)
core.register_key_action(&yank_actions, .Y, proc(state: ^State) {
core.yank_whole_line(state)
core.reset_input_map(state)
}, "Yank Line");
}
core.register_key_action(input_map, .P, proc(state: ^State) {
if state.yank_register.whole_line {
core.move_cursor_end_of_line(core.current_buffer(state), false);
core.insert_content(core.current_buffer(state), []u8{'\n'});
} else {
core.move_cursor_right(core.current_buffer(state))
}
core.paste_register(state, state.yank_register)
core.reset_input_map(state)
}, "Paste");
}
}

View File

@ -181,14 +181,16 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB
ui.open_element(s, nil, { kind = {ui.Grow{}, ui.Grow{}}})
ui.close_element(s)
it := core.new_file_buffer_iter_with_cursor(buffer, buffer.cursor)
ui.open_element(
s,
fmt.tprintf(
"%v:%v - Slice %v:%v",
"%v:%v - Slice %v:%v - Char: %v",
buffer.cursor.line + 1,
buffer.cursor.col + 1,
buffer.cursor.index.slice_index,
buffer.cursor.index.content_index
buffer.cursor.index.content_index,
core.get_character_at_iter(it)
),
{}
)

View File

@ -37,9 +37,12 @@
- Finish selections
- [x] Guarantee that start and end are always ordered
- Add in text actions
- [ ] Yank
- [x] Yank
- [x] Delete
- [x] Change
- [ ] Change
- [ ] Change
- [ ] Change word
- [ ] Change inside delimiter
- Virtual Whitespace
- Allow any-sized tabs
- Modify input system to allow for keybinds that take input