This commit is contained in:
parent
aa2ff7b2f0
commit
2f3113f55d
11742 changed files with 1223940 additions and 0 deletions
13
unikernel/duniverse/dune_/vendor/notty/LICENSE.md
vendored
Normal file
13
unikernel/duniverse/dune_/vendor/notty/LICENSE.md
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Copyright (c) 2016-2017 David Kaloper Meršinjak
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
10
unikernel/duniverse/dune_/vendor/notty/src-unix/dune
vendored
Normal file
10
unikernel/duniverse/dune_/vendor/notty/src-unix/dune
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
(library
|
||||
(synopsis "Notty Unix IO")
|
||||
(name dune_notty_unix)
|
||||
(wrapped false)
|
||||
(foreign_stubs
|
||||
(language c)
|
||||
(names winsize))
|
||||
(libraries dune_notty unix))
|
||||
|
||||
(include_subdirs unqualified)
|
||||
44
unikernel/duniverse/dune_/vendor/notty/src-unix/native/winsize.c
vendored
Normal file
44
unikernel/duniverse/dune_/vendor/notty/src-unix/native/winsize.c
vendored
Normal file
|
|
@ -0,0 +1,44 @@
|
|||
#include <caml/mlvalues.h>
|
||||
|
||||
#ifdef _WIN32
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <sys/ioctl.h>
|
||||
#include <signal.h>
|
||||
#endif
|
||||
|
||||
#ifdef __HAIKU__
|
||||
/* On some platforms, ioctl() is declared in <unistd.h>. */
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
CAMLprim value caml_notty_winsize (value vfd) {
|
||||
#ifdef _WIN32
|
||||
(void) vfd;
|
||||
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
if (hConsole == INVALID_HANDLE_VALUE) return Val_int (0);
|
||||
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
if (GetConsoleScreenBufferInfo(hConsole, &csbi)) {
|
||||
int columns = csbi.srWindow.Right - csbi.srWindow.Left + 1;
|
||||
int rows = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
|
||||
return Val_int ((columns << 16) + ((rows & 0x7fff) << 1));
|
||||
}
|
||||
return Val_int (0);
|
||||
#else
|
||||
int fd = Int_val (vfd);
|
||||
struct winsize w;
|
||||
if (ioctl (fd, TIOCGWINSZ, &w) >= 0)
|
||||
return Val_int ((w.ws_col << 16) + ((w.ws_row & 0x7fff) << 1));
|
||||
return Val_int (0);
|
||||
#endif
|
||||
}
|
||||
|
||||
CAMLprim value caml_notty_winch_number (value vunit) {
|
||||
(void) vunit;
|
||||
#ifdef _WIN32
|
||||
return Val_int (0);
|
||||
#else
|
||||
return Val_int (SIGWINCH);
|
||||
#endif
|
||||
}
|
||||
181
unikernel/duniverse/dune_/vendor/notty/src-unix/notty_unix.ml
vendored
Normal file
181
unikernel/duniverse/dune_/vendor/notty/src-unix/notty_unix.ml
vendored
Normal file
|
|
@ -0,0 +1,181 @@
|
|||
(* Copyright (c) 2016-2017 David Kaloper Meršinjak. All rights reserved.
|
||||
See LICENSE.md. *)
|
||||
|
||||
open Notty
|
||||
|
||||
external c_winsize : Unix.file_descr -> int = "caml_notty_winsize" [@@noalloc]
|
||||
external winch_number : unit -> int = "caml_notty_winch_number" [@@noalloc]
|
||||
|
||||
let iter f = function Some x -> f x | _ -> ()
|
||||
let value x = function Some a -> a | _ -> x
|
||||
|
||||
let winsize fd = match c_winsize fd with
|
||||
| 0 -> None
|
||||
| wh -> Some (wh lsr 16, wh lsr 1 land 0x7fff)
|
||||
|
||||
module Private = struct
|
||||
|
||||
let once f = let v = lazy (f ()) in fun () -> Lazy.force v
|
||||
|
||||
let cap_for_fd =
|
||||
let open Cap in
|
||||
match Sys.getenv "TERM" with
|
||||
| exception Not_found -> fun _ -> dumb
|
||||
| (""|"dumb") -> fun _ -> dumb
|
||||
| _ -> fun fd -> if Unix.isatty fd then ansi else dumb
|
||||
|
||||
let setup_tcattr ~nosig fd =
|
||||
let open Unix in try
|
||||
let tc = tcgetattr fd in
|
||||
let tc1 = { tc with c_icanon = false; c_echo = false } in
|
||||
tcsetattr fd TCSANOW
|
||||
( if nosig then { tc1 with c_isig = false; c_ixon = false } else tc1 );
|
||||
`Revert (once @@ fun _ -> tcsetattr fd TCSANOW tc)
|
||||
with Unix_error (ENOTTY, _, _) -> `Revert ignore
|
||||
|
||||
let set_winch_handler f =
|
||||
let signum = winch_number () in
|
||||
let old_hdl = Sys.(signal signum (Signal_handle (fun _ -> f ()))) in
|
||||
`Revert (once @@ fun () -> Sys.set_signal signum old_hdl)
|
||||
|
||||
module Gen_output (O : sig
|
||||
type fd
|
||||
type k
|
||||
val def : fd
|
||||
val to_fd : fd -> Unix.file_descr
|
||||
val write : fd -> Buffer.t -> k
|
||||
end) = struct
|
||||
|
||||
let scratch = lazy (Buffer.create 4096)
|
||||
|
||||
let output ?cap ?(fd = O.def) f =
|
||||
let cap = cap |> value (cap_for_fd (O.to_fd fd)) in
|
||||
let buf = Lazy.force scratch in
|
||||
Buffer.reset buf; f buf cap fd; O.write fd buf
|
||||
|
||||
let output_image_size ?cap ?fd f =
|
||||
output ?cap ?fd @@ fun buf cap fd ->
|
||||
let size = winsize (O.to_fd fd) in
|
||||
let i = f (value (80, 24) size) in
|
||||
let dim = match size with
|
||||
| Some (w, _) -> I.(w, height i)
|
||||
| None -> I.(width i, height i) in
|
||||
Render.to_buffer buf cap (0, 0) dim i
|
||||
|
||||
let show_cursor ?cap ?fd x =
|
||||
output ?cap ?fd @@ fun buf cap _ -> Direct.show_cursor buf cap x
|
||||
|
||||
let move_cursor ?cap ?fd x =
|
||||
output ?cap ?fd @@ fun buf cap _ -> Direct.move_cursor buf cap x
|
||||
|
||||
let output_image ?cap ?fd i = output_image_size ?cap ?fd (fun _ -> i)
|
||||
|
||||
let eol i = I.(i <-> void 0 1)
|
||||
end
|
||||
end
|
||||
|
||||
open Private
|
||||
|
||||
module Term = struct
|
||||
|
||||
module Winch = struct
|
||||
|
||||
let h = Hashtbl.create 3
|
||||
and id = ref 0
|
||||
|
||||
let add fd f =
|
||||
let n = !id in
|
||||
set_winch_handler (fun () -> Hashtbl.iter (fun _ f -> f ()) h) |> ignore;
|
||||
Hashtbl.add h n (fun () -> winsize fd |> iter f); incr id;
|
||||
`Revert (fun () -> Hashtbl.remove h n)
|
||||
end
|
||||
|
||||
module Input = struct
|
||||
|
||||
type t = {
|
||||
fd : Unix.file_descr
|
||||
; flt : Unescape.t
|
||||
; ibuf : bytes
|
||||
; cleanup : unit -> unit
|
||||
}
|
||||
|
||||
let bsize = 1024
|
||||
|
||||
let create ~nosig fd =
|
||||
let flt = Unescape.create ()
|
||||
and ibuf = Bytes.create bsize
|
||||
and `Revert cleanup = setup_tcattr ~nosig fd in
|
||||
{ fd; flt; ibuf; cleanup }
|
||||
|
||||
let rec event t =
|
||||
match Unescape.next t.flt with
|
||||
| #Unescape.event | `End as r -> r
|
||||
| `Await ->
|
||||
let n = Unix.read t.fd t.ibuf 0 bsize in
|
||||
Unescape.input t.flt t.ibuf 0 n; event t
|
||||
end
|
||||
|
||||
type t = {
|
||||
output : out_channel
|
||||
; trm : Tmachine.t
|
||||
; buf : Buffer.t
|
||||
; input : Input.t
|
||||
; fds : Unix.file_descr * Unix.file_descr
|
||||
; unwinch : (unit -> unit) Lazy.t
|
||||
; mutable winched : bool
|
||||
}
|
||||
|
||||
let write t =
|
||||
Buffer.clear t.buf;
|
||||
Tmachine.output t.trm t.buf;
|
||||
Buffer.output_buffer t.output t.buf; flush t.output
|
||||
|
||||
let set_size t dim = Tmachine.set_size t.trm dim
|
||||
let refresh t = Tmachine.refresh t.trm; write t
|
||||
let image t image = Tmachine.image t.trm image; write t
|
||||
let cursor t curs = Tmachine.cursor t.trm curs; write t
|
||||
let size t = Tmachine.size t.trm
|
||||
|
||||
let release t =
|
||||
if Tmachine.release t.trm then
|
||||
( Lazy.force t.unwinch ();
|
||||
t.input.Input.cleanup ();
|
||||
write t )
|
||||
|
||||
let create ?(dispose=true) ?(nosig=true) ?(mouse=true) ?(bpaste=true)
|
||||
?(input=Unix.stdin) ?(output=Unix.stdout) () =
|
||||
let rec t = {
|
||||
output = Unix.out_channel_of_descr output
|
||||
; trm = Tmachine.create ~mouse ~bpaste (cap_for_fd input)
|
||||
; buf = Buffer.create 4096
|
||||
; input = Input.create ~nosig input
|
||||
; fds = (input, output)
|
||||
; winched = false
|
||||
; unwinch = lazy (
|
||||
let `Revert f = Winch.add output @@ fun dim ->
|
||||
Buffer.reset t.buf; t.winched <- true; set_size t dim in f)
|
||||
} in
|
||||
winsize output |> iter (set_size t);
|
||||
(Lazy.force t.unwinch |> ignore) [@ocaml.warning "-5"];
|
||||
if dispose then at_exit (fun () -> release t);
|
||||
write t;
|
||||
t
|
||||
|
||||
let rec event = function
|
||||
| t when Tmachine.dead t.trm -> `End
|
||||
| t when t.winched -> t.winched <- false; `Resize (size t)
|
||||
| t -> Unix.(try Input.event t.input with Unix_error (EINTR, _, _) -> event t)
|
||||
|
||||
let pending t =
|
||||
not (Tmachine.dead t.trm) &&
|
||||
(t.winched || Unescape.pending t.input.Input.flt)
|
||||
|
||||
let fds t = t.fds
|
||||
end
|
||||
|
||||
include Gen_output (struct
|
||||
type fd = out_channel and k = unit
|
||||
let def = stdout
|
||||
and to_fd = Unix.descr_of_out_channel
|
||||
and write = Buffer.output_buffer
|
||||
end)
|
||||
222
unikernel/duniverse/dune_/vendor/notty/src-unix/notty_unix.mli
vendored
Normal file
222
unikernel/duniverse/dune_/vendor/notty/src-unix/notty_unix.mli
vendored
Normal file
|
|
@ -0,0 +1,222 @@
|
|||
(* Copyright (c) 2016-2017 David Kaloper Meršinjak. All rights reserved.
|
||||
See LICENSE.md. *)
|
||||
|
||||
(** [Notty] IO for pure [Unix].
|
||||
|
||||
This is an IO module for {!Notty}.
|
||||
|
||||
{e 3.20.2 — {{:https://github.com/ocaml/dune }homepage}} *)
|
||||
|
||||
open Notty
|
||||
|
||||
(** {1:fullscreen Fullscreen input and output}. *)
|
||||
|
||||
(** Terminal IO abstraction for fullscreen, interactive applications.
|
||||
|
||||
This module provides both input and output. It assumes exclusive ownership of
|
||||
the IO streams between {{!create}initialization} and {{!release}shutdown}. *)
|
||||
module Term : sig
|
||||
|
||||
type t
|
||||
(** Representation of the terminal, giving structured access to IO. *)
|
||||
|
||||
(** {1 Construction and destruction} *)
|
||||
|
||||
val create : ?dispose:bool ->
|
||||
?nosig:bool ->
|
||||
?mouse:bool ->
|
||||
?bpaste:bool ->
|
||||
?input:Unix.file_descr ->
|
||||
?output:Unix.file_descr ->
|
||||
unit -> t
|
||||
(** [create ~dispose ~nosig ~mouse ~input ~output ()] creates a fresh
|
||||
{{!t}terminal}. It has the following side effects:
|
||||
{ul
|
||||
{- [Unix.tcsetattr] is applied to [input] to disable {e echo} and
|
||||
{e canonical mode}.}
|
||||
{- [output] is set to {e alternate screen mode}, and the cursor is
|
||||
hidden. Mouse and {e bracketed paste} reporting are (optionally)
|
||||
enabled.}
|
||||
{- [SIGWINCH] signal, normally ignored, is handled.}}
|
||||
|
||||
[~dispose] arranges for automatic {{!release}cleanup} of the terminal
|
||||
before the process terminates. The downside is that a reference to this
|
||||
terminal is retained until the program exits. Defaults to [true].
|
||||
|
||||
[~nosig] additionally turns off signal delivery and flow control
|
||||
({e isig} and {e ixon}) on input. Inhibits automatic handling of
|
||||
{e CTRL-\{C,Z,\,S,Q\}}. Defaults to [true].
|
||||
|
||||
[~mouse] activates mouse reporting. Defaults to [true].
|
||||
|
||||
[~bpaste] activates bracketed paste reporting. Defaults to [true].
|
||||
|
||||
[~input] is the input file descriptor. Defaults to [stdin].
|
||||
|
||||
[~output] is the output file descriptor. Defaults to [stdout]. *)
|
||||
|
||||
val release : t -> unit
|
||||
(** Dispose of this terminal. Original behavior of input fd is reinstated,
|
||||
cursor is restored, mouse reporting disabled, and alternate mode is
|
||||
terminated.
|
||||
|
||||
It is an error to use the {{!cmds}commands} on a released terminal, and
|
||||
will raise [Invalid_argument], while [release] itself is idempotent. *)
|
||||
|
||||
(** {1:cmds Commands} *)
|
||||
|
||||
val image : t -> image -> unit
|
||||
(** [image t i] sets [i] as [t]'s current image and redraws the terminal. *)
|
||||
|
||||
val refresh : t -> unit
|
||||
(** [refresh t] redraws the terminal using the current image.
|
||||
|
||||
Useful if the output might have become garbled. *)
|
||||
|
||||
val cursor : t -> (int * int) option -> unit
|
||||
(** [cursor t pos] sets and redraws the cursor.
|
||||
|
||||
[None] hides it. [Some (x, y)] places it at column [x] and row [y], with
|
||||
the origin at [(0, 0)], mapping to the upper-left corner. *)
|
||||
|
||||
(** {1 Events} *)
|
||||
|
||||
val event : t -> [ Unescape.event | `Resize of (int * int) | `End ]
|
||||
(** Wait for a new event. [event t] can be:
|
||||
{ul
|
||||
{- [#Unescape.event], an {{!Notty.Unescape.event}[event]} from the input fd;}
|
||||
{- [`End] if the input fd is closed, or the terminal was released; or}
|
||||
{- [`Resize (cols, rows)] giving the current size of the output tty, if a
|
||||
[SIGWINCH] was delivered before or during this call to [event].}}
|
||||
|
||||
{b Note} [event] is buffered. Calls can either block or immediately
|
||||
return. Use {{!pending}[pending]} to detect when the next call would not
|
||||
block. *)
|
||||
|
||||
val pending : t -> bool
|
||||
(** [pending t] is [true] if the next call to {{!event}[event]} would not
|
||||
block and the terminal has not yet been released. *)
|
||||
|
||||
(** {1 Properties} *)
|
||||
|
||||
val size : t -> int * int
|
||||
(** [size t] is the current size of the terminal's output tty. *)
|
||||
|
||||
val fds : t -> Unix.file_descr * Unix.file_descr
|
||||
(** [fds t] are [t]'s input and output file descriptors. *)
|
||||
|
||||
(** {1 Window size change notifications} *)
|
||||
|
||||
(** Manual [SIGWINCH] handling.
|
||||
|
||||
Unix delivers notifications about tty size changes through the [SIGWINCH]
|
||||
signal. A handler for this signal is installed as soon as a new terminal
|
||||
is {{!create}created}. Replacing the global [SIGWINCH] handler using
|
||||
the [Sys] module will cause this module to malfunction, as the size change
|
||||
notifications will no longer be delivered.
|
||||
|
||||
You might still want to ignore resizes reported by {{!event}[event]} and
|
||||
directly listen to [SIGWINCH]. This module allows installing such
|
||||
listeners without conflicting with the rest of the machinery. *)
|
||||
module Winch : sig
|
||||
|
||||
val add : Unix.file_descr -> ((int * int) -> unit) -> [`Revert of unit -> unit]
|
||||
(** [add fd f] registers a [SIGWINCH] handler. Every time the signal is
|
||||
delivered, [f] is called with the current size of the tty backing [fd].
|
||||
If [fd] is not a tty, [f] is never called.
|
||||
|
||||
Return value is a function that removes the handler [f].
|
||||
|
||||
Handlers are called in an unspecified order. *)
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
(** {1:inline Inline output}
|
||||
|
||||
These operations do not assume exclusive access to the output. This means
|
||||
that they can be combined with other means of producing output. At the same
|
||||
time, it means that they are affected by the current terminal state, and
|
||||
that this state is not tracked. *)
|
||||
|
||||
val winsize : Unix.file_descr -> (int * int) option
|
||||
(** [winsize fd] is [Some (columns, rows)], the current dimensions of [fd]'s
|
||||
backing tty, or [None], when [fd] is not backed by a tty. *)
|
||||
|
||||
val eol : image -> image
|
||||
(** [eol image] is [image], producing an extra newline when printed. *)
|
||||
|
||||
val output_image :
|
||||
?cap:Cap.t -> ?fd:out_channel -> image -> unit
|
||||
(** [output_image ?cap ?fd image] writes [image] to [fd].
|
||||
|
||||
The image is displayed in its full height. If the output is a tty, image
|
||||
width is clipped to the output width. Otherwise, full width is used.
|
||||
|
||||
[~cap] is the {{!caps}optional} terminal capability set.
|
||||
|
||||
[~fd] defaults to [stdout]. *)
|
||||
|
||||
val output_image_size : ?cap:Cap.t -> ?fd:out_channel -> (int * int -> image) -> unit
|
||||
(** [output_image_size ?cap ?fd f] is
|
||||
[output_image ?cap ?fd (f size)] where [size] are [fd]'s current
|
||||
{{!winsize}output dimensions}.
|
||||
|
||||
If [fd] is not backed by a tty, as a matter of convenience, [f] is applied
|
||||
to [(80, 24)]. Use {!Unix.isatty} or {{!winsize}[winsize]} to detect whether
|
||||
the output has a well-defined size. *)
|
||||
|
||||
val show_cursor : ?cap:Cap.t -> ?fd:out_channel -> bool -> unit
|
||||
(** [show_cursor ?cap ?fd visible] toggles the cursor visibility on [fd]. *)
|
||||
|
||||
val move_cursor :
|
||||
?cap:Cap.t -> ?fd:out_channel ->
|
||||
[ `Home | `By of int * int | `To of int * int ] -> unit
|
||||
(** [move_cursor ?cap ?fd motion] moves the cursor on [fd].
|
||||
|
||||
[motion] is one of:
|
||||
{ul
|
||||
{- [`To (column, line)], positioning the cursor to [(column, line)]. Origin
|
||||
is [(0, 0)], the upper-left corner of the screen.}
|
||||
{- [`Home], moving the cursor the beginning of line.}
|
||||
{- [`By (columns, lines)], moving the cursor [columns] to the right (left if
|
||||
negative) and [lines] down (up if negative).
|
||||
|
||||
{b Note} Behavior is terminal dependent if the movement overshoots the
|
||||
output size.}} *)
|
||||
|
||||
(** {1:caps Capability detection}
|
||||
|
||||
All [image] output requires {{!Notty.Cap.t}terminal capabilities}.
|
||||
|
||||
When not provided, capabilities are auto-detected, by checking that the
|
||||
output is a tty, that the environment variable [$TERM] is set, and that it
|
||||
is not set to either [""] or ["dumb"]. If these conditions hold,
|
||||
{{!Notty.Cap.ansi}ANSI} escapes are used. Otherwise, {{!Notty.Cap.dumb}no}
|
||||
escapes are used. *)
|
||||
|
||||
(**/**)
|
||||
(** {1 Private}
|
||||
|
||||
These are private interfaces, prone to breakage. Don't use them. *)
|
||||
module Private : sig
|
||||
|
||||
val cap_for_fd : Unix.file_descr -> Cap.t
|
||||
val setup_tcattr : nosig:bool -> Unix.file_descr -> [ `Revert of (unit -> unit) ]
|
||||
val set_winch_handler : (unit -> unit) -> [ `Revert of (unit -> unit) ]
|
||||
|
||||
module Gen_output (O : sig
|
||||
type fd
|
||||
type k
|
||||
val def : fd
|
||||
val to_fd : fd -> Unix.file_descr
|
||||
val write : fd -> Buffer.t -> k
|
||||
end ) : sig
|
||||
val output_image : ?cap:Cap.t -> ?fd:O.fd -> image -> O.k
|
||||
val output_image_size : ?cap:Cap.t -> ?fd:O.fd -> (int * int -> image) -> O.k
|
||||
val show_cursor : ?cap:Cap.t -> ?fd:O.fd -> bool -> O.k
|
||||
val move_cursor : ?cap:Cap.t -> ?fd:O.fd -> [ `Home | `By of int * int | `To of int * int ] -> O.k
|
||||
val eol : image -> image
|
||||
end
|
||||
end
|
||||
(**/**)
|
||||
9
unikernel/duniverse/dune_/vendor/notty/src/dune
vendored
Normal file
9
unikernel/duniverse/dune_/vendor/notty/src/dune
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
(include_subdirs unqualified)
|
||||
|
||||
(library
|
||||
(name dune_notty)
|
||||
(synopsis "Declaring terminals")
|
||||
(libraries dune_uutf)
|
||||
(wrapped false)
|
||||
(modules notty notty_grapheme_cluster notty_uucp notty_uucp_data)
|
||||
(private_modules notty_grapheme_cluster notty_uucp notty_uucp_data))
|
||||
13
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/README.md
vendored
Normal file
13
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/README.md
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
Cannibalized bits of Uucp:
|
||||
|
||||
- `Notty_uucp_data` is generated from an actual Uucp installation.
|
||||
- `Notty_uucp` uses it to provide the few Unicode properties that Notty needs.
|
||||
- `Notty_grapheme_cluster` is `Grapheme_cluster` from Uuseg, adapted to use the
|
||||
above.
|
||||
|
||||
Compiled size of these is on the order of 70K. Uucp is presently a monolithic 10M.
|
||||
|
||||
The idea is to remove these in favor of the actual Uucp/Uuseg, as soon as it
|
||||
becomes possible to depend only on the necessary parts of Uucp.
|
||||
|
||||
Uucp and Uuseg are Copyright (c) 2014 Daniel C. Bünzli.
|
||||
133
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_grapheme_cluster.ml
vendored
Normal file
133
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_grapheme_cluster.ml
vendored
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
(*---------------------------------------------------------------------------
|
||||
Copyright (c) 2014 Daniel C. Bünzli. All rights reserved.
|
||||
Distributed under the ISC license, see terms at the end of the file.
|
||||
dune 3.20.2
|
||||
---------------------------------------------------------------------------*)
|
||||
|
||||
(* These are the rules as found in [1], with property values aliases [2]
|
||||
substituted.
|
||||
|
||||
GB1. sot ÷ Any
|
||||
GB2. Any ÷ eot
|
||||
GB3. CR × LF
|
||||
GB4. (CN|CR|LF) ÷
|
||||
GB5. ÷ (CN|CR|LF)
|
||||
GB6. L × (L|V|LV|LVT)
|
||||
GB7. (LV|V) × (V|T)
|
||||
GB8. (LVT|T) × T
|
||||
GB9. × (EX|ZWJ)
|
||||
GB9a. × SM
|
||||
GB9b. PP ×
|
||||
GB10. (v10.0.0) (EB|EBG) EX* × EM
|
||||
GB11. (v10.0.0) ZWJ × (GAZ|EBG)
|
||||
GB12. sot (RI RI)* RI × RI
|
||||
GB13. [^RI] (RI RI)* × RI
|
||||
GB999. Any ÷ Any
|
||||
|
||||
[1]: http://www.unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries
|
||||
[2]: http://www.unicode.org/Public/7.0.0/ucd/PropertyValueAliases.txt
|
||||
[3]: http://www.unicode.org/Public/7.0.0/ucd/auxiliary/GraphemeBreakTest.html
|
||||
|
||||
By the structure of the rules we see that grapheme clusters
|
||||
boundaries can *mostly* be determined by simply looking at the
|
||||
grapheme cluster break property value of the character on the left
|
||||
and on the right of a boundary. The exceptions are GB10 and GB12-13
|
||||
which are handled specially by enriching the segmenter state in
|
||||
a horribly ad-hoc fashion. *)
|
||||
|
||||
type ret = [ `Await | `Boundary | `End | `Uchar of Uchar.t ]
|
||||
|
||||
type gcb =
|
||||
| CN | CR | EX | EB | EBG | EM | GAZ | L | LF | LV | LVT | PP | RI
|
||||
| SM | T | V | XX | ZWJ | Sot
|
||||
|
||||
(* WARNING. The indexes used here need to be synchronized with those
|
||||
assigned by uucp for Uucp.Break.Low.grapheme_cluster. *)
|
||||
|
||||
let byte_to_gcb =
|
||||
[| CN; CR; EX; EB; EBG; EM; GAZ; L; LF; LV; LVT; PP; RI;
|
||||
SM; T; V; XX; ZWJ; |]
|
||||
|
||||
let gcb u = byte_to_gcb.(Notty_uucp.grapheme_cluster_boundary u)
|
||||
|
||||
type state =
|
||||
| Fill (* get next uchar to decide boundary. *)
|
||||
| Flush (* an uchar is buffered, client needs to get it out with `Await. *)
|
||||
| End (* `End was added. *)
|
||||
|
||||
type t =
|
||||
{ mutable state : state; (* current state. *)
|
||||
mutable left : gcb; (* break property value left of boundary. *)
|
||||
mutable odd_ri : bool; (* odd number of RI on the left. *)
|
||||
mutable emoji_seq : bool; (* (EB|EBG) Extend* on the left. *)
|
||||
mutable buf : [ `Uchar of Uchar.t ] } (* bufferized add. *)
|
||||
|
||||
let nul_buf = `Uchar (Uchar.unsafe_of_int 0x0000)
|
||||
|
||||
let create () =
|
||||
{ state = Fill; left = Sot;
|
||||
odd_ri = false; emoji_seq = false;
|
||||
buf = nul_buf (* overwritten *); }
|
||||
|
||||
let break s right = match s.left, right with
|
||||
| (* GB1 *) Sot, _ -> true
|
||||
(* GB2 is handled by `End *)
|
||||
| (* GB3 *) CR, LF -> false
|
||||
| (* GB4 *) (CN|CR|LF), _ -> true
|
||||
| (* GB5 *) _, (CN|CR|LF) -> true
|
||||
| (* GB6 *) L, (L|V|LV|LVT) -> false
|
||||
| (* GB7 *) (LV|V), (V|T) -> false
|
||||
| (* GB8 *) (LVT|T), T -> false
|
||||
| (* GB9+a *) _, (EX|ZWJ|SM) -> false
|
||||
| (* GB9b *) PP, _ -> false
|
||||
| (* GB10 *) _, EM when s.emoji_seq -> false
|
||||
| (* GB11 *) ZWJ, (GAZ|EBG) -> false
|
||||
| (* GB12+13 *) RI, RI when s.odd_ri -> false
|
||||
| (* GB999 *) _, _ -> true
|
||||
|
||||
let update_left s right =
|
||||
s.left <- right;
|
||||
match s.left with
|
||||
| EX -> (* keep s.emoji_seq as is *) s.odd_ri <- false
|
||||
| EB | EBG -> s.emoji_seq <- true; s.odd_ri <- false
|
||||
| RI -> s.emoji_seq <- false; s.odd_ri <- not s.odd_ri
|
||||
| _ -> s.emoji_seq <- false; s.odd_ri <- false
|
||||
|
||||
let add s = function
|
||||
| `Uchar u as add ->
|
||||
begin match s.state with
|
||||
| Fill ->
|
||||
let right = gcb u in
|
||||
let break = break s right in
|
||||
update_left s right;
|
||||
if not break then add else
|
||||
(s.state <- Flush; s.buf <- add; `Boundary)
|
||||
| Flush | End -> assert false
|
||||
end
|
||||
| `Await ->
|
||||
begin match s.state with
|
||||
| Flush -> s.state <- Fill; (s.buf :> ret)
|
||||
| End -> `End
|
||||
| Fill -> `Await
|
||||
end
|
||||
| `End ->
|
||||
begin match s.state with
|
||||
| Fill -> s.state <- End; if s.left = Sot then `End else `Boundary
|
||||
| Flush | End -> assert false
|
||||
end
|
||||
|
||||
(*---------------------------------------------------------------------------
|
||||
Copyright (c) 2014 Daniel C. Bünzli
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
---------------------------------------------------------------------------*)
|
||||
27
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_grapheme_cluster.mli
vendored
Normal file
27
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_grapheme_cluster.mli
vendored
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
(*---------------------------------------------------------------------------
|
||||
Copyright (c) 2014 Daniel C. Bünzli. All rights reserved.
|
||||
Distributed under the ISC license, see terms at the end of the file.
|
||||
dune 3.20.2
|
||||
---------------------------------------------------------------------------*)
|
||||
|
||||
type ret = [ `Await | `Boundary | `End | `Uchar of Uchar.t ]
|
||||
|
||||
type t
|
||||
val create : unit -> t
|
||||
val add : t -> [ `Await | `End | `Uchar of Uchar.t ] -> ret
|
||||
|
||||
(*---------------------------------------------------------------------------
|
||||
Copyright (c) 2014 Daniel C. Bünzli
|
||||
|
||||
Permission to use, copy, modify, and/or distribute this software for any
|
||||
purpose with or without fee is hereby granted, provided that the above
|
||||
copyright notice and this permission notice appear in all copies.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
---------------------------------------------------------------------------*)
|
||||
48
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_uucp.ml
vendored
Normal file
48
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_uucp.ml
vendored
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
(* Copyright (c) 2020 David Kaloper Meršinjak. All rights reserved.
|
||||
See LICENSE.md. *)
|
||||
|
||||
(* Unpacked interval lookup table. *)
|
||||
let find_i ~def k (xs, _, _ as tab) =
|
||||
let rec go i j (los, his, vs as tab) (k: int) def =
|
||||
if i > j then def else
|
||||
let x = (i + j) / 2 in
|
||||
if k < Array.unsafe_get los x then go i (x - 1) tab k def else
|
||||
if k > Array.unsafe_get his x then go (x + 1) j tab k def else
|
||||
Array.unsafe_get vs x in
|
||||
go 0 (Array.length xs - 1) tab k def
|
||||
|
||||
(* 12-6-6-bit (0xfff-0x3f-0x3f) trie, 3 levels, array-array-string.
|
||||
Root is variable; lower levels are either empty or complete. *)
|
||||
let find_t ~def k tab =
|
||||
let k = if k > 0xd7ff then k - 0x800 else k in (* Pack to continuous range. *)
|
||||
let b0 = (k lsr 12) land 0xfff in
|
||||
if Array.length tab <= b0 then def else
|
||||
match Array.unsafe_get tab b0 with
|
||||
| [||] -> def
|
||||
| arr -> match Array.unsafe_get arr ((k lsr 6) land 0x3f) with
|
||||
| "" -> def
|
||||
| str -> String.unsafe_get str (k land 0x3f) |> Char.code
|
||||
|
||||
(* We catch w = -1 and default to w = 1 to minimize the table. *)
|
||||
let tty_width_hint u = match Uchar.to_int u with
|
||||
| 0 -> 0
|
||||
| u when u <= 0x001F || 0x007F <= u && u <= 0x009F -> -1
|
||||
| u when u <= 0x02ff -> 1
|
||||
| u -> find_i ~def:1 u Notty_uucp_data.tty_width_hint
|
||||
|
||||
let grapheme_cluster_boundary u =
|
||||
find_t ~def:16 (Uchar.to_int u) Notty_uucp_data.grapheme_cluster_boundary
|
||||
|
||||
(* let check () = *)
|
||||
(* let pp_u ppf u = Format.fprintf ppf "u+%04x" (Uchar.to_int u) in *)
|
||||
(* let rec go i u = *)
|
||||
(* let w1 = tty_width_hint u *)
|
||||
(* and w2 = Uucp.Break.tty_width_hint u in *)
|
||||
(* if w1 <> w2 then Format.printf "w: %a here: %d there: %d@." pp_u u w1 w2; *)
|
||||
(* let gc1 = grapheme_cluster_boundary u *)
|
||||
(* and gc2 = Uucp.Break.Low.grapheme_cluster u in *)
|
||||
(* if gc1 <> gc2 then Format.printf "gc: %a here: %d there: %d@." pp_u u gc1 gc2; *)
|
||||
(* if u = Uchar.max then i else go (i + 1) (Uchar.succ u) in *)
|
||||
(* let n = go 1 Uchar.min in *)
|
||||
(* Format.printf "Checked equality for %d code points.@." n *)
|
||||
|
||||
13
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_uucp.mli
vendored
Normal file
13
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_uucp.mli
vendored
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
(* Copyright (c) 2020 David Kaloper Meršinjak. All rights reserved.
|
||||
See LICENSE.md. *)
|
||||
|
||||
(* This is a local copy of the (very few) relevant [uucp] properties. *)
|
||||
|
||||
val tty_width_hint : Uchar.t -> int
|
||||
(* [Uucp.Break.tty_width_hint]. *)
|
||||
|
||||
val grapheme_cluster_boundary : Uchar.t -> int
|
||||
(* [Uucp.Break.Low.grapheme_cluster]. *)
|
||||
|
||||
(* val check : unit -> unit *)
|
||||
|
||||
446
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_uucp_data.ml
vendored
Normal file
446
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_uucp_data.ml
vendored
Normal file
|
|
@ -0,0 +1,446 @@
|
|||
(* Do not edit.
|
||||
*
|
||||
* This module contains select unicode properties extracted from Uucp,
|
||||
* using `./support/gen_unicode_props.ml`.
|
||||
*
|
||||
* Unicode version 13.0.0.
|
||||
*)
|
||||
|
||||
|
||||
let tty_width_hint =
|
||||
([|0x0000; 0x0300; 0x0483; 0x0591; 0x05bf; 0x05c1; 0x05c4; 0x05c7; 0x0600;
|
||||
0x0610; 0x061c; 0x064b; 0x0670; 0x06d6; 0x06df; 0x06e7; 0x06ea; 0x070f;
|
||||
0x0711; 0x0730; 0x07a6; 0x07eb; 0x07fd; 0x0816; 0x081b; 0x0825; 0x0829;
|
||||
0x0859; 0x08d3; 0x093a; 0x093c; 0x0941; 0x094d; 0x0951; 0x0962; 0x0981;
|
||||
0x09bc; 0x09c1; 0x09cd; 0x09e2; 0x09fe; 0x0a01; 0x0a3c; 0x0a41; 0x0a47;
|
||||
0x0a4b; 0x0a51; 0x0a70; 0x0a75; 0x0a81; 0x0abc; 0x0ac1; 0x0ac7; 0x0acd;
|
||||
0x0ae2; 0x0afa; 0x0b01; 0x0b3c; 0x0b3f; 0x0b41; 0x0b4d; 0x0b55; 0x0b62;
|
||||
0x0b82; 0x0bc0; 0x0bcd; 0x0c00; 0x0c04; 0x0c3e; 0x0c46; 0x0c4a; 0x0c55;
|
||||
0x0c62; 0x0c81; 0x0cbc; 0x0cbf; 0x0cc6; 0x0ccc; 0x0ce2; 0x0d00; 0x0d3b;
|
||||
0x0d41; 0x0d4d; 0x0d62; 0x0d81; 0x0dca; 0x0dd2; 0x0dd6; 0x0e31; 0x0e34;
|
||||
0x0e47; 0x0eb1; 0x0eb4; 0x0ec8; 0x0f18; 0x0f35; 0x0f37; 0x0f39; 0x0f71;
|
||||
0x0f80; 0x0f86; 0x0f8d; 0x0f99; 0x0fc6; 0x102d; 0x1032; 0x1039; 0x103d;
|
||||
0x1058; 0x105e; 0x1071; 0x1082; 0x1085; 0x108d; 0x109d; 0x1100; 0x135d;
|
||||
0x1712; 0x1732; 0x1752; 0x1772; 0x17b4; 0x17b7; 0x17c6; 0x17c9; 0x17dd;
|
||||
0x180b; 0x1885; 0x18a9; 0x1920; 0x1927; 0x1932; 0x1939; 0x1a17; 0x1a1b;
|
||||
0x1a56; 0x1a58; 0x1a60; 0x1a62; 0x1a65; 0x1a73; 0x1a7f; 0x1ab0; 0x1b00;
|
||||
0x1b34; 0x1b36; 0x1b3c; 0x1b42; 0x1b6b; 0x1b80; 0x1ba2; 0x1ba8; 0x1bab;
|
||||
0x1be6; 0x1be8; 0x1bed; 0x1bef; 0x1c2c; 0x1c36; 0x1cd0; 0x1cd4; 0x1ce2;
|
||||
0x1ced; 0x1cf4; 0x1cf8; 0x1dc0; 0x1dfb; 0x200b; 0x202a; 0x2060; 0x2066;
|
||||
0x20d0; 0x231a; 0x2329; 0x23e9; 0x23f0; 0x23f3; 0x25fd; 0x2614; 0x2648;
|
||||
0x267f; 0x2693; 0x26a1; 0x26aa; 0x26bd; 0x26c4; 0x26ce; 0x26d4; 0x26ea;
|
||||
0x26f2; 0x26f5; 0x26fa; 0x26fd; 0x2705; 0x270a; 0x2728; 0x274c; 0x274e;
|
||||
0x2753; 0x2757; 0x2795; 0x27b0; 0x27bf; 0x2b1b; 0x2b50; 0x2b55; 0x2cef;
|
||||
0x2d7f; 0x2de0; 0x2e80; 0x2e9b; 0x2f00; 0x2ff0; 0x3000; 0x302a; 0x302e;
|
||||
0x3041; 0x3099; 0x309b; 0x3105; 0x3131; 0x3190; 0x31f0; 0x3220; 0x3250;
|
||||
0x4e00; 0xa490; 0xa66f; 0xa674; 0xa69e; 0xa6f0; 0xa802; 0xa806; 0xa80b;
|
||||
0xa825; 0xa82c; 0xa8c4; 0xa8e0; 0xa8ff; 0xa926; 0xa947; 0xa960; 0xa980;
|
||||
0xa9b3; 0xa9b6; 0xa9bc; 0xa9e5; 0xaa29; 0xaa31; 0xaa35; 0xaa43; 0xaa4c;
|
||||
0xaa7c; 0xaab0; 0xaab2; 0xaab7; 0xaabe; 0xaac1; 0xaaec; 0xaaf6; 0xabe5;
|
||||
0xabe8; 0xabed; 0xac00; 0xf900; 0xfb1e; 0xfe00; 0xfe10; 0xfe20; 0xfe30;
|
||||
0xfe54; 0xfe68; 0xfeff; 0xff01; 0xffe0; 0xfff9; 0x101fd; 0x102e0;
|
||||
0x10376; 0x10a01; 0x10a05; 0x10a0c; 0x10a38; 0x10a3f; 0x10ae5; 0x10d24;
|
||||
0x10eab; 0x10f46; 0x11001; 0x11038; 0x1107f; 0x110b3; 0x110b9; 0x110bd;
|
||||
0x110cd; 0x11100; 0x11127; 0x1112d; 0x11173; 0x11180; 0x111b6; 0x111c9;
|
||||
0x111cf; 0x1122f; 0x11234; 0x11236; 0x1123e; 0x112df; 0x112e3; 0x11300;
|
||||
0x1133b; 0x11340; 0x11366; 0x11370; 0x11438; 0x11442; 0x11446; 0x1145e;
|
||||
0x114b3; 0x114ba; 0x114bf; 0x114c2; 0x115b2; 0x115bc; 0x115bf; 0x115dc;
|
||||
0x11633; 0x1163d; 0x1163f; 0x116ab; 0x116ad; 0x116b0; 0x116b7; 0x1171d;
|
||||
0x11722; 0x11727; 0x1182f; 0x11839; 0x1193b; 0x1193e; 0x11943; 0x119d4;
|
||||
0x119da; 0x119e0; 0x11a01; 0x11a33; 0x11a3b; 0x11a47; 0x11a51; 0x11a59;
|
||||
0x11a8a; 0x11a98; 0x11c30; 0x11c38; 0x11c3f; 0x11c92; 0x11caa; 0x11cb2;
|
||||
0x11cb5; 0x11d31; 0x11d3a; 0x11d3c; 0x11d3f; 0x11d47; 0x11d90; 0x11d95;
|
||||
0x11d97; 0x11ef3; 0x13430; 0x16af0; 0x16b30; 0x16f4f; 0x16f8f; 0x16fe0;
|
||||
0x16fe4; 0x16ff0; 0x17000; 0x18800; 0x18d00; 0x1b000; 0x1b150; 0x1b164;
|
||||
0x1b170; 0x1bc9d; 0x1bca0; 0x1d167; 0x1d173; 0x1d185; 0x1d1aa; 0x1d242;
|
||||
0x1da00; 0x1da3b; 0x1da75; 0x1da84; 0x1da9b; 0x1daa1; 0x1e000; 0x1e008;
|
||||
0x1e01b; 0x1e023; 0x1e026; 0x1e130; 0x1e2ec; 0x1e8d0; 0x1e944; 0x1f004;
|
||||
0x1f0cf; 0x1f18e; 0x1f191; 0x1f200; 0x1f210; 0x1f240; 0x1f250; 0x1f260;
|
||||
0x1f300; 0x1f32d; 0x1f337; 0x1f37e; 0x1f3a0; 0x1f3cf; 0x1f3e0; 0x1f3f4;
|
||||
0x1f3f8; 0x1f440; 0x1f442; 0x1f4ff; 0x1f54b; 0x1f550; 0x1f57a; 0x1f595;
|
||||
0x1f5a4; 0x1f5fb; 0x1f680; 0x1f6cc; 0x1f6d0; 0x1f6d5; 0x1f6eb; 0x1f6f4;
|
||||
0x1f7e0; 0x1f90c; 0x1f93c; 0x1f947; 0x1f97a; 0x1f9cd; 0x1fa70; 0x1fa78;
|
||||
0x1fa80; 0x1fa90; 0x1fab0; 0x1fac0; 0x1fad0; 0x20000; 0x30000; 0xe0001;
|
||||
0xe0020; 0xe0100|],
|
||||
[|0x0000; 0x036f; 0x0489; 0x05bd; 0x05bf; 0x05c2; 0x05c5; 0x05c7; 0x0605;
|
||||
0x061a; 0x061c; 0x065f; 0x0670; 0x06dd; 0x06e4; 0x06e8; 0x06ed; 0x070f;
|
||||
0x0711; 0x074a; 0x07b0; 0x07f3; 0x07fd; 0x0819; 0x0823; 0x0827; 0x082d;
|
||||
0x085b; 0x0902; 0x093a; 0x093c; 0x0948; 0x094d; 0x0957; 0x0963; 0x0981;
|
||||
0x09bc; 0x09c4; 0x09cd; 0x09e3; 0x09fe; 0x0a02; 0x0a3c; 0x0a42; 0x0a48;
|
||||
0x0a4d; 0x0a51; 0x0a71; 0x0a75; 0x0a82; 0x0abc; 0x0ac5; 0x0ac8; 0x0acd;
|
||||
0x0ae3; 0x0aff; 0x0b01; 0x0b3c; 0x0b3f; 0x0b44; 0x0b4d; 0x0b56; 0x0b63;
|
||||
0x0b82; 0x0bc0; 0x0bcd; 0x0c00; 0x0c04; 0x0c40; 0x0c48; 0x0c4d; 0x0c56;
|
||||
0x0c63; 0x0c81; 0x0cbc; 0x0cbf; 0x0cc6; 0x0ccd; 0x0ce3; 0x0d01; 0x0d3c;
|
||||
0x0d44; 0x0d4d; 0x0d63; 0x0d81; 0x0dca; 0x0dd4; 0x0dd6; 0x0e31; 0x0e3a;
|
||||
0x0e4e; 0x0eb1; 0x0ebc; 0x0ecd; 0x0f19; 0x0f35; 0x0f37; 0x0f39; 0x0f7e;
|
||||
0x0f84; 0x0f87; 0x0f97; 0x0fbc; 0x0fc6; 0x1030; 0x1037; 0x103a; 0x103e;
|
||||
0x1059; 0x1060; 0x1074; 0x1082; 0x1086; 0x108d; 0x109d; 0x115f; 0x135f;
|
||||
0x1714; 0x1734; 0x1753; 0x1773; 0x17b5; 0x17bd; 0x17c6; 0x17d3; 0x17dd;
|
||||
0x180e; 0x1886; 0x18a9; 0x1922; 0x1928; 0x1932; 0x193b; 0x1a18; 0x1a1b;
|
||||
0x1a56; 0x1a5e; 0x1a60; 0x1a62; 0x1a6c; 0x1a7c; 0x1a7f; 0x1ac0; 0x1b03;
|
||||
0x1b34; 0x1b3a; 0x1b3c; 0x1b42; 0x1b73; 0x1b81; 0x1ba5; 0x1ba9; 0x1bad;
|
||||
0x1be6; 0x1be9; 0x1bed; 0x1bf1; 0x1c33; 0x1c37; 0x1cd2; 0x1ce0; 0x1ce8;
|
||||
0x1ced; 0x1cf4; 0x1cf9; 0x1df9; 0x1dff; 0x200f; 0x202e; 0x2064; 0x206f;
|
||||
0x20f0; 0x231b; 0x232a; 0x23ec; 0x23f0; 0x23f3; 0x25fe; 0x2615; 0x2653;
|
||||
0x267f; 0x2693; 0x26a1; 0x26ab; 0x26be; 0x26c5; 0x26ce; 0x26d4; 0x26ea;
|
||||
0x26f3; 0x26f5; 0x26fa; 0x26fd; 0x2705; 0x270b; 0x2728; 0x274c; 0x274e;
|
||||
0x2755; 0x2757; 0x2797; 0x27b0; 0x27bf; 0x2b1c; 0x2b50; 0x2b55; 0x2cf1;
|
||||
0x2d7f; 0x2dff; 0x2e99; 0x2ef3; 0x2fd5; 0x2ffb; 0x3029; 0x302d; 0x303e;
|
||||
0x3096; 0x309a; 0x30ff; 0x312f; 0x318e; 0x31e3; 0x321e; 0x3247; 0x4dbf;
|
||||
0xa48c; 0xa4c6; 0xa672; 0xa67d; 0xa69f; 0xa6f1; 0xa802; 0xa806; 0xa80b;
|
||||
0xa826; 0xa82c; 0xa8c5; 0xa8f1; 0xa8ff; 0xa92d; 0xa951; 0xa97c; 0xa982;
|
||||
0xa9b3; 0xa9b9; 0xa9bd; 0xa9e5; 0xaa2e; 0xaa32; 0xaa36; 0xaa43; 0xaa4c;
|
||||
0xaa7c; 0xaab0; 0xaab4; 0xaab8; 0xaabf; 0xaac1; 0xaaed; 0xaaf6; 0xabe5;
|
||||
0xabe8; 0xabed; 0xd7a3; 0xfaff; 0xfb1e; 0xfe0f; 0xfe19; 0xfe2f; 0xfe52;
|
||||
0xfe66; 0xfe6b; 0xfeff; 0xff60; 0xffe6; 0xfffb; 0x101fd; 0x102e0;
|
||||
0x1037a; 0x10a03; 0x10a06; 0x10a0f; 0x10a3a; 0x10a3f; 0x10ae6; 0x10d27;
|
||||
0x10eac; 0x10f50; 0x11001; 0x11046; 0x11081; 0x110b6; 0x110ba; 0x110bd;
|
||||
0x110cd; 0x11102; 0x1112b; 0x11134; 0x11173; 0x11181; 0x111be; 0x111cc;
|
||||
0x111cf; 0x11231; 0x11234; 0x11237; 0x1123e; 0x112df; 0x112ea; 0x11301;
|
||||
0x1133c; 0x11340; 0x1136c; 0x11374; 0x1143f; 0x11444; 0x11446; 0x1145e;
|
||||
0x114b8; 0x114ba; 0x114c0; 0x114c3; 0x115b5; 0x115bd; 0x115c0; 0x115dd;
|
||||
0x1163a; 0x1163d; 0x11640; 0x116ab; 0x116ad; 0x116b5; 0x116b7; 0x1171f;
|
||||
0x11725; 0x1172b; 0x11837; 0x1183a; 0x1193c; 0x1193e; 0x11943; 0x119d7;
|
||||
0x119db; 0x119e0; 0x11a0a; 0x11a38; 0x11a3e; 0x11a47; 0x11a56; 0x11a5b;
|
||||
0x11a96; 0x11a99; 0x11c36; 0x11c3d; 0x11c3f; 0x11ca7; 0x11cb0; 0x11cb3;
|
||||
0x11cb6; 0x11d36; 0x11d3a; 0x11d3d; 0x11d45; 0x11d47; 0x11d91; 0x11d95;
|
||||
0x11d97; 0x11ef4; 0x13438; 0x16af4; 0x16b36; 0x16f4f; 0x16f92; 0x16fe3;
|
||||
0x16fe4; 0x16ff1; 0x187f7; 0x18cd5; 0x18d08; 0x1b11e; 0x1b152; 0x1b167;
|
||||
0x1b2fb; 0x1bc9e; 0x1bca3; 0x1d169; 0x1d182; 0x1d18b; 0x1d1ad; 0x1d244;
|
||||
0x1da36; 0x1da6c; 0x1da75; 0x1da84; 0x1da9f; 0x1daaf; 0x1e006; 0x1e018;
|
||||
0x1e021; 0x1e024; 0x1e02a; 0x1e136; 0x1e2ef; 0x1e8d6; 0x1e94a; 0x1f004;
|
||||
0x1f0cf; 0x1f18e; 0x1f19a; 0x1f202; 0x1f23b; 0x1f248; 0x1f251; 0x1f265;
|
||||
0x1f320; 0x1f335; 0x1f37c; 0x1f393; 0x1f3ca; 0x1f3d3; 0x1f3f0; 0x1f3f4;
|
||||
0x1f43e; 0x1f440; 0x1f4fc; 0x1f53d; 0x1f54e; 0x1f567; 0x1f57a; 0x1f596;
|
||||
0x1f5a4; 0x1f64f; 0x1f6c5; 0x1f6cc; 0x1f6d2; 0x1f6d7; 0x1f6ec; 0x1f6fc;
|
||||
0x1f7eb; 0x1f93a; 0x1f945; 0x1f978; 0x1f9cb; 0x1f9ff; 0x1fa74; 0x1fa7a;
|
||||
0x1fa86; 0x1faa8; 0x1fab6; 0x1fac2; 0x1fad6; 0x2fffd; 0x3fffd; 0xe0001;
|
||||
0xe007f; 0xe01ef|],
|
||||
[|0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 2; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2;
|
||||
2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 0; 0; 0; 2; 2; 2; 2; 2; 0; 2;
|
||||
2; 0; 2; 2; 2; 2; 2; 2; 2; 2; 2; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 2; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 2;
|
||||
2; 0; 0; 2; 0; 2; 2; 2; 0; 2; 2; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 2; 0; 2; 2; 2; 2; 2; 2; 2; 2; 0;
|
||||
0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 0; 2; 2; 2;
|
||||
2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2;
|
||||
2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 2; 0; 0; 0|])
|
||||
|
||||
let s000 = ""
|
||||
let s001 = "\000\000\000\000\000\000\000\000\000\000\b\000\000\001\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s002 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\000"
|
||||
let s003 = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\016\016\016\016\016\016\016\016\016\016\016\016\000\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s004 = "\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002"
|
||||
let s005 = "\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s006 = "\016\016\016\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s007 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\002"
|
||||
let s008 = "\016\002\002\016\002\002\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s009 = "\011\011\011\011\011\011\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\016\000\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s010 = "\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s011 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\011\016\002\002\002\002\002\002\016\016\002\002\016\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s012 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\011\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002"
|
||||
let s013 = "\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s014 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s015 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\002\016\016"
|
||||
let s016 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\016\002\002\002\002\002\002\002\002\002\016\002\002\002\016\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s017 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s018 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\011\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002"
|
||||
let s019 = "\002\002\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\002\016\r\r"
|
||||
let s020 = "\r\002\002\002\002\002\002\002\002\r\r\r\r\002\r\r\016\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s021 = "\016\002\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\002\r"
|
||||
let s022 = "\r\002\002\002\002\016\016\r\r\016\016\r\r\002\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016"
|
||||
let s023 = "\016\002\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\r\r"
|
||||
let s024 = "\r\002\002\016\016\016\016\002\002\016\016\002\002\002\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\002\016\016\016\016\016\016\016\016\016\016"
|
||||
let s025 = "\r\002\002\002\002\002\016\002\002\r\016\r\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002"
|
||||
let s026 = "\016\002\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\002\002"
|
||||
let s027 = "\r\002\002\002\002\016\016\r\r\016\016\r\r\002\016\016\016\016\016\016\016\002\002\002\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s028 = "\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r"
|
||||
let s029 = "\002\r\r\016\016\016\r\r\r\016\r\r\r\002\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s030 = "\002\r\r\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002"
|
||||
let s031 = "\002\r\r\r\r\016\002\002\002\016\002\002\002\002\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s032 = "\016\002\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\r\002"
|
||||
let s033 = "\r\r\002\r\r\016\002\r\r\016\r\r\002\002\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s034 = "\002\002\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\002\r"
|
||||
let s035 = "\r\002\002\002\002\016\r\r\r\016\r\r\r\002\011\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s036 = "\016\002\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s037 = "\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\002\r\r\002\002\002\016\002\016\r\r\r\r\r\r\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s038 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\r\002\002\002\002\002\002\002\016\016\016\016\016"
|
||||
let s039 = "\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s040 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\r\002\002\002\002\002\002\002\002\002\016\016\016"
|
||||
let s041 = "\016\016\016\016\016\016\016\016\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s042 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\002\016\002\016\016\016\016\r\r"
|
||||
let s043 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\r"
|
||||
let s044 = "\002\002\002\002\002\016\002\002\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016"
|
||||
let s045 = "\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s046 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\r\002\002\002\002\002\002\016\002\002\r\r\002\002\016"
|
||||
let s047 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\002\002\016\016\016\016\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s048 = "\016\016\002\016\r\002\002\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s049 = "\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007"
|
||||
let s050 = "\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015"
|
||||
let s051 = "\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014"
|
||||
let s052 = "\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014"
|
||||
let s053 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s054 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s055 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s056 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\r\002\002\002\002\002\002\002\r\r"
|
||||
let s057 = "\r\r\r\r\r\r\002\r\r\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s058 = "\016\016\016\016\016\016\016\016\016\016\016\002\002\002\000\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s059 = "\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s060 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\r\r\r\r\002\002\r\r\r\016\016\016\016\r\r\002\r\r\r\r\r\r\002\002\002\016\016\016\016"
|
||||
let s061 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\r\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s062 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\002\r\002\002\002\002\002\002\002\016\002\016\002\016\016\002\002\002\002\002\002\002\002\r\r\r\r\r\r\002\002\002\002\002\002\002\002\002\002\016\016\002"
|
||||
let s063 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002"
|
||||
let s064 = "\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s065 = "\002\002\002\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\r\002\r\r\r"
|
||||
let s066 = "\r\r\002\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s067 = "\002\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\002\002\002\002\r\r\002\002\r\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s068 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\002\002\r\r\r\002\r\002\002\002\r\r\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s069 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\r\r\r\r\r\002\002\002\002\002\002\002\002\r\r\002\002\016\016\016\016\016\016\016\016"
|
||||
let s070 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\016\002\002\002\002\002\002\002\002\002\002\002\002\002\r\002\002\002\002\002\002\002\016\016\016\016\002\016\016\016\016\016\016\002\016\016\r\002\002\016\016\016\016\016\016"
|
||||
let s071 = "\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\002\002\002\002\002"
|
||||
let s072 = "\016\016\016\016\016\016\016\016\016\016\016\000\002\017\000\000\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\000\000\000\000\000\000\000\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s073 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s074 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s075 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s076 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002"
|
||||
let s077 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002"
|
||||
let s078 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s079 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s080 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\016\002\002\002\002\002\002\002\002\002\002\016\016"
|
||||
let s081 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s082 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s083 = "\016\016\002\016\016\016\002\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\002\002\r\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s084 = "\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\r\r\r\r\r\r\r\r\r"
|
||||
let s085 = "\r\r\r\r\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\002"
|
||||
let s086 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s087 = "\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\r\r\016\016\016\016\016\016\016\016\016\016\016\016\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\007\016\016\016"
|
||||
let s088 = "\002\002\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\r\002\002\002\002\r\r\002\002\r\r"
|
||||
let s089 = "\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s090 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\r\r\002\002\r\r\002\002\016\016\016\016\016\016\016\016\016"
|
||||
let s091 = "\016\016\016\002\016\016\016\016\016\016\016\016\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016"
|
||||
let s092 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\002\002\002\016\016\002\002\016\016\016\016\016\002\002"
|
||||
let s093 = "\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\002\002\r\r\016\016\016\016\016\r\002\016\016\016\016\016\016\016\016\016"
|
||||
let s094 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\002\r\r\002\r\r\016\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s095 = "\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n"
|
||||
let s096 = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
|
||||
let s097 = "\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
|
||||
let s098 = "\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n"
|
||||
let s099 = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n"
|
||||
let s100 = "\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
|
||||
let s101 = "\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n"
|
||||
let s102 = "\n\n\n\n\n\n\n\n\t\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\016\016\016\016\016\016\016\016\016\016\016\016\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015\015"
|
||||
let s103 = "\015\015\015\015\015\015\015\016\016\016\016\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\014\016\016\016\016"
|
||||
let s104 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s105 = "\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s106 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\000\000\000\000\000\000\000\000\000\000\000\000\016\016\016\016"
|
||||
let s107 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016"
|
||||
let s108 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s109 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\016\016\016\016\016"
|
||||
let s110 = "\016\002\002\002\016\002\002\016\016\016\016\016\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\016\016\016\016\002"
|
||||
let s111 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s112 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s113 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s114 = "\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s115 = "\r\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002"
|
||||
let s116 = "\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002"
|
||||
let s117 = "\002\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\002\002\002\002\r\r\002\002\016\016\011\016\016"
|
||||
let s118 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\011\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s119 = "\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\r\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s120 = "\016\016\016\016\016\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s121 = "\002\002\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\002\002\002\002\002\002\002\002\002\r"
|
||||
let s122 = "\r\016\011\011\016\016\016\016\016\002\002\002\002\016\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s123 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\002\002\002\r\r\002\r\002\002\016\016\016\016\016\016\002\016"
|
||||
let s124 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\r\r\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s125 = "\002\r\r\r\r\016\016\r\r\016\016\r\r\r\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\r\r\016\016\002\002\002\002\002\002\002\016\016\016\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s126 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\002\002\002\002\002\002\002\002"
|
||||
let s127 = "\r\r\002\002\002\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s128 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\r\002\002\002\002\002\002\r\002\r\r\002\r\002"
|
||||
let s129 = "\002\r\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s130 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\r\002\002\002\002\016\016\r\r\r\r\002\002\r\002"
|
||||
let s131 = "\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s132 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\002\002\002\002\002\002\002\002\r\r\002\r\002"
|
||||
let s133 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\002\r\r\002\002\002\002\002\002\r\002\016\016\016\016\016\016\016\016"
|
||||
let s134 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\r\r\002\002\002\002\r\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s135 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\002\002\002\002\002\002\002\002\002\r\002\002\016\016\016\016\016"
|
||||
let s136 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\r\r\r\r\016\r\r\016\016\002\002\r\002\011"
|
||||
let s137 = "\r\011\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s138 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\r\r\002\002\002\002\016\016\002\002\r\r\r\r\002\016\016\016\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s139 = "\016\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\r\011\002\002\002\002\016"
|
||||
let s140 = "\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\r\r\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s141 = "\016\016\016\016\011\011\011\011\011\011\002\002\002\002\002\002\002\002\002\002\002\002\002\r\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s142 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\r\002\002\002\002\002\002\002\016\002\002\002\002\002\002\r\002"
|
||||
let s143 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\r\002\002\002\002\002\002\002\r\002\002\r\002\002\016\016\016\016\016\016\016\016\016"
|
||||
let s144 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\016\016\016\002\016\002\002\016\002"
|
||||
let s145 = "\002\002\002\002\002\002\011\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s146 = "\016\016\016\016\016\016\016\016\016\016\r\r\r\r\r\016\002\002\016\r\r\002\r\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s147 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\r\r\016\016\016\016\016\016\016\016\016"
|
||||
let s148 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\000\000\000\000\000\000\000\000\000\016\016\016\016\016\016\016"
|
||||
let s149 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s150 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016"
|
||||
let s151 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r"
|
||||
let s152 = "\r\r\r\r\r\r\r\r\016\016\016\016\016\016\016\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s153 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\r\r\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s154 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\016\000\000\000\000\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s155 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\r\002\002\002\016\016\016\r\002\002\002\002\002\000\000\000\000\000\000\000\000\002\002\002\002\002"
|
||||
let s156 = "\002\002\002\016\016\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s157 = "\016\016\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s158 = "\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\002\002\002\002\002"
|
||||
let s159 = "\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016"
|
||||
let s160 = "\016\016\016\016\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s161 = "\002\002\002\002\002\002\002\016\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\016\016\002\002\002\002\002\002\002\016\002\002\016\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s162 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s163 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s164 = "\016\016\016\016\002\002\002\002\002\002\002\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016"
|
||||
let s165 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012\012"
|
||||
let s166 = "\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\016\002\002\002\002\002"
|
||||
let s167 = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002"
|
||||
let s168 = "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
|
||||
let s169 = "\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\002\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
|
||||
|
||||
let grapheme_cluster_boundary =
|
||||
[|[|s001; s002; s003; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s004; s005; s000; s000; s000; s000; s006; s000; s000; s000; s007; s008;
|
||||
s009; s010; s000; s011; s012; s013; s014; s015; s016; s017; s000; s018;
|
||||
s019; s020; s021; s022; s023; s024; s023; s025; s026; s027; s028; s029;
|
||||
s030; s031; s032; s033; s034; s035; s036; s037; s038; s039; s040; s041;
|
||||
s042; s043; s044; s045|];
|
||||
[|s046; s047; s048; s000; s049; s050; s051; s052; s000; s000; s000; s000;
|
||||
s000; s053; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s054; s055; s056; s057; s058; s000; s059; s000;
|
||||
s060; s000; s000; s000; s061; s062; s063; s064; s065; s066; s067; s068;
|
||||
s069; s000; s000; s070; s000; s000; s000; s071; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[|s072; s073; s000; s074; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s075; s000; s076; s000; s077; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[|s078; s000; s079; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[||]; [||]; [||]; [||]; [||]; [||];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s080; s081; s082; s000; s000; s000; s000; s083; s000; s084; s085;
|
||||
s086; s087; s088; s089; s090; s091; s092; s093; s000; s000; s000; s094;
|
||||
s095; s096; s097; s098; s099; s100; s101; s095; s096; s097; s098; s099;
|
||||
s100; s101; s095; s096|];
|
||||
[|s097; s098; s099; s100; s101; s095; s096; s097; s098; s099; s100; s101;
|
||||
s095; s096; s097; s098; s099; s100; s101; s095; s096; s097; s098; s099;
|
||||
s100; s101; s095; s096; s097; s098; s099; s100; s101; s095; s096; s097;
|
||||
s098; s099; s100; s101; s095; s096; s097; s098; s099; s100; s101; s095;
|
||||
s096; s097; s098; s099; s100; s101; s095; s096; s097; s098; s099; s100;
|
||||
s101; s095; s096; s097|];
|
||||
[|s098; s099; s100; s101; s095; s096; s097; s098; s099; s100; s101; s095;
|
||||
s096; s097; s098; s099; s100; s101; s095; s096; s097; s098; s099; s100;
|
||||
s101; s095; s096; s097; s098; s099; s100; s101; s095; s096; s097; s098;
|
||||
s099; s100; s101; s095; s096; s097; s098; s099; s100; s101; s095; s096;
|
||||
s097; s098; s099; s100; s101; s095; s096; s097; s098; s099; s100; s101;
|
||||
s095; s096; s097; s098|];
|
||||
[|s099; s100; s101; s095; s096; s097; s098; s099; s100; s101; s095; s096;
|
||||
s097; s098; s099; s100; s101; s095; s096; s097; s098; s099; s100; s101;
|
||||
s095; s096; s097; s098; s099; s100; s102; s103; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[||];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s104; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s105; s000; s000; s002; s000; s000; s081; s106; s000; s000; s000; s000;
|
||||
s000; s000; s000; s107; s000; s000; s000; s108; s000; s109; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s110; s000; s000; s111;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s112; s000; s000; s000;
|
||||
s000; s000; s113; s000; s000; s114; s000; s000; s115; s116; s117; s118;
|
||||
s119; s120; s121; s122; s123; s000; s000; s124; s034; s125; s000; s000;
|
||||
s126; s127; s128; s129; s000; s000; s130; s131; s132; s064; s133; s000;
|
||||
s134; s000; s000; s000|];
|
||||
[|s135; s000; s000; s000; s136; s137; s000; s138; s139; s140; s141; s000;
|
||||
s000; s000; s000; s000; s142; s000; s143; s000; s144; s145; s146; s000;
|
||||
s000; s000; s000; s147; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s148; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[||]; [||]; [||];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s149;
|
||||
s150; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s151; s152; s153; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[||]; [||]; [||]; [||];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s154; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s155; s156; s000; s000; s157; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s158; s159; s160; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s161; s000; s000; s000;
|
||||
s150; s000; s000; s000; s000; s000; s000; s162; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[|s000; s000; s000; s163; s000; s164; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s165; s000; s000; s000; s000; s000; s000; s000; s166;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||]; [||];
|
||||
[||]; [||]; [||]; [||]; [||];
|
||||
[|s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s167; s004; s168; s168;
|
||||
s004; s004; s004; s169; s168; s168; s168; s168; s168; s168; s168; s168;
|
||||
s168; s168; s168; s168; s168; s168; s168; s168; s168; s168; s168; s168;
|
||||
s168; s168; s168; s168|];
|
||||
[|s168; s168; s168; s168; s168; s168; s168; s168; s168; s168; s168; s168;
|
||||
s168; s168; s168; s168; s168; s168; s168; s168; s168; s168; s168; s168;
|
||||
s168; s168; s168; s168; s168; s168; s168; s168; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000; s000;
|
||||
s000; s000; s000; s000|]|]
|
||||
14
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_uucp_data.mli
vendored
Normal file
14
unikernel/duniverse/dune_/vendor/notty/src/no-uucp/notty_uucp_data.mli
vendored
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
(* Do not edit.
|
||||
*
|
||||
* This module contains select unicode properties extracted from Uucp,
|
||||
* using `./support/gen_unicode_props.ml`.
|
||||
*
|
||||
* Unicode version 13.0.0.
|
||||
*)
|
||||
|
||||
(* Uucp.Break.tty_width_hint *)
|
||||
val tty_width_hint: int array * int array * int array
|
||||
|
||||
(* Uucp.Break.Low.grapheme_cluster. *)
|
||||
val grapheme_cluster_boundary: string array array
|
||||
|
||||
925
unikernel/duniverse/dune_/vendor/notty/src/notty.ml
vendored
Normal file
925
unikernel/duniverse/dune_/vendor/notty/src/notty.ml
vendored
Normal file
|
|
@ -0,0 +1,925 @@
|
|||
(* Copyright (c) 2016-2017 David Kaloper Meršinjak. All rights reserved.
|
||||
See LICENSE.md. *)
|
||||
|
||||
open Dune_uutf
|
||||
|
||||
let invalid_arg fmt = Format.kasprintf invalid_arg fmt
|
||||
|
||||
let (&.) f g x = f (g x)
|
||||
|
||||
let btw (x : int) a b = a <= x && x <= b
|
||||
let bit n b = b land (1 lsl n) > 0
|
||||
|
||||
let max (a : int) b = if a > b then a else b
|
||||
let min (a : int) b = if a < b then a else b
|
||||
|
||||
let is_C0 x = x < 0x20 || x = 0x7f
|
||||
and is_C1 x = 0x80 <= x && x < 0xa0
|
||||
let is_ctrl x = is_C0 x || is_C1 x
|
||||
and is_ascii x = x < 0x80
|
||||
|
||||
let rec concatm z (@) xs =
|
||||
let rec accum (@) = function
|
||||
| []|[_] as xs -> xs
|
||||
| a::b::xs -> (a @ b) :: accum (@) xs in
|
||||
match xs with [] -> z | [x] -> x | xs -> concatm z (@) (accum (@) xs)
|
||||
|
||||
let rec linspcm z (@) x n f = match n with
|
||||
| 0 -> z
|
||||
| 1 -> f x
|
||||
| _ -> let m = n / 2 in linspcm z (@) x m f @ linspcm z (@) (x + m) (n - m) f
|
||||
|
||||
let memo (type a) ?(hash=Hashtbl.hash) ?(eq=(=)) ~size f =
|
||||
let module H = Ephemeron.K1.Make
|
||||
(struct type t = a let (hash, equal) = (hash, eq) end) in
|
||||
let t = H.create size in fun x ->
|
||||
try H.find t x with Not_found -> let y = f x in H.add t x y; y
|
||||
|
||||
module Buffer = struct
|
||||
include Buffer
|
||||
let buf = Buffer.create 1024
|
||||
let mkstring f = f buf; let res = contents buf in reset buf; res
|
||||
let add_decimal b = function
|
||||
| x when btw x 0 999 ->
|
||||
let d1 = x / 100 and d2 = (x mod 100) / 10 and d3 = x mod 10 in
|
||||
if d1 > 0 then 0x30 + d1 |> Char.unsafe_chr |> add_char b;
|
||||
if (d1 + d2) > 0 then 0x30 + d2 |> Char.unsafe_chr |> add_char b;
|
||||
0x30 + d3 |> Char.unsafe_chr |> add_char b
|
||||
| x -> string_of_int x |> add_string b
|
||||
let add_chars b c n = for _ = 1 to n do add_char b c done
|
||||
end
|
||||
|
||||
module String = struct
|
||||
include String
|
||||
let sub0cp s i len = if i > 0 || len < length s then sub s i len else s
|
||||
let of_chars_rev = function
|
||||
| [] -> ""
|
||||
| [c] -> String.make 1 c
|
||||
| cs ->
|
||||
let n = List.length cs in
|
||||
let rec go bs i = Bytes.(function
|
||||
| [] -> unsafe_to_string bs
|
||||
| x::xs -> unsafe_set bs i x; go bs (pred i) xs
|
||||
) in go (Bytes.create n) (n - 1) cs
|
||||
end
|
||||
|
||||
module Option = struct
|
||||
|
||||
let map f = function Some x -> Some (f x) | _ -> None
|
||||
let get def = function Some x -> x | _ -> def
|
||||
let to_list = function Some x -> [x] | _ -> []
|
||||
let (>>|) a f = map f a
|
||||
let (>>=) a f = match a with Some x -> f x | _ -> None
|
||||
end
|
||||
|
||||
module Text = struct
|
||||
|
||||
let err_ctrl u = invalid_arg "Notty: control char: U+%02X, %S" (Char.code u)
|
||||
let err_malformed = invalid_arg "Notty: malformed UTF-8: %s, %S"
|
||||
|
||||
type t =
|
||||
| Ascii of string * int * int
|
||||
| Utf8 of string * int array * int * int
|
||||
|
||||
let equal t1 t2 = match (t1, t2) with
|
||||
| (Utf8 (s1, _, i1, n1), Utf8 (s2, _, i2, n2))
|
||||
| (Ascii (s1, i1, n1), Ascii (s2, i2, n2)) -> i1 = i2 && n1 = n2 && s1 = s2
|
||||
| _ -> false
|
||||
|
||||
let width = function Utf8 (_, _, _, w) -> w | Ascii (_, _, w) -> w
|
||||
|
||||
let empty = Ascii ("", 0, 0)
|
||||
|
||||
let is_empty t = width t = 0
|
||||
|
||||
let graphemes str =
|
||||
let module Uuseg = Notty_grapheme_cluster in
|
||||
let seg = Uuseg.create () in
|
||||
let rec f (is, w as acc) i evt =
|
||||
match Uuseg.add seg evt with
|
||||
| `Await | `End -> acc
|
||||
| `Uchar u -> f (is, w + Notty_uucp.tty_width_hint u) i `Await
|
||||
| `Boundary ->
|
||||
let is = match w with 0 -> is | 1 -> i::is | _ -> i::(-1)::is in
|
||||
f (is, 0) i `Await in
|
||||
let acc = Uutf.String.fold_utf_8 (fun acc i -> function
|
||||
| `Malformed err -> err_malformed err str
|
||||
| `Uchar _ as u -> f acc i u
|
||||
) ([0], 0) str in
|
||||
f acc (String.length str) `End |> fst |> List.rev |> Array.of_list (*XXX*)
|
||||
|
||||
let dead = ' '
|
||||
|
||||
let to_buffer buf = function
|
||||
| Ascii (s, off, w) -> Buffer.add_substring buf s off w
|
||||
| Utf8 (s, ix, off, w) ->
|
||||
let x1 = match ix.(off) with
|
||||
| -1 -> Buffer.add_char buf dead; ix.(off + 1) | x -> x
|
||||
and x2 = ix.(off + w) in
|
||||
Buffer.add_substring buf s x1 @@
|
||||
(if x2 = -1 then ix.(off + w - 1) else x2) - x1;
|
||||
if x2 = -1 then Buffer.add_char buf dead
|
||||
|
||||
let sub t x w =
|
||||
let w1 = width t in
|
||||
if w = 0 || x >= w1 then empty else
|
||||
let w = min w (w1 - x) in
|
||||
if w = w1 then t else match t with
|
||||
Ascii (s, off, _) -> Ascii (s, off + x, w)
|
||||
| Utf8 (s, ix, off, _) -> Utf8 (s, ix, off + x, w)
|
||||
|
||||
let is_ascii_or_raise_ctrl s =
|
||||
let (@!) s i = String.unsafe_get s i |> Char.code in
|
||||
let rec go s acc i n =
|
||||
if n = 0 then acc else
|
||||
let x = s @! i in
|
||||
if is_C0 x then
|
||||
err_ctrl s.[i] s
|
||||
else if x = 0xc2 && n > 1 && is_C1 (s @! (i + 1)) then
|
||||
err_ctrl s.[i + 1] s
|
||||
else go s (acc && is_ascii x) (i + 1) (n - 1) in
|
||||
go s true 0 (String.length s)
|
||||
|
||||
let of_ascii s = Ascii (s, 0, String.length s)
|
||||
and of_unicode s = let x = graphemes s in Utf8 (s, x, 0, Array.length x - 1)
|
||||
let of_unicode = memo ~eq:String.equal ~size:128 of_unicode
|
||||
|
||||
let of_string = function
|
||||
| "" -> empty
|
||||
| s -> if is_ascii_or_raise_ctrl s then of_ascii s else of_unicode s
|
||||
|
||||
let of_uchars ucs = of_string @@ Buffer.mkstring @@ fun buf ->
|
||||
Array.iter (Buffer.add_utf_8_uchar buf) ucs
|
||||
|
||||
let replicateu w u =
|
||||
if is_ctrl (Uchar.to_int u) then
|
||||
err_ctrl (Uchar.unsafe_to_char u) "<repeated character>"
|
||||
else if w < 1 then empty
|
||||
else if is_ascii (Uchar.to_int u) then
|
||||
of_ascii (String.make w (Uchar.unsafe_to_char u))
|
||||
else of_unicode @@ Buffer.mkstring @@ fun buf ->
|
||||
for _ = 1 to w do Buffer.add_utf_8_uchar buf u done
|
||||
|
||||
let replicatec w c = replicateu w (Uchar.of_char c)
|
||||
end
|
||||
|
||||
module A = struct
|
||||
|
||||
type color = int
|
||||
type style = int
|
||||
type t = { fg : color; bg : color; st : style }
|
||||
|
||||
let equal t1 t2 = t1.fg = t2.fg && t1.bg = t2.bg && t1.st = t2.st
|
||||
|
||||
let black = 0x01000000
|
||||
and red = 0x01000001
|
||||
and green = 0x01000002
|
||||
and yellow = 0x01000003
|
||||
and blue = 0x01000004
|
||||
and magenta = 0x01000005
|
||||
and cyan = 0x01000006
|
||||
and white = 0x01000007
|
||||
and lightblack = 0x01000008
|
||||
and lightred = 0x01000009
|
||||
and lightgreen = 0x0100000a
|
||||
and lightyellow = 0x0100000b
|
||||
and lightblue = 0x0100000c
|
||||
and lightmagenta = 0x0100000d
|
||||
and lightcyan = 0x0100000e
|
||||
and lightwhite = 0x0100000f
|
||||
|
||||
let tag c = (c land 0x03000000) lsr 24
|
||||
|
||||
let rgb ~r ~g ~b =
|
||||
if r < 0 || g < 0 || b < 0 || r > 5 || g > 5 || b > 5 then
|
||||
invalid_arg "Notty.A.rgb %d %d %d: channel out of range" r g b
|
||||
else 0x01000000 lor (r * 36 + g * 6 + b + 16)
|
||||
|
||||
let gray level =
|
||||
if level < 0 || level > 23 then
|
||||
invalid_arg "Notty.A.gray %d: level out of range" level
|
||||
else 0x01000000 lor (level + 232)
|
||||
|
||||
let rgb_888 ~r ~g ~b =
|
||||
if r < 0 || g < 0 || b < 0 || r > 255 || g > 255 || b > 255 then
|
||||
invalid_arg "Notty.A.rgb_888 %d %d %d: channel out of range" r g b
|
||||
else 0x02000000 lor ((r lsl 16) lor (g lsl 8) lor b)
|
||||
|
||||
let i x = x land 0xff
|
||||
and r x = x lsr 16 land 0xff
|
||||
and g x = x lsr 8 land 0xff
|
||||
and b x = x land 0xff
|
||||
|
||||
let bold = 1
|
||||
and dim = 2
|
||||
and faint = 2
|
||||
and italic = 4
|
||||
and underline = 8
|
||||
and blink = 16
|
||||
and reverse = 32
|
||||
|
||||
let empty = { fg = 0; bg = 0; st = 0 }
|
||||
|
||||
let (++) a1 a2 =
|
||||
if a1 == empty then a2 else if a2 == empty then a1 else
|
||||
{ fg = (match a2.fg with 0 -> a1.fg | x -> x)
|
||||
; bg = (match a2.bg with 0 -> a1.bg | x -> x)
|
||||
; st = a1.st lor a2.st }
|
||||
|
||||
let fg fg = { empty with fg }
|
||||
let bg bg = { empty with bg }
|
||||
let st st = { empty with st }
|
||||
end
|
||||
|
||||
module I = struct
|
||||
|
||||
type dim = int * int
|
||||
|
||||
type t =
|
||||
| Empty
|
||||
| Segment of A.t * Text.t
|
||||
| Hcompose of (t * t) * dim
|
||||
| Vcompose of (t * t) * dim
|
||||
| Zcompose of (t * t) * dim
|
||||
| Hcrop of (t * int * int) * dim
|
||||
| Vcrop of (t * int * int) * dim
|
||||
| Void of dim
|
||||
|
||||
let width = function
|
||||
| Empty -> 0
|
||||
| Segment (_, text) -> Text.width text
|
||||
| Hcompose (_, (w, _)) -> w
|
||||
| Vcompose (_, (w, _)) -> w
|
||||
| Zcompose (_, (w, _)) -> w
|
||||
| Hcrop (_, (w, _)) -> w
|
||||
| Vcrop (_, (w, _)) -> w
|
||||
| Void (w, _) -> w [@@inline]
|
||||
|
||||
let height = function
|
||||
| Empty -> 0
|
||||
| Segment _ -> 1
|
||||
| Hcompose (_, (_, h)) -> h
|
||||
| Vcompose (_, (_, h)) -> h
|
||||
| Zcompose (_, (_, h)) -> h
|
||||
| Hcrop (_, (_, h)) -> h
|
||||
| Vcrop (_, (_, h)) -> h
|
||||
| Void (_, h) -> h [@@inline]
|
||||
|
||||
let equal t1 t2 =
|
||||
let rec eq t1 t2 = match (t1, t2) with
|
||||
| (Empty, Empty) -> true
|
||||
| (Segment (a1, t1), Segment (a2, t2)) ->
|
||||
A.equal a1 a2 && Text.equal t1 t2
|
||||
| (Hcompose ((a, b), _), Hcompose ((c, d), _))
|
||||
| (Vcompose ((a, b), _), Vcompose ((c, d), _))
|
||||
| (Zcompose ((a, b), _), Zcompose ((c, d), _)) -> eq a c && eq b d
|
||||
| (Hcrop ((a, i1, n1), _), Hcrop ((b, i2, n2), _))
|
||||
| (Vcrop ((a, i1, n1), _), Vcrop ((b, i2, n2), _)) ->
|
||||
i1 = i2 && n1 = n2 && eq a b
|
||||
| (Void (a, b), Void (c, d)) -> a = c && b = d
|
||||
| _ -> false in
|
||||
width t1 = width t2 && height t1 = height t2 && eq t1 t2
|
||||
|
||||
let empty = Empty
|
||||
|
||||
let (<|>) t1 t2 = match (t1, t2) with
|
||||
| (_, Empty) -> t1
|
||||
| (Empty, _) -> t2
|
||||
| _ ->
|
||||
let w = width t1 + width t2
|
||||
and h = max (height t1) (height t2) in
|
||||
Hcompose ((t1, t2), (w, h))
|
||||
|
||||
let (<->) t1 t2 = match (t1, t2) with
|
||||
| (_, Empty) -> t1
|
||||
| (Empty, _) -> t2
|
||||
| _ ->
|
||||
let w = max (width t1) (width t2)
|
||||
and h = height t1 + height t2 in
|
||||
Vcompose ((t1, t2), (w, h))
|
||||
|
||||
let (</>) t1 t2 = match (t1, t2) with
|
||||
| (_, Empty) -> t1
|
||||
| (Empty, _) -> t2
|
||||
| _ ->
|
||||
let w = max (width t1) (width t2)
|
||||
and h = max (height t1) (height t2) in
|
||||
Zcompose ((t1, t2), (w, h))
|
||||
|
||||
let void w h =
|
||||
if w < 1 && h < 1 then Empty else Void (max 0 w, max 0 h)
|
||||
|
||||
let lincropinv crop void (++) init fini img =
|
||||
match (init >= 0, fini >= 0) with
|
||||
| (true, true) -> crop init fini img
|
||||
| (true, _ ) -> crop init 0 img ++ void (-fini)
|
||||
| (_ , true) -> void (-init) ++ crop 0 fini img
|
||||
| _ -> void (-init) ++ img ++ void (-fini)
|
||||
|
||||
let hcrop =
|
||||
let ctor left right img =
|
||||
let h = height img and w = width img - left - right in
|
||||
if w > 0 then Hcrop ((img, left, right), (w, h)) else void w h
|
||||
in lincropinv ctor (fun w -> void w 0) (<|>)
|
||||
|
||||
let vcrop =
|
||||
let ctor top bottom img =
|
||||
let w = width img and h = height img - top - bottom in
|
||||
if h > 0 then Vcrop ((img, top, bottom), (w, h)) else void w h
|
||||
in lincropinv ctor (void 0) (<->)
|
||||
|
||||
let crop ?(l=0) ?(r=0) ?(t=0) ?(b=0) img =
|
||||
let img = if l <> 0 || r <> 0 then hcrop l r img else img in
|
||||
if t <> 0 || b <> 0 then vcrop t b img else img
|
||||
|
||||
let hpad left right img = hcrop (-left) (-right) img
|
||||
|
||||
let vpad top bottom img = vcrop (-top) (-bottom) img
|
||||
|
||||
let pad ?(l=0) ?(r=0) ?(t=0) ?(b=0) img =
|
||||
crop ~l:(-l) ~r:(-r) ~t:(-t) ~b:(-b) img
|
||||
|
||||
let hcat = concatm empty (<|>)
|
||||
|
||||
let vcat = concatm empty (<->)
|
||||
|
||||
let zcat xs = List.fold_right (</>) xs empty
|
||||
|
||||
let text attr tx =
|
||||
if Text.is_empty tx then void 0 1 else Segment (attr, tx)
|
||||
|
||||
let string attr s = text attr (Text.of_string s)
|
||||
|
||||
let uchars attr a = text attr (Text.of_uchars a)
|
||||
|
||||
let tabulate m n f =
|
||||
let m = max m 0 and n = max n 0 in
|
||||
linspcm empty (<->) 0 n (fun y -> linspcm empty (<|>) 0 m (fun x -> f x y))
|
||||
|
||||
let chars ctor attr c w h =
|
||||
if w < 1 || h < 1 then void w h else
|
||||
let line = text attr (ctor w c) in tabulate 1 h (fun _ _ -> line)
|
||||
|
||||
let char = chars Text.replicatec
|
||||
let uchar = chars Text.replicateu
|
||||
|
||||
let hsnap ?(align=`Middle) w img =
|
||||
let off = width img - w in match align with
|
||||
| `Left -> hcrop 0 off img
|
||||
| `Right -> hcrop off 0 img
|
||||
| `Middle -> let w1 = off / 2 in hcrop w1 (off - w1) img
|
||||
|
||||
let vsnap ?(align=`Middle) h img =
|
||||
let off = height img - h in match align with
|
||||
| `Top -> vcrop 0 off img
|
||||
| `Bottom -> vcrop off 0 img
|
||||
| `Middle -> let h1 = off / 2 in vcrop h1 (off - h1) img
|
||||
|
||||
module Fmt = struct
|
||||
|
||||
open Format
|
||||
|
||||
type stag += Attr of A.t
|
||||
|
||||
let push r x = r := x :: !r
|
||||
let pop r = r := (match !r with _::xs -> xs | _ -> [])
|
||||
let top_a r = match !r with a::_ -> a | _ -> A.empty
|
||||
|
||||
let create () =
|
||||
let img, line, attr = ref empty, ref empty, ref [] in
|
||||
(* OCaml 5.4 added a new record field so to keep compatibility, get and
|
||||
update the record, even if warning 23 "useless-record-with" is
|
||||
triggered, about all fields being updated in <5.4. *)
|
||||
let formatter_out_functions = get_formatter_out_functions () in
|
||||
let[@warning "-23"] formatter_out_functions = {
|
||||
formatter_out_functions with
|
||||
out_flush = (fun () ->
|
||||
img := !img <-> !line; line := empty; attr := [])
|
||||
; out_newline = (fun () ->
|
||||
img := !img <-> !line; line := void 0 1)
|
||||
; out_string = (fun s i n ->
|
||||
line := !line <|> string (top_a attr) String.(sub0cp s i n))
|
||||
(* Not entirely clear; either or both could be void: *)
|
||||
; out_spaces = (fun w -> line := !line <|> char (top_a attr) ' ' w 1)
|
||||
; out_indent = (fun w -> line := !line <|> char (top_a attr) ' ' w 1)
|
||||
}
|
||||
in
|
||||
let fmt = formatter_of_out_functions formatter_out_functions in
|
||||
pp_set_formatter_stag_functions fmt {
|
||||
(pp_get_formatter_stag_functions fmt ()) with
|
||||
mark_open_stag =
|
||||
(function Attr a -> push attr A.(top_a attr ++ a); "" | _ -> "")
|
||||
; mark_close_stag = (fun _ -> pop attr; "") };
|
||||
pp_set_mark_tags fmt true;
|
||||
fmt, fun () -> let i = !img in img := empty; line := empty; attr := []; i
|
||||
|
||||
let ppf, reset = create ()
|
||||
|
||||
let kstrf ?(attr = A.empty) ?(w = 1000000) k format =
|
||||
let m = ref 0 in
|
||||
let f1 _ () =
|
||||
m := pp_get_margin ppf ();
|
||||
pp_set_margin ppf w;
|
||||
pp_open_stag ppf (Attr attr)
|
||||
and k _ =
|
||||
pp_print_flush ppf ();
|
||||
pp_set_margin ppf !m;
|
||||
reset () |> k
|
||||
in kfprintf k ppf ("%a" ^^ format) f1 ()
|
||||
|
||||
let strf ?attr ?w format = kstrf ?attr ?w (fun i -> i) format
|
||||
|
||||
let attr attr f fmt x =
|
||||
pp_open_stag fmt (Attr attr); f fmt x; pp_close_stag fmt ()
|
||||
end
|
||||
|
||||
let kstrf, strf, pp_attr = Fmt.(kstrf, strf, attr)
|
||||
end
|
||||
|
||||
module Operation = struct
|
||||
|
||||
type t =
|
||||
End
|
||||
| Skip of int * t
|
||||
| Text of A.t * Text.t * t
|
||||
|
||||
let skip n k = if n = 0 then k else match k with
|
||||
End -> End
|
||||
| Skip (m, k) -> Skip (m + n, k)
|
||||
| _ -> Skip (n, k) [@@inline]
|
||||
|
||||
let rec scan x w row i k =
|
||||
let open I in match i with
|
||||
|
||||
| Empty | Void _ -> skip w k
|
||||
|
||||
| Segment _ when row > 0 -> skip w k
|
||||
| Segment (attr, text) ->
|
||||
let t = Text.sub text x w in
|
||||
let w1 = Text.width t in
|
||||
let p = if w > w1 then skip (w - w1) k else k in
|
||||
if w1 > 0 then Text (attr, t, p) else p
|
||||
|
||||
| Hcompose ((i1, i2), _) ->
|
||||
let w1 = width i1
|
||||
and w2 = width i2 in
|
||||
if x >= w1 + w2 then skip w k else
|
||||
if x >= w1 then scan (x - w1) w row i2 k else
|
||||
if x + w <= w1 then scan x w row i1 k else
|
||||
scan x (w1 - x) row i1 @@ scan 0 (w - w1 + x) row i2 @@ k
|
||||
|
||||
| Vcompose ((i1, i2), _) ->
|
||||
let h1 = height i1
|
||||
and h2 = height i2 in
|
||||
if row >= h1 + h2 then skip w k else
|
||||
if row >= h1 then scan x w (row - h1) i2 k else scan x w row i1 k
|
||||
|
||||
| Zcompose ((i1, i2), _) ->
|
||||
let rec stitch x w row i = function
|
||||
| End -> scan x w row i End
|
||||
| Text (a, t, ops) as opss ->
|
||||
let w1 = Text.width t in
|
||||
if w1 >= w then opss else
|
||||
Text (a, t, stitch (x + w1) (w - w1) row i ops)
|
||||
| Skip (w1, ops) ->
|
||||
scan x w1 row i @@
|
||||
if w1 >= w then ops else stitch (x + w1) (w - w1) row i ops
|
||||
in stitch x w row i2 @@ scan x w row i1 @@ k
|
||||
|
||||
| Hcrop ((i, left, _), (w1, _)) ->
|
||||
if x >= w1 then skip w k else
|
||||
if x + w <= w1 then scan (x + left) w row i k else
|
||||
scan (x + left) (w1 - x) row i @@ skip (w - w1 + x) k
|
||||
|
||||
| Vcrop ((i, top, _), (_, h1)) ->
|
||||
if row < h1 then scan x w (top + row) i k else skip w k
|
||||
|
||||
let of_image (x, y) (w, h) i =
|
||||
List.init h (fun off -> scan x (x + w) (y + off) i End)
|
||||
end
|
||||
|
||||
module Cap = struct
|
||||
|
||||
type op = Buffer.t -> unit
|
||||
|
||||
let (&) op1 op2 buf = op1 buf; op2 buf
|
||||
|
||||
type t = {
|
||||
skip : int -> op
|
||||
; sgr : A.t -> op
|
||||
; newline : op
|
||||
; clreol : op
|
||||
; cursvis : bool -> op
|
||||
; cursat : int -> int -> op
|
||||
; cubcuf : int -> op
|
||||
; cuucud : int -> op
|
||||
; cr : op
|
||||
; altscr : bool -> op
|
||||
; mouse : bool -> op
|
||||
; bpaste : bool -> op
|
||||
}
|
||||
|
||||
let ((<|), (<.), (<!)) = Buffer.(add_string, add_char, add_decimal)
|
||||
|
||||
let sts = [ ";1"; ";2"; ";3"; ";4"; ";5"; ";7" ]
|
||||
|
||||
let sgr { A.fg; bg; st } buf =
|
||||
buf <| "\x1b[0";
|
||||
let rgb888 buf x =
|
||||
buf <! A.r x; buf <. ';'; buf <! A.g x; buf <. ';'; buf <! A.b x in
|
||||
( match A.tag fg with
|
||||
0 -> ()
|
||||
| 1 -> let c = A.i fg in
|
||||
if c < 8 then ( buf <. ';'; buf <! (c + 30) )
|
||||
else if c < 16 then ( buf <. ';'; buf <! (c + 82) )
|
||||
else ( buf <| ";38;5;"; buf <! c )
|
||||
| _ -> buf <| ";38;2;"; rgb888 buf fg );
|
||||
( match A.tag bg with
|
||||
0 -> ()
|
||||
| 1 -> let c = A.i bg in
|
||||
if c < 8 then ( buf <. ';'; buf <! (c + 40) )
|
||||
else if c < 16 then ( buf <. ';'; buf <! (c + 92) )
|
||||
else ( buf <| ";48;5;"; buf <! c )
|
||||
| _ -> buf <| ";48;2;"; rgb888 buf bg );
|
||||
if st <> 0 then
|
||||
( let rec go f xs = match (f, xs) with
|
||||
| (0, _) | (_, []) -> ()
|
||||
| (_, x::xs) -> if f land 1 > 0 then buf <| x; go (f lsr 1) xs in
|
||||
go st sts );
|
||||
buf <. 'm'
|
||||
|
||||
let ansi = {
|
||||
skip = (fun n b -> b <| "\x1b[0m"; Buffer.add_chars b ' ' n)
|
||||
; newline = (fun b -> b <| "\x1bE")
|
||||
; altscr = (fun x b -> b <| if x then "\x1b[?1049h" else "\x1b[?1049l")
|
||||
; cursat = (fun w h b -> b <| "\x1b["; b <! h; b <. ';'; b <! w; b <. 'H')
|
||||
; cubcuf = (fun x b -> b <| "\x1b["; b <! abs x; b <. if x < 0 then 'D' else 'C')
|
||||
; cuucud = (fun y b -> b <| "\x1b["; b <! abs y; b <. if y < 0 then 'A' else 'B')
|
||||
; cr = (fun b -> b <| "\x1b[1G")
|
||||
; clreol = (fun b -> b <| "\x1b[K")
|
||||
; cursvis = (fun x b -> b <| if x then "\x1b[34h\x1b[?25h" else "\x1b[?25l")
|
||||
; mouse = (fun x b -> b <| if x then "\x1b[?1000;1002;1005;1015;1006h"
|
||||
else "\x1b[?1000;1002;1005;1015;1006l")
|
||||
; bpaste = (fun x b -> b <| if x then "\x1b[?2004h" else "\x1b[?2004l")
|
||||
; sgr }
|
||||
|
||||
let no0 _ = ()
|
||||
and no1 _ _ = ()
|
||||
and no2 _ _ _ = ()
|
||||
|
||||
let dumb = {
|
||||
skip = (fun n b -> Buffer.add_chars b ' ' n)
|
||||
; newline = (fun b -> b <| "\n")
|
||||
; altscr = no1
|
||||
; cursat = no2
|
||||
; cubcuf = no1
|
||||
; cuucud = no1
|
||||
; cr = no0
|
||||
; clreol = no0
|
||||
; cursvis = no1
|
||||
; sgr = no1
|
||||
; mouse = no1
|
||||
; bpaste = no1
|
||||
}
|
||||
|
||||
let erase cap buf = cap.sgr A.empty buf; cap.clreol buf (* KEEP ETA-LONG. *)
|
||||
let cursat0 cap w h = cap.cursat (max w 0 + 1) (max h 0 + 1)
|
||||
end
|
||||
|
||||
module Render = struct
|
||||
|
||||
open Cap
|
||||
open Operation
|
||||
|
||||
let skip_op cap buf n = cap.skip n buf
|
||||
let text_op cap buf a x = cap.sgr a buf; Text.to_buffer buf x
|
||||
|
||||
let rec line cap buf = function
|
||||
End -> erase cap buf
|
||||
| Skip (n, End) -> erase cap buf; skip_op cap buf n
|
||||
| Text (a, x, End) -> erase cap buf; text_op cap buf a x
|
||||
| Skip (n, ops) -> skip_op cap buf n; line cap buf ops
|
||||
| Text (a, x, ops) -> text_op cap buf a x; line cap buf ops
|
||||
|
||||
let rec lines cap buf = function
|
||||
[] -> ()
|
||||
| [ln] -> line cap buf ln; cap.sgr A.empty buf
|
||||
| ln::lns -> line cap buf ln; cap.newline buf; lines cap buf lns
|
||||
|
||||
let to_buffer buf cap off dim img =
|
||||
Operation.of_image off dim img |> lines cap buf
|
||||
|
||||
let pp cap ppf img =
|
||||
let open Format in
|
||||
let buf = Buffer.create (I.width img * 2) in
|
||||
let h, w = I.(height img, width img |> min (pp_get_margin ppf ())) in
|
||||
let img = I.(img </> vpad (h - 1) 0 (char A.empty ' ' w 1)) in
|
||||
pp_open_vbox ppf 0;
|
||||
for y = 0 to h - 1 do
|
||||
Buffer.clear buf; to_buffer buf cap (0, y) (w, 1) img;
|
||||
pp_print_as ppf w (Buffer.contents buf);
|
||||
if y < h - 1 then pp_print_cut ppf ()
|
||||
done;
|
||||
pp_close_box ppf ()
|
||||
|
||||
let pp_image = pp Cap.ansi
|
||||
let pp_attr ppf a =
|
||||
let string_ = I.string A.empty in
|
||||
pp_image ppf I.(string_ "<" <|> string a "ATTR" <|> string_ ">")
|
||||
end
|
||||
|
||||
module Unescape = struct
|
||||
|
||||
type special = [
|
||||
`Escape
|
||||
| `Enter
|
||||
| `Tab
|
||||
| `Backspace
|
||||
| `Insert
|
||||
| `Delete
|
||||
| `Home | `End
|
||||
| `Arrow of [ `Up | `Down | `Left | `Right ]
|
||||
| `Page of [ `Up | `Down ]
|
||||
| `Function of int
|
||||
]
|
||||
|
||||
type button = [ `Left | `Middle | `Right | `Scroll of [ `Up | `Down ] ]
|
||||
|
||||
type mods = [ `Meta | `Ctrl | `Shift ] list
|
||||
|
||||
type key = [ special | `Uchar of Uchar.t | `ASCII of char ] * mods
|
||||
|
||||
type mouse = [ `Press of button | `Drag | `Release ] * (int * int) * mods
|
||||
|
||||
type paste = [ `Start | `End ]
|
||||
|
||||
type event = [ `Key of key | `Mouse of mouse | `Paste of paste ]
|
||||
|
||||
type esc =
|
||||
C0 of char
|
||||
| C1 of char
|
||||
| SS2 of char
|
||||
| CSI of string * int list * char
|
||||
| Esc_M of int * int * int
|
||||
| Uchar of Uchar.t
|
||||
|
||||
let uchar = function `Uchar u -> u | `ASCII c -> Uchar.of_char c
|
||||
|
||||
let csi =
|
||||
let open Option in
|
||||
let rec priv acc = function
|
||||
| x::xs when btw x 0x3c 0x3f -> priv (Char.unsafe_chr x::acc) xs
|
||||
| xs -> param (String.of_chars_rev acc) None [] xs
|
||||
and param prv p ps = function
|
||||
| x::xs when btw x 0x30 0x39 -> param prv (Some (get 0 p * 10 + x - 0x30)) ps xs
|
||||
| 0x3b::xs -> param prv None (get 0 p :: ps) xs
|
||||
| xs -> code prv (List.rev (to_list p @ ps)) xs
|
||||
and code prv ps = function (* Conflate two classes because urxvt... *)
|
||||
| x::xs when btw x 0x20 0x2f || btw x 0x40 0x7e ->
|
||||
Some (CSI (prv, ps, (Char.chr x)), xs)
|
||||
| _ -> None in
|
||||
priv []
|
||||
|
||||
let rec demux =
|
||||
let chr = Char.chr in function
|
||||
| 0x1b::0x5b::0x4d::a::b::c::xs -> Esc_M (a, b, c) :: demux xs
|
||||
| 0x1b::0x5b::xs | 0x9b::xs ->
|
||||
let (r, xs) = csi xs |> Option.get (C1 '\x5b', xs) in r :: demux xs
|
||||
| 0x1b::0x4f::x::xs | 0x8f::x::xs
|
||||
when is_ascii x -> SS2 (chr x) :: demux xs
|
||||
| 0x1b::x::xs when is_C1 (x + 0x40) -> C1 (chr x) :: demux xs
|
||||
| x::xs when is_C1 x -> C1 (chr (x - 0x40)) :: demux xs
|
||||
| x::xs when is_C0 x -> C0 (chr x) :: demux xs
|
||||
| x::xs -> Uchar (Uchar.unsafe_of_int x) :: demux xs
|
||||
| [] -> []
|
||||
|
||||
let xtrm_mod_flags = function
|
||||
| 2 -> Some [`Shift]
|
||||
| 3 -> Some [`Meta]
|
||||
| 4 -> Some [`Shift; `Meta]
|
||||
| 5 -> Some [`Ctrl]
|
||||
| 6 -> Some [`Shift; `Ctrl]
|
||||
| 7 -> Some [`Meta; `Ctrl]
|
||||
| 8 -> Some [`Shift; `Meta; `Ctrl]
|
||||
| _ -> None
|
||||
|
||||
let mods_xtrm = function
|
||||
| [1;p] -> xtrm_mod_flags p
|
||||
| [] -> Some []
|
||||
| _ -> None
|
||||
|
||||
let mods_rxvt = function
|
||||
| '~' -> Some []
|
||||
| '$' -> Some [`Shift]
|
||||
| '^' -> Some [`Ctrl]
|
||||
| '@' -> Some [`Ctrl; `Shift]
|
||||
| _ -> None
|
||||
|
||||
let mods_common ps code = match (ps, code) with
|
||||
| ([], '~') -> Some []
|
||||
| ([], c) -> mods_rxvt c
|
||||
| ([p], '~') -> xtrm_mod_flags p
|
||||
| _ -> None
|
||||
|
||||
let mouse_p p =
|
||||
let btn = match p land 3 with
|
||||
| 0 when bit 6 p -> `Scroll `Up
|
||||
| 0 -> `Left
|
||||
| 1 when bit 6 p -> `Scroll `Down
|
||||
| 1 -> `Middle
|
||||
| 2 when bit 6 p -> `ALL (* `Scroll `Left *)
|
||||
| 2 -> `Right
|
||||
| 3 when bit 6 p -> `ALL (* `Scroll `Right *)
|
||||
| _ -> `ALL
|
||||
and drag = bit 5 p
|
||||
and mods =
|
||||
(if bit 3 p then [`Meta] else []) @
|
||||
(if bit 4 p then [`Ctrl] else [])
|
||||
in (btn, drag, mods)
|
||||
|
||||
let key k mods = Some (`Key (k, mods))
|
||||
|
||||
let event_of_control_code =
|
||||
let open Option in function
|
||||
| Uchar u when Uchar.to_int u |> is_ascii ->
|
||||
Some (`Key (`ASCII (Uchar.unsafe_to_char u), []))
|
||||
| Uchar u -> Some (`Key (`Uchar u, []))
|
||||
|
||||
| C0 '\x1b' -> key `Escape []
|
||||
| C0 ('\b'|'\x7f') -> key `Backspace []
|
||||
| C0 '\n' -> key `Enter []
|
||||
| C0 '\t' -> key `Tab []
|
||||
|
||||
| C0 x -> key (`ASCII Char.(code x + 0x40 |> unsafe_chr)) [`Ctrl]
|
||||
| C1 x -> key (`ASCII x) [`Meta]
|
||||
|
||||
| CSI ("",[],'Z') -> key `Tab [`Shift]
|
||||
|
||||
| CSI ("",p,'A') -> mods_xtrm p >>= key (`Arrow `Up)
|
||||
| CSI ("",p,'B') -> mods_xtrm p >>= key (`Arrow `Down)
|
||||
| CSI ("",p,'C') -> mods_xtrm p >>= key (`Arrow `Right)
|
||||
| CSI ("",p,'D') -> mods_xtrm p >>= key (`Arrow `Left)
|
||||
|
||||
| CSI ("",[],'a') -> key (`Arrow `Up) [`Shift]
|
||||
| CSI ("",[],'b') -> key (`Arrow `Down) [`Shift]
|
||||
| CSI ("",[],'c') -> key (`Arrow `Right) [`Shift]
|
||||
| CSI ("",[],'d') -> key (`Arrow `Left) [`Shift]
|
||||
| SS2 ('A'|'a') -> key (`Arrow `Up) [`Ctrl]
|
||||
| SS2 ('B'|'b') -> key (`Arrow `Down) [`Ctrl]
|
||||
| SS2 ('C'|'c') -> key (`Arrow `Right) [`Ctrl]
|
||||
| SS2 ('D'|'d') -> key (`Arrow `Left) [`Ctrl]
|
||||
|
||||
| CSI ("",5::p,c) -> mods_common p c >>= key (`Page `Up)
|
||||
| CSI ("",6::p,c) -> mods_common p c >>= key (`Page `Down)
|
||||
|
||||
| CSI ("",2::p,c) -> mods_common p c >>= key `Insert
|
||||
| CSI ("",3::p,c) -> mods_common p c >>= key `Delete
|
||||
|
||||
| CSI ("",[4],'h') -> key `Insert []
|
||||
| CSI ("",[],'L') -> key `Insert [`Ctrl]
|
||||
| CSI ("",[],'P') -> key `Delete []
|
||||
| CSI ("",[],'M') -> key `Delete [`Ctrl]
|
||||
|
||||
| CSI ("",p,'H') -> mods_xtrm p >>= key `Home
|
||||
| CSI ("",[7|1],c) -> mods_rxvt c >>= key `Home
|
||||
|
||||
| CSI ("",p,'F') -> mods_xtrm p >>= key `End
|
||||
| CSI ("",[8|4],c) -> mods_rxvt c >>= key `End
|
||||
| CSI ("",[],'J') -> key `End [`Ctrl]
|
||||
|
||||
| SS2 ('P'..'S' as c) -> key (`Function (Char.code c - 0x4f)) []
|
||||
|
||||
| CSI ("",p,('P'..'S' as c)) ->
|
||||
mods_xtrm p >>= key (`Function (Char.code c - 0x4f))
|
||||
|
||||
| CSI ("",k::p,c) when btw k 11 15 || btw k 17 21 || btw k 23 26 ->
|
||||
mods_common p c >>= key (`Function ((k - 10) - (k - 10) / 6))
|
||||
|
||||
| CSI ("<",[p;x;y],('M'|'m' as c)) ->
|
||||
let (btn, drag, mods) = mouse_p p in
|
||||
( match (c, btn, drag) with
|
||||
| ('M', (#button as b), false) -> Some (`Press b)
|
||||
| ('M', #button, true) -> Some `Drag
|
||||
| ('m', #button, false) -> Some `Release
|
||||
(* | ('M', `ALL , true) -> Some `Move *)
|
||||
| _ -> None
|
||||
) >>| fun e -> `Mouse (e, (x - 1, y - 1), mods)
|
||||
|
||||
| CSI ("",[p;x;y],'M') | Esc_M (p,x,y) as evt ->
|
||||
let (x, y) = match evt with Esc_M _ -> x - 32, y - 32 | _ -> x, y
|
||||
and (btn, drag, mods) = mouse_p (p - 32) in
|
||||
( match (btn, drag) with
|
||||
| (#button as b, false) -> Some (`Press b)
|
||||
| (#button , true ) -> Some `Drag
|
||||
| (`ALL , false) -> Some `Release
|
||||
(* | (`ALL , true) -> Some `Move *)
|
||||
| _ -> None
|
||||
) >>| fun e -> `Mouse (e, (x - 1, y - 1), mods)
|
||||
|
||||
| CSI ("",[200],'~') -> Some (`Paste `Start)
|
||||
| CSI ("",[201],'~') -> Some (`Paste `End)
|
||||
|
||||
| CSI _ | SS2 _ -> None
|
||||
|
||||
let rec events = function
|
||||
| C0 '\x1b' :: cc :: ccs ->
|
||||
( match event_of_control_code cc with
|
||||
| Some (`Key (k, mods)) -> `Key (k, `Meta :: mods) :: events ccs
|
||||
| Some _ -> `Key (`Escape, []) :: events (cc::ccs)
|
||||
| None -> events ccs )
|
||||
| cc::ccs -> (event_of_control_code cc |> Option.to_list) @ events ccs
|
||||
| [] -> []
|
||||
|
||||
let decode = events &. demux &. List.map Uchar.to_int
|
||||
|
||||
type t = (event list * bool) ref
|
||||
|
||||
let create () = ref ([], false)
|
||||
|
||||
let next t = match !t with
|
||||
| (#event as e::es, eof) -> t := (es, eof) ; e
|
||||
| ([], false) -> `Await
|
||||
| _ -> `End
|
||||
|
||||
let list_of_utf8 buf i l =
|
||||
let f cs _ = function `Uchar c -> c::cs | _ -> cs in
|
||||
String.sub0cp (Bytes.unsafe_to_string buf) i l
|
||||
|> Uutf.String.fold_utf_8 f [] |> List.rev
|
||||
|
||||
let input t buf i l = t := match !t with
|
||||
| (es, false) when l > 0 -> (es @ (list_of_utf8 buf i l |> decode), false)
|
||||
| (es, _) -> (es, true)
|
||||
|
||||
let pending t = match !t with ([], false) -> false | _ -> true
|
||||
end
|
||||
|
||||
module Tmachine = struct
|
||||
|
||||
open Cap
|
||||
(* XXX This is sad. This should be a composable, stateless transducer. *)
|
||||
|
||||
type t = {
|
||||
cap : Cap.t
|
||||
; mutable write : Buffer.t -> unit
|
||||
; mutable curs : (int * int) option
|
||||
; mutable dim : (int * int)
|
||||
; mutable image : I.t
|
||||
; mutable dead : bool
|
||||
}
|
||||
|
||||
let emit t op =
|
||||
if t.dead then
|
||||
invalid_arg "Notty: use of released terminal"
|
||||
else t.write <- t.write & op
|
||||
|
||||
let cursor cap = function
|
||||
| None -> cap.cursvis false
|
||||
| Some (w, h) -> cap.cursvis true & cursat0 cap w h
|
||||
|
||||
let create ~mouse ~bpaste cap = {
|
||||
cap
|
||||
; curs = None
|
||||
; dim = (0, 0)
|
||||
; image = I.empty
|
||||
; dead = false
|
||||
; write =
|
||||
cap.altscr true & cursor cap None & cap.mouse mouse & cap.bpaste bpaste
|
||||
}
|
||||
|
||||
let release t =
|
||||
if t.dead then false else
|
||||
( emit t ( t.cap.altscr false & t.cap.cursvis true &
|
||||
t.cap.mouse false & t.cap.bpaste false );
|
||||
t.dead <- true; true )
|
||||
|
||||
let output t buf = t.write buf; t.write <- ignore
|
||||
|
||||
let refresh ({ dim; image; _ } as t) =
|
||||
emit t ( cursor t.cap None & cursat0 t.cap 0 0 &
|
||||
(fun buf -> Render.to_buffer buf t.cap (0, 0) dim image) &
|
||||
cursor t.cap t.curs )
|
||||
|
||||
let set_size t dim = t.dim <- dim
|
||||
let image t image = t.image <- image; refresh t
|
||||
let cursor t curs = t.curs <- curs; emit t (cursor t.cap curs)
|
||||
|
||||
let size t = t.dim
|
||||
let dead t = t.dead
|
||||
end
|
||||
|
||||
module Direct = struct
|
||||
let show_cursor buf cap x = cap.Cap.cursvis x buf
|
||||
and move_cursor buf cap cmd = match cmd with
|
||||
| `To (w, h) -> Cap.cursat0 cap w h buf
|
||||
| `Home -> cap.Cap.cr buf
|
||||
| `By (x, y) ->
|
||||
Cap.(if x <> 0 then cap.cubcuf x buf; if y <> 0 then cap.cuucud y buf)
|
||||
end
|
||||
|
||||
type attr = A.t
|
||||
type image = I.t
|
||||
|
||||
module Infix = struct
|
||||
let ((<->), (<|>), (</>)) = I.((<->), (<|>), (</>))
|
||||
let (++) = A.(++)
|
||||
end
|
||||
966
unikernel/duniverse/dune_/vendor/notty/src/notty.mli
vendored
Normal file
966
unikernel/duniverse/dune_/vendor/notty/src/notty.mli
vendored
Normal file
|
|
@ -0,0 +1,966 @@
|
|||
(* Copyright (c) 2016-2017 David Kaloper Meršinjak. All rights reserved.
|
||||
See LICENSE.md. *)
|
||||
|
||||
(** Declaring terminals.
|
||||
|
||||
Notty is a terminal library that revolves around construction and
|
||||
composition of displayable images.
|
||||
|
||||
This module provides the core {{!I}[image]} abstraction, standalone
|
||||
{{!Render}rendering}, and escape sequence {{!Unescape}parsing}. It does not
|
||||
depend on any platform code, and does not interact with the environment.
|
||||
Input and output are provided by {!Notty_unix} and {!Notty_lwt}.
|
||||
|
||||
Consult the {{!basics}basics}, {{!examples}examples} and
|
||||
{{!limitations}limitations}.
|
||||
|
||||
{e 3.20.2 — {{:https://github.com/ocaml/dune }homepage}} *)
|
||||
|
||||
(** {1 Interface} *)
|
||||
|
||||
type attr
|
||||
(** Visual characteristics of displayed text. *)
|
||||
|
||||
type image
|
||||
(** Rectangles of styled characters. *)
|
||||
|
||||
(** [A] is for attribute.
|
||||
|
||||
Construction and composition of styling characteristics of text.
|
||||
|
||||
Consult the {{!basics}basics} for an overview. *)
|
||||
module A : sig
|
||||
|
||||
(** {1 Colors} *)
|
||||
|
||||
type color
|
||||
(** An ineffable quality of light.
|
||||
|
||||
There are three kinds of colors:
|
||||
{ul
|
||||
{- {e Core 16 colors.}
|
||||
|
||||
ANSI defines 8 color {e names}, with the actual display colors
|
||||
considered an implementation detail. Historically, this palette was
|
||||
extended with their light (sometimes {e bright} or {e high-intensity})
|
||||
counterparts. Their presentation is undefined too, but typically
|
||||
produces a brighter shade. These colors - often called the {e ANSI
|
||||
colors} - tend to be unpredictable, but ubiquitously supported.
|
||||
|
||||
}
|
||||
{- {e Extended 256-color palette.}
|
||||
|
||||
This common feature extends the palette by further 240 colors. They
|
||||
come in two groups:
|
||||
|
||||
{ul
|
||||
{- The {e color cube}, a 6*6*6 approximation to the usual 24-bit RGB
|
||||
color cube; and}
|
||||
{- the {e grayscale ramp}, containing (merely) 24 shades of gray.}}
|
||||
|
||||
XTerm was the first to support this extension. Many terminals have
|
||||
since cloned it, so the support is wide, but not universal.
|
||||
|
||||
As the extended colors are still palette-driven they do not have a
|
||||
fixed presentation, and the presentation can be changed in some
|
||||
terminals. Default palette tends to match {{:
|
||||
https://upload.wikimedia.org/wikipedia/commons/1/15/Xterm_256color_chart.svg}
|
||||
XTerm's}.
|
||||
|
||||
}
|
||||
{- {e True color}
|
||||
|
||||
A recently established convention allows directly sending 24-bit colors
|
||||
to the terminal. This has been adopted by a growing minority of
|
||||
terminals. A reasonably up-to-date status document maintained by the
|
||||
community can be found {{:https://gist.github.com/XVilka/8346728}here}.}}
|
||||
|
||||
Some of the technical and historical background can be found in {{:
|
||||
http://invisible-island.net/xterm/xterm.faq.html#problems_colors}
|
||||
XTerm's FAQ}.
|
||||
|
||||
{b Note} No attempt is made to remap colors depending on the terminal.
|
||||
Terminals might ignore, remap, or completely misinterpret unsupported
|
||||
colors. *)
|
||||
|
||||
(** {2:corecolors Core 16 colors}
|
||||
|
||||
The first 8 have their standard ANSI names. *)
|
||||
|
||||
val black : color
|
||||
val red : color
|
||||
val green : color
|
||||
val yellow : color
|
||||
val blue : color
|
||||
val magenta : color
|
||||
val cyan : color
|
||||
val white : color
|
||||
val lightblack : color
|
||||
val lightred : color
|
||||
val lightgreen : color
|
||||
val lightyellow : color
|
||||
val lightblue : color
|
||||
val lightmagenta : color
|
||||
val lightcyan : color
|
||||
val lightwhite : color
|
||||
|
||||
(** {2 Extended 256-color palette} *)
|
||||
|
||||
val rgb : r:int -> g:int -> b:int -> color
|
||||
(** [rgb ~r:red ~g:green ~b:blue] is an extended-palette color from the color cube.
|
||||
|
||||
All three channels must be in the range [0 - 5]. XTerm default palette maps
|
||||
this to [0x00], [0x5f], [0x87], [0xaf], [0xd7], and [0xff] independently
|
||||
per channel.
|
||||
|
||||
@raise Invalid_argument if a channel is outside the range. *)
|
||||
|
||||
val gray : int -> color
|
||||
(** [gray level] is an extended-palette color from the grayscale ramp.
|
||||
|
||||
[level] must be in the range [0 - 23]. XTerm default palette maps this to
|
||||
[8 + level * 10] on all three channels.
|
||||
|
||||
@raise Invalid_argument if the [level] is outside the range. *)
|
||||
|
||||
(** {2 True Color} *)
|
||||
|
||||
val rgb_888 : r:int -> g:int -> b:int -> color
|
||||
(** [rgb_888 ~r:red ~g:green ~b:blue] is a 24-bit color.
|
||||
|
||||
All three channels must be in the range [0 - 255].
|
||||
|
||||
@raise Invalid_argument if a channel is outside the range. *)
|
||||
|
||||
(** {1 Text styles} *)
|
||||
|
||||
type style
|
||||
(** Additional text properties. *)
|
||||
|
||||
val bold : style
|
||||
val dim : style
|
||||
val faint : style
|
||||
val italic : style
|
||||
val underline : style
|
||||
val blink : style
|
||||
val reverse : style
|
||||
|
||||
(** {1 Attribute construction and composition} *)
|
||||
|
||||
type t = attr
|
||||
|
||||
val equal : t -> t -> bool
|
||||
|
||||
val empty : attr
|
||||
(** [empty] is the attribute with the default foreground and background color
|
||||
and empty style set. *)
|
||||
|
||||
val (++) : attr -> attr -> attr
|
||||
(** [a1 ++ a2] is the concatenation of [a1] and [a2], the attribute that has
|
||||
[a2]'s foreground (resp. background), unless {e unset}, in which case it
|
||||
is [a1]'s, and the union of both style sets.
|
||||
|
||||
[++] is left-associative, and forms a monoid with [empty]. *)
|
||||
|
||||
val fg : color -> attr
|
||||
(** [fg c] is [empty] with foreground [c]. *)
|
||||
|
||||
val bg : color -> attr
|
||||
(** [bg c] is [empty] with background [c]. *)
|
||||
|
||||
val st : style -> attr
|
||||
(** [st s] is [empty] with style [s]. *)
|
||||
end
|
||||
|
||||
(** [I] is for image.
|
||||
|
||||
Construction and composition of images.
|
||||
|
||||
Consult the {{!basics}basics} for an overview. *)
|
||||
module I : sig
|
||||
|
||||
type t = image
|
||||
|
||||
val height : image -> int
|
||||
val width : image -> int
|
||||
|
||||
val equal : t -> t -> bool
|
||||
(** [equal t1 t2] is [true] iff [t1] and [t2] are constructed by the same term.
|
||||
|
||||
{b Note} This is a weak form of equality. Images that are not [equal]
|
||||
could still render the same. *)
|
||||
|
||||
(** {1:imgprims Primitives} *)
|
||||
|
||||
val empty : image
|
||||
(** [empty] is a zero-sized image. *)
|
||||
|
||||
val string : attr -> string -> image
|
||||
(** [string attr s] is an image containing text [s], styled with [attr].
|
||||
|
||||
@raise Invalid_argument if [string] is not a valid UTF-8 sequence, or
|
||||
contains {{!ctrls}control characters}. *)
|
||||
|
||||
val uchars : attr -> Uchar.t array -> image
|
||||
(** [uchars attr us] is an image containing text [us], styled with [attr].
|
||||
|
||||
@raise Invalid_argument if [us] contains {{!ctrls}control characters}. *)
|
||||
|
||||
val char : attr -> char -> int -> int -> image
|
||||
(** [char attr c w h] is a [w * h] grid of [c].
|
||||
|
||||
@raise Invalid_argument if [c] is a {{!ctrls}control character}. *)
|
||||
|
||||
val uchar : attr -> Uchar.t -> int -> int -> image
|
||||
(** [uchar attr u w h] is a [w * h] grid of [u].
|
||||
|
||||
@raise Invalid_argument if [u] is a {{!ctrls}control character}. *)
|
||||
|
||||
val void : int -> int -> image
|
||||
(** [void w h] is a [w * h] rectangle of transparent cells.
|
||||
|
||||
[void] is magical: it has geometry, but no displayable content. This is
|
||||
different, for example, from the space character [U+0020], which renders
|
||||
as a cell filled with the background color. This means that [void]
|
||||
interacts specially with {{!(</>)}overlays}.
|
||||
|
||||
[void 0 0 = empty].
|
||||
[void] with only one dimension [0] acts as a spacing element in the other
|
||||
dimension. Negative size is treated as [0]. *)
|
||||
|
||||
(** {1:imgcomp Image composition}
|
||||
|
||||
Three basic composition modes allow construction of more complex images
|
||||
from simpler ones.
|
||||
|
||||
Composition operators are left-associative and form a monoid with [void].
|
||||
*)
|
||||
|
||||
val (<|>) : image -> image -> image
|
||||
(** [i1 <|> i2] is the horizontal combination of [i1] and [i2].
|
||||
|
||||
[width (i1 <|> i2) = width i1 + width i2]
|
||||
[height (i1 <|> i2) = max (height i1) (height i2)]
|
||||
|
||||
Images are top-aligned. The missing region is implicitly filled with
|
||||
{{!void}[void]}.
|
||||
|
||||
{v
|
||||
[x] <|> [y] = [xy]
|
||||
[y] [.y]
|
||||
v}
|
||||
|
||||
where [.] denotes {{!void}[void]}. *)
|
||||
|
||||
val (<->) : image -> image -> image
|
||||
(** [i1 <-> i2] is the vertical combination of [i1] and [i2].
|
||||
|
||||
[width (i1 <-> i2) = max (width i1) (width i2)]
|
||||
[height (i1 <-> i2) = height i1 + height i2]
|
||||
|
||||
Images are left-aligned. The missing region is implicitly filled with
|
||||
{{!void}[void]}.
|
||||
|
||||
{v
|
||||
[xx] <-> [y] = [xx]
|
||||
[y.]
|
||||
v}
|
||||
*)
|
||||
|
||||
val (</>) : image -> image -> image
|
||||
(** [i1 </> i2] is [i1] overlaid over [i2].
|
||||
|
||||
[width (i1 </> i2) = max (width i1) (width i2)]
|
||||
[height (i1 </> i2) = max (height i1) (height i2)]
|
||||
|
||||
Images are top-left-aligned. In the region of their overlap, only the
|
||||
{{!void}[void]} cells of [i1] show fragments of [i2].
|
||||
|
||||
{v
|
||||
[x.x] </> [yyyy] = [xyxy]
|
||||
v}
|
||||
*)
|
||||
|
||||
(** {1:imgcrop Cropping and padding} *)
|
||||
|
||||
val hcrop : int -> int -> image -> image
|
||||
(** [hcrop left right i] is [i] with [left] leftmost, and [right]
|
||||
rightmost columns missing. If [left + right >= width i] the result is
|
||||
[empty].
|
||||
|
||||
If either [left] or [right] is negative, instead of being cropped, the
|
||||
image is padded on that side.
|
||||
|
||||
For example:
|
||||
{ul
|
||||
{- [hcrop 0 1 [abc]] = [[ab]]}
|
||||
{- [hcrop 1 1 [abc]] = [[b]]}
|
||||
{- [hcrop (-1) 1 [abc]] = [void 1 1 <|> hcrop 0 1 [abc]] = [[.ab]]}
|
||||
{- [hcrop 2 2 [abc]] = [empty]}} *)
|
||||
|
||||
val vcrop : int -> int -> image -> image
|
||||
(** [vcrop top bottom i] is the vertical analogue to {{!hcrop}[hcrop]}. *)
|
||||
|
||||
val crop : ?l:int -> ?r:int -> ?t:int -> ?b:int -> image -> image
|
||||
(** [crop ~l:left ~r:right ~t:top ~b:bottom i] is
|
||||
[vcrop left right (hcrop top bottom) i].
|
||||
|
||||
Missing arguments default to [0]. *)
|
||||
|
||||
val hpad : int -> int -> image -> image
|
||||
(** {{!hcrop}[hcrop]} with margins negated. *)
|
||||
|
||||
val vpad : int -> int -> image -> image
|
||||
(** {{!vcrop}[vcrop]} with margins negated. *)
|
||||
|
||||
val pad : ?l:int -> ?r:int -> ?t:int -> ?b:int -> image -> image
|
||||
(** {{!crop}[crop]} with margins negated. *)
|
||||
|
||||
|
||||
(** {1 Additional combinators} *)
|
||||
|
||||
val hcat : image list -> image
|
||||
(** [hcat xs] horizontally concatenates [xs]. See {{!(<|>)}beside}. *)
|
||||
|
||||
val vcat : image list -> image
|
||||
(** [vcat xs] vertically concatenates [xs]. See {{!(<->)}above}. *)
|
||||
|
||||
val zcat : image list -> image
|
||||
(** [zcat xs] overlays [xs]. See {{!(</>)}over}. *)
|
||||
|
||||
val tabulate : int -> int -> (int -> int -> image) -> image
|
||||
(** [tabulate m n f] is the grid of values [f x y] with [x = 0..m-1]
|
||||
and [y = 0..n-1], where [x] grows to the right, and [y] growns down.
|
||||
|
||||
[f a y] is to the left of [f b y] if [a < b], and [f x a] is above [f x b]
|
||||
if [a < b], but the exact alignment is unspecified if the various [f x y]
|
||||
have different dimensions. *)
|
||||
|
||||
val hsnap : ?align:[ `Left | `Middle | `Right ] -> int -> image -> image
|
||||
(** [hsnap ~align w i] is an image of width strictly [w] obtained by either
|
||||
horizontally padding or cropping [i] and positioning it according to
|
||||
[~align].
|
||||
|
||||
[~align] defaults to [`Middle]. *)
|
||||
|
||||
val vsnap : ?align:[ `Top | `Middle | `Bottom ] -> int -> image -> image
|
||||
(** [vsnap ~align h i] is an image of height strictly [h] obtained by either
|
||||
vertically padding or cropping [i] and positioning it according to
|
||||
[~align].
|
||||
|
||||
[~align] defaults to [`Middle]. *)
|
||||
|
||||
(** {1 [Format] interoperability} *)
|
||||
|
||||
val strf : ?attr:attr -> ?w:int -> ('a, Format.formatter, unit, image) format4 -> 'a
|
||||
(** [strf ?attr ?w:width format ...] pretty-prints like
|
||||
[Format.asprintf format ...], but returns an [image].
|
||||
|
||||
[attr] is the (outermost) attribute. Defaults to {!A.empty}.
|
||||
|
||||
[width] is used to set the margin on the formatter. This is only a hint,
|
||||
and does not guarantee the width of the result. Consult
|
||||
{{: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Format.html#VALset_margin}
|
||||
[Format.set_margin]} for details. Defaults to an unspecified, large
|
||||
number.
|
||||
|
||||
@raise Invalid_argument if the printing process attempts to directly
|
||||
output {{!ctrls}control characters}, by embedding them in [format] or a
|
||||
string printed with the [%s] conversion, for example.
|
||||
{{: http://caml.inria.fr/pub/docs/manual-ocaml/libref/Format.html#fpp}
|
||||
Formatted printing} is allowed. *)
|
||||
|
||||
val kstrf : ?attr:attr -> ?w:int -> (image -> 'a) -> ('b, Format.formatter, unit, 'a) format4 -> 'b
|
||||
(** [kstrf ?attr ?w k format ...] is continuation-based [strf ?attr ?w format ...]. *)
|
||||
|
||||
val pp_attr : attr -> (Format.formatter -> 'a -> unit) -> Format.formatter -> 'a -> unit
|
||||
(** [pp_attr a f] is a pretty-printer like [f], except its output is styled
|
||||
with [a]. This applies only outside of any styling [f] itself might embed. *)
|
||||
end
|
||||
|
||||
(** Operators, repeated. *)
|
||||
module Infix : sig
|
||||
|
||||
(** {2 [I]}
|
||||
|
||||
See {{!I}[I]}. *)
|
||||
|
||||
val (<->) : image -> image -> image
|
||||
val (<|>) : image -> image -> image
|
||||
val (</>) : image -> image -> image
|
||||
|
||||
(** {2 [A]}
|
||||
|
||||
See {{!A}[A]}. *)
|
||||
|
||||
val (++) : attr -> attr -> attr
|
||||
end
|
||||
|
||||
(** {1 Low-level interface}
|
||||
|
||||
You can ignore it, unless you are porting [Notty] to a new platform not
|
||||
supported by the existing IO backends. *)
|
||||
|
||||
(** Terminal capabilities.
|
||||
|
||||
This module describes how to output things so that a terminal understands
|
||||
them. *)
|
||||
module Cap : sig
|
||||
|
||||
type t
|
||||
(** A set of capabilities that distinguish terminals from one another.
|
||||
|
||||
A bundle of magic strings, really. *)
|
||||
|
||||
val ansi : t
|
||||
(** The usual ANSI terminal, with colors, text styles and cursor
|
||||
positioning. *)
|
||||
|
||||
val dumb : t
|
||||
(** Pure text output. Text attributes are stripped and positioning is done
|
||||
with the character [U+0020], SPACE. *)
|
||||
end
|
||||
|
||||
(** Dump images to string buffers. *)
|
||||
module Render : sig
|
||||
|
||||
val to_buffer : Buffer.t -> Cap.t -> int * int -> int * int -> image -> unit
|
||||
(** [to_buffer buf cap (x, y) (w, h) i] writes the string representation of
|
||||
[i] to [buf], as interpreted by [cap].
|
||||
|
||||
It renders the [w * h] rectangle of [i], offset by [(x, y)] from the top
|
||||
left. *)
|
||||
|
||||
val pp : Cap.t -> Format.formatter -> image -> unit
|
||||
(** [pp cap ppf i] renders [i] to the pretty-printer [ppf].
|
||||
|
||||
{b Note} [pp] is generally meant for development and debugging. It tries
|
||||
to be reasonable, but dedicated IO modules handle the actual output
|
||||
better. *)
|
||||
|
||||
(**/**)
|
||||
(* Toplevel. *)
|
||||
val pp_image : Format.formatter -> image -> unit
|
||||
val pp_attr : Format.formatter -> attr -> unit
|
||||
(**/**)
|
||||
end
|
||||
|
||||
(** Parse and decode escape sequences in character streams. *)
|
||||
module Unescape : sig
|
||||
|
||||
(** {1 Input events} *)
|
||||
|
||||
type special = [
|
||||
`Escape
|
||||
| `Enter
|
||||
| `Tab
|
||||
| `Backspace
|
||||
| `Insert
|
||||
| `Delete
|
||||
| `Home | `End
|
||||
| `Arrow of [ `Up | `Down | `Left | `Right ]
|
||||
| `Page of [ `Up | `Down ]
|
||||
| `Function of int
|
||||
]
|
||||
(** A selection of extra keys on the keyboard. *)
|
||||
|
||||
type button = [ `Left | `Middle | `Right | `Scroll of [ `Up | `Down ] ]
|
||||
(** Mouse buttons. *)
|
||||
|
||||
type mods = [ `Meta | `Ctrl | `Shift ] list
|
||||
(** Modifier state. *)
|
||||
|
||||
type key = [ special | `Uchar of Uchar.t | `ASCII of char ] * mods
|
||||
(** Keypress event. *)
|
||||
|
||||
type mouse = [ `Press of button | `Drag | `Release ] * (int * int) * mods
|
||||
(** Mouse event. *)
|
||||
|
||||
type paste = [ `Start | `End ]
|
||||
(** Paste event. *)
|
||||
|
||||
type event = [ `Key of key | `Mouse of mouse | `Paste of paste ]
|
||||
(** Things that terminals say to applications.
|
||||
|
||||
{ul
|
||||
{- [`Key (k, mods)] is keyboard input.
|
||||
|
||||
[k] is a {{!key}key}, one of:
|
||||
{ul
|
||||
{- [`ASCII c] where [c] is a [char] in the
|
||||
{{: https://tools.ietf.org/html/rfc20}ASCII} range;}
|
||||
{- [`Uchar u] where [u] is any other {{!Uchar.t}unicode character}; or}
|
||||
{- a {{!special}special key}.}}
|
||||
|
||||
[`ASCII] and [`Uchar] together represent the textual part of the input.
|
||||
These characters are guaranteed not to be {{!ctrls}control
|
||||
characters}, and are safe to use when constructing images. ASCII is
|
||||
separated from the rest of Unicode for convenient pattern-matching.
|
||||
|
||||
[mods] are the extra {{!mods}modifier keys}.
|
||||
|
||||
}
|
||||
{- [`Mouse (event, (x, y), mods)] is mouse input.
|
||||
|
||||
[event] is the actual mouse event: {{!button}[button]} press, release,
|
||||
or motion of the mouse with buttons depressed.
|
||||
|
||||
[(x, y)] are column and row position of the mouse. The origin is
|
||||
[(0,0)], the upper-left corner.
|
||||
|
||||
{b Note} Every [`Press (`Left|`Middle|`Right)] generates a corresponding
|
||||
[`Release], but there is no portable way to detect which button was
|
||||
released. [`Scroll (`Up|`Down)] presses are not followed by releases.
|
||||
|
||||
}
|
||||
{- [`Paste (`Start|`End)] are {e bracketed paste} events, signalling the
|
||||
beginning and end of a sequence of events pasted into the terminal.
|
||||
|
||||
{b Note} This mechanism is useful, but not reliable. The pasted text
|
||||
could contain spurious start-of-paste or end-of-paste markers, or they
|
||||
could be entered by hand. }}
|
||||
|
||||
Terminal input protocols are historical cruft, and heavily overload the
|
||||
ASCII range. For instance:
|
||||
{ul
|
||||
{- It is impossible to distinguish lower- and upper-case ASCII characters
|
||||
if {b Ctrl} is pressed;}
|
||||
{- several combinations of key-presses are aliased as special keys; and}
|
||||
{- in a UTF-8 encoded stream, there is no representation for non-ASCII
|
||||
characters with modifier keys.}}
|
||||
|
||||
This means that many values that inhabit the [event] type are impossible,
|
||||
while some reflect multiple different user actions. Limitations include:
|
||||
|
||||
{ul
|
||||
{- [`Shift] is reported only with special keys, and not all of them.}
|
||||
{- [`Meta] and [`Control] are reported with mouse events, key events with
|
||||
special keys, and key events with values in the ranges [0x40-0x5f]
|
||||
([@] to [_]) and [0x60-0x7e] ([`] to [~]). If {b Ctrl} is pressed, the higher
|
||||
range is mapped into the lower range.}
|
||||
{- Terminals will variously under-report modifier key state.}}
|
||||
|
||||
Perform own experiments before relying on elaborate key combinations. *)
|
||||
|
||||
val uchar : [< `Uchar of Uchar.t | `ASCII of char ] -> Uchar.t
|
||||
(** [uchar x] is the {!Uchar.t} corresponding to [x]. This operations merges
|
||||
the ASCII and Unicode variants of {{!key}key}. *)
|
||||
|
||||
(** {1 Decoding filter}
|
||||
|
||||
Simple IO-less terminal input processor. It can be used for building
|
||||
custom terminal input abstractions. *)
|
||||
|
||||
type t
|
||||
(** Input decoding filter.
|
||||
|
||||
The filter should be {{!input}fed} strings, which it first decodes from
|
||||
UTF-8, and then extracts the input events.
|
||||
|
||||
Malformed UTF-8 input bytes and unrecognized escape sequences are silently
|
||||
discarded. *)
|
||||
|
||||
val create : unit -> t
|
||||
(** [create ()] is a new, empty filter. *)
|
||||
|
||||
val input : t -> bytes -> int -> int -> unit
|
||||
(** [input t buffer i len] feeds [len] bytes of [string] into [t], starting
|
||||
from position [len].
|
||||
|
||||
[len = 0] signals the end of input.
|
||||
|
||||
[buffer] is immediately processed and can be reused after the call
|
||||
returns. *)
|
||||
|
||||
val next : t -> [ event | `Await | `End ]
|
||||
(** [next t] is the next event in the filter's input stream:
|
||||
|
||||
{ul
|
||||
{- [#event], an input {{!event}[event]}.}
|
||||
{- [`Await] if the filter needs more {{!input}input}.}
|
||||
{- [`End] if the input had ended.}} *)
|
||||
|
||||
val pending : t -> bool
|
||||
(** [pending t] is [true] if a call to [next], without any intervening input,
|
||||
would {e not} return [`Await]. *)
|
||||
|
||||
(** {1 Low-level parsing}
|
||||
|
||||
{b Warning} The parsing interface is subject to change.
|
||||
|
||||
Implementation of small parts of
|
||||
{{: http://www.ecma-international.org/publications/standards/Ecma-035.htm}ECMA-35}
|
||||
and
|
||||
{{: http://www.ecma-international.org/publications/standards/Ecma-048.htm}ECMA-48},
|
||||
as needed by terminal emulators in common use. *)
|
||||
|
||||
val decode : Uchar.t list -> event list
|
||||
(** [decode us] are the events encoded by [us].
|
||||
|
||||
[us] are assumed to have been generated in a burst, and the end of the
|
||||
list is taken to mean a pause.
|
||||
Therefore, [decode us1 @ decode us2 <> decode (us1 @ us2)] if [us1] ends
|
||||
with a partial escape sequence, including a lone [\x1b].
|
||||
|
||||
Unsupported escape sequences are silently discarded. *)
|
||||
end
|
||||
|
||||
(**/**)
|
||||
(** {1 Private}
|
||||
|
||||
These are private interfaces, prone to breakage. Don't use them. *)
|
||||
|
||||
module Operation : sig
|
||||
type t
|
||||
val of_image : (int * int) -> int * int -> image -> t list
|
||||
end
|
||||
|
||||
module Tmachine : sig
|
||||
|
||||
type t
|
||||
|
||||
val create : mouse:bool -> bpaste:bool -> Cap.t -> t
|
||||
val release : t -> bool
|
||||
val output : t -> Buffer.t -> unit
|
||||
|
||||
val refresh : t -> unit
|
||||
val cursor : t -> (int * int) option -> unit
|
||||
val image : t -> image -> unit
|
||||
|
||||
val set_size : t -> int * int -> unit
|
||||
|
||||
val size : t -> int * int
|
||||
val dead : t -> bool
|
||||
end
|
||||
|
||||
module Direct : sig
|
||||
val move_cursor : Buffer.t -> Cap.t -> [ `Home | `By of int * int | `To of int * int ] -> unit
|
||||
val show_cursor : Buffer.t -> Cap.t -> bool -> unit
|
||||
end
|
||||
(**/**)
|
||||
|
||||
(** {1:basics Basics}
|
||||
|
||||
Print a red-on-black ["Wow!"] above its right-shifted copy:
|
||||
{[
|
||||
let wow = I.string A.(fg red ++ bg black) "Wow!" in
|
||||
I.(wow <-> (void 2 0 <|> wow)) |> Notty_unix.output_image
|
||||
]}
|
||||
|
||||
{2:meaning The meaning of images}
|
||||
|
||||
An {{!image}[image]} value is a rectangle of styled character cells. It has a
|
||||
width and height, but is not anchored to an origin. A single character with
|
||||
associated display attributes, or a short fragment of text, are simple
|
||||
examples of images.
|
||||
|
||||
Images are created by combining text fragments with {{!attributes}display
|
||||
attributes}, and composed by placing them {{!I.(<|>)}beside} each other,
|
||||
{{!I.(<->)}above} each other, and {{!I.(</>)}over} each other.
|
||||
|
||||
Once constructed, an image can be rendered, and only at that point it obtains
|
||||
absolute placement.
|
||||
|
||||
Consult {{!I}[I]} for more details.
|
||||
|
||||
{2:attributes Display attributes}
|
||||
|
||||
{{!attr}[attr]} values describe the styling characteristics of fragments of
|
||||
text.
|
||||
|
||||
They combine a foreground and a background {{!A.color}[color]} with a
|
||||
set of {{!A.style}[styles]}. Either color can be {e unset}, which corresponds to
|
||||
the terminal's default foreground (resp. background) color.
|
||||
|
||||
Attributes are used to construct primitive images.
|
||||
|
||||
Consult {{!A}[A]} for more details.
|
||||
|
||||
{2:ctrls Control characters}
|
||||
|
||||
These are taken to be characters in the ranges [0x00-0x1f] ({b C0}), [0x7f]
|
||||
(BACKSPACE), [0x80-0x9f] ({b C1}). This is the
|
||||
{{: http://unicode.org/reports/tr44/#General_Category_Values}Unicode
|
||||
general category} {b Cc}.
|
||||
|
||||
As control characters directly influence the cursor positioning, they
|
||||
cannot be used to create images.
|
||||
|
||||
This, in particular, means that images cannot contain [U+000a] (NEWLINE).
|
||||
|
||||
{1:limitations Limitations}
|
||||
|
||||
[Notty] does not use Terminfo. If your terminal is particularly
|
||||
idiosyncratic, things might fail to work. Get in touch with the author to
|
||||
expand support.
|
||||
|
||||
[Notty] assumes that the terminal is using UTF-8 for input and output.
|
||||
Things might break arbitrarily if this is not the case.
|
||||
|
||||
For performance considerations, consult the {{!perf}performance model}.
|
||||
|
||||
{2:cwidth Unicode vs. Text geometry}
|
||||
|
||||
[Notty] uses [Uucp.Break.tty_width_hint] to guess the width of text
|
||||
fragments when computing geometry, and it suffers from the same
|
||||
shortcomings:
|
||||
|
||||
{ul
|
||||
{- Geometry in general works for alphabets and east Asian scripts, mostly
|
||||
works for abjad scripts, and is a matter of luck for abugidas.}
|
||||
{- East Asian scripts work better when in
|
||||
{{:http://unicode.org/glossary/#normalization_form_c}NFC}.}
|
||||
{- For proper emoji display, [Uucp] and the terminal have to agree on the
|
||||
Unicode version.}}
|
||||
|
||||
When in doubt, see
|
||||
{{: http://erratique.ch/software/uucp/doc/Uucp.Break.html#VALtty_width_hint}
|
||||
[Uucp.Break.tty_width_hint]}.
|
||||
|
||||
Unicode has special interaction with {{!I.hcrop}horizontal cropping}:
|
||||
{ul
|
||||
{- Strings within images are cropped at {{:
|
||||
http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundaries}grapheme
|
||||
cluster} boundaries. This means that scalar value sequences that are
|
||||
rendered combined, or overlaid, stay unbroken.}
|
||||
{- When a crop splits a wide character in two, the remaining half is
|
||||
replaced by [U+0020] (SPACE). Hence, character-cell-accurate cropping is
|
||||
possible even in the presence of characters that horizontally occupy
|
||||
more than one cell.}}
|
||||
|
||||
{1:examples Examples}
|
||||
|
||||
We assume a toplevel with [Notty] support ([#require "notty.top"]).
|
||||
|
||||
{2 Hello}
|
||||
|
||||
["Rad!"] with default foreground and background:
|
||||
|
||||
{[I.string A.empty "Rad!"]}
|
||||
|
||||
Everything has to start somewhere.
|
||||
|
||||
{2 Colors}
|
||||
|
||||
["Rad!"] in rad letters:
|
||||
|
||||
{[I.string A.(fg lightred) "Rad!"]}
|
||||
|
||||
{2 Padding and spacing}
|
||||
|
||||
{[
|
||||
let a1 = A.(fg lightwhite ++ bg red)
|
||||
and a2 = A.(fg red)
|
||||
]}
|
||||
|
||||
["Rad"] and [" stuff!"] in different colors:
|
||||
|
||||
{[I.(string a1 "Rad" <|> string a2 " stuff!")]}
|
||||
|
||||
The second word hanging on a line below:
|
||||
|
||||
{[I.(string a1 "Rad" <|> (string a2 "stuff!" |> vpad 1 0))]}
|
||||
|
||||
{2 More geometry}
|
||||
|
||||
Sierpinski triangle:
|
||||
|
||||
{[
|
||||
let square = "\xe2\x96\xaa"
|
||||
|
||||
let rec sierp n =
|
||||
if n > 1 then
|
||||
let ss = sierp (pred n) in I.(ss <-> (ss <|> ss))
|
||||
else I.(string A.(fg magenta) square |> hpad 1 0)
|
||||
]}
|
||||
|
||||
{[sierp 8]}
|
||||
|
||||
A triangle overlaid over its shifted copy:
|
||||
|
||||
{[let s = sierp 6 in I.(s </> vpad 1 0 s)]}
|
||||
|
||||
Blinkenlights:
|
||||
|
||||
{[
|
||||
let rad n color =
|
||||
let a1 = A.fg color in
|
||||
let a2 = A.(st blink ++ a1) in
|
||||
I.((string a2 "Rad" |> hpad n 0) <->
|
||||
(string a1 "(⌐■_■)" |> hpad (n + 7) 0))
|
||||
|
||||
let colors = A.[red; green; yellow; blue; magenta; cyan]
|
||||
]}
|
||||
|
||||
{[
|
||||
colors |> List.mapi I.(fun i c -> rad i c |> pad ~t:i ~l:(2 * i))
|
||||
|> I.zcat
|
||||
]}
|
||||
|
||||
{b Note} Usage of {{!A.blink}[blink]} might be regulated by law in some
|
||||
jurisdictions.
|
||||
|
||||
{2 Pretty-printing}
|
||||
|
||||
Images can be pretty-printed into:
|
||||
|
||||
{[I.strf "(%d)" 42]}
|
||||
|
||||
Attributes can be applied to the entire format string, or by decorating
|
||||
{e user-defined printers} that are supplied with [%a] conversions:
|
||||
|
||||
{[let pp = Format.pp_print_int]}
|
||||
|
||||
{[I.strf ~attr:A.(fg lightwhite) "(%a)" (I.pp_attr A.(fg green) pp) 42]}
|
||||
|
||||
{2 Now with output}
|
||||
|
||||
The core module has no real IO. Examples above are simple [image]-valued
|
||||
expressions, displayed by the pretty-printer that is installed by the
|
||||
toplevel support. Self-contained programs need a separate IO module:
|
||||
|
||||
{[#require "notty.unix"]}
|
||||
|
||||
{[sierp 8 |> Notty_unix.output_image]}
|
||||
|
||||
(Note the difference in cropping behavior.)
|
||||
|
||||
Computations can be adapted to the current terminal size. A line can stretch
|
||||
end-to-end:
|
||||
|
||||
{[
|
||||
Notty_unix.output_image_size @@ fun (w, _) ->
|
||||
let i1 = I.string A.(fg green) "very"
|
||||
and i2 = I.string A.(fg yellow) "melon" in
|
||||
I.(i1 <|> void (w - width i1 - width i2) 1 <|> i2)
|
||||
]}
|
||||
|
||||
The largest triangle that horizontally fits into the terminal:
|
||||
|
||||
{[
|
||||
Notty_unix.output_image_size @@ fun (w, _) ->
|
||||
let steps = int_of_float ((log (float w)) /. log 2.) in
|
||||
sierp steps |> I.vpad 0 1
|
||||
]}
|
||||
|
||||
{2 Simple interaction}
|
||||
|
||||
Interactive Sierpinski:
|
||||
|
||||
{[open Notty_unix]}
|
||||
|
||||
{[
|
||||
let img (double, n) =
|
||||
let s = sierp n in
|
||||
if double then I.(s </> vpad 1 0 s) else s
|
||||
in
|
||||
let rec update t state = Term.image t (img state); loop t state
|
||||
and loop t (double, n as state) =
|
||||
match Term.event t with
|
||||
| `Key (`Enter,_) -> ()
|
||||
| `Key (`Arrow `Left,_) -> update t (double, max 1 (n - 1))
|
||||
| `Key (`Arrow `Right,_) -> update t (double, min 8 (n + 1))
|
||||
| `Key (`ASCII ' ', _) -> update t (not double, n)
|
||||
| `Resize _ -> update t state
|
||||
| _ -> loop t state
|
||||
in
|
||||
let t = Term.create ()
|
||||
in
|
||||
update t (false, 1); Term.release t
|
||||
]}
|
||||
|
||||
The program uses a fullscreen {{!Notty_unix.Term}terminal} and loops reading
|
||||
the {{!Notty_unix.Term.event}input}. LEFT and RIGHT control the iteration
|
||||
count, and SPACE toggles double-drawing. Resizing the window causes a
|
||||
redraw. When the loop exits on ENTER, the terminal is
|
||||
{{!Notty_unix.Term.release}cleaned up}.
|
||||
|
||||
{1:perf Performance model}
|
||||
|
||||
This section is only relevant if using [Notty] becomes your bottleneck.
|
||||
|
||||
{b TL;DR} Shared sub-expressions do not share work, so operators stick with
|
||||
you.
|
||||
|
||||
The main performance parameter is {e image complexity}. This roughly
|
||||
corresponds to the number of image {{!I.imgcomp}composition} and
|
||||
{{!I.imgcrop}cropping} operators in the fully expanded [image] term,
|
||||
{b ignoring all sharing}.
|
||||
|
||||
Outline numbers:
|
||||
|
||||
{ul
|
||||
{- Highly complex images can be rendered and pushed out to a full-screen
|
||||
terminal more than 1000 times per second.}
|
||||
{- With more realistic images, this number is closer to 30,000.}
|
||||
{- Input processing is somewhere around 50MB/s.}}
|
||||
|
||||
|
||||
Image complexity [cplx] of an image [i] is:
|
||||
{ul
|
||||
{- For a {{!I.imgprims}primitive} [i], [cplx i = 1].}
|
||||
{- For a {{!I.imgcomp}composition} operator [op],
|
||||
[cplx (op i1 i2) = 1 + cplx i1 + cplx i2].}
|
||||
{- For a {{!I.imgcomp}crop} [cr],
|
||||
[cplx (cr i1) = 1 + cplx i1 - k], where [k] is the combined complexity of
|
||||
all the {e maximal} sub-terms that do not contribute to the output.}}
|
||||
|
||||
For example (assuming an image [i]):
|
||||
|
||||
{[
|
||||
let img1 = I.((i <|> i) <-> (i <|> i))
|
||||
let img2 = I.(let x = i <|> i in x <-> x)
|
||||
let img3 = I.(((i <|> i) <|> i) <|> i)
|
||||
]}
|
||||
|
||||
Complexity of each of these is [4 * cplx i + 3]. This might be surprising
|
||||
for [img2].
|
||||
|
||||
If [width i = 1], [cplx (hcrop 1 0 img1) = 3 + 2 * cplx i], and
|
||||
[cplx (hcrop 2 0 img3) = 2 + 2 * cplx i].
|
||||
|
||||
While [Notty] strives to be accommodating to all usage scenarios, these are
|
||||
the things to keep in mind if the rendering becomes slow:
|
||||
|
||||
{ol
|
||||
{- Image composition is cheap.
|
||||
|
||||
Combining images performs a negligible amount of computation.
|
||||
|
||||
Constructing primitive images that contain scalar values outside of the
|
||||
ASCII range does a little more work upfront and is worth holding onto.
|
||||
|
||||
}
|
||||
{- {{!Render}Rendering} depends on image complexity.
|
||||
|
||||
As a consequence, this real-world example of wrapping renders in time
|
||||
O(n{^ 2}) in the number of lines:
|
||||
|
||||
{[
|
||||
let wrap1 width img =
|
||||
let rec go img = img ::
|
||||
if I.width img > width then go (I.hcrop width 0 img) else []
|
||||
in go img |> I.vcat |> I.hsnap ~align:`Left width
|
||||
]}
|
||||
|
||||
Although [crop] is applied only [lines] times, the image complexity of
|
||||
each line depends on the number of preceding lines.
|
||||
|
||||
An O(n) version does not iterate [crop]:
|
||||
|
||||
{[
|
||||
let wrap2 width img =
|
||||
let rec go off = I.hcrop off 0 img ::
|
||||
if I.width img - off > width then go (off + width) else []
|
||||
in go 0 |> I.vcat |> I.hsnap ~align:`Left width
|
||||
]}
|
||||
}
|
||||
{- Rendering depends on the {e output} dimensions, but not on the {e image}
|
||||
dimensions.
|
||||
|
||||
Rendering an image to [w * h] implicitly crops it to its leftmost [w]
|
||||
columns and topmost [h] rows. While [w] and [h] will have an impact on
|
||||
the rendering performance, the complexity of the (cropped) image tends to
|
||||
be more important.}}
|
||||
|
||||
*)
|
||||
Loading…
Add table
Add a link
Reference in a new issue