mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-29 05:11:44 +03:00
Invalidate copilot suggestion on backspaces
Restore an observation on initialization co-authored-by: antonio <antonio@zed.dev>
This commit is contained in:
parent
e2c690cece
commit
b585470518
@ -50,6 +50,27 @@ pub fn init(http: Arc<dyn HttpClient>, node_runtime: Arc<NodeRuntime>, cx: &mut
|
|||||||
});
|
});
|
||||||
cx.set_global(copilot.clone());
|
cx.set_global(copilot.clone());
|
||||||
|
|
||||||
|
cx.observe(&copilot, |handle, cx| {
|
||||||
|
let status = handle.read(cx).status();
|
||||||
|
cx.update_global::<collections::CommandPaletteFilter, _, _>(
|
||||||
|
move |filter, _cx| match status {
|
||||||
|
Status::Disabled => {
|
||||||
|
filter.filtered_namespaces.insert(COPILOT_NAMESPACE);
|
||||||
|
filter.filtered_namespaces.insert(COPILOT_AUTH_NAMESPACE);
|
||||||
|
}
|
||||||
|
Status::Authorized => {
|
||||||
|
filter.filtered_namespaces.remove(COPILOT_NAMESPACE);
|
||||||
|
filter.filtered_namespaces.remove(COPILOT_AUTH_NAMESPACE);
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
filter.filtered_namespaces.insert(COPILOT_NAMESPACE);
|
||||||
|
filter.filtered_namespaces.remove(COPILOT_AUTH_NAMESPACE);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.detach();
|
||||||
|
|
||||||
sign_in::init(cx);
|
sign_in::init(cx);
|
||||||
cx.add_global_action(|_: &SignIn, cx| {
|
cx.add_global_action(|_: &SignIn, cx| {
|
||||||
if let Some(copilot) = Copilot::global(cx) {
|
if let Some(copilot) = Copilot::global(cx) {
|
||||||
|
@ -1037,6 +1037,11 @@ impl CopilotState {
|
|||||||
let completion = self.completions.get(self.active_completion_index)?;
|
let completion = self.completions.get(self.active_completion_index)?;
|
||||||
let excerpt_id = self.excerpt_id?;
|
let excerpt_id = self.excerpt_id?;
|
||||||
let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
|
let completion_buffer = buffer.buffer_for_excerpt(excerpt_id)?;
|
||||||
|
if !completion.range.start.is_valid(completion_buffer)
|
||||||
|
|| !completion.range.end.is_valid(completion_buffer)
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
let mut completion_range = completion.range.to_offset(&completion_buffer);
|
let mut completion_range = completion.range.to_offset(&completion_buffer);
|
||||||
let prefix_len = Self::common_prefix(
|
let prefix_len = Self::common_prefix(
|
||||||
|
@ -6098,6 +6098,65 @@ async fn test_copilot(deterministic: Arc<Deterministic>, cx: &mut gpui::TestAppC
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_copilot_completion_invalidation(
|
||||||
|
deterministic: Arc<Deterministic>,
|
||||||
|
cx: &mut gpui::TestAppContext,
|
||||||
|
) {
|
||||||
|
let (copilot, copilot_lsp) = Copilot::fake(cx);
|
||||||
|
cx.update(|cx| cx.set_global(copilot));
|
||||||
|
let mut cx = EditorLspTestContext::new_rust(
|
||||||
|
lsp::ServerCapabilities {
|
||||||
|
completion_provider: Some(lsp::CompletionOptions {
|
||||||
|
trigger_characters: Some(vec![".".to_string(), ":".to_string()]),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
cx,
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
|
cx.set_state(indoc! {"
|
||||||
|
one
|
||||||
|
twˇ
|
||||||
|
three
|
||||||
|
"});
|
||||||
|
|
||||||
|
handle_copilot_completion_request(
|
||||||
|
&copilot_lsp,
|
||||||
|
vec![copilot::request::Completion {
|
||||||
|
text: "two.foo()".into(),
|
||||||
|
range: lsp::Range::new(lsp::Position::new(1, 0), lsp::Position::new(1, 2)),
|
||||||
|
..Default::default()
|
||||||
|
}],
|
||||||
|
vec![],
|
||||||
|
);
|
||||||
|
cx.update_editor(|editor, cx| editor.next_copilot_suggestion(&Default::default(), cx));
|
||||||
|
deterministic.advance_clock(COPILOT_DEBOUNCE_TIMEOUT);
|
||||||
|
cx.update_editor(|editor, cx| {
|
||||||
|
assert!(editor.has_active_copilot_suggestion(cx));
|
||||||
|
assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n");
|
||||||
|
assert_eq!(editor.text(cx), "one\ntw\nthree\n");
|
||||||
|
|
||||||
|
editor.backspace(&Default::default(), cx);
|
||||||
|
assert!(editor.has_active_copilot_suggestion(cx));
|
||||||
|
assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n");
|
||||||
|
assert_eq!(editor.text(cx), "one\nt\nthree\n");
|
||||||
|
|
||||||
|
editor.backspace(&Default::default(), cx);
|
||||||
|
assert!(editor.has_active_copilot_suggestion(cx));
|
||||||
|
assert_eq!(editor.display_text(cx), "one\ntwo.foo()\nthree\n");
|
||||||
|
assert_eq!(editor.text(cx), "one\n\nthree\n");
|
||||||
|
|
||||||
|
// Deleting across the original suggestion range invalidates it.
|
||||||
|
editor.backspace(&Default::default(), cx);
|
||||||
|
assert!(!editor.has_active_copilot_suggestion(cx));
|
||||||
|
assert_eq!(editor.display_text(cx), "one\nthree\n");
|
||||||
|
assert_eq!(editor.text(cx), "one\nthree\n");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
fn empty_range(row: usize, column: usize) -> Range<DisplayPoint> {
|
||||||
let point = DisplayPoint::new(row as u32, column as u32);
|
let point = DisplayPoint::new(row as u32, column as u32);
|
||||||
point..point
|
point..point
|
||||||
|
@ -1,4 +1,7 @@
|
|||||||
use crate::{BufferSnapshot, Point, PointUtf16, TextDimension, ToOffset, ToPoint, ToPointUtf16};
|
use crate::{
|
||||||
|
locator::Locator, BufferSnapshot, Point, PointUtf16, TextDimension, ToOffset, ToPoint,
|
||||||
|
ToPointUtf16,
|
||||||
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::{cmp::Ordering, fmt::Debug, ops::Range};
|
use std::{cmp::Ordering, fmt::Debug, ops::Range};
|
||||||
use sum_tree::Bias;
|
use sum_tree::Bias;
|
||||||
@ -86,6 +89,20 @@ impl Anchor {
|
|||||||
{
|
{
|
||||||
content.summary_for_anchor(self)
|
content.summary_for_anchor(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns true when the [Anchor] is located inside a visible fragment.
|
||||||
|
pub fn is_valid(&self, buffer: &BufferSnapshot) -> bool {
|
||||||
|
if *self == Anchor::MIN || *self == Anchor::MAX {
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
let fragment_id = buffer.fragment_id_for_anchor(self);
|
||||||
|
let mut fragment_cursor = buffer.fragments.cursor::<(Option<&Locator>, usize)>();
|
||||||
|
fragment_cursor.seek(&Some(fragment_id), Bias::Left, &None);
|
||||||
|
fragment_cursor
|
||||||
|
.item()
|
||||||
|
.map_or(false, |fragment| fragment.visible)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait OffsetRangeExt {
|
pub trait OffsetRangeExt {
|
||||||
|
Loading…
Reference in New Issue
Block a user