diff --git a/README.md b/README.md index 6374ae610..fc843ae24 100644 --- a/README.md +++ b/README.md @@ -43,10 +43,11 @@ These are in the done/doing soon category: - [x] Color Emoji and font fallback - [x] Paste selection via Shift-Insert (bracketed paste is supported!) - [x] SGR style mouse reporting (works in vim and tmux) -- [ ] xterm style selection of text with mouse +- [x] xterm style selection of text with mouse - [ ] Configuration file to specify fonts and colors (in progress) - [ ] Render underline, italic, bold, strikethrough - [ ] Command line argument parsing instead of launching user shell +- [ ] Hyperlinks see: https://gist.github.com/egmontkob/eb114294efbcd5adb1944c9f3cb5feda There's a good number of terminal escape sequences that are not yet implemented and that will get fleshed out as the applications I use uncover them. @@ -56,11 +57,13 @@ Things that I'd like to see happen and that have no immediate priority (contributions to get closer to these are welcomed!) - [ ] Runs on macOS +- [ ] Sixel / iTerm2 graphics protocol support - [ ] Tabs - [ ] Textual renderer. Think `tmux` or `screen`. - [ ] Runs on Linux with Wayland (use XWayland for now) - [ ] Runs on Windows + ## Configuration `wezterm` will look for a TOML configuration file in `$HOME/.config/wezterm/wezterm.toml`, diff --git a/term/src/lib.rs b/term/src/lib.rs index 744a91630..aafa17bff 100644 --- a/term/src/lib.rs +++ b/term/src/lib.rs @@ -1003,13 +1003,39 @@ impl TerminalState { } // Double click to select a word on the current line Some(&LastMouseClick { streak: 2, .. }) => { - // Prepare to start a new selection. - // We don't form the selection until the mouse drags. + let y = event.y as ScrollbackOrVisibleRowIndex; + let idx = self.screen().scrollback_or_visible_row(y); + let line = self.screen().lines[idx].as_str(); + use unicode_segmentation::UnicodeSegmentation; + + self.selection_start = None; self.selection_range = None; - self.selection_start = Some(SelectionCoordinate { - x: event.x, - y: event.y as ScrollbackOrVisibleRowIndex, - }); + // TODO: allow user to configure the word boundary rules. + // Also consider making the default work with URLs? + for (x, word) in line.split_word_bound_indices() { + if event.x < x { + break; + } + if event.x <= x + word.len() { + // this is our word + let start = SelectionCoordinate { x, y }; + let end = SelectionCoordinate { + x: x + word.len() - 1, + y, + }; + self.selection_start = Some(start.clone()); + self.selection_range = Some(SelectionRange { start, end }); + self.dirty_selection_lines(); + let text = self.get_selection_text(); + debug!( + "finish 2click selection {:?} '{}'", + self.selection_range, + text + ); + host.set_clipboard(Some(text))?; + return Ok(()); + } + } host.set_clipboard(None)?; } // triple click to select the current line @@ -1030,7 +1056,11 @@ impl TerminalState { }); self.dirty_selection_lines(); let text = self.get_selection_text(); - println!("finish selection {:?} '{}'", self.selection_range, text); + debug!( + "finish 3click selection {:?} '{}'", + self.selection_range, + text + ); host.set_clipboard(Some(text))?; } // otherwise, clear out the selection @@ -1051,15 +1081,25 @@ impl TerminalState { _) => { // Finish selecting a region, update clipboard self.current_mouse_button = MouseButton::None; - let text = self.get_selection_text(); - println!("finish selection {:?} '{}'", self.selection_range, text); - host.set_clipboard(Some(text))?; - return Ok(()); + match self.last_mouse_click.as_ref() { + // Only consider a drag selection if we have a streak==1. + // The double/triple click cases are handled above. + Some(&LastMouseClick { streak: 1, .. }) => { + let text = self.get_selection_text(); + debug!( + "finish drag selection {:?} '{}'", + self.selection_range, + text + ); + host.set_clipboard(Some(text))?; + return Ok(()); + } + _ => {} + } } (MouseEvent { kind: MouseEventKind::Move, .. }, MouseButton::Left) => { // dragging out the selection region // TODO: may drag and change the viewport - // TODO: scrolling the text (not viewport) should adjust the region self.dirty_selection_lines(); let end = SelectionCoordinate { x: event.x, @@ -1392,6 +1432,7 @@ impl TerminalState { } fn set_scroll_viewport(&mut self, position: VisibleRowIndex) { + self.clear_selection(); let position = position.max(0); let rows = self.screen().physical_rows; @@ -1417,11 +1458,13 @@ impl TerminalState { } fn scroll_up(&mut self, num_rows: usize) { + self.clear_selection(); let scroll_region = self.scroll_region.clone(); self.screen_mut().scroll_up(&scroll_region, num_rows) } fn scroll_down(&mut self, num_rows: usize) { + self.clear_selection(); let scroll_region = self.scroll_region.clone(); self.screen_mut().scroll_down(&scroll_region, num_rows) }