diff --git a/README.md b/README.md index 866b5a1565..23b3eb7ff8 100644 --- a/README.md +++ b/README.md @@ -117,8 +117,8 @@ The following settings are supported: * `java.codeGeneration.toString.limitElements`: Limit number of items in arrays/collections/maps to list, if 0 then list all. Defaults to `0`. * `java.selectionRange.enabled`: Enable/disable Smart Selection support for Java. Disabling this option will not affect the VS Code built-in word-based and bracket-based smart selection. -New in 0.51.0: -* `java.actionsOnPaste.organizeImports`: [Experimental] Triggers "Organize imports" when code is pasted into a java file. This overrides VS Code's default paste action, thus might cause some issues. Disabled by default. +New in 0.52.0: +* "Organize imports" is triggered when pasting code into a java file with `Ctrl+Shift+v` (`Cmd+Shift+v` on Mac). Troubleshooting =============== diff --git a/package.json b/package.json index faabb4f5b9..c3e79392c5 100644 --- a/package.json +++ b/package.json @@ -394,12 +394,6 @@ "default": true, "description": "Enable/disable Smart Selection support for Java. Disabling this option will not affect the VS Code built-in word-based and bracket-based smart selection.", "scope": "window" - }, - "java.actionsOnPaste.organizeImports": { - "type": "boolean", - "description": "[Experimental] Triggers 'Organize imports' when code is pasted into a Java file. This overrides VS Code's default paste action, thus might cause some issues. Disabled by default.", - "default": false, - "scope": "window" } } }, @@ -469,6 +463,12 @@ { "command": "java.workspace.compile", "key": "shift+alt+b" + }, + { + "command": "java.action.clipboardPasteAction", + "key": "ctrl+shift+v", + "mac": "cmd+shift+v", + "when": "javaLSReady && editorLangId == java" } ], "menus": { diff --git a/src/commands.ts b/src/commands.ts index 7f3e27c2b9..832cbbb466 100644 --- a/src/commands.ts +++ b/src/commands.ts @@ -82,7 +82,7 @@ export namespace Commands { /** * Open Java log files side by side */ - export const OPEN_LOGS = 'java.open.logs'; + export const OPEN_LOGS = 'java.open.logs'; /** * Open Java formatter settings @@ -132,6 +132,10 @@ export namespace Commands { * Organize imports silently. */ export const ORGANIZE_IMPORTS_SILENTLY = "java.edit.organizeImports"; + /** + * Custom paste action (triggers auto-import) + */ + export const CLIPBOARD_ONPASTE = 'java.action.clipboardPasteAction'; /** * Choose type to import. */ diff --git a/src/extension.ts b/src/extension.ts index 3aa1d34b75..e2ab742950 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -18,9 +18,10 @@ import * as buildpath from './buildpath'; import * as hoverAction from './hoverAction'; import * as sourceAction from './sourceAction'; import * as refactorAction from './refactorAction'; +import * as pasteAction from './pasteAction'; import * as net from 'net'; import { getJavaConfiguration } from './utils'; -import { onConfigurationChange, excludeProjectSettingsFiles, initializeSettings } from './settings'; +import { onConfigurationChange, excludeProjectSettingsFiles } from './settings'; import { logger, initializeLogFile } from './log'; import glob = require('glob'); @@ -388,7 +389,7 @@ export function activate(context: ExtensionContext): Promise { buildpath.registerCommands(context); sourceAction.registerCommands(languageClient, context); refactorAction.registerCommands(languageClient, context); - initializeSettings(languageClient, context); // may need to move in the future + pasteAction.registerCommands(languageClient, context); context.subscriptions.push(window.onDidChangeActiveTextEditor((editor) => { toggleItem(editor, item); diff --git a/src/pasteAction.ts b/src/pasteAction.ts new file mode 100644 index 0000000000..a7970091e7 --- /dev/null +++ b/src/pasteAction.ts @@ -0,0 +1,50 @@ +'use strict'; + +import { commands, env, ExtensionContext, Range, TextEditor, window } from 'vscode'; +import { LanguageClient } from 'vscode-languageclient'; +import { Commands } from './commands'; + +export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) { + context.subscriptions.push(commands.registerCommand(Commands.CLIPBOARD_ONPASTE, () => { + registerOrganizeImportsOnPasteCommand(); + })); +} + +export async function registerOrganizeImportsOnPasteCommand(): Promise { + const clipboardText: string = await env.clipboard.readText(); + const editor: TextEditor = window.activeTextEditor; + const documentText: string = editor.document.getText(); + const numCursors = editor.selections.length; + let bits: string[] = []; + if (numCursors > 1) { + bits = clipboardText.split(/\r?\n/); + } + const action = editor.edit(textInserter => { + for (let i = 0; i < numCursors; i++) { + const selection = editor.selections[i]; + const isCursorOnly = selection.isEmpty; + const text = bits.length === numCursors ? bits[i] : clipboardText; + if (isCursorOnly) { + textInserter.insert(selection.start, text); + } + else { + const start = selection.start; + const end = selection.end; + textInserter.replace(new Range(start, end), text); + } + } + }); + + action.then((wasApplied) => { + const fileURI = editor.document.uri.toString(); + if (wasApplied && fileURI.endsWith(".java")) { + const hasText: boolean = documentText !== null && /\S/.test(documentText); + if (hasText) { + // Organize imports silently to avoid surprising the user + commands.executeCommand(Commands.ORGANIZE_IMPORTS_SILENTLY, fileURI); + } else { + commands.executeCommand(Commands.ORGANIZE_IMPORTS, { textDocument: { uri: fileURI } }); + } + } + }); +} \ No newline at end of file diff --git a/src/settings.ts b/src/settings.ts index f475339122..a5d1f767c0 100644 --- a/src/settings.ts +++ b/src/settings.ts @@ -15,8 +15,6 @@ const changeItem = { const EXCLUDE_FILE_CONFIG = 'configuration.checkProjectSettingsExclusions'; export const ORGANIZE_IMPORTS_ON_PASTE = 'actionsOnPaste.organizeImports'; // java.actionsOnPaste.organizeImports -// index of the paste disposable in the subscriptions array -let pasteSubscriptionIndex; let oldConfig: WorkspaceConfiguration = getJavaConfiguration(); @@ -39,21 +37,11 @@ export function onConfigurationChange(languageClient: LanguageClient, context: E } }); } - handleJavaPasteConfigurationChange(languageClient, context, newConfig); // update old config oldConfig = newConfig; }); } -/** - * Starting point for any settings that need to be handled when the server starts - * @param languageClient - * @param context - */ -export function initializeSettings(languageClient: LanguageClient, context: ExtensionContext) { - handleInitialConfigurations(languageClient, context, getJavaConfiguration()); -} - export function excludeProjectSettingsFiles() { if (workspace.workspaceFolders && workspace.workspaceFolders.length) { workspace.workspaceFolders.forEach((folder) => { @@ -128,78 +116,3 @@ export function getJavaEncoding(): string { } return javaEncoding; } - -export function handleInitialConfigurations(languageClient: LanguageClient, context: ExtensionContext, newConfig: WorkspaceConfiguration) { - // organize imports on paste registration - if (newConfig.get(ORGANIZE_IMPORTS_ON_PASTE)) { - registerOverridePasteCommand(languageClient, context); - } -} - -export function handleJavaPasteConfigurationChange(languageClient: LanguageClient, context: ExtensionContext, newConfig: WorkspaceConfiguration) { - const oldOrganizeImportsOnPaste = oldConfig.get(ORGANIZE_IMPORTS_ON_PASTE); - const newOrganizeImportsOnPaste = newConfig.get(ORGANIZE_IMPORTS_ON_PASTE); - if (oldOrganizeImportsOnPaste !== newOrganizeImportsOnPaste) { - if (newOrganizeImportsOnPaste === true) { - registerOverridePasteCommand(languageClient, context); - } - else { - unregisterOverridePasteCommand(languageClient, context); - } - } -} - -export function registerOverridePasteCommand(languageClient: LanguageClient, context: ExtensionContext): void { - // referencing https://github.com/gazugafan/vscode-indent-on-paste/blob/master/src/extension.ts - const length = context.subscriptions.push(commands.registerCommand('editor.action.clipboardPasteAction', async () => { - - const clipboardText: string = await env.clipboard.readText(); - const editor: TextEditor = window.activeTextEditor; - const documentText: string = editor.document.getText(); - const numCursors = editor.selections.length; - let bits: string[] = []; - if (numCursors > 1) { - bits = clipboardText.split(/\r?\n/); - } - const action = editor.edit(textInserter => { - for (let i = 0; i < numCursors; i++) { - const selection = editor.selections[i]; - const isCursorOnly = selection.isEmpty; - const text = bits.length === numCursors ? bits[i] : clipboardText; - if (isCursorOnly) { - textInserter.insert(selection.start, text); - } - else { - const start = selection.start; - const end = selection.end; - textInserter.replace(new Range(start, end), text); - } - } - }); - - action.then((wasApplied) => { - const fileURI = editor.document.uri.toString(); - if (wasApplied && fileURI.endsWith(".java")) { - const hasText: boolean = documentText !== null && /\S/.test(documentText); - if (hasText) { - // Organize imports silently to avoid surprising the user - commands.executeCommand(Commands.ORGANIZE_IMPORTS_SILENTLY, fileURI); - } else { - commands.executeCommand(Commands.ORGANIZE_IMPORTS, { textDocument: { uri: fileURI } }); - } - } - }); - })); - - pasteSubscriptionIndex = length - 1; - languageClient.info(`Registered 'java.${ORGANIZE_IMPORTS_ON_PASTE}' command.`); -} - -export function unregisterOverridePasteCommand(languageClient: LanguageClient, context: ExtensionContext) { - if (pasteSubscriptionIndex !== null) { - const pasteDisposable: Disposable = context.subscriptions[pasteSubscriptionIndex]; - pasteDisposable.dispose(); - pasteSubscriptionIndex = null; - languageClient.info(`Unregistered 'java.${ORGANIZE_IMPORTS_ON_PASTE}' command.`); - } -} diff --git a/test/extension.test.ts b/test/extension.test.ts index 8b4a6bc8e8..731f7b8265 100644 --- a/test/extension.test.ts +++ b/test/extension.test.ts @@ -54,7 +54,8 @@ suite('Java Language Extension', () => { Commands.GENERATE_DELEGATE_METHODS_PROMPT, Commands.APPLY_REFACTORING_COMMAND, Commands.RENAME_COMMAND, - Commands.NAVIGATE_TO_SUPER_IMPLEMENTATION_COMMAND + Commands.NAVIGATE_TO_SUPER_IMPLEMENTATION_COMMAND, + Commands.CLIPBOARD_ONPASTE ]; const foundJavaCommands = commands.filter((value) => { return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.');