Skip to content

Commit

Permalink
duplicate-token move/select logic
Browse files Browse the repository at this point in the history
  • Loading branch information
dm0n3y committed Jul 8, 2024
1 parent 82136c7 commit 3367c9d
Show file tree
Hide file tree
Showing 5 changed files with 183 additions and 34 deletions.
61 changes: 55 additions & 6 deletions src/core/editor/Move.re
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,29 @@ module Action = {
| Hole(Dir.t);
};

// enters unmarked token or moves cursor in marked token.
// returns Some(_) if caret remains strictly within token,
// otherwise returns None if caret reaches token edge.
let hstep_tok = (d: Dir.t, tok: Token.t): option(Token.t) => {
let (m, n) = (Token.length(tok), Utf8.length(tok.text));
let (l, r) = (1, Token.is_complete(tok) ? m - 1 : n);
switch (tok.marks) {
| _ when m <= 1 => None
| None =>
let car = Caret.focus(Dir.pick(d, (r, l)));
Some(Token.put_cursor(Point(car), tok));
| Some(Point(car)) when Dir.pick(d, (car.path <= l, car.path >= r)) =>
None
| Some(Point(car)) =>
let car = Step.Caret.shift(Dir.pick(d, ((-1), 1)), car);
Some(Token.put_cursor(Point(car), tok));
| Some(Select(sel)) =>
let (l, r) = Step.Selection.carets(sel);
let car = Caret.focus(Dir.pick(d, (l, r)).path);
Some(Token.put_cursor(Point(car), tok));
};
};

