12 Commits

Author SHA1 Message Date
cqc
b705c598ff use main branch 2022-11-17 20:25:20 -06:00
cqc
9d1ccb93b5 little re-arranging 2022-11-17 20:16:15 -06:00
cqc
3fc8125d42 lol browser requests github repo via cors proxy (via npm, run with ./cors_proxy.sh) but then stack overflows 2022-11-08 22:06:58 -06:00
cqc
3b09bb1c11 works 2022-10-06 14:29:57 -05:00
cqc
281351371d Irmin_git.KV (Irmin_git.Mem) (Git.Mem.Sync (Irmin_git.Mem)) results in a.caml_thread_initialize is not a function 2022-10-06 12:18:32 -05:00
cqc
fec4249d9f irmin 2022-10-04 23:36:25 -05:00
cqc
65aa7ff901 character insertion 2022-09-03 15:20:22 -05:00
cqc
39193ff253 cursor works 2022-09-03 11:24:34 -05:00
cqc
399280d9c4 correct? rendering 2022-09-02 21:34:47 -05:00
cqc
6a484c3a06 it renders text, but wrong 2022-09-02 19:22:06 -05:00
cqc
7460b8f793 halfway to graphv_webgl replacing wall 2022-08-31 12:32:44 -05:00
cqc
c40e725978 uhh 2022-08-06 12:03:33 -05:00
11 changed files with 2096 additions and 1814 deletions

View File

@ -1 +0,0 @@
profile = compact

205
backend.ml Normal file
View File

