Skip to content

Commit

Permalink
feat: Navigate to convenient editing loc after insert; auto fill for …
Browse files Browse the repository at this point in the history
…node creation
  • Loading branch information
justinpombrio committed May 5, 2024
1 parent 2b1e301 commit 786d07e
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 12 deletions.
3 changes: 3 additions & 0 deletions src/engine/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,9 @@ pub enum TreeNavCommand {
/// If the node before the cursor is texty, enter text mode, placing the cursor at the
/// end of the text.
EnterText,
/// Use this when the node before the cursor has just been `Insert`ed, to move the cursor to a
/// convenient editing location.
FirstInsertLoc,
}

#[derive(Debug)]
Expand Down
3 changes: 3 additions & 0 deletions src/engine/doc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,9 @@ fn execute_tree_nav(
EnterText => cursor
.left_node(s)
.and_then(|node| Location::end_of_text(s, node)),
FirstInsertLoc => cursor
.left_node(s)
.map(|node| Location::first_insert_loc(s, node)),
};

if let Some(new_loc) = new_loc {
Expand Down
21 changes: 21 additions & 0 deletions src/language/interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,23 @@ impl Sort {
construct: id,
})
}

/// Returns the single unique construct in this sort, or `None` if it has zero or more than one
/// construct.
pub fn unique_construct(self, s: &Storage) -> Option<Construct> {
let mut unique = None;
for construct in self.matching_constructs(s) {
if construct.is_hole(s) {
continue;
}
if unique.is_some() {
return None;
} else {
unique = Some(construct);
}
}
unique
}
}

impl Construct {
Expand Down Expand Up @@ -295,6 +312,10 @@ impl Construct {
grammar(s, self.language).constructs[self.construct].is_comment_or_ws
}

pub fn is_hole(self, s: &Storage) -> bool {
grammar(s, self.language).hole_construct == self.construct
}

pub fn is_root(self, s: &Storage) -> bool {
grammar(s, self.language).root_construct == self.construct
}
Expand Down
5 changes: 3 additions & 2 deletions src/runtime.rs
Original file line number Diff line number Diff line change
Expand Up @@ -348,8 +348,9 @@ impl<F: Frontend<Style = Style> + 'static> Runtime<F> {
}

pub fn insert_node(&mut self, construct: Construct) -> Result<(), SynlessError> {
let node = Node::new(self.engine.raw_storage_mut(), construct);
self.engine.execute(TreeEdCommand::Insert(node))
let node = Node::new_with_auto_fill(self.engine.raw_storage_mut(), construct);
self.engine.execute(TreeEdCommand::Insert(node))?;
self.engine.execute(TreeNavCommand::FirstInsertLoc)
}

/*************
Expand Down
21 changes: 21 additions & 0 deletions src/tree/location.rs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,27 @@ impl Location {
Some(Location(LocationInner::InText(node, text_len)))
}

/// Where to move the cursor after inserting this node.
pub fn first_insert_loc(s: &Storage, node: Node) -> Location {
Location::first_insert_loc_impl(s, node, true)
}

fn first_insert_loc_impl(s: &Storage, node: Node, top_level: bool) -> Location {
match node.arity(s) {
Arity::Texty => Location::end_of_text(s, node).bug(),
Arity::Listy(_) => Location::before_children(s, node).bug(),
Arity::Fixed(_) => {
if let Some(child) = node.first_child(s) {
Location::first_insert_loc_impl(s, child, false)
} else if top_level {
Location::after(s, node)
} else {
Location::before(s, node)
}
}
}
}

/*************
* Accessors *
*************/
Expand Down
29 changes: 19 additions & 10 deletions src/tree/node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,20 @@ impl Node {
****************/

pub fn new_hole(s: &mut Storage, lang: Language) -> Node {
Node::new(s, lang.hole_construct(s))
Node::new_impl(s, lang.hole_construct(s), false)
}

/// Creates a new root node.
pub fn new(s: &mut Storage, construct: Construct) -> Node {
Node::new_impl(s, construct, false)
}

/// Creates a new root node, filling in any children that can only be one construct.
pub fn new_with_auto_fill(s: &mut Storage, construct: Construct) -> Node {
Node::new_impl(s, construct, true)
}

fn new_impl(s: &mut Storage, construct: Construct, auto_fill: bool) -> Node {
let id = inc_id(&mut s.node_forest.next_id);
match construct.arity(s) {
Arity::Texty => Node(s.forest_mut().new_node(NodeData {
Expand All @@ -73,16 +82,16 @@ impl Node {
construct,
text: None,
});
let num_children = sorts.len(s);
let hole_construct = construct.language().hole_construct(s);
for _ in 0..num_children {
let child_id = inc_id(&mut s.node_forest.next_id);
let child = s.forest_mut().new_node(NodeData {
id: child_id,
construct: hole_construct,
text: None,
});
bug_assert!(s.forest_mut().insert_last_child(parent, child));
for i in 0..sorts.len(s) {
let sort = sorts.get(s, i).bug();
let child = match sort.unique_construct(s) {
Some(child_construct) if auto_fill => {
Node::new_impl(s, child_construct, auto_fill)
}
_ => Node::new_impl(s, hole_construct, false),
};
bug_assert!(s.forest_mut().insert_last_child(parent, child.0));
}
Node(parent)
}
Expand Down

0 comments on commit 786d07e

Please sign in to comment.