diff --git a/crates/languages/src/python.rs b/crates/languages/src/python.rs index 978f22d91c26c604ba670d712589199a64275950..659a6b017c9eec85be4d950f2cac18d9ccdc7f17 100644 --- a/crates/languages/src/python.rs +++ b/crates/languages/src/python.rs @@ -87,6 +87,18 @@ fn server_binary_arguments(server_path: &Path) -> Vec { vec![server_path.into(), "--stdio".into()] } +/// Pyright assigns each completion item a `sortText` of the form `XX.YYYY.name`. +/// Where `XX` is the sorting category, `YYYY` is based on most recent usage, +/// and `name` is the symbol name itself. +/// +/// The problem with it is that Pyright adjusts the sort text based on previous resolutions (items for which we've issued `completion/resolve` call have their sortText adjusted), +/// which - long story short - makes completion items list non-stable. Pyright probably relies on VSCode's implementation detail. +/// see https://github.com/microsoft/pyright/blob/95ef4e103b9b2f129c9320427e51b73ea7cf78bd/packages/pyright-internal/src/languageService/completionProvider.ts#LL2873 +fn process_pyright_completions(items: &mut [lsp::CompletionItem]) { + for item in items { + item.sort_text.take(); + } +} pub struct PythonLspAdapter { node: NodeRuntime, } @@ -232,26 +244,7 @@ impl LspAdapter for PythonLspAdapter { } async fn process_completions(&self, items: &mut [lsp::CompletionItem]) { - // Pyright assigns each completion item a `sortText` of the form `XX.YYYY.name`. - // Where `XX` is the sorting category, `YYYY` is based on most recent usage, - // and `name` is the symbol name itself. - // - // Because the symbol name is included, there generally are not ties when - // sorting by the `sortText`, so the symbol's fuzzy match score is not taken - // into account. Here, we remove the symbol name from the sortText in order - // to allow our own fuzzy score to be used to break ties. - // - // see https://github.com/microsoft/pyright/blob/95ef4e103b9b2f129c9320427e51b73ea7cf78bd/packages/pyright-internal/src/languageService/completionProvider.ts#LL2873 - for item in items { - let Some(sort_text) = &mut item.sort_text else { - continue; - }; - let mut parts = sort_text.split('.'); - let Some(first) = parts.next() else { continue }; - let Some(second) = parts.next() else { continue }; - let Some(_) = parts.next() else { continue }; - sort_text.replace_range(first.len() + second.len() + 1.., ""); - } + process_pyright_completions(items); } async fn label_for_completion( @@ -1490,26 +1483,7 @@ impl LspAdapter for BasedPyrightLspAdapter { } async fn process_completions(&self, items: &mut [lsp::CompletionItem]) { - // Pyright assigns each completion item a `sortText` of the form `XX.YYYY.name`. - // Where `XX` is the sorting category, `YYYY` is based on most recent usage, - // and `name` is the symbol name itself. - // - // Because the symbol name is included, there generally are not ties when - // sorting by the `sortText`, so the symbol's fuzzy match score is not taken - // into account. Here, we remove the symbol name from the sortText in order - // to allow our own fuzzy score to be used to break ties. - // - // see https://github.com/microsoft/pyright/blob/95ef4e103b9b2f129c9320427e51b73ea7cf78bd/packages/pyright-internal/src/languageService/completionProvider.ts#LL2873 - for item in items { - let Some(sort_text) = &mut item.sort_text else { - continue; - }; - let mut parts = sort_text.split('.'); - let Some(first) = parts.next() else { continue }; - let Some(second) = parts.next() else { continue }; - let Some(_) = parts.next() else { continue }; - sort_text.replace_range(first.len() + second.len() + 1.., ""); - } + process_pyright_completions(items); } async fn label_for_completion(