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]>
63 lines
1.9 KiB
Rust
63 lines
1.9 KiB
Rust
//! The system clipboard, behind the `"+` register (and behind every yank
|
|
//! and paste with `clipboard = "unnamedplus"`). It's opened the first time
|
|
//! it's used, and kept open: on Linux, text copied there lasts as long as
|
|
//! cumulus runs, or until a clipboard manager takes it over.
|
|
//!
|
|
//! The tests keep their clipboard in memory, so they never touch yours.
|
|
|
|
/// The system clipboard.
|
|
#[derive(Default)]
|
|
pub struct Clipboard {
|
|
#[cfg(not(test))]
|
|
system: Option<arboard::Clipboard>,
|
|
#[cfg(test)]
|
|
text: Option<String>,
|
|
}
|
|
|
|
impl std::fmt::Debug for Clipboard {
|
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
f.write_str("Clipboard")
|
|
}
|
|
}
|
|
|
|
#[cfg(not(test))]
|
|
impl Clipboard {
|
|
/// The text on the clipboard.
|
|
pub fn read(&mut self) -> Result<String, String> {
|
|
self.open()?.get_text().map_err(problem)
|
|
}
|
|
|
|
/// Puts text on the clipboard.
|
|
pub fn write(&mut self, text: &str) -> Result<(), String> {
|
|
self.open()?.set_text(text.to_string()).map_err(problem)
|
|
}
|
|
|
|
fn open(&mut self) -> Result<&mut arboard::Clipboard, String> {
|
|
if self.system.is_none() {
|
|
self.system = Some(arboard::Clipboard::new().map_err(problem)?);
|
|
}
|
|
self.system.as_mut().ok_or_else(|| "the clipboard isn't available".to_string())
|
|
}
|
|
}
|
|
|
|
/// What went wrong with the clipboard, in words.
|
|
#[cfg(not(test))]
|
|
fn problem(error: arboard::Error) -> String {
|
|
match error {
|
|
arboard::Error::ContentNotAvailable => "the clipboard holds no text".to_string(),
|
|
error => format!("the clipboard isn't available: {error}"),
|
|
}
|
|
}
|
|
|
|
#[cfg(test)]
|
|
impl Clipboard {
|
|
pub fn read(&mut self) -> Result<String, String> {
|
|
self.text.clone().ok_or_else(|| "the clipboard holds no text".to_string())
|
|
}
|
|
|
|
pub fn write(&mut self, text: &str) -> Result<(), String> {
|
|
self.text = Some(text.to_string());
|
|
Ok(())
|
|
}
|
|
}
|