Skip to content
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

Add missing import on paste #2795

Closed
Closed
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
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,9 @@
"publisher": "redhat",
"bugs": "https://github.com/redhat-developer/vscode-java/issues",
"preview": false,
"enableProposedApi": false,
"enabledApiProposals": [
"documentPaste"
],
"capabilities": {
"untrustedWorkspaces": {
"supported": "limited",
Expand Down
4 changes: 4 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,10 @@ export namespace Commands {
* Organize imports silently.
*/
export const ORGANIZE_IMPORTS_SILENTLY = "java.edit.organizeImports";
/**
* Add imports on paste.
*/
export const ADD_IMPORTS_PASTE = "java.edit.addImportsOnPaste";
/**
* Custom paste action (triggers auto-import)
*/
Expand Down
49 changes: 49 additions & 0 deletions src/pasteEventHandler.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { CancellationToken, commands, DataTransfer, DocumentPasteEdit, DocumentPasteEditProvider, DocumentPasteProviderMetadata, DocumentSelector, EndOfLine, ExtensionContext, languages, Range, TextDocument, TextEditor, window, WorkspaceEdit } from "vscode";
import { LanguageClient } from "vscode-languageclient/node";
import { Commands } from "./commands";
import { JAVA_SELECTOR } from "./standardLanguageClient";

const TEXT_MIMETYPE: string = "text/plain";

const MIMETYPES: DocumentPasteProviderMetadata = {
pasteMimeTypes: [TEXT_MIMETYPE]
};

class StringPasteEditProvider implements DocumentPasteEditProvider {

private client: LanguageClient;
private copiedDocumentUri: string | undefined;
private copiedContent: string | undefined;

constructor(client: LanguageClient) {
this.client = client;
}

async prepareDocumentPaste(document: TextDocument, _ranges: readonly Range[], dataTransfer: DataTransfer, _token: CancellationToken): Promise<void> {
const copiedContent: string = await dataTransfer.get(TEXT_MIMETYPE).asString();
if (copiedContent) {
this.copiedContent = copiedContent;
this.copiedDocumentUri = document.uri.toString();
}
}

async provideDocumentPasteEdits(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, _token: CancellationToken): Promise<DocumentPasteEdit> {
const insertContent: string = await dataTransfer.get(TEXT_MIMETYPE).asString();
if (!insertContent) {
return new DocumentPasteEdit("");
}
const documentPasteEdit = new DocumentPasteEdit(insertContent);
const workspaceEdit = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.ADD_IMPORTS_PASTE, document.uri.toString(), JSON.stringify(this.client.code2ProtocolConverter.asRange(ranges[0])), insertContent, this.copiedContent === insertContent ? this.copiedDocumentUri : null);
if (workspaceEdit) {
documentPasteEdit.additionalEdit = this.client.protocol2CodeConverter.asWorkspaceEdit(workspaceEdit);
}
return documentPasteEdit;
CsCherrYY marked this conversation as resolved.
Show resolved Hide resolved
}

}

export function registerPasteEventHandler(context: ExtensionContext, client: LanguageClient) {
if (languages["registerDocumentPasteEditProvider"]){
context.subscriptions.push(languages["registerDocumentPasteEditProvider"](JAVA_SELECTOR, new StringPasteEditProvider(client), MIMETYPES));
}
}
17 changes: 11 additions & 6 deletions src/standardLanguageClient.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
'use strict';

import { ExtensionContext, window, workspace, commands, Uri, ProgressLocation, ViewColumn, EventEmitter, extensions, Location, languages, CodeActionKind, TextEditor, CancellationToken, ConfigurationTarget } from "vscode";
import { ExtensionContext, window, workspace, commands, Uri, ProgressLocation, ViewColumn, EventEmitter, extensions, Location, languages, CodeActionKind, TextEditor, CancellationToken, ConfigurationTarget, DocumentSelector } from "vscode";
import { Commands } from "./commands";
import { serverStatus, ServerStatusKind } from "./serverStatus";
import { prepareExecutable, awaitServerConnection } from "./javaServerStarter";
Expand Down Expand Up @@ -37,6 +37,7 @@ import { JavaInlayHintsProvider } from "./inlayHintsProvider";
import { gradleCodeActionMetadata, GradleCodeActionProvider } from "./gradle/gradleCodeActionProvider";
import { checkLombokDependency } from "./lombokSupport";
import { askForProjects, projectConfigurationUpdate, upgradeGradle } from "./standardLanguageClientUtils";
import { registerPasteEventHandler } from "./pasteEventHandler";

const extensionName = 'Language Support for Java';
const GRADLE_CHECKSUM = "gradle/checksum/prompt";
Expand All @@ -46,6 +47,12 @@ const AS_GRADLE_JVM = " as Gradle JVM";
const UPGRADE_GRADLE = "Upgrade Gradle to ";
const GRADLE_IMPORT_JVM = "java.import.gradle.java.home";

export const JAVA_SELECTOR: DocumentSelector = [
{ scheme: "file", language: "java", pattern: "**/*.java" },
{ scheme: "jdt", language: "java", pattern: "**/*.class" },
{ scheme: "untitled", language: "java", pattern: "**/*.java" }
];

export class StandardLanguageClient {

private languageClient: LanguageClient;
Expand Down Expand Up @@ -589,12 +596,10 @@ export class StandardLanguageClient {
}, new GradleCodeActionProvider(context), gradleCodeActionMetadata);

if (languages.registerInlayHintsProvider) {
context.subscriptions.push(languages.registerInlayHintsProvider([
{ scheme: "file", language: "java", pattern: "**/*.java" },
{ scheme: "jdt", language: "java", pattern: "**/*.class" },
{ scheme: "untitled", language: "java", pattern: "**/*.java" }
], new JavaInlayHintsProvider(this.languageClient)));
context.subscriptions.push(languages.registerInlayHintsProvider(JAVA_SELECTOR, new JavaInlayHintsProvider(this.languageClient)));
}

registerPasteEventHandler(context, this.languageClient);
});
}

