Start on copy-paste
This commit is contained in:
parent
7469240a2e
commit
f4c1ffc329
6 changed files with 87 additions and 9 deletions
|
@ -1215,6 +1215,10 @@ impl MutableAppContext {
|
|||
pub fn copy(&self, text: &str) {
|
||||
self.platform.copy(text);
|
||||
}
|
||||
|
||||
pub fn paste(&self) -> Option<String> {
|
||||
self.platform.paste()
|
||||
}
|
||||
}
|
||||
|
||||
impl ReadModel for MutableAppContext {
|
||||
|
|
|
@ -26,6 +26,7 @@ use std::{
|
|||
path::PathBuf,
|
||||
ptr,
|
||||
rc::Rc,
|
||||
slice,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
|
@ -299,6 +300,19 @@ impl platform::Platform for MacPlatform {
|
|||
}
|
||||
}
|
||||
|
||||
fn paste(&self) -> Option<String> {
|
||||
unsafe {
|
||||
let pasteboard = NSPasteboard::generalPasteboard(nil);
|
||||
let data = pasteboard.dataForType(NSPasteboardTypeString);
|
||||
if data == nil {
|
||||
None
|
||||
} else {
|
||||
let bytes = slice::from_raw_parts(data.bytes() as *mut u8, data.length() as usize);
|
||||
Some(String::from_utf8_unchecked(bytes.to_vec()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_menus(&self, menus: Vec<Menu>) {
|
||||
unsafe {
|
||||
let app: id = msg_send![APP_CLASS, sharedApplication];
|
||||
|
|
|
@ -43,6 +43,7 @@ pub trait Platform {
|
|||
fn prompt_for_paths(&self, options: PathPromptOptions) -> Option<Vec<PathBuf>>;
|
||||
fn quit(&self);
|
||||
fn copy(&self, text: &str);
|
||||
fn paste(&self) -> Option<String>;
|
||||
fn set_menus(&self, menus: Vec<Menu>);
|
||||
}
|
||||
|
||||
|
|
|
@ -73,6 +73,10 @@ impl super::Platform for Platform {
|
|||
}
|
||||
|
||||
fn copy(&self, _: &str) {}
|
||||
|
||||
fn paste(&self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl Window {
|
||||
|
|
|
@ -563,10 +563,13 @@ impl Buffer {
|
|||
self.chars().collect()
|
||||
}
|
||||
|
||||
pub fn text_for_range<T: ToOffset>(&self, range: Range<T>) -> Result<String> {
|
||||
pub fn text_for_range<'a, T: ToOffset>(
|
||||
&'a self,
|
||||
range: Range<T>,
|
||||
) -> Result<impl 'a + Iterator<Item = char>> {
|
||||
let start = range.start.to_offset(self)?;
|
||||
let end = range.end.to_offset(self)?;
|
||||
Ok(self.chars_at(start)?.take(end - start).collect())
|
||||
Ok(self.chars_at(start)?.take(end - start))
|
||||
}
|
||||
|
||||
pub fn chars(&self) -> CharIter {
|
||||
|
@ -2470,13 +2473,9 @@ mod tests {
|
|||
let old_len = old_range.end - old_range.start;
|
||||
let new_len = new_range.end - new_range.start;
|
||||
let old_start = (old_range.start as isize + delta) as usize;
|
||||
|
||||
let new_text: String = buffer.text_for_range(new_range).unwrap().collect();
|
||||
old_buffer
|
||||
.edit(
|
||||
Some(old_start..old_start + old_len),
|
||||
buffer.text_for_range(new_range).unwrap(),
|
||||
None,
|
||||
)
|
||||
.edit(Some(old_start..old_start + old_len), new_text, None)
|
||||
.unwrap();
|
||||
|
||||
delta += new_len as isize - old_len as isize;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use super::{
|
||||
buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point,
|
||||
Selection, SelectionSetId, ToOffset,
|
||||
Selection, SelectionSetId, ToOffset, ToPoint,
|
||||
};
|
||||
use crate::{settings::Settings, watch, workspace};
|
||||
use anyhow::Result;
|
||||
|
@ -28,6 +28,9 @@ pub fn init(app: &mut MutableAppContext) {
|
|||
app.add_bindings(vec![
|
||||
Binding::new("backspace", "buffer:backspace", Some("BufferView")),
|
||||
Binding::new("enter", "buffer:newline", Some("BufferView")),
|
||||
Binding::new("cmd-x", "buffer:cut", Some("BufferView")),
|
||||
Binding::new("cmd-c", "buffer:copy", Some("BufferView")),
|
||||
Binding::new("cmd-v", "buffer:paste", Some("BufferView")),
|
||||
Binding::new("cmd-z", "buffer:undo", Some("BufferView")),
|
||||
Binding::new("cmd-shift-Z", "buffer:redo", Some("BufferView")),
|
||||
Binding::new("up", "buffer:move_up", Some("BufferView")),
|
||||
|
@ -54,6 +57,9 @@ pub fn init(app: &mut MutableAppContext) {
|
|||
app.add_action("buffer:insert", BufferView::insert);
|
||||
app.add_action("buffer:newline", BufferView::newline);
|
||||
app.add_action("buffer:backspace", BufferView::backspace);
|
||||
app.add_action("buffer:cut", BufferView::cut);
|
||||
app.add_action("buffer:copy", BufferView::copy);
|
||||
app.add_action("buffer:paste", BufferView::paste);
|
||||
app.add_action("buffer:undo", BufferView::undo);
|
||||
app.add_action("buffer:redo", BufferView::redo);
|
||||
app.add_action("buffer:move_up", BufferView::move_up);
|
||||
|
@ -449,6 +455,56 @@ impl BufferView {
|
|||
self.end_transaction(ctx);
|
||||
}
|
||||
|
||||
pub fn cut(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||
self.start_transaction(ctx);
|
||||
let mut text = String::new();
|
||||
let mut selections = self.selections(ctx.app()).to_vec();
|
||||
{
|
||||
let buffer = self.buffer.read(ctx);
|
||||
let max_point = buffer.max_point();
|
||||
for selection in &mut selections {
|
||||
let mut start = selection.start.to_point(buffer).expect("invalid start");
|
||||
let mut end = selection.end.to_point(buffer).expect("invalid end");
|
||||
if start == end {
|
||||
start = Point::new(start.row, 0);
|
||||
end = cmp::min(max_point, Point::new(start.row + 1, 0));
|
||||
selection.start = buffer.anchor_before(start).unwrap();
|
||||
selection.end = buffer.anchor_after(end).unwrap();
|
||||
}
|
||||
text.extend(buffer.text_for_range(start..end).unwrap());
|
||||
}
|
||||
}
|
||||
self.update_selections(selections, ctx);
|
||||
self.changed_selections(ctx);
|
||||
self.insert(&String::new(), ctx);
|
||||
self.end_transaction(ctx);
|
||||
|
||||
ctx.app_mut().copy(&text);
|
||||
}
|
||||
|
||||
pub fn copy(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||
let buffer = self.buffer.read(ctx);
|
||||
let max_point = buffer.max_point();
|
||||
let mut text = String::new();
|
||||
for selection in self.selections(ctx.app()) {
|
||||
let mut start = selection.start.to_point(buffer).expect("invalid start");
|
||||
let mut end = selection.end.to_point(buffer).expect("invalid end");
|
||||
if start == end {
|
||||
start = Point::new(start.row, 0);
|
||||
end = cmp::min(max_point, Point::new(start.row + 1, 0));
|
||||
}
|
||||
text.extend(buffer.text_for_range(start..end).unwrap());
|
||||
}
|
||||
|
||||
ctx.app_mut().copy(&text);
|
||||
}
|
||||
|
||||
pub fn paste(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||
if let Some(text) = ctx.app_mut().paste() {
|
||||
self.insert(&text, ctx);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn undo(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
|
||||
self.buffer
|
||||
.update(ctx, |buffer, ctx| buffer.undo(Some(ctx)));
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue