Skip to content

Commit 72a6b03

Browse files
hopehadfieldrgrunber
authored andcommitted
Support for pasting a java file in the file explorer
Signed-off-by: Hope Hadfield <[email protected]>
1 parent 7bd5ded commit 72a6b03

File tree

10 files changed

+77
-7
lines changed

10 files changed

+77
-7
lines changed

package.json

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,11 @@
14871487
"command": "java.server.restart",
14881488
"title": "%java.server.restart%",
14891489
"category": "Java"
1490+
},
1491+
{
1492+
"command": "java.action.filesExplorerPasteAction",
1493+
"title": "%java.action.filesExplorerPasteAction%",
1494+
"category": "Java"
14901495
}
14911496
],
14921497
"keybindings": [
@@ -1504,6 +1509,12 @@
15041509
"key": "ctrl+shift+v",
15051510
"mac": "cmd+shift+v",
15061511
"when": "javaLSReady && editorLangId == java"
1512+
},
1513+
{
1514+
"command": "java.action.filesExplorerPasteAction",
1515+
"key": "ctrl+shift+v",
1516+
"mac": "cmd+shift+v",
1517+
"when": "explorerViewletFocus && config.editor.pasteAs.enabled"
15071518
}
15081519
],
15091520
"menus": {
@@ -1622,6 +1633,10 @@
16221633
{
16231634
"command": "java.server.restart",
16241635
"when": "javaLSReady"
1636+
},
1637+
{
1638+
"command": "java.action.filesExplorerPasteAction",
1639+
"when": "false"
16251640
}
16261641
],
16271642
"view/title": [

package.nls.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@
2525
"java.project.createModuleInfo.command": "Create module-info.java",
2626
"java.clean.sharedIndexes": "Clean Shared Indexes",
2727
"java.server.restart": "Restart Java Language Server",
28-
"java.edit.smartSemicolonDetection": "Java Smart Semicolon Detection"
28+
"java.edit.smartSemicolonDetection": "Java Smart Semicolon Detection",
29+
"java.action.filesExplorerPasteAction": "Paste clipboard text into a file"
2930
}

package.nls.ko.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
"java.action.showSupertypeHierarchy": "Supertype 계층 구조 표시",
2323
"java.action.showSubtypeHierarchy": "Subtype 계층 구조 표시",
2424
"java.action.changeBaseType": "이 유형을 기준으로",
25-
"java.project.createModuleInfo.command": "module-info.java 생성"
25+
"java.project.createModuleInfo.command": "module-info.java 생성",
26+
"java.action.filesExplorerPasteAction": "클립보드 텍스트를 파일에 붙여넣기"
2627
}

package.nls.zh-cn.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,6 @@
2323
"java.action.showSubtypeHierarchy": "显示子类层次结构",
2424
"java.action.changeBaseType": "基于此类型",
2525
"java.project.createModuleInfo.command": "创建 module-info.java",
26-
"java.clean.sharedIndexes": "清理共享的索引文件"
26+
"java.clean.sharedIndexes": "清理共享的索引文件",
27+
"java.action.filesExplorerPasteAction": "将剪贴板文本粘贴到文件中"
2728
}

package.nls.zh-tw.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,6 @@
2222
"java.action.showSupertypeHierarchy": "顯示父類別階層結構",
2323
"java.action.showSubtypeHierarchy": "顯示子類別階層結構",
2424
"java.action.changeBaseType": "以此型別為基礎",
25-
"java.project.createModuleInfo.command": "創建 module-info.java"
25+
"java.project.createModuleInfo.command": "創建 module-info.java",
26+
"java.action.filesExplorerPasteAction": "將剪貼簿文字貼到文件中"
2627
}

