diff options
Diffstat (limited to 'mirai.old/graphics/terminal/terminal.zig')
| -rw-r--r-- | mirai.old/graphics/terminal/terminal.zig | 184 |
1 files changed, 184 insertions, 0 deletions
diff --git a/mirai.old/graphics/terminal/terminal.zig b/mirai.old/graphics/terminal/terminal.zig new file mode 100644 index 0000000..f1f2e8f --- /dev/null +++ b/mirai.old/graphics/terminal/terminal.zig @@ -0,0 +1,184 @@ +//! Terminal - Console output with cursor and scrolling + +const ascii = @import("../../common/constants/ascii.zig"); +const boot = @import("../../boot/multiboot/multiboot.zig"); +const colors = @import("../../common/constants/colors.zig"); +const font = @import("../fonts/psf.zig"); +const pixel = @import("../../utils/graphics/pixel.zig"); +const terminal_limits = @import("../../common/limits/terminal.zig"); +const video = @import("../video/video.zig"); + +const LineType = enum { Hard, Soft }; + +var fb: ?boot.FramebufferInfo = null; +var cursor_x: u32 = 0; +var cursor_y: u32 = 0; +var char_width: u32 = terminal_limits.DEFAULT_CHAR_WIDTH; +var char_height: u32 = terminal_limits.DEFAULT_CHAR_HEIGHT; +var max_line_width: u32 = 0; +var line_types: [terminal_limits.MAX_LINES]LineType = [_]LineType{.Hard} ** terminal_limits.MAX_LINES; +var current_line: usize = 0; + +pub fn init(framebuffer: boot.FramebufferInfo) void { + fb = framebuffer; + cursor_x = 0; + cursor_y = 0; + current_line = 0; + + char_width = font.get_width(); + char_height = font.get_height(); + max_line_width = pixel.line_width(framebuffer); + + video.init(framebuffer); + video.clear(colors.BLACK); + + reset_line_types(); +} + +fn reset_line_types() void { + for (&line_types) |*lt| { + lt.* = .Hard; + } +} + +pub fn put_char(char: u8) void { + put_char_color(char, colors.WHITE); +} + +pub fn put_char_color(char: u8, color: u32) void { + const f = fb orelse return; + + switch (char) { + ascii.NEWLINE => handle_newline(f), + ascii.BACKSPACE => handle_backspace(f), + ascii.TAB => handle_tab(f), + else => handle_printable(f, char, color), + } +} + +fn handle_newline(f: boot.FramebufferInfo) void { + cursor_x = 0; + cursor_y += char_height; + mark_line(.Hard); + check_scroll(f); +} + +fn handle_backspace(f: boot.FramebufferInfo) void { + if (cursor_x >= char_width) { + cursor_x -= char_width; + clear_char_at_cursor(f); + } else if (cursor_x == 0 and cursor_y > 0) { + const line_num = cursor_y / char_height; + if (line_num > 0 and line_num < terminal_limits.MAX_LINES) { + if (line_types[line_num] == .Soft) { + cursor_y -= char_height; + current_line = cursor_y / char_height; + cursor_x = ((max_line_width - char_width) / char_width) * char_width; + clear_char_at_cursor(f); + } + } + } +} + +fn handle_tab(f: boot.FramebufferInfo) void { + cursor_x += char_width * terminal_limits.TAB_WIDTH; + if (cursor_x >= max_line_width) { + cursor_x = 0; + cursor_y += char_height; + mark_line(.Soft); + check_scroll(f); + } +} + +fn handle_printable(f: boot.FramebufferInfo, char: u8, color: u32) void { + if (char < ascii.PRINTABLE_START or char > ascii.PRINTABLE_END) return; + + if (cursor_x + char_width > max_line_width) { + cursor_x = 0; + cursor_y += char_height; + mark_line(.Soft); + check_scroll(f); + } + + font.render_char(char, cursor_x, cursor_y, f, color); + cursor_x += char_width; +} + +fn mark_line(line_type: LineType) void { + const new_line = cursor_y / char_height; + if (new_line != current_line and new_line < terminal_limits.MAX_LINES) { + line_types[new_line] = line_type; + } + current_line = new_line; +} + +fn check_scroll(f: boot.FramebufferInfo) void { + if (cursor_y + char_height >= f.height) { + scroll(f); + } +} + +fn clear_char_at_cursor(f: boot.FramebufferInfo) void { + pixel.fill_rect(f, cursor_x, cursor_y, char_width, char_height, colors.BLACK); +} + +fn scroll(f: boot.FramebufferInfo) void { + var dst_y: u32 = 0; + var src_y: u32 = char_height; + + while (src_y < f.height) : ({ + src_y += 1; + dst_y += 1; + }) { + pixel.copy_row(f, dst_y, src_y); + } + + while (dst_y < f.height) : (dst_y += 1) { + pixel.clear_row(f, dst_y, colors.BLACK); + } + + cursor_y -= char_height; + + var i: usize = 1; + while (i < terminal_limits.MAX_LINES) : (i += 1) { + line_types[i - 1] = line_types[i]; + } + line_types[terminal_limits.MAX_LINES - 1] = .Hard; + + if (current_line > 0) current_line -= 1; +} + +pub fn print(text: []const u8) void { + for (text) |char| { + put_char(char); + } +} + +pub fn print_color(text: []const u8, color: u32) void { + for (text) |char| { + put_char_color(char, color); + } +} + +pub fn clear_screen() void { + const f = fb orelse return; + + pixel.fill(f, colors.BLACK); + cursor_x = 0; + cursor_y = 0; + current_line = 0; + reset_line_types(); +} + +pub fn get_cursor_x() u32 { + return cursor_x; +} + +pub fn get_cursor_y() u32 { + return cursor_y; +} + +pub fn set_cursor(x: u32, y: u32) void { + cursor_x = x; + cursor_y = y; +} |
