forked from redhat-developer/vscode-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathpasteEventHandler.ts
More file actions
130 lines (109 loc) · 4.93 KB
/
pasteEventHandler.ts
File metadata and controls
130 lines (109 loc) · 4.93 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import { CancellationToken, commands, DataTransfer, DocumentPasteEdit as VDocumentPasteEdit, DocumentPasteEditProvider, DocumentPasteProviderMetadata, ExtensionContext, languages, Range, TextDocument, window, DocumentPasteEditContext, ProviderResult, DocumentPasteEdit, version } from "vscode";
import { FormattingOptions, Location, WorkspaceEdit as PWorkspaceEdit } from "vscode-languageclient";
import { LanguageClient } from "vscode-languageclient/node";
import { Commands } from "./commands";
import { JAVA_SELECTOR } from "./standardLanguageClient";
import * as semver from 'semver';
const TEXT_MIMETYPE: string = "text/plain";
const MIMETYPES: DocumentPasteProviderMetadata = {
pasteMimeTypes: [TEXT_MIMETYPE],
providedPasteEditKinds: []
};
/**
* Parameters for `Commands.HANDLE_PASTE_EVENT`
*/
interface PasteEventParams {
location: Location;
text: string;
formattingOptions: FormattingOptions;
copiedDocumentUri?: string;
}
/**
* Response from jdt.ls for `Commands.HANDLE_PASTE_EVENT` that's similar, but not identical, to VS Code's paste edit.
*
* @see VDocumentPasteEdit
*/
interface PDocumentPasteEdit {
insertText: string;
additionalEdit: PWorkspaceEdit;
}
/**
* Registers the vscode-java DocumentPasteEditProviders and sets them up to be disposed.
*
* @param context the extension context
*/
export function registerPasteEventHandler(context: ExtensionContext, languageClient: LanguageClient) {
if (languages["registerDocumentPasteEditProvider"]) {
context.subscriptions.push(languages["registerDocumentPasteEditProvider"](JAVA_SELECTOR, new PasteEditProvider(languageClient), MIMETYPES));
}
}
/**
* `DocumentPasteEditProvider` that delegates to jdt.ls to make any changes necessary to the pasted text and add any additional workspace edits.
*/
class PasteEditProvider implements DocumentPasteEditProvider {
private languageClient: LanguageClient;
private copiedContent: string | undefined;
private copiedDocumentUri: string | undefined;
constructor(languageClient: LanguageClient) {
this.languageClient = languageClient;
}
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.copiedDocumentUri = document.uri.toString();
this.copiedContent = copiedContent;
}
}
async provideDocumentPasteEdits?(document: TextDocument, ranges: readonly Range[], dataTransfer: DataTransfer, context: DocumentPasteEditContext, token: CancellationToken): Promise<any> {
const insertText: string = await dataTransfer.get(TEXT_MIMETYPE).asString();
// don't try to provide for multi character inserts; the implementation will get messy and the feature won't be that helpful
if (!insertText || (!!token && token.isCancellationRequested) || ranges.length !== 1) {
return null;
}
// Skip paste handling for single line copies from the same document to avoid unwanted escaping
// in string literals when copying lines
const isSingleLineCopy = !insertText.includes('\n') && !insertText.includes('\r');
const isFromSameDocument = this.copiedContent === insertText && this.copiedDocumentUri === document.uri.toString();
if (isSingleLineCopy && isFromSameDocument) {
return undefined; // Let VS Code handle this normally
}
// Skip paste handling when pasting content that contains quotes to avoid unwanted escaping
// This is a broader check than the above to handle cases where content is modified or from different documents
if (insertText.includes('"')) {
return undefined; // Let VS Code handle this normally
}
const range = ranges[0];
const location: Location = {
range: this.languageClient.code2ProtocolConverter.asRange(range),
uri: document.uri.toString(),
};
const activeTextEditor = window.activeTextEditor;
const pasteEventParams: PasteEventParams = {
location: location,
text: insertText,
copiedDocumentUri: this.copiedContent === insertText ? this.copiedDocumentUri : undefined,
formattingOptions: {
insertSpaces: <boolean>activeTextEditor.options.insertSpaces,
tabSize: <number>activeTextEditor.options.tabSize
}
};
try {
const pasteResponse: PDocumentPasteEdit = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.HANDLE_PASTE_EVENT, JSON.stringify(pasteEventParams));
if (pasteResponse) {
const pasteEdit = {
insertText: pasteResponse.insertText,
additionalEdit: pasteResponse.additionalEdit ? await this.languageClient.protocol2CodeConverter.asWorkspaceEdit(pasteResponse.additionalEdit) : undefined
};
if (semver.lt(version, '1.88.0')) {
return pasteEdit as DocumentPasteEdit;
} else {
return [ pasteEdit ] as DocumentPasteEdit[];
}
}
} catch (e) {
// Do nothing
}
// either the handler returns null or encounters problems, fall back to return undefined to let VS Code ignore this handler
return undefined;
}
}