49 Commits

Author SHA1 Message Date
cqc
60be88d4e1 who knows what was going on here 2023-08-26 15:23:07 -05:00
cqc
420e350544 examples.ml lol that was hard 2023-03-05 15:50:18 -06:00
cqc
ab91e5dee0 toplevel emits round trip pprint of ast to console. 2023-03-03 18:47:24 -06:00
cqc
272778ad7b well this is a toplevel, now to add a ppx ast printer? 2023-03-03 13:48:46 -06:00
cqc
8c16946650 time to pivot again 2023-02-23 23:43:57 -06:00
cqc
7a1e4ef2ba Dom.preventDefault hack keeps browser shortcuts from happening. 2023-02-17 15:25:04 -06:00
cqc
480e77bbb9 switched to using local test repo because there was no internet on Le Canadien, fixed tree_nav focus handle embedding, added Moar to may_handle 2023-02-16 13:35:34 -06:00
cqc
53982ab0c6 more debug 2023-02-13 09:29:47 -06:00
cqc
5c11183217 colorizing the focus status of each node reveals things are v broke 2023-02-08 15:40:39 -06:00
cqc
2ec6426fe5 key press display 2023-02-06 09:36:14 -06:00
cqc
0df5884a88 list-based key press handlers 2023-02-05 15:47:00 -06:00
cqc
6948a65a97 padding 2023-02-05 14:47:26 -06:00
cqc
bba26b9c0f cleanup 2023-02-03 12:10:27 -06:00
cqc
fcf528275b selectable node/contents, needs correcting focus control 2023-02-03 12:07:10 -06:00
cqc
d53f6687e5 broke focus, but rearranged for better save implementation 2023-01-23 13:04:04 -06:00
cqc
d46c1de49d still works 2023-01-23 11:54:46 -06:00
cqc
f0c5556450 tree_nav :3 2023-01-22 23:16:15 -06:00
cqc
97730899c6 tree_nav cursor movement 2023-01-13 09:30:36 -06:00
cqc
18daf83c1c loads and displays teh git tree 2023-01-13 05:39:51 -06:00
cqc
dfef26fcf5 text_area basic nav 2023-01-07 07:24:29 -06:00
cqc
048ea0eab4 text_area improvements 2022-12-18 11:14:37 -06:00
cqc
3509930195 added Focus.releases for line_table 2022-12-15 12:05:15 -06:00
cqc
b1ac36ce3e text editor issue is a problem with focus resolution
might require Focus.release, but may be incorrect use of Focus.request.
2022-12-14 19:39:28 -06:00
cqc
a12db025e0 Backspace but there's a subtle/unusual issue with enter/backspace and the text insertion occuring on the wrong line after unknown sequence. 2022-12-14 13:23:16 -06:00
cqc
5c10f3860a basic text field edition 2022-12-14 09:46:09 -06:00
cqc
a64fcbb010 refactored resizing and stuff 2022-12-11 18:25:57 -06:00
cqc
7baa6f3648 compute ui.w and ui.h during update 2022-12-10 14:27:22 -06:00
cqc
af92f03706 moar 2022-12-08 20:12:56 -06:00
cqc
cb263b5758 edit field editsdune build -w ./boot_js.bc.js 2022-12-08 12:27:36 -06:00
cqc
44879eb947 another barely working text rendering scheme 2022-12-07 12:47:56 -06:00
cqc
49bddb6365 urgh... stuck with how to implement cursor/focus etc. Decided to try to integrate Nottui and Nottui_widgets directly istead of reinventing another wheel. 2022-12-04 12:25:00 -06:00
cqc
b5d846b35d re-arranged 2022-11-22 23:38:53 -06:00
cqc
60c83c608a looks like shit 2022-11-22 13:19:51 -06:00
cqc
58ec73972b lwd-ifying it 2022-11-22 02:21:45 -06:00
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
cqc
50831dc73d most cursor movement functionality works, but there are lots of weird quirks to iron out 2022-03-20 16:01:41 -05:00
cqc
98e78d81ec ok it works now 2022-03-20 13:06:06 -05:00
cqc
fd7db32917 what have i done 2022-03-20 11:57:25 -05:00
20 changed files with 6690 additions and 2208 deletions

View File

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

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

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

123
boot_js.ml Normal file
View File

