72 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
cqc
c81dce7148 cursor movement by char works across lines (i.e. subnested joins) 2022-03-19 16:05:11 -05:00
cqc
205f650eac Action.pp_t and cleanup 2022-03-19 15:14:23 -05:00
cqc
8067e29ea8 C-f and C-b 2022-03-19 12:10:23 -05:00
cqc
0d831aa9cf ui node tree pretty-printer 2022-03-13 15:55:10 -05:00
cqc
ecf9983728 working on cursor contro 2022-02-13 16:28:58 -06:00
cqc
a82c9464f4 here i am going to abandon using the linear "Regions" which are "Trope"s from grenier.trope which were adopted while star-struck from a weird ui library i can't remember the name of at the moment, because using regions with nodes is just pure fucking premature optimization and makes the backward references really hard and i don't want to deal with it anymore 2022-02-06 18:34:17 -06:00
cqc
481870e067 i left it like this for a long time whoops 2022-01-04 04:17:26 -06:00
cqc
8ee3789cb9 mr. derpsalot derps more; refactored the ui widget thing again... 2021-11-08 22:27:47 -06:00
cqc
983fc326d6 storeview 2021-10-29 12:27:58 -05:00
cqc
364e3e7165 getting super confused while trying to make generic tree structure operations that map to irmin 2021-10-25 11:08:01 -05:00
cqc
4054f78564 fonts and lwd and nottui and more progress towards the irc client 2021-10-20 14:15:08 -05:00
cqc
50073f19e1 well inuit integration kinda works but is still v broken 2021-10-14 10:05:22 -05:00
cqc
4ec076826c (failed?) attempt to use Inuit with Format.symbolic_output_buffer 2021-10-13 07:34:52 -05:00
cqc
f3d52bc506 Further integration of lwt, irc basically works 2021-10-11 11:52:36 -05:00
cqc
630ccb0a6f lol took me forever to understand lwt but finally have concurrency in the actor event processing handlers 2021-10-07 14:07:26 -05:00
cqc
c8e9e1bd6c remove half done lwt stuff while we continue just working on the editor dammit 2021-09-28 08:00:02 -05:00
cqc
cf01415754 how to start lwt-ifying the pane tree portion where Display.state gets threaded through all the image drawing functions 2021-09-23 18:13:19 -05:00
cqc
eca8a055cf revamped sdl level event handling code 2021-09-22 18:34:15 -05:00
cqc
fe935c4e1f input and bindings refactoring 2021-09-22 17:28:12 -05:00
cqc
72e907a341 removing entries and creating subtrees kinda works 2021-09-22 10:31:52 -05:00
cqc
d095c1478a working towards store editor features 2021-09-21 14:22:48 -05:00
cqc
72e3bab78f pressing e lets you edit the file, but it doesn't save it yet 2021-09-16 10:42:13 -05:00
cqc
1d99823d44 refactored navigation and displays contents 2021-09-14 11:24:23 -05:00
64 changed files with 8482 additions and 1595 deletions

1
.console Normal file
View File

@ -0,0 +1 @@
it consoles you

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

238
dune
View File

@ -1,63 +1,183 @@
(env
(dev
(flags (:standard -warn-error -A))))
(executable
(name main)
(modes byte)
(modules main)
(link_flags (-linkall))
(libraries
topinf
tsdl
tgls.tgles2
wall
zed
lambda-term
irmin-unix
ocaml-compiler-libs.common
ocaml-compiler-libs.bytecomp
ocaml-compiler-libs.toplevel))
(executable
(name irc)
(modes byte)
(modules irc)
(libraries
fmt
topinf
irc-client
irc-client-lwt
irc-client-unix
irc-client-tls
))
(executable
(name boot)
(modes byte)
(modules boot)
(link_flags (-linkall))
(libraries
lambda-term
topinf))
(dev (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
(name topinf)
(modes byte)
(modules topinf)
(name log_js)
(modes byte)
(preprocess (pps js_of_ocaml-ppx))
(flags (:standard -rectypes -linkall))
(modules log_js)
(libraries
fmt
tsdl
tgls.tgles2
wall
zed
lambda-term
irmin-unix
irc-client
irc-client-lwt
irc-client-unix
irc-client-tls
ocaml-compiler-libs.common
ocaml-compiler-libs.bytecomp
ocaml-compiler-libs.toplevel))
logs))
(library
(name graphast)
(modes byte)
(kind ppx_rewriter)
(modules graphast)
(libraries
logs
ppxlib
fmt
lwt
))
(executable
(name ppx_graph)
(modes byte)
(modules ppx_graph)
(libraries
graphast))
(executable
(name boot_js)
(modes byte js)
(preprocess (pps js_of_ocaml-ppx))
(flags (:standard -rectypes -linkall))
(modules boot_js human)
(libraries
fmt
graphv_webgl
js_of_ocaml-lwt
js_of_ocaml-compiler
js_of_ocaml-toplevel
digestif.ocaml
checkseum.ocaml
irmin.mem
git
irmin-git
cohttp-lwt-jsoo
mimic
uri
gg
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}
; 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)
(name komm)
(wrapped_executables false)
(lang dune 3.4)
(name boot)

202
fonts/LICENSE.txt Normal file
View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

94
fonts/OFL.txt Normal file
View File