let hstep = (d: Dir.t, z: Zipper.t): option(Zipper.t) => {
open Options.Syntax;
let b = Dir.toggle(d);
Expand All @@ -19,17 +42,43 @@ let hstep = (d: Dir.t, z: Zipper.t): option(Zipper.t) => {
return(Ctx.push_zigg(~onto=b, zigg, z.ctx))
| Point(_) =>
let+ (tok, ctx) = Ctx.pull(~from=d, z.ctx);
// todo: add movement granularity
switch (Token.pull(~from=b, tok)) {
| None => Ctx.push(~onto=b, tok, ctx)
| Some((l, r)) =>
let (c, tok) = Dir.order(b, (l, r));
ctx |> Ctx.push(~onto=d, tok) |> Ctx.push(~onto=b, c);
switch (hstep_tok(d, tok)) {
| None => ctx |> Ctx.push(~onto=b, Token.clear_marks(tok))
| Some(tok) =>
// more efficient to push onto z.ctx instead of ctx
z.ctx |> Ctx.push(~onto=d, tok) |> Ctx.push(~onto=b, tok)
};
};
Zipper.(button(mk(ctx)));
};

// let hstep = (d: Dir.t, z: Zipper.t): option(Zipper.t) => {
// open Options.Syntax;
// let b = Dir.toggle(d);
// // print_endline("--- Move.hstep ---");
// // print_endline("z = " ++ Zipper.show(z));
// let+ ctx =
// switch (z.cur) {
// // move to d end of selection
// | Select({range: zigg, _}) =>
// return(Ctx.push_zigg(~onto=b, zigg, z.ctx))
// | Point(_) =>
// let+ (tok, ctx) = Ctx.pull(~from=d, z.ctx);
// // todo: add movement granularity
// switch (Token.pull(~from=b, tok)) {
// | None => Ctx.push(~onto=b, tok, ctx)
// | Some((l, r)) =>
// // print_endline("l = " ++ Token.show(l));
// // print_endline("r = " ++ Token.show(r));
// let (c, tok) = Dir.order(b, (l, r));
// ctx |> Ctx.push(~onto=d, tok) |> Ctx.push(~onto=b, c);
// };
// };
// // print_endline("ctx = " ++ Ctx.show(ctx));
// // print_endline("buttoned = " ++ Zipper.(show(button(mk(ctx)))));
// Zipper.(button(mk(ctx)));
// };

let rec hstep_n = (n: int, z: Zipper.t): Zipper.t => {
let move = (d, z) =>
hstep(d, z) |> Options.get_exn(Invalid_argument("Move.move_n"));
Expand Down
121 changes: 100 additions & 21 deletions src/core/editor/Select.re
Original file line number Diff line number Diff line change
Expand Up @@ -19,48 +19,76 @@ let unselect = (~toward=?, ~save_anchor=false, z: Zipper.t) =>
Zipper.mk(Ctx.push_zigg(~onto, zigg, ~fill, z.ctx));
};

let hstep_tok = (d: Dir.t, tok: Token.t): Result.t(Token.t, Token.t) => {
let (m, n) = (Token.length(tok), Utf8.length(tok.text));
let (l, r) = (1, Token.is_complete(tok) ? m - 1 : n);
switch (tok.marks) {
| _ when m <= 1 => Error(Token.clear_marks(tok))
| None =>
let car = Caret.focus(Dir.pick(d, (r, l)));
Ok(Token.put_cursor(Point(car), tok));
| Some(Point({hand: Anchor, _} as anc)) =>
let foc = Caret.focus(Dir.pick(d, (r, l)));
let cur = Step.Cursor.mk(foc, anc);
Ok(Token.put_cursor(cur, tok));
| Some(Point({hand: Focus, _} as foc)) =>
if (Dir.pick(d, (foc.path <= l, foc.path >= r))) {
Error(Token.clear_marks(tok));
} else {
let foc = Step.Caret.shift(Dir.pick(d, ((-1), 1)), foc);
Ok(Token.put_cursor(Point(foc), tok));
}
| Some(Select(sel)) =>
let (foc, anc) = Dir.order(sel.focus, Step.Selection.carets(sel));
if (Dir.pick(d, (foc.path <= l, foc.path >= r))) {
Error(Token.put_cursor(Point(anc), tok));
} else {
let foc = Step.Caret.shift(Dir.pick(d, ((-1), 1)), foc);
let cur = Step.Cursor.mk(foc, anc);
Ok(Token.put_cursor(cur, tok));
};
};
};

let hstep = (d: Dir.t, z: Zipper.t): option(Zipper.t) => {
open Options.Syntax;
let b = Dir.toggle(d);
switch (z.cur) {
| Point(_) =>
let+ (tok, ctx) = Ctx.pull(~from=d, z.ctx);
let (tok, ctx) =
switch (Token.pull(~from=b, tok)) {
| None => (tok, ctx)
| Some((l, r)) =>
let (c, tok) = Dir.order(b, (l, r));
(c, Ctx.push(~onto=d, tok, ctx));
switch (hstep_tok(d, tok)) {
| Error(tok) => (tok, ctx)
| Ok(tok) => (tok, Ctx.push(~onto=d, tok, z.ctx))
};
Zipper.mk(~cur=Select({focus: d, range: Zigg.of_tok(tok)}), ctx);
| Select({focus: side, range: zigg}) =>
if (side == d) {
let+ (tok, ctx) = Ctx.pull(~from=d, z.ctx);
let (tok, ctx) =
switch (Token.pull(~from=b, tok)) {
| None => (tok, ctx)
| Some((l, r)) =>
let (c, tok) = Dir.order(b, (l, r));
(c, Ctx.push(~onto=d, tok, ctx));
switch (hstep_tok(d, tok)) {
| Error(tok) => (tok, ctx)
| Ok(tok) => (tok, Ctx.push(~onto=d, tok, z.ctx))
};
let zigg = Zigg.grow(~side, tok, zigg);
Zipper.mk(~cur=Select({focus: d, range: zigg}), ctx);
} else {
let (tok, rest) = Zigg.pull(~side=d, zigg);
let (tok, rest) = Zigg.pull(~side, zigg);
let (tok, cur) =
switch (Token.pull(~from=b, tok), rest) {
| (None, None) => (tok, Cursor.Point(Caret.focus()))
| (None, Some(zigg)) => (
switch (hstep_tok(d, tok), rest) {
| (Error(tok), None) => (tok, Cursor.Point(Caret.focus()))
| (Error(tok), Some(zigg)) => (
tok,
Select(Selection.{focus: side, range: zigg}),
)
| (Some((l, r)), None) =>
let (c, tok) = Dir.order(b, (l, r));
(c, Select({focus: side, range: Zigg.of_tok(tok)}));
| (Some((l, r)), Some(zigg)) =>
let (c, tok) = Dir.order(b, (l, r));
let zigg = Zigg.push_fail(~side, tok, zigg);
(c, Select({focus: side, range: zigg}));
| (Ok(tok), None) => (
tok,
Select({focus: side, range: Zigg.of_tok(tok)}),
)
| (Ok(tok), Some(zigg)) => (
tok,
Select({focus: side, range: Zigg.grow(~side, tok, zigg)}),
)
};
Ctx.push(~onto=b, tok, z.ctx)
|> Zipper.mk(~cur)
Expand All @@ -70,6 +98,57 @@ let hstep = (d: Dir.t, z: Zipper.t): option(Zipper.t) => {
};
};

// let hstep = (d: Dir.t, z: Zipper.t): option(Zipper.t) => {
// open Options.Syntax;
// let b = Dir.toggle(d);
// switch (z.cur) {
// | Point(_) =>
// let+ (tok, ctx) = Ctx.pull(~from=d, z.ctx);
// let (tok, ctx) =
// switch (Token.pull(~from=b, tok)) {
// | None => (tok, ctx)
// | Some((l, r)) =>
// let (c, tok) = Dir.order(b, (l, r));
// (c, Ctx.push(~onto=d, tok, ctx));
// };
// Zipper.mk(~cur=Select({focus: d, range: Zigg.of_tok(tok)}), ctx);
// | Select({focus: side, range: zigg}) =>
// if (side == d) {
// let+ (tok, ctx) = Ctx.pull(~from=d, z.ctx);
// let (tok, ctx) =
// switch (Token.pull(~from=b, tok)) {
// | None => (tok, ctx)
// | Some((l, r)) =>
// let (c, tok) = Dir.order(b, (l, r));
// (c, Ctx.push(~onto=d, tok, ctx));
// };
// let zigg = Zigg.grow(~side, tok, zigg);
// Zipper.mk(~cur=Select({focus: d, range: zigg}), ctx);
// } else {
// let (tok, rest) = Zigg.pull(~side=d, zigg);
// let (tok, cur) =
// switch (Token.pull(~from=b, tok), rest) {
// | (None, None) => (tok, Cursor.Point(Caret.focus()))
// | (None, Some(zigg)) => (
// tok,
// Select(Selection.{focus: side, range: zigg}),
// )
// | (Some((l, r)), None) =>
// let (c, tok) = Dir.order(b, (l, r));
// (c, Select({focus: side, range: Zigg.of_tok(tok)}));
// | (Some((l, r)), Some(zigg)) =>
// let (c, tok) = Dir.order(b, (l, r));
// let zigg = Zigg.push_fail(~side, tok, zigg);
// (c, Select({focus: side, range: zigg}));
// };
// Ctx.push(~onto=b, tok, z.ctx)
// |> Zipper.mk(~cur)
// |> Zipper.button
// |> Option.some;
// }
// };
// };

let perform = (a: Action.t, z: Zipper.t): option(Zipper.t) =>
switch (a) {
| Un(d) => Some(unselect(~toward=d, z))
Expand Down
15 changes: 8 additions & 7 deletions src/core/structure/Token.re
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,13 @@ module Molded = {
| Space () => Utf8.length(tok.text)
};

let is_complete = (tok: t) =>
switch (tok.mtrl) {
| Space ()
| Grout(_) => true
| Tile((lbl, _)) => Label.is_complete(tok.text, lbl)
};

let merge = (l: t, ~caret=?, r: t) => {
let n = Utf8.length(l.text);
let marks =
Expand All @@ -111,13 +118,6 @@ module Molded = {
None;
};

let is_complete = (tok: t) =>
switch (tok.mtrl) {
| Space ()
| Grout(_) => true
| Tile((lbl, _)) => Label.is_complete(tok.text, lbl)
};

// beware calling this on partial tokens
let unzip = (tok: t) =>
tok.marks
Expand Down Expand Up @@ -151,6 +151,7 @@ module Molded = {
| _ => raise(Invalid_argument("Token.Molded.split_caret"))
};

// beware calling this on partial tokens
let pull = (~from: Dir.t, tok: t): option((t, t)) =>
if (is_empty(tok) || length(tok) == 1) {
None;
Expand Down
10 changes: 10 additions & 0 deletions src/core/structure/marks/Path.re
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ module Map = {
module Range = {
[@deriving (show({with_path: false}), sexp, yojson, hash)]
type t = (Base.t, Base.t);
let mk = (p1: Base.t, p2: Base.t) =>
Base.compare(p1, p2) <= 0 ? (p1, p2) : (p2, p1);
let is_empty = ((l, r): t) => Base.compare(l, r) == 0;
let map = Tuples.map2;
let hd =
Expand Down Expand Up @@ -94,6 +96,10 @@ module Selection = {
};
let carets: t => (Caret.t, Caret.t) =
Selection.carets(~split_range=Fun.id);
let of_carets = (c1: Caret.t, c2: Caret.t) =>
Base.compare(c1.path, c2.path) <= 0
? mk(~focus=c1.hand == Focus ? L : R, (c1.path, c2.path))
: mk(~focus=c2.hand == Focus ? L : R, (c2.path, c1.path));
};

module Cursor = {
Expand Down Expand Up @@ -143,4 +149,8 @@ module Cursor = {
)
),
);

let mk = (c1: Caret.t, c2: Caret.t) =>
Base.compare(c1.path, c2.path) == 0
? Point(Caret.focus(c1.path)) : Select(Selection.of_carets(c1, c2));
};
10 changes: 10 additions & 0 deletions src/core/structure/marks/Step.re
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,24 @@ module Caret = {
include Caret;
[@deriving (show({with_path: false}), sexp, yojson, hash)]
type t = Caret.t(Base.t);
let shift = n => map((+)(n));
};

module Selection = {
include Selection;
[@deriving (show({with_path: false}), sexp, yojson, hash)]
type t = Selection.t(Range.t);
let map = f => Selection.map(Range.map(f));
let carets: t => (Caret.t, Caret.t) =
Selection.carets(~split_range=Fun.id);
let of_carets = (c1: Caret.t, c2: Caret.t) =>
Base.compare(c1.path, c2.path) <= 0
? mk(~focus=c1.hand == Focus ? L : R, (c1.path, c2.path))
: mk(~focus=c2.hand == Focus ? L : R, (c2.path, c1.path));
};

module Cursor = {
include Cursor;
[@deriving (show({with_path: false}), sexp, yojson, hash)]
type t = Cursor.t(Caret.t, Selection.t);
let map = f => Cursor.map(Caret.map(f), Selection.map(f));
Expand All @@ -42,4 +49,7 @@ module Cursor = {
| (Point({path: l, hand}), Point({path: r, _})) =>
Select({focus: hand == Focus ? L : R, range: (l, r)})
};
let mk = (c1: Caret.t, c2: Caret.t) =>
Base.compare(c1.path, c2.path) == 0
? Point(Caret.focus(c1.path)) : Select(Selection.of_carets(c1, c2));
};

0 comments on commit 3367c9d

Please sign in to comment.