Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 28 additions & 6 deletions crates/ty_ide/src/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,11 @@ use ruff_text_size::{Ranged, TextRange, TextSize};
use ty_python_semantic::{Completion, NameKind, SemanticModel};

use crate::Db;
use crate::docstring::Docstring;
use crate::find_node::covering_node;
use crate::goto::DefinitionsOrTargets;

pub fn completion(db: &dyn Db, file: File, offset: TextSize) -> Vec<Completion<'_>> {
pub fn completion(db: &dyn Db, file: File, offset: TextSize) -> Vec<DetailedCompletion<'_>> {
let parsed = parsed_module(db, file).load(db);

let Some(target_token) = CompletionTargetTokens::find(&parsed, offset) else {
Expand Down Expand Up @@ -40,6 +42,27 @@ pub fn completion(db: &dyn Db, file: File, offset: TextSize) -> Vec<Completion<'
completions.sort_by(compare_suggestions);
completions.dedup_by(|c1, c2| c1.name == c2.name);
completions
.into_iter()
.map(|completion| {
let definition = DefinitionsOrTargets::from_ty(db, completion.ty);
let documentation = definition.and_then(|def| def.docstring(db));
DetailedCompletion {
inner: completion,
documentation,
}
})
.collect()
}

pub struct DetailedCompletion<'db> {
pub inner: Completion<'db>,
pub documentation: Option<Docstring>,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we make this a field on Completion instead that defaults to None: Given that completion is the only method constructing the completions

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently that doesn't work out because Docstring is defined in ty_ide and Completion is defined in ty_python_semantic. The crate boundaries have gotten quite wobbly 😅

}
impl<'db> std::ops::Deref for DetailedCompletion<'db> {
type Target = Completion<'db>;
fn deref(&self) -> &Self::Target {
&self.inner
}
}

/// The kind of tokens identified under the cursor.
Expand Down Expand Up @@ -478,9 +501,8 @@ fn compare_suggestions(c1: &Completion, c2: &Completion) -> Ordering {
mod tests {
use insta::assert_snapshot;
use ruff_python_parser::{Mode, ParseOptions, TokenKind, Tokens};
use ty_python_semantic::Completion;

use crate::completion;
use crate::completion::{DetailedCompletion, completion};
use crate::tests::{CursorTest, cursor_test};

use super::token_suffix_by_kinds;
Expand Down Expand Up @@ -3022,14 +3044,14 @@ from os.<CURSOR>
)
}

fn completions_if(&self, predicate: impl Fn(&Completion) -> bool) -> String {
fn completions_if(&self, predicate: impl Fn(&DetailedCompletion) -> bool) -> String {
self.completions_if_snapshot(predicate, |c| c.name.as_str().to_string())
}

fn completions_if_snapshot(
&self,
predicate: impl Fn(&Completion) -> bool,
snapshot: impl Fn(&Completion) -> String,
predicate: impl Fn(&DetailedCompletion) -> bool,
snapshot: impl Fn(&DetailedCompletion) -> String,
) -> String {
let completions = completion(&self.db, self.cursor.file, self.cursor.offset);
if completions.is_empty() {
Expand Down
22 changes: 22 additions & 0 deletions crates/ty_ide/src/goto.rs
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,28 @@ pub(crate) enum DefinitionsOrTargets<'db> {
}

impl<'db> DefinitionsOrTargets<'db> {
pub(crate) fn from_ty(db: &'db dyn crate::Db, ty: Type<'db>) -> Option<Self> {
let ty_def = ty.definition(db)?;
let resolved = match ty_def {
ty_python_semantic::types::TypeDefinition::Module(module) => {
ResolvedDefinition::Module(module.file(db)?)
}
ty_python_semantic::types::TypeDefinition::Class(definition) => {
ResolvedDefinition::Definition(definition)
}
ty_python_semantic::types::TypeDefinition::Function(definition) => {
ResolvedDefinition::Definition(definition)
}
ty_python_semantic::types::TypeDefinition::TypeVar(definition) => {
ResolvedDefinition::Definition(definition)
}
ty_python_semantic::types::TypeDefinition::TypeAlias(definition) => {
ResolvedDefinition::Definition(definition)
}
};
Some(DefinitionsOrTargets::Definitions(vec![resolved]))
}

/// Get the "goto-declaration" interpretation of this definition
///
/// In this case it basically returns exactly what was found.
Expand Down
9 changes: 7 additions & 2 deletions crates/ty_server/src/server/api/requests/completion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ use std::borrow::Cow;
use std::time::Instant;

use lsp_types::request::Completion;
use lsp_types::{CompletionItem, CompletionItemKind, CompletionParams, CompletionResponse, Url};
use lsp_types::{
CompletionItem, CompletionItemKind, CompletionParams, CompletionResponse, Documentation, Url,
};
use ruff_db::source::{line_index, source_text};
use ty_ide::completion;
use ty_project::ProjectDatabase;
Expand Down Expand Up @@ -64,9 +66,12 @@ impl BackgroundDocumentRequestHandler for CompletionRequestHandler {
.map(|(i, comp)| {
let kind = comp.kind(db).map(ty_kind_to_lsp_kind);
CompletionItem {
label: comp.name.into(),
label: comp.inner.name.into(),
kind,
sort_text: Some(format!("{i:-max_index_len$}")),
documentation: comp
.documentation
.map(|docstring| Documentation::String(docstring.render_plaintext())),
..Default::default()
}
})
Expand Down
7 changes: 6 additions & 1 deletion crates/ty_wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,10 @@ impl Workspace {
.into_iter()
.map(|completion| Completion {
kind: completion.kind(&self.db).map(CompletionKind::from),
name: completion.name.into(),
name: completion.inner.name.into(),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be nice to also hook up documentation in the playground. You have to add a new documentation field to Completion, then propagate the field here

insertText: completion.name,

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think done? Never tested the playground.

documentation: completion
.documentation
.map(|documentation| documentation.render_plaintext()),
})
.collect())
}
Expand Down Expand Up @@ -908,6 +911,8 @@ pub struct Completion {
#[wasm_bindgen(getter_with_clone)]
pub name: String,
pub kind: Option<CompletionKind>,
#[wasm_bindgen(getter_with_clone)]
pub documentation: Option<String>,
}

#[wasm_bindgen]
Expand Down
1 change: 1 addition & 0 deletions playground/ty/src/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,7 @@ class PlaygroundServer
? CompletionItemKind.Variable
: mapCompletionKind(completion.kind),
insertText: completion.name,
documentation: completion.documentation,
// TODO(micha): It's unclear why this field is required for monaco but not VS Code.
// and omitting it works just fine? The LSP doesn't expose this information right now
// which is why we go with undefined for now.
Expand Down
Loading