Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Basic notty integration #1

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions examples/dune
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
(executable
(name icat)
(modules icat)
(libraries kittyimg stb_image))

(executable
(name nottycat)
(modules nottycat)
(libraries notty notty.unix kittyimg.notty stb_image))
17 changes: 17 additions & 0 deletions examples/nottycat.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
let icat filename =
let img = Result.get_ok (Stb_image.load ~channels:4 filename) in
let img_s = Kittyimg.string_of_bytes_ba img.Stb_image.data in
let img =
Nottyimg.of_string ~w:img.Stb_image.width ~h:img.Stb_image.height
~format:`RGBA img_s
in
let open Notty in
let blanks n = I.(vcat @@ List.init n (fun _ -> string A.empty "")) in
I.((img <-> blanks 2 <-> string A.empty "Woop woop!") <|> (blanks 4 <-> img))
|> Notty_unix.output_image

let () =
match Array.to_list Sys.argv |> List.tl with
| [ filename ] -> icat filename
| _ ->
Printf.eprintf "usage: %s <imagefile>\n" Sys.argv.(0); exit 1
28 changes: 27 additions & 1 deletion lib/dune
Original file line number Diff line number Diff line change
@@ -1,4 +1,30 @@
(library
(libraries base64)
(name kittyimg)
(public_name kittyimg))
(public_name kittyimg)
(modules kittyimg))

(library
(libraries kittyimg notty unix)
(name nottyimg)
(public_name kittyimg.notty)
(modules :standard \ kittyimg)
(foreign_stubs (language c) (names more_winsize)))

(rule
(target rowcolumn-diacritics.txt)
(action
(with-stdout-to
%{target}
(bash "curl https://sw.kovidgoyal.net/kitty/_downloads/f0a0de9ec8d9ff4456206db8e0814937/rowcolumn-diacritics.txt"))))

(rule
(target rowcolumns.ml)
(deps rowcolumn-diacritics.txt)
(action
(with-stdout-to
%{target}
(progn
(echo "let diacritics = [|\n")
(bash "tail -n +14 %{deps} | less | cut -d';' -f1 | sed 's/.*/ Uchar.of_int 0x\\0;/g'")
(echo "|]")))))
6 changes: 4 additions & 2 deletions lib/kittyimg.ml
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ end

type display_opts = {
placement : Placement.t option;
virtual_placement : unit option;
(* source rectangle *)
x : int option;
y : int option;
Expand All @@ -62,7 +63,7 @@ type display_opts = {
}

let display_opts
?placement
?placement ?virtual_placement
?x ?y ?w ?h
?xoff ?yoff
?cstretch ?rstretch
Expand All @@ -71,12 +72,13 @@ let display_opts
?quiet
()
=
{ placement; x; y; w; h; xoff; yoff;
{ placement; virtual_placement; x; y; w; h; xoff; yoff;
cstretch; rstretch; move_cursor; zindex; quiet }

let items_of_display_opts opts =
[
'p', (opts.placement :> int option);
'U', Option.map (fun () -> 1) opts.virtual_placement;
'x', opts.x;
'y', opts.y;
'w', opts.w;
Expand Down
1 change: 1 addition & 0 deletions lib/kittyimg.mli
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ type display_opts

val display_opts :
?placement:Placement.t ->
?virtual_placement:unit ->
?x:int -> ?y:int ->
?w:int -> ?h:int ->
?xoff:int -> ?yoff:int ->
Expand Down
27 changes: 27 additions & 0 deletions lib/more_winsize.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
#include <sys/ioctl.h>
#include <caml/mlvalues.h>
#include <caml/alloc.h>
#include <caml/fail.h>
#include <caml/memory.h>

CAMLprim value caml_kittyimg_winsize (value vfd) {
CAMLparam1 (vfd);

int fd = Int_val (vfd);
struct winsize w;

if (ioctl (fd, TIOCGWINSZ, &w) >= 0) {
CAMLlocal1 (result);
result = caml_alloc_tuple(4);

Store_field (result, 0, Val_int (w.ws_col));
Store_field (result, 1, Val_int (w.ws_row));
Store_field (result, 2, Val_int (w.ws_xpixel));
Store_field (result, 3, Val_int (w.ws_ypixel));

CAMLreturn (result);
}

caml_failwith("couldn't get winsize\0");
}

72 changes: 72 additions & 0 deletions lib/nottyimg.ml
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
module K = Kittyimg
module RC = Rowcolumns

exception Too_many_images

module Ids = struct
type t = Notty.A.color

let state = ref (0,0,0)

let incr () =
let (r,g,b) = !state in
let b,g = if b = 5 then 0, g + 1 else b + 1, g in
let g,r = if g > 5 then 0, r + 1 else g, r in
if r > 5 then
raise Too_many_images
else
state := (r,g,b)

let fresh () =
let (r,g,b) = !state in
let id = Notty.A.rgb ~r ~g ~b in
incr ();
id

let to_kittyid i = K.Id.of_int (Obj.magic i land 0xff)
end

let placeholder = Uchar.of_int 0x10EEEE

external wsize : Unix.file_descr -> int * int * int * int =
"caml_kittyimg_winsize"

(* Haaaaacky *)
let winsize = wsize (Unix.descr_of_out_channel stdout)

let width_to_cols iw =
let (c,_,w,_) = winsize in
Float.round (float iw /. (float w /. float c))
|> Float.to_int

let height_to_rows ih =
let (_,r,_,h) = winsize in
Float.round (float ih /. (float h /. float r))
|> Float.to_int

let of_string ~w ~h ~format data =
let id = Ids.fresh () in
(* Load image *)
K.send_image ~w ~h ~format ~quiet:`OK ~mode:(`Store (Ids.to_kittyid id)) data;
(* Create virtual placement *)
let c = width_to_cols w in
let r = height_to_rows h in
let opts =
K.display_opts ~virtual_placement:() ~cstretch:c ~rstretch:r
~quiet:`Failure ()
in
K.display_image ~opts (Ids.to_kittyid id);
(* Create placeholder as a notty I.t *)
let id_as_attr = Notty.A.fg id in
let rows =
List.init r (fun row ->
let row = RC.diacritics.(row) in
let line = Array.make (c * 3) placeholder in
for i = 0 to c - 1 do
line.(i * 3 + 1) <- row;
line.(i * 3 + 2) <- RC.diacritics.(i);
done;
Notty.I.uchars id_as_attr line
)
in
Notty.I.vcat rows