diff --git a/src/core/editor/Modify.re b/src/core/editor/Modify.re index ad0f42a2..094739d0 100644 --- a/src/core/editor/Modify.re +++ b/src/core/editor/Modify.re @@ -139,10 +139,10 @@ let rec remold = (~fill=Cell.dirty, ctx: Ctx.t): (Cell.t, Ctx.t) => { (), ); // hack(?) to avoid completion if no new ghosts are generated. if only - // grout are generated, then we can generated them later at the end of - // remolding. better to delay their generation bc there may be grout in - // the suffix whose relative position around neighboring whitespace we - // want to preserve. + // grout are generated, then we can generate them later as needed at the + // end of remolding. better to delay their generation bc there may already + // be grout in the suffix whose relative position around neighboring + // whitespace we want to preserve. effs |> List.for_all( fun diff --git a/src/core/editor/Select.re b/src/core/editor/Select.re index 915499ac..0b0db8de 100644 --- a/src/core/editor/Select.re +++ b/src/core/editor/Select.re @@ -90,7 +90,7 @@ let hstep = (d: Dir.t, z: Zipper.t): option(Zipper.t) => { Zipper.mk(~cur=Select(sel), ctx); } else { // points always grow, only selections can shrink. - // d points toward selection anchor. + // d points from selection focus toward anchor. let sel = Option.get(Cursor.get_select(z.cur)); let sites = Option.get(Cursor.get_select(cur_site)); let (_site_foc, site_anc) = Dir.order(sel.focus, sites); diff --git a/src/core/editor/Zigg.re b/src/core/editor/Zigg.re index e79bd3bf..5baa196d 100644 --- a/src/core/editor/Zigg.re +++ b/src/core/editor/Zigg.re @@ -98,11 +98,7 @@ let of_dn = dn => let of_up = up => Stds.Lists.Framed.ft(up) |> Option.map(((up, t: Terr.t)) => - mk( - ~up=List.rev(up), - Wald.rev(t.wald), - ~dn=snd(Slope.Up.unroll(t.cell)), - ) + mk(~up=List.rev(up), t.wald, ~dn=snd(Slope.Dn.unroll(t.cell))) ); let roll = (~l=Cell.empty, ~r=Cell.empty, {up, top, dn}: t) => @@ -190,6 +186,7 @@ let roll_bounds = (~l=Delim.root, ~r=Delim.root, zigg: Base.t(_)) => { let l = switch (l) { | Root => (List.length(zigg.up), Rel.Neq(Dir.L)) + | Node(tok) when Token.merges(tok, face(~side=L, zigg)) => (0, Rel.Eq()) | Node(tok) => switch (push(~side=L, tok, zigg)) { | Error(_) => (List.length(zigg.up), Rel.Neq(L)) @@ -207,6 +204,7 @@ let roll_bounds = (~l=Delim.root, ~r=Delim.root, zigg: Base.t(_)) => { let r = switch (r) { | Root => (List.length(zigg.dn), Rel.Neq(Dir.R)) + | Node(tok) when Token.merges(tok, face(~side=R, zigg)) => (0, Rel.Eq()) | Node(tok) => switch (push(~side=R, tok, zigg)) { | Error(_) => (List.length(zigg.dn), Rel.Neq(R)) diff --git a/src/core/editor/Zipper.re b/src/core/editor/Zipper.re index beec49ec..0c8a2bb8 100644 --- a/src/core/editor/Zipper.re +++ b/src/core/editor/Zipper.re @@ -192,7 +192,13 @@ and unzip_select = (~ctx=Ctx.empty, sel: Path.Selection.t, meld: Meld.t) => { }; let unzip_exn = (~ctx=Ctx.empty, c: Cell.t) => - unzip(~ctx, c) |> Options.get_exn(Invalid_argument("Zipper.unzip_exn")); + switch (unzip(~ctx, c)) { + | Some(z) => z + | None => + P.show("unzip_exn ctx", Ctx.show(ctx)); + P.show("unzip_exn cell", Cell.show(c)); + raise(Invalid_argument("Zipper.unzip_exn")); + }; let rec zip_neighbor = (~side: Dir.t, ~zipped: Cell.t, ctx: Ctx.t) => { open Options.Syntax; diff --git a/src/core/layout/Layout.re b/src/core/layout/Layout.re index 06adc8b1..0491c782 100644 --- a/src/core/layout/Layout.re +++ b/src/core/layout/Layout.re @@ -330,6 +330,50 @@ let states = (~init: State.t, m: LMeld.t) => let nth_line = (tree: LCell.t, r: Loc.Row.t) => Block.nth_line(LCell.flatten(tree), r); +let unroll = (~ctx=Ctx.empty, side: Dir.t, cell: LCell.t) => { + let f_open = + side == L + ? ([], LSlope.Up.unroll(cell)) : (LSlope.Dn.unroll(cell), []); + Ctx.map_hd(Frame.Open.cat(f_open), ctx); +}; +let rec unzip_point = + (~side: Dir.t, ~ctx=LCtx.empty, car: Path.Caret.t, c: LCell.t): LCtx.t => { + let hd = Path.Caret.hd(car); + switch (hd) { + | Error(_) => + assert(Option.is_none(c.meld)); + ctx; + | Ok(step) => + let tl = Option.get(Path.Caret.peel(step, car)); + let m = Options.get_exn(Marks.Invalid, c.meld); + switch (LMeld.unzip(step, m)) { + | Loop((pre, cell, suf)) => + let ctx = LCtx.add((pre, suf), ctx); + unzip_point(~side, ~ctx, tl, cell); + | Link((pre, tok, suf)) => + let put_tok_l = () => { + let pre = Chain.Affix.cons(tok, pre); + let (cell, suf) = Chain.uncons(suf); + let ctx = LCtx.add((pre, suf), ctx); + unroll(L, cell, ~ctx); + }; + let put_tok_r = () => { + let (cell, pre) = Chain.uncons(pre); + let suf = Chain.Affix.cons(tok, suf); + let ctx = LCtx.add((pre, suf), ctx); + unroll(R, cell, ~ctx); + }; + switch (side, tl) { + | (L, {path: [char_step, ..._], _}) when char_step >= Block.len(tok) => + put_tok_r() + | (L, _) => put_tok_l() + | (R, {path: [char_step, ..._], _}) when char_step <= 0 => put_tok_r() + | (R, _) => put_tok_l() + }; + }; + }; +}; + let rec unzip = (~ctx=LCtx.empty, cur: Path.Cursor.t, c: LCell.t): LZipper.t => { let hd = Path.Cursor.hd(cur); switch (hd) { @@ -342,16 +386,13 @@ let rec unzip = (~ctx=LCtx.empty, cur: Path.Cursor.t, c: LCell.t): LZipper.t => | Ok(step) => let tl = Option.get(Path.Cursor.peel(step, cur)); let m = Options.get_exn(Marks.Invalid, c.meld); - switch (Meld.Base.unzip(step, m)) { + switch (LMeld.unzip(step, m)) { | Loop((pre, cell, suf)) => let ctx = LCtx.add((pre, suf), ctx); unzip(~ctx, tl, cell); - // | Link((pre, tok, suf)) => - // // if caret points to token, then take the entire meld as focused cell - // let cur = Cursor.map(Caret.map(Fun.const()), Fun.id, cur); - // (cur, c, frame); | Link((pre, tok, suf)) => switch (cur) { + // if caret points to token, then take the entire meld as focused cell | Point(_) => LZipper.mk(Cursor.Point(c), ctx) | Select(_) => let (l, pre) = Chain.uncons(pre); @@ -380,8 +421,8 @@ and unzip_select = (~ctx, sel: Path.Selection.t, meld: LMeld.t) => { let (hd_pre, tl_pre) = Chain.uncons(pre); let l_tl = l_hd mod 2 == 0 ? List.tl(l) : LCell.end_path(hd_pre, ~side=R); - let z = unzip(Point(Caret.focus(l_tl)), hd_pre); - let (eqs, flat) = LCtx.flatten(z.ctx); + let ctx = unzip_point(~side=L, Caret.focus(l_tl), hd_pre); + let (eqs, flat) = LCtx.flatten(ctx); let eqs = Chain.Affix.is_empty(tl_pre) ? eqs : [(0, (-1)), ...LEqs.incr(~side=L, 1, eqs)]; @@ -397,8 +438,8 @@ and unzip_select = (~ctx, sel: Path.Selection.t, meld: LMeld.t) => { let (hd_suf, tl_suf) = Chain.uncons(suf); let r_tl = r_hd mod 2 == 0 ? List.tl(r) : LCell.end_path(~side=L, hd_suf); - let z = unzip(Point(Caret.focus(r_tl)), hd_suf); - let (eqs, flat) = LCtx.flatten(z.ctx); + let ctx = unzip_point(~side=R, Caret.focus(r_tl), hd_suf); + let (eqs, flat) = LCtx.flatten(ctx); let eqs = Chain.Affix.is_empty(tl_suf) ? eqs : [((-1), 0), ...LEqs.incr(~side=R, 1, eqs)]; diff --git a/src/core/structure/Cell.re b/src/core/structure/Cell.re index 272d7558..5d3ec128 100644 --- a/src/core/structure/Cell.re +++ b/src/core/structure/Cell.re @@ -290,10 +290,9 @@ module Space = { let shift = 2 * List.length(Meld.tokens(m)); Marks.map_paths( fun - | [] => { - assert(r.meld == None); - [shift]; - } + | [] => + // assert(r.meld == None); + [shift] | [hd, ...tl] => [hd + shift, ...tl], ); }