-
Notifications
You must be signed in to change notification settings - Fork 30k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hook up prototype paste with imports for JS/TS #204665
Changes from 1 commit
c85c0ed
d095d9c
e16523b
fd83a2a
39fab02
ead73d7
c4ac2e0
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,111 @@ | ||
/*--------------------------------------------------------------------------------------------- | ||
* Copyright (c) Microsoft Corporation. All rights reserved. | ||
* Licensed under the MIT License. See License.txt in the project root for license information. | ||
*--------------------------------------------------------------------------------------------*/ | ||
|
||
import * as vscode from 'vscode'; | ||
import { DocumentSelector } from '../configuration/documentSelector'; | ||
import * as typeConverters from '../typeConverters'; | ||
import { ClientCapability, ITypeScriptServiceClient } from '../typescriptService'; | ||
import { conditionalRegistration, requireSomeCapability } from './util/dependentRegistration'; | ||
|
||
class CopyMetadata { | ||
constructor( | ||
readonly resource: vscode.Uri, | ||
readonly ranges: readonly vscode.Range[], | ||
) { } | ||
|
||
toJSON() { | ||
return JSON.stringify({ | ||
resource: this.resource.toJSON(), | ||
ranges: this.ranges, | ||
}); | ||
} | ||
|
||
static fromJSON(str: string): CopyMetadata | undefined { | ||
try { | ||
const parsed = JSON.parse(str); | ||
return new CopyMetadata( | ||
vscode.Uri.from(parsed.resource), | ||
parsed.ranges.map((r: any) => new vscode.Range(r[0].line, r[0].character, r[1].line, r[1].character))); | ||
} catch { | ||
// ignore | ||
} | ||
return undefined; | ||
} | ||
} | ||
|
||
class DocumentPasteProvider implements vscode.DocumentPasteEditProvider { | ||
|
||
static readonly metadataMimeType = 'application/vnd.code.jsts.metadata'; | ||
|
||
constructor( | ||
private readonly _client: ITypeScriptServiceClient, | ||
) { } | ||
|
||
prepareDocumentPaste(document: vscode.TextDocument, ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, _token: vscode.CancellationToken) { | ||
dataTransfer.set(DocumentPasteProvider.metadataMimeType, | ||
new vscode.DataTransferItem(new CopyMetadata(document.uri, ranges).toJSON())); | ||
} | ||
|
||
async provideDocumentPasteEdits(document: vscode.TextDocument, ranges: readonly vscode.Range[], dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<vscode.DocumentPasteEdit | undefined> { | ||
const file = this._client.toOpenTsFilePath(document); | ||
if (!file) { | ||
return; | ||
} | ||
|
||
const text = await dataTransfer.get('text/plain')?.asString(); | ||
if (!text || token.isCancellationRequested) { | ||
return; | ||
} | ||
|
||
// Get optional metadata | ||
const metadata = await this.extractMetadata(dataTransfer, token); | ||
if (token.isCancellationRequested) { | ||
return; | ||
} | ||
|
||
const copyRange = metadata?.ranges.at(0); | ||
const copyFile = metadata ? this._client.toTsFilePath(metadata.resource) : undefined; | ||
|
||
const response = await this._client.execute('getPostPasteImportFixes', { | ||
file, | ||
pastes: ranges.map(range => ({ text, range: typeConverters.Range.toTextSpan(range) })), | ||
copy: metadata && copyFile && copyRange | ||
? { file: copyFile, ...typeConverters.Range.toTextSpan(copyRange) } | ||
: undefined, | ||
}, token); | ||
if (response.type !== 'response' || !response.body || token.isCancellationRequested) { | ||
return; | ||
} | ||
|
||
const edit = new vscode.DocumentPasteEdit('', vscode.l10n.t("Paste with imports")); | ||
const additionalEdit = new vscode.WorkspaceEdit(); | ||
for (const edit of response.body.edits) { | ||
additionalEdit.set(this._client.toResource(edit.fileName), edit.textChanges.map(typeConverters.TextEdit.fromCodeEdit)); | ||
} | ||
edit.additionalEdit = additionalEdit; | ||
return edit; | ||
} | ||
|
||
private async extractMetadata(dataTransfer: vscode.DataTransfer, token: vscode.CancellationToken): Promise<CopyMetadata | undefined> { | ||
const metadata = await dataTransfer.get(DocumentPasteProvider.metadataMimeType)?.asString(); | ||
if (token.isCancellationRequested) { | ||
return undefined; | ||
} | ||
|
||
return metadata ? CopyMetadata.fromJSON(metadata) : undefined; | ||
} | ||
} | ||
|
||
export function register(selector: DocumentSelector, client: ITypeScriptServiceClient) { | ||
return conditionalRegistration([ | ||
requireSomeCapability(client, ClientCapability.Semantic), | ||
], () => { | ||
return vscode.languages.registerDocumentPasteEditProvider(selector.semantic, new DocumentPasteProvider(client), { | ||
id: 'jsts.pasteWithImports', | ||
copyMimeTypes: [DocumentPasteProvider.metadataMimeType], | ||
pasteMimeTypes: ['text/plain'], | ||
}); | ||
}); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -20,6 +20,7 @@ declare module 'typescript/lib/tsserverlibrary' { | |
readonly _serverType?: ServerType; | ||
} | ||
|
||
//#region MapCode | ||
export interface MapCodeRequestArgs { | ||
/// The files and changes to try and apply/map. | ||
mappings: MapCodeRequestDocumentMapping[]; | ||
|
@@ -55,6 +56,29 @@ declare module 'typescript/lib/tsserverlibrary' { | |
export interface MapCodeResponse extends Response { | ||
body: FileCodeEdits[] | ||
} | ||
//#endregion | ||
|
||
//#region Paste | ||
export interface GetPostPasteImportFixesRequest extends Request { | ||
command: 'getPostPasteImportFixes'; | ||
arguments: GetPostPasteImportFixesRequestArgs; | ||
} | ||
export type DocumentRange = FileRangeRequestArgs; | ||
export type CopyRange = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Updated the protocol. I believe we can remove the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I've updated the pull request @mjbvz microsoft/TypeScript#57262 |
||
start: Location; | ||
end: Location; | ||
} | ||
export type GetPostPasteImportFixesRequestArgs = FileRequestArgs & { | ||
pastes: Array<{ text: string; range: TextSpan }>, | ||
copy?: FileSpan; | ||
} | ||
export interface GetPostPasteImportFixesResponse extends Response { | ||
body: PostPasteImportAction; | ||
} | ||
export interface PostPasteImportAction { | ||
edits: FileCodeEdits[]; | ||
} | ||
//#endregion | ||
} | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name should like come from TS