Add set_clipboard_context function and relevant plumbing. Use Option more consistantly (less unwraps) in textinput's selection handling.

This commit is contained in:
Avi Weinstock 2015-06-18 11:58:03 -04:00
parent 52c2049f2a
commit f86252a60b
5 changed files with 83 additions and 48 deletions

View file

@ -475,6 +475,13 @@ impl<LTF: LayoutTaskFactory, STF: ScriptTaskFactory> Constellation<LTF, STF> {
); );
sender.send(result).unwrap(); sender.send(result).unwrap();
} }
ConstellationMsg::SetClipboardContents(s) => {
if let Some(ref ctx) = self.clipboard_ctx {
if let Err(e) = ctx.set_contents(s) {
debug!("Error setting clipboard contents ({})", e);
}
}
}
ConstellationMsg::WebDriverCommand(command) => { ConstellationMsg::WebDriverCommand(command) => {
debug!("constellation got webdriver command message"); debug!("constellation got webdriver command message");
self.handle_webdriver_msg(command); self.handle_webdriver_msg(command);

View file

@ -247,6 +247,8 @@ pub enum Msg {
Focus(PipelineId), Focus(PipelineId),
/// Requests that the constellation retrieve the current contents of the clipboard /// Requests that the constellation retrieve the current contents of the clipboard
GetClipboardContents(IpcSender<String>), GetClipboardContents(IpcSender<String>),
/// Requests that the constellation set the contents of the clipboard
SetClipboardContents(String),
/// Dispatch a webdriver command /// Dispatch a webdriver command
WebDriverCommand(WebDriverCommandMsg), WebDriverCommand(WebDriverCommandMsg),
/// Notifies the constellation that the viewport has been constrained in some manner /// Notifies the constellation that the viewport has been constrained in some manner

View file

@ -13,7 +13,7 @@ pub trait ClipboardProvider {
// blocking method to get the clipboard contents // blocking method to get the clipboard contents
fn clipboard_contents(&mut self) -> String; fn clipboard_contents(&mut self) -> String;
// blocking method to set the clipboard contents // blocking method to set the clipboard contents
fn set_clipboard_contents(&mut self, &str); fn set_clipboard_contents(&mut self, String);
} }
impl ClipboardProvider for ConstellationChan { impl ClipboardProvider for ConstellationChan {
@ -22,8 +22,8 @@ impl ClipboardProvider for ConstellationChan {
self.0.send(ConstellationMsg::GetClipboardContents(tx)).unwrap(); self.0.send(ConstellationMsg::GetClipboardContents(tx)).unwrap();
rx.recv().unwrap() rx.recv().unwrap()
} }
fn set_clipboard_contents(&mut self, _: &str) { fn set_clipboard_contents(&mut self, s: String) {
panic!("not yet implemented"); self.0.send(ConstellationMsg::SetClipboardContents(s)).unwrap();
} }
} }
@ -43,7 +43,7 @@ impl ClipboardProvider for DummyClipboardContext {
fn clipboard_contents(&mut self) -> String { fn clipboard_contents(&mut self) -> String {
self.content.clone() self.content.clone()
} }
fn set_clipboard_contents(&mut self, s: &str) { fn set_clipboard_contents(&mut self, s: String) {
self.content = s.to_owned(); self.content = s;
} }
} }

View file