@ -0,0 +1,94 @@
Copyright (c) 1994-2021, SIL International (http://www.sil.org/),
with Reserved Font Names "Scheherazade" and "SIL".
This Font Software is licensed under the SIL Open Font License, Version 1.1.
This license is copied below, and is also available with a FAQ at:
http://scripts.sil.org/OFL
-----------------------------------------------------------
SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
-----------------------------------------------------------
PREAMBLE
The goals of the Open Font License (OFL) are to stimulate worldwide
development of collaborative font projects, to support the font creation
efforts of academic and linguistic communities, and to provide a free and
open framework in which fonts may be shared and improved in partnership
with others.
The OFL allows the licensed fonts to be used, studied, modified and
redistributed freely as long as they are not sold by themselves. The
fonts, including any derivative works, can be bundled, embedded,
redistributed and/or sold with any software provided that any reserved
names are not used by derivative works. The fonts and derivatives,
however, cannot be released under any other type of license. The
requirement for fonts to remain under this license does not apply
to any document created using the fonts or their derivatives.
DEFINITIONS
"Font Software" refers to the set of files released by the Copyright
Holder(s) under this license and clearly marked as such. This may
include source files, build scripts and documentation.
"Reserved Font Name" refers to any names specified as such after the
copyright statement(s).
"Original Version" refers to the collection of Font Software components as
distributed by the Copyright Holder(s).
"Modified Version" refers to any derivative made by adding to, deleting,
or substituting -- in part or in whole -- any of the components of the
Original Version, by changing formats or by porting the Font Software to a
new environment.
"Author" refers to any designer, engineer, programmer, technical
writer or other person who contributed to the Font Software.
PERMISSION & CONDITIONS
Permission is hereby granted, free of charge, to any person obtaining
a copy of the Font Software, to use, study, copy, merge, embed, modify,
redistribute, and sell modified and unmodified copies of the Font
Software, subject to the following conditions:
1) Neither the Font Software nor any of its individual components,
in Original or Modified Versions, may be sold by itself.
2) Original or Modified Versions of the Font Software may be bundled,
redistributed and/or sold with any software, provided that each copy
contains the above copyright notice and this license. These can be
included either as stand-alone text files, human-readable headers or
in the appropriate machine-readable metadata fields within text or
binary files as long as those fields can be easily viewed by the user.
3) No Modified Version of the Font Software may use the Reserved Font
Name(s) unless explicit written permission is granted by the corresponding
Copyright Holder. This restriction only applies to the primary font name as
presented to the users.
4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
Software shall not be used to promote, endorse or advertise any
Modified Version, except to acknowledge the contribution(s) of the
Copyright Holder(s) and the Author(s) or with their explicit written
permission.
5) The Font Software, modified or unmodified, in part or in whole,
must be distributed entirely under this license, and must not be
distributed under any other license. The requirement for fonts to
remain under this license does not apply to any document created
using the Font Software.
TERMINATION
This license becomes null and void if any of the above conditions are
not met.
DISCLAIMER
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
OTHER DEALINGS IN THE FONT SOFTWARE.

77
fonts/README.txt Normal file
View File

@ -0,0 +1,77 @@
Roboto Mono Variable Font
=========================
This download contains Roboto Mono as both variable fonts and static fonts.
Roboto Mono is a variable font with this axis:
wght
This means all the styles are contained in these files:
RobotoMono-VariableFont_wght.ttf
RobotoMono-Italic-VariableFont_wght.ttf
If your app fully supports variable fonts, you can now pick intermediate styles
that arent available as static fonts. Not all apps support variable fonts, and
in those cases you can use the static font files for Roboto Mono:
static/RobotoMono-Thin.ttf
static/RobotoMono-ExtraLight.ttf
static/RobotoMono-Light.ttf
static/RobotoMono-Regular.ttf
static/RobotoMono-Medium.ttf
static/RobotoMono-SemiBold.ttf
static/RobotoMono-Bold.ttf
static/RobotoMono-ThinItalic.ttf
static/RobotoMono-ExtraLightItalic.ttf
static/RobotoMono-LightItalic.ttf
static/RobotoMono-Italic.ttf
static/RobotoMono-MediumItalic.ttf
static/RobotoMono-SemiBoldItalic.ttf
static/RobotoMono-BoldItalic.ttf
Get started
-----------
1. Install the font files you want to use
2. Use your app's font picker to view the font family and all the
available styles
Learn more about variable fonts
-------------------------------
https://developers.google.com/web/fundamentals/design-and-ux/typography/variable-fonts
https://variablefonts.typenetwork.com
https://medium.com/variable-fonts
In desktop apps
https://theblog.adobe.com/can-variable-fonts-illustrator-cc
https://helpx.adobe.com/nz/photoshop/using/fonts.html#variable_fonts
Online
https://developers.google.com/fonts/docs/getting_started
https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Fonts/Variable_Fonts_Guide
https://developer.microsoft.com/en-us/microsoft-edge/testdrive/demos/variable-fonts
Installing fonts
MacOS: https://support.apple.com/en-us/HT201749
Linux: https://www.google.com/search?q=how+to+install+a+font+on+gnu%2Blinux
Windows: https://support.microsoft.com/en-us/help/314960/how-to-install-or-remove-a-font-in-windows
Android Apps
https://developers.google.com/fonts/docs/android
https://developer.android.com/guide/topics/ui/look-and-feel/downloadable-fonts
License
-------
Please read the full license text (LICENSE.txt) to understand the permissions,
restrictions and requirements for usage, redistribution, and modification.
You can use them freely in your products & projects - print or digital,
commercial or otherwise.
This isn't legal advice, please consider consulting a lawyer and see the full
license for all details.

