diff --git a/package.json b/package.json index 625f4eddc..4117101e4 100644 --- a/package.json +++ b/package.json @@ -1487,6 +1487,11 @@ "command": "java.server.restart", "title": "%java.server.restart%", "category": "Java" + }, + { + "command": "java.action.filesExplorerPasteAction", + "title": "%java.action.filesExplorerPasteAction%", + "category": "Java" } ], "keybindings": [ @@ -1504,6 +1509,12 @@ "key": "ctrl+shift+v", "mac": "cmd+shift+v", "when": "javaLSReady && editorLangId == java" + }, + { + "command": "java.action.filesExplorerPasteAction", + "key": "ctrl+shift+v", + "mac": "cmd+shift+v", + "when": "explorerViewletFocus && config.editor.pasteAs.enabled" } ], "menus": { @@ -1622,6 +1633,10 @@ { "command": "java.server.restart", "when": "javaLSReady" + }, + { + "command": "java.action.filesExplorerPasteAction", + "when": "false" } ], "view/title": [ diff --git a/package.nls.json b/package.nls.json index e01775313..ca4690b3b 100644 --- a/package.nls.json +++ b/package.nls.json @@ -25,5 +25,6 @@ "java.project.createModuleInfo.command": "Create module-info.java", "java.clean.sharedIndexes": "Clean Shared Indexes", "java.server.restart": "Restart Java Language Server", - "java.edit.smartSemicolonDetection": "Java Smart Semicolon Detection" + "java.edit.smartSemicolonDetection": "Java Smart Semicolon Detection", + "java.action.filesExplorerPasteAction": "Paste clipboard text into a file" } diff --git a/package.nls.ko.json b/package.nls.ko.json index 359ee31b1..2e7214d92 100644 --- a/package.nls.ko.json +++ b/package.nls.ko.json @@ -22,5 +22,6 @@ "java.action.showSupertypeHierarchy": "Supertype 계층 구조 표시", "java.action.showSubtypeHierarchy": "Subtype 계층 구조 표시", "java.action.changeBaseType": "이 유형을 기준으로", - "java.project.createModuleInfo.command": "module-info.java 생성" + "java.project.createModuleInfo.command": "module-info.java 생성", + "java.action.filesExplorerPasteAction": "클립보드 텍스트를 파일에 붙여넣기" } diff --git a/package.nls.zh-cn.json b/package.nls.zh-cn.json index 771247f40..ebe40f3e8 100644 --- a/package.nls.zh-cn.json +++ b/package.nls.zh-cn.json @@ -23,5 +23,6 @@ "java.action.showSubtypeHierarchy": "显示子类层次结构", "java.action.changeBaseType": "基于此类型", "java.project.createModuleInfo.command": "创建 module-info.java", - "java.clean.sharedIndexes": "清理共享的索引文件" + "java.clean.sharedIndexes": "清理共享的索引文件", + "java.action.filesExplorerPasteAction": "将剪贴板文本粘贴到文件中" } diff --git a/package.nls.zh-tw.json b/package.nls.zh-tw.json index c2e2031ae..43ca820ce 100644 --- a/package.nls.zh-tw.json +++ b/package.nls.zh-tw.json @@ -22,5 +22,6 @@ "java.action.showSupertypeHierarchy": "顯示父類別階層結構", "java.action.showSubtypeHierarchy": "顯示子類別階層結構", "java.action.changeBaseType": "以此型別為基礎", - "java.project.createModuleInfo.command": "創建 module-info.java" + "java.project.createModuleInfo.command": "創建 module-info.java", + "java.action.filesExplorerPasteAction": "將剪貼簿文字貼到文件中" } \ No newline at end of file diff --git a/src/commands.ts b/src/commands.ts index 0654ec363..5ad0a8085 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -191,6 +191,10 @@ export namespace Commands { * Custom paste action (triggers auto-import) */ export const CLIPBOARD_ONPASTE = 'java.action.clipboardPasteAction'; + /** + * Custom paste action in files explorer + */ + export const FILESEXPLORER_ONPASTE = 'java.action.filesExplorerPasteAction'; /** * Choose type to import. */ @@ -341,4 +345,9 @@ export namespace Commands { */ export const SMARTSEMICOLON_DETECTION = "java.edit.smartSemicolonDetection"; + /** + * Determine if pasted text is a java file and resolve packages + */ + export const RESOLVE_PASTED_TEXT = "java.project.resolveText"; + } diff --git a/src/extension.ts b/src/extension.ts index 5246d3b37..30cf1b506 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -37,6 +37,7 @@ import { TelemetryService } from '@redhat-developer/vscode-redhat-telemetry/lib' import { activationProgressNotification } from "./serverTaskPresenter"; import { loadSupportedJreNames } from './jdkUtils'; import { BuildFileSelector, PICKED_BUILD_FILES, cleanupProjectPickerCache } from './buildFilesSelector'; +import { pasteFile } from './pasteAction'; const syntaxClient: SyntaxLanguageClient = new SyntaxLanguageClient(); const standardClient: StandardLanguageClient = new StandardLanguageClient(); @@ -93,6 +94,14 @@ function getHeapDumpFolderFromSettings(): string { export async function activate(context: ExtensionContext): Promise { await loadSupportedJreNames(context); + context.subscriptions.push(commands.registerCommand(Commands.FILESEXPLORER_ONPASTE, async () => { + const originalClipboard = await env.clipboard.readText(); + // Hack in order to get path to selected folder if applicable (see https://github.com/microsoft/vscode/issues/3553#issuecomment-1098562676) + await commands.executeCommand('copyFilePath'); + const folder = await env.clipboard.readText(); + await env.clipboard.writeText(originalClipboard); + pasteFile(folder); + })); context.subscriptions.push(markdownPreviewProvider); context.subscriptions.push(commands.registerCommand(Commands.TEMPLATE_VARIABLES, async () => { markdownPreviewProvider.show(context.asAbsolutePath(path.join('document', `${Commands.TEMPLATE_VARIABLES}.md`)), 'Predefined Variables', "", context); @@ -650,7 +659,7 @@ function enableJavadocSymbols() { }); } -function getTempWorkspace() { +export function getTempWorkspace() { return path.resolve(os.tmpdir(), `vscodesws_${makeRandomHexString(5)}`); } diff --git a/src/pasteAction.ts b/src/pasteAction.ts index c500f0f3e..4a3f83adf 100644 --- a/src/pasteAction.ts +++ b/src/pasteAction.ts @@ -1,9 +1,11 @@ 'use strict'; -import { commands, env, ExtensionContext, Range, TextEditor, window } from 'vscode'; +import { TextEncoder } from 'util'; +import { commands, env, ExtensionContext, Range, TextEditor, Uri, window, workspace } from 'vscode'; import { LanguageClient } from 'vscode-languageclient/node'; - +import { apiManager } from './apiManager'; import { Commands } from './commands'; +import fs = require('fs'); export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { context.subscriptions.push(commands.registerCommand(Commands.CLIPBOARD_ONPASTE, () => { @@ -48,4 +50,32 @@ export async function registerOrganizeImportsOnPasteCommand(): Promise { } } }); +} + +let serverReady = false; + +export async function pasteFile(folder: fs.PathLike): Promise { + const clipboardText: string = await env.clipboard.readText(); + let filePath = folder.toString(); + fs.stat(folder, async (err, stats) => { + // If given path to selected folder is invalid (no folder is selected) + if (filePath === clipboardText || stats.isFile() || (filePath === "." && workspace.workspaceFolders !== undefined)) { + filePath = workspace.workspaceFolders[0].uri.fsPath; + } + if (!serverReady) { + await apiManager.getApiInstance().serverReady().then( async () => { + serverReady = true; + }); + } + const fileString: string = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.RESOLVE_PASTED_TEXT, filePath, clipboardText); + const fileUri = fileString !== null ? Uri.file(fileString) : null; + if (fileUri !== null){ + try { + await workspace.fs.writeFile(fileUri, new TextEncoder().encode(clipboardText)); + window.showTextDocument(fileUri, { preview: false }); + } catch (error: unknown) { + // Do nothing (file does not have write permissions) + } + } + }); } \ No newline at end of file diff --git a/test/lightweight-mode-suite/extension.test.ts b/test/lightweight-mode-suite/extension.test.ts index 495e90624..b3424da6c 100644 --- a/test/lightweight-mode-suite/extension.test.ts +++ b/test/lightweight-mode-suite/extension.test.ts @@ -25,6 +25,7 @@ suite('Java Language Extension - LightWeight', () => { Commands.OPEN_FILE, Commands.CLEAN_SHARED_INDEXES, Commands.RESTART_LANGUAGE_SERVER, + Commands.FILESEXPLORER_ONPASTE ].sort(); const foundJavaCommands = commands.filter((value) => { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.'); diff --git a/test/standard-mode-suite/extension.test.ts b/test/standard-mode-suite/extension.test.ts index 3fd5828b7..c364990e8 100644 --- a/test/standard-mode-suite/extension.test.ts +++ b/test/standard-mode-suite/extension.test.ts @@ -118,6 +118,8 @@ suite('Java Language Extension - Standard', () => { Commands.UPDATE_SOURCE_ATTACHMENT_CMD, Commands.SMARTSEMICOLON_DETECTION, Commands.RESOLVE_SOURCE_ATTACHMENT, + Commands.FILESEXPLORER_ONPASTE, + Commands.RESOLVE_PASTED_TEXT, ].sort(); const foundJavaCommands = commands.filter((value) => { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.');