Get editor tests compiling

This commit is contained in:
Mikayla 2023-11-13 12:10:14 -08:00
parent 4c5d5105f3
commit 0e3fd92bd0
No known key found for this signature in database
8 changed files with 1618 additions and 1426 deletions

View file

@ -10056,76 +10056,76 @@ pub fn diagnostic_style(
}
}
// pub fn combine_syntax_and_fuzzy_match_highlights(
// text: &str,
// default_style: HighlightStyle,
// syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
// match_indices: &[usize],
// ) -> Vec<(Range<usize>, HighlightStyle)> {
// let mut result = Vec::new();
// let mut match_indices = match_indices.iter().copied().peekable();
pub fn combine_syntax_and_fuzzy_match_highlights(
text: &str,
default_style: HighlightStyle,
syntax_ranges: impl Iterator<Item = (Range<usize>, HighlightStyle)>,
match_indices: &[usize],
) -> Vec<(Range<usize>, HighlightStyle)> {
let mut result = Vec::new();
let mut match_indices = match_indices.iter().copied().peekable();
// for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
// {
// syntax_highlight.weight = None;
for (range, mut syntax_highlight) in syntax_ranges.chain([(usize::MAX..0, Default::default())])
{
syntax_highlight.font_weight = None;
// // Add highlights for any fuzzy match characters before the next
// // syntax highlight range.
// while let Some(&match_index) = match_indices.peek() {
// if match_index >= range.start {
// break;
// }
// match_indices.next();
// let end_index = char_ix_after(match_index, text);
// let mut match_style = default_style;
// match_style.weight = Some(FontWeight::BOLD);
// result.push((match_index..end_index, match_style));
// }
// Add highlights for any fuzzy match characters before the next
// syntax highlight range.
while let Some(&match_index) = match_indices.peek() {
if match_index >= range.start {
break;
}
match_indices.next();
let end_index = char_ix_after(match_index, text);
let mut match_style = default_style;
match_style.font_weight = Some(FontWeight::BOLD);
result.push((match_index..end_index, match_style));
}
// if range.start == usize::MAX {
// break;
// }
if range.start == usize::MAX {
break;
}
// // Add highlights for any fuzzy match characters within the
// // syntax highlight range.
// let mut offset = range.start;
// while let Some(&match_index) = match_indices.peek() {
// if match_index >= range.end {
// break;
// }
// Add highlights for any fuzzy match characters within the
// syntax highlight range.
let mut offset = range.start;
while let Some(&match_index) = match_indices.peek() {
if match_index >= range.end {
break;
}
// match_indices.next();
// if match_index > offset {
// result.push((offset..match_index, syntax_highlight));
// }
match_indices.next();
if match_index > offset {
result.push((offset..match_index, syntax_highlight));
}
// let mut end_index = char_ix_after(match_index, text);
// while let Some(&next_match_index) = match_indices.peek() {
// if next_match_index == end_index && next_match_index < range.end {
// end_index = char_ix_after(next_match_index, text);
// match_indices.next();
// } else {
// break;
// }
// }
let mut end_index = char_ix_after(match_index, text);
while let Some(&next_match_index) = match_indices.peek() {
if next_match_index == end_index && next_match_index < range.end {
end_index = char_ix_after(next_match_index, text);
match_indices.next();
} else {
break;
}
}
// let mut match_style = syntax_highlight;
// match_style.weight = Some(FontWeight::BOLD);
// result.push((match_index..end_index, match_style));
// offset = end_index;
// }
let mut match_style = syntax_highlight;
match_style.font_weight = Some(FontWeight::BOLD);
result.push((match_index..end_index, match_style));
offset = end_index;
}
// if offset < range.end {
// result.push((offset..range.end, syntax_highlight));
// }
// }
if offset < range.end {
result.push((offset..range.end, syntax_highlight));
}
}
// fn char_ix_after(ix: usize, text: &str) -> usize {
// ix + text[ix..].chars().next().unwrap().len_utf8()
// }
fn char_ix_after(ix: usize, text: &str) -> usize {
ix + text[ix..].chars().next().unwrap().len_utf8()
}
// result
// }
result
}
// pub fn styled_runs_for_code_label<'a>(
// label: &'a CodeLabel,