BIN
fonts/Roboto-Black.ttf Normal file

Binary file not shown.

Binary file not shown.

BIN
fonts/Roboto-Bold.ttf Executable file → Normal file

Binary file not shown.

BIN
fonts/Roboto-BoldItalic.ttf Normal file

Binary file not shown.

BIN
fonts/Roboto-Italic.ttf Normal file

Binary file not shown.

BIN
fonts/Roboto-Light.ttf Executable file → Normal file

Binary file not shown.

Binary file not shown.

BIN
fonts/Roboto-Medium.ttf Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
fonts/Roboto-Thin.ttf Normal file

Binary file not shown.

BIN
fonts/Roboto-ThinItalic.ttf Normal file

Binary file not shown.

BIN
fonts/Roboto.zip Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
fonts/Roboto_Mono.zip Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
fonts/Scheherazade_New.zip Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

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"

3827
human.ml Normal file

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>

View File

@ -6,11 +6,13 @@ let print_directives () =
Format.printf "directive_info_table:@.";
Hashtbl.iter (fun n _ -> Format.printf "\t%s@." n) Topinf.directive_info_table;;
#directory "+compiler-libs";;
(*#directory "+compiler-libs";; *)
let print_modules () =
Format.printf "Env.fold_modules !Topinf.toplevel_env :\n";
Env.fold_modules (fun modname _ _ () -> Format.printf "\t%s@." modname) None !Topinf.toplevel_env ();;
(*print_modules ();;*)
#use_silently "main.ml";;
#use_silently "human.ml";;
start ();;

567
irc.ml
View File

@ -1,109 +1,494 @@
(*
when all you can do is type, making things more complicated than a list is hard?
we need to design this somehow before implementing it
really the graphical drawing / window management funcitons i think at this point.
features:
- message drafts? more like, if you send too many messages to someone all at once it will hold them so you can respond later and not flood people.......
- i mean really what you want is an editable stream, so you can stage messages for later
- because i mean, if this is a bicycle, and you can make it however you want, you can just fuck with the conversation thread with computer assistance instaed of just relying on your memory.
*)
open Lwt
module C = Irc_client_tls
module M = Irc_message
open Lwt_react
module F = Fmt
let host = ref "irc.hackint.org"
let port = ref 6697
let nick = ref "cqcaml"
let channel = ref "#freeside"
let message = "Hello, world! This is a test from ocaml-irc-client"
module Communicator = struct
let base_path = "communicator"
let topch = "top"
let output_channel_of_ppf ppf =
Lwt_io.make ~mode:Output (fun b o l ->
let s = String.sub (Lwt_bytes.to_string b) o l in
Fmt.pf ppf "%s" s ;
Lwt.return (String.length s) )
module Istore = struct
include Human.Store
let callback connection result =
match result with
| Result.Ok ({M.command= M.Other _; _} as msg) ->
Lwt_io.printf "Got unknown message: %s\n" (M.to_string msg)
>>= fun () -> Lwt_io.flush Lwt_io.stdout
| Result.Ok ({M.command= M.PRIVMSG (_target, data); _} as msg) ->
Lwt_io.printf "Got message: %s\n" (M.to_string msg)
>>= fun () ->
Lwt_io.flush Lwt_io.stdout
>>= fun () ->
C.send_privmsg ~connection ~target:"cqc"
~message:("ack: " ^ data)
| Result.Ok msg ->
Lwt_io.printf "Got message: %s\n" (M.to_string msg)
>>= fun () -> Lwt_io.flush Lwt_io.stdout
| Result.Error e -> Lwt_io.printl e
let from_storeview (sv : storeview) = sv.store
let lwt_main () =
C.reconnect_loop ~after:30
~connect:(fun () ->
Lwt_io.printl "Connecting..."
>>= fun () ->
C.connect_by_name ~server:!host ~port:!port ~nick:!nick () )
~f:(fun connection ->
Lwt_io.printl "Connected"
>>= fun () ->
Lwt_io.printl "send join msg"
>>= fun () ->
C.send_join ~connection ~channel:!channel
>>= fun () ->
C.send_privmsg ~connection ~target:!channel ~message )
~callback ()
include Human.Store.Istore
end
module Message = struct
type t = {time: string list; content: string}
let make ?(time = Unix.gettimeofday ()) content =
let tm = Unix.localtime time in
{ time=
List.map string_of_int
[tm.tm_year + 1900; tm.tm_mon + 1; tm.tm_mday; tm.tm_hour]
@ [ string_of_float
( float_of_int (tm.tm_min * tm.tm_sec)
+. fst (modf time) ) ]
; content }
end
module Channel = struct
(* a channels step key may not be blank (i.e. "") *)
type t = {store: Istore.t; path: Istore.key}
let make (store : Istore.t) ~path ~(name : string) =
Lwt.return {store; path= path @ ["#" ^ name]}
let add_msg {store; path} (msg : Message.t) : unit Lwt.t =
F.epr "add_msg path=[" ;
F.list ~sep:F.semi F.string F.stderr (path @ msg.time) ;
F.epr "] content=%s @." msg.content ;
Istore.set_exn store ~info:Irmin.Info.none (path @ msg.time)
msg.content
end
module Tree = struct
open Message
type selection = Istore.Key.t
type t = {store: Istore.t; view: Istore.key}
let contents {store; view} (s : selection) :
Istore.Contents.t option Lwt.t =
Istore.find store (view @ s)
let make_top ?(view = [base_path]) gitpath branchname : t Lwt.t =
Istore.Repo.v (Irmin_git.config gitpath)
>>= fun repo ->
Istore.of_branch repo branchname
>>= fun store ->
let t = {store; view} in
Channel.make store ~path:view ~name:topch
>>= fun ch_top ->
Channel.add_msg ch_top
(Message.make "Communicator restarting...")
>>= fun () ->
Channel.add_msg ch_top
(Message.make "Currently only IRC is implemented")
>>= fun () -> Lwt.return t
let add {store; view} ~(name : string list) ~(config : Istore.tree)
: t Lwt.t =
Istore.get_tree store name
>>= fun tree ->
Istore.Tree.remove tree ["_config"]
>>= fun tree ->
Istore.Tree.add_tree tree [] config
>>= fun tree ->
Istore.set_tree_exn ~info:Irmin.Info.none store name tree
>>= fun () -> Lwt.return {store; view}
end
module Protocol = struct
type t = Irc | Email | Rss | Mublog | ActivityPub
let to_string = function
| Irc -> ("IRC", "Internet Relay Chat")
| Email -> ("E-mail", "Electronic Mail")
| Rss -> ("RSS", "Really Simple Subscriptions???")
| Mublog -> ("uBlog", "Microblogging (Twitter)")
| ActivityPub -> ("ActivityPub", "Mastodon, etc.")
let id t = fst (to_string t)
let desc t = snd (to_string t)
end
module Irc = struct
module C = Irc_client_tls
module M = Irc_message
module Config = struct
type t = Istore.tree
open Lwt.Infix
let path = "_config"
let make_connection Tree.{store; view} server port nick =
let name = F.str "%s@%s:%d" nick server port in
Istore.Tree.add Istore.Tree.empty ["server"] server
>>= fun t' ->
Istore.Tree.add t' ["port"] (string_of_int port)
>>= fun t' ->
Istore.Tree.add t' ["nick"] nick
>>= fun t' ->
Istore.Tree.add t' ["protocol"] (Protocol.id Irc)
>>= fun t' ->
F.epr "Creating connection config /%s/%s/@." name path ;
Istore.set_tree_exn ~info:Irmin.Info.none store
(view @ [name; path])
t'
>>= fun _ -> Lwt.return_unit
let server t : string Lwt.t = Istore.Tree.get t [path; "server"]
let port t : int Lwt.t =
Istore.Tree.get t [path; "port"] >|= fun p -> int_of_string p
let nick t : string Lwt.t = Istore.Tree.get t [path; "nick"]
let protocol t : string option Lwt.t =
Istore.Tree.find t [path; "protocol"]
end
let get_channels ~store ~path =
Istore.list store path
>>= fun c ->
let rec iter l =
Lwt_list.filter_map_p
(fun (s, _) ->
if String.length s > 1 && String.get s 0 = '#' then
Lwt.return (Some s)
else Lwt.return None )
l in
iter c
let connect ?(path = [base_path]) ({store; _} : Tree.t) :
unit Lwt.t =
(* search for all connections and start them *)
(* also need ot figure out how to preserve custom ordering of items like servers and channels
maybe just a _order file that has the ordering of files listed and hten gets updated etc. *)
Channel.make store ~path ~name:topch
>>= fun top_channel ->
let _top_msg str =
Channel.add_msg top_channel (Message.make str) in
let channel_assoc = ref [] in
let make_channel store path (name : string) =
Channel.make store ~path ~name
>>= fun ch ->
channel_assoc := (name, ch) :: !channel_assoc ;
Channel.add_msg ch
(Message.make (F.str "channel %s created" name))
>>= fun () -> Lwt.return ch in
Istore.list store path
>>= fun servers ->
Lwt_list.filter_p
(fun (_, tree) ->
Config.protocol tree
>|= function Some p -> p = Protocol.id Irc | None -> false
)
servers
(* filter out non-irc protocols, TODO currently relying on this to filter out non-server folders too *)
>>= fun servers ->
F.epr "protocols filtered for irc@." ;
Lwt_list.iter_p
(fun (name, tree) ->
F.epr "Irc.connect server=%s @." name ;
Config.nick tree
>>= fun nick ->
Config.server tree
>>= fun server ->
Config.port tree
>>= fun port ->
Channel.make store ~path:(path @ [name]) ~name:topch
>>= fun server_channel ->
let add_msg s =
Channel.add_msg server_channel (Message.make s) in
C.reconnect_loop ~after:30
~connect:(fun () ->
add_msg "Connecting..."
>>= fun () ->
C.connect_by_name ~server ~port ~nick ()
>>= fun c -> Lwt.return c )
~f:(fun connection ->
F.epr "Irc.connect C.reconnect_loop ~f:(Connected...)@." ;
add_msg "Connected"
>>= fun () ->
get_channels ~store ~path:[name]
>>= fun chs ->
Lwt_list.iter_p
(fun chname ->
C.send_join ~connection ~channel:chname
>>= fun () ->
ignore (make_channel store [name] chname) ;
Lwt.return_unit )
chs )
~callback:(fun _connection result ->
match result with
| Result.Ok ({M.command= M.Other _; _} as msg) ->
add_msg (M.to_string msg)
| Result.Ok
{M.command= M.PRIVMSG (target, data); prefix= user}
-> (
let user =
match user with
| Some u -> List.hd (String.split_on_char '!' u)
| None -> "unknown" in
match List.assoc_opt target !channel_assoc with
| Some ch ->
Channel.add_msg ch
(Message.make (F.str "<%s> %s" user data))
| None ->
make_channel store [server] target
>>= fun ch ->
Channel.add_msg ch
(Message.make (F.str "<%s> %s" user data)) )
| Result.Ok msg ->
add_msg (M.to_string msg)
>>= fun () -> Lwt.return_unit
| Result.Error e -> Lwt_io.printl e )
() )
servers
end
module Panel = struct
open Panel
open Panel.Ui
type viewer =
{ step: string
; var: view Lwd.var
; mutable parent: view
; mutable node: viewer list }
and view = [`Empty | `View of viewer]
let add v node =
( match v with
| `View v ->
v.node <- node :: v.node ;
Lwd.set v.var (`View v)
| `Empty -> () ) ;
node.parent <- v ;
Lwd.set node.var (`View node) ;
`View node
let make step parent node =
let v = {step; var= Lwd.var `Empty; parent; node} in
( match parent with
| `View parent ->
parent.node <- v :: parent.node ;
Lwd.set parent.var (`View parent)
| `Empty -> () ) ;
let rec iter = function
| [] -> ()
| x :: xs ->
x.parent <- `View v ;
Lwd.set x.var (`View x) ;
iter xs in
iter node ;
Lwd.set v.var (`View v) ;
`View v
let rec last = function
| [] -> None
| [x] -> Some x
| _ :: xs -> last xs
let rec last_def = function
| [] -> "[]"
| [x] -> x
| _ :: xs -> last_def xs
let find_node ~step ~view =
match view with
| `Empty -> None
| `View v -> List.find_opt (fun v' -> v'.step = step) v.node
let string_of_path path =
"[" ^ F.str "%a" (F.list ~sep:F.semi F.string) path ^ "]"
let remove (v : viewer) =
Lwd.set v.var `Empty ;
`Empty
let storeview store path =
Istore.get_tree store path
>>= fun tree ->
let update d key (view : view) : view option Lwt.t =
F.epr "fold ~pre:update key=%s @." (string_of_path key) ;
Lwt.return
( match
( List.rev key
, find_node
~step:(Option.value (last key) ~default:"[]")
~view
, d )
with
| [], None, `Added | [], None, `Updated ->
Some (make "[]" view [])
| [], Some v, _ -> Some (`View v)
| [], None, `Removed -> None
| _ :: k :: _, _, _ when k.[0] == '#' -> None
| k :: _, None, `Added | k :: _, None, `Updated ->
Some (make k view [])
| _ :: _, None, `Removed -> None
| _ :: _, Some v, _ -> Some (`View v) ) in
(* if pre returns None, the children of that node are skipped. *)
let rec map ?(key = []) ~node tree (acc : view) : view Lwt.t =
let acc =
match acc with
| `Empty -> make (last_def key) acc []
| v -> v in
Istore.Tree.list tree []
>>= fun tree ->
Lwt_list.iter_s
(fun (s, t) ->
let k = key @ [s] in
node k acc
>|= function
| Some a ->
F.epr "storeview Fold step=%s @." s ;
ignore (map ~key:k ~node t a)
| None -> F.epr "storeview None step=%s @." s )
tree
>|= fun () -> acc in
map ~node:(update `Added) tree `Empty
>>= fun t ->
let root = Lwd.var t in
Istore.watch_key store path (fun diff ->
let d, tree =
match diff with
| `Added (_, tree) -> (`Added, tree)
| `Removed (_, tree) -> (`Removed, tree)
| `Updated (_, (_, tree)) -> (`Updated, tree) in
map ~node:(update d) tree t
>>= fun t' -> Lwd.set root t' ; Lwt.return_unit )
>>= fun watch -> Lwt.return (watch, root)
let channelview (store, path) =
storeview store path
>>= fun (_watch, root) ->
let ui =
Lwd.join
(Lwd.map (Lwd.get root) ~f:(function
| `Empty ->
failwith "channelview says root Lwd.var is `Empty"
| `View v ->
let rec iter ?(indent = 0) (v : viewer) =
Lwd.bind (Lwd.get v.var) ~f:(function
| `Empty -> Lwd.return Ui.empty
| `View v' ->
let sub =
Lwd_utils.pack Ui.pack_y
(List.map
(iter ~indent:(indent + 1))
v'.node ) in
Lwd.map sub ~f:(fun sub ->
Ui.join_y
(Ui.string
( String.make indent '>' ^ " "
^ v'.step ) )
sub ) ) in
iter v ) ) in
let chs, chs_push = Lwt_stream.create () in
Channel.make store ~path:[base_path] ~name:topch
>>= fun ch ->
chs_push (Some ch) ;
Lwt.return (chs, ui)
let messagelist ({store; path} : Channel.t) mlist :
Istore.watch Lwt.t =
let mlist' () =
Istore.get_tree store path
>>= fun tree ->
Istore.Tree.fold ~depth:(`Eq 5)
~contents:(fun key contents view ->
match key with
| [y; m; d; h; s] ->
Lwt.return (((y, m, d, h, s), contents) :: view)
| _ ->
F.epr
"ERROR: messagelist (fold ~depth:(`Eq 5)) got \
wrong number of steps@." ;
Lwt.return view )
~node:(fun _key _node view ->
F.epr
"ERROR: messagelist (fold ~depth:(`Eq 5)) found a \
node@." ;
Lwt.return view )
tree [] in
mlist' ()
>>= fun ml ->
Lwd.set mlist ml ;
Istore.watch_key store path (fun _ ->
mlist' ()
>>= fun mlist' -> Lwt.return (Lwd.set mlist mlist') )
let messageview ch =
let mlist = Lwd.var [(("", "", "", "", ""), "")] in
let rec update_messagelist watch () =
Lwt_stream.last_new ch
>>= fun ch ->
( match watch with
| None -> Lwt.return_unit
| Some w -> Istore.unwatch w )
>>= fun () ->
messagelist ch mlist
>>= fun watch -> update_messagelist (Some watch) () in
Lwt.async (update_messagelist None) ;
Lwt.return
(Lwd.map (Lwd.get mlist) ~f:(fun mlist ->
scroll
(List.fold_left
(fun doc ((year, month, day, hour, sec), content) ->
F.epr
"Communicator.Panel.messagelist ch.content=%s@."
content ;
doc
^/^ Ui.string
(F.str "%s.%s.%s.%s.%s" year month day hour
sec )
^^ Ui.string " | " ^^ string content )
Ui.empty mlist ) ) )
let commview (store, path) =
channelview (store, List.rev (List.tl (List.rev path)))
>>= fun (ch, cv) ->
messageview ch
>>= fun mv ->
Lwt.return (Lwd.map2 cv mv ~f:(fun c m -> join_x c m))
let panel ({store; view} : Tree.t) : (Event.t -> atom Lwt.t) Lwt.t
=
commview (store, view) >>= fun cv -> Panel.Ui.panel cv
end
end
(**
program starts...
- spawn connections to servers
- these connections will populate the Channel.t in a Channel.tree
**)
let _ =
Lwt_main.run
(Lwt.catch lwt_main (fun e ->
Printf.printf "exception: %s\n" (Printexc.to_string e) ;
exit 1 ) )
(* ocamlfind ocamlopt -package irc-client.lwt -linkpkg code.ml *)
(*open Lwt
module C = Irc_client_lwt
let host = "irc.hackint.org"
let port = 6697
let realname = "Demo IRC bot"
let nick = "cqcqcqcqc"
let username = nick
let channel = "#freeside"
let message = "Hello, world! This is a test from ocaml-irc-client"
let callback oc _connection result =
let open Irc_message in
match result with
| Result.Ok msg ->
Fmt.epr "irc msg: msg" ;
Lwt_io.fprintf oc "Got message: %s\n" (to_string msg)
| Result.Error e -> Lwt_io.fprintl oc e
let lwt_main =
let oc = output_channel_of_ppf !Topinf.ppf in
Lwt_unix.gethostbyname host
>>= fun he ->
C.connect
~addr:he.Lwt_unix.h_addr_list.(0)
~port ~username ~mode:0 ~realname ~nick ()
>>= fun connection ->
Lwt_io.fprintl oc "Connected"
>>= fun () ->
C.send_join ~connection ~channel
>>= fun () ->
C.send_privmsg ~connection ~target:channel ~message
>>= fun () ->
C.listen ~connection ~callback:(callback oc) ()
>>= fun () -> C.send_quit ~connection ()
let _ = Lwt_main.run lwt_main
*)
Lwt.async (fun () ->
Communicator.Tree.make_top "commstore" "current"
>>= fun comm ->
Communicator.Irc.Config.make_connection comm "irc.hackint.org"
6697 "cqcaml"
>>= fun () ->
Lwt.async (fun () -> Communicator.Irc.connect comm) ;
F.epr
"root_actor := std_actor (Communicator.Panel.panel comm)@." ;
Communicator.Panel.panel comm
>|= fun f ->
root_actor :=
std_actor
(Lwt.return
Panel.
{ act=
(fun _ events ->
Lwt_list.fold_left_s
(fun _ ev ->
f ev
>>= fun i ->
Lwt.return (fun s ->
( s
, ( Gg.Box2.of_pts Gg.V2.zero (snd i)
, fst i ) ) ) )
Display.pane_empty events )
; subpanels= []
; tag= "irc" } ) )

