mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 11:01:54 +00:00
Finished terminal search
This commit is contained in:
parent
25aae1107b
commit
ebae991cb2
8 changed files with 288 additions and 263 deletions
|
@ -553,39 +553,55 @@ impl SearchableItem for Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn activate_next_match(
|
fn activate_match(
|
||||||
&mut self,
|
|
||||||
index: usize,
|
|
||||||
direction: Direction,
|
|
||||||
matches: Vec<Range<Anchor>>,
|
|
||||||
cx: &mut ViewContext<Self>,
|
|
||||||
) {
|
|
||||||
let new_index: usize = match_index_for_direction(
|
|
||||||
matches.as_slice(),
|
|
||||||
&self.selections.newest_anchor().head(),
|
|
||||||
index,
|
|
||||||
direction,
|
|
||||||
&self.buffer().read(cx).snapshot(cx),
|
|
||||||
);
|
|
||||||
|
|
||||||
let range_to_select = matches[new_index].clone();
|
|
||||||
self.unfold_ranges([range_to_select.clone()], false, cx);
|
|
||||||
self.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
|
||||||
s.select_ranges([range_to_select])
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
fn activate_match_at_index(
|
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
matches: Vec<Range<Anchor>>,
|
matches: Vec<Range<Anchor>>,
|
||||||
cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) {
|
) {
|
||||||
|
self.unfold_ranges([matches[index].clone()], false, cx);
|
||||||
self.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
self.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
||||||
s.select_ranges([matches[index].clone()])
|
s.select_ranges([matches[index].clone()])
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn match_index_for_direction(
|
||||||
|
&mut self,
|
||||||
|
matches: &Vec<Range<Anchor>>,
|
||||||
|
mut current_index: usize,
|
||||||
|
direction: Direction,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) -> usize {
|
||||||
|
let buffer = self.buffer().read(cx).snapshot(cx);
|
||||||
|
let cursor = self.selections.newest_anchor().head();
|
||||||
|
if matches[current_index].start.cmp(&cursor, &buffer).is_gt() {
|
||||||
|
if direction == Direction::Prev {
|
||||||
|
if current_index == 0 {
|
||||||
|
current_index = matches.len() - 1;
|
||||||
|
} else {
|
||||||
|
current_index -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if matches[current_index].end.cmp(&cursor, &buffer).is_lt() {
|
||||||
|
if direction == Direction::Next {
|
||||||
|
current_index = 0;
|
||||||
|
}
|
||||||
|
} else if direction == Direction::Prev {
|
||||||
|
if current_index == 0 {
|
||||||
|
current_index = matches.len() - 1;
|
||||||
|
} else {
|
||||||
|
current_index -= 1;
|
||||||
|
}
|
||||||
|
} else if direction == Direction::Next {
|
||||||
|
if current_index == matches.len() - 1 {
|
||||||
|
current_index = 0
|
||||||
|
} else {
|
||||||
|
current_index += 1;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
current_index
|
||||||
|
}
|
||||||
|
|
||||||
fn find_matches(
|
fn find_matches(
|
||||||
&mut self,
|
&mut self,
|
||||||
query: project::search::SearchQuery,
|
query: project::search::SearchQuery,
|
||||||
|
@ -637,41 +653,6 @@ impl SearchableItem for Editor {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn match_index_for_direction(
|
|
||||||
ranges: &[Range<Anchor>],
|
|
||||||
cursor: &Anchor,
|
|
||||||
mut index: usize,
|
|
||||||
direction: Direction,
|
|
||||||
buffer: &MultiBufferSnapshot,
|
|
||||||
) -> usize {
|
|
||||||
if ranges[index].start.cmp(cursor, buffer).is_gt() {
|
|
||||||
if direction == Direction::Prev {
|
|
||||||
if index == 0 {
|
|
||||||
index = ranges.len() - 1;
|
|
||||||
} else {
|
|
||||||
index -= 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else if ranges[index].end.cmp(cursor, buffer).is_lt() {
|
|
||||||
if direction == Direction::Next {
|
|
||||||
index = 0;
|
|
||||||
}
|
|
||||||
} else if direction == Direction::Prev {
|
|
||||||
if index == 0 {
|
|
||||||
index = ranges.len() - 1;
|
|
||||||
} else {
|
|
||||||
index -= 1;
|
|
||||||
}
|
|
||||||
} else if direction == Direction::Next {
|
|
||||||
if index == ranges.len() - 1 {
|
|
||||||
index = 0
|
|
||||||
} else {
|
|
||||||
index += 1;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
index
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn active_match_index(
|
pub fn active_match_index(
|
||||||
ranges: &[Range<Anchor>],
|
ranges: &[Range<Anchor>],
|
||||||
cursor: &Anchor,
|
cursor: &Anchor,
|
||||||
|
|
|
@ -233,7 +233,6 @@ impl SyntaxSnapshot {
|
||||||
};
|
};
|
||||||
let (start_byte, start_point) = layer.range.start.summary::<(usize, Point)>(text);
|
let (start_byte, start_point) = layer.range.start.summary::<(usize, Point)>(text);
|
||||||
|
|
||||||
|
|
||||||
// Ignore edits that end before the start of this layer, and don't consider them
|
// Ignore edits that end before the start of this layer, and don't consider them
|
||||||
// for any subsequent layers at this same depth.
|
// for any subsequent layers at this same depth.
|
||||||
loop {
|
loop {
|
||||||
|
|
|
@ -95,6 +95,12 @@ impl View for BufferSearchBar {
|
||||||
} else {
|
} else {
|
||||||
theme.search.editor.input.container
|
theme.search.editor.input.container
|
||||||
};
|
};
|
||||||
|
let supported_options = self
|
||||||
|
.active_searchable_item
|
||||||
|
.as_ref()
|
||||||
|
.map(|active_searchable_item| active_searchable_item.supported_options())
|
||||||
|
.unwrap_or_default();
|
||||||
|
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_child(
|
.with_child(
|
||||||
Flex::row()
|
Flex::row()
|
||||||
|
@ -143,9 +149,24 @@ impl View for BufferSearchBar {
|
||||||
)
|
)
|
||||||
.with_child(
|
.with_child(
|
||||||
Flex::row()
|
Flex::row()
|
||||||
.with_child(self.render_search_option("Case", SearchOption::CaseSensitive, cx))
|
.with_children(self.render_search_option(
|
||||||
.with_child(self.render_search_option("Word", SearchOption::WholeWord, cx))
|
supported_options.case,
|
||||||
.with_child(self.render_search_option("Regex", SearchOption::Regex, cx))
|
"Case",
|
||||||
|
SearchOption::CaseSensitive,
|
||||||
|
cx,
|
||||||
|
))
|
||||||
|
.with_children(self.render_search_option(
|
||||||
|
supported_options.word,
|
||||||
|
"Word",
|
||||||
|
SearchOption::WholeWord,
|
||||||
|
cx,
|
||||||
|
))
|
||||||
|
.with_children(self.render_search_option(
|
||||||
|
supported_options.regex,
|
||||||
|
"Regex",
|
||||||
|
SearchOption::Regex,
|
||||||
|
cx,
|
||||||
|
))
|
||||||
.contained()
|
.contained()
|
||||||
.with_style(theme.search.option_button_group)
|
.with_style(theme.search.option_button_group)
|
||||||
.aligned()
|
.aligned()
|
||||||
|
@ -234,7 +255,7 @@ impl BufferSearchBar {
|
||||||
if let Some(searchable_item) =
|
if let Some(searchable_item) =
|
||||||
WeakSearchableItemHandle::upgrade(searchable_item.as_ref(), cx)
|
WeakSearchableItemHandle::upgrade(searchable_item.as_ref(), cx)
|
||||||
{
|
{
|
||||||
searchable_item.clear_highlights(cx);
|
searchable_item.clear_matches(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(active_editor) = self.active_searchable_item.as_ref() {
|
if let Some(active_editor) = self.active_searchable_item.as_ref() {
|
||||||
|
@ -283,36 +304,43 @@ impl BufferSearchBar {
|
||||||
|
|
||||||
fn render_search_option(
|
fn render_search_option(
|
||||||
&self,
|
&self,
|
||||||
|
option_supported: bool,
|
||||||
icon: &str,
|
icon: &str,
|
||||||
option: SearchOption,
|
option: SearchOption,
|
||||||
cx: &mut RenderContext<Self>,
|
cx: &mut RenderContext<Self>,
|
||||||
) -> ElementBox {
|
) -> Option<ElementBox> {
|
||||||
|
if !option_supported {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
|
let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
|
||||||
let is_active = self.is_search_option_enabled(option);
|
let is_active = self.is_search_option_enabled(option);
|
||||||
MouseEventHandler::new::<Self, _, _>(option as usize, cx, |state, cx| {
|
Some(
|
||||||
let style = &cx
|
MouseEventHandler::new::<Self, _, _>(option as usize, cx, |state, cx| {
|
||||||
.global::<Settings>()
|
let style = &cx
|
||||||
.theme
|
.global::<Settings>()
|
||||||
.search
|
.theme
|
||||||
.option_button
|
.search
|
||||||
.style_for(state, is_active);
|
.option_button
|
||||||
Label::new(icon.to_string(), style.text.clone())
|
.style_for(state, is_active);
|
||||||
.contained()
|
Label::new(icon.to_string(), style.text.clone())
|
||||||
.with_style(style.container)
|
.contained()
|
||||||
.boxed()
|
.with_style(style.container)
|
||||||
})
|
.boxed()
|
||||||
.on_click(MouseButton::Left, move |_, cx| {
|
})
|
||||||
cx.dispatch_any_action(option.to_toggle_action())
|
.on_click(MouseButton::Left, move |_, cx| {
|
||||||
})
|
cx.dispatch_any_action(option.to_toggle_action())
|
||||||
.with_cursor_style(CursorStyle::PointingHand)
|
})
|
||||||
.with_tooltip::<Self, _>(
|
.with_cursor_style(CursorStyle::PointingHand)
|
||||||
option as usize,
|
.with_tooltip::<Self, _>(
|
||||||
format!("Toggle {}", option.label()),
|
option as usize,
|
||||||
Some(option.to_toggle_action()),
|
format!("Toggle {}", option.label()),
|
||||||
tooltip_style,
|
Some(option.to_toggle_action()),
|
||||||
cx,
|
tooltip_style,
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.boxed(),
|
||||||
)
|
)
|
||||||
.boxed()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_nav_button(
|
fn render_nav_button(
|
||||||
|
@ -422,8 +450,10 @@ impl BufferSearchBar {
|
||||||
.seachable_items_with_matches
|
.seachable_items_with_matches
|
||||||
.get(&searchable_item.downgrade())
|
.get(&searchable_item.downgrade())
|
||||||
{
|
{
|
||||||
searchable_item.select_next_match_in_direction(index, direction, matches, cx);
|
let new_match_index =
|
||||||
searchable_item.highlight_matches(matches, cx);
|
searchable_item.match_index_for_direction(matches, index, direction, cx);
|
||||||
|
searchable_item.update_matches(matches, cx);
|
||||||
|
searchable_item.activate_match(new_match_index, matches, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -479,7 +509,7 @@ impl BufferSearchBar {
|
||||||
if Some(&searchable_item) == self.active_searchable_item.as_ref() {
|
if Some(&searchable_item) == self.active_searchable_item.as_ref() {
|
||||||
active_item_matches = Some((searchable_item.downgrade(), matches));
|
active_item_matches = Some((searchable_item.downgrade(), matches));
|
||||||
} else {
|
} else {
|
||||||
searchable_item.clear_highlights(cx);
|
searchable_item.clear_matches(cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -494,7 +524,7 @@ impl BufferSearchBar {
|
||||||
if let Some(active_searchable_item) = self.active_searchable_item.as_ref() {
|
if let Some(active_searchable_item) = self.active_searchable_item.as_ref() {
|
||||||
if query.is_empty() {
|
if query.is_empty() {
|
||||||
self.active_match_index.take();
|
self.active_match_index.take();
|
||||||
active_searchable_item.clear_highlights(cx);
|
active_searchable_item.clear_matches(cx);
|
||||||
} else {
|
} else {
|
||||||
let query = if self.regex {
|
let query = if self.regex {
|
||||||
match SearchQuery::regex(query, self.whole_word, self.case_sensitive) {
|
match SearchQuery::regex(query, self.whole_word, self.case_sensitive) {
|
||||||
|
@ -509,7 +539,7 @@ impl BufferSearchBar {
|
||||||
SearchQuery::text(query, self.whole_word, self.case_sensitive)
|
SearchQuery::text(query, self.whole_word, self.case_sensitive)
|
||||||
};
|
};
|
||||||
|
|
||||||
let matches = active_searchable_item.matches(query, cx);
|
let matches = active_searchable_item.find_matches(query, cx);
|
||||||
|
|
||||||
let active_searchable_item = active_searchable_item.downgrade();
|
let active_searchable_item = active_searchable_item.downgrade();
|
||||||
self.pending_search = Some(cx.spawn_weak(|this, mut cx| async move {
|
self.pending_search = Some(cx.spawn_weak(|this, mut cx| async move {
|
||||||
|
@ -529,13 +559,13 @@ impl BufferSearchBar {
|
||||||
.seachable_items_with_matches
|
.seachable_items_with_matches
|
||||||
.get(&active_searchable_item.downgrade())
|
.get(&active_searchable_item.downgrade())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
active_searchable_item.update_matches(matches, cx);
|
||||||
if select_closest_match {
|
if select_closest_match {
|
||||||
if let Some(match_ix) = this.active_match_index {
|
if let Some(match_ix) = this.active_match_index {
|
||||||
active_searchable_item
|
active_searchable_item
|
||||||
.select_match_by_index(match_ix, matches, cx);
|
.activate_match(match_ix, matches, cx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
active_searchable_item.highlight_matches(matches, cx);
|
|
||||||
}
|
}
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,8 @@ use crate::{
|
||||||
};
|
};
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
use editor::{
|
use editor::{
|
||||||
items::{active_match_index, match_index_for_direction},
|
items::active_match_index, Anchor, Autoscroll, Editor, MultiBuffer, SelectAll,
|
||||||
Anchor, Autoscroll, Editor, MultiBuffer, SelectAll, MAX_TAB_TITLE_LEN,
|
MAX_TAB_TITLE_LEN,
|
||||||
};
|
};
|
||||||
use gpui::{
|
use gpui::{
|
||||||
actions, elements::*, platform::CursorStyle, Action, AnyViewHandle, AppContext, ElementBox,
|
actions, elements::*, platform::CursorStyle, Action, AnyViewHandle, AppContext, ElementBox,
|
||||||
|
@ -23,7 +23,7 @@ use std::{
|
||||||
};
|
};
|
||||||
use util::ResultExt as _;
|
use util::ResultExt as _;
|
||||||
use workspace::{
|
use workspace::{
|
||||||
searchable::{Direction, SearchableItemHandle},
|
searchable::{Direction, SearchableItem, SearchableItemHandle},
|
||||||
Item, ItemHandle, ItemNavHistory, Pane, ToolbarItemLocation, ToolbarItemView, Workspace,
|
Item, ItemHandle, ItemNavHistory, Pane, ToolbarItemLocation, ToolbarItemView, Workspace,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -486,16 +486,12 @@ impl ProjectSearchView {
|
||||||
|
|
||||||
fn select_match(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
|
fn select_match(&mut self, direction: Direction, cx: &mut ViewContext<Self>) {
|
||||||
if let Some(index) = self.active_match_index {
|
if let Some(index) = self.active_match_index {
|
||||||
let model = self.model.read(cx);
|
let match_ranges = self.model.read(cx).match_ranges.clone();
|
||||||
let results_editor = self.results_editor.read(cx);
|
let new_index = self.results_editor.update(cx, |editor, cx| {
|
||||||
let new_index = match_index_for_direction(
|
editor.match_index_for_direction(&match_ranges, index, direction, cx)
|
||||||
&model.match_ranges,
|
});
|
||||||
&results_editor.selections.newest_anchor().head(),
|
|
||||||
index,
|
let range_to_select = match_ranges[new_index].clone();
|
||||||
direction,
|
|
||||||
&results_editor.buffer().read(cx).snapshot(cx),
|
|
||||||
);
|
|
||||||
let range_to_select = model.match_ranges[new_index].clone();
|
|
||||||
self.results_editor.update(cx, |editor, cx| {
|
self.results_editor.update(cx, |editor, cx| {
|
||||||
editor.unfold_ranges([range_to_select.clone()], false, cx);
|
editor.unfold_ranges([range_to_select.clone()], false, cx);
|
||||||
editor.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
editor.change_selections(Some(Autoscroll::Fit), cx, |s| {
|
||||||
|
|
|
@ -10,7 +10,7 @@ use alacritty_terminal::{
|
||||||
event::{Event as AlacTermEvent, EventListener, Notify, WindowSize},
|
event::{Event as AlacTermEvent, EventListener, Notify, WindowSize},
|
||||||
event_loop::{EventLoop, Msg, Notifier},
|
event_loop::{EventLoop, Msg, Notifier},
|
||||||
grid::{Dimensions, Scroll as AlacScroll},
|
grid::{Dimensions, Scroll as AlacScroll},
|
||||||
index::{Column, Direction, Line, Point},
|
index::{Column, Direction as AlacDirection, Line, Point},
|
||||||
selection::{Selection, SelectionRange, SelectionType},
|
selection::{Selection, SelectionRange, SelectionType},
|
||||||
sync::FairMutex,
|
sync::FairMutex,
|
||||||
term::{
|
term::{
|
||||||
|
@ -84,6 +84,7 @@ pub enum Event {
|
||||||
Bell,
|
Bell,
|
||||||
Wakeup,
|
Wakeup,
|
||||||
BlinkChanged,
|
BlinkChanged,
|
||||||
|
SelectionsChanged,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -93,7 +94,8 @@ enum InternalEvent {
|
||||||
Clear,
|
Clear,
|
||||||
// FocusNextMatch,
|
// FocusNextMatch,
|
||||||
Scroll(AlacScroll),
|
Scroll(AlacScroll),
|
||||||
SetSelection(Option<Selection>),
|
ScrollToPoint(Point),
|
||||||
|
SetSelection(Option<(Selection, Point)>),
|
||||||
UpdateSelection(Vector2F),
|
UpdateSelection(Vector2F),
|
||||||
Copy,
|
Copy,
|
||||||
}
|
}
|
||||||
|
@ -384,6 +386,7 @@ impl TerminalBuilder {
|
||||||
matches: Vec::new(),
|
matches: Vec::new(),
|
||||||
last_synced: Instant::now(),
|
last_synced: Instant::now(),
|
||||||
sync_task: None,
|
sync_task: None,
|
||||||
|
selection_head: None,
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(TerminalBuilder {
|
Ok(TerminalBuilder {
|
||||||
|
@ -494,12 +497,13 @@ pub struct Terminal {
|
||||||
events: VecDeque<InternalEvent>,
|
events: VecDeque<InternalEvent>,
|
||||||
default_title: String,
|
default_title: String,
|
||||||
title: String,
|
title: String,
|
||||||
last_mouse: Option<(Point, Direction)>,
|
last_mouse: Option<(Point, AlacDirection)>,
|
||||||
pub matches: Vec<RangeInclusive<Point>>,
|
pub matches: Vec<RangeInclusive<Point>>,
|
||||||
cur_size: TerminalSize,
|
cur_size: TerminalSize,
|
||||||
last_content: TerminalContent,
|
last_content: TerminalContent,
|
||||||
last_synced: Instant,
|
last_synced: Instant,
|
||||||
sync_task: Option<Task<()>>,
|
sync_task: Option<Task<()>>,
|
||||||
|
selection_head: Option<Point>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Terminal {
|
impl Terminal {
|
||||||
|
@ -576,33 +580,14 @@ impl Terminal {
|
||||||
InternalEvent::Scroll(scroll) => {
|
InternalEvent::Scroll(scroll) => {
|
||||||
term.scroll_display(*scroll);
|
term.scroll_display(*scroll);
|
||||||
}
|
}
|
||||||
// InternalEvent::FocusNextMatch => {
|
InternalEvent::SetSelection(selection) => {
|
||||||
// if let Some((Some(searcher), _origin)) = &self.searcher {
|
term.selection = selection.as_ref().map(|(sel, _)| sel.clone());
|
||||||
// match term.search_next(
|
|
||||||
// searcher,
|
|
||||||
// Point {
|
|
||||||
// line: Line(0),
|
|
||||||
// column: Column(0),
|
|
||||||
// },
|
|
||||||
// SEARCH_FORWARD,
|
|
||||||
// Direction::Left,
|
|
||||||
// None,
|
|
||||||
// ) {
|
|
||||||
// Some(regex_match) => {
|
|
||||||
// term.scroll_to_point(*regex_match.start());
|
|
||||||
|
|
||||||
// //Focus is done with selections in zed
|
if let Some((_, head)) = selection {
|
||||||
// let focus = make_selection(*regex_match.start(), *regex_match.end());
|
self.selection_head = Some(*head);
|
||||||
// term.selection = Some(focus);
|
}
|
||||||
// }
|
cx.emit(Event::SelectionsChanged)
|
||||||
// None => {
|
}
|
||||||
// //Clear focused match
|
|
||||||
// term.selection = None;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
InternalEvent::SetSelection(sel) => term.selection = sel.clone(),
|
|
||||||
InternalEvent::UpdateSelection(position) => {
|
InternalEvent::UpdateSelection(position) => {
|
||||||
if let Some(mut selection) = term.selection.take() {
|
if let Some(mut selection) = term.selection.take() {
|
||||||
let point = mouse_point(*position, self.cur_size, term.grid().display_offset());
|
let point = mouse_point(*position, self.cur_size, term.grid().display_offset());
|
||||||
|
@ -610,6 +595,9 @@ impl Terminal {
|
||||||
|
|
||||||
selection.update(point, side);
|
selection.update(point, side);
|
||||||
term.selection = Some(selection);
|
term.selection = Some(selection);
|
||||||
|
|
||||||
|
self.selection_head = Some(point);
|
||||||
|
cx.emit(Event::SelectionsChanged)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -618,6 +606,7 @@ impl Terminal {
|
||||||
cx.write_to_clipboard(ClipboardItem::new(txt))
|
cx.write_to_clipboard(ClipboardItem::new(txt))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InternalEvent::ScrollToPoint(point) => term.scroll_to_point(*point),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -625,53 +614,24 @@ impl Terminal {
|
||||||
&self.last_content
|
&self.last_content
|
||||||
}
|
}
|
||||||
|
|
||||||
fn begin_select(&mut self, sel: Selection) {
|
//To test:
|
||||||
|
//- Activate match on terminal (scrolling and selection)
|
||||||
|
//- Editor search snapping behavior
|
||||||
|
|
||||||
|
pub fn activate_match(&mut self, index: usize) {
|
||||||
|
if let Some(search_match) = self.matches.get(index).cloned() {
|
||||||
|
self.set_selection(Some((make_selection(&search_match), *search_match.end())));
|
||||||
|
|
||||||
|
self.events
|
||||||
|
.push_back(InternalEvent::ScrollToPoint(*search_match.start()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_selection(&mut self, selection: Option<(Selection, Point)>) {
|
||||||
self.events
|
self.events
|
||||||
.push_back(InternalEvent::SetSelection(Some(sel)));
|
.push_back(InternalEvent::SetSelection(selection));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn continue_selection(&mut self, location: Vector2F) {
|
|
||||||
self.events
|
|
||||||
.push_back(InternalEvent::UpdateSelection(location))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn end_select(&mut self) {
|
|
||||||
self.events.push_back(InternalEvent::SetSelection(None));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn scroll(&mut self, scroll: AlacScroll) {
|
|
||||||
self.events.push_back(InternalEvent::Scroll(scroll));
|
|
||||||
}
|
|
||||||
|
|
||||||
// fn focus_next_match(&mut self) {
|
|
||||||
// self.events.push_back(InternalEvent::FocusNextMatch);
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn search(&mut self, search: &str) {
|
|
||||||
// let new_searcher = RegexSearch::new(search).ok();
|
|
||||||
// self.searcher = match (new_searcher, &self.searcher) {
|
|
||||||
// //Nothing to do :(
|
|
||||||
// (None, None) => None,
|
|
||||||
// //No existing search, start a new one
|
|
||||||
// (Some(new_searcher), None) => Some((Some(new_searcher), self.viewport_origin())),
|
|
||||||
// //Existing search, carry over origin
|
|
||||||
// (new_searcher, Some((_, origin))) => Some((new_searcher, *origin)),
|
|
||||||
// };
|
|
||||||
|
|
||||||
// if let Some((Some(_), _)) = self.searcher {
|
|
||||||
// self.focus_next_match();
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// fn viewport_origin(&mut self) -> Point {
|
|
||||||
// let viewport_top = alacritty_terminal::index::Line(-(self.last_offset as i32)) - 1;
|
|
||||||
// Point::new(viewport_top, alacritty_terminal::index::Column(0))
|
|
||||||
// }
|
|
||||||
|
|
||||||
// pub fn end_search(&mut self) {
|
|
||||||
// self.searcher = None;
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn copy(&mut self) {
|
pub fn copy(&mut self) {
|
||||||
self.events.push_back(InternalEvent::Copy);
|
self.events.push_back(InternalEvent::Copy);
|
||||||
}
|
}
|
||||||
|
@ -691,8 +651,10 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn input(&mut self, input: String) {
|
pub fn input(&mut self, input: String) {
|
||||||
self.scroll(AlacScroll::Bottom);
|
self.events
|
||||||
self.end_select();
|
.push_back(InternalEvent::Scroll(AlacScroll::Bottom));
|
||||||
|
self.events.push_back(InternalEvent::SetSelection(None));
|
||||||
|
|
||||||
self.write_to_pty(input);
|
self.write_to_pty(input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -790,7 +752,7 @@ impl Terminal {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn mouse_changed(&mut self, point: Point, side: Direction) -> bool {
|
pub fn mouse_changed(&mut self, point: Point, side: AlacDirection) -> bool {
|
||||||
match self.last_mouse {
|
match self.last_mouse {
|
||||||
Some((old_point, old_side)) => {
|
Some((old_point, old_side)) => {
|
||||||
if old_point == point && old_side == side {
|
if old_point == point && old_side == side {
|
||||||
|
@ -830,7 +792,8 @@ impl Terminal {
|
||||||
if !self.mouse_mode(e.shift) {
|
if !self.mouse_mode(e.shift) {
|
||||||
// Alacritty has the same ordering, of first updating the selection
|
// Alacritty has the same ordering, of first updating the selection
|
||||||
// then scrolling 15ms later
|
// then scrolling 15ms later
|
||||||
self.continue_selection(position);
|
self.events
|
||||||
|
.push_back(InternalEvent::UpdateSelection(position));
|
||||||
|
|
||||||
// Doesn't make sense to scroll the alt screen
|
// Doesn't make sense to scroll the alt screen
|
||||||
if !self.last_content.mode.contains(TermMode::ALT_SCREEN) {
|
if !self.last_content.mode.contains(TermMode::ALT_SCREEN) {
|
||||||
|
@ -840,8 +803,11 @@ impl Terminal {
|
||||||
};
|
};
|
||||||
|
|
||||||
let scroll_lines = (scroll_delta / self.cur_size.line_height) as i32;
|
let scroll_lines = (scroll_delta / self.cur_size.line_height) as i32;
|
||||||
self.scroll(AlacScroll::Delta(scroll_lines));
|
|
||||||
self.continue_selection(position)
|
self.events
|
||||||
|
.push_back(InternalEvent::Scroll(AlacScroll::Delta(scroll_lines)));
|
||||||
|
self.events
|
||||||
|
.push_back(InternalEvent::UpdateSelection(position))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -870,7 +836,10 @@ impl Terminal {
|
||||||
self.pty_tx.notify(bytes);
|
self.pty_tx.notify(bytes);
|
||||||
}
|
}
|
||||||
} else if e.button == MouseButton::Left {
|
} else if e.button == MouseButton::Left {
|
||||||
self.begin_select(Selection::new(SelectionType::Simple, point, side));
|
self.events.push_back(InternalEvent::SetSelection(Some((
|
||||||
|
Selection::new(SelectionType::Simple, point, side),
|
||||||
|
point,
|
||||||
|
))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -893,7 +862,8 @@ impl Terminal {
|
||||||
selection_type.map(|selection_type| Selection::new(selection_type, point, side));
|
selection_type.map(|selection_type| Selection::new(selection_type, point, side));
|
||||||
|
|
||||||
if let Some(sel) = selection {
|
if let Some(sel) = selection {
|
||||||
self.begin_select(sel);
|
self.events
|
||||||
|
.push_back(InternalEvent::SetSelection(Some((sel, point))));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -951,7 +921,8 @@ impl Terminal {
|
||||||
((e.delta.y() * ALACRITTY_SCROLL_MULTIPLIER) / self.cur_size.line_height) as i32;
|
((e.delta.y() * ALACRITTY_SCROLL_MULTIPLIER) / self.cur_size.line_height) as i32;
|
||||||
if scroll_lines != 0 {
|
if scroll_lines != 0 {
|
||||||
let scroll = AlacScroll::Delta(scroll_lines);
|
let scroll = AlacScroll::Delta(scroll_lines);
|
||||||
self.scroll(scroll);
|
|
||||||
|
self.events.push_back(InternalEvent::Scroll(scroll));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -994,11 +965,11 @@ impl Entity for Terminal {
|
||||||
type Event = Event;
|
type Event = Event;
|
||||||
}
|
}
|
||||||
|
|
||||||
// fn make_selection(from: Point, to: Point) -> Selection {
|
fn make_selection(range: &RangeInclusive<Point>) -> Selection {
|
||||||
// let mut focus = Selection::new(SelectionType::Simple, from, Direction::Left);
|
let mut selection = Selection::new(SelectionType::Simple, *range.start(), AlacDirection::Left);
|
||||||
// focus.update(to, Direction::Right);
|
selection.update(*range.end(), AlacDirection::Right);
|
||||||
// focus
|
selection
|
||||||
// }
|
}
|
||||||
|
|
||||||
/// Copied from alacritty/src/display/hint.rs HintMatches::visible_regex_matches()
|
/// Copied from alacritty/src/display/hint.rs HintMatches::visible_regex_matches()
|
||||||
/// Iterate over all visible regex matches.
|
/// Iterate over all visible regex matches.
|
||||||
|
@ -1013,7 +984,7 @@ fn make_search_matches<'a, T>(
|
||||||
start.line = start.line.max(viewport_start - MAX_SEARCH_LINES);
|
start.line = start.line.max(viewport_start - MAX_SEARCH_LINES);
|
||||||
end.line = end.line.min(viewport_end + MAX_SEARCH_LINES);
|
end.line = end.line.min(viewport_end + MAX_SEARCH_LINES);
|
||||||
|
|
||||||
RegexIter::new(start, end, Direction::Right, term, regex)
|
RegexIter::new(start, end, AlacDirection::Right, term, regex)
|
||||||
.skip_while(move |rm| rm.end().line < viewport_start)
|
.skip_while(move |rm| rm.end().line < viewport_start)
|
||||||
.take_while(move |rm| rm.start().line <= viewport_end)
|
.take_while(move |rm| rm.start().line <= viewport_end)
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ use gpui::{
|
||||||
actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MutableAppContext, Task,
|
actions, elements::*, AnyViewHandle, AppContext, Entity, ModelHandle, MutableAppContext, Task,
|
||||||
View, ViewContext, ViewHandle,
|
View, ViewContext, ViewHandle,
|
||||||
};
|
};
|
||||||
use workspace::searchable::{Direction, SearchEvent, SearchableItem, SearchableItemHandle};
|
use workspace::searchable::{SearchEvent, SearchOptions, SearchableItem, SearchableItemHandle};
|
||||||
use workspace::{Item, Workspace};
|
use workspace::{Item, Workspace};
|
||||||
|
|
||||||
use crate::TerminalSize;
|
use crate::TerminalSize;
|
||||||
|
@ -340,11 +340,19 @@ impl Item for TerminalContainer {
|
||||||
impl SearchableItem for TerminalContainer {
|
impl SearchableItem for TerminalContainer {
|
||||||
type Match = RangeInclusive<Point>;
|
type Match = RangeInclusive<Point>;
|
||||||
|
|
||||||
|
fn supported_options() -> SearchOptions {
|
||||||
|
SearchOptions {
|
||||||
|
case: false,
|
||||||
|
word: false,
|
||||||
|
regex: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Convert events raised by this item into search-relevant events (if applicable)
|
/// Convert events raised by this item into search-relevant events (if applicable)
|
||||||
fn to_search_event(event: &Self::Event) -> Option<SearchEvent> {
|
fn to_search_event(event: &Self::Event) -> Option<SearchEvent> {
|
||||||
match event {
|
match event {
|
||||||
Event::Wakeup => Some(SearchEvent::MatchesInvalidated),
|
Event::Wakeup => Some(SearchEvent::MatchesInvalidated),
|
||||||
//TODO selection changed
|
Event::SelectionsChanged => Some(SearchEvent::ActiveMatchChanged),
|
||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -380,25 +388,13 @@ impl SearchableItem for TerminalContainer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Given an index, a set of matches for this index, and a direction,
|
|
||||||
/// get the next match (clicking the arrow)
|
|
||||||
fn activate_next_match(
|
|
||||||
&mut self,
|
|
||||||
_index: usize,
|
|
||||||
_direction: Direction,
|
|
||||||
_matches: Vec<Self::Match>,
|
|
||||||
_cx: &mut ViewContext<Self>,
|
|
||||||
) {
|
|
||||||
// TODO:
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Focus match at given index into the Vec of matches
|
/// Focus match at given index into the Vec of matches
|
||||||
fn activate_match_at_index(
|
fn activate_match(&mut self, index: usize, _: Vec<Self::Match>, cx: &mut ViewContext<Self>) {
|
||||||
&mut self,
|
if let TerminalContainerContent::Connected(connected) = &self.content {
|
||||||
_index: usize,
|
let terminal = connected.read(cx).terminal().clone();
|
||||||
_matches: Vec<Self::Match>,
|
terminal.update(cx, |term, _| term.activate_match(index));
|
||||||
_cx: &mut ViewContext<Self>,
|
cx.notify();
|
||||||
) {
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get all of the matches for this query, should be done on the background
|
/// Get all of the matches for this query, should be done on the background
|
||||||
|
@ -419,10 +415,27 @@ impl SearchableItem for TerminalContainer {
|
||||||
fn active_match_index(
|
fn active_match_index(
|
||||||
&mut self,
|
&mut self,
|
||||||
matches: Vec<Self::Match>,
|
matches: Vec<Self::Match>,
|
||||||
_cx: &mut ViewContext<Self>,
|
cx: &mut ViewContext<Self>,
|
||||||
) -> Option<usize> {
|
) -> Option<usize> {
|
||||||
if matches.len() > 0 {
|
if let TerminalContainerContent::Connected(connected) = &self.content {
|
||||||
Some(0)
|
if let Some(selection_head) = connected.read(cx).terminal().read(cx).selection_head {
|
||||||
|
// If selection head is contained in a match. Return that match
|
||||||
|
for (ix, search_match) in matches.iter().enumerate() {
|
||||||
|
if search_match.contains(&selection_head) {
|
||||||
|
return Some(ix);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If not contained, return the next match after the selection head
|
||||||
|
if search_match.start() > &selection_head {
|
||||||
|
return Some(ix);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no selection after selection head, return the last match
|
||||||
|
return Some(matches.len() - 1);
|
||||||
|
} else {
|
||||||
|
Some(0)
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
|
@ -579,12 +579,12 @@ impl Element for TerminalElement {
|
||||||
|
|
||||||
// searches, highlights to a single range representations
|
// searches, highlights to a single range representations
|
||||||
let mut relative_highlighted_ranges = Vec::new();
|
let mut relative_highlighted_ranges = Vec::new();
|
||||||
if let Some(selection) = selection {
|
|
||||||
relative_highlighted_ranges.push((selection.start..=selection.end, selection_color));
|
|
||||||
}
|
|
||||||
for search_match in search_matches {
|
for search_match in search_matches {
|
||||||
relative_highlighted_ranges.push((search_match, match_color))
|
relative_highlighted_ranges.push((search_match, match_color))
|
||||||
}
|
}
|
||||||
|
if let Some(selection) = selection {
|
||||||
|
relative_highlighted_ranges.push((selection.start..=selection.end, selection_color));
|
||||||
|
}
|
||||||
|
|
||||||
// then have that representation be converted to the appropriate highlight data structure
|
// then have that representation be converted to the appropriate highlight data structure
|
||||||
|
|
||||||
|
|
|
@ -14,32 +14,64 @@ pub enum SearchEvent {
|
||||||
ActiveMatchChanged,
|
ActiveMatchChanged,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
|
||||||
pub enum Direction {
|
pub enum Direction {
|
||||||
Prev,
|
Prev,
|
||||||
Next,
|
Next,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Copy, Debug, Default)]
|
||||||
|
pub struct SearchOptions {
|
||||||
|
pub case: bool,
|
||||||
|
pub word: bool,
|
||||||
|
pub regex: bool,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait SearchableItem: Item {
|
pub trait SearchableItem: Item {
|
||||||
type Match: Any + Sync + Send + Clone;
|
type Match: Any + Sync + Send + Clone;
|
||||||
|
|
||||||
|
fn supported_options() -> SearchOptions {
|
||||||
|
SearchOptions {
|
||||||
|
case: true,
|
||||||
|
word: true,
|
||||||
|
regex: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
fn to_search_event(event: &Self::Event) -> Option<SearchEvent>;
|
fn to_search_event(event: &Self::Event) -> Option<SearchEvent>;
|
||||||
fn clear_matches(&mut self, cx: &mut ViewContext<Self>);
|
fn clear_matches(&mut self, cx: &mut ViewContext<Self>);
|
||||||
fn update_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>);
|
fn update_matches(&mut self, matches: Vec<Self::Match>, cx: &mut ViewContext<Self>);
|
||||||
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String;
|
fn query_suggestion(&mut self, cx: &mut ViewContext<Self>) -> String;
|
||||||
fn activate_next_match(
|
fn activate_match(
|
||||||
&mut self,
|
&mut self,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
matches: Vec<Self::Match>,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
);
|
||||||
|
fn match_index_for_direction(
|
||||||
|
&mut self,
|
||||||
|
matches: &Vec<Self::Match>,
|
||||||
|
mut current_index: usize,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
matches: Vec<Self::Match>,
|
_: &mut ViewContext<Self>,
|
||||||
cx: &mut ViewContext<Self>,
|
) -> usize {
|
||||||
);
|
match direction {
|
||||||
fn activate_match_at_index(
|
Direction::Prev => {
|
||||||
&mut self,
|
if current_index == 0 {
|
||||||
index: usize,
|
matches.len() - 1
|
||||||
matches: Vec<Self::Match>,
|
} else {
|
||||||
cx: &mut ViewContext<Self>,
|
current_index - 1
|
||||||
);
|
}
|
||||||
|
}
|
||||||
|
Direction::Next => {
|
||||||
|
current_index += 1;
|
||||||
|
if current_index == matches.len() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
current_index
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
fn find_matches(
|
fn find_matches(
|
||||||
&mut self,
|
&mut self,
|
||||||
query: SearchQuery,
|
query: SearchQuery,
|
||||||
|
@ -55,28 +87,29 @@ pub trait SearchableItem: Item {
|
||||||
pub trait SearchableItemHandle: ItemHandle {
|
pub trait SearchableItemHandle: ItemHandle {
|
||||||
fn downgrade(&self) -> Box<dyn WeakSearchableItemHandle>;
|
fn downgrade(&self) -> Box<dyn WeakSearchableItemHandle>;
|
||||||
fn boxed_clone(&self) -> Box<dyn SearchableItemHandle>;
|
fn boxed_clone(&self) -> Box<dyn SearchableItemHandle>;
|
||||||
|
fn supported_options(&self) -> SearchOptions;
|
||||||
fn subscribe(
|
fn subscribe(
|
||||||
&self,
|
&self,
|
||||||
cx: &mut MutableAppContext,
|
cx: &mut MutableAppContext,
|
||||||
handler: Box<dyn Fn(SearchEvent, &mut MutableAppContext)>,
|
handler: Box<dyn Fn(SearchEvent, &mut MutableAppContext)>,
|
||||||
) -> Subscription;
|
) -> Subscription;
|
||||||
fn clear_highlights(&self, cx: &mut MutableAppContext);
|
fn clear_matches(&self, cx: &mut MutableAppContext);
|
||||||
fn highlight_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut MutableAppContext);
|
fn update_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut MutableAppContext);
|
||||||
fn query_suggestion(&self, cx: &mut MutableAppContext) -> String;
|
fn query_suggestion(&self, cx: &mut MutableAppContext) -> String;
|
||||||
fn select_next_match_in_direction(
|
fn activate_match(
|
||||||
&self,
|
&self,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
matches: &Vec<Box<dyn Any + Send>>,
|
||||||
|
cx: &mut MutableAppContext,
|
||||||
|
);
|
||||||
|
fn match_index_for_direction(
|
||||||
|
&self,
|
||||||
|
matches: &Vec<Box<dyn Any + Send>>,
|
||||||
|
current_index: usize,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
matches: &Vec<Box<dyn Any + Send>>,
|
|
||||||
cx: &mut MutableAppContext,
|
cx: &mut MutableAppContext,
|
||||||
);
|
) -> usize;
|
||||||
fn select_match_by_index(
|
fn find_matches(
|
||||||
&self,
|
|
||||||
index: usize,
|
|
||||||
matches: &Vec<Box<dyn Any + Send>>,
|
|
||||||
cx: &mut MutableAppContext,
|
|
||||||
);
|
|
||||||
fn matches(
|
|
||||||
&self,
|
&self,
|
||||||
query: SearchQuery,
|
query: SearchQuery,
|
||||||
cx: &mut MutableAppContext,
|
cx: &mut MutableAppContext,
|
||||||
|
@ -97,6 +130,10 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
|
||||||
Box::new(self.clone())
|
Box::new(self.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn supported_options(&self) -> SearchOptions {
|
||||||
|
T::supported_options()
|
||||||
|
}
|
||||||
|
|
||||||
fn subscribe(
|
fn subscribe(
|
||||||
&self,
|
&self,
|
||||||
cx: &mut MutableAppContext,
|
cx: &mut MutableAppContext,
|
||||||
|
@ -109,40 +146,38 @@ impl<T: SearchableItem> SearchableItemHandle for ViewHandle<T> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_highlights(&self, cx: &mut MutableAppContext) {
|
fn clear_matches(&self, cx: &mut MutableAppContext) {
|
||||||
self.update(cx, |this, cx| this.clear_matches(cx));
|
self.update(cx, |this, cx| this.clear_matches(cx));
|
||||||
}
|
}
|
||||||
fn highlight_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut MutableAppContext) {
|
fn update_matches(&self, matches: &Vec<Box<dyn Any + Send>>, cx: &mut MutableAppContext) {
|
||||||
let matches = downcast_matches(matches);
|
let matches = downcast_matches(matches);
|
||||||
self.update(cx, |this, cx| this.update_matches(matches, cx));
|
self.update(cx, |this, cx| this.update_matches(matches, cx));
|
||||||
}
|
}
|
||||||
fn query_suggestion(&self, cx: &mut MutableAppContext) -> String {
|
fn query_suggestion(&self, cx: &mut MutableAppContext) -> String {
|
||||||
self.update(cx, |this, cx| this.query_suggestion(cx))
|
self.update(cx, |this, cx| this.query_suggestion(cx))
|
||||||
}
|
}
|
||||||
fn select_next_match_in_direction(
|
fn activate_match(
|
||||||
&self,
|
&self,
|
||||||
index: usize,
|
index: usize,
|
||||||
|
matches: &Vec<Box<dyn Any + Send>>,
|
||||||
|
cx: &mut MutableAppContext,
|
||||||
|
) {
|
||||||
|
let matches = downcast_matches(matches);
|
||||||
|
self.update(cx, |this, cx| this.activate_match(index, matches, cx));
|
||||||
|
}
|
||||||
|
fn match_index_for_direction(
|
||||||
|
&self,
|
||||||
|
matches: &Vec<Box<dyn Any + Send>>,
|
||||||
|
current_index: usize,
|
||||||
direction: Direction,
|
direction: Direction,
|
||||||
matches: &Vec<Box<dyn Any + Send>>,
|
|
||||||
cx: &mut MutableAppContext,
|
cx: &mut MutableAppContext,
|
||||||
) {
|
) -> usize {
|
||||||
let matches = downcast_matches(matches);
|
let matches = downcast_matches(matches);
|
||||||
self.update(cx, |this, cx| {
|
self.update(cx, |this, cx| {
|
||||||
this.activate_next_match(index, direction, matches, cx)
|
this.match_index_for_direction(&matches, current_index, direction, cx)
|
||||||
});
|
})
|
||||||
}
|
}
|
||||||
fn select_match_by_index(
|
fn find_matches(
|
||||||
&self,
|
|
||||||
index: usize,
|
|
||||||
matches: &Vec<Box<dyn Any + Send>>,
|
|
||||||
cx: &mut MutableAppContext,
|
|
||||||
) {
|
|
||||||
let matches = downcast_matches(matches);
|
|
||||||
self.update(cx, |this, cx| {
|
|
||||||
this.activate_match_at_index(index, matches, cx)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
fn matches(
|
|
||||||
&self,
|
&self,
|
||||||
query: SearchQuery,
|
query: SearchQuery,
|
||||||
cx: &mut MutableAppContext,
|
cx: &mut MutableAppContext,
|
||||||
|
|
Loading…
Reference in a new issue