From 8d568855b305580591263114cc356726f393e4bf Mon Sep 17 00:00:00 2001 From: Akshay Date: Sun, 8 Aug 2021 10:16:39 +0530 Subject: init --- .gitignore | 2 + dune-project | 1 + flake.lock | 41 ++++++++++++++++++ flake.nix | 27 ++++++++++++ grump.opam | 0 src/chart.ml | 135 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/dune | 3 ++ src/grump.ml | 1 + 8 files changed, 210 insertions(+) create mode 100644 .gitignore create mode 100644 dune-project create mode 100644 flake.lock create mode 100644 flake.nix create mode 100644 grump.opam create mode 100644 src/chart.ml create mode 100644 src/dune create mode 100644 src/grump.ml diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..06c9926 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +_build +result diff --git a/dune-project b/dune-project new file mode 100644 index 0000000..c994249 --- /dev/null +++ b/dune-project @@ -0,0 +1 @@ +(lang dune 2.9) diff --git a/flake.lock b/flake.lock new file mode 100644 index 0000000..08aa38a --- /dev/null +++ b/flake.lock @@ -0,0 +1,41 @@ +{ + "nodes": { + "nixpkgs": { + "locked": { + "lastModified": 1626855004, + "narHash": "sha256-wm0wLIZkbr92iu10N7hHttrLIX58tQxIUCeQxPxA10o=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "621afb9980bc06ed695b0e3d62109a7dbd00e3da", + "type": "github" + }, + "original": { + "id": "nixpkgs", + "type": "indirect" + } + }, + "root": { + "inputs": { + "nixpkgs": "nixpkgs", + "utils": "utils" + } + }, + "utils": { + "locked": { + "lastModified": 1623875721, + "narHash": "sha256-A8BU7bjS5GirpAUv4QA+QnJ4CceLHkcXdRp4xITDB0s=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "f7e004a55b120c02ecb6219596820fcd32ca8772", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + } + }, + "root": "root", + "version": 7 +} diff --git a/flake.nix b/flake.nix new file mode 100644 index 0000000..4c483e6 --- /dev/null +++ b/flake.nix @@ -0,0 +1,27 @@ +{ + inputs = { + utils.url = "github:numtide/flake-utils"; + }; + + outputs = { self, nixpkgs, utils, ... }: + utils.lib.eachDefaultSystem (system: + let + pname = "grump"; + version = "0.0.0"; + pkgs = nixpkgs.legacyPackages."${system}"; + + buildInputs = with pkgs.ocamlPackages; [ + utop + pkgs.nixUnstable + ]; + + in + with pkgs; + rec { + defaultPackage = ocamlPackages.buildDunePackage rec { + inherit pname version buildInputs; + useDune2 = true; + src = ./.; + }; + }); +} diff --git a/grump.opam b/grump.opam new file mode 100644 index 0000000..e69de29 diff --git a/src/chart.ml b/src/chart.ml new file mode 100644 index 0000000..0aee05d --- /dev/null +++ b/src/chart.ml @@ -0,0 +1,135 @@ +exception Empty_list +let fold fn = function + | [] -> raise Empty_list + | head :: tail -> List.fold_left fn head tail + +let list_min ls = fold Stdlib.min ls +let list_max ls = fold Stdlib.max ls + +let rec repeat n a = + if n <= 0 + then [] + else a :: repeat (n - 1) a + +let empty ls = (ls = []) + +let rec zip l1 l2 = + match (l1, l2) with + | ([], _) -> [] + | (_, []) -> [] + | (h1 :: t1, h2 :: t2) -> (h1, h2) :: zip t1 t2 + +let rec transpose = function + | [] :: _ -> [] + | ls -> List.(map hd ls) :: transpose List.(map tl ls) + +let flip f a b = f b a + +let rot_right ls = List.(rev ls |> transpose) +let rot_left ls = List.(transpose ls |> rev) + +let to_string c = String.make 1 c +let space = to_string ' ' + +let saturating_sub b a = + if a < b then 0 + else a - b + +module type Marker = sig + type t + val of_string : string -> t + val to_string : t -> string +end + +module Marker = struct + type t = Point + | Pixel + | Circle + | TriangleDown + | TriangleUp + | TriangleLeft + | TriangleRight + | Custom of string + + exception Invalid_marker_length + let of_string s = + if String.length s <> 1 + then raise Invalid_marker_length + else Custom(s) + + let to_string = function + | Point -> "." + | Pixel -> "," + | Circle -> "o" + | TriangleDown -> "v" + | TriangleUp -> "^" + | TriangleLeft -> ">" + | TriangleRight -> "<" + | Custom(s) -> s +end + +module type ChartOptions = sig + type t + val default : t + val with_height : int -> t -> t + val with_marker : string -> t -> t +end + +module ChartOptions = struct + type t = { height: int; ascii: bool; marker: Marker.t} + let default = + { height = 14 + ; ascii = false + ; marker = Marker.Point + } + let with_height v c = {c with height = v; } + let with_marker v c = {c with marker = v; } +end + +module Chart = struct + let draw vals (opts: ChartOptions.t) = + let height = opts.height in + (* let width = List.length vals in *) + let min_val = list_min vals in + let max_val = list_max vals in + (*let range = max_val - min_val in*) + + (* rescale from min-max to 0-height *) + let scale v = ((v - min_val) * height) / max_val in + let new_vals = List.map scale vals in + let rec pad left right s = + if left = 0 + then s :: repeat right space + else space :: pad (left - 1) right s + in + let new_vals' = zip new_vals (List.tl new_vals) in + let make_connector s e = + match Stdlib.compare s e with + | 0 -> pad s (height - s - 1) "-" + | x -> + let (ltr_chr, rtl_chr) = + match x with + | 1 -> ("└", "┐") + | _ -> ("┘", "┌") + in + let (st, en) = Stdlib.((min s e, max s e)) in + let l = en - st |> saturating_sub 1 in + let (left, right) = (repeat st space, repeat (height - l - st - 1) space) + in + List.flatten [left; [ltr_chr]; repeat l "│"; [rtl_chr]; right] + in + let m = Marker.to_string opts.marker in + let rec make_graph = function + | [] -> [] + | (s, e) :: [] -> + pad s (height - s - 1) m + :: make_connector s e + :: pad e (height - e - 1) m + :: [] + | (s, e) :: tl -> + pad s (height - s - 1) m + :: make_connector s e + :: make_graph tl + in + make_graph new_vals' |> rot_left +end diff --git a/src/dune b/src/dune new file mode 100644 index 0000000..6b1e6d9 --- /dev/null +++ b/src/dune @@ -0,0 +1,3 @@ +(library + (name grump) + (public_name grump)) diff --git a/src/grump.ml b/src/grump.ml new file mode 100644 index 0000000..b4b1288 --- /dev/null +++ b/src/grump.ml @@ -0,0 +1 @@ +print_endline "hello world!" -- cgit v1.2.3