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
30 changes: 30 additions & 0 deletions crates/ty_wasm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,27 @@ impl Workspace {
}))
}

#[wasm_bindgen]
pub fn completions(
&self,
file_id: &FileHandle,
position: Position,
) -> Result<Vec<Completion>, 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 completions = ty_ide::completion(&self.db, file_id.file, offset);

Ok(completions
.into_iter()
.map(|completion| Completion {
label: completion.label,
})
.collect())
}

#[wasm_bindgen(js_name = "inlayHints")]
pub fn inlay_hints(&self, file_id: &FileHandle, range: Range) -> Result<Vec<InlayHint>, Error> {
let index = line_index(&self.db, file_id.file);
Expand Down Expand Up @@ -586,6 +607,7 @@ pub struct LocationLink {
}

#[wasm_bindgen]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Hover {
#[wasm_bindgen(getter_with_clone)]
pub markdown: String,
Expand All @@ -594,6 +616,14 @@ pub struct Hover {
}

#[wasm_bindgen]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Completion {
#[wasm_bindgen(getter_with_clone)]
pub label: String,
}

#[wasm_bindgen]
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct InlayHint {
#[wasm_bindgen(getter_with_clone)]
pub markdown: String,
Expand Down
2 changes: 1 addition & 1 deletion playground/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

57 changes: 51 additions & 6 deletions playground/ty/src/Editor/Editor.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,16 +18,16 @@ import {
import { useCallback, useEffect, useRef } from "react";
import { Theme } from "shared";
import {
Position as TyPosition,
Range as TyRange,
Severity,
type Workspace,
Position as TyPosition,
} from "ty_wasm";

import IStandaloneCodeEditor = editor.IStandaloneCodeEditor;
import { FileId, ReadonlyFiles } from "../Playground";
import { isPythonFile } from "./Files";
import { Diagnostic } from "./Diagnostics";
import IStandaloneCodeEditor = editor.IStandaloneCodeEditor;
import CompletionItemKind = languages.CompletionItemKind;

type Props = {
visible: boolean;
Expand Down Expand Up @@ -146,13 +146,15 @@ class PlaygroundServer
editor.ICodeEditorOpener,
languages.HoverProvider,
languages.InlayHintsProvider,
languages.DocumentFormattingEditProvider
languages.DocumentFormattingEditProvider,
languages.CompletionItemProvider
{
private typeDefinitionProviderDisposable: IDisposable;
private editorOpenerDisposable: IDisposable;
private hoverDisposable: IDisposable;
private inlayHintsDisposable: IDisposable;
private formatDisposable: IDisposable;
private completionDisposable: IDisposable;

constructor(
private monaco: Monaco,
Expand All @@ -168,11 +170,53 @@ class PlaygroundServer
"python",
this,
);
this.completionDisposable = monaco.languages.registerCompletionItemProvider(
"python",
this,
);
this.editorOpenerDisposable = monaco.editor.registerEditorOpener(this);
this.formatDisposable =
monaco.languages.registerDocumentFormattingEditProvider("python", this);
}

triggerCharacters: undefined;

provideCompletionItems(
model: editor.ITextModel,
position: Position,
): languages.ProviderResult<languages.CompletionList> {
const selectedFile = this.props.files.selected;

if (selectedFile == null) {
return;
}

const selectedHandle = this.props.files.handles[selectedFile];

if (selectedHandle == null) {
return;
}

const completions = this.props.workspace.completions(
selectedHandle,
new TyPosition(position.lineNumber, position.column),
);

return {
suggestions: completions.map((completion) => ({
label: completion.label,
kind: CompletionItemKind.Variable,
insertText: completion.label,
// 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.
range: undefined as any,
})),
};
}

resolveCompletionItem: undefined;

provideInlayHints(
_model: editor.ITextModel,
range: Range,
Expand All @@ -194,7 +238,7 @@ class PlaygroundServer

const inlayHints = workspace.inlayHints(
selectedHandle,
MonacoRangeToTyRange(range),
monacoRangeToTyRange(range),
);

if (inlayHints.length === 0) {
Expand Down Expand Up @@ -447,6 +491,7 @@ class PlaygroundServer
this.typeDefinitionProviderDisposable.dispose();
this.inlayHintsDisposable.dispose();
this.formatDisposable.dispose();
this.editorOpenerDisposable.dispose();
}
}

Expand All @@ -459,7 +504,7 @@ function tyRangeToMonacoRange(range: TyRange): IRange {
};
}

function MonacoRangeToTyRange(range: IRange): TyRange {
function monacoRangeToTyRange(range: IRange): TyRange {
return new TyRange(
new TyPosition(range.startLineNumber, range.startColumn),
new TyPosition(range.endLineNumber, range.endColumn),
Expand Down
Loading