7 Commits

11 changed files with 1185 additions and 88 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 242 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 280 KiB

View File

@ -90,7 +90,7 @@ let _ =
let gravity_crop = Gravity.make ~h:`Positive ~v:`Negative in let gravity_crop = Gravity.make ~h:`Positive ~v:`Negative in
let body = Lwd.var (Lwd.pure Ui.empty) in let body = Lwd.var (Lwd.pure Ui.empty) in
let wm = Widgets.window_manager (Lwd.join (Lwd.get body)) in let wm = Widgets.window_manager (Lwd.join (Lwd.get body)) in
Nav.test_pull () >>= fun test_store -> Nav.test_populate () >>= fun test_store ->
let ui = Widgets.(h_node_area (test_store, [ [] ])) in let ui = Widgets.(h_node_area (test_store, [ [] ])) in
let root = let root =
Lwd.set body Lwd.set body
@ -118,5 +118,6 @@ let _ =
images); images);
buffered_loop (make_event Dom_html.Event.keydown) Dom_html.document buffered_loop (make_event Dom_html.Event.keydown) Dom_html.document
(fun ev _ -> (fun ev _ ->
Dom.preventDefault ev;
Lwt.return Lwt.return
@@ push_event (Some (`Keys [ Event_js.evt_of_jskey ev ]))) @@ push_event (Some (`Keys [ Event_js.evt_of_jskey ev ])))

144
dune
View File

@ -1,20 +1,31 @@
(env (env
(dev (flags (:standard -warn-error -A)) (dev (flags (:standard -warn-error -A))
(js_of_ocaml (flags --no-inline --pretty --source-map-inline --debug-info) (js_of_ocaml (flags :standard)
(build_runtime_flags --no-inline --pretty --source-map-inline --debug-info) (build_runtime_flags :standard --no-inline --debug-info)
(link_flags --source-map-inline)))) (compilation_mode whole_program)
(link_flags :standard))))
(library
(name log_js)
(modes byte)
(preprocess (pps js_of_ocaml-ppx))
(flags (:standard -rectypes -linkall))
(modules log_js)
(libraries
logs))
(executable (executable
(name boot_js) (name boot_js)
(modes byte js) (modes byte js)
(preprocess (pps js_of_ocaml-ppx)) (preprocess (pps js_of_ocaml-ppx))
(flags (:standard -rectypes -linkall))
(modules boot_js human) (modules boot_js human)
(libraries (libraries
fmt fmt
logs
graphv_webgl graphv_webgl
js_of_ocaml-lwt js_of_ocaml-lwt
js_of_ocaml-compiler
js_of_ocaml-toplevel
digestif.ocaml digestif.ocaml
checkseum.ocaml checkseum.ocaml
irmin.mem irmin.mem
@ -23,8 +34,127 @@
cohttp-lwt-jsoo cohttp-lwt-jsoo
mimic mimic
uri uri
zed
gg gg
lwd lwd
)) log_js))
(rule
(targets test_dynlink.cmo test_dynlink.cmi)
(action
(run ocamlc -c %{dep:test_dynlink.ml})))
(rule
(targets test_dynlink.js)
(action
(run %{bin:js_of_ocaml} --pretty --toplevel %{dep:test_dynlink.cmo})))
(rule
(targets embedded_fs.js)
(action
(run %{bin:jsoo_fs} -I . -o %{targets} %{dep:examples.ml} %{dep:test_dynlink.js})))
(rule
(targets export.txt)
(deps
(package js_of_ocaml-ppx)
(package js_of_ocaml)
(package js_of_ocaml-compiler)
(package js_of_ocaml-lwt)
(package js_of_ocaml-tyxml)
(package js_of_ocaml-toplevel))
(action
(run
jsoo_listunits
-o
%{targets}
stdlib
graphics
str
dynlink
js_of_ocaml-compiler.runtime
js_of_ocaml-lwt.graphics
js_of_ocaml-ppx.as-lib
js_of_ocaml.deriving
lwt
tyxml.functor
tyxml.functor:html_types.cmi
react
reactiveData
js_of_ocaml
js_of_ocaml-lwt
js_of_ocaml-tyxml
js_of_ocaml-toplevel
dynlink)))
(executables
(names toplevel)
(modules toplevel ppx_graph)
(flags
(:standard -rectypes -linkall))
(modes js)
(js_of_ocaml
(flags
compile
--pretty
--Werror
--target-env
browser
--export
%{dep:export.txt}
--toplevel
--disable
shortvar
+toplevel.js
+dynlink.js
%{dep:embedded_fs.js}))
(preprocess
(pps js_of_ocaml-ppx))
(libraries
js_of_ocaml-compiler
js_of_ocaml-tyxml
js_of_ocaml-toplevel
lwt
js_of_ocaml-lwt
;; not used directly
graphics
js_of_ocaml.deriving
js_of_ocaml-lwt.graphics
js_of_ocaml-ppx.as-lib
compiler-libs
compiler-libs.common
compiler-libs.bytecomp
js_of_ocaml-compiler.runtime
ocp-indent.lib
react
reactiveData
str
log_js)
)
; (rule
; (targets toplevel.js)
; (deps examples.ml)
; (action
; (run
; %{bin:js_of_ocaml}
; compile
; --pretty
; --Werror
; --target-env
; browser
; --extern-fs
; "--file=%{dep:examples.ml}"
; --export
; %{dep:export.txt}
; --toplevel
; --disable
; shortvar
; +toplevel.js
; +dynlink.js
; %{dep:toplevel.bc}
; -o
; %{targets})))
(alias
(name default)
(deps toplevel.bc.js index.html toplevel.html))

185
human.ml
View File

@ -1,3 +1,40 @@
(* ok it's monad time *)
(*
1. implement toplevel eval of git repo content
1. eval `/init` on startup for now
1. start looking under the hood of js_of_ocaml top level to see if
1. there are ways to display and allow easy manipulation of the values used when calling
Irmin.S.Tree.fold on things.
1. Make sure js_of_ocaml toplevel and native top level of ocaml 5.0
are reasonably compatible in this "under the hood" stuff
1. save all JSOOTOP input into a history file that gets committed for each command!!
1. Build a text editor based on irmin-tree?
1. What you really want is a data structure that is easy for you to call commands on to manipulate the values of
irmin stores
1. If you go by the default, a text file is split into a list of lines,
which has a cursor which is an index into the list of lines, and an index into the specific line.
1. Various common cursor movement commands should be bound to the common keys
1. A display of the cursor data structure values
1. these commands just mutate the cursor state, so the text editor is just the structure of the Lwd.vars which are Lwd.get'd and mapped against the Tree.watch ified stuff???
ughhh
1. but yea fold being
1. fix fetching of `console/boot` so it doesn't crash and can deal!!!!
1. like just tell it to fetch teh latest commit or something
*)
(* why *) (* why *)
(* (*
@ -441,6 +478,8 @@ module Nav = struct
end end
module Sync = Irmin.Sync.Make (S) module Sync = Irmin.Sync.Make (S)
(* owo *)
(* owo *)
type t = S.tree type t = S.tree
type store = S.t type store = S.t
@ -448,13 +487,24 @@ module Nav = struct
type step = S.step type step = S.step
type path = step list type path = step list
let init () = S.Repo.v (Irmin_mem.config ()) >>= S.main >>= S.tree let empty_repo_main () = S.Repo.v (Irmin_mem.config ()) >>= S.main
let test_populate () : t Lwt.t = let time_now () =
Int64.of_float ((new%js Js.date_now)##getTime /. 1000.)
let info_msg ?(time = time_now ()) message = S.Info.v ~message time
let test_populate () : store Lwt.t =
let add p s t = S.Tree.add t p s in let add p s t = S.Tree.add t p s in
let r' = empty_repo_main () in
add [ "hello" ] "world" (S.Tree.empty ()) add [ "hello" ] "world" (S.Tree.empty ())
>>= add [ "hello"; "daddy" ] "ily" >>= add [ "daddy" ] "ily"
>>= add [ "beep"; "beep" ] "motherfucker" >>= add [ "beep"; "beep" ] "motherfucker"
>>= fun t ->
r' >>= fun r ->
S.set_tree ~info:(fun () -> info_msg "test_populate ()") r [] t
|> ignore;
r'
let test_pull () : store Lwt.t = let test_pull () : store Lwt.t =
(* test_populate ()*) (* test_populate ()*)
@ -573,7 +623,6 @@ module NVG = struct
include Graphv_webgl.Color include Graphv_webgl.Color
let none = Color.transparent let none = Color.transparent
let transparent = rgbaf ~r:0. ~g:0. ~b:0. ~a:0.000001
let gray a = rgbf ~r:a ~g:a ~b:a let gray a = rgbf ~r:a ~g:a ~b:a
let light = gray 0.8 let light = gray 0.8
let dark = gray 0.2 let dark = gray 0.2
@ -1260,7 +1309,7 @@ module Nottui = struct
let request_var (v : var) = let request_var (v : var) =
incr clock; incr clock;
Log.debug (fun m -> Log.debug (fun m ->
m "Focus.request_var v=%d clock=%d" (Lwd.peek v) !clock); m "Focus.request_var v=%d->%d" (Lwd.peek v) !clock);
Lwd.set v !clock Lwd.set v !clock
let request ((v, _) : handle) = request_var v let request ((v, _) : handle) = request_var v
@ -1359,7 +1408,7 @@ module Nottui = struct
end end
module Ui = struct module Ui = struct
type may_handle = [ `Unhandled | `Handled ] type may_handle = [ `Unhandled | `Handled | `Moar ]
let may_handle (type a) (v : a option) (f : a -> may_handle) : let may_handle (type a) (v : a option) (f : a -> may_handle) :
may_handle = may_handle =
@ -1368,6 +1417,7 @@ module Nottui = struct
let pp_may_handle ppf = function let pp_may_handle ppf = function
| `Unhandled -> F.pf ppf "`Unhandled" | `Unhandled -> F.pf ppf "`Unhandled"
| `Handled -> F.pf ppf "`Handled" | `Handled -> F.pf ppf "`Handled"
| `Moar -> F.pf ppf "`Moar"
type mouse_handler = type mouse_handler =
x:float -> x:float ->
@ -1621,10 +1671,9 @@ module Nottui = struct
let has_focus t = Focus.has_focus t.focus let has_focus t = Focus.has_focus t.focus
let rec pp ppf t = let rec pp ppf t =
if has_focus t then (* if has_focus t then*)
F.pf ppf "@[<hov>%a %a@]" Focus.pp_status t.focus pp_desc F.pf ppf "@[<hov>%a %a@]" Focus.pp_status t.focus pp_desc t.desc
t.desc (* else F.pf ppf "@[<hov> %a@]" pp_desc t.desc *)
else F.pf ppf "@[<hov> %a@]" pp_desc t.desc
and pp_desc ppf = function and pp_desc ppf = function
| Atom a -> | Atom a ->
@ -1814,7 +1863,10 @@ module Nottui = struct
let update_focus ui = let update_focus ui =
match ui.focus with match ui.focus with
| Focus.Empty | Focus.Handle _ -> () | Focus.Empty | Focus.Handle _ -> ()
| Focus.Conflict i -> solve_focus ui i | Focus.Conflict i ->
Log.debug (fun m ->
m "update_focus Conflict %d -> solve_focus ()" i);
solve_focus ui i
let rec t_size_desc_of_t vg (size : box2) (ui : Ui.t desc) = let rec t_size_desc_of_t vg (size : box2) (ui : Ui.t desc) =
match ui with match ui with
@ -1963,7 +2015,7 @@ module Nottui = struct
| Event_filter (n, f) -> ( | Event_filter (n, f) -> (
match f (`Mouse (`Press btn, (x, y), [])) with match f (`Mouse (`Press btn, (x, y), [])) with
| `Handled -> true | `Handled -> true
| `Unhandled -> aux ox oy sw sh n) | `Unhandled | `Moar -> aux ox oy sw sh n)
in in
aux 0. 0. w h t aux 0. 0. w h t
@ -2033,7 +2085,9 @@ module Nottui = struct
| Atom image -> | Atom image ->
let image = let image =
if Focus.has_focus t.focus then ( if Focus.has_focus t.focus then (
Log.debug (fun m -> m "render_node Atom has_focus"); Log.debug (fun m ->
m "render_node Atom has_focus status=%a"
Focus.pp_status t.focus);
I.attr A.clickable image) I.attr A.clickable image)
else image else image
in in
@ -2167,7 +2221,11 @@ module Nottui = struct
else else
{ {
cache with cache with
image = I.attr A.(bg Color.transparent) cache.image; image =
I.attr
A.(bg Color.(rgbaf ~r:0. ~g:0. ~b:0. ~a:0.000001))
(* TODO: HACK *)
cache.image;
} }
in in
t.cache <- cache; t.cache <- cache;
@ -2179,7 +2237,7 @@ module Nottui = struct
(render_node vg 0. 0. w h w h view).image (render_node vg 0. 0. w h w h view).image
let dispatch_raw_key st keys = let dispatch_raw_key st keys =
let rec iter (st : ui list) : [> `Unhandled ] = let rec iter (st : ui list) : [> `Unhandled | `Moar ] =
match st with match st with
| [] -> `Unhandled | [] -> `Unhandled
| ui :: tl -> ( | ui :: tl -> (
@ -2195,10 +2253,10 @@ module Nottui = struct
| Focus_area (t, f) -> ( | Focus_area (t, f) -> (
match iter [ t ] with match iter [ t ] with
| `Handled -> `Handled | `Handled -> `Handled
| `Unhandled -> ( | `Unhandled | `Moar -> (
match f keys with match f keys with
| `Handled -> `Handled | `Handled -> `Handled
| `Unhandled -> iter tl)) | `Unhandled | `Moar -> iter tl))
| Attr (t, _) | Attr (t, _)
| Mouse_handler (t, _) | Mouse_handler (t, _)
| Size_sensor (t, _) | Size_sensor (t, _)
@ -2211,7 +2269,7 @@ module Nottui = struct
| Event_filter (t, f) -> ( | Event_filter (t, f) -> (
match f (`Keys keys) with match f (`Keys keys) with
| `Unhandled -> iter (t :: tl) | `Unhandled -> iter (t :: tl)
| `Handled -> `Handled)) | a -> a))
in in
iter [ st.view ] iter [ st.view ]
@ -2302,25 +2360,24 @@ module Nottui = struct
let rec dispatch_key st (keys : Ui.keys) = let rec dispatch_key st (keys : Ui.keys) =
match (dispatch_raw_key st keys, keys) with match (dispatch_raw_key st keys, keys) with
| `Handled, _ -> `Handled | `Handled, _ -> `Handled
| `Unhandled, [ (`Arrow dir, []) ] -> | _, [ (`Arrow dir, []) ] ->
let dir : [ `Down | `Left | `Right | `Up ] :> let dir : [ `Down | `Left | `Right | `Up ] :>
[ `Down | `Left | `Right | `Up | `Next | `Prev ] = [ `Down | `Left | `Right | `Up | `Next | `Prev ] =
dir dir
in in
dispatch_key st [ (`Focus dir, [ `Meta ]) ] dispatch_key st [ (`Focus dir, [ `Meta ]) ]
| `Unhandled, [ (`Tab, mods) ] | _, [ (`Tab, mods) ] when mods == [] || mods = [ `Shift ] ->
when mods == [] || mods = [ `Shift ] ->
dispatch_key st dispatch_key st
[ [
( `Focus (if List.mem `Shift mods then `Prev else `Next), ( `Focus (if List.mem `Shift mods then `Prev else `Next),
mods ); mods );
] ]
| `Unhandled, [ (`Focus dir, _) ] -> | _, [ (`Focus dir, _) ] ->
let r = dispatch_focus st.view dir in let r = dispatch_focus st.view dir in
(if r then Log.debug else Log.warn) (fun m -> (if r then Log.debug else Log.warn) (fun m ->
m "Renderer.dispatch_focus key:%a -> %b" pp_keys keys r); m "Renderer.dispatch_focus key:%a -> %b" pp_keys keys r);
if r then `Handled else `Unhandled if r then `Handled else `Unhandled
| `Unhandled, _ -> `Unhandled | a, _ -> a
let dispatch_event t = function let dispatch_event t = function
| `Keys keys -> dispatch_key t keys | `Keys keys -> dispatch_key t keys
@ -2396,12 +2453,12 @@ module Nottui_lwt = struct
match match
Renderer.dispatch_event renderer (`Keys !key_list) Renderer.dispatch_event renderer (`Keys !key_list)
with with
| `Handled -> key_list := [] | `Handled | `Unhandled -> key_list := []
| `Unhandled -> ()) | `Moar -> ())
| #Ui.event as event -> ( | #Ui.event as event -> (
match Renderer.dispatch_event renderer event with match Renderer.dispatch_event renderer event with
| `Handled -> () | `Handled -> ()
| `Unhandled -> | `Moar | `Unhandled ->
Log.warn (fun m -> Log.warn (fun m ->
m m
"Nottui_lwt.render process_event #Ui.event -> \ "Nottui_lwt.render process_event #Ui.event -> \
@ -2479,6 +2536,10 @@ module Widgets = struct
List.mem List.mem
(`Uchar (Uchar.of_char 'g'), [ `Ctrl ]) (`Uchar (Uchar.of_char 'g'), [ `Ctrl ])
k' k'
||
match k' with
| [ (`Escape, []) ] -> true
| _ -> false
then `Handled then `Handled
else `Unhandled else `Unhandled
| _ -> `Unhandled) | _ -> `Unhandled)
@ -3139,7 +3200,7 @@ module Widgets = struct
else `Unhandled)) else `Unhandled))
| [ (`Uchar u, [ `Ctrl ]) ] when eq_uc_c u 'k' -> | [ (`Uchar u, [ `Ctrl ]) ] when eq_uc_c u 'k' ->
`Handled `Handled
| [ (`Uchar u, [ `Ctrl ]) ] when eq_uc_c u 'x' -> | [ (`Uchar s, [ `Ctrl ]) ] when eq_uc_c s 's' ->
let b = Buffer.create 1024 in let b = Buffer.create 1024 in
Lwd_table.iter Lwd_table.iter
(fun line -> (fun line ->
@ -3183,6 +3244,7 @@ module Widgets = struct
Lwd_table.append' table (Focus.make (), step)) Lwd_table.append' table (Focus.make (), step))
treelist; treelist;
let cursor = Lwd.var @@ Lwd_table.first table in let cursor = Lwd.var @@ Lwd_table.first table in
Log.debug (fun m -> m "tree_nav cursor focus.request");
Lwd.peek cursor Lwd.peek cursor
|> Option.iter (fun cursor -> |> Option.iter (fun cursor ->
Lwd_table.get cursor Lwd_table.get cursor
@ -3191,8 +3253,17 @@ module Widgets = struct
(Lwd_table.map_reduce (Lwd_table.map_reduce
(fun _ (f, s) -> (fun _ (f, s) ->
Lwd.map (Focus.status f) ~f:(fun focus_h -> Lwd.map (Focus.status f) ~f:(fun focus_h ->
if Focus.has_focus focus_h then string ~attr:A.cursor s Ui.keyboard_area ~focus:focus_h
else string s)) (fun k ->
Log.debug (fun m ->
m
"keyboard_area: tree_nav map_reduce \
%a->`Unhandled"
Ui.pp_keys k);
`Unhandled)
(if Focus.has_focus focus_h then
string ~attr:A.cursor s
else string s)))
(Lwd_utils.lift_monoid Ui.pack_y) (Lwd_utils.lift_monoid Ui.pack_y)
table table
|> Lwd.join |> Lwd.join
@ -3201,7 +3272,11 @@ module Widgets = struct
Lwd.peek cursor Lwd.peek cursor
|> Option.iter (fun cursor -> |> Option.iter (fun cursor ->
Lwd_table.get cursor Lwd_table.get cursor
|> Option.iter (fun (f, _) -> Focus.request f)); |> Option.iter (fun (f, _) ->
Log.debug (fun m ->
m "tree_nav has_focus request %a"
Focus.pp_status focus');
Focus.request f));
Ui.keyboard_area ~focus:focus' (fun k -> Ui.keyboard_area ~focus:focus' (fun k ->
Log.debug (fun m -> Log.debug (fun m ->
m "keyboard_area: tree_nav %a" Ui.pp_keys k); m "keyboard_area: tree_nav %a" Ui.pp_keys k);
@ -3230,47 +3305,6 @@ module Widgets = struct
| [ (`Backspace, []) ] -> `Unhandled | [ (`Backspace, []) ] -> `Unhandled
| _ -> `Unhandled))) | _ -> `Unhandled)))
(* let cursorview =
Lwd.var @@ Lwd.pure @@ string "initializing..."
in
let cv, push_cv = Lwt_stream.create () in
let cvroot =
Lwd.observe ~on_invalidate:(fun _ ->
Log.info (fun m ->
m
"tree_nav cursorviewroot on_invalidate push_cv \
triggered??");
push_cv (Some ()))
@@ Lwd.map (Lwd.get cursor) ~f:(function
| Some cursor_row -> (
match Lwd_table.get cursor_row with
| Some (focus, step) -> (
let path' = path @ [ step ] in
Nav.S.kind store path' >>= function
| Some `Node -> lwt_lwd_string "Sub-node??"
| Some `Contents -> node_edit_area (store, path')
| None ->
lwt_lwd_string
("Nav.S.kind " ^ String.concat "/" path'
^ " -> None?"))
| None ->
lwt_lwd_string "cursor table row doesn't exist")
| None -> lwt_lwd_string "cursor doesn't exist")
in
Lwt.async (fun () ->
Lwt_stream.iter_s
(fun _ ->
Lwd.quick_sample cvroot >>= fun cursorview'' ->
Log.info (fun m ->
m "tree_nav Lwt.async (Lwd.set cursorview)");
Lwt.return (Lwd.set cursorview cursorview''))
cv);
push_cv (Some ()); *)
(*|> Lwd.map2
(Lwd.join @@ Lwd.get cursorview)
~f:(fun cursorview' tree_view ->
Ui.join_x tree_view cursorview') *)
open Lwt.Infix open Lwt.Infix
let rec node_ui ?(focus = Focus.make ()) store path let rec node_ui ?(focus = Focus.make ()) store path
@ -3314,7 +3348,6 @@ module Widgets = struct
Lwt.return_unit) Lwt.return_unit)
let h_node_area ?(table = Lwd_table.make ()) let h_node_area ?(table = Lwd_table.make ())
?(focus = Focus.make ())
((store, paths) : Nav.S.t * Nav.path list) : Ui.t Lwd.t = ((store, paths) : Nav.S.t * Nav.path list) : Ui.t Lwd.t =
List.iter List.iter
(fun path -> (fun path ->
@ -3327,14 +3360,6 @@ module Widgets = struct
(Lwd_utils.lift_monoid Ui.pack_x) (Lwd_utils.lift_monoid Ui.pack_x)
table table
|> Lwd.join |> Lwd.join
|> Lwd.map2 (Focus.status focus) ~f:(fun focus' ->
Ui.keyboard_area ~focus:focus' (fun k ->
Log.debug (fun m ->
m "keyboard_area: h_node_area_handler %a"
Ui.pp_keys k);
match k with
| [ (`Enter, []) ] -> `Unhandled
| _ -> `Unhandled))
(** Tab view, where exactly one element of [l] is shown at a time. *) (** Tab view, where exactly one element of [l] is shown at a time. *)
let tabs (tabs : (string * (unit -> Ui.t Lwd.t)) list) : Ui.t Lwd.t let tabs (tabs : (string * (unit -> Ui.t Lwd.t)) list) : Ui.t Lwd.t

