Skip to content

Commit

Permalink
Smart semicolon autocorrect
Browse files Browse the repository at this point in the history
Signed-off-by: Snjezana Peco <[email protected]>
  • Loading branch information
snjeza authored and rgrunber committed Jul 28, 2023
1 parent 8b3c2ec commit f7651bd
Show file tree
Hide file tree
Showing 9 changed files with 141 additions and 4 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,7 @@ The following settings are supported:
- `ask`: Ask to reload the sources of the open class files
- `auto`: Automatically reload the sources of the open class files
- `manual`: Manually reload the sources of the open class files
* `java.edit.smartSemicolonDetection.enabled`: Defines the `smart semicolon` detection. Defaults to `false`.

Semantic Highlighting
===============
Expand Down
26 changes: 26 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1140,6 +1140,12 @@
"markdownDescription": "Specifies whether to recheck all open Java files for diagnostics when editing a Java file.",
"scope": "window"
},
"java.edit.smartSemicolonDetection.enabled": {
"type": "boolean",
"default": false,
"markdownDescription": "Defines the `smart semicolon` detection. Defaults to `false`.",
"scope": "window"
},
"java.editor.reloadChangedSources": {
"type": "string",
"enum": [
Expand Down Expand Up @@ -1302,6 +1308,16 @@
"command": "java.server.restart",
"title": "%java.server.restart%",
"category": "Java"
},
{
"command": "java.edit.smartSemicolonDetection.command",
"title": "%java.edit.smartSemicolonDetection%",
"category": "Java"
},
{
"command": "java.edit.smartSemicolonDetectionUndo",
"title": "%java.edit.smartSemicolonDetectionUndo%",
"category": "Java"
}
],
"keybindings": [
Expand All @@ -1319,6 +1335,16 @@
"key": "ctrl+shift+v",
"mac": "cmd+shift+v",
"when": "javaLSReady && editorLangId == java"
},
{
"command": "java.edit.smartSemicolonDetection.command",
"key": ";",
"when": "editorTextFocus && !editorReadonly && javaLSReady && editorLangId == java"
},
{
"command": "java.edit.smartSemicolonDetectionUndo",
"key": "backspace",
"when": "editorTextFocus && !editorReadonly && javaLSReady && editorLangId == java"
}
],
"menus": {
Expand Down
4 changes: 3 additions & 1 deletion package.nls.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,7 @@
"java.action.changeBaseType": "Base on this Type",
"java.project.createModuleInfo.command": "Create module-info.java",
"java.clean.sharedIndexes": "Clean Shared Indexes",
"java.server.restart": "Restart Java Language Server"
"java.server.restart": "Restart Java Language Server",
"java.edit.smartSemicolonDetection": "Java Smart Semicolon Detection",
"java.edit.smartSemicolonDetectionUndo": "Java Smart Semicolon Detection Undo"
}
11 changes: 11 additions & 0 deletions src/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -335,4 +335,15 @@ export namespace Commands {
*/
export const GET_DECOMPILED_SOURCE = "java.decompile";

/**
* Smart semicolon detection.
*/
export const SMARTSEMICOLON_DETECTION = "java.edit.smartSemicolonDetection";
export const SMARTSEMICOLON_DETECTION_CMD = "java.edit.smartSemicolonDetection.command";

/**
* Smart semicolon detection backspace.
*/
export const SMARTSEMICOLON_DETECTION_UNDO = "java.edit.smartSemicolonDetectionUndo";

}
3 changes: 1 addition & 2 deletions src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import * as fs from 'fs';
import * as fse from 'fs-extra';
import * as os from 'os';
import * as path from 'path';
import { CodeActionContext, commands, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions, IndentAction, InputBoxOptions, languages, RelativePattern, TextDocument, UIKind, Uri, ViewColumn, window, workspace, WorkspaceConfiguration, ProgressLocation } from 'vscode';
import { CodeActionContext, commands, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions, IndentAction, InputBoxOptions, languages, RelativePattern, TextDocument, UIKind, Uri, ViewColumn, window, workspace, WorkspaceConfiguration, ProgressLocation, Position, Selection, Range } from 'vscode';
import { CancellationToken, CodeActionParams, CodeActionRequest, Command, DidChangeConfigurationNotification, ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, RevealOutputChannelOn } from 'vscode-languageclient';
import { LanguageClient } from 'vscode-languageclient/node';
import { apiManager } from './apiManager';
Expand Down Expand Up @@ -268,7 +268,6 @@ export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
// the promise is resolved
// no need to pass `resolve` into any code past this point,
// since `resolve` is a no-op from now on

