diff --git a/src/core/editor/Ctx.re b/src/core/editor/Ctx.re index 5506845f..04fead1a 100644 --- a/src/core/editor/Ctx.re +++ b/src/core/editor/Ctx.re @@ -167,6 +167,17 @@ let push_zigg = (~onto as d: Dir.t, zigg: Zigg.t, ~fill=Cell.empty, ctx: t) => { map_hd(Frame.Open.cat(rest), ctx); }; +let trim_space = (~side: Dir.t, ctx: t) => + switch (pull(~from=side, ctx)) { + | (Node(tok), ctx) when Mtrl.is_space(tok.mtrl) => + let tok = + Strings.chop_prefix(~prefix=" ", tok.text) + |> Option.map(text => {...tok, text}) + |> Option.value(~default=tok); + Token.is_empty(tok) ? ctx : push(~onto=side, tok, ctx); + | _ => ctx + }; + let zip_toks = (~save_cursor=false, ctx: t): option((Meld.t, t)) => { let (hd, tl) = uncons(ctx); Frame.Open.zip_toks(~save_cursor, hd) diff --git a/src/core/editor/Modify.re b/src/core/editor/Modify.re index 094739d0..47d418a7 100644 --- a/src/core/editor/Modify.re +++ b/src/core/editor/Modify.re @@ -295,6 +295,7 @@ let expand = (tok: Token.t) => let try_expand = (s: string, z: Zipper.t): option(Zipper.t) => { open Options.Syntax; let* () = Options.of_bool(String.starts_with(~prefix=" ", s)); + // todo: check if in middle of token let (face, rest) = Ctx.pull(~from=L, z.ctx); let* tok = Delim.is_tok(face); // if expandable, consider all expandable const labels @@ -314,6 +315,7 @@ let try_expand = (s: string, z: Zipper.t): option(Zipper.t) => { ) ) |> Ctx.push(~onto=L, Token.space()) + |> Ctx.trim_space(~side=R) |> finalize(~mode=Inserting(" "), ~fill=Cell.point(~dirty=true, Focus)) |> return; }; diff --git a/src/web/view/Code.re b/src/web/view/Code.re index f507121b..be34bd5f 100644 --- a/src/web/view/Code.re +++ b/src/web/view/Code.re @@ -44,7 +44,9 @@ let cursor = (~font, z: Zipper.t) => { switch (ind_lc.meld) { | None => [] | Some(lm) => - Dec.Meld.Profile.mk(~whole=lc, ~state, lm) |> snd |> Dec.Meld.mk(~font) + Dec.Meld.Profile.mk(~whole=lc, ~state, lm) + |> snd + |> Dec.Layers.view(~font) } | Select(ind_zigg) => let sel = Option.get(Cursor.get_select(z.cur)); @@ -66,24 +68,10 @@ let cursor = (~font, z: Zipper.t) => { ); ind_zigg |> Dec.Zigg.Profile.mk(~whole=lc, ~state, ~null, ~eqs, ~rolled) - |> Dec.Zigg.mk(~font); + |> Dec.Layers.view(~font); }; }; -// let cursor = (~font, z: Zipper.t) => -// switch (z.cur) { -// | Select(_) => [] -// | Point(_) => -// let tree = Layout.mk_cell(Zipper.zip(~save_cursor=true, z)); -// let (cell, ctx) = Zipper.zip_indicated(z); -// switch (Cell.get(cell)) { -// | None => [] -// | Some(m) => -// let path = Zipper.path_of_ctx(ctx); -// m |> Dec.Meld.Profile.mk(~tree, ~path) |> Dec.Meld.mk(~font); -// }; -// }; - let view = (~font: Model.Font.t, ~zipper: Zipper.t): Node.t => { // print_endline("--- Code.view ---"); // print_endline("z = " ++ Zipper.show(zipper)); diff --git a/src/web/view/dec/Child.re b/src/web/view/dec/Child.re index b3c65d1a..5216802c 100644 --- a/src/web/view/dec/Child.re +++ b/src/web/view/dec/Child.re @@ -70,7 +70,7 @@ let includes_all_but_padding = }; }; -let mk = (~font, p: Profile.t) => { +let view = (~font, p: Profile.t) => { let end_loc: Loc.t = Dims.skip(p.loc, ~over=p.dims, ~ind=p.ind); let Dims.{height, widths: (hd, _)} = p.dims; diff --git a/src/web/view/dec/Dec.re b/src/web/view/dec/Dec.re index 2e8d678a..466682aa 100644 --- a/src/web/view/dec/Dec.re +++ b/src/web/view/dec/Dec.re @@ -1,5 +1,7 @@ module DecUtil = DecUtil; +module Layers = Layers; + module Token = Token; module Meld = Meld; module Zigg = Zigg; diff --git a/src/web/view/dec/Layers.re b/src/web/view/dec/Layers.re new file mode 100644 index 00000000..a3ae7b8a --- /dev/null +++ b/src/web/view/dec/Layers.re @@ -0,0 +1,35 @@ +open Sexplib.Std; +open Ppx_yojson_conv_lib.Yojson_conv.Primitives; +open Virtual_dom.Vdom; + +[@deriving (show({with_path: false}), sexp, yojson)] +type t = { + outer: list(Silhouette.Outer.Profile.t), + inner: list(Silhouette.Inner.Profile.t), + cells: list(Child.Profile.t), + tokens: list(Token.Profile.t), +}; + +let mk = (~outer=[], ~inner=[], ~cells=[], ~tokens=[], ()) => { + outer, + inner, + cells, + tokens, +}; +let empty = {outer: [], inner: [], tokens: [], cells: []}; +let cat = (l: t, r: t) => { + let outer = l.outer @ r.outer; + let inner = l.inner @ r.inner; + let cells = l.cells @ r.cells; + let tokens = l.tokens @ r.tokens; + {outer, inner, tokens, cells}; +}; +let concat = List.fold_left(cat, empty); + +let view = (~font, {outer, inner, tokens, cells}: t): list(Node.t) => + List.concat([ + List.map(Silhouette.Outer.view(~font), outer), + List.concat_map(Silhouette.Inner.view(~font), inner), + List.map(Child.view(~font), cells), + List.map(Token.view(~font), tokens), + ]); diff --git a/src/web/view/dec/Meld.re b/src/web/view/dec/Meld.re index 2c09d942..b7f043e7 100644 --- a/src/web/view/dec/Meld.re +++ b/src/web/view/dec/Meld.re @@ -37,16 +37,16 @@ module Profile = { let s_init = state |> L.State.jump_cell(~over=p_l); let s_tok = L.State.jump_cell(s_init, ~over=lc_l); - let silhouette = + let inner = sil - ? Some( - Silhouette.Inner.Profile.mk( - ~is_space=Mtrl.is_space(LMeld.sort(lm)), - ~state=s_init, - LMeld.flatten(~flatten=LCell.flatten, lm), - ), - ) - : None; + ? [ + Silhouette.Inner.Profile.mk( + ~is_space=Mtrl.is_space(LMeld.sort(lm)), + ~state=s_init, + LMeld.flatten(~flatten=LCell.flatten, lm), + ), + ] + : []; let l = Child.Profile.mk( @@ -71,16 +71,8 @@ module Profile = { ); let state = state |> L.State.jump_cell(~over=lc_r) |> L.State.jump_cell(~over=p_r); - let p = {chain: Chain.consnoc(~hd=l, w, ~ft=r), sil: silhouette}; + let p = {...w, inner, cells: [l] @ w.cells @ [r]}; + // let p = {chain: Chain.consnoc(~hd=l, w, ~ft=r), sil: silhouette}; (state, p); }; }; - -let mk = (~font, p: Profile.t) => - List.concat([ - p.sil - |> Option.map(Silhouette.Inner.mk(~font)) - |> Option.value(~default=[]), - List.map(T.mk(~font), Profile.tokens(p)), - List.map(Child.mk(~font), Profile.cells(p)), - ]); diff --git a/src/web/view/dec/Silhouette.re b/src/web/view/dec/Silhouette.re index 02bf0f3e..c3ac9fcc 100644 --- a/src/web/view/dec/Silhouette.re +++ b/src/web/view/dec/Silhouette.re @@ -53,7 +53,7 @@ module Inner = { let h_pad = 0.1; let v_trunc = T.v_trunc -. 0.06; - let mk = (~font, p: Profile.t) => { + let view = (~font, p: Profile.t) => { p.is_space ? [] : Block.flatten(p.block) @@ -103,6 +103,7 @@ module Inner = { module Outer = { module Profile = { open Util.Svgs; + [@deriving (show({with_path: false}), sexp, yojson)] type t = list(Rect.t); let mk = (~state: L.State.t, block: Block.t) => { Block.flatten(block) @@ -134,7 +135,7 @@ module Outer = { }; }; - let mk = (~font, p: Profile.t) => { + let view = (~font, p: Profile.t) => { p |> Util.Svgs.OrthogonalPolygon.mk(~corner_radii=(0.35, 0.15)) |> Util.Svgs.Path.view diff --git a/src/web/view/dec/Terr.re b/src/web/view/dec/Terr.re index 55ef4bce..9365a2cb 100644 --- a/src/web/view/dec/Terr.re +++ b/src/web/view/dec/Terr.re @@ -23,6 +23,16 @@ module Profile = { let ind = L.Indent.curr(state.ind); // let (null_l, null_r) = ; // let state = eq ? state : L.State.push_ind(state); + let inner = + sil + ? [ + Silhouette.Inner.Profile.mk( + ~is_space=Mtrl.is_space(LTerr.sort(terr)), + ~state, + LTerr.L.flatten(terr), + ), + ] + : []; let (state, wald) = W.Profile.mk( ~sil, @@ -41,7 +51,8 @@ module Profile = { terr.cell, ); let state = L.State.jump_cell(state, ~over=terr.cell); - (state, {cell, wald}); + let p = {...wald, inner, cells: wald.cells @ [cell]}; + (state, p); }; let mk_r = @@ -53,6 +64,17 @@ module Profile = { ~eq, terr: LTerr.t, ) => { + let inner = + sil + ? [ + Silhouette.Inner.Profile.mk( + ~is_space=Mtrl.is_space(LTerr.sort(terr)), + ~state, + LTerr.R.flatten(terr), + ), + ] + : []; + let s_mid = L.State.jump_cell(state, ~over=terr.cell); let cell = Child.Profile.mk( @@ -72,11 +94,7 @@ module Profile = { ~eq=(false, eq), Wald.rev(terr.wald), ); - (state, {cell, wald}); + let p = {...wald, inner, cells: [cell] @ wald.cells}; + (state, p); }; }; - -let mk = (~font, p: Profile.t) => [ - Child.mk(~font, p.cell), - ...W.mk(~font, p.wald), -]; diff --git a/src/web/view/dec/Token.re b/src/web/view/dec/Token.re index 57ac27fa..d8ac48bd 100644 --- a/src/web/view/dec/Token.re +++ b/src/web/view/dec/Token.re @@ -128,7 +128,7 @@ module Sil = { }; }; -let mk = (prof: Profile.t) => +let view = (prof: Profile.t) => prof.style |> Option.map((style: Style.t) => (style.sil ? [Sil.mk(prof.len, style.shape)] : []) diff --git a/src/web/view/dec/Wald.re b/src/web/view/dec/Wald.re index 95ad0566..fb94e079 100644 --- a/src/web/view/dec/Wald.re +++ b/src/web/view/dec/Wald.re @@ -6,7 +6,7 @@ module L = Layout; module Profile = { [@deriving (show({with_path: false}), sexp, yojson)] - type t = Chain.t(T.Profile.t, Child.Profile.t); + type t = Layers.t; let tokens = fst; let cells = snd; @@ -18,43 +18,51 @@ module Profile = { ~state: L.State.t, ~null: (bool, bool), ~eq: (bool, bool), - W(w): LWald.t, + W(w) as lw: LWald.t, ) => { let state = fst(eq) ? L.State.pop_ind(state) : L.State.push_ind(state); let ind = L.Indent.curr(state.ind); // let ind = state.ind + state.rel; let n = Chain.length(w); + let inner = + sil + ? [ + Silhouette.Inner.Profile.mk( + ~is_space=Mtrl.is_space(LWald.sort(lw)), + ~state, + LWald.flatten(~flatten=LCell.flatten, lw), + ), + ] + : []; // logic below assumes w won't be space - w - |> Chain.mapi_loop((i, b) => (i, b)) - |> Chain.fold_left_map( - ((_, b_tok)) => { - let null = (fst(null), n == 1 && snd(null)); - let t = T.Profile.mk(~sil, ~loc=state.loc, ~null, b_tok); - let state = L.State.jump_tok(state, ~over=b_tok); - (state, t); - }, - (state, cell, (i, b_tok)) => { - let c = - Child.Profile.mk( - ~sil, - ~whole, - ~ind, - ~loc=state.loc, - ~null=(false, false), - cell, - ); - let state = L.State.jump_cell(state, ~over=cell); - let null = (false, i == n - 1 && snd(null)); - let t = T.Profile.mk(~sil, ~loc=state.loc, ~null, b_tok); - let state = L.State.jump_tok(state, ~over=b_tok); - (state, c, t); - }, - ) - |> Stds.Tuples.map_fst(snd(eq) ? Fun.id : L.State.pop_ind); + let (state, (tokens, cells)) = + w + |> Chain.mapi_loop((i, b) => (i, b)) + |> Chain.fold_left_map( + ((_, b_tok)) => { + let null = (fst(null), n == 1 && snd(null)); + let t = T.Profile.mk(~sil, ~loc=state.loc, ~null, b_tok); + let state = L.State.jump_tok(state, ~over=b_tok); + (state, t); + }, + (state, cell, (i, b_tok)) => { + let c = + Child.Profile.mk( + ~sil, + ~whole, + ~ind, + ~loc=state.loc, + ~null=(false, false), + cell, + ); + let state = L.State.jump_cell(state, ~over=cell); + let null = (false, i == n - 1 && snd(null)); + let t = T.Profile.mk(~sil, ~loc=state.loc, ~null, b_tok); + let state = L.State.jump_tok(state, ~over=b_tok); + (state, c, t); + }, + ) + |> Stds.Tuples.map_fst(snd(eq) ? Fun.id : L.State.pop_ind); + (state, Layers.mk(~inner, ~cells, ~tokens, ())); }; }; - -let mk = (~font, p: Profile.t) => - List.map(T.mk(~font), Profile.tokens(p)) - @ List.map(Child.mk(~font), Profile.cells(p)); diff --git a/src/web/view/dec/Zigg.re b/src/web/view/dec/Zigg.re index ebe36c79..61e1003e 100644 --- a/src/web/view/dec/Zigg.re +++ b/src/web/view/dec/Zigg.re @@ -8,45 +8,16 @@ open Tylr_core; module L = Layout; -module Sil = { - type t = { - // total selection silhouette - outer: Silhouette.Outer.Profile.t, - // parsed inner silhouettes - inner: list(Silhouette.Inner.Profile.t), - }; -}; - module Profile = { - type t = { - l: option(Either.t(M.Profile.t, Child.Profile.t)), - up: list(T.Profile.t), - top: W.Profile.t, - dn: list(T.Profile.t), - r: option(Either.t(M.Profile.t, Child.Profile.t)), - sil: Sil.t, - }; - - // let tokens = ({up, top, dn, _}: t) => - // List.concat([ - // List.concat_map(T.Profile.tokens, up), - // fst(top), - // List.concat_map(T.Profile.tokens, dn), - // ]); - // let cells = ({up, top, dn, _}: t) => - // List.concat_map(T.Profile.cells, up) - // @ snd(top) - // @ List.concat_map(T.Profile.cells, dn); + type t = Layers.t; let mk_rolled = (~side: Dir.t, ~whole, ~state, ~rel: Either.t(_), rolled: LCell.t) => { switch (rolled.meld) { - | None => (state, (None, [])) + | None => (state, Layers.empty) | Some(m) => switch (rel) { - | Left () => - let (state, p) = M.Profile.mk(~sil=true, ~whole, ~state, m); - (state, (Some(Either.Left(p)), [])); + | Left () => M.Profile.mk(~sil=true, ~whole, ~state, m) | Right((s_neighbor, neighbor)) => let s_post = L.State.jump_cell(state, ~over=rolled); let s_tok = Dir.pick(side, (s_post, state)); @@ -60,7 +31,7 @@ module Profile = { |> Dir.order(side) |> Funs.uncurry(Block.hcat), ); - let p = + let cell = Child.Profile.mk( ~sil=true, ~whole, @@ -69,7 +40,8 @@ module Profile = { ~null=Dir.pick(side, ((true, false), (false, true))), rolled, ); - (s_post, (Some(Either.Right(p)), [sil])); + let p = Layers.mk(~inner=[sil], ~cells=[cell], ()); + (s_post, p); } }; }; @@ -96,22 +68,16 @@ module Profile = { let (p_r, cell) = LCell.depad(terr.cell, ~side=R); let terr = {...terr, cell}; - let sil = - Silhouette.Inner.Profile.mk( - ~is_space=Mtrl.is_space(LTerr.sort(terr)), - ~state, - LTerr.L.flatten(terr), - ); let (state, p) = T.Profile.mk_l(~sil=true, ~whole, ~state, ~eq, ~null, terr); let state = L.State.jump_cell(state, ~over=p_r); - (state, (p, sil)); + (state, p); }, state, ) - |> Tuples.map_snd(List.split); + |> Tuples.map_snd(Layers.concat); }; let mk_dn = @@ -141,21 +107,14 @@ module Profile = { let terr = {...terr, cell}; let state = L.State.jump_cell(state, ~over=p_l); - - let sil = - Silhouette.Inner.Profile.mk( - ~is_space=Mtrl.is_space(LTerr.sort(terr)), - ~state, - LTerr.R.flatten(terr), - ); let (state, p) = T.Profile.mk_r(~sil=true, ~whole, ~state, ~eq, ~null, terr); - (state, (p, sil)); + (state, p); }, state, ) - |> Tuples.map_snd(List.split); + |> Tuples.map_snd(Layers.concat); }; let mk = @@ -185,9 +144,9 @@ module Profile = { // this state doesn't matter, just to satisfy types Right((state, LZigg.hd_block(~side=L, rolled_z))) }; - let (state, (m_l, m_l_sil)) = + let (state, m_l) = mk_rolled(~side=L, ~whole, ~state, ~rel=rel_l, rolled_l); - let (state, (up, up_sil)) = + let (state, up) = mk_up( ~whole, ~state, @@ -202,24 +161,16 @@ module Profile = { state_before_right_hd := state; }; - let (state, (top, top_sil)) = { + let (state, top) = { let null = ( List.for_all(t => Mtrl.is_space(LTerr.sort(t)), zigg.up) && null_l, List.for_all(t => Mtrl.is_space(LTerr.sort(t)), zigg.dn) && null_r, ); let eq = List.(mem(-1, eqs_l), mem(-1, eqs_r)); - let sil = - Silhouette.Inner.Profile.mk( - ~is_space=Mtrl.is_space(LWald.sort(rolled_z.top)), - ~state, - LWald.flatten(~flatten=LCell.flatten, rolled_z.top), - ); - let (state, p) = - W.Profile.mk(~sil=true, ~whole, ~state, ~null, ~eq, rolled_z.top); - (state, (p, sil)); + W.Profile.mk(~sil=true, ~whole, ~state, ~null, ~eq, rolled_z.top); }; - let (state, (dn, dn_sil)) = + let (state, dn) = mk_dn( ~whole, ~state, @@ -236,37 +187,8 @@ module Profile = { | Neq(R) => Right((state_before_right_hd^, LZigg.hd_block(~side=R, rolled_z))) }; - let (_state, (m_r, m_r_sil)) = + let (_state, m_r) = mk_rolled(~side=R, ~whole, ~state, ~rel=rel_r, rolled_r); - - let sil = - Sil.{ - outer: outer_sil, - inner: List.concat([m_l_sil, up_sil, [top_sil], dn_sil, m_r_sil]), - }; - {l: m_l, up, top, dn, r: m_r, sil}; + {...Layers.concat([m_l, up, top, dn, m_r]), outer: [outer_sil]}; }; }; - -let mk = (~font, p: Profile.t) => - List.concat([ - [Silhouette.Outer.mk(~font, p.sil.outer)], - List.concat_map(Silhouette.Inner.mk(~font), p.sil.inner), - p.l - |> Option.map( - fun - | Either.Left(p) => M.mk(~font, p) - | Right(p) => [Child.mk(~font, p)], - ) - |> Option.value(~default=[]), - List.concat_map(T.mk(~font), p.up), - W.mk(~font, p.top), - List.concat_map(T.mk(~font), p.dn), - p.r - |> Option.map( - fun - | Either.Left(p) => M.mk(~font, p) - | Right(p) => [Child.mk(~font, p)], - ) - |> Option.value(~default=[]), - ]);