56
log_js.ml Normal file
View File

@ -0,0 +1,56 @@
module Logs_reporter = struct
(* Console reporter *)
open Jsoo_runtime
let console : Logs.level -> string -> unit =
fun level s ->
let meth =
match level with
| Logs.Error -> "error"
| Logs.Warning -> "warn"
| Logs.Info -> "info"
| Logs.Debug -> "debug"
| Logs.App -> "log"
in
ignore
(Js.meth_call
(Js.pure_js_expr "console")
meth
[| Js.string s |])
let ppf, flush =
let b = Buffer.create 255 in
let flush () =
let s = Buffer.contents b in
Buffer.clear b;
s
in
(Format.formatter_of_buffer b, flush)
let hook =
ref (fun level s ->
ignore (Logs.level_to_string (Some level) ^ ": " ^ s))
let console_report _src level ~over k msgf =
let k _ =
let s = flush () in
console level s;
!hook level s;
over ();
k ()
in
msgf @@ fun ?header ?tags fmt ->
let _tags = tags in
match header with
| None -> Format.kfprintf k ppf ("@[" ^^ fmt ^^ "@]@.")
| Some h -> Format.kfprintf k ppf ("[%s] @[" ^^ fmt ^^ "@]@.") h
let console_reporter () = { Logs.report = console_report }
end
let _ =
Logs.set_reporter (Logs_reporter.console_reporter ());
Logs.set_level (Some Debug)
module Log = Logs

