Initial public release of Warp.
Repo-Sync-Origin: warpdotdev/warp-internal@12af1d983b
This commit is contained in:
@@ -0,0 +1,247 @@
|
||||
use warpui::{App, ModelHandle};
|
||||
|
||||
use crate::content::{
|
||||
buffer::{AutoScrollBehavior, Buffer, BufferEditAction, BufferSelectAction, EditOrigin},
|
||||
find::{Match, SearchResults},
|
||||
selection_model::BufferSelectionModel,
|
||||
text::IndentBehavior,
|
||||
};
|
||||
|
||||
use super::Searcher;
|
||||
|
||||
#[test]
|
||||
fn test_literal_search() {
|
||||
App::test((), |mut app| async move {
|
||||
let (content, selection) = buffer(&mut app, "abc def abc def");
|
||||
let search = searcher(&mut app, content, selection);
|
||||
|
||||
search
|
||||
.update(&mut app, |search, ctx| {
|
||||
search.set_query("abc", ctx);
|
||||
search.search_finished(ctx)
|
||||
})
|
||||
.await;
|
||||
|
||||
search.read(&app, |search, _| {
|
||||
assert_eq!(search.match_count(), 2);
|
||||
assert_eq!(
|
||||
search.results,
|
||||
Some(SearchResults {
|
||||
matches: vec![
|
||||
Match {
|
||||
start: 1.into(),
|
||||
end: 4.into()
|
||||
},
|
||||
Match {
|
||||
start: 9.into(),
|
||||
end: 12.into()
|
||||
}
|
||||
]
|
||||
})
|
||||
)
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_navigate_search_results() {
|
||||
App::test((), |mut app| async move {
|
||||
let (content, selection) = buffer(&mut app, "abc def abc def");
|
||||
let search = searcher(&mut app, content, selection);
|
||||
|
||||
search
|
||||
.update(&mut app, |search, ctx| {
|
||||
search.set_auto_select(true);
|
||||
search.set_query("abc", ctx);
|
||||
search.search_finished(ctx)
|
||||
})
|
||||
.await;
|
||||
|
||||
search.update(&mut app, |search, ctx| {
|
||||
assert_eq!(search.match_count(), 2);
|
||||
// With auto-selection, the first match should be selected (cursor is at start)
|
||||
assert_eq!(search.selected_match(), Some(0));
|
||||
|
||||
// Move to the next result.
|
||||
search.select_next_result(ctx);
|
||||
assert_eq!(search.selected_match(), Some(1));
|
||||
|
||||
// Keep moving until we wrap around.
|
||||
search.select_next_result(ctx);
|
||||
assert_eq!(search.selected_match(), Some(0));
|
||||
|
||||
// Now do the same in the other direction.
|
||||
search.select_previous_result(ctx);
|
||||
assert_eq!(search.selected_match(), Some(1));
|
||||
|
||||
search.select_previous_result(ctx);
|
||||
assert_eq!(search.selected_match(), Some(0));
|
||||
|
||||
// Starting from no selection, select the last result.
|
||||
search.selected_result = None;
|
||||
search.select_previous_result(ctx);
|
||||
assert_eq!(search.selected_match(), Some(1));
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edit_results_valid() {
|
||||
App::test((), |mut app| async move {
|
||||
let (content, content_selection) = buffer(&mut app, "a git command");
|
||||
let search = searcher(&mut app, content.clone(), content_selection.clone());
|
||||
|
||||
search
|
||||
.update(&mut app, |search, ctx| {
|
||||
search.set_auto_select(true);
|
||||
search.set_regex(true, ctx);
|
||||
search.set_query(r"g\w+t", ctx);
|
||||
search.search_finished(ctx)
|
||||
})
|
||||
.await;
|
||||
|
||||
search.update(&mut app, |search, ctx| {
|
||||
search.select_next_result(ctx);
|
||||
assert_eq!(search.selected_match(), Some(0));
|
||||
});
|
||||
|
||||
// Insert some text before the match.
|
||||
content.update(&mut app, |buffer, ctx| {
|
||||
buffer.update_selection(
|
||||
content_selection.clone(),
|
||||
BufferSelectAction::AddCursorAt {
|
||||
offset: 2.into(),
|
||||
clear_selections: true,
|
||||
},
|
||||
AutoScrollBehavior::Selection,
|
||||
ctx,
|
||||
);
|
||||
buffer.update_content(
|
||||
BufferEditAction::Insert {
|
||||
text: "sdf",
|
||||
style: Default::default(),
|
||||
override_text_style: None,
|
||||
},
|
||||
EditOrigin::UserTyped,
|
||||
content_selection.clone(),
|
||||
ctx,
|
||||
);
|
||||
assert_eq!(buffer.debug(), "<text>asdf git command");
|
||||
});
|
||||
|
||||
search
|
||||
.update(&mut app, |search, ctx| search.search_finished(ctx))
|
||||
.await;
|
||||
|
||||
// When the search finishes, we should have the same result.
|
||||
assert_eq!(
|
||||
search.read(&app, |search, _| search.selected_match()),
|
||||
Some(0)
|
||||
);
|
||||
|
||||
// Insert a new match before the selected one, which should move it back.
|
||||
content.update(&mut app, |buffer, ctx| {
|
||||
buffer.update_content(
|
||||
BufferEditAction::Insert {
|
||||
text: "got",
|
||||
style: Default::default(),
|
||||
override_text_style: None,
|
||||
},
|
||||
EditOrigin::UserTyped,
|
||||
content_selection.clone(),
|
||||
ctx,
|
||||
);
|
||||
assert_eq!(buffer.debug(), "<text>asdfgot git command");
|
||||
});
|
||||
|
||||
search
|
||||
.update(&mut app, |search, ctx| search.search_finished(ctx))
|
||||
.await;
|
||||
|
||||
assert_eq!(
|
||||
search.read(&app, |search, _| search.selected_match()),
|
||||
Some(1)
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_edit_results_invalid() {
|
||||
App::test((), |mut app| async move {
|
||||
let (content, content_selection) = buffer(&mut app, "a git command for git");
|
||||
let search = searcher(&mut app, content.clone(), content_selection.clone());
|
||||
|
||||
search
|
||||
.update(&mut app, |search, ctx| {
|
||||
search.set_auto_select(true);
|
||||
search.set_regex(true, ctx);
|
||||
search.set_query(r"g\w+t", ctx);
|
||||
search.search_finished(ctx)
|
||||
})
|
||||
.await;
|
||||
|
||||
search.update(&mut app, |search, ctx| {
|
||||
// Move to the second match
|
||||
search.select_next_result(ctx);
|
||||
assert_eq!(search.selected_match(), Some(1));
|
||||
});
|
||||
|
||||
// Invalidate the match
|
||||
content.update(&mut app, |buffer, ctx| {
|
||||
buffer.update_selection(
|
||||
content_selection.clone(),
|
||||
BufferSelectAction::AddCursorAt {
|
||||
offset: 6.into(),
|
||||
clear_selections: true,
|
||||
},
|
||||
AutoScrollBehavior::Selection,
|
||||
ctx,
|
||||
);
|
||||
buffer.update_content(
|
||||
BufferEditAction::Backspace,
|
||||
EditOrigin::UserTyped,
|
||||
content_selection.clone(),
|
||||
ctx,
|
||||
);
|
||||
assert_eq!(buffer.debug(), "<text>a gi command for git");
|
||||
});
|
||||
|
||||
search
|
||||
.update(&mut app, |search, ctx| search.search_finished(ctx))
|
||||
.await;
|
||||
|
||||
// When the search finishes, auto-selection should pick the remaining match.
|
||||
search.read(&app, |search, _| {
|
||||
assert_eq!(search.selected_match(), Some(0));
|
||||
assert_eq!(search.match_count(), 1);
|
||||
});
|
||||
})
|
||||
}
|
||||
/// Create a new buffer model with the given Markdown.
|
||||
fn buffer(
|
||||
app: &mut App,
|
||||
markdown: &str,
|
||||
) -> (ModelHandle<Buffer>, ModelHandle<BufferSelectionModel>) {
|
||||
let buffer = app.add_model(|_| Buffer::new(Box::new(|_, _| IndentBehavior::Ignore)));
|
||||
let selection = app.add_model(|_| BufferSelectionModel::new(buffer.clone()));
|
||||
|
||||
buffer.update(app, |buffer, ctx| {
|
||||
*buffer = Buffer::from_markdown(
|
||||
markdown,
|
||||
None,
|
||||
Box::new(|_, _| IndentBehavior::Ignore),
|
||||
selection.clone(),
|
||||
ctx,
|
||||
);
|
||||
});
|
||||
|
||||
(buffer, selection)
|
||||
}
|
||||
|
||||
fn searcher(
|
||||
app: &mut App,
|
||||
buffer: ModelHandle<Buffer>,
|
||||
selection: ModelHandle<BufferSelectionModel>,
|
||||
) -> ModelHandle<Searcher> {
|
||||
app.add_model(|ctx| Searcher::new(buffer, selection, ctx))
|
||||
}
|
||||
Reference in New Issue
Block a user