@ -143,51 +143,71 @@ impl<T: ClipboardProvider> TextInput<T> {
self.replace_selection(s.into()); self.replace_selection(s.into());
} }
pub fn get_sorted_selection(&self) -> (TextPoint, TextPoint) { pub fn get_sorted_selection(&self) -> Option<(TextPoint, TextPoint)> {
let begin = self.selection_begin.unwrap(); self.selection_begin.map(|begin| {
let end = self.edit_point; let end = self.edit_point;
if begin.line < end.line || (begin.line == end.line && begin.index < end.index) { if begin.line < end.line || (begin.line == end.line && begin.index < end.index) {
(begin, end) (begin, end)
} else { } else {
(end, begin) (end, begin)
} }
})
}
pub fn get_selection_text(&self) -> Option<String> {
self.get_sorted_selection().map(|(begin, end)| {
if begin.line != end.line {
let mut s = String::new();
s.push_str(self.lines[begin.line].slice_chars(begin.index, self.lines[begin.line].len()));
for (_, line) in self.lines.iter().enumerate().filter(|&(i,_)| begin.line < i && i < end.line) {
s.push_str("\n");
s.push_str(line);
}
s.push_str("\n");
s.push_str(self.lines[end.line].slice_chars(0, end.index));
s
} else {
self.lines[begin.line].slice_chars(begin.index, end.index).to_owned()
}
})
} }
pub fn replace_selection(&mut self, insert: String) { pub fn replace_selection(&mut self, insert: String) {
let (begin, end) = self.get_sorted_selection(); if let Some((begin, end)) = self.get_sorted_selection() {
self.clear_selection(); self.clear_selection();
let new_lines = { let new_lines = {
let prefix = self.lines[begin.line].slice_chars(0, begin.index); let prefix = self.lines[begin.line].slice_chars(0, begin.index);
let suffix = self.lines[end.line].slice_chars(end.index, self.lines[end.line].chars().count()); let suffix = self.lines[end.line].slice_chars(end.index, self.lines[end.line].chars().count());
let lines_prefix = &self.lines[..begin.line]; let lines_prefix = &self.lines[..begin.line];
let lines_suffix = &self.lines[end.line + 1..]; let lines_suffix = &self.lines[end.line + 1..];
let mut insert_lines = if self.multiline { let mut insert_lines = if self.multiline {
insert.split('\n').map(|s| s.to_owned()).collect() insert.split('\n').map(|s| s.to_owned()).collect()
} else { } else {
vec!(insert) vec!(insert)
};
let mut new_line = prefix.to_owned();
new_line.push_str(&insert_lines[0]);
insert_lines[0] = new_line;
let last_insert_lines_index = insert_lines.len() - 1;
self.edit_point.index = insert_lines[last_insert_lines_index].chars().count();
self.edit_point.line = begin.line + last_insert_lines_index;
insert_lines[last_insert_lines_index].push_str(suffix);
let mut new_lines = vec!();
new_lines.push_all(lines_prefix);
new_lines.push_all(&insert_lines);
new_lines.push_all(lines_suffix);
new_lines
}; };
let mut new_line = prefix.to_owned(); self.lines = new_lines;
new_line.push_str(&insert_lines[0]); }
insert_lines[0] = new_line;
let last_insert_lines_index = insert_lines.len() - 1;
self.edit_point.index = insert_lines[last_insert_lines_index].chars().count();
self.edit_point.line = begin.line + last_insert_lines_index;
insert_lines[last_insert_lines_index].push_str(suffix);
let mut new_lines = vec!();
new_lines.push_all(lines_prefix);
new_lines.push_all(&insert_lines);
new_lines.push_all(lines_suffix);
new_lines
};
self.lines = new_lines;
} }
/// Return the length of the current line under the editing point. /// Return the length of the current line under the editing point.
@ -237,8 +257,7 @@ impl<T: ClipboardProvider> TextInput<T> {
self.selection_begin = Some(self.edit_point); self.selection_begin = Some(self.edit_point);
} }
} else { } else {
if self.selection_begin.is_some() { if let Some((begin, end)) = self.get_sorted_selection() {
let (begin, end) = self.get_sorted_selection();
self.edit_point = if adjust < 0 {begin} else {end}; self.edit_point = if adjust < 0 {begin} else {end};
self.clear_selection(); self.clear_selection();
return return
@ -304,11 +323,18 @@ impl<T: ClipboardProvider> TextInput<T> {
pub fn handle_keydown_aux(&mut self, key: Key, mods: KeyModifiers) -> KeyReaction { pub fn handle_keydown_aux(&mut self, key: Key, mods: KeyModifiers) -> KeyReaction {
let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected }; let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected };
match key { match key {
Key::A if is_control_key(mods) => { Key::A if is_control_key(mods) => {
self.select_all(); self.select_all();
KeyReaction::Nothing KeyReaction::Nothing
}, },
Key::V if is_control_key(mods) => { Key::C if is_control_key(mods) => {
if let Some(text) = self.get_selection_text() {
println!("get_selection_text(): {}", &text);
self.clipboard_provider.set_clipboard_contents(text);
}
KeyReaction::DispatchInput
},
Key::V if is_control_key(mods) => {
let contents = self.clipboard_provider.clipboard_contents(); let contents = self.clipboard_provider.clipboard_contents();
self.insert_string(contents); self.insert_string(contents);
KeyReaction::DispatchInput KeyReaction::DispatchInput

View file

@ -50,14 +50,14 @@ fn test_textinput_get_sorted_selection() {
let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new("")); let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new(""));
textinput.adjust_horizontal(2, Selection::NotSelected); textinput.adjust_horizontal(2, Selection::NotSelected);
textinput.adjust_horizontal(2, Selection::Selected); textinput.adjust_horizontal(2, Selection::Selected);
let (begin, end) = textinput.get_sorted_selection(); let (begin, end) = textinput.get_sorted_selection().unwrap();
assert_eq!(begin.index, 2); assert_eq!(begin.index, 2);
assert_eq!(end.index, 4); assert_eq!(end.index, 4);
textinput.clear_selection(); textinput.clear_selection();
textinput.adjust_horizontal(-2, Selection::Selected); textinput.adjust_horizontal(-2, Selection::Selected);
let (begin, end) = textinput.get_sorted_selection(); let (begin, end) = textinput.get_sorted_selection().unwrap();
assert_eq!(begin.index, 2); assert_eq!(begin.index, 2);
assert_eq!(end.index, 4); assert_eq!(end.index, 4);
} }