1
1
mirror of https://github.com/wez/wezterm.git synced 2024-12-24 13:52:55 +03:00

copy mode: move by semantic zone, select by zone

Allows the following assignment actions; I was just over-using z for
no real reason, I'm not suggesting that these are good assignments.

```
      -- move the cursor backwards to the start of the current zone, or
      -- to the prior zone if already at the start
      { key = 'z', mods = 'NONE', action = act.CopyMode 'MoveBackwardSemanticZone' },
      -- move the cursor forwards to the start of the next zone
      { key = 'Z', mods = 'NONE', action = act.CopyMode 'MoveForwardSemanticZone' },
      -- start selecting by zone: both the start point and the cursor
      -- position will be expanded to the containing zone and the union
      -- of those two will be used for the selection
      {
        key = 'z',
        mods = 'CTRL',
        action = act.CopyMode { SetSelectionMode = 'SemanticZone' },
      },
      -- like MoveBackwardSemanticZone by only considers zones of the
      -- specified type
      { key = 'z', mods = 'ALT', action = act.CopyMode { MoveBackwardZoneOfType ='Output' }},
      -- like MoveForwardSemanticZone by only considers zones of the
      -- specified type
      { key = 'Z', mods = 'ALT', action = act.CopyMode { MoveForwardZoneOfType ='Output' }},
```

refs: https://github.com/wez/wezterm/issues/2346
This commit is contained in:
Wez Furlong 2022-08-02 21:56:53 -07:00
parent 33866dad70
commit 1df1f166ca
3 changed files with 98 additions and 31 deletions

View File

