Compare commits
8 Commits
test-threa
...
v0.82.3-pr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6dde8a9b59 | ||
|
|
ccde289ed7 | ||
|
|
9a026f3c4b | ||
|
|
301609d595 | ||
|
|
ea8dba625d | ||
|
|
b089be40ba | ||
|
|
b83451ccf6 | ||
|
|
50658077a0 |
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -8516,7 +8516,7 @@ checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
||||
[[package]]
|
||||
name = "zed"
|
||||
version = "0.82.0"
|
||||
version = "0.82.3"
|
||||
dependencies = [
|
||||
"activity_indicator",
|
||||
"anyhow",
|
||||
|
||||
@@ -1040,7 +1040,8 @@ impl CopilotState {
|
||||
let completion = self.completions.get(self.active_completion_index)?;
|
||||
let excerpt_id = self.excerpt_id?;
|
||||
let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
|
||||
if !completion.range.start.is_valid(completion_buffer)
|
||||
if excerpt_id != cursor.excerpt_id
|
||||
|| !completion.range.start.is_valid(completion_buffer)
|
||||
|| !completion.range.end.is_valid(completion_buffer)
|
||||
{
|
||||
return None;
|
||||
@@ -6619,13 +6620,15 @@ impl Editor {
|
||||
.as_singleton()
|
||||
.and_then(|b| b.read(cx).file()),
|
||||
) {
|
||||
let settings = cx.global::<Settings>();
|
||||
|
||||
let extension = Path::new(file.file_name(cx))
|
||||
.extension()
|
||||
.and_then(|e| e.to_str());
|
||||
project.read(cx).client().report_event(
|
||||
name,
|
||||
json!({ "File Extension": extension }),
|
||||
cx.global::<Settings>().telemetry(),
|
||||
json!({ "File Extension": extension, "Vim Mode": settings.vim_mode }),
|
||||
settings.telemetry(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6163,6 +6163,110 @@ async fn test_copilot_completion_invalidation(
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
async fn test_copilot_multibuffer(
|
||||
deterministic: Arc<Deterministic>,
|
||||
cx: &mut gpui::TestAppContext,
|
||||
) {
|
||||
let (copilot, copilot_lsp) = Copilot::fake(cx);
|
||||
cx.update(|cx| {
|
||||
cx.set_global(Settings::test(cx));
|
||||
cx.set_global(copilot)
|
||||
});
|
||||
|
||||
let buffer_1 = cx.add_model(|cx| Buffer::new(0, "a = 1\nb = 2\n", cx));
|
||||
let buffer_2 = cx.add_model(|cx| Buffer::new(0, "c = 3\nd = 4\n", cx));
|
||||
let multibuffer = cx.add_model(|cx| {
|
||||
let mut multibuffer = MultiBuffer::new(0);
|
||||
multibuffer.push_excerpts(
|
||||
buffer_1.clone(),
|
||||
[ExcerptRange {
|
||||
context: Point::new(0, 0)..Point::new(2, 0),
|
||||
primary: None,
|
||||
}],
|
||||
cx,
|
||||
);
|
||||
multibuffer.push_excerpts(
|
||||
buffer_2.clone(),
|
||||
[ExcerptRange {
|
||||
context: Point::new(0, 0)..Point::new(2, 0),
|
||||
primary: None,
|
||||
}],
|
||||
cx,
|
||||
);
|
||||
multibuffer
|
||||
});
|
||||
let (_, editor) = cx.add_window(|cx| build_editor(multibuffer, cx));
|
||||
|
||||
handle_copilot_completion_request(
|
||||
&copilot_lsp,
|
||||
vec![copilot::request::Completion {
|
||||
text: "b = 2 + a".into(),
|
||||
range: lsp::Range::new(lsp::Position::new(1, 0), lsp::Position::new(1, 5)),
|
||||
..Default::default()
|
||||
}],
|
||||
vec![],
|
||||
);
|
||||
editor.update(cx, |editor, cx| {
|
||||
// Ensure copilot suggestions are shown for the first excerpt.
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.select_ranges([Point::new(1, 5)..Point::new(1, 5)])
|
||||
});
|
||||
editor.next_copilot_suggestion(&Default::default(), cx);
|
||||
});
|
||||
deterministic.advance_clock(COPILOT_DEBOUNCE_TIMEOUT);
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert!(editor.has_active_copilot_suggestion(cx));
|
||||
assert_eq!(
|
||||
editor.display_text(cx),
|
||||
"\n\na = 1\nb = 2 + a\n\n\n\nc = 3\nd = 4\n"
|
||||
);
|
||||
assert_eq!(editor.text(cx), "a = 1\nb = 2\n\nc = 3\nd = 4\n");
|
||||
});
|
||||
|
||||
handle_copilot_completion_request(
|
||||
&copilot_lsp,
|
||||
vec![copilot::request::Completion {
|
||||
text: "d = 4 + c".into(),
|
||||
range: lsp::Range::new(lsp::Position::new(1, 0), lsp::Position::new(1, 6)),
|
||||
..Default::default()
|
||||
}],
|
||||
vec![],
|
||||
);
|
||||
editor.update(cx, |editor, cx| {
|
||||
// Move to another excerpt, ensuring the suggestion gets cleared.
|
||||
editor.change_selections(None, cx, |s| {
|
||||
s.select_ranges([Point::new(4, 5)..Point::new(4, 5)])
|
||||
});
|
||||
assert!(!editor.has_active_copilot_suggestion(cx));
|
||||
assert_eq!(
|
||||
editor.display_text(cx),
|
||||
"\n\na = 1\nb = 2\n\n\n\nc = 3\nd = 4\n"
|
||||
);
|
||||
assert_eq!(editor.text(cx), "a = 1\nb = 2\n\nc = 3\nd = 4\n");
|
||||
|
||||
// Type a character, ensuring we don't even try to interpolate the previous suggestion.
|
||||
editor.handle_input(" ", cx);
|
||||
assert!(!editor.has_active_copilot_suggestion(cx));
|
||||
assert_eq!(
|
||||
editor.display_text(cx),
|
||||
"\n\na = 1\nb = 2\n\n\n\nc = 3\nd = 4 \n"
|
||||
);
|
||||
assert_eq!(editor.text(cx), "a = 1\nb = 2\n\nc = 3\nd = 4 \n");
|
||||
});
|
||||
|
||||
// Ensure the new suggestion is displayed when the debounce timeout expires.
|
||||
deterministic.advance_clock(COPILOT_DEBOUNCE_TIMEOUT);
|
||||
editor.update(cx, |editor, cx| {
|
||||
assert!(editor.has_active_copilot_suggestion(cx));
|
||||
assert_eq!(
|
||||
editor.display_text(cx),
|
||||
"\n\na = 1\nb = 2\n\n\n\nc = 3\nd = 4 + c\n"
|
||||
);
|
||||
assert_eq!(editor.text(cx), "a = 1\nb = 2\n\nc = 3\nd = 4 \n");
|
||||
});
|
||||
}
|
||||
|
||||
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
||||
let point = DisplayPoint::new(row as u32, column as u32);
|
||||
point..point
|
||||
|
||||
@@ -523,31 +523,7 @@ impl FakeFs {
|
||||
}
|
||||
|
||||
pub async fn insert_file(&self, path: impl AsRef<Path>, content: String) {
|
||||
let mut state = self.state.lock();
|
||||
let path = path.as_ref();
|
||||
let inode = state.next_inode;
|
||||
let mtime = state.next_mtime;
|
||||
state.next_inode += 1;
|
||||
state.next_mtime += Duration::from_nanos(1);
|
||||
let file = Arc::new(Mutex::new(FakeFsEntry::File {
|
||||
inode,
|
||||
mtime,
|
||||
content,
|
||||
}));
|
||||
state
|
||||
.write_path(path, move |entry| {
|
||||
match entry {
|
||||
btree_map::Entry::Vacant(e) => {
|
||||
e.insert(file);
|
||||
}
|
||||
btree_map::Entry::Occupied(mut e) => {
|
||||
*e.get_mut() = file;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
.unwrap();
|
||||
state.emit_event(&[path]);
|
||||
self.write_file_internal(path, content).unwrap()
|
||||
}
|
||||
|
||||
pub async fn insert_symlink(&self, path: impl AsRef<Path>, target: PathBuf) {
|
||||
@@ -569,6 +545,33 @@ impl FakeFs {
|
||||
state.emit_event(&[path]);
|
||||
}
|
||||
|
||||
fn write_file_internal(&self, path: impl AsRef<Path>, content: String) -> Result<()> {
|
||||
let mut state = self.state.lock();
|
||||
let path = path.as_ref();
|
||||
let inode = state.next_inode;
|
||||
let mtime = state.next_mtime;
|
||||
state.next_inode += 1;
|
||||
state.next_mtime += Duration::from_nanos(1);
|
||||
let file = Arc::new(Mutex::new(FakeFsEntry::File {
|
||||
inode,
|
||||
mtime,
|
||||
content,
|
||||
}));
|
||||
state.write_path(path, move |entry| {
|
||||
match entry {
|
||||
btree_map::Entry::Vacant(e) => {
|
||||
e.insert(file);
|
||||
}
|
||||
btree_map::Entry::Occupied(mut e) => {
|
||||
*e.get_mut() = file;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
})?;
|
||||
state.emit_event(&[path]);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn pause_events(&self) {
|
||||
self.state.lock().events_paused = true;
|
||||
}
|
||||
@@ -952,7 +955,7 @@ impl Fs for FakeFs {
|
||||
async fn atomic_write(&self, path: PathBuf, data: String) -> Result<()> {
|
||||
self.simulate_random_delay().await;
|
||||
let path = normalize_path(path.as_path());
|
||||
self.insert_file(path, data.to_string()).await;
|
||||
self.write_file_internal(path, data.to_string())?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -961,7 +964,7 @@ impl Fs for FakeFs {
|
||||
self.simulate_random_delay().await;
|
||||
let path = normalize_path(path);
|
||||
let content = chunks(text, line_ending).collect();
|
||||
self.insert_file(path, content).await;
|
||||
self.write_file_internal(path, content)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
@@ -2183,7 +2183,7 @@ async fn test_apply_code_actions_with_commands(cx: &mut gpui::TestAppContext) {
|
||||
});
|
||||
}
|
||||
|
||||
#[gpui::test]
|
||||
#[gpui::test(iterations = 10)]
|
||||
async fn test_save_file(cx: &mut gpui::TestAppContext) {
|
||||
let fs = FakeFs::new(cx.background());
|
||||
fs.insert_tree(
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -154,6 +154,12 @@ impl<K> TreeSet<K>
|
||||
where
|
||||
K: Clone + Debug + Default + Ord,
|
||||
{
|
||||
pub fn from_ordered_entries(entries: impl IntoIterator<Item = K>) -> Self {
|
||||
Self(TreeMap::from_ordered_entries(
|
||||
entries.into_iter().map(|key| (key, ())),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn insert(&mut self, key: K) {
|
||||
self.0.insert(key, ());
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ authors = ["Nathan Sobo <nathansobo@gmail.com>"]
|
||||
description = "The fast, collaborative code editor."
|
||||
edition = "2021"
|
||||
name = "zed"
|
||||
version = "0.82.0"
|
||||
version = "0.82.3"
|
||||
publish = false
|
||||
|
||||
[lib]
|
||||
|
||||
@@ -1 +1 @@
|
||||
dev
|
||||
preview
|
||||
Reference in New Issue
Block a user