Compare commits
3 Commits
6b4d9f0cda
...
722f05be61
Author | SHA1 | Date |
---|---|---|
|
722f05be61 | |
|
f6d7dc0db0 | |
|
f8ba2e587d |
|
@ -102,10 +102,12 @@ FileBufferPanel :: struct {
|
|||
|
||||
GrepPanel :: struct {
|
||||
query_arena: mem.Arena,
|
||||
query_region: mem.Arena_Temp_Memory,
|
||||
buffer: int,
|
||||
selected_result: int,
|
||||
search_query: string,
|
||||
query_results: []GrepQueryResult,
|
||||
glyphs: GlyphBuffer,
|
||||
}
|
||||
|
||||
GrepQueryResult :: struct {
|
||||
|
|
|
@ -43,11 +43,6 @@ Selection :: struct {
|
|||
end: Cursor,
|
||||
}
|
||||
|
||||
Glyph :: struct {
|
||||
codepoint: u8,
|
||||
color: theme.PaletteColor,
|
||||
}
|
||||
|
||||
FileBuffer :: struct {
|
||||
allocator: mem.Allocator,
|
||||
|
||||
|
@ -63,9 +58,7 @@ FileBuffer :: struct {
|
|||
added_content: [dynamic]u8,
|
||||
content_slices: [dynamic][]u8,
|
||||
|
||||
glyph_buffer_width: int,
|
||||
glyph_buffer_height: int,
|
||||
glyph_buffer: [dynamic]Glyph,
|
||||
glyphs: GlyphBuffer,
|
||||
|
||||
input_buffer: [dynamic]u8,
|
||||
}
|
||||
|
@ -527,9 +520,12 @@ move_cursor_down :: proc(buffer: ^FileBuffer, amount: int = 1, cursor: Maybe(^Cu
|
|||
break;
|
||||
}
|
||||
}
|
||||
if it.hit_end {
|
||||
return
|
||||
}
|
||||
|
||||
line_length := file_buffer_line_length(buffer, it.cursor.index);
|
||||
if it.cursor.col < line_length && it.cursor.col < current_col {
|
||||
if it.cursor.col < line_length-1 && it.cursor.col < current_col {
|
||||
for _ in iterate_file_buffer(&it) {
|
||||
if it.cursor.col >= line_length-1 || it.cursor.col >= current_col {
|
||||
break;
|
||||
|
@ -705,10 +701,7 @@ new_virtual_file_buffer :: proc(allocator: mem.Allocator) -> FileBuffer {
|
|||
added_content = make([dynamic]u8, 0, 1024*1024),
|
||||
content_slices = make([dynamic][]u8, 0, 1024*1024),
|
||||
|
||||
glyph_buffer_width = width,
|
||||
glyph_buffer_height = height,
|
||||
glyph_buffer = make([dynamic]Glyph, width*height, width*height),
|
||||
|
||||
glyphs = make_glyph_buffer(width, height),
|
||||
input_buffer = make([dynamic]u8, 0, 1024),
|
||||
};
|
||||
|
||||
|
@ -760,10 +753,7 @@ new_file_buffer :: proc(allocator: mem.Allocator, file_path: string, base_dir: s
|
|||
added_content = make([dynamic]u8, 0, 1024*1024),
|
||||
content_slices = make([dynamic][]u8, 0, 1024*1024),
|
||||
|
||||
glyph_buffer_width = width,
|
||||
glyph_buffer_height = height,
|
||||
glyph_buffer = make([dynamic]Glyph, width*height, width*height),
|
||||
|
||||
glyphs = make_glyph_buffer(width, height),
|
||||
input_buffer = make([dynamic]u8, 0, 1024),
|
||||
};
|
||||
|
||||
|
@ -809,11 +799,12 @@ next_buffer :: proc(state: ^State, prev_buffer: ^int) -> int {
|
|||
return index;
|
||||
}
|
||||
|
||||
// TODO: replace this with arena for the file buffer
|
||||
free_file_buffer :: proc(buffer: ^FileBuffer) {
|
||||
delete(buffer.original_content);
|
||||
delete(buffer.added_content);
|
||||
delete(buffer.content_slices);
|
||||
delete(buffer.glyph_buffer);
|
||||
delete(buffer.glyphs.buffer);
|
||||
delete(buffer.input_buffer);
|
||||
}
|
||||
|
||||
|
@ -827,9 +818,9 @@ color_character :: proc(buffer: ^FileBuffer, start: Cursor, end: Cursor, palette
|
|||
start.line -= buffer.top_line;
|
||||
}
|
||||
|
||||
if end.line >= buffer.top_line + buffer.glyph_buffer_height {
|
||||
end.line = buffer.glyph_buffer_height - 1;
|
||||
end.col = buffer.glyph_buffer_width - 1;
|
||||
if end.line >= buffer.top_line + buffer.glyphs.height {
|
||||
end.line = buffer.glyphs.height - 1;
|
||||
end.col = buffer.glyphs.width - 1;
|
||||
} else {
|
||||
end.line -= buffer.top_line;
|
||||
}
|
||||
|
@ -839,72 +830,19 @@ color_character :: proc(buffer: ^FileBuffer, start: Cursor, end: Cursor, palette
|
|||
end_col := end.col;
|
||||
if j > start.line && j < end.line {
|
||||
start_col = 0;
|
||||
end_col = buffer.glyph_buffer_width;
|
||||
end_col = buffer.glyphs.width;
|
||||
} else if j < end.line {
|
||||
end_col = buffer.glyph_buffer_width;
|
||||
end_col = buffer.glyphs.width;
|
||||
} else if j > start.line && j == end.line {
|
||||
start_col = 0;
|
||||
}
|
||||
|
||||
for i in start_col..<math.min(end_col+1, buffer.glyph_buffer_width) {
|
||||
buffer.glyph_buffer[i + j * buffer.glyph_buffer_width].color = palette_index;
|
||||
for i in start_col..<math.min(end_col+1, buffer.glyphs.width) {
|
||||
buffer.glyphs.buffer[i + j * buffer.glyphs.width].color = palette_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update_glyph_buffer :: proc(buffer: ^FileBuffer) {
|
||||
for &glyph in buffer.glyph_buffer {
|
||||
glyph = Glyph{};
|
||||
}
|
||||
|
||||
begin := buffer.top_line;
|
||||
rendered_col: int;
|
||||
rendered_line: int;
|
||||
|
||||
it := new_file_buffer_iter(buffer);
|
||||
for character in iterate_file_buffer(&it) {
|
||||
if character == '\r' { continue; }
|
||||
|
||||
screen_line := rendered_line - begin;
|
||||
// don't render past the screen
|
||||
if rendered_line >= begin && screen_line >= buffer.glyph_buffer_height { break; }
|
||||
|
||||
// render INSERT mode text into glyph buffer
|
||||
if len(buffer.input_buffer) > 0 && rendered_line == buffer.cursor.line && rendered_col >= buffer.cursor.col && rendered_col < buffer.cursor.col + len(buffer.input_buffer) {
|
||||
for k in 0..<len(buffer.input_buffer) {
|
||||
screen_line = rendered_line - begin;
|
||||
|
||||
if buffer.input_buffer[k] == '\n' {
|
||||
rendered_col = 0;
|
||||
rendered_line += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if rendered_line >= begin && rendered_col < buffer.glyph_buffer_width {
|
||||
buffer.glyph_buffer[rendered_col + screen_line * buffer.glyph_buffer_width].color = .Foreground;
|
||||
buffer.glyph_buffer[rendered_col + screen_line * buffer.glyph_buffer_width].codepoint = buffer.input_buffer[k];
|
||||
|
||||
rendered_col += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
screen_line = rendered_line - begin;
|
||||
|
||||
if character == '\n' {
|
||||
rendered_col = 0;
|
||||
rendered_line += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if rendered_line >= begin && rendered_col < buffer.glyph_buffer_width {
|
||||
buffer.glyph_buffer[rendered_col + screen_line * buffer.glyph_buffer_width] = Glyph { codepoint = character, color = .Foreground };
|
||||
}
|
||||
|
||||
rendered_col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, show_line_numbers: bool = true) {
|
||||
update_glyph_buffer(buffer);
|
||||
|
||||
|
@ -961,7 +899,8 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho
|
|||
draw_rect(state, cursor_x, cursor_y, state.source_font_width, state.source_font_height, .Blue);
|
||||
}
|
||||
|
||||
for j in 0..<buffer.glyph_buffer_height {
|
||||
// TODO: replace with glyph_buffer.draw_glyph_buffer
|
||||
for j in 0..<buffer.glyphs.height {
|
||||
text_y := y + state.source_font_height * j;
|
||||
|
||||
if show_line_numbers {
|
||||
|
@ -969,9 +908,9 @@ draw_file_buffer :: proc(state: ^State, buffer: ^FileBuffer, x: int, y: int, sho
|
|||
}
|
||||
|
||||
line_length := 0;
|
||||
for i in 0..<buffer.glyph_buffer_width {
|
||||
for i in 0..<buffer.glyphs.width {
|
||||
text_x := x + padding + i * state.source_font_width;
|
||||
glyph := buffer.glyph_buffer[i + j * buffer.glyph_buffer_width];
|
||||
glyph := buffer.glyphs.buffer[i + j * buffer.glyphs.width];
|
||||
|
||||
if glyph.codepoint == 0 { break; }
|
||||
line_length += 1;
|
||||
|
@ -1015,14 +954,14 @@ update_file_buffer_scroll :: proc(buffer: ^FileBuffer, cursor: Maybe(^Cursor) =
|
|||
cursor = &buffer.cursor;
|
||||
}
|
||||
|
||||
if cursor.?.line > (buffer.top_line + buffer.glyph_buffer_height - 5) {
|
||||
buffer.top_line = math.max(cursor.?.line - buffer.glyph_buffer_height + 5, 0);
|
||||
if cursor.?.line > (buffer.top_line + buffer.glyphs.height - 5) {
|
||||
buffer.top_line = math.max(cursor.?.line - buffer.glyphs.height + 5, 0);
|
||||
} else if cursor.?.line < (buffer.top_line + 5) {
|
||||
buffer.top_line = math.max(cursor.?.line - 5, 0);
|
||||
}
|
||||
|
||||
// if buffer.cursor.line > (buffer.top_line + buffer.glyph_buffer_height - 5) {
|
||||
// buffer.top_line = math.max(buffer.cursor.line - buffer.glyph_buffer_height + 5, 0);
|
||||
// if buffer.cursor.line > (buffer.top_line + buffer.glyphs.height - 5) {
|
||||
// buffer.top_line = math.max(buffer.cursor.line - buffer.glyphs.height + 5, 0);
|
||||
// } else if buffer.cursor.line < (buffer.top_line + 5) {
|
||||
// buffer.top_line = math.max(buffer.cursor.line - 5, 0);
|
||||
// }
|
||||
|
|
|
@ -0,0 +1,139 @@
|
|||
package core
|
||||
|
||||
import "core:fmt"
|
||||
|
||||
import "../theme"
|
||||
|
||||
GlyphBuffer :: struct {
|
||||
buffer: []Glyph,
|
||||
width: int,
|
||||
height: int,
|
||||
}
|
||||
|
||||
Glyph :: struct {
|
||||
codepoint: u8,
|
||||
color: theme.PaletteColor,
|
||||
}
|
||||
|
||||
make_glyph_buffer :: proc(width, height: int, allocator := context.allocator) -> GlyphBuffer {
|
||||
context.allocator = allocator
|
||||
|
||||
return GlyphBuffer {
|
||||
width = width,
|
||||
height = height,
|
||||
buffer = make([]Glyph, width*height)
|
||||
}
|
||||
}
|
||||
|
||||
update_glyph_buffer_from_file_buffer :: proc(buffer: ^FileBuffer) {
|
||||
for &glyph in buffer.glyphs.buffer {
|
||||
glyph = Glyph{};
|
||||
}
|
||||
|
||||
begin := buffer.top_line;
|
||||
rendered_col: int;
|
||||
rendered_line: int;
|
||||
|
||||
it := new_file_buffer_iter(buffer);
|
||||
for character in iterate_file_buffer(&it) {
|
||||
if character == '\r' { continue; }
|
||||
|
||||
screen_line := rendered_line - begin;
|
||||
// don't render past the screen
|
||||
if rendered_line >= begin && screen_line >= buffer.glyphs.height { break; }
|
||||
|
||||
// render INSERT mode text into glyph buffer
|
||||
if len(buffer.input_buffer) > 0 && rendered_line == buffer.cursor.line && rendered_col >= buffer.cursor.col && rendered_col < buffer.cursor.col + len(buffer.input_buffer) {
|
||||
for k in 0..<len(buffer.input_buffer) {
|
||||
screen_line = rendered_line - begin;
|
||||
|
||||
if buffer.input_buffer[k] == '\n' {
|
||||
rendered_col = 0;
|
||||
rendered_line += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if rendered_line >= begin && rendered_col < buffer.glyphs.width {
|
||||
buffer.glyphs.buffer[rendered_col + screen_line * buffer.glyphs.width].color = .Foreground;
|
||||
buffer.glyphs.buffer[rendered_col + screen_line * buffer.glyphs.width].codepoint = buffer.input_buffer[k];
|
||||
|
||||
rendered_col += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
screen_line = rendered_line - begin;
|
||||
|
||||
if character == '\n' {
|
||||
rendered_col = 0;
|
||||
rendered_line += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if rendered_line >= begin && rendered_col < buffer.glyphs.width {
|
||||
buffer.glyphs.buffer[rendered_col + screen_line * buffer.glyphs.width] = Glyph { codepoint = character, color = .Foreground };
|
||||
}
|
||||
|
||||
rendered_col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
update_glyph_buffer_from_bytes :: proc(glyphs: ^GlyphBuffer, data: []u8, top_line: int) {
|
||||
for &glyph in glyphs.buffer {
|
||||
glyph = Glyph{};
|
||||
}
|
||||
|
||||
begin := top_line;
|
||||
rendered_col: int;
|
||||
rendered_line: int;
|
||||
|
||||
for character in data {
|
||||
if character == '\r' { continue; }
|
||||
|
||||
screen_line := rendered_line - begin;
|
||||
// don't render past the screen
|
||||
if rendered_line >= begin && screen_line >= glyphs.height { break; }
|
||||
|
||||
screen_line = rendered_line - begin;
|
||||
|
||||
if character == '\n' {
|
||||
rendered_col = 0;
|
||||
rendered_line += 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if rendered_line >= begin && rendered_col < glyphs.width {
|
||||
glyphs.buffer[rendered_col + screen_line * glyphs.width] = Glyph { codepoint = character, color = .Foreground };
|
||||
}
|
||||
|
||||
rendered_col += 1;
|
||||
}
|
||||
}
|
||||
|
||||
update_glyph_buffer :: proc{update_glyph_buffer_from_file_buffer, update_glyph_buffer_from_bytes}
|
||||
|
||||
draw_glyph_buffer :: proc(state: ^State, glyphs: ^GlyphBuffer, x: int, y: int, top_line: int, show_line_numbers: bool = true) {
|
||||
padding := 0;
|
||||
if show_line_numbers {
|
||||
padding = state.source_font_width * 5;
|
||||
}
|
||||
|
||||
for j in 0..<glyphs.height {
|
||||
text_y := y + state.source_font_height * j;
|
||||
|
||||
if show_line_numbers {
|
||||
draw_text(state, fmt.tprintf("%d", top_line + j + 1), x, text_y);
|
||||
}
|
||||
|
||||
line_length := 0;
|
||||
for i in 0..<glyphs.width {
|
||||
text_x := x + padding + i * state.source_font_width;
|
||||
glyph := glyphs.buffer[i + j * glyphs.width];
|
||||
|
||||
if glyph.codepoint == 0 { break; }
|
||||
line_length += 1;
|
||||
|
||||
draw_codepoint(state, rune(glyph.codepoint), text_x, text_y, glyph.color);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package input
|
||||
|
||||
import "base:runtime"
|
||||
import "core:log"
|
||||
|
||||
import "vendor:sdl2"
|
||||
|
@ -220,11 +221,16 @@ register_default_text_input_actions :: proc(input_map: ^core.InputActions) {
|
|||
// TODO: add shift+o to insert newline above current one
|
||||
|
||||
core.register_key_action(input_map, .O, proc(state: ^State) {
|
||||
core.move_cursor_end_of_line(core.current_buffer(state), false);
|
||||
core.insert_content(core.current_buffer(state), []u8{'\n'});
|
||||
if buffer := core.current_buffer(state); buffer != nil {
|
||||
core.move_cursor_end_of_line(buffer, false);
|
||||
runtime.clear(&buffer.input_buffer)
|
||||
|
||||
append(&buffer.input_buffer, '\n')
|
||||
|
||||
state.mode = .Insert;
|
||||
|
||||
sdl2.StartTextInput();
|
||||
}
|
||||
}, "insert mode on newline");
|
||||
|
||||
// Copy-Paste
|
||||
|
|
|
@ -54,8 +54,8 @@ ui_font_height :: proc() -> i32 {
|
|||
|
||||
draw :: proc(state: ^State) {
|
||||
if buffer := core.current_buffer(state); buffer != nil {
|
||||
buffer.glyph_buffer_height = math.min(256, int((state.screen_height - state.source_font_height*2) / state.source_font_height)) + 1;
|
||||
buffer.glyph_buffer_width = math.min(256, int((state.screen_width - state.source_font_width) / state.source_font_width));
|
||||
buffer.glyphs.height = math.min(256, int((state.screen_height - state.source_font_height*2) / state.source_font_height)) + 1;
|
||||
buffer.glyphs.width = math.min(256, int((state.screen_width - state.source_font_width) / state.source_font_width));
|
||||
}
|
||||
|
||||
render_color := theme.get_palette_color(.Background);
|
||||
|
@ -168,8 +168,8 @@ ui_file_buffer :: proc(s: ^ui.State, buffer: ^FileBuffer) {
|
|||
draw_func := proc(state: ^State, e: ui.UI_Element, user_data: rawptr) {
|
||||
buffer := transmute(^FileBuffer)user_data;
|
||||
if buffer != nil {
|
||||
buffer.glyph_buffer_width = e.layout.size.x / state.source_font_width;
|
||||
buffer.glyph_buffer_height = e.layout.size.y / state.source_font_height + 1;
|
||||
buffer.glyphs.width = e.layout.size.x / state.source_font_width;
|
||||
buffer.glyphs.height = e.layout.size.y / state.source_font_height + 1;
|
||||
|
||||
core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y);
|
||||
}
|
||||
|
|
|
@ -120,7 +120,9 @@ close :: proc(state: ^core.State, panel_id: int) {
|
|||
util.delete(&state.panels, panel_id)
|
||||
|
||||
// TODO: keep track of the last active panel instead of focusing back to the first one
|
||||
state.current_panel = util.get_first_active_index(&state.panels).?
|
||||
if first_active, ok := util.get_first_active_index(&state.panels).?; ok {
|
||||
state.current_panel = first_active
|
||||
}
|
||||
|
||||
core.reset_input_map(state)
|
||||
}
|
||||
|
@ -152,8 +154,8 @@ render_file_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileB
|
|||
draw_func := proc(state: ^core.State, e: ui.UI_Element, user_data: rawptr) {
|
||||
buffer := transmute(^core.FileBuffer)user_data;
|
||||
if buffer != nil {
|
||||
buffer.glyph_buffer_width = e.layout.size.x / state.source_font_width;
|
||||
buffer.glyph_buffer_height = e.layout.size.y / state.source_font_height + 1;
|
||||
buffer.glyphs.width = e.layout.size.x / state.source_font_width;
|
||||
buffer.glyphs.height = e.layout.size.y / state.source_font_height + 1;
|
||||
|
||||
core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y);
|
||||
}
|
||||
|
@ -205,8 +207,8 @@ render_raw_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileBu
|
|||
draw_func := proc(state: ^core.State, e: ui.UI_Element, user_data: rawptr) {
|
||||
buffer := transmute(^core.FileBuffer)user_data;
|
||||
if buffer != nil {
|
||||
buffer.glyph_buffer_width = e.layout.size.x / state.source_font_width;
|
||||
buffer.glyph_buffer_height = e.layout.size.y / state.source_font_height + 1;
|
||||
buffer.glyphs.width = e.layout.size.x / state.source_font_width;
|
||||
buffer.glyphs.height = e.layout.size.y / state.source_font_height + 1;
|
||||
|
||||
core.draw_file_buffer(state, buffer, e.layout.pos.x, e.layout.pos.y, false);
|
||||
}
|
||||
|
@ -219,6 +221,24 @@ render_raw_buffer :: proc(state: ^core.State, s: ^ui.State, buffer: ^core.FileBu
|
|||
|
||||
}
|
||||
|
||||
render_glyph_buffer :: proc(state: ^core.State, s: ^ui.State, glyphs: ^core.GlyphBuffer) {
|
||||
draw_func := proc(state: ^core.State, e: ui.UI_Element, user_data: rawptr) {
|
||||
glyphs := transmute(^core.GlyphBuffer)user_data;
|
||||
if glyphs != nil {
|
||||
glyphs.width = e.layout.size.x / state.source_font_width;
|
||||
glyphs.height = e.layout.size.y / state.source_font_height + 1;
|
||||
|
||||
core.draw_glyph_buffer(state, glyphs, e.layout.pos.x, e.layout.pos.y, 0, true);
|
||||
}
|
||||
};
|
||||
|
||||
ui.open_element(s, ui.UI_Element_Kind_Custom{fn = draw_func, user_data = transmute(rawptr)glyphs}, {
|
||||
kind = {ui.Grow{}, ui.Grow{}}
|
||||
})
|
||||
ui.close_element(s)
|
||||
|
||||
}
|
||||
|
||||
make_file_buffer_panel :: proc(buffer_index: int) -> core.Panel {
|
||||
input_map := core.new_input_map()
|
||||
|
||||
|
@ -256,15 +276,19 @@ make_file_buffer_panel :: proc(buffer_index: int) -> core.Panel {
|
|||
|
||||
make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
||||
query_arena: mem.Arena
|
||||
mem.arena_init(&query_arena, make([]u8, 1024*1024, state.ctx.allocator))
|
||||
mem.arena_init(&query_arena, make([]u8, 1024*1024*2, state.ctx.allocator))
|
||||
|
||||
glyphs := core.make_glyph_buffer(256,256, allocator = mem.arena_allocator(&query_arena))
|
||||
|
||||
input_map := core.new_input_map()
|
||||
grep_input_buffer := core.new_virtual_file_buffer(context.allocator)
|
||||
runtime.append(&state.buffers, grep_input_buffer)
|
||||
|
||||
run_query :: proc(panel_state: ^core.GrepPanel, query: string, directory: string) {
|
||||
mem.arena_free_all(&panel_state.query_arena)
|
||||
panel_state.query_results = nil
|
||||
if panel_state.query_region.arena != nil {
|
||||
mem.end_arena_temp_memory(panel_state.query_region)
|
||||
}
|
||||
panel_state.query_region = mem.begin_arena_temp_memory(&panel_state.query_arena)
|
||||
|
||||
context.allocator = mem.arena_allocator(&panel_state.query_arena)
|
||||
|
||||
|
@ -275,6 +299,13 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
|||
|
||||
panel_state.query_results = rs_grep_as_results(&rs_results)
|
||||
free_grep_results(rs_results)
|
||||
|
||||
panel_state.selected_result = 0
|
||||
core.update_glyph_buffer_from_bytes(
|
||||
&panel_state.glyphs,
|
||||
transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context,
|
||||
panel_state.query_results[panel_state.selected_result].line,
|
||||
)
|
||||
}
|
||||
|
||||
core.register_key_action(&input_map.mode[.Normal], .ENTER, proc(state: ^core.State) {
|
||||
|
@ -308,6 +339,12 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
|||
if panel_state, ok := ¤t_panel.panel_state.(core.GrepPanel); ok {
|
||||
// TODO: bounds checking
|
||||
panel_state.selected_result -= 1
|
||||
|
||||
core.update_glyph_buffer_from_bytes(
|
||||
&panel_state.glyphs,
|
||||
transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context,
|
||||
panel_state.query_results[panel_state.selected_result].line,
|
||||
)
|
||||
}
|
||||
}
|
||||
}, "move selection up");
|
||||
|
@ -318,6 +355,12 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
|||
if panel_state, ok := ¤t_panel.panel_state.(core.GrepPanel); ok {
|
||||
// TODO: bounds checking
|
||||
panel_state.selected_result += 1
|
||||
|
||||
core.update_glyph_buffer_from_bytes(
|
||||
&panel_state.glyphs,
|
||||
transmute([]u8)panel_state.query_results[panel_state.selected_result].file_context,
|
||||
panel_state.query_results[panel_state.selected_result].line,
|
||||
)
|
||||
}
|
||||
}
|
||||
}, "move selection down");
|
||||
|
@ -338,6 +381,7 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
|||
query_arena = query_arena,
|
||||
buffer = len(state.buffers)-1,
|
||||
query_results = nil,
|
||||
glyphs = glyphs,
|
||||
},
|
||||
input_map = input_map,
|
||||
buffer_proc = proc(state: ^core.State, panel_state: ^core.PanelState) -> (buffer: ^core.FileBuffer, ok: bool) {
|
||||
|
@ -357,8 +401,7 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
|||
}
|
||||
},
|
||||
render_proc = proc(state: ^core.State, panel_state: ^core.PanelState) -> (ok: bool) {
|
||||
panel_state := panel_state.(core.GrepPanel) or_return;
|
||||
|
||||
if panel_state, ok := &panel_state.(core.GrepPanel); ok {
|
||||
s := transmute(^ui.State)state.ui
|
||||
|
||||
ui.open_element(s, nil, {
|
||||
|
@ -405,10 +448,7 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
|||
|
||||
// file contents
|
||||
selected_result := &panel_state.query_results[panel_state.selected_result]
|
||||
ui.open_element(s, selected_result.file_context, {
|
||||
kind = {ui.Grow{}, ui.Grow{}}
|
||||
})
|
||||
ui.close_element(s)
|
||||
render_glyph_buffer(state, s, &panel_state.glyphs)
|
||||
}
|
||||
}
|
||||
ui.close_element(s)
|
||||
|
@ -427,5 +467,8 @@ make_grep_panel :: proc(state: ^core.State) -> core.Panel {
|
|||
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -49,7 +49,8 @@ impl Match {
|
|||
let column = value.bytes_range_in_buffer().len() as u64;
|
||||
|
||||
Ok(Self {
|
||||
text: line,
|
||||
// TODO: only return N-lines of context instead of the entire freakin' buffer
|
||||
text: value.buffer().to_vec(),
|
||||
path: path.unwrap_or_default(),
|
||||
line_number: value.line_number(),
|
||||
column,
|
||||
|
|
|
@ -322,23 +322,48 @@ delete_across_slices :: proc(t: ^testing.T) {
|
|||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||
}
|
||||
|
||||
// @(test)
|
||||
// insert_line_under_current :: proc(t: ^testing.T) {
|
||||
// e := new_test_editor()
|
||||
// setup_empty_buffer(&e)
|
||||
@(test)
|
||||
move_down_next_line_has_shorter_length :: proc(t: ^testing.T) {
|
||||
e := new_test_editor()
|
||||
setup_empty_buffer(&e)
|
||||
|
||||
// buffer := &e.buffers[0]
|
||||
is_ctrl_pressed := false
|
||||
|
||||
// inputted_text := "Hello, world!\nThis is a new line"
|
||||
// expected_text := fmt.aprintf("%v\n", inputted_text)
|
||||
// run_text_insertion(&e, inputted_text)
|
||||
buffer := &e.buffers[0]
|
||||
|
||||
// expect_line_col(t, buffer.cursor, 1, 17)
|
||||
// expect_cursor_index(t, buffer.cursor, 0, 31)
|
||||
run_text_insertion(&e, "012345678\n0")
|
||||
|
||||
// contents := buffer_to_string(core.current_buffer(&e))
|
||||
// testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||
// }
|
||||
// Move up to the first line
|
||||
run_input_multiple(&e, press_key(.K), 1)
|
||||
|
||||
// Move to the end of the line
|
||||
run_inputs(&e, []ArtificialInput{ press_key(.G), press_key(.L)})
|
||||
|
||||
// Move down to the second line
|
||||
run_input_multiple(&e, press_key(.J), 1)
|
||||
|
||||
expect_line_col(t, buffer.cursor, 1, 0)
|
||||
expect_cursor_index(t, buffer.cursor, 0, 10)
|
||||
}
|
||||
|
||||
@(test)
|
||||
move_down_on_last_line :: proc(t: ^testing.T) {
|
||||
e := new_test_editor()
|
||||
setup_empty_buffer(&e)
|
||||
|
||||
is_ctrl_pressed := false
|
||||
|
||||
buffer := &e.buffers[0]
|
||||
|
||||
run_text_insertion(&e, "012345678")
|
||||
|
||||
// Try to move down
|
||||
run_input_multiple(&e, press_key(.J), 1)
|
||||
|
||||
// Cursor should stay where it is
|
||||
expect_line_col(t, buffer.cursor, 0, 8)
|
||||
expect_cursor_index(t, buffer.cursor, 0, 8)
|
||||
}
|
||||
|
||||
@(test)
|
||||
move_left_at_beginning_of_file :: proc(t: ^testing.T) {
|
||||
|
@ -478,6 +503,42 @@ move_to_beginning_of_line_from_start :: proc(t: ^testing.T) {
|
|||
expect_cursor_index(t, buffer.cursor, 0, 0)
|
||||
}
|
||||
|
||||
@(test)
|
||||
insert_line_under_current :: proc(t: ^testing.T) {
|
||||
e := new_test_editor()
|
||||
setup_empty_buffer(&e)
|
||||
|
||||
buffer := &e.buffers[0]
|
||||
|
||||
initial_text := "Hello, world!\nThis is a new line"
|
||||
run_text_insertion(&e, initial_text)
|
||||
|
||||
expected_text := "Hello, world!\nThis is the second line\nThis is a new line\n"
|
||||
// ------------- ----------------------
|
||||
// -------------------------
|
||||
// 0 1 3
|
||||
|
||||
// Move cursor up onto the end of "Hello, world!"
|
||||
run_input_multiple(&e, press_key(.K), 1)
|
||||
|
||||
// Insert line below and enter insert mode
|
||||
run_input_multiple(&e, press_key(.O), 1)
|
||||
|
||||
// Technically the cursor is still on the first line, because the `input_buffer`
|
||||
// has been modified but not the actual contents of the filebuffer
|
||||
expect_line_col(t, buffer.cursor, 0, 13)
|
||||
expect_cursor_index(t, buffer.cursor, 0, 13)
|
||||
|
||||
run_text_insertion(&e, "This is the second line")
|
||||
|
||||
expect_line_col(t, buffer.cursor, 1, 22)
|
||||
expect_cursor_index(t, buffer.cursor, 1, 23)
|
||||
|
||||
contents := buffer_to_string(core.current_buffer(&e))
|
||||
testing.expectf(t, contents == expected_text, "got '%v', expected '%v'", contents, expected_text)
|
||||
}
|
||||
|
||||
|
||||
run_editor_frame :: proc(state: ^core.State, input: ArtificialInput, is_ctrl_pressed: ^bool) {
|
||||
log.infof("running input: %v", input)
|
||||
|
||||
|
|
Loading…
Reference in New Issue