Add visual mode, node registers, search and the jump list (stage 8c)
The rest of vim, on nodes. Visual mode takes in what lies between where it started and the cursor: on the canvas, every node the rectangle from one end's box to the other's touches; in the outline and the Note view, the nodes in between in reading order. V takes whole branches, Ctrl+click and Ctrl+drag pick with the mouse, and the operators take exactly what's selected: d, y, > and <, M, and the pickers on every node at once. Registers now hold text or nodes, so yy, dd and x keep what they take and p, P and ]p paste it, layout and links included. "+ is the system clipboard through arboard: nodes go there as Markdown in the user's format (## headings, a --- tag list, the body), and come back whole while the clipboard still holds them. clipboard = "unnamedplus" makes plain yanks use it, as in vim. . repeats the last change made with keys, with the text typed after it. / opens a Telescope-style search: fuzzy matches over titles, tags and bodies, best first, with the note of the one you're on beside them; n and N go on with it, and :find searches straight away. Each pane keeps a jump list for Ctrl-o and Ctrl-i that crosses documents and reopens closed ones. Capital marks lead into any document and, like the small ones, are kept in memory.ron. gd follows a cross-link, and :marks, :jumps and :registers list what they hold. Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
1 parent
abe3dc1d84
commit
7bec5bf3fc
45 files changed
+3922
-272
No files matched your search
+77
-3
@@ -6,12 +6,14 @@
|
||||
//! [`Buffer::apply`]: super::buffer::Buffer::apply
|
||||
|
||||
use super::documents::BufferId;
|
||||
use super::jumps::Place;
|
||||
use super::panes::Arrange;
|
||||
use super::popup::{MenuFor, PickKind};
|
||||
use super::repeat::Look;
|
||||
use super::text_edit::StartEdit;
|
||||
use crate::command::parse::SetArg;
|
||||
use crate::config::ConfigFile;
|
||||
use crate::input::command::Command;
|
||||
use crate::input::command::{Command, Register};
|
||||
use crate::input::key::Key;
|
||||
use crate::model::{Direction, EditOp, Group, NodeId, Title};
|
||||
use crate::view::ViewKind;
|
||||
@@ -34,6 +36,11 @@ pub struct Message {
|
||||
pub tone: Tone,
|
||||
}
|
||||
|
||||
/// "1 node", "3 nodes".
|
||||
pub fn nodes(count: usize) -> String {
|
||||
if count == 1 { "1 node".to_string() } else { format!("{count} nodes") }
|
||||
}
|
||||
|
||||
impl Message {
|
||||
pub fn info(text: impl Into<String>) -> Message {
|
||||
Message { text: text.into(), tone: Tone::Info }
|
||||
@@ -101,8 +108,20 @@ pub enum AppAction {
|
||||
EndEdit,
|
||||
/// Put the text cursor here, in the text being edited (a click).
|
||||
TextCursor(usize),
|
||||
/// Move mode: hjkl moves the cursor's branch.
|
||||
EnterMoveMode,
|
||||
/// Visual mode, `V` (`branches`) or `v`; in visual mode, switches
|
||||
/// between the two.
|
||||
Visual {
|
||||
branches: bool,
|
||||
},
|
||||
/// In visual mode: the cursor goes to the other end (`o`).
|
||||
SwapEnds,
|
||||
/// A node into the selection, or out of it (a Ctrl+click).
|
||||
ToggleSelected(NodeId),
|
||||
/// Nodes into the selection (a Ctrl+drag).
|
||||
SelectAlso(Vec<NodeId>),
|
||||
/// Move mode: hjkl moves the cursor's branch, or these nodes (a
|
||||
/// selection's).
|
||||
EnterMoveMode(Vec<NodeId>),
|
||||
/// In move mode: the whole branch, or just the node.
|
||||
ToggleWhole,
|
||||
/// Back to normal mode.
|
||||
@@ -119,6 +138,22 @@ pub enum AppAction {
|
||||
/// Keys, as if typed: for a key that waits for more (`m` waits for a
|
||||
/// mark's letter).
|
||||
Type(Vec<Key>),
|
||||
/// Keep nodes in a register (`yy`, and before a delete): exactly
|
||||
/// `nodes`, or (`branches`) each with its whole branch.
|
||||
Yank {
|
||||
register: Option<Register>,
|
||||
nodes: Vec<NodeId>,
|
||||
branches: bool,
|
||||
},
|
||||
/// Paste what a register holds (`p`, `P`, `]p`): its nodes, or its text
|
||||
/// made into nodes, `times` copies.
|
||||
Paste {
|
||||
register: Option<Register>,
|
||||
at: PasteAt,
|
||||
times: u32,
|
||||
},
|
||||
/// A value was picked in a picker: `.` can put it on another node.
|
||||
Picked(Look),
|
||||
/// Focus mode: Open branches act like Auto ones.
|
||||
ToggleFocus,
|
||||
ToggleWhichKey,
|
||||
@@ -128,6 +163,34 @@ pub enum AppAction {
|
||||
// Popups.
|
||||
/// Every key and command, with this already searched for.
|
||||
OpenHelp(String),
|
||||
/// `/`: the search.
|
||||
OpenSearch,
|
||||
/// A search went somewhere: `n` and `N` go on with it.
|
||||
Searched(String),
|
||||
/// `Ctrl-o` (`back`) and `Ctrl-i`: through the focused pane's jump list.
|
||||
Travel {
|
||||
back: bool,
|
||||
times: u32,
|
||||
},
|
||||
/// `n` and `N`: the next or previous match of the last search.
|
||||
FindAgain {
|
||||
forward: bool,
|
||||
times: u32,
|
||||
},
|
||||
/// `:find`: straight to the best match.
|
||||
Find(String),
|
||||
/// A capital mark on the cursor's node (`mA`).
|
||||
SetFileMark(char),
|
||||
/// To a capital mark, in any document (`'A`).
|
||||
JumpToFileMark(char),
|
||||
/// To a place from the jump list (`:jumps`).
|
||||
GoToPlace(Place),
|
||||
/// `:marks`, `:jumps` and `:registers`.
|
||||
OpenMarks,
|
||||
OpenJumps,
|
||||
OpenRegisters,
|
||||
/// `gd` on a node with several cross-links: which one to follow.
|
||||
OpenLinks,
|
||||
/// The cursor's body in a card beside it.
|
||||
OpenCard,
|
||||
OpenPicker(PickKind),
|
||||
@@ -193,6 +256,17 @@ pub enum AppAction {
|
||||
Say(Message),
|
||||
}
|
||||
|
||||
/// Where `p` and its kin paste, from the cursor's node.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum PasteAt {
|
||||
/// Its next siblings (`p`).
|
||||
After,
|
||||
/// Its siblings before it (`P`).
|
||||
Before,
|
||||
/// Its last children (`]p`).
|
||||
Child,
|
||||
}
|
||||
|
||||
/// What `:w` and its kin save.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub enum SaveWhich {
|
||||
|
||||
Reference in new issue
Block a user