const serverOptions = prepareExecutable(requirements, syntaxServerWorkspacePath, getJavaConfig(requirements.java_home), context, true);
if (requireSyntaxServer) {
if (process.env['SYNTAXLS_CLIENT_PORT']) {
Expand Down
9 changes: 8 additions & 1 deletion src/settings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

import * as fs from 'fs';
import * as path from 'path';
import { commands, ConfigurationTarget, env, ExtensionContext, Position, Range, SnippetString, TextDocument, Uri, window, workspace, WorkspaceConfiguration, WorkspaceFolder } from 'vscode';
import { commands, ConfigurationTarget, env, ExtensionContext, Position, Range, Selection, SnippetString, TextDocument, Uri, window, workspace, WorkspaceConfiguration, WorkspaceFolder } from 'vscode';
import { Commands } from './commands';
import { cleanupLombokCache } from './lombokSupport';
import { ensureExists, getJavaConfiguration } from './utils';
import { apiManager } from './apiManager';
import { setSmartSemiColonDetectionState } from './smartSemicolonDetection';

const DEFAULT_HIDDEN_FILES: string[] = ['**/.classpath', '**/.project', '**/.settings', '**/.factorypath'];
const IS_WORKSPACE_JDK_ALLOWED = "java.ls.isJdkAllowed";
Expand Down Expand Up @@ -329,6 +331,9 @@ export function handleTextBlockClosing(document: TextDocument, changes: readonly
return;
}
if (lastChange.text !== '"""";') {
if (lastChange.text !== ';') {
setSmartSemiColonDetectionState(null, null);
}
return;
}
const selection = activeTextEditor.selection.active;
Expand All @@ -349,3 +354,5 @@ export function handleTextBlockClosing(document: TextDocument, changes: readonly
}
}
}


76 changes: 76 additions & 0 deletions src/smartSemicolonDetection.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
'use strict';

import { commands, ExtensionContext, Position, Range, Selection, window } from 'vscode';
import { Commands } from './commands';
import { getJavaConfiguration } from './utils';

let oldPosition: Position = null;
let newPosition: Position = null;

export function registerSmartSemicolonDetection(context: ExtensionContext) {
context.subscriptions.push(commands.registerCommand(Commands.SMARTSEMICOLON_DETECTION_CMD, async () => {
if (!didSmartSemicolonInsertion() && enabled()) {
const params: SmartDetectionParams = {
uri: window.activeTextEditor.document.uri.toString(),
position: window.activeTextEditor!.selection.active,
};
const response: SmartDetectionParams = await commands.executeCommand(Commands.EXECUTE_WORKSPACE_COMMAND, Commands.SMARTSEMICOLON_DETECTION, JSON.stringify(params));
if (response !== null) {
window.activeTextEditor!.edit(editBuilder => {
oldPosition = window.activeTextEditor!.selection.active;
editBuilder.insert(response.position, ";");
window.activeTextEditor.selections = [new Selection(response.position, response.position)];
newPosition = window.activeTextEditor!.selection.active;
});
return;
}
}
window.activeTextEditor!.edit(editBuilder => {
editBuilder.insert(window.activeTextEditor!.selection.active, ";");
});
newPosition = null;
oldPosition = null;
}));
context.subscriptions.push(commands.registerCommand(Commands.SMARTSEMICOLON_DETECTION_UNDO, async () => {
if (didSmartSemicolonInsertion() && enabled()) {
window.activeTextEditor!.edit(editBuilder => {
editBuilder.insert(oldPosition, ";");
const delRange = new Range(newPosition, new Position(newPosition.line, newPosition.character + 1));
editBuilder.delete(delRange);
window.activeTextEditor.selections = [new Selection(oldPosition, oldPosition)];
oldPosition = null;
newPosition = null;
});
return;
}
window.activeTextEditor!.edit(() => {
commands.executeCommand("deleteLeft");
});
oldPosition = null;
newPosition = null;
}));
}

