Make p paste as children and P as siblings below
After trying part 8c, the user found p and P doing the same thing on the canvas: both pasted a sibling below the node (P only differed in the outline's order). Their pick: p pastes under the node, as its last children, the way a adds a child; P pastes the next siblings, below it, where o adds one. ]p went away, since p does what it did. Inside a title p and P still paste after and before the text cursor, as in vim: they're their own commands (paste-after, paste-before), and the node ones are paste-as-child and paste-as-sibling. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
7bec5bf3fc
commit
bd819409f4
10 files changed
+59
-53
No files matched your search
@@ -157,9 +157,11 @@ lines.
|
|||||||
- A register holds text or nodes, and either pastes anywhere: nodes pasted
|
- A register holds text or nodes, and either pastes anywhere: nodes pasted
|
||||||
into a text give their titles, text pasted on nodes becomes nodes. `yy`,
|
into a text give their titles, text pasted on nodes becomes nodes. `yy`,
|
||||||
`yab`, `yib` yank nodes; every delete (`dd`, `x`, `dib`, `d` on a
|
`yab`, `yib` yank nodes; every delete (`dd`, `x`, `dib`, `d` on a
|
||||||
selection) keeps what it took, so `dd` then `p` moves a branch. `p` `P`
|
selection) keeps what it took, so `dd` then `p` moves a branch. `p`
|
||||||
`]p` paste after, before, or as the last children, keeping the yanked
|
pastes as the node's last children and `P` as its next siblings (the
|
||||||
layout, where a new node would go; a count pastes copies. Links between
|
user's pick after trying part 8c: `p` goes under the node as `a` adds,
|
||||||
|
`P` below it as `o` adds), keeping the yanked layout, where a new node
|
||||||
|
would go; a count pastes copies. Links between
|
||||||
the pasted nodes come along, and so do links to nodes still there when
|
the pasted nodes come along, and so do links to nodes still there when
|
||||||
they go back into the document they came from.
|
they go back into the document they came from.
|
||||||
- `"+` is the system clipboard. Nodes go there as Markdown, the user's
|
- `"+` is the system clipboard. Nodes go there as Markdown, the user's
|
||||||
@@ -421,7 +423,7 @@ text).
|
|||||||
| **Move** (every view) | `hjkl` or arrows · `gh gj gk gl` tree moves · `w` `b` next / previous in reading order · `gg` root · `G` last · `/` `n` `N` search · `Ctrl-o` `Ctrl-i` (Tab) jump back / forward · `m{a-z}` `'{a-z}` marks (`A–Z` across documents) · Enter or `gf` through a portal · `gd` follow a cross-link |
|
| **Move** (every view) | `hjkl` or arrows · `gh gj gk gl` tree moves · `w` `b` next / previous in reading order · `gg` root · `G` last · `/` `n` `N` search · `Ctrl-o` `Ctrl-i` (Tab) jump back / forward · `m{a-z}` `'{a-z}` marks (`A–Z` across documents) · Enter or `gf` through a portal · `gd` follow a cross-link |
|
||||||
| **View** | `zz` center · `Ctrl-e` `Ctrl-y` `zh` `zl` pan · `Ctrl-d` `Ctrl-u` half a screen · `+` `-` zoom · `za zo zc zR zM` folds · `zf` Auto · `zi` focus · `K` body card |
|
| **View** | `zz` center · `Ctrl-e` `Ctrl-y` `zh` `zl` pan · `Ctrl-d` `Ctrl-u` half a screen · `+` `-` zoom · `za zo zc zR zM` folds · `zf` Auto · `zi` focus · `K` body card |
|
||||||
| **Create and edit** | `o` `O` sibling below / above · `a` child · `i` `A` Enter edit the title · `I` edit from its start · `cc` `S` retype |
|
| **Create and edit** | `o` `O` sibling below / above · `a` child · `i` `A` Enter edit the title · `I` edit from its start · `cc` `S` retype |
|
||||||
| **Operators** | `dd` or `dab` delete branch · `dib` delete children · `x` delete just the node · `yy` `yab` `yib` yank · `p` `P` paste after / before · `]p` paste as child · `>>` `<<` indent / outdent · `"a`–`"z` and `"+` registers · `.` repeat · `u` `Ctrl-r` undo / redo |
|
| **Operators** | `dd` or `dab` delete branch · `dib` delete children · `x` delete just the node · `yy` `yab` `yib` yank · `p` paste as children · `P` paste as siblings below · `>>` `<<` indent / outdent · `"a`–`"z` and `"+` registers · `.` repeat · `u` `Ctrl-r` undo / redo |
|
||||||
| **Modes** | `v` `V` visual · `M` move · `C` connect · `:` command · Esc back to normal |
|
| **Modes** | `v` `V` visual · `M` move · `C` connect · `:` command · Esc back to normal |
|
||||||
| **Leader** `<Space>` | `c` color · `s` style · `B` border · `t` tags · `p` new portal · `i` inbox · `b` documents · `v` then `c`/`o`/`n` for canvas / outline / note · `w` which-key on/off · `?` help |
|
| **Leader** `<Space>` | `c` color · `s` style · `B` border · `t` tags · `p` new portal · `i` inbox · `b` documents · `v` then `c`/`o`/`n` for canvas / outline / note · `w` which-key on/off · `?` help |
|
||||||
| **Panes, documents** | `Ctrl-w v` `Ctrl-w s` split · `Ctrl-w hjkl` focus · `Ctrl-w w` the next pane · `Ctrl-w c` close · `Ctrl-w o` only · `Ctrl-w =` even sizes · `gt` `gT` `]b` `[b` next / previous document · `ZZ` close pane (the last one quits) |
|
| **Panes, documents** | `Ctrl-w v` `Ctrl-w s` split · `Ctrl-w hjkl` focus · `Ctrl-w w` the next pane · `Ctrl-w c` close · `Ctrl-w o` only · `Ctrl-w =` even sizes · `gt` `gT` `]b` `[b` next / previous document · `ZZ` close pane (the last one quits) |
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ The plan for the everyday keys (all of them are in DESIGN.md):
|
|||||||
| `o` `O` `a` | new sibling below / above, new child: type its title, Enter for the next one |
|
| `o` `O` `a` | new sibling below / above, new child: type its title, Enter for the next one |
|
||||||
| `i` or Enter | edit the title (Esc: vim keys inside it, Esc again: done) |
|
| `i` or Enter | edit the title (Esc: vim keys inside it, Esc again: done) |
|
||||||
| `dd` `x` | delete the branch / just the node (kept in a register, as in vim) |
|
| `dd` `x` | delete the branch / just the node (kept in a register, as in vim) |
|
||||||
| `yy` `p` `P` `]p` | yank the branch / paste after, before, as a child (`dd` then `p` moves a branch) |
|
| `yy` `p` `P` | yank the branch / paste as children, or as siblings below (`dd` then `p` moves a branch) |
|
||||||
| `"a` `"+` | before `y`, `d` or `p`: register `a`; `"+` is the system clipboard (nodes go there as Markdown) |
|
| `"a` `"+` | before `y`, `d` or `p`: register `a`; `"+` is the system clipboard (nodes go there as Markdown) |
|
||||||
| `.` | the last change again |
|
| `.` | the last change again |
|
||||||
| `>>` `<<` | under the node above / out a level |
|
| `>>` `<<` | under the node above / out a level |
|
||||||
|
|||||||
+6
-7
@@ -145,7 +145,7 @@ pub enum AppAction {
|
|||||||
nodes: Vec<NodeId>,
|
nodes: Vec<NodeId>,
|
||||||
branches: bool,
|
branches: bool,
|
||||||
},
|
},
|
||||||
/// Paste what a register holds (`p`, `P`, `]p`): its nodes, or its text
|
/// Paste what a register holds (`p`, `P`): its nodes, or its text
|
||||||
/// made into nodes, `times` copies.
|
/// made into nodes, `times` copies.
|
||||||
Paste {
|
Paste {
|
||||||
register: Option<Register>,
|
register: Option<Register>,
|
||||||
@@ -256,15 +256,14 @@ pub enum AppAction {
|
|||||||
Say(Message),
|
Say(Message),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Where `p` and its kin paste, from the cursor's node.
|
/// Where `p` and `P` paste, from the cursor's node (the user's pick after
|
||||||
|
/// trying part 8c: `p` pastes under the node, as `a` adds).
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub enum PasteAt {
|
pub enum PasteAt {
|
||||||
/// Its next siblings (`p`).
|
/// Its last children (`p`).
|
||||||
After,
|
|
||||||
/// Its siblings before it (`P`).
|
|
||||||
Before,
|
|
||||||
/// Its last children (`]p`).
|
|
||||||
Child,
|
Child,
|
||||||
|
/// Its next siblings, below it, where `o` adds one (`P`).
|
||||||
|
Sibling,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// What `:w` and its kin save.
|
/// What `:w` and its kin save.
|
||||||
|
|||||||
+7
-9
@@ -64,13 +64,12 @@ pub fn shared(typed: &Typed, ctx: &ViewContext<'_>) -> Option<Vec<Action>> {
|
|||||||
app(AppAction::Yank { register: typed.register, nodes: children.to_vec(), branches: true })
|
app(AppAction::Yank { register: typed.register, nodes: children.to_vec(), branches: true })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Command::PasteAfter => app(AppAction::Paste { register: typed.register, at: PasteAt::After, times }),
|
|
||||||
Command::PasteBefore => {
|
|
||||||
app(AppAction::Paste { register: typed.register, at: PasteAt::Before, times })
|
|
||||||
}
|
|
||||||
Command::PasteAsChild => {
|
Command::PasteAsChild => {
|
||||||
app(AppAction::Paste { register: typed.register, at: PasteAt::Child, times })
|
app(AppAction::Paste { register: typed.register, at: PasteAt::Child, times })
|
||||||
}
|
}
|
||||||
|
Command::PasteAsSibling => {
|
||||||
|
app(AppAction::Paste { register: typed.register, at: PasteAt::Sibling, times })
|
||||||
|
}
|
||||||
Command::Operate(Operator::Indent, Target::Current) => indent(ctx, &siblings(ctx, times), None),
|
Command::Operate(Operator::Indent, Target::Current) => indent(ctx, &siblings(ctx, times), None),
|
||||||
Command::Operate(Operator::Outdent, Target::Current) => outdent(ctx, &siblings(ctx, times), None),
|
Command::Operate(Operator::Outdent, Target::Current) => outdent(ctx, &siblings(ctx, times), None),
|
||||||
Command::ToggleFold => toggle_fold(ctx),
|
Command::ToggleFold => toggle_fold(ctx),
|
||||||
@@ -415,17 +414,16 @@ fn delete_children(ctx: &ViewContext<'_>, register: Option<Register>) -> Vec<Act
|
|||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `p`, `P` and `]p`: copies of a clip around the cursor's node, placed
|
/// `p` and `P`: copies of a clip under the cursor's node or after it,
|
||||||
/// where a new sibling or child would go, one below the other, each keeping
|
/// placed where a new child or sibling would go, one below the other, each
|
||||||
/// the clip's own layout.
|
/// keeping the clip's own layout.
|
||||||
pub fn paste(ctx: &ViewContext<'_>, clip: Clip, at: PasteAt, times: u32) -> Option<EditOp> {
|
pub fn paste(ctx: &ViewContext<'_>, clip: Clip, at: PasteAt, times: u32) -> Option<EditOp> {
|
||||||
let (doc, cursor) = (ctx.doc, ctx.cursor);
|
let (doc, cursor) = (ctx.doc, ctx.cursor);
|
||||||
let bounds = clip.bounds(|node| ctx.box_size(node))?;
|
let bounds = clip.bounds(|node| ctx.box_size(node))?;
|
||||||
let rects = ctx.box_rects();
|
let rects = ctx.box_rects();
|
||||||
let (spot, start) = match at {
|
let (spot, start) = match at {
|
||||||
PasteAt::After => (Spot::After(cursor), below_spot(cursor, bounds.size, &rects)),
|
|
||||||
PasteAt::Before => (Spot::Before(cursor), below_spot(cursor, bounds.size, &rects)),
|
|
||||||
PasteAt::Child => (Spot::LastChildOf(cursor), child_spot(doc, cursor, bounds.size, &rects)),
|
PasteAt::Child => (Spot::LastChildOf(cursor), child_spot(doc, cursor, bounds.size, &rects)),
|
||||||
|
PasteAt::Sibling => (Spot::After(cursor), below_spot(cursor, bounds.size, &rects)),
|
||||||
};
|
};
|
||||||
let mut offsets = Vec::new();
|
let mut offsets = Vec::new();
|
||||||
let mut pos = start;
|
let mut pos = start;
|
||||||
|
|||||||
+3
-3
@@ -494,8 +494,8 @@ impl Popup {
|
|||||||
Popup::Menu(Runs { list, runs })
|
Popup::Menu(Runs { list, runs })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// `:registers`: what each register holds. Enter pastes it after the
|
/// `:registers`: what each register holds. Enter pastes it under the
|
||||||
/// cursor's node.
|
/// cursor's node, as `p` does.
|
||||||
pub fn registers(registers: &[(char, String)], theme: &Theme) -> Popup {
|
pub fn registers(registers: &[(char, String)], theme: &Theme) -> Popup {
|
||||||
let key = Style::new().fg(theme.accent).add_modifier(Modifier::BOLD);
|
let key = Style::new().fg(theme.accent).add_modifier(Modifier::BOLD);
|
||||||
let muted = Style::new().fg(theme.muted);
|
let muted = Style::new().fg(theme.muted);
|
||||||
@@ -507,7 +507,7 @@ impl Popup {
|
|||||||
rows.push(ListRow::new(spans, what));
|
rows.push(ListRow::new(spans, what));
|
||||||
runs.push(Run::Keys(vec![Key::char('"'), Key::char(name), Key::char('p')]));
|
runs.push(Run::Keys(vec![Key::char('"'), Key::char(name), Key::char('p')]));
|
||||||
}
|
}
|
||||||
let footer = "Enter: paste it after the cursor's node · Esc: close";
|
let footer = "Enter: paste it under the cursor's node · Esc: close";
|
||||||
let list = ListPopup::new("registers", footer, rows, Place::Center { width: CONFLICT_WIDTH });
|
let list = ListPopup::new("registers", footer, rows, Place::Center { width: CONFLICT_WIDTH });
|
||||||
Popup::Menu(Runs { list, runs })
|
Popup::Menu(Runs { list, runs })
|
||||||
}
|
}
|
||||||
|
|||||||
+24
-22
@@ -17,18 +17,18 @@ fn yank_and_paste_nodes() {
|
|||||||
// yy on Raised beds: the node and its branch.
|
// yy on Raised beds: the node and its branch.
|
||||||
h.type_keys("glgjyy");
|
h.type_keys("glgjyy");
|
||||||
assert_eq!(h.message(), "yanked 3 nodes");
|
assert_eq!(h.message(), "yanked 3 nodes");
|
||||||
// p on Watering: the copy goes after it, with its children.
|
// P on Watering: the copy goes after it, with its children.
|
||||||
h.type_keys("gjp");
|
h.type_keys("gjP");
|
||||||
assert_eq!(top(&h), ["Soil", "Raised beds", "Watering", "Raised beds", "Kitchen"]);
|
assert_eq!(top(&h), ["Soil", "Raised beds", "Watering", "Raised beds", "Kitchen"]);
|
||||||
let copy = h.doc().children(h.node("Garden plans"))[3];
|
let copy = h.doc().children(h.node("Garden plans"))[3];
|
||||||
assert_eq!(h.app.current().cursor(), copy, "the cursor goes to what was pasted");
|
assert_eq!(h.app.current().cursor(), copy, "the cursor goes to what was pasted");
|
||||||
let titles: Vec<String> = h.doc().children(copy).iter().map(|&id| h.title(id)).collect();
|
let titles: Vec<String> = h.doc().children(copy).iter().map(|&id| h.title(id)).collect();
|
||||||
assert_eq!(titles, ["Cedar, untreated", "40 cm high"]);
|
assert_eq!(titles, ["Cedar, untreated", "40 cm high"]);
|
||||||
assert_eq!(h.doc().node(copy).unwrap().look.color.as_ref().map(|c| c.as_str()), Some("orange"));
|
assert_eq!(h.doc().node(copy).unwrap().look.color.as_ref().map(|c| c.as_str()), Some("orange"));
|
||||||
// ]p: as the last children; 2p: two copies.
|
// p: as the last children; 2P: two copies.
|
||||||
h.type_keys("gg]p");
|
h.type_keys("ggp");
|
||||||
assert_eq!(top(&h).len(), 6);
|
assert_eq!(top(&h).len(), 6);
|
||||||
h.type_keys("u2p");
|
h.type_keys("u2P");
|
||||||
assert_eq!(h.message(), "pasted 6 nodes");
|
assert_eq!(h.message(), "pasted 6 nodes");
|
||||||
assert_eq!(top(&h), ["Soil", "Raised beds", "Watering", "Raised beds", "Kitchen"]);
|
assert_eq!(top(&h), ["Soil", "Raised beds", "Watering", "Raised beds", "Kitchen"]);
|
||||||
assert_eq!(h.doc().loose().len(), 4, "after the root: loose nodes, before the two there were");
|
assert_eq!(h.doc().loose().len(), 4, "after the root: loose nodes, before the two there were");
|
||||||
@@ -39,32 +39,34 @@ fn yank_and_paste_nodes() {
|
|||||||
#[test]
|
#[test]
|
||||||
fn deletes_keep_what_they_take() {
|
fn deletes_keep_what_they_take() {
|
||||||
let mut h = Harness::new();
|
let mut h = Harness::new();
|
||||||
// dd then p: the branch moves.
|
// dd then P: the branch moves, after Watering.
|
||||||
h.type_keys("glgjdd");
|
h.type_keys("glgjdd");
|
||||||
assert_eq!(h.cursor(), "Watering");
|
assert_eq!(h.cursor(), "Watering");
|
||||||
h.type_keys("p");
|
h.type_keys("P");
|
||||||
assert_eq!(top(&h), ["Soil", "Watering", "Raised beds", "Kitchen"]);
|
assert_eq!(top(&h), ["Soil", "Watering", "Raised beds", "Kitchen"]);
|
||||||
assert_eq!(h.children("Raised beds"), ["Cedar, untreated", "40 cm high"]);
|
assert_eq!(h.children("Raised beds"), ["Cedar, untreated", "40 cm high"]);
|
||||||
// x keeps just the node: its children stay behind.
|
// x keeps just the node: its children stay behind.
|
||||||
h.type_keys("x");
|
h.type_keys("x");
|
||||||
assert_eq!(top(&h), ["Soil", "Watering", "Cedar, untreated", "40 cm high", "Kitchen"]);
|
assert_eq!(top(&h), ["Soil", "Watering", "Cedar, untreated", "40 cm high", "Kitchen"]);
|
||||||
h.type_keys("ggP");
|
// p: under the node, as its last child.
|
||||||
assert_eq!(h.message(), "nothing goes before the root");
|
h.type_keys("ggglp");
|
||||||
h.type_keys("glP");
|
assert_eq!(h.children("Soil"), ["Raised beds"]);
|
||||||
assert_eq!(top(&h)[0], "Raised beds", "P: before Soil");
|
|
||||||
assert!(h.children("Raised beds").is_empty());
|
assert!(h.children("Raised beds").is_empty());
|
||||||
|
// P on the root: a loose node, where o adds one.
|
||||||
|
h.type_keys("ggP");
|
||||||
|
assert_eq!((h.cursor().as_str(), h.doc().loose().len()), ("Raised beds", 3));
|
||||||
// Named registers, and the black hole.
|
// Named registers, and the black hole.
|
||||||
h.type_keys("gl\"ayy");
|
h.type_keys("\"ayy");
|
||||||
assert_eq!(h.message(), "yanked 1 node into \"a");
|
assert_eq!(h.message(), "yanked 1 node into \"a");
|
||||||
h.type_keys("gj\"_dd");
|
h.type_keys("gggl\"_x");
|
||||||
assert_eq!(h.message(), "deleted 1 node · u to undo");
|
assert_eq!(h.message(), "deleted 1 node · u to undo");
|
||||||
h.type_keys("gg]p");
|
h.type_keys("ggp");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
h.children("Garden plans").last().map(String::as_str),
|
h.children("Garden plans").last().map(String::as_str),
|
||||||
Some("Raised beds"),
|
Some("Raised beds"),
|
||||||
"\"_ kept nothing"
|
"\"_ kept nothing"
|
||||||
);
|
);
|
||||||
h.type_keys("gg\"a]p");
|
h.type_keys("gg\"ap");
|
||||||
assert_eq!(h.children("Garden plans").iter().filter(|title| *title == "Raised beds").count(), 3);
|
assert_eq!(h.children("Garden plans").iter().filter(|title| *title == "Raised beds").count(), 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -81,7 +83,7 @@ fn the_clipboard_holds_markdown() {
|
|||||||
assert_eq!(h.doc().node(pasted).unwrap().look.color.as_ref().map(|c| c.as_str()), Some("orange"));
|
assert_eq!(h.doc().node(pasted).unwrap().look.color.as_ref().map(|c| c.as_str()), Some("orange"));
|
||||||
// Text another app put there: a node per section, tags and body too.
|
// Text another app put there: a node per section, tags and body too.
|
||||||
h.app.registers.clipboard().write("## Mulch\n---\n- todo\n---\nStraw or leaves.\n\n### Straw\n").unwrap();
|
h.app.registers.clipboard().write("## Mulch\n---\n- todo\n---\nStraw or leaves.\n\n### Straw\n").unwrap();
|
||||||
h.type_keys("gg\"+]p");
|
h.type_keys("gg\"+p");
|
||||||
assert_eq!(h.cursor(), "Mulch");
|
assert_eq!(h.cursor(), "Mulch");
|
||||||
assert_eq!((h.tags("Mulch").as_str(), h.body("Mulch").as_str()), ("#todo", "Straw or leaves."));
|
assert_eq!((h.tags("Mulch").as_str(), h.body("Mulch").as_str()), ("#todo", "Straw or leaves."));
|
||||||
assert_eq!(h.children("Mulch"), ["Straw"]);
|
assert_eq!(h.children("Mulch"), ["Straw"]);
|
||||||
@@ -97,9 +99,9 @@ fn text_and_nodes_paste_into_each_other() {
|
|||||||
// A word yanked in a title, pasted on nodes: a node.
|
// A word yanked in a title, pasted on nodes: a node.
|
||||||
h.type_keys("gli<Esc>yiw<Esc>ggp");
|
h.type_keys("gli<Esc>yiw<Esc>ggp");
|
||||||
assert_eq!(h.cursor(), "Soil");
|
assert_eq!(h.cursor(), "Soil");
|
||||||
assert_eq!(h.doc().loose().len(), 3, "after the root: a loose node");
|
assert_eq!(top(&h).last().map(String::as_str), Some("Soil"), "under the root, at the end");
|
||||||
// Nodes pasted into a title: their titles.
|
// Nodes pasted into a title: their titles.
|
||||||
h.type_keys("gg]pu");
|
h.type_keys("ggpu");
|
||||||
h.type_keys("glgjyyggi <Esc>p");
|
h.type_keys("glgjyyggi <Esc>p");
|
||||||
assert_eq!(h.draft(), "Garden plans Raised beds Cedar, untreated 40 cm high");
|
assert_eq!(h.draft(), "Garden plans Raised beds Cedar, untreated 40 cm high");
|
||||||
}
|
}
|
||||||
@@ -141,10 +143,10 @@ fn visual_mode_takes_in_a_rectangle() {
|
|||||||
h.type_keys("d");
|
h.type_keys("d");
|
||||||
assert_eq!(top(&h), ["Kitchen"]);
|
assert_eq!(top(&h), ["Kitchen"]);
|
||||||
assert_eq!(h.message(), "deleted 8 nodes · u to undo");
|
assert_eq!(h.message(), "deleted 8 nodes · u to undo");
|
||||||
// What went is in the register: ]p puts it back under the root, where
|
// What went is in the register: p puts it back under the root, where
|
||||||
// the cursor went.
|
// the cursor went.
|
||||||
assert_eq!(h.cursor(), "Garden plans");
|
assert_eq!(h.cursor(), "Garden plans");
|
||||||
h.type_keys("]p");
|
h.type_keys("p");
|
||||||
assert_eq!(top(&h), ["Kitchen", "Soil", "Raised beds", "Watering"]);
|
assert_eq!(top(&h), ["Kitchen", "Soil", "Raised beds", "Watering"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -393,9 +395,9 @@ fn registers_list_and_paste() {
|
|||||||
let screen = h.screen();
|
let screen = h.screen();
|
||||||
assert!(screen.contains("\"a 1 node") && screen.contains("\"b 3 nodes"), "{screen}");
|
assert!(screen.contains("\"a 1 node") && screen.contains("\"b 3 nodes"), "{screen}");
|
||||||
assert!(screen.contains("\"+ the system clipboard"));
|
assert!(screen.contains("\"+ the system clipboard"));
|
||||||
// Enter on "a: pasted after the cursor's node.
|
// Enter on "a: pasted under the cursor's node.
|
||||||
h.type_keys("j<CR>");
|
h.type_keys("j<CR>");
|
||||||
assert_eq!(top(&h), ["Soil", "Raised beds", "Soil", "Watering", "Kitchen"]);
|
assert_eq!(h.children("Raised beds"), ["Cedar, untreated", "40 cm high", "Soil"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|||||||
+1
-1
@@ -1,5 +1,5 @@
|
|||||||
//! Nodes into registers and back: `yy` and the deletes keep nodes in a
|
//! Nodes into registers and back: `yy` and the deletes keep nodes in a
|
||||||
//! register, `p` `P` `]p` paste them (or a register's text, made into
|
//! register, `p` and `P` paste them (or a register's text, made into
|
||||||
//! nodes). See [`registers`](super::registers).
|
//! nodes). See [`registers`](super::registers).
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
|
|||||||
@@ -208,9 +208,8 @@ const NORMAL: &[DefaultBinding] = &[
|
|||||||
operator("y", Op::Yank),
|
operator("y", Op::Yank),
|
||||||
operator(">", Op::Indent),
|
operator(">", Op::Indent),
|
||||||
operator("<lt>", Op::Outdent),
|
operator("<lt>", Op::Outdent),
|
||||||
bind("p", C::PasteAfter),
|
bind("p", C::PasteAsChild),
|
||||||
bind("P", C::PasteBefore),
|
bind("P", C::PasteAsSibling),
|
||||||
bind("]p", C::PasteAsChild),
|
|
||||||
bind("u", C::Undo),
|
bind("u", C::Undo),
|
||||||
bind("<C-r>", C::Redo),
|
bind("<C-r>", C::Redo),
|
||||||
bind(".", C::Repeat),
|
bind(".", C::Repeat),
|
||||||
|
|||||||
@@ -254,9 +254,14 @@ pub enum Command {
|
|||||||
EditBodyAtStart,
|
EditBodyAtStart,
|
||||||
/// `x`: delete just this node; its children move up.
|
/// `x`: delete just this node; its children move up.
|
||||||
DeleteNode,
|
DeleteNode,
|
||||||
|
/// Inside text: paste after the text cursor.
|
||||||
PasteAfter,
|
PasteAfter,
|
||||||
|
/// Inside text: paste before the text cursor.
|
||||||
PasteBefore,
|
PasteBefore,
|
||||||
|
/// `p` on nodes: paste as the node's last children.
|
||||||
PasteAsChild,
|
PasteAsChild,
|
||||||
|
/// `P` on nodes: paste as the node's next siblings.
|
||||||
|
PasteAsSibling,
|
||||||
Undo,
|
Undo,
|
||||||
Redo,
|
Redo,
|
||||||
Repeat,
|
Repeat,
|
||||||
@@ -468,7 +473,8 @@ pub const COMMANDS: &[CommandInfo] = &[
|
|||||||
info("outdent-selection", C::Operate(Op::Outdent, Target::Selection), "outdent the selection"),
|
info("outdent-selection", C::Operate(Op::Outdent, Target::Selection), "outdent the selection"),
|
||||||
info("paste-after", C::PasteAfter, "paste after"),
|
info("paste-after", C::PasteAfter, "paste after"),
|
||||||
info("paste-before", C::PasteBefore, "paste before"),
|
info("paste-before", C::PasteBefore, "paste before"),
|
||||||
info("paste-as-child", C::PasteAsChild, "paste as a child"),
|
info("paste-as-child", C::PasteAsChild, "paste as children"),
|
||||||
|
info("paste-as-sibling", C::PasteAsSibling, "paste as siblings below"),
|
||||||
info("undo", C::Undo, "undo"),
|
info("undo", C::Undo, "undo"),
|
||||||
info("redo", C::Redo, "redo"),
|
info("redo", C::Redo, "redo"),
|
||||||
info("repeat", C::Repeat, "repeat the last change"),
|
info("repeat", C::Repeat, "repeat the last change"),
|
||||||
|
|||||||
+2
-2
@@ -389,11 +389,11 @@ mod tests {
|
|||||||
assert_eq!(type_keys(&mut engine, &keymap, "12j"), run(Command::Move(Motion::Down), Some(12), None));
|
assert_eq!(type_keys(&mut engine, &keymap, "12j"), run(Command::Move(Motion::Down), Some(12), None));
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
type_keys(&mut engine, &keymap, "\"+p"),
|
type_keys(&mut engine, &keymap, "\"+p"),
|
||||||
run(Command::PasteAfter, None, Some(Register::Clipboard))
|
run(Command::PasteAsChild, None, Some(Register::Clipboard))
|
||||||
);
|
);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
type_keys(&mut engine, &keymap, "3\"ap"),
|
type_keys(&mut engine, &keymap, "3\"ap"),
|
||||||
run(Command::PasteAfter, Some(3), Some(Register::Named('a')))
|
run(Command::PasteAsChild, Some(3), Some(Register::Named('a')))
|
||||||
);
|
);
|
||||||
assert_eq!(type_keys(&mut engine, &keymap, "gq"), Outcome::Unknown("gq".into()));
|
assert_eq!(type_keys(&mut engine, &keymap, "gq"), Outcome::Unknown("gq".into()));
|
||||||
assert_eq!(type_keys(&mut engine, &keymap, "z<Esc>"), Outcome::Cancelled);
|
assert_eq!(type_keys(&mut engine, &keymap, "z<Esc>"), Outcome::Cancelled);
|
||||||
|
|||||||
Reference in new issue
Block a user