diff --git a/crates/ty_ide/src/completion.rs b/crates/ty_ide/src/completion.rs index 9ef5e20d8a..e283045391 100644 --- a/crates/ty_ide/src/completion.rs +++ b/crates/ty_ide/src/completion.rs @@ -5,13 +5,121 @@ use ruff_db::parsed::{ParsedModuleRef, parsed_module}; use ruff_python_ast as ast; use ruff_python_parser::{Token, TokenAt, TokenKind}; use ruff_text_size::{Ranged, TextRange, TextSize}; -use ty_python_semantic::{Completion, NameKind, SemanticModel}; +use ty_python_semantic::{ + Completion as SemanticCompletion, ModuleName, NameKind, SemanticModel, + types::{CycleDetector, Type}, +}; use crate::docstring::Docstring; use crate::find_node::covering_node; use crate::goto::DefinitionsOrTargets; use crate::{Db, all_symbols}; +impl<'db> Completion<'db> { + /// Returns the "kind" of this completion. + /// + /// This is meant to be a very general classification of this completion. + /// Typically, this is communicated from the LSP server to a client, and + /// the client uses this information to help improve the UX (perhaps by + /// assigning an icon of some kind to the completion). + pub fn kind(&self, db: &'db dyn Db) -> Option { + type CompletionKindVisitor<'db> = + CycleDetector, Option>; + + fn imp<'db>( + db: &'db dyn Db, + ty: Type<'db>, + visitor: &CompletionKindVisitor<'db>, + ) -> Option { + Some(match ty { + Type::FunctionLiteral(_) + | Type::DataclassDecorator(_) + | Type::WrapperDescriptor(_) + | Type::DataclassTransformer(_) + | Type::Callable(_) => CompletionKind::Function, + Type::BoundMethod(_) | Type::KnownBoundMethod(_) => CompletionKind::Method, + Type::ModuleLiteral(_) => CompletionKind::Module, + Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => { + CompletionKind::Class + } + // This is a little weird for "struct." I'm mostly interpreting + // "struct" here as a more general "object." ---AG + Type::NominalInstance(_) + | Type::PropertyInstance(_) + | Type::BoundSuper(_) + | Type::TypedDict(_) => CompletionKind::Struct, + Type::IntLiteral(_) + | Type::BooleanLiteral(_) + | Type::TypeIs(_) + | Type::StringLiteral(_) + | Type::LiteralString + | Type::BytesLiteral(_) => CompletionKind::Value, + Type::EnumLiteral(_) => CompletionKind::Enum, + Type::ProtocolInstance(_) => CompletionKind::Interface, + Type::NonInferableTypeVar(_) | Type::TypeVar(_) => CompletionKind::TypeParameter, + Type::Union(union) => union + .elements(db) + .iter() + .find_map(|&ty| imp(db, ty, visitor))?, + Type::Intersection(intersection) => intersection + .iter_positive(db) + .find_map(|ty| imp(db, ty, visitor))?, + Type::Dynamic(_) + | Type::Never + | Type::SpecialForm(_) + | Type::KnownInstance(_) + | Type::AlwaysTruthy + | Type::AlwaysFalsy => return None, + Type::TypeAlias(alias) => { + visitor.visit(ty, || imp(db, alias.value_type(db), visitor))? + } + }) + } + self.kind.or_else(|| { + self.ty + .and_then(|ty| imp(db, ty, &CompletionKindVisitor::default())) + }) + } +} + +/// The "kind" of a completion. +/// +/// This is taken directly from the LSP completion specification: +/// +/// +/// The idea here is that [`Completion::kind`] defines the mapping to this from +/// `Type` (and possibly other information), which might be interesting and +/// contentious. Then the outer edges map this to the LSP types, which is +/// expected to be mundane and boring. +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum CompletionKind { + Text, + Method, + Function, + Constructor, + Field, + Variable, + Class, + Interface, + Module, + Property, + Unit, + Value, + Enum, + Keyword, + Snippet, + Color, + File, + Reference, + Folder, + EnumMember, + Constant, + Struct, + Event, + Operator, + TypeParameter, +} + #[derive(Clone, Debug, Default)] pub struct CompletionSettings { pub auto_import: bool, diff --git a/crates/ty_ide/src/lib.rs b/crates/ty_ide/src/lib.rs index c481c5ad14..40721ee492 100644 --- a/crates/ty_ide/src/lib.rs +++ b/crates/ty_ide/src/lib.rs @@ -26,7 +26,7 @@ mod symbols; mod workspace_symbols; pub use all_symbols::{AllSymbolInfo, all_symbols}; -pub use completion::{CompletionSettings, completion}; +pub use completion::{Completion, CompletionKind, CompletionSettings, completion}; pub use doc_highlights::document_highlights; pub use document_symbols::document_symbols; pub use goto::{goto_declaration, goto_definition, goto_type_definition}; diff --git a/crates/ty_ide/src/symbols.rs b/crates/ty_ide/src/symbols.rs index 6ba3d7101d..39cc0c3aea 100644 --- a/crates/ty_ide/src/symbols.rs +++ b/crates/ty_ide/src/symbols.rs @@ -13,7 +13,8 @@ use ruff_python_ast::visitor::source_order::{self, SourceOrderVisitor}; use ruff_python_ast::{Expr, Stmt}; use ruff_text_size::{Ranged, TextRange}; use ty_project::Db; -use ty_python_semantic::CompletionKind; + +use crate::completion::CompletionKind; /// A compiled query pattern used for searching symbols. /// diff --git a/crates/ty_python_semantic/src/lib.rs b/crates/ty_python_semantic/src/lib.rs index e82fc54c0b..dbe07aa600 100644 --- a/crates/ty_python_semantic/src/lib.rs +++ b/crates/ty_python_semantic/src/lib.rs @@ -19,7 +19,7 @@ pub use program::{ pub use python_platform::PythonPlatform; use rustc_hash::FxHasher; pub use semantic_model::{ - Completion, CompletionKind, HasDefinition, HasType, NameKind, SemanticModel, + Completion, HasDefinition, HasType, MemberDefinition, NameKind, SemanticModel, }; pub use site_packages::{PythonEnvironment, SitePackagesPaths, SysPrefixPathOrigin}; pub use types::DisplaySettings; diff --git a/crates/ty_python_semantic/src/semantic_model.rs b/crates/ty_python_semantic/src/semantic_model.rs index 133553458b..4e7afe275b 100644 --- a/crates/ty_python_semantic/src/semantic_model.rs +++ b/crates/ty_python_semantic/src/semantic_model.rs @@ -11,7 +11,7 @@ use crate::semantic_index::definition::Definition; use crate::semantic_index::scope::FileScopeId; use crate::semantic_index::semantic_index; use crate::types::ide_support::all_declarations_and_bindings; -use crate::types::{CycleDetector, Type, binding_type, infer_scope_types}; +use crate::types::{Type, binding_type, infer_scope_types}; pub struct SemanticModel<'db> { db: &'db dyn Db, @@ -51,7 +51,6 @@ impl<'db> SemanticModel<'db> { Completion { name: Name::new(module.name(self.db).as_str()), ty: Some(ty), - kind: None, builtin, } }) @@ -166,7 +165,6 @@ impl<'db> SemanticModel<'db> { completions.push(Completion { name, ty: Some(ty), - kind: None, builtin, }); } @@ -187,7 +185,6 @@ impl<'db> SemanticModel<'db> { completions.push(Completion { name: Name::new(base), ty: Some(ty), - kind: None, builtin, }); } @@ -202,7 +199,6 @@ impl<'db> SemanticModel<'db> { .map(|member| Completion { name: member.name, ty: Some(member.ty), - kind: None, builtin: false, }) .collect() @@ -239,7 +235,6 @@ impl<'db> SemanticModel<'db> { .map(|memberdef| Completion { name: memberdef.member.name, ty: Some(memberdef.member.ty), - kind: None, builtin: false, }), ); @@ -296,15 +291,6 @@ pub struct Completion<'db> { /// an unimported symbol. In that case, computing the /// type of all such symbols could be quite expensive. pub ty: Option>, - /// The "kind" of this completion. - /// - /// When this is set, it takes priority over any kind - /// inferred from `ty`. - /// - /// Usually this is set when `ty` is `None`, since it - /// may be cheaper to compute at scale. (e.g., For - /// unimported symbol completions.) - pub kind: Option, /// Whether this suggestion came from builtins or not. /// /// At time of writing (2025-06-26), this information @@ -314,110 +300,6 @@ pub struct Completion<'db> { pub builtin: bool, } -impl<'db> Completion<'db> { - /// Returns the "kind" of this completion. - /// - /// This is meant to be a very general classification of this completion. - /// Typically, this is communicated from the LSP server to a client, and - /// the client uses this information to help improve the UX (perhaps by - /// assigning an icon of some kind to the completion). - pub fn kind(&self, db: &'db dyn Db) -> Option { - fn imp<'db>( - db: &'db dyn Db, - ty: Type<'db>, - visitor: &CompletionKindVisitor<'db>, - ) -> Option { - Some(match ty { - Type::FunctionLiteral(_) - | Type::DataclassDecorator(_) - | Type::WrapperDescriptor(_) - | Type::DataclassTransformer(_) - | Type::Callable(_) => CompletionKind::Function, - Type::BoundMethod(_) | Type::KnownBoundMethod(_) => CompletionKind::Method, - Type::ModuleLiteral(_) => CompletionKind::Module, - Type::ClassLiteral(_) | Type::GenericAlias(_) | Type::SubclassOf(_) => { - CompletionKind::Class - } - // This is a little weird for "struct." I'm mostly interpreting - // "struct" here as a more general "object." ---AG - Type::NominalInstance(_) - | Type::PropertyInstance(_) - | Type::BoundSuper(_) - | Type::TypedDict(_) => CompletionKind::Struct, - Type::IntLiteral(_) - | Type::BooleanLiteral(_) - | Type::TypeIs(_) - | Type::StringLiteral(_) - | Type::LiteralString - | Type::BytesLiteral(_) => CompletionKind::Value, - Type::EnumLiteral(_) => CompletionKind::Enum, - Type::ProtocolInstance(_) => CompletionKind::Interface, - Type::NonInferableTypeVar(_) | Type::TypeVar(_) => CompletionKind::TypeParameter, - Type::Union(union) => union - .elements(db) - .iter() - .find_map(|&ty| imp(db, ty, visitor))?, - Type::Intersection(intersection) => intersection - .iter_positive(db) - .find_map(|ty| imp(db, ty, visitor))?, - Type::Dynamic(_) - | Type::Never - | Type::SpecialForm(_) - | Type::KnownInstance(_) - | Type::AlwaysTruthy - | Type::AlwaysFalsy => return None, - Type::TypeAlias(alias) => { - visitor.visit(ty, || imp(db, alias.value_type(db), visitor))? - } - }) - } - self.kind.or_else(|| { - self.ty - .and_then(|ty| imp(db, ty, &CompletionKindVisitor::default())) - }) - } -} - -type CompletionKindVisitor<'db> = CycleDetector, Option>; - -/// The "kind" of a completion. -/// -/// This is taken directly from the LSP completion specification: -/// -/// -/// The idea here is that `Completion::kind` defines the mapping to this from -/// `Type` (and possibly other information), which might be interesting and -/// contentious. Then the outer edges map this to the LSP types, which is -/// expected to be mundane and boring. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] -pub enum CompletionKind { - Text, - Method, - Function, - Constructor, - Field, - Variable, - Class, - Interface, - Module, - Property, - Unit, - Value, - Enum, - Keyword, - Snippet, - Color, - File, - Reference, - Folder, - EnumMember, - Constant, - Struct, - Event, - Operator, - TypeParameter, -} - pub trait HasType { /// Returns the inferred type of `self`. /// diff --git a/crates/ty_wasm/src/lib.rs b/crates/ty_wasm/src/lib.rs index 4bf3d19249..6b750e0f6d 100644 --- a/crates/ty_wasm/src/lib.rs +++ b/crates/ty_wasm/src/lib.rs @@ -425,14 +425,11 @@ impl Workspace { .into_iter() .map(|completion| Completion { kind: completion.kind(&self.db).map(CompletionKind::from), - name: completion.inner.name.into(), + name: completion.name.into(), documentation: completion .documentation .map(|documentation| documentation.render_plaintext()), - detail: completion - .inner - .ty - .map(|ty| ty.display(&self.db).to_string()), + detail: completion.ty.map(|ty| ty.display(&self.db).to_string()), }) .collect()) } @@ -956,34 +953,34 @@ pub enum CompletionKind { TypeParameter, } -impl From for CompletionKind { - fn from(value: ty_python_semantic::CompletionKind) -> Self { +impl From for CompletionKind { + fn from(value: ty_ide::CompletionKind) -> Self { match value { - ty_python_semantic::CompletionKind::Text => Self::Text, - ty_python_semantic::CompletionKind::Method => Self::Method, - ty_python_semantic::CompletionKind::Function => Self::Function, - ty_python_semantic::CompletionKind::Constructor => Self::Constructor, - ty_python_semantic::CompletionKind::Field => Self::Field, - ty_python_semantic::CompletionKind::Variable => Self::Variable, - ty_python_semantic::CompletionKind::Class => Self::Class, - ty_python_semantic::CompletionKind::Interface => Self::Interface, - ty_python_semantic::CompletionKind::Module => Self::Module, - ty_python_semantic::CompletionKind::Property => Self::Property, - ty_python_semantic::CompletionKind::Unit => Self::Unit, - ty_python_semantic::CompletionKind::Value => Self::Value, - ty_python_semantic::CompletionKind::Enum => Self::Enum, - ty_python_semantic::CompletionKind::Keyword => Self::Keyword, - ty_python_semantic::CompletionKind::Snippet => Self::Snippet, - ty_python_semantic::CompletionKind::Color => Self::Color, - ty_python_semantic::CompletionKind::File => Self::File, - ty_python_semantic::CompletionKind::Reference => Self::Reference, - ty_python_semantic::CompletionKind::Folder => Self::Folder, - ty_python_semantic::CompletionKind::EnumMember => Self::EnumMember, - ty_python_semantic::CompletionKind::Constant => Self::Constant, - ty_python_semantic::CompletionKind::Struct => Self::Struct, - ty_python_semantic::CompletionKind::Event => Self::Event, - ty_python_semantic::CompletionKind::Operator => Self::Operator, - ty_python_semantic::CompletionKind::TypeParameter => Self::TypeParameter, + ty_ide::CompletionKind::Text => Self::Text, + ty_ide::CompletionKind::Method => Self::Method, + ty_ide::CompletionKind::Function => Self::Function, + ty_ide::CompletionKind::Constructor => Self::Constructor, + ty_ide::CompletionKind::Field => Self::Field, + ty_ide::CompletionKind::Variable => Self::Variable, + ty_ide::CompletionKind::Class => Self::Class, + ty_ide::CompletionKind::Interface => Self::Interface, + ty_ide::CompletionKind::Module => Self::Module, + ty_ide::CompletionKind::Property => Self::Property, + ty_ide::CompletionKind::Unit => Self::Unit, + ty_ide::CompletionKind::Value => Self::Value, + ty_ide::CompletionKind::Enum => Self::Enum, + ty_ide::CompletionKind::Keyword => Self::Keyword, + ty_ide::CompletionKind::Snippet => Self::Snippet, + ty_ide::CompletionKind::Color => Self::Color, + ty_ide::CompletionKind::File => Self::File, + ty_ide::CompletionKind::Reference => Self::Reference, + ty_ide::CompletionKind::Folder => Self::Folder, + ty_ide::CompletionKind::EnumMember => Self::EnumMember, + ty_ide::CompletionKind::Constant => Self::Constant, + ty_ide::CompletionKind::Struct => Self::Struct, + ty_ide::CompletionKind::Event => Self::Event, + ty_ide::CompletionKind::Operator => Self::Operator, + ty_ide::CompletionKind::TypeParameter => Self::TypeParameter, } } }