mirror of
https://github.com/zaphar/sheetsui.git
synced 2025-07-22 04:39:48 -04:00
wip: copy/paste from system clipboard
This commit is contained in:
parent
563a885b70
commit
8a76a031cb
@ -18,6 +18,7 @@ The currently supported commands are:
|
||||
* `help [topic]` Display help for a given topic.
|
||||
* `export-csv <path>` Export the current sheet to a csv file at `<path>`.
|
||||
* `quit` Quits the application. `q` is a shorthand alias for this command.
|
||||
* `system-paste` Paste from the system clipboard
|
||||
|
||||
<aside>Note that in the case of `quit` and `edit` that we do not currently
|
||||
prompt you if the current spreadsheet has not been saved yet. So your changes
|
||||
|
@ -49,3 +49,5 @@ Range selections made from navigation mode will be available to paste into a Cel
|
||||
<aside>Note that for `q` this will not currently prompt you if the sheet is not
|
||||
saved.</aside>
|
||||
|
||||
Note also that copy paste works with the system clipboard.
|
||||
|
||||
|
@ -5,8 +5,8 @@ select mode from CellEdit mode with `CTRL-r`.
|
||||
|
||||
* `h`, `j`, `k`, `l` will navigate around the sheet.
|
||||
* `Ctrl-n`, `Ctrl-p` will navigate between sheets.
|
||||
* `Ctrl-c`, `y` Copy the cell or range contents.
|
||||
* `Ctrl-Shift-C`, 'Y' Copy the cell or range formatted content.
|
||||
* `Ctrl-c`, `y` Copy the cell or range formatted contents.
|
||||
* `Ctrl-Shift-C`, 'Y' Copy the cell or range content.
|
||||
* `The spacebar will select the start and end of the range respectively.
|
||||
* `d` will delete the contents of the range leaving any style untouched
|
||||
* `D` will delete the contents of the range including any style
|
||||
|
@ -16,6 +16,7 @@ pub enum Cmd<'a> {
|
||||
Edit(&'a str),
|
||||
Help(Option<&'a str>),
|
||||
ExportCsv(&'a str),
|
||||
SystemPaste,
|
||||
Quit,
|
||||
}
|
||||
|
||||
@ -68,6 +69,9 @@ pub fn parse<'cmd, 'i: 'cmd>(input: &'i str) -> Result<Option<Cmd<'cmd>>, &'stat
|
||||
if let Some(cmd) = try_consume_color_cell(cursor.clone())? {
|
||||
return Ok(Some(cmd));
|
||||
}
|
||||
if let Some(cmd) = try_consume_system_paste(cursor.clone())? {
|
||||
return Ok(Some(cmd));
|
||||
}
|
||||
Ok(None)
|
||||
}
|
||||
|
||||
@ -316,6 +320,22 @@ fn try_consume_quit<'cmd, 'i: 'cmd>(
|
||||
return Ok(Some(Cmd::Quit));
|
||||
}
|
||||
|
||||
fn try_consume_system_paste<'cmd, 'i: 'cmd>(
|
||||
mut input: StrCursor<'i>,
|
||||
) -> Result<Option<Cmd<'cmd>>, &'static str> {
|
||||
const LONG: &'static str = "system-paste";
|
||||
|
||||
if compare(input.clone(), LONG) {
|
||||
input.seek(LONG.len());
|
||||
} else {
|
||||
return Ok(None);
|
||||
}
|
||||
if input.remaining() > 0 {
|
||||
return Err("Invalid command: system-paste does not take an argument");
|
||||
}
|
||||
return Ok(Some(Cmd::SystemPaste));
|
||||
}
|
||||
|
||||
fn try_consume_rename_sheet<'cmd, 'i: 'cmd>(
|
||||
mut input: StrCursor<'i>,
|
||||
) -> Result<Option<Cmd<'cmd>>, &'static str> {
|
||||
|
@ -513,6 +513,12 @@ impl<'ws> Workspace<'ws> {
|
||||
.set_cell_style(&[("fill.bg_color", &color)], &area)?;
|
||||
Ok(None)
|
||||
}
|
||||
Ok(Some(Cmd::SystemPaste)) => {
|
||||
let rows = self.get_rows_from_system_cipboard()?;
|
||||
self.state.clipboard = Some(ClipboardContents::Range(rows));
|
||||
self.paste_range()?;
|
||||
Ok(None)
|
||||
}
|
||||
Ok(None) => {
|
||||
self.enter_dialog_mode(Markdown::from_str(&format!(
|
||||
"Unrecognized commmand {}",
|
||||
@ -607,19 +613,19 @@ impl<'ws> Workspace<'ws> {
|
||||
Ok(())
|
||||
})?;
|
||||
}
|
||||
KeyCode::Char('C') if key.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||
KeyCode::Char('c') if key.modifiers.contains(KeyModifiers::CONTROL) => {
|
||||
self.copy_range(true)?;
|
||||
self.exit_range_select_mode()?;
|
||||
}
|
||||
KeyCode::Char('Y') => {
|
||||
self.copy_range(true)?;
|
||||
self.exit_range_select_mode()?;
|
||||
}
|
||||
KeyCode::Char('c') if key.modifiers == KeyModifiers::CONTROL => {
|
||||
self.copy_range(false)?;
|
||||
self.exit_range_select_mode()?;
|
||||
}
|
||||
KeyCode::Char('y') => {
|
||||
self.copy_range(true)?;
|
||||
self.exit_range_select_mode()?;
|
||||
}
|
||||
KeyCode::Char('C') if key.modifiers == KeyModifiers::CONTROL => {
|
||||
self.copy_range(false)?;
|
||||
self.exit_range_select_mode()?;
|
||||
}
|
||||
KeyCode::Char('Y') => {
|
||||
self.copy_range(false)?;
|
||||
self.exit_range_select_mode()?;
|
||||
}
|
||||
@ -662,7 +668,9 @@ impl<'ws> Workspace<'ws> {
|
||||
}
|
||||
// TODO(zaphar): Rethink this a bit perhaps?
|
||||
let mut cb = Clipboard::new()?;
|
||||
let (html, csv) = self.book.range_to_clipboard_content(AddressRange { start, end })?;
|
||||
let (html, csv) = self
|
||||
.book
|
||||
.range_to_clipboard_content(AddressRange { start, end })?;
|
||||
cb.set_html(html, Some(csv))?;
|
||||
self.state.clipboard = Some(ClipboardContents::Range(rows));
|
||||
}
|
||||
@ -677,6 +685,26 @@ impl<'ws> Workspace<'ws> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn get_rows_from_system_cipboard(&mut self) -> Result<Vec<Vec<String>>, anyhow::Error> {
|
||||
use arboard::Clipboard;
|
||||
let mut cb = Clipboard::new()?;
|
||||
let txt = match cb.get_text() {
|
||||
Ok(txt) => txt,
|
||||
Err(e) => return Err(anyhow!(e)),
|
||||
};
|
||||
let reader = csv::Reader::from_reader(txt.as_bytes());
|
||||
let mut rows = Vec::new();
|
||||
for rec in reader.into_byte_records() {
|
||||
let record = rec?;
|
||||
let mut row = Vec::with_capacity(record.len());
|
||||
for i in 0..record.len() {
|
||||
row.push(String::from_utf8_lossy(record.get(i).expect("Unexpected failure to get cell row")).to_string());
|
||||
};
|
||||
rows.push(row);
|
||||
}
|
||||
Ok(rows)
|
||||
}
|
||||
|
||||
fn update_range_selection(&mut self) -> Result<bool, anyhow::Error> {
|
||||
Ok(if self.state.range_select.start.is_none() {
|
||||
self.state.range_select.start = Some(self.book.location.clone());
|
||||
|
Loading…
x
Reference in New Issue
Block a user