src/commands.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,10 @@ export namespace Commands {
191191
* Custom paste action (triggers auto-import)
192192
*/
193193
export const CLIPBOARD_ONPASTE = 'java.action.clipboardPasteAction';
194+
/**
195+
* Custom paste action in files explorer
196+
*/
197+
export const FILESEXPLORER_ONPASTE = 'java.action.filesExplorerPasteAction';
194198
/**
195199
* Choose type to import.
196200
*/
@@ -341,4 +345,9 @@ export namespace Commands {
341345
*/
342346
export const SMARTSEMICOLON_DETECTION = "java.edit.smartSemicolonDetection";
343347

348+
/**
349+
* Determine if pasted text is a java file and resolve packages
350+
*/
351+
export const RESOLVE_PASTED_TEXT = "java.project.resolveText";
352+
344353
}

src/extension.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ import { TelemetryService } from '@redhat-developer/vscode-redhat-telemetry/lib'
3737
import { activationProgressNotification } from "./serverTaskPresenter";
3838
import { loadSupportedJreNames } from './jdkUtils';
3939
import { BuildFileSelector, PICKED_BUILD_FILES, cleanupProjectPickerCache } from './buildFilesSelector';
40+
import { pasteFile } from './pasteAction';
4041

4142
const syntaxClient: SyntaxLanguageClient = new SyntaxLanguageClient();
4243
const standardClient: StandardLanguageClient = new StandardLanguageClient();
@@ -93,6 +94,14 @@ function getHeapDumpFolderFromSettings(): string {
9394

9495
export async function activate(context: ExtensionContext): Promise<ExtensionAPI> {
9596
await loadSupportedJreNames(context);
97+
context.subscriptions.push(commands.registerCommand(Commands.FILESEXPLORER_ONPASTE, async () => {
98+
const originalClipboard = await env.clipboard.readText();
99+
// Hack in order to get path to selected folder if applicable (see https://github.com/microsoft/vscode/issues/3553#issuecomment-1098562676)
100+
await commands.executeCommand('copyFilePath');
101+
const folder = await env.clipboard.readText();
102+
await env.clipboard.writeText(originalClipboard);
103+
pasteFile(folder);
104+
}));
96105
context.subscriptions.push(markdownPreviewProvider);
97106
context.subscriptions.push(commands.registerCommand(Commands.TEMPLATE_VARIABLES, async () => {
98107
markdownPreviewProvider.show(context.asAbsolutePath(path.join('document', `${Commands.TEMPLATE_VARIABLES}.md`)), 'Predefined Variables', "", context);
@@ -650,7 +659,7 @@ function enableJavadocSymbols() {
650659
});
651660
}
652661

653-
function getTempWorkspace() {
662+
export function getTempWorkspace() {
654663
return path.resolve(os.tmpdir(), `vscodesws_${makeRandomHexString(5)}`);
655664
}
656665

src/pasteAction.ts

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
'use strict';
22

3-
import { commands, env, ExtensionContext, Range, TextEditor, window } from 'vscode';
3+
import { TextEncoder } from 'util';
4+
import { commands, env, ExtensionContext, Range, TextEditor, Uri, window, workspace } from 'vscode';
45
import { LanguageClient } from 'vscode-languageclient/node';
5-
6+
import { apiManager } from './apiManager';
67
import { Commands } from './commands';
8+
import fs = require('fs');
79

810
export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) {
911
context.subscriptions.push(commands.registerCommand(Commands.CLIPBOARD_ONPASTE, () => {
@@ -48,4 +50,32 @@ export async function registerOrganizeImportsOnPasteCommand(): Promise<void> {
4850
}
4951
}
5052
});
53+
}
54+
55+
let serverReady = false;
56+
57+
export async function pasteFile(folder: fs.PathLike): Promise<void> {
58+
const clipboardText: string = await env.clipboard.readText();
59+
let filePath = folder.toString();
60+
fs.stat(folder, async (err, stats) => {
61+
// If given path to selected folder is invalid (no folder is selected)
62+
if (filePath === clipboardText || stats.isFile() || (filePath === "." && workspace.workspaceFolders !== undefined)) {
63+
filePath = workspace.workspaceFolders[0].uri.fsPath;
64+
}
65+
if (!serverReady) {
66+
await apiManager.getApiInstance().serverReady().then( async () => {
67+
serverReady = true;
68+
});
69+
}
70+
const fileString: string = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.RESOLVE_PASTED_TEXT, filePath, clipboardText);
71+
const fileUri = fileString !== null ? Uri.file(fileString) : null;
72+
if (fileUri !== null){
73+
try {
74+
await workspace.fs.writeFile(fileUri, new TextEncoder().encode(clipboardText));
75+
window.showTextDocument(fileUri, { preview: false });
76+
} catch (error: unknown) {
77+
// Do nothing (file does not have write permissions)
78+
}
79+
}
80+
});
5181
}

test/lightweight-mode-suite/extension.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ suite('Java Language Extension - LightWeight', () => {
2525
Commands.OPEN_FILE,
2626
Commands.CLEAN_SHARED_INDEXES,
2727
Commands.RESTART_LANGUAGE_SERVER,
28+
Commands.FILESEXPLORER_ONPASTE
2829
].sort();
2930
const foundJavaCommands = commands.filter((value) => {
3031
return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.');

test/standard-mode-suite/extension.test.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,8 @@ suite('Java Language Extension - Standard', () => {
118118
Commands.UPDATE_SOURCE_ATTACHMENT_CMD,
119119
Commands.SMARTSEMICOLON_DETECTION,
120120
Commands.RESOLVE_SOURCE_ATTACHMENT,
121+
Commands.FILESEXPLORER_ONPASTE,
122+
Commands.RESOLVE_PASTED_TEXT,
121123
].sort();
122124
const foundJavaCommands = commands.filter((value) => {
123125
return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.');

0 commit comments

Comments
 (0)