[ty] Add signature help provider to playground (#19276)

This commit is contained in:
Micha Reiser 2025-07-11 09:58:14 +02:00 committed by GitHub
parent b0b65c24ff
commit 426fa4bb12
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 138 additions and 1 deletions

View file

@ -14,6 +14,7 @@ use ruff_notebook::Notebook;
use ruff_python_formatter::formatted_file; use ruff_python_formatter::formatted_file;
use ruff_source_file::{LineIndex, OneIndexed, SourceLocation}; use ruff_source_file::{LineIndex, OneIndexed, SourceLocation};
use ruff_text_size::{Ranged, TextSize}; use ruff_text_size::{Ranged, TextSize};
use ty_ide::signature_help;
use ty_ide::{MarkupKind, goto_type_definition, hover, inlay_hints}; use ty_ide::{MarkupKind, goto_type_definition, hover, inlay_hints};
use ty_project::ProjectMetadata; use ty_project::ProjectMetadata;
use ty_project::metadata::options::Options; use ty_project::metadata::options::Options;
@ -385,6 +386,51 @@ impl Workspace {
Ok(result) Ok(result)
} }
#[wasm_bindgen(js_name = "signatureHelp")]
pub fn signature_help(
&self,
file_id: &FileHandle,
position: Position,
) -> Result<Option<SignatureHelp>, Error> {
let source = source_text(&self.db, file_id.file);
let index = line_index(&self.db, file_id.file);
let offset = position.to_text_size(&source, &index, self.position_encoding)?;
let Some(signature_help_info) = signature_help(&self.db, file_id.file, offset) else {
return Ok(None);
};
let signatures = signature_help_info
.signatures
.into_iter()
.map(|sig| {
let parameters = sig
.parameters
.into_iter()
.map(|param| ParameterInformation {
label: param.label,
documentation: param.documentation,
})
.collect();
SignatureInformation {
label: sig.label,
documentation: sig.documentation,
parameters,
active_parameter: sig.active_parameter.and_then(|p| u32::try_from(p).ok()),
}
})
.collect();
Ok(Some(SignatureHelp {
signatures,
active_signature: signature_help_info
.active_signature
.and_then(|s| u32::try_from(s).ok()),
}))
}
} }
pub(crate) fn into_error<E: std::fmt::Display>(err: E) -> Error { pub(crate) fn into_error<E: std::fmt::Display>(err: E) -> Error {
@ -749,6 +795,35 @@ pub struct SemanticToken {
pub range: Range, pub range: Range,
} }
#[wasm_bindgen]
#[derive(Clone)]
pub struct SignatureHelp {
#[wasm_bindgen(getter_with_clone)]
pub signatures: Vec<SignatureInformation>,
pub active_signature: Option<u32>,
}
#[wasm_bindgen]
#[derive(Clone)]
pub struct SignatureInformation {
#[wasm_bindgen(getter_with_clone)]
pub label: String,
#[wasm_bindgen(getter_with_clone)]
pub documentation: Option<String>,
#[wasm_bindgen(getter_with_clone)]
pub parameters: Vec<ParameterInformation>,
pub active_parameter: Option<u32>,
}
#[wasm_bindgen]
#[derive(Clone)]
pub struct ParameterInformation {
#[wasm_bindgen(getter_with_clone)]
pub label: String,
#[wasm_bindgen(getter_with_clone)]
pub documentation: Option<String>,
}
#[wasm_bindgen] #[wasm_bindgen]
impl SemanticToken { impl SemanticToken {
pub fn kinds() -> Vec<String> { pub fn kinds() -> Vec<String> {

View file

@ -152,7 +152,8 @@ class PlaygroundServer
languages.DocumentFormattingEditProvider, languages.DocumentFormattingEditProvider,
languages.CompletionItemProvider, languages.CompletionItemProvider,
languages.DocumentSemanticTokensProvider, languages.DocumentSemanticTokensProvider,
languages.DocumentRangeSemanticTokensProvider languages.DocumentRangeSemanticTokensProvider,
languages.SignatureHelpProvider
{ {
private typeDefinitionProviderDisposable: IDisposable; private typeDefinitionProviderDisposable: IDisposable;
private editorOpenerDisposable: IDisposable; private editorOpenerDisposable: IDisposable;
@ -162,6 +163,7 @@ class PlaygroundServer
private completionDisposable: IDisposable; private completionDisposable: IDisposable;
private semanticTokensDisposable: IDisposable; private semanticTokensDisposable: IDisposable;
private rangeSemanticTokensDisposable: IDisposable; private rangeSemanticTokensDisposable: IDisposable;
private signatureHelpDisposable: IDisposable;
constructor( constructor(
private monaco: Monaco, private monaco: Monaco,
@ -191,9 +193,13 @@ class PlaygroundServer
this.editorOpenerDisposable = monaco.editor.registerEditorOpener(this); this.editorOpenerDisposable = monaco.editor.registerEditorOpener(this);
this.formatDisposable = this.formatDisposable =
monaco.languages.registerDocumentFormattingEditProvider("python", this); monaco.languages.registerDocumentFormattingEditProvider("python", this);
this.signatureHelpDisposable =
monaco.languages.registerSignatureHelpProvider("python", this);
} }
triggerCharacters: string[] = ["."]; triggerCharacters: string[] = ["."];
signatureHelpTriggerCharacters: string[] = ["(", ","];
signatureHelpRetriggerCharacters: string[] = [")"];
getLegend(): languages.SemanticTokensLegend { getLegend(): languages.SemanticTokensLegend {
return { return {
@ -292,6 +298,61 @@ class PlaygroundServer
resolveCompletionItem: undefined; resolveCompletionItem: undefined;
provideSignatureHelp(
model: editor.ITextModel,
position: Position,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_token: CancellationToken,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
_context: languages.SignatureHelpContext,
): languages.ProviderResult<languages.SignatureHelpResult> {
const selectedFile = this.props.files.selected;
if (selectedFile == null) {
return;
}
const selectedHandle = this.props.files.handles[selectedFile];
if (selectedHandle == null) {
return;
}
const signatureHelp = this.props.workspace.signatureHelp(
selectedHandle,
new TyPosition(position.lineNumber, position.column),
);
if (signatureHelp == null) {
return undefined;
}
return {
dispose() {},
value: {
signatures: signatureHelp.signatures.map((sig) => ({
label: sig.label,
documentation: sig.documentation
? { value: sig.documentation }
: undefined,
parameters: sig.parameters.map((param) => ({
label: param.label,
documentation: param.documentation
? { value: param.documentation }
: undefined,
})),
activeParameter: sig.active_parameter,
})),
activeSignature: signatureHelp.active_signature ?? 0,
activeParameter:
signatureHelp.active_signature != null
? (signatureHelp.signatures[signatureHelp.active_signature]
?.active_parameter ?? 0)
: 0,
},
};
}
provideInlayHints( provideInlayHints(
_model: editor.ITextModel, _model: editor.ITextModel,
range: Range, range: Range,
@ -569,6 +630,7 @@ class PlaygroundServer
this.rangeSemanticTokensDisposable.dispose(); this.rangeSemanticTokensDisposable.dispose();
this.semanticTokensDisposable.dispose(); this.semanticTokensDisposable.dispose();
this.completionDisposable.dispose(); this.completionDisposable.dispose();
this.signatureHelpDisposable.dispose();
} }
} }