View File

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

1224
main.ml

File diff suppressed because it is too large Load Diff

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

361
opam-switch Normal file
View File

@ -0,0 +1,361 @@
opam-version: "2.0"
compiler: ["ocaml-system.4.13.1"]
roots: [
"bogue.20210917"
"findlib_top.v0.11.0"
"glfw-ocaml.3.3.1-1"
"huffman.0.1.2"
"inuit.0.4.1"
"irc-client.0.7.0"
"irc-client-lwt.0.7.0"
"irc-client-tls.0.7.0"
"irc-client-unix.0.7.0"
"irmin.2.9.0"
"irmin-unix.2.9.0"
"lambda-term.3.1.0"
"lwd.0.1"
"lwt_ppx.2.0.3"
"merlin.4.4-413"
"note.0.0.1"
"nottui.0.1"
"nottui-lwt.0.1"
"nottui-pretty.0.1"
"ocaml-manual.4.13.0"
"ocaml-system.4.13.1"
"ocamlformat.0.20.1"
"odig.0.0.7"
"odoc.2.0.2"
"pp.1.1.2"
"pprint.20211129"
"tgls.0.8.5"
"tsdl.0.9.8"
"user-setup.0.7"
"wall.0.4.1"
"zed.3.1.0"
]
installed: [
"angstrom.0.15.0"
"arp.3.0.0"
"asn1-combinators.0.2.6"
"astring.0.8.5"
"awa.0.0.4"
"awa-mirage.0.0.4"
"b0.0.0.3"
"base.v0.14.2"
"base-bigarray.base"
"base-bytes.base"
"base-threads.base"
"base-unix.base"
"base64.3.5.0"
"bheap.2.0.0"
"bigarray-compat.1.0.0"
"bigstringaf.0.8.0"
"biniou.1.2.1"
"bogue.20210917"
"bos.0.2.0"
"ca-certs.0.2.2"
"ca-certs-nss.3.71"
"camomile.1.0.2"
"carton.0.4.3"
"carton-git.0.4.3"
"carton-lwt.0.4.3"
"cf.0.4"
"cf-lwt.0.4"
"charInfo_width.1.1.0"
"checkseum.0.3.2"
"cmdliner.1.0.4"
"cohttp.4.0.0"
"cohttp-lwt.4.0.0"
"cohttp-lwt-unix.4.0.0"
"conduit.4.0.2"
"conduit-lwt.4.0.2"
"conduit-lwt-unix.4.0.2"
"conf-cairo.1"
"conf-gles2.1"
"conf-glfw3.2"
"conf-gmp.3"
"conf-gmp-powm-sec.3"
"conf-libffi.2.0.0"
"conf-libX11.1"
"conf-m4.1"
"conf-pkg-config.2"
"conf-sdl2.1"
"conf-sdl2-image.1"
"conf-sdl2-ttf.1"
"cppo.1.6.8"
"crunch.3.2.0"
"csexp.1.5.1"
"cstruct.6.0.1"
"cstruct-lwt.6.0.1"
"cstruct-sexp.6.0.1"
"cstruct-unix.6.0.1"
"ctypes.0.20.0"
"ctypes-foreign.0.18.0"
"decompress.1.4.2"
"digestif.1.1.0"
"dispatch.0.5.0"
"domain-name.0.3.1"
"dot-merlin-reader.4.1"
"duff.0.4"
"dune.2.9.1"
"dune-build-info.2.9.1"
"dune-configurator.2.9.1"
"duration.0.2.0"
"easy-format.1.3.2"
"either.1.0.0"
"emile.1.1"
"encore.0.8"
"eqaf.0.8"
"ethernet.3.0.0"
"findlib_top.v0.11.0"
"fix.20211125"
"fmt.0.9.0"
"fpath.0.7.3"
"fsevents.0.3.0"
"fsevents-lwt.0.3.0"
"gg.0.9.3"
"git.3.6.0"
"git-cohttp.3.6.0"
"git-cohttp-unix.3.6.0"
"git-unix.3.6.0"
"glfw-ocaml.3.3.1-1"
"gmap.0.3.0"
"graphql.0.13.0"
"graphql-cohttp.0.13.0"
"graphql-lwt.0.13.0"
"graphql_parser.0.13.0"
"graphv_core.0.1.1"
"graphv_core_lib.0.1.1"
"graphv_font.0.1.1"
"graphv_font_js.0.1.1"
"graphv_gles2.0.1.1"
"graphv_gles2_native_impl.0.1.1"
"graphv_webgl.0.1.1"
"graphv_webgl_impl.0.1.1"
"grenier.0.13"
"hex.1.4.0"
"hkdf.1.0.4"
"huffman.0.1.2"
"hxd.0.3.1"
"index.1.5.0"
"inotify.2.3"
"integers.0.5.1"
"inuit.0.4.1"
"ipaddr.5.2.0"
"ipaddr-sexp.5.2.0"
"irc-client.0.7.0"
"irc-client-lwt.0.7.0"
"irc-client-tls.0.7.0"
"irc-client-unix.0.7.0"
"irmin.2.9.0"
"irmin-fs.2.9.0"
"irmin-git.2.9.0"
"irmin-graphql.2.9.0"
"irmin-http.2.9.0"
"irmin-layers.2.9.0"
"irmin-pack.2.9.0"
"irmin-unix.2.9.0"
"irmin-watcher.0.5.0"
"jbuilder.1.0+beta20.2"
"js_of_ocaml.3.11.0"
"js_of_ocaml-compiler.3.11.0"
"js_of_ocaml-ppx.3.11.0"
"jsonm.1.0.1"
"ke.0.4"
"lambda-term.3.1.0"
"logs.0.7.0"
"lru.0.3.0"
"lwd.0.1"
"lwt.5.5.0"
"lwt-dllist.1.0.1"
"lwt_log.1.1.1"
"lwt_ppx.2.0.3"
"lwt_react.1.1.5"
"macaddr.5.2.0"
"macaddr-cstruct.5.2.0"
"magic-mime.1.2.0"
"menhir.20211128"
"menhirLib.20211128"
"menhirSdk.20211128"
"merlin.4.4-413"
"metrics.0.3.0"
"mew.0.1.0"
"mew_vi.0.5.0"
"mimic.0.0.4"
"mirage-clock.4.0.0"
"mirage-clock-unix.4.0.0"
"mirage-crypto.0.10.5"
"mirage-crypto-ec.0.10.5"
"mirage-crypto-pk.0.10.5"
"mirage-crypto-rng.0.10.5"
"mirage-device.2.0.0"
"mirage-flow.3.0.0"
"mirage-kv.4.0.0"
"mirage-net.4.0.0"
"mirage-no-solo5.1"
"mirage-no-xen.1"
"mirage-profile.0.9.1"
"mirage-protocols.8.0.0"
"mirage-random.3.0.0"
"mirage-stack.4.0.0"
"mirage-time.3.0.0"
"mmap.1.1.0"
"mtime.1.3.0"
"note.0.0.1"
"nottui.0.1"
"nottui-lwt.0.1"
"nottui-pretty.0.1"
"notty.0.2.2"
"num.1.4"
"oasis.0.4.11"
"ocaml.4.13.1"
"ocaml-compiler-libs.v0.12.4"
"ocaml-config.2"
"ocaml-manual.4.13.0"
"ocaml-migrate-parsetree.2.3.0"
"ocaml-options-vanilla.1"
"ocaml-syntax-shims.1.0.0"
"ocaml-system.4.13.1"
"ocaml-version.3.4.0"
"ocamlbuild.0.14.0"
"ocamlfind.1.9.1"
"ocamlformat.0.20.1"
"ocamlgraph.2.0.0"
"ocamlify.0.0.1"
"ocamlmod.0.0.9"
"ocb-stubblr.0.1.1-1"
"ocp-indent.1.8.1"
"ocplib-endian.1.2"
"odig.0.0.7"
"odoc.2.0.2"
"odoc-parser.1.0.0"
"optint.0.1.0"
"parsexp.v0.14.1"
"pbkdf.1.2.0"
"pecu.0.6"
"pp.1.1.2"
"pprint.20211129"
"ppx_cstruct.6.0.1"
"ppx_derivers.1.2.1"
"ppx_deriving.5.2.1"
"ppx_irmin.2.9.0"
"ppx_repr.0.5.0"
"ppx_sexp_conv.v0.14.3"
"ppxlib.0.24.0"
"progress.0.2.1"
"psq.0.2.0"
"ptime.0.8.6"
"randomconv.0.1.3"
"re.1.10.3"
"react.1.2.1"
"repr.0.5.0"
"result.1.5"
"rresult.0.6.0"
"semaphore-compat.1.0.1"
"seq.base"
"sexplib.v0.14.0"
"sexplib0.v0.14.0"
"stb_image.0.5"
"stb_truetype.0.6"
"stdio.v0.14.0"
"stdlib-shims.0.3.0"
"stringext.1.6.0"
"tcpip.7.0.0"
"terminal.0.2.1"
"terminal_size.0.1.4"
"tgls.0.8.5"
"tls.0.14.1"
"tls-mirage.0.14.1"
"topkg.1.0.4"
"trie.1.0.0"
"tsdl.0.9.8"
"tsdl-image.0.3.2"
"tsdl-ttf.0.3.2"
"tyxml.4.5.0"
"uchar.0.0.2"
"uri.4.2.0"
"uri-sexp.4.2.0"
"user-setup.0.7"
"uucp.14.0.0"
"uuseg.14.0.0"
"uutf.1.0.2"
"vector.1.0.0"
"wall.0.4.1"
"webmachine.0.7.0"
"x509.0.14.1"
"yaml.3.0.0"
"yojson.1.7.0"
"zarith.1.12"
"zed.3.1.0"
]
pinned: ["lwd.0.1" "nottui.0.1"]
package "lwd" {
opam-version: "2.0"
version: "0.1"
synopsis: "Lightweight reactive documents"
maintainer: "fred@tarides.com"
authors: "Frédéric Bour"
license: "MIT"
homepage: "https://github.com/let-def/lwd"
doc: "https://let-def.github.io/lwd/doc"
bug-reports: "https://github.com/let-def/lwd/issues"
depends: [
"dune" {>= "2.0"}
"seq"
"ocaml" {>= "4.03"}
"qtest" {with-test}
"qcheck" {with-test}
]
build: [
["dune" "subst"] {pinned}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/let-def/lwd.git"
url {
src: "git+file:///home/cqc/p/console/ref/lwd#master"
}
}
package "nottui" {
opam-version: "2.0"
version: "0.1"
synopsis: "UI toolkit for the terminal built on top of Notty and Lwd"
maintainer: "fred@tarides.com"
authors: "Frédéric Bour"
license: "MIT"
homepage: "https://github.com/let-def/lwd"
doc: "https://let-def.github.io/lwd/doc"
bug-reports: "https://github.com/let-def/lwd/issues"
depends: [
"dune" {>= "2.0"}
"lwd"
"notty"
]
build: [
["dune" "subst"] {pinned}
[
"dune"
"build"
"-p"
name
"-j"
jobs
"@install"
"@runtest" {with-test}
"@doc" {with-doc}
]
]
dev-repo: "git+https://github.com/let-def/lwd.git"
url {
src: "git+file:///home/cqc/p/console/ref/lwd#master"
}
}

643
topinf.ml

File diff suppressed because it is too large Load Diff

View File

@ -21,7 +21,10 @@ type directive_fun =
type directive_info = {section: string; doc: string}
val add_directive : Misc.filepath -> directive_fun -> directive_info -> unit
val add_directive :
Misc.filepath -> directive_fun -> directive_info -> unit
val directive_info_table : (string, directive_info) Hashtbl.t
val ppf : Format.formatter ref
val eval : evalenv option ref
val eval : evalenv ref
val eval_value_path : Env.t -> Path.t -> Obj.t

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