mirror of
https://github.com/wez/wezterm.git
synced 2024-09-21 19:58:15 +03:00
wezterm: search: select current match
When cycling through matches, set the current selection to the matched range. This doesn't implicitly copy; it just marks the range. You can use the `Copy` key assignment to explicitly copy the selection to the clipboard. I'm sort of on the fence about implicit copying.
This commit is contained in:
parent
191a67bc9f
commit
7ff8d9e7a3
@ -1,3 +1,4 @@
|
||||
use crate::frontend::gui::selection::{SelectionCoordinate, SelectionRange};
|
||||
use crate::frontend::gui::termwindow::TermWindow;
|
||||
use crate::mux::domain::DomainId;
|
||||
use crate::mux::renderable::*;
|
||||
@ -135,8 +136,7 @@ impl Tab for SearchOverlay {
|
||||
} else {
|
||||
r.results.len() - 1
|
||||
};
|
||||
r.result_pos.replace(prior);
|
||||
r.set_viewport(Some(r.results[prior].start_y));
|
||||
r.activate_match_number(prior);
|
||||
}
|
||||
}
|
||||
(KeyCode::Char('n'), KeyModifiers::CTRL) => {
|
||||
@ -148,8 +148,7 @@ impl Tab for SearchOverlay {
|
||||
} else {
|
||||
*cur + 1
|
||||
};
|
||||
r.result_pos.replace(next);
|
||||
r.set_viewport(Some(r.results[next].start_y));
|
||||
r.activate_match_number(next);
|
||||
}
|
||||
}
|
||||
(KeyCode::Char('r'), KeyModifiers::CTRL) => {
|
||||
@ -309,13 +308,54 @@ impl SearchRenderable {
|
||||
|
||||
self.recompute_results();
|
||||
}
|
||||
if let Some(last) = self.results.last() {
|
||||
self.result_pos.replace(self.results.len() - 1);
|
||||
self.set_viewport(Some(last.start_y));
|
||||
if !self.results.is_empty() {
|
||||
self.activate_match_number(self.results.len() - 1);
|
||||
} else {
|
||||
self.set_viewport(None);
|
||||
self.clear_selection();
|
||||
}
|
||||
}
|
||||
|
||||
fn clear_selection(&mut self) {
|
||||
let tab_id = self.delegate.tab_id();
|
||||
self.window.apply(move |term_window, _window| {
|
||||
if let Some(term_window) = term_window.downcast_mut::<TermWindow>() {
|
||||
let mut selection = term_window.selection(tab_id);
|
||||
selection.start.take();
|
||||
selection.range.take();
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
}
|
||||
|
||||
fn activate_match_number(&mut self, n: usize) {
|
||||
self.result_pos.replace(n);
|
||||
let result = self.results[n].clone();
|
||||
|
||||
let tab_id = self.delegate.tab_id();
|
||||
self.window.apply(move |term_window, _window| {
|
||||
if let Some(term_window) = term_window.downcast_mut::<TermWindow>() {
|
||||
let mut selection = term_window.selection(tab_id);
|
||||
let start = SelectionCoordinate {
|
||||
x: result.start_x,
|
||||
y: result.start_y,
|
||||
};
|
||||
selection.start = Some(start);
|
||||
selection.range = Some(SelectionRange {
|
||||
start,
|
||||
end: SelectionCoordinate {
|
||||
// inclusive range for selection, but the result
|
||||
// range is exclusive
|
||||
x: result.end_x.saturating_sub(1),
|
||||
y: result.end_y,
|
||||
},
|
||||
});
|
||||
}
|
||||
Ok(())
|
||||
});
|
||||
|
||||
self.set_viewport(Some(result.start_y));
|
||||
}
|
||||
}
|
||||
|
||||
impl Renderable for SearchRenderable {
|
||||
|
@ -656,20 +656,29 @@ impl TermWindow {
|
||||
let dirty = render.get_dirty_lines(visible_range);
|
||||
|
||||
if !dirty.is_empty() {
|
||||
// If any of the changed lines intersect with the selection,
|
||||
// then we need to clear the selection
|
||||
let clear_selection = if let Some(selection_range) =
|
||||
myself.selection(tab.tab_id()).range.as_ref()
|
||||
{
|
||||
let selection_rows = selection_range.rows();
|
||||
selection_rows.into_iter().any(|row| dirty.contains(row))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
if tab.downcast_ref::<SearchOverlay>().is_none() {
|
||||
// If any of the changed lines intersect with the
|
||||
// selection, then we need to clear the selection, but not
|
||||
// when the search overlay is active; the search overlay
|
||||
// marks lines as dirty to force invalidate them for
|
||||
// highlighting purpose but also manipulates the selection
|
||||
// and we want to allow it to retain the selection it made!
|
||||
|
||||
if clear_selection {
|
||||
myself.selection(tab.tab_id()).range.take();
|
||||
myself.selection(tab.tab_id()).start.take();
|
||||
let clear_selection = if let Some(selection_range) =
|
||||
myself.selection(tab.tab_id()).range.as_ref()
|
||||
{
|
||||
let selection_rows = selection_range.rows();
|
||||
selection_rows
|
||||
.into_iter()
|
||||
.any(|row| dirty.contains(row))
|
||||
} else {
|
||||
false
|
||||
};
|
||||
|
||||
if clear_selection {
|
||||
myself.selection(tab.tab_id()).range.take();
|
||||
myself.selection(tab.tab_id()).start.take();
|
||||
}
|
||||
}
|
||||
|
||||
myself.window.as_ref().unwrap().invalidate();
|
||||
@ -2657,7 +2666,7 @@ impl TermWindow {
|
||||
})
|
||||
}
|
||||
|
||||
fn selection(&self, tab_id: TabId) -> RefMut<Selection> {
|
||||
pub fn selection(&self, tab_id: TabId) -> RefMut<Selection> {
|
||||
RefMut::map(self.tab_state(tab_id), |state| &mut state.selection)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user