mirror of
https://github.com/Microsoft/vscode
synced 2024-10-01 08:50:48 +00:00
Hook up prototype paste with imports for JS/TS (#204665)
* Hook up prototype paste with imports for JS/TS For https://github.com/microsoft/TypeScript/pull/57262 but with proposed changes to ts protocol * Support new api * Update
This commit is contained in:
parent
fb7f5a9a83
commit
934af755c4
|
@ -13,7 +13,8 @@
|
|||
"multiDocumentHighlightProvider",
|
||||
"mappedEditsProvider",
|
||||
"codeActionAI",
|
||||
"codeActionRanges"
|
||||
"codeActionRanges",
|
||||
"documentPaste"
|
||||
],
|
||||
"capabilities": {
|
||||
"virtualWorkspaces": {
|
||||
|
@ -1316,6 +1317,20 @@
|
|||
"default": true,
|
||||
"markdownDescription": "%typescript.workspaceSymbols.excludeLibrarySymbols%",
|
||||
"scope": "window"
|
||||
},
|
||||
"javascript.experimental.updateImportsOnPaste": {
|
||||
"scope": "resource",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.updateImportsOnPaste%",
|
||||
"tags": ["experimental"]
|
||||
},
|
||||
"typescript.experimental.updateImportsOnPaste": {
|
||||
"scope": "resource",
|
||||
"type": "boolean",
|
||||
"default": false,
|
||||
"description": "%configuration.updateImportsOnPaste%",
|
||||
"tags": ["experimental"]
|
||||
}
|
||||
}
|
||||
},
|
||||
|
|
|
@ -219,6 +219,7 @@
|
|||
"configuration.tsserver.web.projectWideIntellisense.suppressSemanticErrors": "Suppresses semantic errors on web even when project wide IntelliSense is enabled. This is always on when project wide IntelliSense is not enabled or available. See `#typescript.tsserver.web.projectWideIntellisense.enabled#`",
|
||||
"configuration.tsserver.web.typeAcquisition.enabled": "Enable/disable package acquisition on the web. This enables IntelliSense for imported packages. Requires `#typescript.tsserver.web.projectWideIntellisense.enabled#`. Currently not supported for Safari.",
|
||||
"configuration.tsserver.nodePath": "Run TS Server on a custom Node installation. This can be a path to a Node executable, or 'node' if you want VS Code to detect a Node installation.",
|
||||
"configuration.updateImportsOnPaste": "Automatically update imports when pasting code. Requires TypeScript 5.5+.",
|
||||
"walkthroughs.nodejsWelcome.title": "Get started with JavaScript and Node.js",
|
||||
"walkthroughs.nodejsWelcome.description": "Make the most of Visual Studio Code's first-class JavaScript experience.",
|
||||
"walkthroughs.nodejsWelcome.downloadNode.forMacOrWindows.title": "Install Node.js",
|
||||
|
|
|
@ -0,0 +1,137 @@
|
|||
/*---------------------------------------------------------------------------------------------
|
||||
* 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, requireMinVersion, requireSomeCapability } from './util/dependentRegistration';
|
||||
import protocol from '../tsServer/protocol/protocol';
|
||||
import { API } from '../tsServer/api';
|
||||
import { LanguageDescription } from '../configuration/languageDescription';
|
||||
|
||||
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 kind = vscode.DocumentDropOrPasteEditKind.Empty.append('text', 'jsts', 'pasteWithImports');
|
||||
static readonly metadataMimeType = 'application/vnd.code.jsts.metadata';
|
||||
|
||||
constructor(
|
||||
private readonly _modeId: string,
|
||||
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,
|
||||
_context: vscode.DocumentPasteEditContext,
|
||||
token: vscode.CancellationToken,
|
||||
): Promise<vscode.DocumentPasteEdit[] | undefined> {
|
||||
const config = vscode.workspace.getConfiguration(this._modeId, document.uri);
|
||||
if (!config.get('experimental.updateImportsOnPaste')) {
|
||||
return;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
let copiedFrom: {
|
||||
file: string;
|
||||
spans: protocol.TextSpan[];
|
||||
} | undefined;
|
||||
if (metadata) {
|
||||
const spans = metadata.ranges.map(typeConverters.Range.toTextSpan);
|
||||
const copyFile = this._client.toTsFilePath(metadata.resource);
|
||||
if (copyFile) {
|
||||
copiedFrom = { file: copyFile, spans };
|
||||
}
|
||||
}
|
||||
|
||||
const response = await this._client.execute('getPasteEdits', {
|
||||
file,
|
||||
// TODO: only supports a single paste for now
|
||||
pastedText: [text],
|
||||
pasteLocations: ranges.map(typeConverters.Range.toTextSpan),
|
||||
copiedFrom
|
||||
}, token);
|
||||
if (response.type !== 'response' || !response.body || token.isCancellationRequested) {
|
||||
return;
|
||||
}
|
||||
|
||||
const edit = new vscode.DocumentPasteEdit('', vscode.l10n.t("Paste with imports"), DocumentPasteProvider.kind);
|
||||
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, language: LanguageDescription, client: ITypeScriptServiceClient) {
|
||||
return conditionalRegistration([
|
||||
requireSomeCapability(client, ClientCapability.Semantic),
|
||||
requireMinVersion(client, API.v550),
|
||||
], () => {
|
||||
return vscode.languages.registerDocumentPasteEditProvider(selector.semantic, new DocumentPasteProvider(language.id, client), {
|
||||
providedPasteEditKinds: [DocumentPasteProvider.kind],
|
||||
copyMimeTypes: [DocumentPasteProvider.metadataMimeType],
|
||||
pasteMimeTypes: ['text/plain'],
|
||||
});
|
||||
});
|
||||
}
|
|
@ -65,6 +65,7 @@ export default class LanguageProvider extends Disposable {
|
|||
import('./languageFeatures/codeLens/implementationsCodeLens').then(provider => this._register(provider.register(selector, this.description, this.client, cachedNavTreeResponse))),
|
||||
import('./languageFeatures/codeLens/referencesCodeLens').then(provider => this._register(provider.register(selector, this.description, this.client, cachedNavTreeResponse))),
|
||||
import('./languageFeatures/completions').then(provider => this._register(provider.register(selector, this.description, this.client, this.typingsStatus, this.fileConfigurationManager, this.commandManager, this.telemetryReporter, this.onCompletionAccepted))),
|
||||
import('./languageFeatures/copyPaste').then(provider => this._register(provider.register(selector, this.description, this.client))),
|
||||
import('./languageFeatures/definitions').then(provider => this._register(provider.register(selector, this.client))),
|
||||
import('./languageFeatures/directiveCommentCompletions').then(provider => this._register(provider.register(selector, this.client))),
|
||||
import('./languageFeatures/documentHighlight').then(provider => this._register(provider.register(selector, this.client))),
|
||||
|
|
|
@ -37,6 +37,7 @@ export class API {
|
|||
public static readonly v520 = API.fromSimpleString('5.2.0');
|
||||
public static readonly v544 = API.fromSimpleString('5.4.4');
|
||||
public static readonly v540 = API.fromSimpleString('5.4.0');
|
||||
public static readonly v550 = API.fromSimpleString('5.5.0');
|
||||
|
||||
public static fromVersionString(versionString: string): API {
|
||||
let version = semver.valid(versionString);
|
||||
|
|
|
@ -20,6 +20,7 @@ declare module '../../../../node_modules/typescript/lib/typescript' {
|
|||
readonly _serverType?: ServerType;
|
||||
}
|
||||
|
||||
//#region MapCode
|
||||
export interface MapCodeRequestArgs extends FileRequestArgs {
|
||||
/**
|
||||
* The files and changes to try and apply/map.
|
||||
|
@ -49,7 +50,39 @@ declare module '../../../../node_modules/typescript/lib/typescript' {
|
|||
}
|
||||
|
||||
export interface MapCodeResponse extends Response {
|
||||
body: readonly FileCodeEdits[];
|
||||
body: FileCodeEdits[]
|
||||
}
|
||||
//#endregion
|
||||
|
||||
//#region Paste
|
||||
export interface GetPasteEditsRequest extends Request {
|
||||
command: 'getPasteEdits';
|
||||
arguments: GetPasteEditsRequestArgs;
|
||||
}
|
||||
|
||||
export interface GetPasteEditsRequestArgs extends FileRequestArgs {
|
||||
/** The text that gets pasted in a file. */
|
||||
pastedText: string[];
|
||||
/** Locations of where the `pastedText` gets added in a file. If the length of the `pastedText` and `pastedLocations` are not the same,
|
||||
* then the `pastedText` is combined into one and added at all the `pastedLocations`.
|
||||
*/
|
||||
pasteLocations: TextSpan[];
|
||||
/** The source location of each `pastedText`. If present, the length of `spans` must be equal to the length of `pastedText`. */
|
||||
copiedFrom?: {
|
||||
file: string;
|
||||
spans: TextSpan[];
|
||||
};
|
||||
}
|
||||
|
||||
export interface GetPasteEditsResponse extends Response {
|
||||
body: PasteEditsAction;
|
||||
}
|
||||
export interface PasteEditsAction {
|
||||
edits: FileCodeEdits[];
|
||||
fixId?: {};
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -77,6 +77,7 @@ interface StandardTsServerRequests {
|
|||
'getMoveToRefactoringFileSuggestions': [Proto.GetMoveToRefactoringFileSuggestionsRequestArgs, Proto.GetMoveToRefactoringFileSuggestions];
|
||||
'linkedEditingRange': [Proto.FileLocationRequestArgs, Proto.LinkedEditingRangeResponse];
|
||||
'mapCode': [Proto.MapCodeRequestArgs, Proto.MapCodeResponse];
|
||||
'getPasteEdits': [Proto.GetPasteEditsRequestArgs, Proto.GetPasteEditsResponse];
|
||||
}
|
||||
|
||||
interface NoResponseTsServerRequests {
|
||||
|
|
|
@ -17,5 +17,6 @@
|
|||
"../../src/vscode-dts/vscode.proposed.mappedEditsProvider.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.multiDocumentHighlightProvider.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.workspaceTrust.d.ts",
|
||||
"../../src/vscode-dts/vscode.proposed.documentPaste.d.ts",
|
||||
]
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue