WIP layout engine
This commit is contained in:
+183
@@ -0,0 +1,183 @@
|
||||
open Unix
|
||||
|
||||
(* type coords = int * int *)
|
||||
type offset = { x : int; y : int }
|
||||
type ansirgb = int * int * int
|
||||
|
||||
type cursor_ops = Hide | Show | Move of offset
|
||||
type screen_ops = Clear
|
||||
|
||||
type color =
|
||||
| Black
|
||||
| Red
|
||||
| Green
|
||||
| Yellow
|
||||
| Blue
|
||||
| Magenta
|
||||
| Cyan
|
||||
| White
|
||||
| Gray
|
||||
| BrightRed
|
||||
| BrightGreen
|
||||
| BrightYellow
|
||||
| BrightBlue
|
||||
| BrightMagenta
|
||||
| BrightCyan
|
||||
| BrightWhite
|
||||
| Default
|
||||
| Custom of ansirgb
|
||||
|
||||
type color_style =
|
||||
| Foreground of color
|
||||
| Background of color
|
||||
|
||||
type style =
|
||||
| Reset
|
||||
| Bold
|
||||
| Underlined
|
||||
| Blink
|
||||
| Inverse
|
||||
| Hidden
|
||||
|
||||
type ansi =
|
||||
| Cursor of cursor_ops
|
||||
| Screen of screen_ops
|
||||
| ColorStyle of color_style
|
||||
| Style of style
|
||||
|
||||
let top_block = "▀"
|
||||
let bot_block = "▄"
|
||||
let block = "█"
|
||||
|
||||
let black = Foreground Black
|
||||
let red = Foreground Red
|
||||
let green = Foreground Green
|
||||
let yellow = Foreground Yellow
|
||||
let blue = Foreground Blue
|
||||
let magenta = Foreground Magenta
|
||||
let cyan = Foreground Cyan
|
||||
let white = Foreground White
|
||||
let default = Foreground Default
|
||||
let bg_black = Background Black
|
||||
let bg_red = Background Red
|
||||
let bg_green = Background Green
|
||||
let bg_yellow = Background Yellow
|
||||
let bg_blue = Background Blue
|
||||
let bg_magenta = Background Magenta
|
||||
let bg_cyan = Background Cyan
|
||||
let bg_white = Background White
|
||||
let bg_default = Background Default
|
||||
|
||||
let is_valid_rgb = function x when x > 5 || x < 0 -> false | _ -> true
|
||||
|
||||
let rgb_to_ansi (rgb : ansirgb) =
|
||||
let rr, gg, bb = rgb in
|
||||
if is_valid_rgb rr && is_valid_rgb gg && is_valid_rgb bb then
|
||||
Ok (16 + (36 * rr) + (6 * gg) + bb)
|
||||
else Error "Invalid r, g, or b value provided (must be between 0-5)"
|
||||
|
||||
let screenop_to_ansi = function Clear -> "\027[2J"
|
||||
|
||||
let cursorop_to_ansi = function
|
||||
| Show -> "\027[?25h"
|
||||
| Hide -> "\027[?25l"
|
||||
| Move coord -> Printf.sprintf "\027[%d;%dH" coord.y coord.x
|
||||
|
||||
(* Function to get the ANSI escape code for a color *)
|
||||
let color_to_ansi = function
|
||||
| Black -> "\027[30m"
|
||||
| Red -> "\027[31m"
|
||||
| Green -> "\027[32m"
|
||||
| Yellow -> "\027[33m"
|
||||
| Blue -> "\027[34m"
|
||||
| Magenta -> "\027[35m"
|
||||
| Cyan -> "\027[36m"
|
||||
| White -> "\027[37m"
|
||||
| Gray -> "\027[90m"
|
||||
| BrightRed -> "\027[91m"
|
||||
| BrightGreen -> "\027[92m"
|
||||
| BrightYellow -> "\027[9m"
|
||||
| BrightBlue -> "\027[94m"
|
||||
| BrightMagenta -> "\027[95m"
|
||||
| BrightCyan -> "\027[96m"
|
||||
| BrightWhite -> "\027[97m"
|
||||
| Default -> "\027[39m" (* Reset to default foreground color *)
|
||||
| Custom rgb -> (
|
||||
let ansi = rgb_to_ansi rgb in
|
||||
match ansi with Ok s -> Printf.sprintf "\027[38m;5;%d" s | Error _ -> "")
|
||||
|
||||
let bgcolor_to_ansi = function
|
||||
| Black -> "\027[40m"
|
||||
| Red -> "\027[41m"
|
||||
| Green -> "\027[42m"
|
||||
| Yellow -> "\027[4m"
|
||||
| Blue -> "\027[44m"
|
||||
| Magenta -> "\027[45m"
|
||||
| Cyan -> "\027[46m"
|
||||
| White -> "\027[47m"
|
||||
| Gray -> "\027[100m"
|
||||
| BrightRed -> "\027[101m"
|
||||
| BrightGreen -> "\027[102m"
|
||||
| BrightYellow -> "\027[10m"
|
||||
| BrightBlue -> "\027[10m"
|
||||
| BrightMagenta -> "\027[105m"
|
||||
| BrightCyan -> "\027[106m"
|
||||
| BrightWhite -> "\027[107m"
|
||||
| Default -> "\027[49m" (* Reset to default background color *)
|
||||
| Custom rgb -> (
|
||||
let ansi = rgb_to_ansi rgb in
|
||||
match ansi with Ok s -> Printf.sprintf "\027[48m;5;%d" s | Error _ -> "")
|
||||
|
||||
(* Function to get the ANSI escape code for a style *)
|
||||
let style_to_ansi = function
|
||||
| Reset -> "\027[0m"
|
||||
| Bold -> "\027[1m"
|
||||
| Underlined -> "\027[4m"
|
||||
| Blink -> "\027[5m"
|
||||
| Inverse -> "\027[7m"
|
||||
| Hidden -> "\027[8m"
|
||||
|
||||
let color_style_to_ansi = function
|
||||
| Foreground color -> color_to_ansi color
|
||||
| Background color -> bgcolor_to_ansi color
|
||||
(* You would define background colors as well *)
|
||||
|
||||
let string_of_ansi = function
|
||||
| ColorStyle op -> color_style_to_ansi op
|
||||
| Cursor op -> cursorop_to_ansi op
|
||||
| Style op -> style_to_ansi op
|
||||
| Screen op -> screenop_to_ansi op
|
||||
|
||||
(* let cus_for = color_to_ansi Foreground Custom (3; 4; 1)) *)
|
||||
let pixel_ansi offset color_style =
|
||||
let color_ansi = color_style_to_ansi color_style in
|
||||
let move_ansi = cursorop_to_ansi (Move offset) in
|
||||
let ansi = Printf.sprintf "%s%s%s" move_ansi color_ansi block in
|
||||
ansi
|
||||
|
||||
(* Gets the terminal height and width from running `stty size` *)
|
||||
let termsize: offset =
|
||||
let command = "stty size" in
|
||||
let in_channel = open_process_in command in
|
||||
try
|
||||
let line = input_line in_channel in
|
||||
close_in in_channel;
|
||||
let parts = String.split_on_char ' ' line in
|
||||
match parts with
|
||||
| [height; width] ->
|
||||
{x = (int_of_string width); y = (int_of_string height)}
|
||||
| _ ->
|
||||
let msg = Printf.sprintf "Unexpected output from stty size: %s" line in
|
||||
failwith msg
|
||||
with
|
||||
| End_of_file ->
|
||||
close_in in_channel;
|
||||
failwith "No output from `stty size`"
|
||||
| Sys_error msg ->
|
||||
close_in in_channel;
|
||||
Printf.eprintf "Error reading input: %s\n" msg;
|
||||
failwith "Failed to get terminal size"
|
||||
| Failure msg ->
|
||||
Printf.eprintf "Error converting size to int: %s\n" msg;
|
||||
failwith "Failed to parse terminal size"
|
||||
|
||||
Reference in New Issue
Block a user