Expand Down
75 changes: 75 additions & 0 deletions vscode.proposed.documentPaste.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/

declare module 'vscode' {

// https://github.com/microsoft/vscode/issues/30066/

/**
* Provider invoked when the user copies and pastes code.
*/
interface DocumentPasteEditProvider {

/**
* Optional method invoked after the user copies text in a file.
*
* During {@link prepareDocumentPaste}, an extension can compute metadata that is attached to
* a {@link DataTransfer} and is passed back to the provider in {@link provideDocumentPasteEdits}.
*
* @param document Document where the copy took place.
* @param ranges Ranges being copied in the `document`.
* @param dataTransfer The data transfer associated with the copy. You can store additional values on this for later use in {@link provideDocumentPasteEdits}.
* @param token A cancellation token.
*/
prepareDocumentPaste?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): void | Thenable<void>;

/**
* Invoked before the user pastes into a document.
*
* In this method, extensions can return a workspace edit that replaces the standard pasting behavior.
*
* @param document Document being pasted into
* @param ranges Currently selected ranges in the document.
* @param dataTransfer The data transfer associated with the paste.
* @param token A cancellation token.
*
* @return Optional workspace edit that applies the paste. Return undefined to use standard pasting.
*/
provideDocumentPasteEdits(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, token: CancellationToken): ProviderResult<DocumentPasteEdit>;
}

/**
* An operation applied on paste
*/
class DocumentPasteEdit {
/**
* The text or snippet to insert at the pasted locations.
*/
insertText: string | SnippetString;

/**
* An optional additional edit to apply on paste.
*/
additionalEdit?: WorkspaceEdit;

/**
* @param insertText The text or snippet to insert at the pasted locations.
*/
constructor(insertText: string | SnippetString);
}

interface DocumentPasteProviderMetadata {
/**
* Mime types that `provideDocumentPasteEdits` should be invoked for.
*
* Use the special `files` mimetype to indicate the provider should be invoked if any files are present in the `DataTransfer`.
*/
readonly pasteMimeTypes: readonly string[];
}

namespace languages {
export function registerDocumentPasteEditProvider(selector: DocumentSelector, provider: DocumentPasteEditProvider, metadata: DocumentPasteProviderMetadata): Disposable;
}
}