11
ppx_graph.ml Normal file
View File

@ -0,0 +1,11 @@
open Ppxlib
open Log_js
let log_info pp exp =
Log.info (fun m -> m "ppx_graph: %a" pp exp);
exp
let init () =
Driver.register_transformation
~impl:(log_info Ocaml_common.Pprintast.structure)
"ppx_graph"

230
toplevel.html Normal file
View File

@ -0,0 +1,230 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>OCaml toplevel</title>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<link rel="stylesheet" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.3.5/css/bootstrap.min.css" />
<style>
code, kbd, pre, samp {
font-family: Menlo,Monaco,Consolas,monospace;
}
body,html {
height: 100%;
background-color:#eee;
}
#toplevel-container {
width: 50%;
background-color: black;
color: #ccc;
overflow: auto;
overflow-x: hidden;
height: 100%;
float:left;
padding:10px;
padding-top: 20px;
}
#toplevel-container pre#output {
padding: 0px;
}
#toplevel-container #output {
background-color:transparent;
color: #ccc;
border: none;
line-height:18px;
font-size: 12px;
margin-bottom: 0px;
}
#toplevel-container textarea {
width:90%;
line-height:18px;
font-size: 12px;
background-color: transparent;
color: #fff;
border: 0;
resize: none;
outline: none;
font-family: Menlo,Monaco,Consolas,monospace;
font-weight: bold;
float:left;
margin: 0px;
padding:0px;
}
#toplevel-container #sharp {
float: left;
line-height:18px;
font-size: 12px;
font-family: Menlo,Monaco,Consolas,monospace;
white-space: pre;
}
.sharp:before{
content:"# ";
line-height:18px;
font-size: 12px;
font-family: Menlo,Monaco,Consolas,monospace;
}
.caml{
color:rgb(110, 110, 201);
}
#toplevel-side{
position:relative;
width:45%;
height: 100%;
overflow: auto;
text-align:justify;
float:left;
margin-left:30px;
}
#toplevel-side ul{
padding: 0px;
list-style-type: none;
}
.stderr {
color: #d9534f;
}
.stdout {
}
.errorloc{
border-bottom-width: 3px;
border-bottom-style: solid;
border-bottom-color: red;
}
canvas {
border: 1px dashed black;
float: left;
margin: 7px;
}
#output canvas {
background-color: #464646;
float: none;
display: block;
border: 1px dashed while;
margin: 7px;
}
#output img {
display:block;
}
#toplevel-examples {
width: 270px;
float: left;
}
#toplevel-examples .list-group-item{
padding: 5px 15px;
}
#btn-share {
float:right;
margin-top:-20px;
background-color:rgb(92, 129, 184);
border-color: rgb(70, 75, 128);
padding: 1px 5px;
display:none;
}
.clear { clear:both; }
.sharp .id { color: #59B65C ; font-style: italic }
.sharp .kw0 { color: rgb(64, 75, 190); font-weight: bold ;}
.sharp .kw1 { color: rgb(150, 0, 108); font-weight: bold ;}
.sharp .kw2 { color: rgb(23, 100, 42); font-weight: bold ;}
.sharp .kw3 { color: #59B65C; font-weight: bold ;}
.sharp .kw4 { color: #59B65C; font-weight: bold ;}
.sharp .comment { color: green ; font-style: italic ; }
.sharp .string { color: #6B6B6B; font-weight: bold ; }
.sharp .text { }
.sharp .numeric { color: #729AAF; }
.sharp .directive { font-style: italic ; color : #EB00FF; } ;
.sharp .escape { color: #409290 ; }
.sharp .symbol0 { color: orange ; font-weight: bold ; }
.sharp .symbol1 { color: #993300 ; font-weight: bold ; }
.sharp .constant { color: rgb(0, 152, 255); }
</style>
<script type="text/javascript">
window.onhashchange = function() { window.location.reload() }
var hash = window.location.hash.replace(/^#/,"");
var fields = hash.split(/&/);
var prefix = "";
var version = "";
for(var f in fields){
var data = fields[f].split(/=/);
if(data[0] == "version"){
version = data[1].replace(/%20|%2B/g,"+");
break;
}
}
function load_script(url){
var fileref=document.createElement('script');
fileref.setAttribute("type","text/javascript");
fileref.setAttribute("src", prefix+(version==""?"":(version+"/"))+url);
document.getElementsByTagName("head")[0].appendChild(fileref);
}
load_script("_build/default/exported-unit.cmis.js");
load_script("_build/default/toplevel.bc.js");
</script>
</head>
<body>
<div id="toplevel-container">
<pre id="output"></pre>
<div>
<div id="sharp" class="sharp"></div>
<textarea id="userinput">Loading ...</textarea>
<button type="button" class="btn btn-default"
id="btn-share">Share</button>
</div>
</div>
<div id="toplevel-side">
<h3>Js_of_ocaml</h3>
<h4>A compiler from OCaml bytecode to Javascript.</h4>
<p>It makes OCaml programs that run on Web browsers. It is
easy to install as it works with an existing installation of OCaml,
with no need to recompile any library. It comes with bindings for a
large part of the browser APIs.</p>
<p>This web-based OCaml toplevel is compiled using Js_of_ocaml.</p>
<h4>Command</h4>
<table class="table table-striped table-condensed">
<tbody class>
<tr>
<td>Enter/Return</td>
<td>Submit code</td>
</tr>
<tr>
<td>Ctrl + Enter</td>
<td>Newline</td>
</tr>
<tr>
<td>Up / Down</td>
<td>Browse history</td>
</tr>
<tr>
<td>Ctrl + l</td>
<td>Clear display</td>
</tr>
<tr>
<td>Ctrl + k</td>
<td>Reset toplevel</td>
</tr>
<tr>
<td>Tab</td>
<td>Indent code</td>
</tr>
</tbody>
</table>
<h4>Try to execute samples</h4>
<div id="toplevel-examples" class="list-group"></div>
<canvas width=200 height=200 id="test-canvas"></canvas>
<h4 class="clear">See the generated javascript code</h4>
<pre id="last-js">
</pre>
</div>
</body>
</html>

644
toplevel.ml Normal file
View File

@ -0,0 +1,644 @@
(* Js_of_ocaml toplevel
* http://www.ocsigen.org/js_of_ocaml/
* Copyright (C) 2011 Jérôme Vouillon
* Laboratoire PPS - CNRS Université Paris Diderot
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, with linking exception;
* either version 2.1 of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*)
open Js_of_ocaml
open Js_of_ocaml_lwt
open Js_of_ocaml_tyxml
open Js_of_ocaml_toplevel
open Lwt
module Graphics_support = struct
let init elt = Graphics_js.open_canvas elt
end
open Log_js
module Ppx_support = struct
let init () =
Ppx_graph.init ();
Ast_mapper.register "js_of_ocaml" (fun _ -> Ppx_js.mapper);
Ast_mapper.register "ppxlib" (fun _ ->
Log.info (fun m -> m "Ppxlib.mapper");
{
Ast_mapper.default_mapper with
structure =
(fun _ ->
Log.info (fun m -> m "Ppxlib.Driver.map_structure");
Ppxlib.Driver.map_structure);
signature =
(fun _ ->
Log.info (fun m -> m "Ppxlib.Driver.map_signature");
Ppxlib.Driver.map_signature);
})
end
module Colorize = struct
open Js_of_ocaml
open Js_of_ocaml_tyxml
let text ~a_class:cl s =
Tyxml_js.Html.(span ~a:[ a_class [ cl ] ] [ txt s ])
let ocaml = text
let highlight from_ to_ e =
match Js.Opt.to_option e##.textContent with
| None -> assert false
| Some x ->
let x = Js.to_string x in
let (`Pos from_) = from_ in
let to_ =
match to_ with `Pos n -> n | `Last -> String.length x - 1
in
e##.innerHTML := Js.string "";
let span kind s =
if s <> "" then
let span =
Tyxml_js.Html.(span ~a:[ a_class [ kind ] ] [ txt s ])
in
Dom.appendChild e (Tyxml_js.To_dom.of_element span)
in
span "normal" (String.sub x 0 from_);
span "errorloc" (String.sub x from_ (to_ - from_));
span "normal" (String.sub x to_ (String.length x - to_))
end
module Indent : sig
val textarea : Dom_html.textAreaElement Js.t -> unit
end = struct
let _ = Approx_lexer.enable_extension "lwt"
let indent s in_lines =
let output =
{
IndentPrinter.debug = false;
config = IndentConfig.default;
in_lines;
indent_empty = true;
adaptive = true;
kind = IndentPrinter.Print (fun s acc -> acc ^ s);
}
in
let stream = Nstream.of_string s in
IndentPrinter.proceed output stream IndentBlock.empty ""
let textarea (textbox : Dom_html.textAreaElement Js.t) : unit =
let rec loop s acc (i, pos') =
try
let pos = String.index_from s pos' '\n' in
loop s ((i, (pos', pos)) :: acc) (succ i, succ pos)
with _ -> List.rev ((i, (pos', String.length s)) :: acc)
in
let rec find (l : (int * (int * int)) list) c =
match l with
| [] -> assert false
| (i, (lo, up)) :: _ when up >= c -> (c, i, lo, up)
| (_, (_lo, _up)) :: rem -> find rem c
in
let v = textbox##.value in
let pos =
let c1 = textbox##.selectionStart
and c2 = textbox##.selectionEnd in
if
Js.Opt.test (Js.Opt.return c1)
&& Js.Opt.test (Js.Opt.return c2)
then
let l = loop (Js.to_string v) [] (0, 0) in
Some (find l c1, find l c2)
else None
in
let f =
match pos with
| None -> fun _ -> true
| Some ((_c1, line1, _lo1, _up1), (_c2, line2, _lo2, _up2)) ->
fun l -> l >= line1 + 1 && l <= line2 + 1
in
let v = indent (Js.to_string v) f in
textbox##.value := Js.string v;
match pos with
| Some ((c1, line1, _lo1, up1), (c2, line2, _lo2, up2)) ->
let l = loop v [] (0, 0) in
let lo1'', up1'' = List.assoc line1 l in
let lo2'', up2'' = List.assoc line2 l in
let n1 = max (c1 + up1'' - up1) lo1'' in
let n2 = max (c2 + up2'' - up2) lo2'' in
let () = (Obj.magic textbox)##setSelectionRange n1 n2 in
textbox##focus;
()
| None -> ()
end
let compiler_name = "OCaml"
let by_id s = Dom_html.getElementById s
let by_id_coerce s f =
Js.Opt.get
(f (Dom_html.getElementById s))
(fun () -> raise Not_found)
let do_by_id s f =
try f (Dom_html.getElementById s) with Not_found -> ()
(* load file using a synchronous XMLHttpRequest *)
let load_resource_aux filename url =
Js_of_ocaml_lwt.XmlHttpRequest.perform_raw
~response_type:XmlHttpRequest.ArrayBuffer url
>|= fun frame ->
if frame.Js_of_ocaml_lwt.XmlHttpRequest.code = 200 then
Js.Opt.case frame.Js_of_ocaml_lwt.XmlHttpRequest.content
(fun () -> Printf.eprintf "Could not load %s\n" filename)
(fun b ->
Sys_js.update_file ~name:filename
~content:(Typed_array.String.of_arrayBuffer b))
else ()
let load_resource scheme ~prefix ~path:suffix =
let url = scheme ^ suffix in
let filename = Filename.concat prefix suffix in
Lwt.async (fun () -> load_resource_aux filename url);
Some ""
let setup_pseudo_fs () =
Sys_js.mount ~path:"/dev/" (fun ~prefix:_ ~path:_ -> None);
Sys_js.mount ~path:"/http/" (load_resource "http://");
Sys_js.mount ~path:"/https/" (load_resource "https://");
Sys_js.mount ~path:"/ftp/" (load_resource "ftp://");
Sys_js.mount ~path:"/home/" (load_resource "filesys/")
let exec' s =
let res : bool = JsooTop.use Format.std_formatter s in
if not res then Format.eprintf "error while evaluating %s@." s
module Version = struct
type t = int list
let split_char ~sep p =
let len = String.length p in
let rec split beg cur =
if cur >= len then
if cur - beg > 0 then [ String.sub p beg (cur - beg) ] else []
else if sep p.[cur] then
String.sub p beg (cur - beg) :: split (cur + 1) (cur + 1)
else split beg (cur + 1)
in
split 0 0
let split v =
match
split_char
~sep:(function '+' | '-' | '~' -> true | _ -> false)
v
with
| [] -> assert false
| x :: _ ->
List.map int_of_string
(split_char ~sep:(function '.' -> true | _ -> false) x)
let current : t = split Sys.ocaml_version
let compint (a : int) b = compare a b
let rec compare v v' =
match (v, v') with
| [ x ], [ y ] -> compint x y
| [], [] -> 0
| [], y :: _ -> compint 0 y
| x :: _, [] -> compint x 0
| x :: xs, y :: ys -> (
match compint x y with 0 -> compare xs ys | n -> n)
end
let setup_toplevel () =
JsooTop.initialize ();
Sys.interactive := false;
if Version.compare Version.current [ 4; 07 ] >= 0 then
exec' "open Stdlib";
exec'
"module Lwt_main = struct\n\
\ let run t = match Lwt.state t with\n\
\ | Lwt.Return x -> x\n\
\ | Lwt.Fail e -> raise e\n\
\ | Lwt.Sleep -> failwith \"Lwt_main.run: thread \
didn't return\"\n\
\ end";
let header1 =
Printf.sprintf " %s version %%s" compiler_name
in
let header2 =
Printf.sprintf " Compiled with Js_of_ocaml version %s"
Sys_js.js_of_ocaml_version
in
exec'
(Printf.sprintf "Format.printf \"%s@.\" Sys.ocaml_version;;"
header1);
exec' (Printf.sprintf "Format.printf \"%s@.\";;" header2);
exec' "#enable \"pretty\";;";
exec' "#disable \"shortvar\";;";
Ppx_support.init ();
let[@alert "-deprecated"] new_directive n k =
Hashtbl.add Toploop.directive_table n k
in
new_directive "load_js"
(Toploop.Directive_string
(fun name -> Js.Unsafe.global##load_script_ name));
Sys.interactive := true;
()
let resize ~container ~textbox () =
Lwt.pause () >>= fun () ->
textbox##.style##.height := Js.string "auto";
textbox##.style##.height
:= Js.string (Printf.sprintf "%dpx" (max 18 textbox##.scrollHeight));
container##.scrollTop := container##.scrollHeight;
Lwt.return ()
let setup_printers () =
exec'
"let _print_error fmt e = Format.pp_print_string fmt \
(Js_of_ocaml.Js_error.to_string e)";
Topdirs.dir_install_printer Format.std_formatter
Longident.(Lident "_print_error");
exec'
"let _print_unit fmt (_ : 'a) : 'a = Format.pp_print_string fmt \
\"()\"";
Topdirs.dir_install_printer Format.std_formatter
Longident.(Lident "_print_unit")
let setup_examples ~container ~textbox =
let r = Regexp.regexp "^\\(\\*+(.*)\\*+\\)$" in
let all = ref [] in
(try
let ic = open_in "/static/examples.ml" in
while true do
let line = input_line ic in
match Regexp.string_match r line 0 with
| Some res ->
let name =
match Regexp.matched_group res 1 with
| Some s -> s
| None -> assert false
in
all := `Title name :: !all
| None -> all := `Content line :: !all
done;
assert false
with _ -> ());
let example_container = by_id "toplevel-examples" in
let _ =
List.fold_left
(fun acc tok ->
match tok with
| `Content line -> line ^ "\n" ^ acc
| `Title name ->
let a =
Tyxml_js.Html.(
a
~a:
[
a_class [ "list-group-item" ];
a_onclick (fun _ ->
textbox##.value := (Js.string acc)##trim;
Lwt.async (fun () ->
resize ~container ~textbox ()
>>= fun () ->
textbox##focus;
Lwt.return_unit);
true);
]
[ txt name ])
in
Dom.appendChild example_container (Tyxml_js.To_dom.of_a a);
"")
"" !all
in
()
(* we need to compute the hash form href to avoid different encoding behavior
across browser. see Url.get_fragment *)
let parse_hash () =
let frag = Url.Current.get_fragment () in
Url.decode_arguments frag
let rec iter_on_sharp ~f x =
Js.Opt.iter (Dom_html.CoerceTo.element x) (fun e ->
if Js.to_bool (e##.classList##contains (Js.string "sharp")) then
f e);
match Js.Opt.to_option x##.nextSibling with
| None -> ()
| Some n -> iter_on_sharp ~f n
let setup_share_button ~output =
do_by_id "btn-share" (fun e ->
e##.style##.display := Js.string "block";
e##.onclick :=
Dom_html.handler (fun _ ->
(* get all ocaml code *)
let code = ref [] in
Js.Opt.iter output##.firstChild
(iter_on_sharp ~f:(fun e ->
code :=
Js.Opt.case e##.textContent
(fun () -> "")
Js.to_string
:: !code));
let code_encoded = String.concat "" (List.rev !code) in
let url, is_file =
match Url.Current.get () with
| Some (Url.Http url) ->
(Url.Http { url with Url.hu_fragment = "" }, false)
| Some (Url.Https url) ->
(Url.Https { url with Url.hu_fragment = "" }, false)
| Some (Url.File url) ->
(Url.File { url with Url.fu_fragment = "" }, true)
| _ -> assert false
in
let frag =
let frags = parse_hash () in
let frags =
List.remove_assoc "code" frags
@ [ ("code", code_encoded) ]
in
Url.encode_arguments frags
in
let uri = Url.string_of_url url ^ "#" ^ frag in
let append_url str =
let dom =
Tyxml_js.Html.(
p
[
txt "Share this url : ";
a ~a:[ a_href str ] [ txt str ];
])
in
Dom.appendChild output (Tyxml_js.To_dom.of_element dom)
in
Lwt.async (fun () ->
Lwt.catch
(fun () ->
if is_file then
failwith "Cannot shorten url with file scheme"
else
let uri =
Printf.sprintf
"http://is.gd/create.php?format=json&url=%s"
(Url.urlencode uri)
in
Lwt.bind (Js_of_ocaml_lwt.Jsonp.call uri)
(fun o ->
let str = Js.to_string o##.shorturl in
append_url str;
Lwt.return_unit))
(fun exn ->
Format.eprintf
"Could not generate short url. reason: %s@."
(Printexc.to_string exn);
append_url uri;
Lwt.return_unit));
Js._false))
let setup_js_preview () =
let ph = by_id "last-js" in
let runcode : string -> 'a = Js.Unsafe.global##.toplevelEval in
Js.Unsafe.global##.toplevelEval := fun bc ->
ph##.innerHTML := Js.string bc;
runcode bc
let current_position = ref 0
let highlight_location loc =
let x = ref 0 in
let output = by_id "output" in
let first =
Js.Opt.get
(output##.childNodes##item !current_position)
(fun _ -> assert false)
in
iter_on_sharp first ~f:(fun e ->
incr x;
let _file1, line1, col1 =
Location.get_pos_info loc.Location.loc_start
in
let _file2, line2, col2 =
Location.get_pos_info loc.Location.loc_end
in
if !x >= line1 && !x <= line2 then
let from_ = if !x = line1 then `Pos col1 else `Pos 0 in
let to_ = if !x = line2 then `Pos col2 else `Last in
Colorize.highlight from_ to_ e)
let append colorize output cl s =
Dom.appendChild output
(Tyxml_js.To_dom.of_element (colorize ~a_class:cl s))
module History = struct
let data = ref [| "" |]
let idx = ref 0
let get_storage () =
match Js.Optdef.to_option Dom_html.window##.localStorage with
| exception _ -> raise Not_found
| None -> raise Not_found
| Some t -> t
let setup () =
try
let s = get_storage () in
match Js.Opt.to_option (s##getItem (Js.string "history")) with
| None -> raise Not_found
| Some s ->
let a = Json.unsafe_input s in
data := a;
idx := Array.length a - 1
with _ -> ()
let push text =
let l = Array.length !data in
let n = Array.make (l + 1) "" in
!data.(l - 1) <- text;
Array.blit !data 0 n 0 l;
data := n;
idx := l;
try
let s = get_storage () in
let str = Json.output !data in
s##setItem (Js.string "history") str
with Not_found -> ()
let current text = !data.(!idx) <- text
let previous textbox =
if !idx > 0 then (
decr idx;
textbox##.value := Js.string !data.(!idx))
let next textbox =
if !idx < Array.length !data - 1 then (
incr idx;
textbox##.value := Js.string !data.(!idx))
end
let run _ =
let container = by_id "toplevel-container" in
let output = by_id "output" in
let textbox : 'a Js.t =
by_id_coerce "userinput" Dom_html.CoerceTo.textarea
in
let sharp_chan = open_out "/dev/null0" in
let sharp_ppf = Format.formatter_of_out_channel sharp_chan in
let caml_chan = open_out "/dev/null1" in
let caml_ppf = Format.formatter_of_out_channel caml_chan in
let execute () =
let content = Js.to_string textbox##.value##trim in
let content' =
let len = String.length content in
if
try
content <> ""
&& content.[len - 1] <> ';'
&& content.[len - 2] <> ';'
with _ -> true
then content ^ ";;"
else content
in
current_position := output##.childNodes##.length;
textbox##.value := Js.string "";
History.push content;
JsooTop.execute true ~pp_code:sharp_ppf ~highlight_location
caml_ppf content';
resize ~container ~textbox () >>= fun () ->
container##.scrollTop := container##.scrollHeight;
textbox##focus;
Lwt.return_unit
in
let history_down _e =
let txt = Js.to_string textbox##.value in
let pos = textbox##.selectionStart in
try
if String.length txt = pos then raise Not_found;
let _ = String.index_from txt pos '\n' in
Js._true
with Not_found ->
History.current txt;
History.next textbox;
Js._false
in
let history_up _e =
let txt = Js.to_string textbox##.value in
let pos = textbox##.selectionStart - 1 in
try
if pos < 0 then raise Not_found;
let _ = String.rindex_from txt pos '\n' in
Js._true
with Not_found ->
History.current txt;
History.previous textbox;
Js._false
in
let meta e =
let b = Js.to_bool in
b e##.ctrlKey || b e##.altKey || b e##.metaKey
in
let shift e = Js.to_bool e##.shiftKey in
(* setup handlers *)
textbox##.onkeyup :=
Dom_html.handler (fun _ ->
Lwt.async (resize ~container ~textbox);
Js._true);
textbox##.onchange :=
Dom_html.handler (fun _ ->
Lwt.async (resize ~container ~textbox);
Js._true);
textbox##.onkeydown :=
Dom_html.handler (fun e ->
match e##.keyCode with
| 13 when not (meta e || shift e) ->
Lwt.async execute;
Js._false
| 13 ->
Lwt.async (resize ~container ~textbox);
Js._true
| 09 ->
Indent.textarea textbox;
Js._false
| 76 when meta e ->
output##.innerHTML := Js.string "";
Js._true
| 75 when meta e ->
setup_toplevel ();
Js._false
| 38 -> history_up e
| 40 -> history_down e
| _ -> Js._true);
(Lwt.async_exception_hook :=
fun exc ->
Format.eprintf "exc during Lwt.async: %s@."
(Printexc.to_string exc);
match exc with
| Js_error.Exn e ->
let e = Js_error.to_error e in
Firebug.console##log e##.stack
| _ -> ());
Lwt.async (fun () ->
resize ~container ~textbox () >>= fun () ->
textbox##focus;
Lwt.return_unit);
Graphics_support.init
(by_id_coerce "test-canvas" Dom_html.CoerceTo.canvas);
Sys_js.set_channel_flusher caml_chan
(append Colorize.ocaml output "caml");
Sys_js.set_channel_flusher sharp_chan
(append Colorize.ocaml output "sharp");
Sys_js.set_channel_flusher stdout
(append Colorize.text output "stdout");
Sys_js.set_channel_flusher stderr
(append Colorize.text output "stderr");
let readline () =
Js.Opt.case
(Dom_html.window##prompt
(Js.string "The toplevel expects inputs:")
(Js.string ""))
(fun () -> "")
(fun s -> Js.to_string s ^ "\n")
in
Sys_js.set_channel_filler stdin readline;
setup_share_button ~output;
setup_examples ~container ~textbox;
setup_pseudo_fs ();
setup_toplevel ();
setup_js_preview ();
setup_printers ();
History.setup ();
textbox##.value := Js.string "";
(* Run initial code if any *)
try
let code = List.assoc "code" (parse_hash ()) in
textbox##.value := Js.string code;
Lwt.async execute
with
| Not_found -> ()
| exc ->
Firebug.console##log_3 (Js.string "exception")
(Js.string (Printexc.to_string exc))
exc
let _ =
Dom_html.window##.onload
:= Dom_html.handler (fun _ ->
run ();
Js._false)