interface SmartDetectionParams {
uri: String;
position: Position;
}

function didSmartSemicolonInsertion() {
const smartSemicolonInsertion = window.activeTextEditor.selections.length === 1 && enabled() && oldPosition !== null && newPosition !== null;
if (smartSemicolonInsertion) {
const active = window.activeTextEditor!.selection.active;
const prev = new Position(active.line, active.character === 0 ? 0 : active.character - 1);
return newPosition.isEqual(prev);
}
return smartSemicolonInsertion;
}

function enabled() {
return getJavaConfiguration().get<boolean>("edit.smartSemicolonDetection.enabled");
}

export function setSmartSemiColonDetectionState(oldPos: Position, newPos: Position) {
oldPosition = oldPos;
newPos = newPos;
}
6 changes: 6 additions & 0 deletions src/standardLanguageClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ import { getAllJavaProjects, getJavaConfig, getJavaConfiguration } from "./utils
import { Telemetry } from "./telemetry";
import { TelemetryEvent } from "@redhat-developer/vscode-redhat-telemetry/lib";
import { registerDocumentValidationListener } from './diagnostic';
import { registerSmartSemicolonDetection } from './smartSemicolonDetection';

const extensionName = 'Language Support for Java';
const GRADLE_CHECKSUM = "gradle/checksum/prompt";
Expand Down Expand Up @@ -137,6 +138,11 @@ export class StandardLanguageClient {
// clients may not have properly configured documentPaste
logger.error(error);
}
try {
registerSmartSemicolonDetection(context);
} catch (error) {
logger.error(error);
}
activationProgressNotification.hide();
if (!hasImported) {
showImportFinishNotification(context);
Expand Down
9 changes: 9 additions & 0 deletions test/standard-mode-suite/extension.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ suite('Java Language Extension - Standard', () => {
return vscode.commands.getCommands(true).then((commands) =>
{
const JAVA_COMMANDS = [
Commands.ADD_TO_SOURCEPATH,
Commands.ADD_TO_SOURCEPATH_CMD,
Commands.APPLY_REFACTORING_COMMAND,
Commands.APPLY_WORKSPACE_EDIT,
Expand All @@ -53,6 +54,7 @@ suite('Java Language Extension - Standard', () => {
Commands.CLIPBOARD_ONPASTE,
Commands.COMPILE_WORKSPACE,
Commands.CONFIGURATION_UPDATE,
Commands.CREATE_MODULE_INFO,
Commands.CREATE_MODULE_INFO_COMMAND,
Commands.EXECUTE_WORKSPACE_COMMAND,
Commands.GENERATE_ACCESSORS_PROMPT,
Expand Down Expand Up @@ -102,13 +104,20 @@ suite('Java Language Extension - Standard', () => {
Commands.SHOW_SERVER_TASK_STATUS,
Commands.SWITCH_SERVER_MODE,
"java.edit.stringFormatting",
"java.completion.onDidSelect",
"java.decompile",
"java.protobuf.generateSources",
Commands.SHOW_TYPE_HIERARCHY,
Commands.SHOW_SUBTYPE_HIERARCHY,
Commands.SHOW_SUPERTYPE_HIERARCHY,
Commands.SHOW_CLASS_HIERARCHY,
Commands.UPGRADE_GRADLE_WRAPPER,
Commands.UPGRADE_GRADLE_WRAPPER_CMD,
Commands.UPDATE_SOURCE_ATTACHMENT,
Commands.UPDATE_SOURCE_ATTACHMENT_CMD,
Commands.SMARTSEMICOLON_DETECTION_CMD,
Commands.SMARTSEMICOLON_DETECTION_UNDO,
Commands.RESOLVE_SOURCE_ATTACHMENT,
].sort();
const foundJavaCommands = commands.filter((value) => {
return JAVA_COMMANDS.indexOf(value)>=0 || value.startsWith('java.');
Expand Down

0 comments on commit f7651bd

Please sign in to comment.