diff --git a/crates/terminal/README.md b/crates/terminal/README.md index cdfdaffe854ef51533bd63f2bfb24199fd7b830c..272212a538a06766d254b6bbd675643af62e1175 100644 --- a/crates/terminal/README.md +++ b/crates/terminal/README.md @@ -10,7 +10,7 @@ The TerminalView struct abstracts over failed and successful terminals, passing #Input -There are currently 3 distinct paths for getting keystrokes to the terminal: +There are currently many distinct paths for getting keystrokes to the terminal: 1. Terminal specific characters and bindings. Things like ctrl-a mapping to ASCII control character 1, ANSI escape codes associated with the function keys, etc. These are caught with a raw key-down handler in the element and are processed immediately. This is done with the `try_keystroke()` method on Terminal @@ -18,3 +18,6 @@ There are currently 3 distinct paths for getting keystrokes to the terminal: 3. IME text. When the special character mappings fail, we pass the keystroke back to GPUI to hand it to the IME system. This comes back to us in the `View::replace_text_in_range()` method, and we then send that to the terminal directly, bypassing `try_keystroke()`. +4. Pasted text has a seperate pathway. + +Generally, there's a distinction between 'keystrokes that need to be mapped' and 'strings which need to be written'. I've attempted to unify these under the '.try_keystroke()' API and the `.input()` API (which try_keystroke uses) so we have consistent input handling across the terminal \ No newline at end of file diff --git a/crates/terminal/src/connected_el.rs b/crates/terminal/src/connected_el.rs index 48f58762b043c0fb239942cf275943ae582e6fa0..020c71f4219608bb2c6577f35333e190ab0ff2d1 100644 --- a/crates/terminal/src/connected_el.rs +++ b/crates/terminal/src/connected_el.rs @@ -473,6 +473,22 @@ impl TerminalEl { } } }) + .on_drag(MouseButton::Left, move |_prev, event, cx| { + if let Some(conn_handle) = connection.upgrade(cx.app) { + conn_handle.update(cx.app, |terminal, cx| { + let (point, side) = TerminalEl::mouse_to_cell_data( + event.position, + origin, + cur_size, + display_offset, + ); + + terminal.mouse_drag(point, side); + + cx.notify(); + }) + } + }) .on_down( MouseButton::Left, TerminalEl::generic_button_handler( @@ -696,7 +712,7 @@ impl Element for TerminalEl { ( cells, - content.selection, + dbg!(content.selection), content.cursor, content.display_offset, cursor_text, diff --git a/crates/terminal/src/connected_view.rs b/crates/terminal/src/connected_view.rs index 5b521748bb02b869d6d6688e76c8a6d6d8d0068b..703a54ba91e3419fb625bde968db1370f9096b2d 100644 --- a/crates/terminal/src/connected_view.rs +++ b/crates/terminal/src/connected_view.rs @@ -251,7 +251,8 @@ impl ConnectedView { ///Attempt to paste the clipboard into the terminal fn paste(&mut self, _: &Paste, cx: &mut ViewContext) { if let Some(item) = cx.read_from_clipboard() { - self.terminal.read(cx).paste(item.text()); + self.terminal + .update(cx, |terminal, _cx| terminal.paste(item.text())); } } @@ -359,8 +360,7 @@ impl View for ConnectedView { cx: &mut ViewContext, ) { self.terminal.update(cx, |terminal, _| { - terminal.write_to_pty(text.into()); - terminal.scroll(alacritty_terminal::grid::Scroll::Bottom); + terminal.input(text.into()); }); } diff --git a/crates/terminal/src/terminal.rs b/crates/terminal/src/terminal.rs index 15227951956c8c4dd6f73ae077508fa0f8475da4..37bf85e78f9dd312734c7975ab9527a38582e88a 100644 --- a/crates/terminal/src/terminal.rs +++ b/crates/terminal/src/terminal.rs @@ -508,8 +508,14 @@ impl Terminal { } } + pub fn input(&mut self, input: String) { + self.scroll(Scroll::Bottom); + self.events.push(InternalEvent::SetSelection(None)); + self.write_to_pty(input); + } + ///Write the Input payload to the tty. - pub fn write_to_pty(&self, input: String) { + fn write_to_pty(&self, input: String) { self.pty_tx.notify(input.into_bytes()); } @@ -525,8 +531,7 @@ impl Terminal { pub fn try_keystroke(&mut self, keystroke: &Keystroke) -> bool { let esc = to_esc_str(keystroke, &self.last_mode); if let Some(esc) = esc { - self.write_to_pty(esc); - self.scroll(Scroll::Bottom); + self.input(esc); true } else { false @@ -534,14 +539,13 @@ impl Terminal { } ///Paste text into the terminal - pub fn paste(&self, text: &str) { - if self.last_mode.contains(TermMode::BRACKETED_PASTE) { - self.write_to_pty("\x1b[200~".to_string()); - self.write_to_pty(text.replace('\x1b', "")); - self.write_to_pty("\x1b[201~".to_string()); + pub fn paste(&mut self, text: &str) { + let paste_text = if self.last_mode.contains(TermMode::BRACKETED_PASTE) { + format!("{}{}{}", "\x1b[200~", text.replace('\x1b', ""), "\x1b[201~") } else { - self.write_to_pty(text.replace("\r\n", "\r").replace('\n', "\r")); - } + text.replace("\r\n", "\r").replace('\n', "\r") + }; + self.input(paste_text) } pub fn copy(&mut self) { @@ -598,18 +602,20 @@ impl Terminal { } } - /// Handle a mouse move, this is mutually exclusive with drag. + /// Handle a mouse move pub fn mouse_move(&mut self, point: Point, side: Direction, e: &MouseMovedEvent) { if self.mouse_changed(point, side) { if let Some(bytes) = mouse_moved_report(point, e, self.last_mode) { self.pty_tx.notify(bytes); } - } else if matches!(e.pressed_button, Some(gpui::MouseButton::Left)) { - self.events - .push(InternalEvent::UpdateSelection((point, side))); } } + pub fn mouse_drag(&mut self, point: Point, side: Direction) { + self.events + .push(InternalEvent::UpdateSelection((point, side))); + } + pub fn mouse_down(&mut self, point: Point, side: Direction) { if self.last_mode.intersects(TermMode::MOUSE_REPORT_CLICK) { //TODE: MOUSE MODE