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

Use custom paste action instead of overriding the native one. #1116

Merged
merged 1 commit into from
Oct 23, 2019
Merged
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: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
===============
Expand Down
12 changes: 6 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
}
}
},
Expand Down Expand Up @@ -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": {
Expand Down
6 changes: 5 additions & 1 deletion src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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.
*/
Expand Down
5 changes: 3 additions & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');

Expand Down Expand Up @@ -388,7 +389,7 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
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);
Expand Down
50 changes: 50 additions & 0 deletions src/pasteAction.ts
Original file line number Diff line number Diff line change
@@ -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<void> {
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 } });
}
}
});
}
87 changes: 0 additions & 87 deletions src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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();

Expand All @@ -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) => {
Expand Down Expand Up @@ -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.`);
}
}
3 changes: 2 additions & 1 deletion test/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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.');
Expand Down