mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-30 23:12:53 +03:00
Start work on handling snippet completions
This commit is contained in:
parent
680fde9608
commit
7270fd00ba
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -1562,6 +1562,7 @@ dependencies = [
|
|||||||
"serde",
|
"serde",
|
||||||
"smallvec",
|
"smallvec",
|
||||||
"smol",
|
"smol",
|
||||||
|
"snippet",
|
||||||
"sum_tree",
|
"sum_tree",
|
||||||
"text",
|
"text",
|
||||||
"theme",
|
"theme",
|
||||||
|
@ -22,7 +22,9 @@ collections = { path = "../collections" }
|
|||||||
fuzzy = { path = "../fuzzy" }
|
fuzzy = { path = "../fuzzy" }
|
||||||
gpui = { path = "../gpui" }
|
gpui = { path = "../gpui" }
|
||||||
language = { path = "../language" }
|
language = { path = "../language" }
|
||||||
|
lsp = { path = "../lsp" }
|
||||||
project = { path = "../project" }
|
project = { path = "../project" }
|
||||||
|
snippet = { path = "../snippet" }
|
||||||
sum_tree = { path = "../sum_tree" }
|
sum_tree = { path = "../sum_tree" }
|
||||||
theme = { path = "../theme" }
|
theme = { path = "../theme" }
|
||||||
util = { path = "../util" }
|
util = { path = "../util" }
|
||||||
|
@ -42,6 +42,7 @@ use postage::watch;
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use smol::Timer;
|
use smol::Timer;
|
||||||
|
use snippet::Snippet;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId,
|
any::TypeId,
|
||||||
cmp::{self, Ordering, Reverse},
|
cmp::{self, Ordering, Reverse},
|
||||||
@ -1656,10 +1657,22 @@ impl Editor {
|
|||||||
.matches
|
.matches
|
||||||
.get(completion_state.selected_item)?;
|
.get(completion_state.selected_item)?;
|
||||||
let completion = completion_state.completions.get(mat.candidate_id)?;
|
let completion = completion_state.completions.get(mat.candidate_id)?;
|
||||||
|
|
||||||
|
if completion.lsp_completion.insert_text_format == Some(lsp::InsertTextFormat::SNIPPET) {
|
||||||
|
self.insert_snippet(completion.old_range.clone(), &completion.new_text, cx)
|
||||||
|
.log_err();
|
||||||
|
} else {
|
||||||
|
self.buffer.update(cx, |buffer, cx| {
|
||||||
|
buffer.edit_with_autoindent(
|
||||||
|
[completion.old_range.clone()],
|
||||||
|
&completion.new_text,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
self.buffer.update(cx, |buffer, cx| {
|
self.buffer.update(cx, |buffer, cx| {
|
||||||
let mut completion = completion.clone();
|
buffer.apply_additional_edits_for_completion(completion.clone(), cx)
|
||||||
// completion.
|
|
||||||
buffer.apply_completion(completion, cx)
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1722,6 +1735,42 @@ impl Editor {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn insert_snippet<S>(
|
||||||
|
&mut self,
|
||||||
|
range: Range<S>,
|
||||||
|
text: &str,
|
||||||
|
cx: &mut ViewContext<Self>,
|
||||||
|
) -> Result<()>
|
||||||
|
where
|
||||||
|
S: Clone + ToOffset,
|
||||||
|
{
|
||||||
|
let snippet = Snippet::parse(text)?;
|
||||||
|
let tabstops = self.buffer.update(cx, |buffer, cx| {
|
||||||
|
buffer.edit_with_autoindent([range.clone()], snippet.text, cx);
|
||||||
|
let snapshot = buffer.read(cx);
|
||||||
|
let start = range.start.to_offset(&snapshot);
|
||||||
|
snippet
|
||||||
|
.tabstops
|
||||||
|
.iter()
|
||||||
|
.map(|ranges| {
|
||||||
|
ranges
|
||||||
|
.into_iter()
|
||||||
|
.map(|range| {
|
||||||
|
snapshot.anchor_before(start + range.start)
|
||||||
|
..snapshot.anchor_after(start + range.end)
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
})
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
});
|
||||||
|
|
||||||
|
if let Some(tabstop) = tabstops.first() {
|
||||||
|
self.select_ranges(tabstop.iter().cloned(), Some(Autoscroll::Fit), cx);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
|
pub fn clear(&mut self, cx: &mut ViewContext<Self>) {
|
||||||
self.start_transaction(cx);
|
self.start_transaction(cx);
|
||||||
self.select_all(&SelectAll, cx);
|
self.select_all(&SelectAll, cx);
|
||||||
@ -6581,6 +6630,23 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[gpui::test]
|
||||||
|
async fn test_snippets(mut cx: gpui::TestAppContext) {
|
||||||
|
let settings = cx.read(EditorSettings::test);
|
||||||
|
|
||||||
|
let text = "a. b";
|
||||||
|
let buffer = cx.update(|cx| MultiBuffer::build_simple(&text, cx));
|
||||||
|
let (_, editor) = cx.add_window(|cx| build_editor(buffer, settings, cx));
|
||||||
|
|
||||||
|
editor.update(&mut cx, |editor, cx| {
|
||||||
|
editor
|
||||||
|
.insert_snippet(2..2, "f(${1:one}, ${2:two})$0", cx)
|
||||||
|
.unwrap();
|
||||||
|
assert_eq!(editor.text(cx), "a.f(one, two) b");
|
||||||
|
assert_eq!(editor.selected_ranges::<usize>(cx), &[4..7]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
#[gpui::test]
|
#[gpui::test]
|
||||||
async fn test_completion(mut cx: gpui::TestAppContext) {
|
async fn test_completion(mut cx: gpui::TestAppContext) {
|
||||||
let settings = cx.read(EditorSettings::test);
|
let settings = cx.read(EditorSettings::test);
|
||||||
|
@ -929,7 +929,7 @@ impl MultiBuffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_completion(
|
pub fn apply_additional_edits_for_completion(
|
||||||
&self,
|
&self,
|
||||||
completion: Completion<Anchor>,
|
completion: Completion<Anchor>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
@ -941,7 +941,7 @@ impl MultiBuffer {
|
|||||||
.buffer
|
.buffer
|
||||||
.clone();
|
.clone();
|
||||||
buffer.update(cx, |buffer, cx| {
|
buffer.update(cx, |buffer, cx| {
|
||||||
buffer.apply_completion(
|
buffer.apply_additional_edits_for_completion(
|
||||||
Completion {
|
Completion {
|
||||||
old_range: completion.old_range.start.text_anchor
|
old_range: completion.old_range.start.text_anchor
|
||||||
..completion.old_range.end.text_anchor,
|
..completion.old_range.end.text_anchor,
|
||||||
|
@ -1777,13 +1777,11 @@ impl Buffer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_completion(
|
pub fn apply_additional_edits_for_completion(
|
||||||
&mut self,
|
&mut self,
|
||||||
completion: Completion<Anchor>,
|
completion: Completion<Anchor>,
|
||||||
cx: &mut ModelContext<Self>,
|
cx: &mut ModelContext<Self>,
|
||||||
) -> Option<Task<Result<()>>> {
|
) -> Option<Task<Result<()>>> {
|
||||||
self.edit_with_autoindent([completion.old_range], completion.new_text.clone(), cx);
|
|
||||||
|
|
||||||
self.file.as_ref()?.as_local()?;
|
self.file.as_ref()?.as_local()?;
|
||||||
let server = self.language_server.as_ref()?.server.clone();
|
let server = self.language_server.as_ref()?.server.clone();
|
||||||
Some(cx.spawn(|this, mut cx| async move {
|
Some(cx.spawn(|this, mut cx| async move {
|
||||||
|
Loading…
Reference in New Issue
Block a user