File diff suppressed because it is too large Load diff

View file

@ -10,7 +10,7 @@ use serde_json::json;
use crate::{Editor, ToPoint};
use collections::HashSet;
use futures::Future;
use gpui::{json, View, ViewContext};
use gpui::{View, ViewContext, VisualTestContext};
use indoc::indoc;
use language::{point_to_lsp, FakeLspAdapter, Language, LanguageConfig, LanguageQueries};
use lsp::{notification, request};
@ -19,7 +19,7 @@ use project::Project;
use smol::stream::StreamExt;
use workspace::{AppState, Workspace, WorkspaceHandle};
use super::editor_test_context::EditorTestContext;
use super::editor_test_context::{AssertionContextManager, EditorTestContext};
pub struct EditorLspTestContext<'a> {
pub cx: EditorTestContext<'a>,
@ -34,8 +34,6 @@ impl<'a> EditorLspTestContext<'a> {
capabilities: lsp::ServerCapabilities,
cx: &'a mut gpui::TestAppContext,
) -> EditorLspTestContext<'a> {
use json::json;
let app_state = cx.update(AppState::test);
cx.update(|cx| {
@ -70,9 +68,10 @@ impl<'a> EditorLspTestContext<'a> {
.await;
let window = cx.add_window(|cx| Workspace::test_new(project.clone(), cx));
let workspace = window.root(cx);
let workspace = window.root_view(cx).unwrap();
let mut cx = VisualTestContext::from_window(*window.deref(), cx);
project
.update(cx, |project, cx| {
.update(&mut cx, |project, cx| {
project.find_or_create_local_worktree("/root", true, cx)
})
.await
@ -82,7 +81,7 @@ impl<'a> EditorLspTestContext<'a> {
let file = cx.read(|cx| workspace.file_project_paths(cx)[0].clone());
let item = workspace
.update(cx, |workspace, cx| {
.update(&mut cx, |workspace, cx| {
workspace.open_path(file, None, true, cx)
})
.await
@ -92,7 +91,7 @@ impl<'a> EditorLspTestContext<'a> {
item.act_as::<Editor>(cx)
.expect("Opened test file wasn't an editor")
});
editor.update(cx, |_, cx| cx.focus_self());
editor.update(&mut cx, |editor, cx| editor.focus(cx));
let lsp = fake_servers.next().await.unwrap();
@ -101,6 +100,7 @@ impl<'a> EditorLspTestContext<'a> {
cx,
window: window.into(),
editor,
assertion_cx: AssertionContextManager::new(),
},
lsp,
workspace,
@ -258,7 +258,7 @@ impl<'a> EditorLspTestContext<'a> {
where
F: FnOnce(&mut Workspace, &mut ViewContext<Workspace>) -> T,
{
self.workspace.update(self.cx.cx, update)
self.workspace.update(&mut self.cx.cx, update)
}
pub fn handle_request<T, F, Fut>(

View file

@ -1,28 +1,37 @@
use crate::{
display_map::ToDisplayPoint, AnchorRangeExt, Autoscroll, DisplayPoint, Editor, MultiBuffer,
};
use collections::BTreeMap;
use futures::Future;
use gpui::{
AnyWindowHandle, AppContext, ForegroundExecutor, Keystroke, ModelContext, View, ViewContext,
VisualTestContext, WindowHandle,
};
use indoc::indoc;
use itertools::Itertools;
use language::{Buffer, BufferSnapshot};
use parking_lot::RwLock;
use project::{FakeFs, Project};
use std::{
any::TypeId,
ops::{Deref, DerefMut, Range},
sync::{
atomic::{AtomicUsize, Ordering},
Arc,
},
};
use util::{
assert_set_eq,
test::{generate_marked_text, marked_text_ranges},
};
// use super::build_editor_with_project;
use super::build_editor_with_project;
pub struct EditorTestContext<'a> {
pub cx: &'a mut gpui::TestAppContext,
pub cx: gpui::VisualTestContext<'a>,
pub window: AnyWindowHandle,
pub editor: View<Editor>,
pub assertion_cx: AssertionContextManager,
}
impl<'a> EditorTestContext<'a> {
@ -43,15 +52,18 @@ impl<'a> EditorTestContext<'a> {
})
.await
.unwrap();
let window = cx.add_window(|cx| {
cx.focus_self();
build_editor_with_project(project, MultiBuffer::build_from_buffer(buffer, cx), cx)
let editor = cx.add_window(|cx| {
let editor =
build_editor_with_project(project, MultiBuffer::build_from_buffer(buffer, cx), cx);
editor.focus(cx);
editor
});
let editor = window.root(cx);
let editor_view = editor.root_view(cx).unwrap();
Self {
cx,
window: window.into(),
editor,
cx: VisualTestContext::from_window(*editor.deref(), cx),
window: editor.into(),
editor: editor_view,
assertion_cx: AssertionContextManager::new(),
}
}
@ -59,24 +71,27 @@ impl<'a> EditorTestContext<'a> {
&self,
predicate: impl FnMut(&Editor, &AppContext) -> bool,
) -> impl Future<Output = ()> {
self.editor.condition(self.cx, predicate)
self.editor.condition::<crate::Event>(&self.cx, predicate)
}
pub fn editor<F, T>(&self, read: F) -> T
#[track_caller]
pub fn editor<F, T>(&mut self, read: F) -> T
where
F: FnOnce(&Editor, &ViewContext<Editor>) -> T,
{
self.editor.update(self.cx, read)
self.editor
.update(&mut self.cx, |this, cx| read(&this, &cx))
}
#[track_caller]
pub fn update_editor<F, T>(&mut self, update: F) -> T
where
F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
{
self.editor.update(self.cx, update)
self.editor.update(&mut self.cx, update)
}
pub fn multibuffer<F, T>(&self, read: F) -> T
pub fn multibuffer<F, T>(&mut self, read: F) -> T
where
F: FnOnce(&MultiBuffer, &AppContext) -> T,
{
@ -90,11 +105,11 @@ impl<'a> EditorTestContext<'a> {
self.update_editor(|editor, cx| editor.buffer().update(cx, update))
}
pub fn buffer_text(&self) -> String {
pub fn buffer_text(&mut self) -> String {
self.multibuffer(|buffer, cx| buffer.snapshot(cx).text())
}
pub fn buffer<F, T>(&self, read: F) -> T
pub fn buffer<F, T>(&mut self, read: F) -> T
where
F: FnOnce(&Buffer, &AppContext) -> T,
{
@ -114,10 +129,18 @@ impl<'a> EditorTestContext<'a> {
})
}
pub fn buffer_snapshot(&self) -> BufferSnapshot {
pub fn buffer_snapshot(&mut self) -> BufferSnapshot {
self.buffer(|buffer, _| buffer.snapshot())
}
pub fn add_assertion_context(&self, context: String) -> ContextHandle {
self.assertion_cx.add_context(context)
}
pub fn assertion_context(&self) -> String {
self.assertion_cx.context()
}
pub fn simulate_keystroke(&mut self, keystroke_text: &str) -> ContextHandle {
let keystroke_under_test_handle =
self.add_assertion_context(format!("Simulated Keystroke: {:?}", keystroke_text));
@ -141,16 +164,12 @@ impl<'a> EditorTestContext<'a> {
// before returning.
// NOTE: we don't do this in simulate_keystroke() because a possible cause of bugs is that typing too
// quickly races with async actions.
if let Foreground::Deterministic { cx_id: _, executor } = self.cx.foreground().as_ref() {
executor.run_until_parked();
} else {
unreachable!();
}
self.cx.background_executor.run_until_parked();
keystrokes_under_test_handle
}
pub fn ranges(&self, marked_text: &str) -> Vec<Range<usize>> {
pub fn ranges(&mut self, marked_text: &str) -> Vec<Range<usize>> {
let (unmarked_text, ranges) = marked_text_ranges(marked_text, false);
assert_eq!(self.buffer_text(), unmarked_text);
ranges
@ -160,12 +179,12 @@ impl<'a> EditorTestContext<'a> {
let ranges = self.ranges(marked_text);
let snapshot = self
.editor
.update(self.cx, |editor, cx| editor.snapshot(cx));
.update(&mut self.cx, |editor, cx| editor.snapshot(cx));
ranges[0].start.to_display_point(&snapshot)
}
// Returns anchors for the current buffer using `«` and `»`
pub fn text_anchor_range(&self, marked_text: &str) -> Range<language::Anchor> {
pub fn text_anchor_range(&mut self, marked_text: &str) -> Range<language::Anchor> {
let ranges = self.ranges(marked_text);
let snapshot = self.buffer_snapshot();
snapshot.anchor_before(ranges[0].start)..snapshot.anchor_after(ranges[0].end)
@ -190,7 +209,7 @@ impl<'a> EditorTestContext<'a> {
marked_text.escape_debug().to_string()
));
let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
self.editor.update(self.cx, |editor, cx| {
self.editor.update(&mut self.cx, |editor, cx| {
editor.set_text(unmarked_text, cx);
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges(selection_ranges)
@ -206,7 +225,7 @@ impl<'a> EditorTestContext<'a> {
marked_text.escape_debug().to_string()
));
let (unmarked_text, selection_ranges) = marked_text_ranges(marked_text, true);
self.editor.update(self.cx, |editor, cx| {
self.editor.update(&mut self.cx, |editor, cx| {
assert_eq!(editor.text(cx), unmarked_text);
editor.change_selections(Some(Autoscroll::fit()), cx, |s| {
s.select_ranges(selection_ranges)
@ -273,9 +292,12 @@ impl<'a> EditorTestContext<'a> {
self.assert_selections(expected_selections, expected_marked_text)
}
fn editor_selections(&self) -> Vec<Range<usize>> {
#[track_caller]
fn editor_selections(&mut self) -> Vec<Range<usize>> {
self.editor
.read_with(self.cx, |editor, cx| editor.selections.all::<usize>(cx))
.update(&mut self.cx, |editor, cx| {
editor.selections.all::<usize>(cx)
})
.into_iter()
.map(|s| {
if s.reversed {
@ -320,7 +342,7 @@ impl<'a> Deref for EditorTestContext<'a> {
type Target = gpui::TestAppContext;
fn deref(&self) -> &Self::Target {
self.cx
&self.cx
}
}
@ -329,3 +351,50 @@ impl<'a> DerefMut for EditorTestContext<'a> {
&mut self.cx
}
}
/// Tracks string context to be printed when assertions fail.
/// Often this is done by storing a context string in the manager and returning the handle.
#[derive(Clone)]
pub struct AssertionContextManager {
id: Arc<AtomicUsize>,
contexts: Arc<RwLock<BTreeMap<usize, String>>>,
}
impl AssertionContextManager {
pub fn new() -> Self {
Self {
id: Arc::new(AtomicUsize::new(0)),
contexts: Arc::new(RwLock::new(BTreeMap::new())),
}
}
pub fn add_context(&self, context: String) -> ContextHandle {
let id = self.id.fetch_add(1, Ordering::Relaxed);
let mut contexts = self.contexts.write();
contexts.insert(id, context);
ContextHandle {
id,
manager: self.clone(),
}
}
pub fn context(&self) -> String {
let contexts = self.contexts.read();
format!("\n{}\n", contexts.values().join("\n"))
}
}
/// Used to track the lifetime of a piece of context so that it can be provided when an assertion fails.
/// For example, in the EditorTestContext, `set_state` returns a context handle so that if an assertion fails,
/// the state that was set initially for the failure can be printed in the error message
pub struct ContextHandle {
id: usize,
manager: AssertionContextManager,
}
impl Drop for ContextHandle {
fn drop(&mut self) {
let mut contexts = self.manager.contexts.write();
contexts.remove(&self.id);
}
}