@ -0,0 +1,123 @@
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)
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 webgl_initialize canvas =
scale_canvas canvas;
(* 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
let graphv_initialize webgl_ctx =
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.;
vg
let request_animation_frame () =
let t, s = Lwt.wait () in
let (_ : Dom_html.animation_frame_request_id) =
Dom_html.window##requestAnimationFrame
(Js.wrap_callback (fun (time : float) -> Lwt.wakeup s time))
in
t
let render_stream canvas webgl_ctx vg
(render : NVG.t -> ?time:float -> Gg.p2 -> Human.I.t -> unit) :
Human.I.t Lwt_stream.t -> unit Lwt.t =
Lwt_stream.iter_n (fun i ->
request_animation_frame () >>= fun time ->
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
NVG.begin_frame vg ~width:canvas##.width ~height:canvas##.height
~device_ratio;
NVG.Transform.scale vg ~x:device_ratio ~y:device_ratio;
render vg ~time Gg.P2.o i;
NVG.end_frame vg;
Lwt.return_unit)
open Human
let _ =
let canvas =
Js.Unsafe.coerce (Dom_html.getElementById_exn "canvas")
in
let webgl_ctx = webgl_initialize canvas in
let vg = graphv_initialize webgl_ctx in
let open Js_of_ocaml_lwt.Lwt_js_events in
let open Nottui in
let gravity_pad = Gravity.make ~h:`Negative ~v:`Negative in
let gravity_crop = Gravity.make ~h:`Positive ~v:`Negative in
let body = Lwd.var (Lwd.pure Ui.empty) in
let wm = Widgets.window_manager (Lwd.join (Lwd.get body)) in
Nav.test_populate () >>= fun test_store ->
let ui = Widgets.(h_node_area (test_store, [ [] ])) in
let root =
Lwd.set body
(Lwd.map ~f:(Ui.resize ~pad:gravity_pad ~crop:gravity_crop) ui);
Widgets.window_manager_view wm
in
let events, push_event = Lwt_stream.create () in
let images =
Human.Nottui_lwt.render vg
~size:(Gg.P2.v canvas##.width canvas##.height)
events root
in
async (fun () ->
render_stream canvas webgl_ctx vg
(fun vg ?(time = 0.) p i ->
let _ = time in
Log.debug (fun m ->
m "Drawing image: p=%a n=%a" Gg.V2.pp p
(I.Draw.pp ~attr:A.dark)
i);
let p' = I.Draw.node vg A.dark p i in
Logs.debug (fun m ->
m "Drawing finished: p'=%a" Gg.V2.pp p'))
images);
buffered_loop (make_event Dom_html.Event.keydown) Dom_html.document
(fun ev _ ->
Dom.preventDefault ev;
Lwt.return
@@ push_event (Some (`Keys [ Event_js.evt_of_jskey ev ])))

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

231
dune
View File

@ -1,78 +1,183 @@
(env (env
(dev (dev (flags (:standard -warn-error -A))
(flags (:standard -warn-error -A)))) (js_of_ocaml (flags :standard)
(build_runtime_flags :standard --no-inline --debug-info)
(compilation_mode whole_program)
(link_flags :standard))))
(library (library
(name human) (name log_js)
(modes byte) (modes byte)
(modules human) (preprocess (pps js_of_ocaml-ppx))
(flags (:standard -rectypes -linkall))
(modules log_js)
(libraries (libraries
topinf logs))
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))
(library
(executable (name graphast)
(name irc)
(modes byte) (modes byte)
(modules irc) (kind ppx_rewriter)
(modules graphast)
(libraries (libraries
human logs
ppxlib
fmt
lwt lwt
fmt ))
topinf
lwt_ppx
irc-client
irc-client-lwt
irc-client-unix
irc-client-tls
nottui-lwt
nottui-pretty
))
(executable (executable
(name boot) (name ppx_graph)
(modes byte) (modes byte)
(modules boot) (modules ppx_graph)
(link_flags (-linkall))
(libraries (libraries
lwt_ppx graphast))
lambda-term
topinf))
(library (executable
(name topinf) (name boot_js)
(modes byte) (modes byte js)
(modules topinf) (preprocess (pps js_of_ocaml-ppx))
(flags (:standard -rectypes -linkall))
(modules boot_js human)
(libraries (libraries
fmt fmt
tsdl graphv_webgl
tgls.tgles2 js_of_ocaml-lwt
wall js_of_ocaml-compiler
zed js_of_ocaml-toplevel
lambda-term digestif.ocaml
irmin-unix checkseum.ocaml
nottui irmin.mem
nottui-pretty git
nottui-lwt irmin-git
uuseg cohttp-lwt-jsoo
irc-client mimic
irc-client-lwt uri
irc-client-unix gg
irc-client-tls lwd
ocaml-compiler-libs.common log_js))
ocaml-compiler-libs.bytecomp
ocaml-compiler-libs.toplevel)) (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}
; lol hack?
-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
dynlink
js_of_ocaml
js_of_ocaml-lwt
js_of_ocaml-tyxml
js_of_ocaml-toplevel
js_of_ocaml-compiler
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
ppxlib)))
(executables
(names toplevel)
(modules toplevel)
(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 ppxlib.metaquot))
(libraries
fmt
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
ppxlib))
; (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))

View File

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

997
graphast.ml Normal file
View File

@ -0,0 +1,997 @@
(* graph typed abstract syntax tree:
couple options for hooking into compilation:
- modify ocaml source
- reimplement toplevel functions to allow extracting tast
* needs multiple implementaitons for byte and js
* only accepts toplevel phrases
- ppx
* only gets ast, would need to parse for tast (could use merlin or ocamlcommon?)
- merlin
* need to understand protocol and whether current lib interfaces give enough control
*)
open Ppxlib
open Lwt
module F = Fmt
module Log = Logs
module Printast = struct
include Ocaml_common.Printast
open Asttypes
open Format
open Lexing
open Location
open Parsetree
let fmt_position with_name f l =
let fname = if with_name then l.pos_fname else "" in
if l.pos_lnum = -1 then fprintf f "%s[%d]" fname l.pos_cnum
else
fprintf f "%s[%d,%d+%d]" fname l.pos_lnum l.pos_bol
(l.pos_cnum - l.pos_bol)
let fmt_location f loc =
if not !Ocaml_common.Clflags.locations then ()
else
let p_2nd_name =
loc.loc_start.pos_fname <> loc.loc_end.pos_fname
in
fprintf f "(%a..%a)" (fmt_position true) loc.loc_start
(fmt_position p_2nd_name)
loc.loc_end;
if loc.loc_ghost then fprintf f " ghost"
let rec fmt_longident_aux f x =
match x with
| Longident.Lident s -> fprintf f "%s" s
| Longident.Ldot (y, s) -> fprintf f "%a.%s" fmt_longident_aux y s
| Longident.Lapply (y, z) ->
fprintf f "%a(%a)" fmt_longident_aux y fmt_longident_aux z
let fmt_longident f x = fprintf f "\"%a\"" fmt_longident_aux x
let fmt_longident_loc f (x : Longident.t loc) =
fprintf f "%a" fmt_longident_aux x.txt
let fmt_string_loc f (x : string loc) = fprintf f "\"%s\"@ " x.txt
let fmt_str_opt_loc f (x : string option loc) =
fprintf f "\"%s\"@ " (Option.value x.txt ~default:"_")
let fmt_char_option f = function
| None -> fprintf f ""
| Some c -> fprintf f "%c" c
let fmt_constant f x =
match x with
| Pconst_integer (i, m) -> fprintf f "%s%a" i fmt_char_option m
| Pconst_char c -> fprintf f "'%02x'" (Char.code c)
| Pconst_string (s, _strloc, None) -> fprintf f "%S" s
| Pconst_string (s, _strloc, Some delim) ->
fprintf f "%S(%S)" s delim
| Pconst_float (s, _) -> fprintf f "%s" s
let str_longident_loc = F.to_to_string fmt_longident_loc
let str_constant = F.to_to_string fmt_constant
let fmt_mutable_flag f x =
match x with
| Immutable -> fprintf f "Immutable"
| Mutable -> fprintf f "Mutable"
let fmt_virtual_flag f x =
match x with
| Virtual -> fprintf f "Virtual"
| Concrete -> fprintf f "Concrete"
let fmt_override_flag f x =
match x with
| Override -> fprintf f "Override"
| Fresh -> fprintf f "Fresh"
let fmt_closed_flag f x =
match x with
| Closed -> fprintf f "Closed"
| Open -> fprintf f "Open"
let fmt_rec_flag f x =
match x with
| Nonrecursive -> fprintf f ""
| Recursive -> fprintf f "Rec "
let fmt_direction_flag f x =
match x with Upto -> fprintf f "Up" | Downto -> fprintf f "Down"
let fmt_private_flag f x =
match x with
| Public -> fprintf f "Public"
| Private -> fprintf f "Private"
let line = F.pf
let list f ppf l =
F.pf ppf "%a" (F.brackets @@ F.list ~sep:F.semi f) l
let option f = F.option ~none:(fun ppf () -> F.pf ppf "None") f
let longident_loc ppf li = line ppf "%a@ " fmt_longident_loc li
let string ppf s = line ppf "\"%s\"@ " s
let string_loc ppf s = line ppf "%a@ " fmt_string_loc s
let str_opt_loc ppf s = line ppf "%a@ " fmt_str_opt_loc s
let arg_label ppf = function
| Nolabel -> fprintf ppf "" (* "Nolabel\n" *)
| Optional s -> fprintf ppf "?:%s@ " s
| Labelled s -> fprintf ppf "~:%s@ " s
let rec core_type ppf x =
attributes ppf x.ptyp_attributes;
match x.ptyp_desc with
| Ptyp_any -> line ppf "Ptyp_any@ "
| Ptyp_var s -> line ppf "Ptyp_var %s@ " s
| Ptyp_arrow (l, ct1, ct2) ->
line ppf "Ptyp_arrow@ ";
arg_label ppf l;
core_type ppf ct1;
core_type ppf ct2
| Ptyp_tuple l ->
line ppf "Ptyp_tuple@ ";
list core_type ppf l
| Ptyp_constr (li, l) ->
line ppf "Ptyp_constr %a@ " fmt_longident_loc li;
list core_type ppf l
| Ptyp_variant (l, closed, low) ->
line ppf "Ptyp_variant closed=%a@ " fmt_closed_flag closed;
list label_x_bool_x_core_type_list ppf l;
option (list string) ppf low
| Ptyp_object (l, c) ->
line ppf "Ptyp_object %a@ " fmt_closed_flag c;
List.iter
(fun field ->
match field.pof_desc with
| Otag (l, t) ->
line ppf "method %s@ " l.txt;
attributes ppf field.pof_attributes;
core_type ppf t
| Oinherit ct ->
line ppf "Oinherit@ ";
core_type ppf ct)
l
| Ptyp_class (li, l) ->
line ppf "Ptyp_class %a@ " fmt_longident_loc li;
list core_type ppf l
| Ptyp_alias (ct, s) ->
line ppf "Ptyp_alias \"%s\"@ " s;
core_type ppf ct
| Ptyp_poly (sl, ct) ->
line ppf "Ptyp_poly%a@ "
(fun ppf ->
List.iter (fun x ->
fprintf ppf " %a" Ocaml_common.Pprintast.tyvar x.txt))
sl;
core_type ppf ct
| Ptyp_package (s, l) ->
line ppf "Ptyp_package %a@ " fmt_longident_loc s;
list package_with ppf l
| Ptyp_extension (s, arg) ->
line ppf "Ptyp_extension \"%s\"@ " s.txt;
payload ppf arg
and package_with ppf (s, t) =
line ppf "with type %a@ " fmt_longident_loc s;
core_type ppf t
and pattern ppf x =
(* line i ppf "pattern %a@ " fmt_location x.ppat_loc; *)
attributes ppf x.ppat_attributes;
match x.ppat_desc with
| Ppat_any -> line ppf "Ppat_any@ "
| Ppat_var s -> line ppf "<var> %a@ " fmt_string_loc s
| Ppat_alias (p, s) ->
line ppf "Ppat_alias %a@ " fmt_string_loc s;
pattern ppf p
| Ppat_constant c -> line ppf "Ppat %a@ " fmt_constant c
| Ppat_interval (c1, c2) ->
line ppf "Ppat_interval %a..%a@ " fmt_constant c1 fmt_constant
c2
| Ppat_tuple l ->
line ppf "Ppat_tuple@ ";
list pattern ppf l
| Ppat_construct (li, po) ->
line ppf "Ppat_construct %a@ " fmt_longident_loc li;
option pattern ppf (Option.map snd po)
| Ppat_variant (l, po) ->
line ppf "Ppat_variant \"%s\"@ " l;
option pattern ppf po
| Ppat_record (l, c) ->
line ppf "Ppat_record %a@ " fmt_closed_flag c;
list longident_x_pattern ppf l
| Ppat_array l ->
line ppf "Ppat_array@ ";
list pattern ppf l
| Ppat_or (p1, p2) ->
line ppf "Ppat_or@ ";
pattern ppf p1;
pattern ppf p2
| Ppat_lazy p ->
line ppf "Ppat_lazy@ ";
pattern ppf p
| Ppat_constraint (p, ct) ->
line ppf "Ppat_constraint@ ";
pattern ppf p;
core_type ppf ct
| Ppat_type li ->
line ppf "Ppat_type@ ";
longident_loc ppf li
| Ppat_unpack s -> line ppf "Ppat_unpack %a@ " fmt_str_opt_loc s
| Ppat_exception p ->
line ppf "Ppat_exception@ ";
pattern ppf p
| Ppat_open (m, p) ->
line ppf "Ppat_open \"%a\"@ " fmt_longident_loc m;
pattern ppf p
| Ppat_extension (s, arg) ->
line ppf "Ppat_extension \"%s\"@ " s.txt;
payload ppf arg
and expression ppf x : unit =
(* line ppf "expression %a@ " fmt_location x.pexp_loc; *)
attributes ppf x.pexp_attributes;
match x.pexp_desc with
| Pexp_ident _li ->
(* line ppf "Pexp_ident %a@ " fmt_longident_loc li; *)
(* str_longident_loc li *)
()
| Pexp_constant _c ->
(*line ppf "Pexp %a@ " fmt_constant c;*)
(* str_constant c *)
()
| Pexp_let (rf, l, e) ->
line ppf "Pexp_let %a@ " fmt_rec_flag rf;
list value_binding ppf l;
expression ppf e
| Pexp_function _l ->
line ppf "Pexp_function@ " (* ; list case ppf l *)
| Pexp_fun (l, eo, p, e) ->
line ppf "Pexp_fun@ ";
arg_label ppf l;
F.option (fun ppf -> F.pf ppf "=%a" expression) ppf eo;
F.pf ppf "%a@ ->@ %a" pattern p expression e
| Pexp_apply (e, l) ->
line ppf "Pexp_apply@ ";
expression ppf e;
let name = Pprintast.string_of_expression x in
list (graph_node name) ppf l
| Pexp_match (e, l) ->
line ppf "Pexp_match@ ";
expression ppf e;
list case ppf l
| Pexp_try (e, l) ->
line ppf "Pexp_try@ ";
expression ppf e;
list case ppf l
| Pexp_tuple l ->
line ppf "Pexp_tuple@ ";
list expression ppf l
| Pexp_construct (li, eo) ->
line ppf "Pexp_construct %a@ " fmt_longident_loc li;
option expression ppf eo
| Pexp_variant (l, eo) ->
line ppf "Pexp_variant \"%s\"@ " l;
option expression ppf eo
| Pexp_record (l, eo) ->
line ppf "Pexp_record@ ";
list longident_x_expression ppf l;
option expression ppf eo
| Pexp_field (e, li) ->
line ppf "Pexp_field@ ";
expression ppf e;
longident_loc ppf li
| Pexp_setfield (e1, li, e2) ->
line ppf "Pexp_setfield@ ";
expression ppf e1;
longident_loc ppf li;
expression ppf e2
| Pexp_array l ->
line ppf "Pexp_array@ ";
list expression ppf l
| Pexp_ifthenelse (e1, e2, eo) ->
line ppf "Pexp_if@ ";
expression ppf e1;
line ppf "Pexp_then@ ";
expression ppf e2;
F.option
(fun ppf ->
line ppf "Pexp_else@ ";
expression ppf)
ppf eo
| Pexp_sequence (e1, e2) ->
line ppf "Pexp_sequence@ ";
expression ppf e1;
expression ppf e2
| Pexp_while (e1, e2) ->
line ppf "Pexp_while@ ";
expression ppf e1;
expression ppf e2
| Pexp_for (p, e1, e2, df, e3) ->
line ppf "Pexp_for %a@ " fmt_direction_flag df;
pattern ppf p;
expression ppf e1;
expression ppf e2;
expression ppf e3
| Pexp_constraint (e, ct) ->
line ppf "Pexp_constraint@ ";
expression ppf e;
core_type ppf ct
| Pexp_coerce (e, cto1, cto2) ->
line ppf "Pexp_coerce@ ";
expression ppf e;
option core_type ppf cto1;
core_type ppf cto2
| Pexp_send (e, s) ->
line ppf "Pexp_send \"%s\"@ " s.txt;
expression ppf e
| Pexp_new li -> line ppf "Pexp_new %a@ " fmt_longident_loc li
| Pexp_setinstvar (s, e) ->
line ppf "Pexp_setinstvar %a@ " fmt_string_loc s;
expression ppf e
| Pexp_override l ->
line ppf "Pexp_override@ ";
list string_x_expression ppf l
| Pexp_letmodule (s, me, e) ->
line ppf "Pexp_letmodule %a@ " fmt_str_opt_loc s;
module_expr ppf me;
expression ppf e
| Pexp_letexception (cd, e) ->
line ppf "Pexp_letexception@ ";
extension_constructor ppf cd;
expression ppf e
| Pexp_assert e ->
line ppf "Pexp_assert@ ";
expression ppf e
| Pexp_lazy e ->
line ppf "Pexp_lazy@ ";
expression ppf e
| Pexp_poly (e, cto) ->
line ppf "Pexp_poly@ ";
expression ppf e;
option core_type ppf cto
| Pexp_object s ->
line ppf "Pexp_object@ ";
class_structure ppf s
| Pexp_newtype (s, e) ->
line ppf "Pexp_newtype \"%s\"@ " s.txt;
expression ppf e
| Pexp_pack me ->
line ppf "Pexp_pack@ ";
module_expr ppf me
| Pexp_open (o, e) ->
line ppf "Pexp_open %a@ " fmt_override_flag o.popen_override;
module_expr ppf o.popen_expr;
expression ppf e
| Pexp_letop { let_; ands; body } ->
line ppf "Pexp_letop@ ";
binding_op ppf let_;
list binding_op ppf ands;
expression ppf body
| Pexp_extension (s, arg) ->
line ppf "Pexp_extension \"%s\"@ " s.txt;
payload ppf arg
| Pexp_unreachable -> line ppf "Pexp_unreachable"
and value_description ppf x =
line ppf "value_description %a %a@ " fmt_string_loc x.pval_name
fmt_location x.pval_loc;
attributes ppf x.pval_attributes;
core_type ppf x.pval_type;
list string ppf x.pval_prim
and type_parameter ppf (x, _variance) = core_type ppf x
and type_declaration ppf x =
line ppf "type_declaration %a %a@ " fmt_string_loc x.ptype_name
fmt_location x.ptype_loc;
attributes ppf x.ptype_attributes;
line ppf "ptype_params =@ ";
list type_parameter ppf x.ptype_params;
line ppf "ptype_cstrs =@ ";
list core_type_x_core_type_x_location ppf x.ptype_cstrs;
line ppf "ptype_kind =@ ";
type_kind ppf x.ptype_kind;
line ppf "ptype_private = %a@ " fmt_private_flag x.ptype_private;
line ppf "ptype_manifest =@ ";
option core_type ppf x.ptype_manifest
and attribute ppf k a =
line ppf "%s \"%s\"@ " k a.attr_name.txt;
payload ppf a.attr_payload
and attributes ppf l =
List.iter
(fun a ->
line ppf "attribute \"%s\"@ " a.attr_name.txt;
payload ppf a.attr_payload)
l
and payload ppf = function
| PStr x -> structure ppf x
| PSig x -> signature ppf x
| PTyp x -> core_type ppf x
| PPat (x, None) -> pattern ppf x
| PPat (x, Some g) ->
pattern ppf x;
line ppf "<when>@ ";
expression ppf g
and type_kind ppf x =
match x with
| Ptype_abstract -> line ppf "Ptype_abstract@ "
| Ptype_variant l ->
line ppf "Ptype_variant@ ";
list constructor_decl ppf l
| Ptype_record l ->
line ppf "Ptype_record@ ";
list label_decl ppf l
| Ptype_open -> line ppf "Ptype_open@ "
and type_extension ppf x =
line ppf "type_extension@ ";
attributes ppf x.ptyext_attributes;
line ppf "ptyext_path = %a@ " fmt_longident_loc x.ptyext_path;
line ppf "ptyext_params =@ ";
list type_parameter ppf x.ptyext_params;
line ppf "ptyext_constructors =@ ";
list extension_constructor ppf x.ptyext_constructors;
line ppf "ptyext_private = %a@ " fmt_private_flag x.ptyext_private
and type_exception ppf x =
line ppf "type_exception@ ";
attributes ppf x.ptyexn_attributes;
line ppf "ptyext_constructor =@ ";
extension_constructor ppf x.ptyexn_constructor
and extension_constructor ppf x =
line ppf "extension_constructor %a@ " fmt_location x.pext_loc;
attributes ppf x.pext_attributes;
line ppf "pext_name = \"%s\"@ " x.pext_name.txt;
line ppf "pext_kind =@ ";
extension_constructor_kind ppf x.pext_kind
and extension_constructor_kind ppf x =
match x with
| Pext_decl (_, a, r) ->
line ppf "Pext_decl@ ";
constructor_arguments ppf a;
option core_type ppf r
| Pext_rebind li ->
line ppf "Pext_rebind@ ";
line ppf "%a@ " fmt_longident_loc li
and class_type ppf x =
line ppf "class_type %a@ " fmt_location x.pcty_loc;
attributes ppf x.pcty_attributes;
match x.pcty_desc with
| Pcty_constr (li, l) ->
line ppf "Pcty_constr %a@ " fmt_longident_loc li;
list core_type ppf l
| Pcty_signature cs ->
line ppf "Pcty_signature@ ";
class_signature ppf cs
| Pcty_arrow (l, co, cl) ->
line ppf "Pcty_arrow@ ";
arg_label ppf l;
core_type ppf co;
class_type ppf cl
| Pcty_extension (s, arg) ->
line ppf "Pcty_extension \"%s\"@ " s.txt;
payload ppf arg
| Pcty_open (o, e) ->
line ppf "Pcty_open %a %a@ " fmt_override_flag
o.popen_override fmt_longident_loc o.popen_expr;
class_type ppf e
and class_signature ppf cs =
line ppf "class_signature@ ";
core_type ppf cs.pcsig_self;
list class_type_field ppf cs.pcsig_fields
and class_type_field ppf x =
line ppf "class_type_field %a@ " fmt_location x.pctf_loc;
attributes ppf x.pctf_attributes;
match x.pctf_desc with
| Pctf_inherit ct ->
line ppf "Pctf_inherit@ ";
class_type ppf ct
| Pctf_val (s, mf, vf, ct) ->
line ppf "Pctf_val \"%s\" %a %a@ " s.txt fmt_mutable_flag mf
fmt_virtual_flag vf;
core_type ppf ct
| Pctf_method (s, pf, vf, ct) ->
line ppf "Pctf_method \"%s\" %a %a@ " s.txt fmt_private_flag
pf fmt_virtual_flag vf;
core_type ppf ct
| Pctf_constraint (ct1, ct2) ->
line ppf "Pctf_constraint@ ";
core_type ppf ct1;
core_type ppf ct2
| Pctf_attribute a -> attribute ppf "Pctf_attribute" a
| Pctf_extension (s, arg) ->
line ppf "Pctf_extension \"%s\"@ " s.txt;
payload ppf arg
and class_description ppf x =
line ppf "class_description %a@ " fmt_location x.pci_loc;
attributes ppf x.pci_attributes;
line ppf "pci_virt = %a@ " fmt_virtual_flag x.pci_virt;
line ppf "pci_params =@ ";
list type_parameter ppf x.pci_params;
line ppf "pci_name = %a@ " fmt_string_loc x.pci_name;
line ppf "pci_expr =@ ";
class_type ppf x.pci_expr
and class_type_declaration ppf x =
line ppf "class_type_declaration %a@ " fmt_location x.pci_loc;
attributes ppf x.pci_attributes;
line ppf "pci_virt = %a@ " fmt_virtual_flag x.pci_virt;
line ppf "pci_params =@ ";
list type_parameter ppf x.pci_params;
line ppf "pci_name = %a@ " fmt_string_loc x.pci_name;
line ppf "pci_expr =@ ";
class_type ppf x.pci_expr
and class_expr ppf x =
line ppf "class_expr %a@ " fmt_location x.pcl_loc;
attributes ppf x.pcl_attributes;
match x.pcl_desc with
| Pcl_constr (li, l) ->
line ppf "Pcl_constr %a@ " fmt_longident_loc li;
list core_type ppf l
| Pcl_structure cs ->
line ppf "Pcl_structure@ ";
class_structure ppf cs
| Pcl_fun (l, eo, p, e) ->
line ppf "Pcl_fun@ ";
arg_label ppf l;
option expression ppf eo;
pattern ppf p;
class_expr ppf e
| Pcl_apply (ce, l) ->
line ppf "Pcl_apply@ ";
class_expr ppf ce;
list label_x_expression ppf l
| Pcl_let (rf, l, ce) ->
line ppf "Pcl_let %a@ " fmt_rec_flag rf;
list value_binding ppf l;
class_expr ppf ce
| Pcl_constraint (ce, ct) ->
line ppf "Pcl_constraint@ ";
class_expr ppf ce;
class_type ppf ct
| Pcl_extension (s, arg) ->
line ppf "Pcl_extension \"%s\"@ " s.txt;
payload ppf arg
| Pcl_open (o, e) ->
line ppf "Pcl_open %a %a@ " fmt_override_flag o.popen_override
fmt_longident_loc o.popen_expr;
class_expr ppf e
and class_structure ppf { pcstr_self = p; pcstr_fields = l } =
line ppf "class_structure@ ";
pattern ppf p;
list class_field ppf l
and class_field ppf x =
line ppf "class_field %a@ " fmt_location x.pcf_loc;
attributes ppf x.pcf_attributes;
match x.pcf_desc with
| Pcf_inherit (ovf, ce, so) ->
line ppf "Pcf_inherit %a@ " fmt_override_flag ovf;
class_expr ppf ce;
option string_loc ppf so
| Pcf_val (s, mf, k) ->
line ppf "Pcf_val %a@ " fmt_mutable_flag mf;
line ppf "%a@ " fmt_string_loc s;
class_field_kind ppf k
| Pcf_method (s, pf, k) ->
line ppf "Pcf_method %a@ " fmt_private_flag pf;
line ppf "%a@ " fmt_string_loc s;
class_field_kind ppf k
| Pcf_constraint (ct1, ct2) ->
line ppf "Pcf_constraint@ ";
core_type ppf ct1;
core_type ppf ct2
| Pcf_initializer e ->
line ppf "Pcf_initializer@ ";
expression ppf e
| Pcf_attribute a -> attribute ppf "Pcf_attribute" a
| Pcf_extension (s, arg) ->
line ppf "Pcf_extension \"%s\"@ " s.txt;
payload ppf arg
and class_field_kind ppf = function
| Cfk_concrete (o, e) ->
line ppf "Concrete %a@ " fmt_override_flag o;
expression ppf e
| Cfk_virtual t ->
line ppf "Virtual@ ";
core_type ppf t
and class_declaration ppf x =
line ppf "class_declaration %a@ " fmt_location x.pci_loc;
attributes ppf x.pci_attributes;
line ppf "pci_virt = %a@ " fmt_virtual_flag x.pci_virt;
line ppf "pci_params =@ ";
list type_parameter ppf x.pci_params;
line ppf "pci_name = %a@ " fmt_string_loc x.pci_name;
line ppf "pci_expr =@ ";
class_expr ppf x.pci_expr
and module_type ppf x =
line ppf "module_type %a@ " fmt_location x.pmty_loc;
attributes ppf x.pmty_attributes;
match x.pmty_desc with
| Pmty_ident li -> line ppf "Pmty_ident %a@ " fmt_longident_loc li
| Pmty_alias li -> line ppf "Pmty_alias %a@ " fmt_longident_loc li
| Pmty_signature s ->
line ppf "Pmty_signature@ ";
signature ppf s
| Pmty_functor (Unit, mt2) ->
line ppf "Pmty_functor ()@ ";
module_type ppf mt2
| Pmty_functor (Named (s, mt1), mt2) ->
line ppf "Pmty_functor %a@ " fmt_str_opt_loc s;
module_type ppf mt1;
module_type ppf mt2
| Pmty_with (mt, l) ->
line ppf "Pmty_with@ ";
module_type ppf mt;
list with_constraint ppf l
| Pmty_typeof m ->
line ppf "Pmty_typeof@ ";
module_expr ppf m
| Pmty_extension (s, arg) ->
line ppf "Pmod_extension \"%s\"@ " s.txt;
payload ppf arg
and signature ppf x = list signature_item ppf x
and signature_item ppf x =
line ppf "signature_item %a@ " fmt_location x.psig_loc;
match x.psig_desc with
| Psig_value vd ->
line ppf "Psig_value@ ";
value_description ppf vd
| Psig_type (rf, l) ->
line ppf "Psig_type %a@ " fmt_rec_flag rf;
list type_declaration ppf l
| Psig_typesubst l ->
line ppf "Psig_typesubst@ ";
list type_declaration ppf l
| Psig_typext te ->
line ppf "Psig_typext@ ";
type_extension ppf te
| Psig_exception te ->
line ppf "Psig_exception@ ";
type_exception ppf te
| Psig_module pmd ->
line ppf "Psig_module %a@ " fmt_str_opt_loc pmd.pmd_name;
attributes ppf pmd.pmd_attributes;
module_type ppf pmd.pmd_type
| Psig_modsubst pms ->
line ppf "Psig_modsubst %a = %a@ " fmt_string_loc pms.pms_name
fmt_longident_loc pms.pms_manifest;
attributes ppf pms.pms_attributes
| Psig_recmodule decls ->
line ppf "Psig_recmodule@ ";
list module_declaration ppf decls
| Psig_modtype x ->
line ppf "Psig_modtype %a@ " fmt_string_loc x.pmtd_name;
attributes ppf x.pmtd_attributes;
modtype_declaration ppf x.pmtd_type
| Psig_open od ->
line ppf "Psig_open %a %a@ " fmt_override_flag
od.popen_override fmt_longident_loc od.popen_expr;
attributes ppf od.popen_attributes
| Psig_include incl ->
line ppf "Psig_include@ ";
module_type ppf incl.pincl_mod;
attributes ppf incl.pincl_attributes
| Psig_class l ->
line ppf "Psig_class@ ";
list class_description ppf l
| Psig_class_type l ->
line ppf "Psig_class_type@ ";
list class_type_declaration ppf l
| Psig_extension ((s, arg), attrs) ->
line ppf "Psig_extension \"%s\"@ " s.txt;
attributes ppf attrs;
payload ppf arg
| Psig_attribute a -> attribute ppf "Psig_attribute" a
| _ ->
Log.err (fun m -> m "Printast signature_item not matched");
raise Not_found
and modtype_declaration ppf = function
| None -> line ppf "#abstract"
| Some mt -> module_type ppf mt
and with_constraint ppf x =
match x with
| Pwith_type (lid, td) ->
line ppf "Pwith_type %a@ " fmt_longident_loc lid;
type_declaration ppf td
| Pwith_typesubst (lid, td) ->
line ppf "Pwith_typesubst %a@ " fmt_longident_loc lid;
type_declaration ppf td
| Pwith_module (lid1, lid2) ->
line ppf "Pwith_module %a = %a@ " fmt_longident_loc lid1
fmt_longident_loc lid2
| Pwith_modsubst (lid1, lid2) ->
line ppf "Pwith_modsubst %a = %a@ " fmt_longident_loc lid1
fmt_longident_loc lid2
| _ ->
Log.err (fun m -> m "Printast with_constraint not matched");
raise Not_found
and module_expr ppf x =
line ppf "module_expr %a@ " fmt_location x.pmod_loc;
attributes ppf x.pmod_attributes;
match x.pmod_desc with
| Pmod_ident li -> line ppf "Pmod_ident %a@ " fmt_longident_loc li
| Pmod_structure s ->
line ppf "Pmod_structure@ ";
structure ppf s
| Pmod_functor (Unit, me) ->
line ppf "Pmod_functor ()@ ";
module_expr ppf me
| Pmod_functor (Named (s, mt), me) ->
line ppf "Pmod_functor %a@ " fmt_str_opt_loc s;
module_type ppf mt;
module_expr ppf me
| Pmod_apply (me1, me2) ->
line ppf "Pmod_apply@ ";
module_expr ppf me1;
module_expr ppf me2
| Pmod_constraint (me, mt) ->
line ppf "Pmod_constraint@ ";
module_expr ppf me;
module_type ppf mt
| Pmod_unpack e ->
line ppf "Pmod_unpack@ ";
expression ppf e
| Pmod_extension (s, arg) ->
line ppf "Pmod_extension \"%s\"@ " s.txt;
payload ppf arg
and structure ppf x =
line ppf "struct@ ";
list structure_item ppf x
and structure_item ppf x =
match x.pstr_desc with
| Pstr_eval (e, attrs) ->
line ppf "Pstr_eval ";
attributes ppf attrs;
expression ppf e
| Pstr_value (rf, l) ->
line ppf "%a" fmt_rec_flag rf;
list value_binding ppf l
| Pstr_primitive vd ->
line ppf "Pstr_primitive@ ";
value_description ppf vd
| Pstr_type (rf, l) ->
line ppf "Pstr_type %a@ " fmt_rec_flag rf;
list type_declaration ppf l
| Pstr_typext te ->
line ppf "Pstr_typext@ ";
type_extension ppf te
| Pstr_exception te ->
line ppf "Pstr_exception@ ";
type_exception ppf te
| Pstr_module x ->
line ppf "Pstr_module@ ";
module_binding ppf x
| Pstr_recmodule bindings ->
line ppf "Pstr_recmodule@ ";
list module_binding ppf bindings
| Pstr_modtype x ->
line ppf "Pstr_modtype %a@ " fmt_string_loc x.pmtd_name;
attributes ppf x.pmtd_attributes;
modtype_declaration ppf x.pmtd_type
| Pstr_open od ->
line ppf "Pstr_open %a@ " fmt_override_flag od.popen_override;
module_expr ppf od.popen_expr;
attributes ppf od.popen_attributes
| Pstr_class l ->
line ppf "Pstr_class@ ";
list class_declaration ppf l
| Pstr_class_type l ->
line ppf "Pstr_class_type@ ";
list class_type_declaration ppf l
| Pstr_include incl ->
line ppf "Pstr_include";
attributes ppf incl.pincl_attributes;
module_expr ppf incl.pincl_mod
| Pstr_extension ((s, arg), attrs) ->
line ppf "Pstr_extension \"%s\"@ " s.txt;
attributes ppf attrs;
payload ppf arg
| Pstr_attribute a -> attribute ppf "Pstr_attribute" a
and module_declaration ppf pmd =
str_opt_loc ppf pmd.pmd_name;
attributes ppf pmd.pmd_attributes;
module_type ppf pmd.pmd_type
and module_binding ppf x =
str_opt_loc ppf x.pmb_name;
attributes ppf x.pmb_attributes;
module_expr ppf x.pmb_expr
and core_type_x_core_type_x_location ppf (ct1, ct2, l) =
line ppf "<constraint> %a@ " fmt_location l;
core_type ppf ct1;
core_type ppf ct2
and constructor_decl ppf
{ pcd_name; pcd_args; pcd_res; pcd_loc; pcd_attributes; _ } =
line ppf "%a@ " fmt_location pcd_loc;
line ppf "%a@ " fmt_string_loc pcd_name;
attributes ppf pcd_attributes;
constructor_arguments ppf pcd_args;
option core_type ppf pcd_res
and constructor_arguments ppf = function
| Pcstr_tuple l -> list core_type ppf l
| Pcstr_record l -> list label_decl ppf l
and label_decl ppf
{ pld_name; pld_mutable; pld_type; pld_loc; pld_attributes } =
line ppf "%a@ " fmt_location pld_loc;
attributes ppf pld_attributes;
line ppf "%a@ " fmt_mutable_flag pld_mutable;
line ppf "%a" fmt_string_loc pld_name;
core_type ppf pld_type
and longident_x_pattern ppf (li, p) =
line ppf "%a@ " fmt_longident_loc li;
pattern ppf p
and case ppf { pc_lhs; pc_guard; pc_rhs } =
line ppf "<case>@ ";
pattern ppf pc_lhs;
(match pc_guard with
| None -> ()
| Some g ->
line ppf "<when>@ ";
expression ppf g);
expression ppf pc_rhs
and value_binding ppf x =
line ppf "<def> ";
attributes ppf x.pvb_attributes;
pattern ppf x.pvb_pat;
expression ppf x.pvb_expr
and binding_op ppf x =
line ppf "<binding_op> %a %a" fmt_string_loc x.pbop_op
fmt_location x.pbop_loc;
pattern ppf x.pbop_pat;
expression ppf x.pbop_exp
and string_x_expression ppf (s, e) =
line ppf "<override> %a " fmt_string_loc s;
expression ppf e
and longident_x_expression ppf (li, e) =
line ppf "%a@ " fmt_longident_loc li;
expression ppf e
and label_x_expression ppf (l, e) =
fprintf ppf "<arg> ";
arg_label ppf l;
expression ppf e
and graph_node (name : string) ppf (l, e) =
F.pf ppf "\"%s\"" name;
label_x_expression ppf (l, e)
and label_x_bool_x_core_type_list ppf x =
match x.prf_desc with
| Rtag (l, b, ctl) ->
line ppf "Rtag \"%s\" %s@ " l.txt (string_of_bool b);
attributes ppf x.prf_attributes;
list core_type ppf ctl
| Rinherit ct ->
line ppf "Rinherit@ ";
core_type ppf ct
let rec toplevel_phrase ppf x =
match x with
| Ptop_def s ->
line ppf "Ptop_def\n";
structure ppf s
| Ptop_dir { pdir_name; pdir_arg; _ } -> (
line ppf "Ptop_dir \"%s\"\n" pdir_name.txt;
match pdir_arg with
| None -> ()
| Some da -> directive_argument ppf da)
and directive_argument ppf x =
match x.pdira_desc with
| Pdir_string s -> line ppf "Pdir_string \"%s\"\n" s
| Pdir_int (n, None) -> line ppf "Pdir_int %s\n" n
| Pdir_int (n, Some m) -> line ppf "Pdir_int %s%c\n" n m
| Pdir_ident li -> line ppf "Pdir_ident %a\n" fmt_longident li
| Pdir_bool b -> line ppf "Pdir_bool %s\n" (string_of_bool b)
let interface = signature
let implementation = structure
let top_phrase = toplevel_phrase
end
let log_info pp exp = Log.info (fun m -> m "ppx_graph:@ %a" pp exp)
let graph_structure str =
let string_constants_of =
object
inherit [string list] Ast_traverse.fold as super
(* sig
val interface : Format.formatter -> signature_item list -> unit
val implementation : Format.formatter -> structure_item list -> unit
val top_phrase : Format.formatter -> toplevel_phrase -> unit
val expression : int -> Format.formatter -> expression -> unit
val structure : int -> Format.formatter -> Parsetree.structure -> unit
val payload : int -> Format.formatter -> payload -> unit
end *)
method! expression e acc =
let acc = super#expression e acc in
F.str "%a" Printast.expression e :: acc
(* match e.pexp_desc with
| Pexp_constant (Pconst_string (s, _, _)) -> s :: acc
| Pexp_let (_, vb, exp) ->
F.str "\"%a\" -> \"%a\""
(F.parens
(F.list
~sep:(fun ppf () -> F.string ppf "->")
(F.pair Pprintast.pattern ppPprintast.expression)))
(List.map (fun vb -> (vb.pvb_pat, vb.pvb_expr)) vb)
Pprintast.expression exp
:: acc
| _ -> acc *)
(* method! pattern p acc =
let acc = super#pattern p acc in
match p.ppat_desc with
| Ppat_constant (Pconst_string (s, _, _)) -> s :: acc
| _ -> acc *)
end
in
Log.debug (fun m ->
m "graph_structure:@[<hov> %a@]"
(F.list ~sep:(fun ppf () -> F.pf ppf "\n") F.string)
(List.rev (string_constants_of#structure str [])))
let init () =
Driver.register_transformation
~impl:(fun str ->
log_info Ocaml_common.Pprintast.structure str;
(* log_info Ocaml_common.Printast.implementation str; *)
Ocaml_common.Clflags.locations := false;
log_info Printast.implementation str;
Ocaml_common.Clflags.locations := true;
str)
"ppx_graph"

5837
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>
<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>

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

44
notes.org Normal file
View File

@ -0,0 +1,44 @@
* 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
* 221211
ok you got the scroll box mostly working so next:
** fix the scroll jump bugs
** setup better keybindings
** fix cursor and active focus indicators
* 221210 -
** need to resolve the issue with the ui.t Resize type.
this is an issue with the direction of the determination of the .height and .width fields of Ui.t
currently you were planning to combine update_sensors and update_size
in the original nottui.ml library, are Ui.t.w and Ui.t.h determined from the top down orbottom up?
the bottom up, becahse they are chars

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>

645
toplevel.ml Normal file
View File

@ -0,0 +1,645 @@
(* 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
module Log = Log_js.Log
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;
Ppx_graph.setup_graph ~container ~textbox;
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)

37
unicom.org Normal file
View File

@ -0,0 +1,37 @@
UNICOM
unifying tools for thought and commmunication
At the top level is a kind of "trace" that connects all the tools together
and records the exact use of all the tools in a session. Traces are the only
kind of document in the system, and are basically written by a user when
they interact with the system. Users can store, retrieve, view, and modify
traces as a way of controlling system state, retrieving history, and sharing
information?
tools for thought:
- todo lists
- personal journal
- calendar
- calculator/spreadsheet
- health, fitness, finance data tracking, analysis
- Integrated Development Environment [for development/configuration of all these tools]
tools for communication:
- collaborative documents
video / .txt file
- content discovery,display,labeling?
twitter / netflix / books
- direct messages
sms / email
- group messages
private (chat) / private (irc,twitter)
- audio/music production
sound driver / DAW
- cad
KiCad / OpenSCAD