@ -0,0 +1,205 @@
module F = Fmt
module Key = struct
type special =
[ `Enter
| `Escape
| `Tab
| `Arrow of [`Up | `Down | `Left | `Right]
| `Function of int
| `Page of [`Up | `Down]
| `Home
| `End
| `Insert
| `Delete
| `Backspace ]
(** Type of key code. *)
type code =
[`Uchar of Uchar.t (** A unicode character. *) | special]
type keystate =
{ctrl: bool; meta: bool; shift: bool; super: bool; code: code}
module KeyS = struct
type t = keystate
let compare = compare
end
module Bind = struct
(* parts stolen from lambda-term/src/lTerm_{edit,key}.ml{,i} *)
module S = Zed_input.Make (KeyS)
type 'a t = 'a list S.t
type 'a resolver = 'a list S.resolver
type 'a result = 'a list S.result
type 'a state =
{ mutable bindings: 'a t
; mutable state: 'a result
; mutable last_keyseq: keystate list
; mutable last_actions: 'a list }
type mods = Ctrl | Meta | Super | Shift
type key = C of char | U of code
let keystate_of_mods ks m =
List.fold_left
(fun ks m ->
match m with
| Meta -> {ks with meta= true}
| Ctrl -> {ks with ctrl= true}
| Super -> {ks with super= true}
| Shift -> {ks with shift= true} )
ks m
let add events action bindings =
let events =
List.map
(fun (m, k) ->
keystate_of_mods
{ meta= false
; ctrl= false
; super= false
; shift= false
; code=
( match k with
| C c -> `Uchar (Uchar.of_char c)
| U c -> c ) }
m )
events in
S.add events action bindings
let default_resolver b = S.resolver [S.pack (fun x -> x) b]
let get_resolver result default =
match result with S.Continue r -> r | _ -> default
let init bindings =
{bindings; state= S.Rejected; last_keyseq= []; last_actions= []}
let resolve = S.resolve
let empty = S.empty
type action =
| Custom of (unit -> unit)
| CustomLwt of (unit -> unit Lwt.t)
| Zed of Zed_edit.action
let resolve_events (state : 'a state) events =
List.flatten
(List.filter_map
(fun e ->
match e with
| `Key (`Press, (k : keystate)) -> (
( match state.state with
| Continue _ -> ()
| _ -> state.last_keyseq <- [] ) ;
state.state <-
resolve k
(get_resolver state.state
(default_resolver state.bindings) ) ;
state.last_keyseq <- k :: state.last_keyseq ;
match state.state with
| Accepted a ->
state.last_actions <- a ;
Some a
| Rejected ->
state.last_actions <- [] ;
None
| _ -> None )
| _ -> None )
events )
let actions_of_events (state : action state) events =
List.flatten
(List.filter_map
(fun e ->
match e with
| `Key (`Press, (k : keystate)) -> (
( match state.state with
| Continue _ -> ()
| _ -> state.last_keyseq <- [] ) ;
state.state <-
resolve k
(get_resolver state.state
(default_resolver state.bindings) ) ;
state.last_keyseq <- k :: state.last_keyseq ;
match state.state with
| Accepted a ->
state.last_actions <- a ;
Some a
| Rejected ->
state.last_actions <- [] ;
None
| _ -> None )
| _ -> None )
events )
let process bindstate events =
Lwt_list.iter_s
(function
| Custom f -> Lwt.return (f ())
| CustomLwt f -> f ()
| Zed _ -> Lwt.return_unit )
(actions_of_events bindstate events)
end
(* stolen from lambda-term/src/lTerm_{edit,key}.ml{,i} *)
let string_of_code = function
| `Uchar ch ->
if Uchar.is_char ch then F.str "Char '%c'" (Uchar.to_char ch)
else F.str "Char 0x%02x" (Uchar.to_int ch)
| `Enter -> "Enter"
| `Escape -> "Escape"
| `Tab -> "Tab"
| `Arrow `Up -> "Up"
| `Arrow `Down -> "Down"
| `Arrow `Left -> "Left"
| `Arrow `Right -> "Right"
| `Function i -> F.str "F%d" i
| `Page `Up -> "Page Up"
| `Page `Down -> "Page Down"
| `Home -> "Home"
| `End -> "End"
| `Insert -> "Insert"
| `Delete -> "Delete"
| `Backspace -> "Backspace"
let to_string key =
Printf.sprintf
"{ control = %B; meta = %B; shift = %B; super = %B; code = %s }"
key.ctrl key.meta key.shift key.super
(string_of_code key.code)
let to_string_compact key =
let buffer = Buffer.create 32 in
if key.ctrl then Buffer.add_string buffer "Ctrl-" ;
if key.meta then Buffer.add_string buffer "Meta-" ;
if key.shift then Buffer.add_string buffer "Shift-" ;
if key.super then Buffer.add_string buffer "Super-" ;
( match key.code with
| `Uchar ch ->
let code = Uchar.to_int ch in
if Uchar.is_char ch then
match Uchar.to_char ch with
| ( 'a' .. 'z'
| 'A' .. 'Z'
| '0' .. '9'
| '_' | '(' | ')' | '[' | ']' | '{' | '}' | '#' | '~'
| '&' | '$' | '*' | '%' | '!' | '?' | ',' | ';' | ':'
| '/' | '\\' | '.' | '@' | '=' | '+' | '-' ) as ch ->
Buffer.add_char buffer ch
| ' ' -> Buffer.add_string buffer "space"
| _ -> Printf.bprintf buffer "U+%02x" code
else if code <= 0xffff then
Printf.bprintf buffer "U+%04x" code
else Printf.bprintf buffer "U+%06x" code
| `Page `Down -> Buffer.add_string buffer "pgup"
| `Page `Up -> Buffer.add_string buffer "pgdn"
| code ->
Buffer.add_string buffer
(String.lowercase_ascii (string_of_code code)) ) ;
Buffer.contents buffer
end

7
backend_js.ml Normal file
View File

@ -0,0 +1,7 @@
include Backend
module Keycode = struct
open Js_of_ocaml
type t = Dom_html.Keyboard_code.t
end

438
backend_sdl.ml Normal file
View File

@ -0,0 +1,438 @@
module Key = struct
let sdlkey_map = Hashtbl.create 1024
let () =
let aa (x : int) (y : Key.code) = Hashtbl.add sdlkey_map x y in
aa return `Enter ;
aa escape `Escape ;
aa backspace `Backspace ;
aa tab `Tab ;
aa f1 (`Function 1) ;
aa f2 (`Function 2) ;
aa f3 (`Function 3) ;
aa f4 (`Function 4) ;
aa f5 (`Function 5) ;
aa f6 (`Function 6) ;
aa f7 (`Function 7) ;
aa f8 (`Function 8) ;
aa f9 (`Function 9) ;
aa f10 (`Function 10) ;
aa f11 (`Function 11) ;
aa f12 (`Function 12) ;
aa insert `Insert ;
aa delete `Delete ;
aa home `Home ;
aa kend `End ;
aa pageup (`Page `Up) ;
aa pagedown (`Page `Down) ;
aa right (`Arrow `Right) ;
aa left (`Arrow `Left) ;
aa down (`Arrow `Down) ;
aa up (`Arrow `Up)
let key_of_sdlkey ev =
let (kc : Sdl.keycode) =
Sdl.Event.get ev Sdl.Event.keyboard_keycode
land lnot Sdl.K.scancode_mask in
match (Hashtbl.find_opt sdlkey_map kc, Uchar.is_valid kc) with
| Some s, _ -> Some s
| None, true -> Some (`Uchar (Uchar.of_int kc))
| None, false -> None
let event_of_sdlevent ev : t option =
match Sdl.Event.enum (Sdl.Event.get ev Sdl.Event.typ) with
| (`Key_down | `Key_up) as d -> (
match key_of_sdlkey ev with
| None -> None
| Some code ->
let km = Sdl.Event.get ev Sdl.Event.keyboard_keymod in
Some
(`Key
( ( match d with
| _
when Sdl.Event.get ev Sdl.Event.keyboard_repeat > 1
->
`Repeat
| `Key_up -> `Release
| _ -> `Press )
, { code
; ctrl= km land Sdl.Kmod.ctrl > 0
; meta= km land Sdl.Kmod.alt > 0
; super= km land Sdl.Kmod.gui > 0
; shift= km land Sdl.Kmod.shift > 0 } ) ) )
| `Mouse_motion ->
let x, y = snd (Tsdl.Sdl.get_mouse_state ()) in
Some (`Mouse (V2.v (float x) (float y)))
| `Quit -> Some `Quit
(* Unhandled events *)
| `Text_editing -> Some (`Unknown "`Text_editing")
| `Text_input -> Some (`Unknown "`Text_input")
| `App_did_enter_background ->
Some (`Unknown "`App_did_enter_background")
| `App_did_enter_foreground ->
Some (`Unknown "`App_did_enter_foreground ")
| `App_low_memory -> Some (`Unknown "`App_low_memory ")
| `App_terminating -> Some (`Unknown "`App_terminating ")
| `App_will_enter_background ->
Some (`Unknown "`App_will_enter_background ")
| `App_will_enter_foreground ->
Some (`Unknown "`App_will_enter_foreground ")
| `Clipboard_update -> Some (`Unknown "`Clipboard_update ")
| `Controller_axis_motion ->
Some (`Unknown "`Controller_axis_motion ")
| `Controller_button_down ->
Some (`Unknown "`Controller_button_down ")
| `Controller_button_up -> Some (`Unknown "`Controller_button_up ")
| `Controller_device_added ->
Some (`Unknown "`Controller_device_added ")
| `Controller_device_remapped ->
Some (`Unknown "`Controller_device_remapped ")
| `Controller_device_removed ->
Some (`Unknown "`Controller_device_removed ")
| `Dollar_gesture -> Some (`Unknown "`Dollar_gesture ")
| `Dollar_record -> Some (`Unknown "`Dollar_record ")
| `Drop_file -> Some (`Unknown "`Drop_file ")
| `Finger_down -> Some (`Unknown "`Finger_down")
| `Finger_motion -> Some (`Unknown "`Finger_motion ")
| `Finger_up -> Some (`Unknown "`Finger_up ")
| `Joy_axis_motion -> Some (`Unknown "`Joy_axis_motion ")
| `Joy_ball_motion -> Some (`Unknown "`Joy_ball_motion ")
| `Joy_button_down -> Some (`Unknown "`Joy_button_down ")
| `Joy_button_up -> Some (`Unknown "`Joy_button_up ")
| `Joy_device_added -> Some (`Unknown "`Joy_device_added ")
| `Joy_device_removed -> Some (`Unknown "`Joy_device_removed ")
| `Joy_hat_motion -> Some (`Unknown "`Joy_hat_motion ")
| `Mouse_button_down -> Some (`Unknown "`Mouse_button_down ")
| `Mouse_button_up -> Some (`Unknown "`Mouse_button_up")
| `Mouse_wheel -> Some (`Unknown "`Mouse_wheel ")
| `Multi_gesture -> Some (`Unknown "`Multi_gesture")
| `Sys_wm_event -> Some (`Unknown "`Sys_wm_event ")
| `Unknown e -> Some (`Unknown (Format.sprintf "`Unknown %d" e))
| `User_event -> Some (`Unknown "`User_event ")
| `Display_event -> Some (`Unknown "`Display_event ")
| `Sensor_update -> Some (`Unknown "`Sensor_update ")
| `Window_event -> Some (`Unknown "`Window_event ")
let key_up : Sdl.keycode = 0x40000052
let key_down : Sdl.keycode = 0x40000051
let key_left : Sdl.keycode = 0x40000050
let key_right : Sdl.keycode = 0x4000004f
end
module Display = struct
open Tgles2
open Tsdl
open Gg
open Wall
module I = Image
module P = Path
let ( >>>= ) x f =
match x with Ok a -> f a | Error _ as result -> result
let get_result = function
| Ok x -> x
| Error (`Msg msg) -> failwith msg
(* current window state to be passed to window renderer *)
type state =
{ box: box2
(* This is cannonically box within which the next element should draw *)
; time: float
; wall: Wall.renderer }
(* the box2 here is cannonically the place the returner drew
(the Wall.image extents) *)
type image = box2 * Wall.image
type pane = state -> state * image
type actor = (Event.events -> pane Lwt.t) ref
let pane_empty s =
(s, (Box2.of_pts (Box2.o s.box) (Box2.o s.box), Image.empty))
type frame =
{ sdl_win: Sdl.window
; gl: Sdl.gl_context
; wall: Wall.renderer
; mutable last_pane: pane
; mutable quit: bool
; mutable fullscreen: bool }
let ticks () = Int32.to_float (Sdl.get_ticks ()) /. 1000.
let on_failure ~cleanup result =
(match result with Ok _ -> () | Error _ -> cleanup ()) ;
result
let video_initialized = lazy (Sdl.init Sdl.Init.video)
let make_frame ?(title = "komm") ~w ~h () =
Lazy.force video_initialized
>>>= fun () ->
Sdl.create_window ~w ~h title
Sdl.Window.(
opengl + allow_highdpi + resizable (*+ input_grabbed*))
>>>= fun sdl_win ->
Sdl.set_window_title sdl_win title ;
ignore (Sdl.gl_set_swap_interval (-1)) ;
ignore (Sdl.gl_set_attribute Sdl.Gl.stencil_size 1) ;
on_failure
( Sdl.gl_create_context sdl_win
>>>= fun gl ->
let wall =
Wall.Renderer.create ~antialias:true ~stencil_strokes:true ()
in
Ok
{ sdl_win
; gl
; wall
; quit= false
; fullscreen= false
; last_pane= pane_empty } )
~cleanup:(fun () -> Sdl.destroy_window sdl_win)
let handle_frame_events frame events =
List.iter
(fun (e : Event.t) ->
match e with
| `Quit -> frame.quit <- true
| `Fullscreen a ->
frame.fullscreen <- a ;
ignore (Sdl.show_cursor (not frame.fullscreen) : _ result) ;
ignore
( Sdl.set_window_fullscreen frame.sdl_win
( if frame.fullscreen then
Sdl.Window.fullscreen_desktop
else Sdl.Window.windowed )
: _ result )
| _ -> () )
events
let draw_pane frame pane =
let width, height = Sdl.gl_get_drawable_size frame.sdl_win in
let _, (_, image) =
pane
{ box= Box2.v (P2.v 0. 0.) (P2.v (float width) (float height))
; time= ticks ()
; wall= frame.wall } in
Sdl.gl_make_current frame.sdl_win frame.gl
>>>= fun () ->
Gl.viewport 0 0 width height ;
Gl.clear_color 0.0 0.0 0.0 1.0 ;
Gl.(
clear
(color_buffer_bit lor depth_buffer_bit lor stencil_buffer_bit)) ;
Gl.enable Gl.blend ;
Gl.blend_func_separate Gl.one Gl.src_alpha Gl.one
Gl.one_minus_src_alpha ;
Gl.enable Gl.cull_face_enum ;
Gl.disable Gl.depth_test ;
let width = float width and height = float height in
Wall.Renderer.render frame.wall ~width ~height image ;
Sdl.gl_swap_window frame.sdl_win ;
Ok ()
let rec get_events () : Event.t list =
(* create and fill event list *)
let ev = Sdl.Event.create () in
if Sdl.poll_event (Some ev) then
match Event.event_of_sdlevent ev with
| Some e -> get_events () @ [e]
| None -> get_events ()
else []
let successful_actor = ref (fun _ -> Lwt.return pane_empty)
let display_frame frame (actor : actor) =
let events = get_events () in
handle_frame_events frame events ;
if List.length events > 0 then (
(* recompute the actor definition with the new events to return a new pane *)
( try
!actor events
>|= fun p ->
successful_actor := !actor ;
p
with e ->
F.epr
"Display.display_frame (!actor events) failed with:@. %s \
@."
(Printexc.to_string e) ;
actor := !successful_actor ;
!actor events )
>>= fun p ->
frame.last_pane <- p ;
(* call draw_pane because we should redraw now that we have updated *)
ignore (draw_pane frame frame.last_pane) ;
Lwt.return_unit )
else Lwt.return_unit
let run frame actor () =
let frame = get_result frame in
Sdl.show_window frame.sdl_win ;
let rec loop () =
Lwt.pause () (* seems required for the irc connection to work *)
>>= fun () ->
Lwt_unix.sleep 0.030
>>= fun () ->
display_frame frame actor
>>= fun () ->
if not frame.quit then loop () else Lwt.return_unit in
Lwt_main.run (loop ()) ;
print_endline "quit" ;
Sdl.hide_window frame.sdl_win ;
Sdl.gl_delete_context frame.gl ;
Sdl.destroy_window frame.sdl_win ;
Sdl.quit () ;
()
let gray ?(a = 1.0) v = Color.v v v v a
module FontCache = Map.Make (String)
let font_cache = ref FontCache.empty
let load_font name =
match FontCache.find_opt name !font_cache with
| Some font -> font
| None -> (
let ic = open_in_bin name in
let dim = in_channel_length ic in
let fd = Unix.descr_of_in_channel ic in
let buffer =
Unix.map_file fd Bigarray.int8_unsigned Bigarray.c_layout
false [|dim|]
|> Bigarray.array1_of_genarray in
let offset = List.hd (Stb_truetype.enum buffer) in
match Stb_truetype.init buffer offset with
| None -> assert false
| Some font ->
font_cache := FontCache.add name font !font_cache ;
font )
let font_icons = lazy (load_font "fonts/entypo.ttf")
let font_sans = lazy (load_font "fonts/Roboto-Regular.ttf")
let font_sans_bold = lazy (load_font "fonts/Roboto-Bold.ttf")
let font_sans_light = lazy (load_font "fonts/Roboto-Light.ttf")
let font_sans_italic = lazy (load_font "fonts/Roboto-Italic.ttf")
let font_sans_bold_italic =
lazy (load_font "fonts/Roboto-BoldItalic.ttf")
let font_serif =
lazy (load_font "fonts/ScheherazadeNew-Regular.ttf")
let font_serif_bold =
lazy (load_font "fonts/ScheherazadeNew-Bold.ttf")
let font_mono = lazy (load_font "fonts/static/RobotoMono-Regular")
let font_mono_bold =
lazy (load_font "fonts/static/RobotoMono-Regular")
let font_mono_light =
lazy (load_font "fonts/static/RobotoMono-Regular")
let font_emoji = lazy (load_font "fonts/NotoEmoji-Regular.ttf")
let str_of_box b =
Printf.sprintf "(ox:%0.1f oy:%0.1f ex%0.1f ey%0.1f)" (Box2.ox b)
(Box2.oy b) (Box2.maxx b) (Box2.maxy b)
let draw_label text b =
let f =
Wall_text.Font.make ~size:(Box2.h b) (Lazy.force font_sans)
in
( Box2.v (Box2.o b)
(P2.v (Wall_text.Font.text_width f text) (Box2.h b))
, I.paint
(Paint.color (gray ~a:0.5 1.0))
Wall_text.(
simple_text f ~valign:`BASELINE ~halign:`LEFT ~x:(Box2.ox b)
~y:(Box2.oy b +. (Box2.h b *. 0.75))
text) )
let fill_box c b =
( b
, I.paint (Paint.color c)
( I.fill_path
@@ fun t ->
P.rect t ~x:(Box2.ox b) ~y:(Box2.oy b) ~w:(Box2.w b)
~h:(Box2.h b) ) )
let draw_filled_box c (s : state) = (s, fill_box c s.box)
let path_box c b (s : state) =
( s
, ( b
, I.paint (Paint.color c)
( I.stroke_path (Outline.make ())
@@ fun t ->
P.rect t ~x:(Box2.ox b) ~y:(Box2.oy b) ~w:(Box2.w b)
~h:(Box2.h b) ) ) )
let path_circle c b (s : state) =
( s
, ( b
, I.paint (Paint.color c)
( I.stroke_path (Outline.make ())
@@ fun t ->
P.circle t ~cx:(Box2.midx b) ~cy:(Box2.midy b)
~r:(Box2.w b /. 2.) ) ) )
(** Display.state.box as supplied to a widget defines the allowed drawing area for the widget.
This way basic widgets will just expand to the full area of a box, while other widgets can have
the express purpose of limiting the size of an object in a larger system of limitations.
Panes return a tuple: (state, (box, image))
state is the updated state, where state.box is always
- the top left corner of the box the pane drew in, and
- the bottom right corner of the state.box that was passed in
box is the area the widget actually drew in (or wants to sort of "use")
image is the Wall.image to compose with other panes and draw to the display
*)
let simple_text f text (s : state) =
let fm = Wall_text.Font.font_metrics f in
let font_height = fm.ascent -. fm.descent +. fm.line_gap in
let tm = Wall_text.Font.text_measure f text in
let br_pt =
P2.v (Box2.ox s.box +. tm.width) (Box2.oy s.box +. font_height)
in
let bextent = Box2.of_pts (Box2.o s.box) br_pt in
(* let _, (_, redbox) = path_box Color.red bextent s in*)
( {s with box= Box2.of_pts (Box2.br_pt bextent) (Box2.max s.box)}
, ( bextent
, (* I.stack redbox *)
I.paint
(Paint.color (gray ~a:0.5 1.0))
Wall_text.(
simple_text f ~valign:`BASELINE ~halign:`LEFT
~x:(Box2.ox s.box)
~y:(Box2.oy s.box +. fm.ascent)
text) ) )
let pane_box next_point_func (subpanes : pane list) (so : state) =
let sr, (br, ir) =
List.fold_left
(fun (sp, (bp, ip)) (pane : pane) ->
(* uses br to hold max extent of boxes *)
let sr, (br, ir) = pane sp in
(* draw the pane *)
let _, (_, irb) = path_box Color.blue br sr in
(* draw the box around the pane *)
( { sr with
box= Box2.of_pts (next_point_func br) (Box2.max sp.box)
}
, ( Box2.of_pts (Box2.o bp)
(P2.v
(max (Box2.maxx br) (Box2.maxx bp))
(max (Box2.maxy br) (Box2.maxy bp)) )
, Image.seq [ip; irb; ir] ) ) )
( so
, (Box2.of_pts (Box2.o so.box) (Box2.o so.box), Image.empty)
)
subpanes in
let _, (_, redbox) = path_box Color.red br sr in
(sr, (br, Image.stack redbox ir))
end

109
boot_js.ml Normal file
View File

@ -0,0 +1,109 @@
open Js_of_ocaml
open Lwt.Infix
module NVG = Graphv_webgl
let _ =
Logs.set_reporter (Human.Logs_reporter.console_reporter ());
Logs.set_level (Some Debug);
Logs.debug (fun m -> m "hello")
module Log = (val Logs.src_log Logs.default : Logs.LOG)
(* This scales the canvas to match the DPI of the window,
it prevents blurriness when rendering to the canvas *)
let scale_canvas (canvas : Dom_html.canvasElement Js.t) =
let dpr = Dom_html.window##.devicePixelRatio in
let rect = canvas##getBoundingClientRect in
let width = rect##.right -. rect##.left in
let height = rect##.bottom -. rect##.top in
canvas##.width := width *. dpr |> int_of_float;
canvas##.height := height *. dpr |> int_of_float;
let width =
Printf.sprintf "%dpx" (int_of_float width) |> Js.string
in
let height =
Printf.sprintf "%dpx" (int_of_float height) |> Js.string
in
canvas##.style##.width := width;
canvas##.style##.height := height
let _ =
let canvas =
Js.Unsafe.coerce (Dom_html.getElementById_exn "canvas")
in
scale_canvas canvas;
let webgl_ctx =
(* Graphv requires a stencil buffer to work properly *)
let attrs = WebGL.defaultContextAttributes in
attrs##.stencil := Js._true;
match
WebGL.getContextWithAttributes canvas attrs |> Js.Opt.to_option
with
| None ->
print_endline "Sorry your browser does not support WebGL";
raise Exit
| Some ctx -> ctx
in
let open NVG in
let vg =
create
~flags:CreateFlags.(antialias lor stencil_strokes)
webgl_ctx
in
(* File in this case is actually the CSS font name *)
Text.create vg ~name:"sans" ~file:"sans" |> ignore;
webgl_ctx##clearColor 0.3 0.3 0.32 1.;
(*
let render ev =
webgl_ctx##clear
(webgl_ctx##._COLOR_BUFFER_BIT_
lor webgl_ctx##._DEPTH_BUFFER_BIT_
lor webgl_ctx##._STENCIL_BUFFER_BIT_);
let device_ratio = Dom_html.window##.devicePixelRatio in
begin_frame vg ~width:canvas##.width ~height:canvas##.height
~device_ratio;
Transform.scale vg ~x:device_ratio ~y:device_ratio;
ignore Human.Panel.Ui.(panel vg Gg.P2.o test ev);
(*
Path.begin_ vg ;
Path.rect vg ~x:40. ~y:40. ~w:320. ~h:320. ;
set_fill_color vg ~color:Color.(rgba ~r:154 ~g:203 ~b:255 ~a:200) ;
fill vg ;
Transform.translate vg ~x:200. ~y:200. ;
Transform.rotate vg ~angle:(time *. 0.0005) ;
Text.set_font_face vg ~name:"sans" ;
Text.set_size vg ~size:48. ;
Text.set_align vg ~align:Align.(center lor middle) ;
set_fill_color vg ~color:Color.white ;
Text.text vg ~x:0. ~y:0. "Hello World!" ; *)
NVG.end_frame vg
in
Dom_html.window##requestAnimationFrame
(Js.wrap_callback (fun _ -> render Human.Event.empty))
|> ignore;*)
let open Js_of_ocaml_lwt.Lwt_js_events in
async (fun () ->
buffered_loop (make_event Dom_html.Event.keydown)
Dom_html.document (fun ev _ ->
webgl_ctx##clear
(webgl_ctx##._COLOR_BUFFER_BIT_
lor webgl_ctx##._DEPTH_BUFFER_BIT_
lor webgl_ctx##._STENCIL_BUFFER_BIT_);
let device_ratio = Dom_html.window##.devicePixelRatio in
begin_frame vg ~width:canvas##.width ~height:canvas##.height
~device_ratio;
Transform.scale vg ~x:device_ratio ~y:device_ratio;
Human.Panel.Ui.(
render_lwt vg Gg.P2.o
(Human.Event_js.evt_of_jskey `Press ev))
>>= fun p ->
Logs.debug (fun m ->
m "Drawing finished at point: %a" Gg.V2.pp p);
NVG.end_frame vg;
Lwt.return_unit))
(* Dom_html.document##.onkeydown
:= Dom.handler (fun (evt : Dom_html.keyboardEvent Js.t) ->
render (Human.Event_js.evt_of_jskey `Press evt) ;
Js._false ) *)

7
cors_proxy.sh Executable file
View File

@ -0,0 +1,7 @@
#!/bin/bash
if [ ! -f /tmp/key.pem ]; then
echo Creating key
openssl req -newkey rsa:2048 -new -nodes -x509 -days 3650 -keyout /tmp/key.pem -out /tmp/cert.pem -batch
fi
npx http-server --cors -S -P https://gitea.departmentofinter.net --log-ip -c-1 -C /tmp/cert.pem -K /tmp/key.pem

95
dune
View File

@ -1,78 +1,31 @@
(env (env
(dev (dev (flags (:standard -warn-error -A))
(flags (:standard -warn-error -A)))) (js_of_ocaml (flags --no-inline --pretty --source-map-inline --debug-info)
(build_runtime_flags --no-inline --pretty --source-map-inline --debug-info)
(library (link_flags --source-map-inline))))
(name human)
(modes byte)
(modules human)
(libraries
topinf
lwt_ppx
tsdl
tgls.tgles2
wall
zed
lambda-term
irmin-unix
nottui
nottui-pretty
uuseg.string
uutf
uucp
ocaml-compiler-libs.common
ocaml-compiler-libs.bytecomp
ocaml-compiler-libs.toplevel))
(executable (executable
(name irc) (name boot_js)
(modes byte) (modes byte js)
(modules irc) (preprocess (pps js_of_ocaml-ppx))
(modules boot_js human)
(libraries (libraries
human
lwt
fmt fmt
topinf logs
lwt_ppx graphv_webgl
irc-client js_of_ocaml-lwt
irc-client-lwt digestif.ocaml
irc-client-unix checkseum.ocaml
irc-client-tls irmin.mem
nottui-lwt git
nottui-pretty irmin-git
cohttp-lwt-jsoo
mimic
uri
zed
gg
wall
)) ))
(executable
(name boot)
(modes byte)
(modules boot)
(link_flags (-linkall))
(libraries
lwt_ppx
lambda-term
topinf))
(library
(name topinf)
(modes byte)
(modules topinf)
(libraries
fmt
tsdl
tgls.tgles2
wall
zed
lambda-term
irmin-unix
nottui
nottui-pretty
nottui-lwt
uuseg
irc-client
irc-client-lwt
irc-client-unix
irc-client-tls
ocaml-compiler-libs.common
ocaml-compiler-libs.bytecomp
ocaml-compiler-libs.toplevel))

View File

@ -1,3 +1,2 @@
(lang dune 2.8) (lang dune 3.4)
(name komm) (name boot)
(wrapped_executables false)

2738
human.ml

File diff suppressed because it is too large Load Diff

35
index.html Normal file
View File

@ -0,0 +1,35 @@
<!DOCTYPE>
<html>
<head>
<style>
html, body {
width: 100%;
height: 100%;
overflow: hidden;
margin: 0;
padding: 0;
}
div {
display: flex;
align-items: center;
justify-content: center;
}
canvas {
width: 100%;
height: 100%;
}
</style>
</head>
<body>
<div>
<canvas id='canvas'></canvas>
</div>
</body>
<script
type='text/javascript'
defer
src='_build/default/boot_js.bc.js'>
</script>
</html>

26
notes.org Normal file
View File

@ -0,0 +1,26 @@
* mvp todo
** toplevel repl in js_of_ocaml
** git pull from gitea.departmentofinter.net/console/boot
** git push to gitea.departmentofinter.net/console/boot
** execute a git file execution in top level
** display arbitrary git file from pulled repo
** edit arbitrary file with common emacs bindings
*** move left and right by character
*** move up and down by line
* other todo
*** yank (to clipboard) next char
*** move left and right by word and sentance
*** region select
* principles?
an "anywhere" programming environment