editor: Change to pass cursor as offset for completions method. (#1271)
And to support `filter_text` as completion item highlight match.
This commit is contained in:
parent
62748aad9b
commit
f93e9a9475
4 changed files with 30 additions and 29 deletions
2
.github/workflows/ci.yml
vendored
2
.github/workflows/ci.yml
vendored
|
|
@ -32,7 +32,7 @@ jobs:
|
||||||
run: script/bootstrap
|
run: script/bootstrap
|
||||||
- name: Machete
|
- name: Machete
|
||||||
if: ${{ matrix.run_on == 'macos-latest' }}
|
if: ${{ matrix.run_on == 'macos-latest' }}
|
||||||
uses: bnjbvr/cargo-machete@main
|
uses: bnjbvr/cargo-machete@v0.9.1
|
||||||
- name: Setup | Cache Cargo
|
- name: Setup | Cache Cargo
|
||||||
uses: actions/cache@v4
|
uses: actions/cache@v4
|
||||||
with:
|
with:
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ impl ExampleLspStore {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn completion_item(
|
fn completion_item(
|
||||||
range: &lsp_types::Range,
|
replace_range: &lsp_types::Range,
|
||||||
label: &str,
|
label: &str,
|
||||||
replace_text: &str,
|
replace_text: &str,
|
||||||
documentation: &str,
|
documentation: &str,
|
||||||
|
|
@ -177,8 +177,8 @@ fn completion_item(
|
||||||
kind: Some(lsp_types::CompletionItemKind::FUNCTION),
|
kind: Some(lsp_types::CompletionItemKind::FUNCTION),
|
||||||
text_edit: Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit {
|
text_edit: Some(CompletionTextEdit::InsertAndReplace(InsertReplaceEdit {
|
||||||
new_text: replace_text.to_string(),
|
new_text: replace_text.to_string(),
|
||||||
insert: range.clone(),
|
insert: replace_range.clone(),
|
||||||
replace: range.clone(),
|
replace: replace_range.clone(),
|
||||||
})),
|
})),
|
||||||
documentation: Some(lsp_types::Documentation::String(documentation.to_string())),
|
documentation: Some(lsp_types::Documentation::String(documentation.to_string())),
|
||||||
insert_text: None,
|
insert_text: None,
|
||||||
|
|
@ -204,33 +204,28 @@ impl CompletionProvider for ExampleLspStore {
|
||||||
let rope = rope.clone();
|
let rope = rope.clone();
|
||||||
let items = self.completions.clone();
|
let items = self.completions.clone();
|
||||||
cx.background_spawn(async move {
|
cx.background_spawn(async move {
|
||||||
let pos = rope.offset_to_position(offset);
|
|
||||||
|
|
||||||
// Simulate a slow completion source, to test Editor async handling.
|
// Simulate a slow completion source, to test Editor async handling.
|
||||||
smol::Timer::after(Duration::from_millis(20)).await;
|
smol::Timer::after(Duration::from_millis(20)).await;
|
||||||
|
|
||||||
let range = lsp_types::Range::new(
|
|
||||||
pos,
|
|
||||||
lsp_types::Position {
|
|
||||||
line: pos.line,
|
|
||||||
character: pos.character + 1,
|
|
||||||
},
|
|
||||||
);
|
|
||||||
|
|
||||||
if trigger_character.starts_with("/") {
|
if trigger_character.starts_with("/") {
|
||||||
|
let start = offset.saturating_sub(trigger_character.len());
|
||||||
|
let start_pos = rope.offset_to_position(start);
|
||||||
|
let end_pos = rope.offset_to_position(offset);
|
||||||
|
let replace_range = lsp_types::Range::new(start_pos, end_pos);
|
||||||
|
|
||||||
let items = vec![
|
let items = vec![
|
||||||
completion_item(
|
completion_item(
|
||||||
&range,
|
&replace_range,
|
||||||
"/date",
|
"/date",
|
||||||
format!("{}", chrono::Local::now().date_naive()).as_str(),
|
format!("{}", chrono::Local::now().date_naive()).as_str(),
|
||||||
"Insert current date",
|
"Insert current date",
|
||||||
),
|
),
|
||||||
completion_item(&range, "/thanks", "Thank you!", "Insert Thank you!"),
|
completion_item(&replace_range, "/thanks", "Thank you!", "Insert Thank you!"),
|
||||||
completion_item(&range, "/+1", "👍", "Insert 👍"),
|
completion_item(&replace_range, "/+1", "👍", "Insert 👍"),
|
||||||
completion_item(&range, "/-1", "👎", "Insert 👎"),
|
completion_item(&replace_range, "/-1", "👎", "Insert 👎"),
|
||||||
completion_item(&range, "/smile", "😊", "Insert 😊"),
|
completion_item(&replace_range, "/smile", "😊", "Insert 😊"),
|
||||||
completion_item(&range, "/sad", "😢", "Insert 😢"),
|
completion_item(&replace_range, "/sad", "😢", "Insert 😢"),
|
||||||
completion_item(&range, "/launch", "🚀", "Insert 🚀"),
|
completion_item(&replace_range, "/launch", "🚀", "Insert 🚀"),
|
||||||
];
|
];
|
||||||
return Ok(CompletionResponse::Array(items));
|
return Ok(CompletionResponse::Array(items));
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,8 @@ use crate::input::{
|
||||||
pub trait CompletionProvider {
|
pub trait CompletionProvider {
|
||||||
/// Fetches completions based on the given byte offset.
|
/// Fetches completions based on the given byte offset.
|
||||||
///
|
///
|
||||||
|
/// - The `offset` is in bytes of current cursor.
|
||||||
|
///
|
||||||
/// textDocument/completion
|
/// textDocument/completion
|
||||||
///
|
///
|
||||||
/// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
|
/// https://microsoft.github.io/language-server-protocol/specifications/lsp/3.17/specification/#textDocument_completion
|
||||||
|
|
@ -107,7 +109,7 @@ impl InputState {
|
||||||
};
|
};
|
||||||
|
|
||||||
let provider_responses =
|
let provider_responses =
|
||||||
provider.completions(&self.text, start_offset, completion_context, window, cx);
|
provider.completions(&self.text, new_offset, completion_context, window, cx);
|
||||||
self._context_menu_task = cx.spawn_in(window, async move |editor, cx| {
|
self._context_menu_task = cx.spawn_in(window, async move |editor, cx| {
|
||||||
let mut completions: Vec<CompletionItem> = vec![];
|
let mut completions: Vec<CompletionItem> = vec![];
|
||||||
if let Some(provider_responses) = provider_responses.await.ok() {
|
if let Some(provider_responses) = provider_responses.await.ok() {
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ struct CompletionMenuItem {
|
||||||
item: Rc<CompletionItem>,
|
item: Rc<CompletionItem>,
|
||||||
children: Vec<AnyElement>,
|
children: Vec<AnyElement>,
|
||||||
selected: bool,
|
selected: bool,
|
||||||
highlight_prefix_len: usize,
|
highlight_prefix: SharedString,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompletionMenuItem {
|
impl CompletionMenuItem {
|
||||||
|
|
@ -58,12 +58,12 @@ impl CompletionMenuItem {
|
||||||
item,
|
item,
|
||||||
children: vec![],
|
children: vec![],
|
||||||
selected: false,
|
selected: false,
|
||||||
highlight_prefix_len: 0,
|
highlight_prefix: "".into(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn highlight_prefix(mut self, len: usize) -> Self {
|
fn highlight_prefix(mut self, s: impl Into<SharedString>) -> Self {
|
||||||
self.highlight_prefix_len = len;
|
self.highlight_prefix = s.into();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -88,7 +88,12 @@ impl RenderOnce for CompletionMenuItem {
|
||||||
let item = self.item;
|
let item = self.item;
|
||||||
|
|
||||||
let deprecated = item.deprecated.unwrap_or(false);
|
let deprecated = item.deprecated.unwrap_or(false);
|
||||||
let matched_len = self.highlight_prefix_len;
|
let matched_len = item
|
||||||
|
.filter_text
|
||||||
|
.as_ref()
|
||||||
|
.map(|s| s.len())
|
||||||
|
.unwrap_or(self.highlight_prefix.len());
|
||||||
|
|
||||||
let highlights = vec![(
|
let highlights = vec![(
|
||||||
0..matched_len,
|
0..matched_len,
|
||||||
HighlightStyle {
|
HighlightStyle {
|
||||||
|
|
@ -139,8 +144,7 @@ impl ListDelegate for ContextMenuDelegate {
|
||||||
_: &mut Context<List<Self>>,
|
_: &mut Context<List<Self>>,
|
||||||
) -> Option<Self::Item> {
|
) -> Option<Self::Item> {
|
||||||
let item = self.items.get(ix.row)?;
|
let item = self.items.get(ix.row)?;
|
||||||
let matched_len = self.query.len();
|
Some(CompletionMenuItem::new(ix.row, item.clone()).highlight_prefix(self.query.clone()))
|
||||||
Some(CompletionMenuItem::new(ix.row, item.clone()).highlight_prefix(matched_len))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_selected_index(
|
fn set_selected_index(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue