diff --git a/components/compositing/constellation.rs b/components/compositing/constellation.rs index 695c6688e9a0..4b6ffb467a33 100644 --- a/components/compositing/constellation.rs +++ b/components/compositing/constellation.rs @@ -475,6 +475,13 @@ impl Constellation { ); 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) => { debug!("constellation got webdriver command message"); self.handle_webdriver_msg(command); diff --git a/components/msg/constellation_msg.rs b/components/msg/constellation_msg.rs index fcd9afdf7f01..26b5a97ce091 100644 --- a/components/msg/constellation_msg.rs +++ b/components/msg/constellation_msg.rs @@ -247,6 +247,8 @@ pub enum Msg { Focus(PipelineId), /// Requests that the constellation retrieve the current contents of the clipboard GetClipboardContents(IpcSender), + /// Requests that the constellation set the contents of the clipboard + SetClipboardContents(String), /// Dispatch a webdriver command WebDriverCommand(WebDriverCommandMsg), /// Notifies the constellation that the viewport has been constrained in some manner diff --git a/components/script/clipboard_provider.rs b/components/script/clipboard_provider.rs index facdf4aca14d..ce57a82857dd 100644 --- a/components/script/clipboard_provider.rs +++ b/components/script/clipboard_provider.rs @@ -13,7 +13,7 @@ pub trait ClipboardProvider { // blocking method to get the clipboard contents fn clipboard_contents(&mut self) -> String; // 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 { @@ -22,8 +22,8 @@ impl ClipboardProvider for ConstellationChan { self.0.send(ConstellationMsg::GetClipboardContents(tx)).unwrap(); rx.recv().unwrap() } - fn set_clipboard_contents(&mut self, _: &str) { - panic!("not yet implemented"); + fn set_clipboard_contents(&mut self, s: String) { + self.0.send(ConstellationMsg::SetClipboardContents(s)).unwrap(); } } @@ -43,7 +43,7 @@ impl ClipboardProvider for DummyClipboardContext { fn clipboard_contents(&mut self) -> String { self.content.clone() } - fn set_clipboard_contents(&mut self, s: &str) { - self.content = s.to_owned(); + fn set_clipboard_contents(&mut self, s: String) { + self.content = s; } } diff --git a/components/script/textinput.rs b/components/script/textinput.rs index c1fda44b5fbb..16af930518fd 100644 --- a/components/script/textinput.rs +++ b/components/script/textinput.rs @@ -143,51 +143,71 @@ impl TextInput { self.replace_selection(s.into()); } - pub fn get_sorted_selection(&self) -> (TextPoint, TextPoint) { - let begin = self.selection_begin.unwrap(); - let end = self.edit_point; + pub fn get_sorted_selection(&self) -> Option<(TextPoint, TextPoint)> { + self.selection_begin.map(|begin| { + let end = self.edit_point; - if begin.line < end.line || (begin.line == end.line && begin.index < end.index) { - (begin, end) - } else { - (end, begin) - } + if begin.line < end.line || (begin.line == end.line && begin.index < end.index) { + (begin, end) + } else { + (end, begin) + } + }) } - pub fn replace_selection(&mut self, insert: String) { - let (begin, end) = self.get_sorted_selection(); - self.clear_selection(); - - let new_lines = { - 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 lines_prefix = &self.lines[..begin.line]; - let lines_suffix = &self.lines[end.line + 1..]; - - let mut insert_lines = if self.multiline { - insert.split('\n').map(|s| s.to_owned()).collect() + pub fn get_selection_text(&self) -> Option { + 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 { - 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; + self.lines[begin.line].slice_chars(begin.index, end.index).to_owned() + } + }) + } - insert_lines[last_insert_lines_index].push_str(suffix); + pub fn replace_selection(&mut self, insert: String) { + if let Some((begin, end)) = self.get_sorted_selection() { + self.clear_selection(); - 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 new_lines = { + 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 lines_prefix = &self.lines[..begin.line]; + let lines_suffix = &self.lines[end.line + 1..]; + + let mut insert_lines = if self.multiline { + insert.split('\n').map(|s| s.to_owned()).collect() + } else { + 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 + }; - self.lines = new_lines; + self.lines = new_lines; + } } /// Return the length of the current line under the editing point. @@ -237,8 +257,7 @@ impl TextInput { self.selection_begin = Some(self.edit_point); } } else { - if self.selection_begin.is_some() { - let (begin, end) = self.get_sorted_selection(); + if let Some((begin, end)) = self.get_sorted_selection() { self.edit_point = if adjust < 0 {begin} else {end}; self.clear_selection(); return @@ -304,11 +323,18 @@ impl TextInput { pub fn handle_keydown_aux(&mut self, key: Key, mods: KeyModifiers) -> KeyReaction { let maybe_select = if mods.contains(SHIFT) { Selection::Selected } else { Selection::NotSelected }; match key { - Key::A if is_control_key(mods) => { + Key::A if is_control_key(mods) => { self.select_all(); 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(); self.insert_string(contents); KeyReaction::DispatchInput diff --git a/tests/unit/script/textinput.rs b/tests/unit/script/textinput.rs index 1c364d5739a1..4d59ebf28691 100644 --- a/tests/unit/script/textinput.rs +++ b/tests/unit/script/textinput.rs @@ -50,14 +50,14 @@ fn test_textinput_get_sorted_selection() { let mut textinput = TextInput::new(Lines::Single, "abcdefg".to_owned(), DummyClipboardContext::new("")); textinput.adjust_horizontal(2, Selection::NotSelected); 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!(end.index, 4); textinput.clear_selection(); 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!(end.index, 4); }