@ -9,6 +9,7 @@ use std::path::PathBuf;
use wezterm_dynamic::{FromDynamic, ToDynamic}; use wezterm_dynamic::{FromDynamic, ToDynamic};
use wezterm_input_types::{KeyCode, Modifiers}; use wezterm_input_types::{KeyCode, Modifiers};
use wezterm_term::input::MouseButton; use wezterm_term::input::MouseButton;
use wezterm_term::SemanticType;
#[derive(Default, Debug, Clone, FromDynamic, ToDynamic, PartialEq, Eq)] #[derive(Default, Debug, Clone, FromDynamic, ToDynamic, PartialEq, Eq)]
pub struct LauncherActionArgs { pub struct LauncherActionArgs {
@ -496,6 +497,10 @@ pub enum CopyModeAssignment {
ClearPattern, ClearPattern,
EditPattern, EditPattern,
AcceptPattern, AcceptPattern,
MoveBackwardSemanticZone,
MoveForwardSemanticZone,
MoveBackwardZoneOfType(SemanticType),
MoveForwardZoneOfType(SemanticType),
} }
pub type KeyTable = HashMap<(KeyCode, Modifiers), KeyTableEntry>; pub type KeyTable = HashMap<(KeyCode, Modifiers), KeyTableEntry>;

View File

@ -147,7 +147,7 @@ macro_rules! bitfield {
/// Input (that the user typed) and Prompt (effectively, "chrome" provided /// Input (that the user typed) and Prompt (effectively, "chrome" provided
/// by the shell or application that the user is interacting with. /// by the shell or application that the user is interacting with.
#[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))] #[cfg_attr(feature = "use_serde", derive(Serialize, Deserialize))]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, FromDynamic, ToDynamic)]
#[repr(u16)] #[repr(u16)]
pub enum SemanticType { pub enum SemanticType {
Output = 0, Output = 0,

View File

@ -22,8 +22,8 @@ use unicode_segmentation::*;
use url::Url; use url::Url;
use wezterm_term::color::ColorPalette; use wezterm_term::color::ColorPalette;
use wezterm_term::{ use wezterm_term::{
unicode_column_width, Clipboard, KeyCode, KeyModifiers, Line, MouseEvent, StableRowIndex, unicode_column_width, Clipboard, KeyCode, KeyModifiers, Line, MouseEvent, SemanticType,
TerminalSize, StableRowIndex, TerminalSize,
}; };
use window::{KeyCode as WKeyCode, Modifiers, WindowOps}; use window::{KeyCode as WKeyCode, Modifiers, WindowOps};
@ -352,35 +352,47 @@ impl CopyRenderable {
fn select_to_cursor_pos(&mut self) { fn select_to_cursor_pos(&mut self) {
self.clamp_cursor_to_scrollback(); self.clamp_cursor_to_scrollback();
if let Some(start) = self.start { if let Some(sel_start) = self.start {
let cursor_is_above_start = self.cursor.y < start.y; let cursor = SelectionCoordinate::x_y(self.cursor.x, self.cursor.y);
let start = if self.selection_mode == SelectionMode::Line {
SelectionCoordinate::x_y( let (start, end) = match self.selection_mode {
SelectionMode::Line => {
let cursor_is_above_start = self.cursor.y < sel_start.y;
let start = SelectionCoordinate::x_y(
if cursor_is_above_start { if cursor_is_above_start {
usize::max_value() usize::max_value()
} else { } else {
0 0
}, },
start.y, sel_start.y,
) );
} else { let end = SelectionCoordinate::x_y(
SelectionCoordinate {
x: start.x,
y: start.y,
}
};
let end = if self.selection_mode == SelectionMode::Line {
SelectionCoordinate::x_y(
if cursor_is_above_start { if cursor_is_above_start {
0 0
} else { } else {
usize::max_value() usize::max_value()
}, },
self.cursor.y, self.cursor.y,
) );
} else { (start, end)
SelectionCoordinate::x_y(self.cursor.x, self.cursor.y) }
SelectionMode::SemanticZone => {
let zone_range = SelectionRange::zone_around(cursor, &*self.delegate);
let start_zone = SelectionRange::zone_around(sel_start, &*self.delegate);
let range = zone_range.extend_with(start_zone);
(range.start, range.end)
}
_ => {
let start = SelectionCoordinate {
x: sel_start.x,
y: sel_start.y,
};
let end = cursor;
(start, end)
}
}; };
self.adjust_selection(start, SelectionRange { start, end }); self.adjust_selection(start, SelectionRange { start, end });
@ -764,6 +776,52 @@ impl CopyRenderable {
self.select_to_cursor_pos(); self.select_to_cursor_pos();
} }
fn move_by_zone(&mut self, mut delta: isize, zone_type: Option<SemanticType>) {
if delta == 0 {
return;
}
let zones = self
.delegate
.get_semantic_zones()
.unwrap_or_else(|_| vec![]);
let mut idx = match zones.binary_search_by(|zone| {
if zone.start_y == self.cursor.y {
zone.start_x.cmp(&self.cursor.x)
} else if zone.start_y < self.cursor.y {
std::cmp::Ordering::Less
} else {
std::cmp::Ordering::Greater
}
}) {
Ok(idx) | Err(idx) => idx,
};
let step = if delta > 0 { 1 } else { -1 };
while delta != 0 {
if step > 0 {
idx = idx.saturating_add(1);
} else {
idx = idx.saturating_sub(1);
}
let zone = match zones.get(idx) {
Some(z) => z,
None => return,
};
if let Some(zone_type) = &zone_type {
if zone.semantic_type != *zone_type {
continue;
}
}
delta = delta.saturating_sub(step);
self.cursor.x = zone.start_x;
self.cursor.y = zone.start_y;
}
self.select_to_cursor_pos();
}
fn set_selection_mode(&mut self, mode: &Option<SelectionMode>) { fn set_selection_mode(&mut self, mode: &Option<SelectionMode>) {
match mode { match mode {
None => { None => {
@ -878,6 +936,10 @@ impl Pane for CopyOverlay {
EditPattern => render.edit_pattern(), EditPattern => render.edit_pattern(),
AcceptPattern => render.accept_pattern(), AcceptPattern => render.accept_pattern(),
SetSelectionMode(mode) => render.set_selection_mode(mode), SetSelectionMode(mode) => render.set_selection_mode(mode),
MoveBackwardSemanticZone => render.move_by_zone(-1, None),
MoveForwardSemanticZone => render.move_by_zone(1, None),
MoveBackwardZoneOfType(zone_type) => render.move_by_zone(-1, Some(*zone_type)),
MoveForwardZoneOfType(zone_type) => render.move_by_zone(1, Some(*zone_type)),
} }
true true
} }