Skip to content

Commit 17bfd19

Browse files
authored
refactor: move utilities out of extension.ts (#2824)
* extract OutputInfoCollector from extension.ts * extract ClientErrorHandler from extension.ts * move hasBuildToolConflicts to utils.ts * move getJavaConfig to utils.ts * move constant cleanWorkspaceFileName into settings.ts * move applyWorkspaceEdit to standardLanguageClient.ts Signed-off-by: Yan Zhang <[email protected]>
1 parent 1895510 commit 17bfd19

9 files changed

+189
-181
lines changed

src/clientErrorHandler.ts

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
import { window, commands } from "vscode";
2+
import { ErrorHandler, Message, ErrorAction, CloseAction } from "vscode-languageclient";
3+
import { Commands } from "./commands";
4+
import { logger } from "./log";
5+
6+
export class ClientErrorHandler implements ErrorHandler {
7+
private restarts: number[];
8+
9+
constructor(private name: string) {
10+
this.restarts = [];
11+
}
12+
13+
public error(_error: Error, _message: Message, count: number): ErrorAction {
14+
if (count && count <= 3) {
15+
logger.error(`${this.name} server encountered error: ${_message}, ${_error && _error.toString()}`);
16+
return ErrorAction.Continue;
17+
}
18+
19+
logger.error(`${this.name} server encountered error and will shut down: ${_message}, ${_error && _error.toString()}`);
20+
return ErrorAction.Shutdown;
21+
}
22+
23+
public closed(): CloseAction {
24+
this.restarts.push(Date.now());
25+
if (this.restarts.length < 5) {
26+
logger.error(`The ${this.name} server crashed and will restart.`);
27+
return CloseAction.Restart;
28+
} else {
29+
const diff = this.restarts[this.restarts.length - 1] - this.restarts[0];
30+
if (diff <= 3 * 60 * 1000) {
31+
const message = `The ${this.name} server crashed 5 times in the last 3 minutes. The server will not be restarted.`;
32+
logger.error(message);
33+
const action = "Show logs";
34+
window.showErrorMessage(message, action).then(selection => {
35+
if (selection === action) {
36+
commands.executeCommand(Commands.OPEN_LOGS);
37+
}
38+
});
39+
return CloseAction.DoNotRestart;
40+
}
41+
42+
logger.error(`The ${this.name} server crashed and will restart.`);
43+
this.restarts.shift();
44+
return CloseAction.Restart;
45+
}
46+
}
47+
}

src/extension.ts

Lines changed: 6 additions & 170 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,30 @@ import * as fs from 'fs';
55
import * as fse from 'fs-extra';
66
import * as os from 'os';
77
import * as path from 'path';
8-
import { CodeActionContext, CodeActionTriggerKind, commands, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions, IndentAction, InputBoxOptions, languages, OutputChannel, RelativePattern, TextDocument, UIKind, Uri, version, ViewColumn, window, workspace, WorkspaceConfiguration } from 'vscode';
9-
import { CancellationToken, CloseAction, CodeActionParams, CodeActionRequest, Command, DidChangeConfigurationNotification, ErrorAction, ErrorHandler, ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, Message, RevealOutputChannelOn } from 'vscode-languageclient';
8+
import { CodeActionContext, CodeActionTriggerKind, commands, ConfigurationTarget, Diagnostic, env, EventEmitter, ExtensionContext, extensions, IndentAction, InputBoxOptions, languages, RelativePattern, TextDocument, UIKind, Uri, ViewColumn, window, workspace, WorkspaceConfiguration } from 'vscode';
9+
import { CancellationToken, CodeActionParams, CodeActionRequest, Command, DidChangeConfigurationNotification, ExecuteCommandParams, ExecuteCommandRequest, LanguageClientOptions, RevealOutputChannelOn } from 'vscode-languageclient';
1010
import { LanguageClient } from 'vscode-languageclient/node';
1111
import { apiManager } from './apiManager';
12+
import { ClientErrorHandler } from './clientErrorHandler';
1213
import { Commands } from './commands';
1314
import { ClientStatus, ExtensionAPI } from './extension.api';
1415
import * as fileEventHandler from './fileEventHandler';
1516
import { HEAP_DUMP_LOCATION, prepareExecutable } from './javaServerStarter';
1617
import { initializeLogFile, logger } from './log';
1718
import { cleanupLombokCache } from "./lombokSupport";
1819
import { markdownPreviewProvider } from "./markdownPreviewProvider";
20+
import { OutputInfoCollector } from './outputInfoCollector';
1921
import { collectJavaExtensions, getBundlesToReload, isContributedPartUpdated } from './plugin';
2022
import { registerClientProviders } from './providerDispatcher';
2123
import { initialize as initializeRecommendation } from './recommendation';
2224
import * as requirements from './requirements';
2325
import { runtimeStatusBarProvider } from './runtimeStatusBarProvider';
2426
import { serverStatusBarProvider } from './serverStatusBarProvider';
25-
import { ACTIVE_BUILD_TOOL_STATE, getJavaServerMode, handleTextBlockClosing, onConfigurationChange, ServerMode } from './settings';
27+
import { ACTIVE_BUILD_TOOL_STATE, cleanWorkspaceFileName, getJavaServerMode, handleTextBlockClosing, onConfigurationChange, ServerMode } from './settings';
2628
import { snippetCompletionProvider } from './snippetCompletionProvider';
2729
import { StandardLanguageClient } from './standardLanguageClient';
2830
import { SyntaxLanguageClient } from './syntaxLanguageClient';
29-
import { convertToGlob, deleteDirectory, ensureExists, getBuildFilePatterns, getExclusionBlob, getInclusionPatternsFromNegatedExclusion, getJavaConfiguration } from './utils';
31+
import { convertToGlob, deleteDirectory, ensureExists, getBuildFilePatterns, getExclusionBlob, getInclusionPatternsFromNegatedExclusion, getJavaConfig, getJavaConfiguration, hasBuildToolConflicts } from './utils';
3032
import glob = require('glob');
3133

3234
const syntaxClient: SyntaxLanguageClient = new SyntaxLanguageClient();
@@ -36,51 +38,6 @@ const extensionName = 'Language Support for Java';
3638
let storagePath: string;
3739
let clientLogFile: string;
3840

39-
export const cleanWorkspaceFileName = '.cleanWorkspace';
40-
41-
export class ClientErrorHandler implements ErrorHandler {
42-
private restarts: number[];
43-
44-
constructor(private name: string) {
45-
this.restarts = [];
46-
}
47-
48-
public error(_error: Error, _message: Message, count: number): ErrorAction {
49-
if (count && count <= 3) {
50-
logger.error(`${this.name} server encountered error: ${_message}, ${_error && _error.toString()}`);
51-
return ErrorAction.Continue;
52-
}
53-
54-
logger.error(`${this.name} server encountered error and will shut down: ${_message}, ${_error && _error.toString()}`);
55-
return ErrorAction.Shutdown;
56-
}
57-
58-
public closed(): CloseAction {
59-
this.restarts.push(Date.now());
60-
if (this.restarts.length < 5) {
61-
logger.error(`The ${this.name} server crashed and will restart.`);
62-
return CloseAction.Restart;
63-
} else {
64-
const diff = this.restarts[this.restarts.length - 1] - this.restarts[0];
65-
if (diff <= 3 * 60 * 1000) {
66-
const message = `The ${this.name} server crashed 5 times in the last 3 minutes. The server will not be restarted.`;
67-
logger.error(message);
68-
const action = "Show logs";
69-
window.showErrorMessage(message, action).then(selection => {
70-
if (selection === action) {
71-
commands.executeCommand(Commands.OPEN_LOGS);
72-
}
73-
});
74-
return CloseAction.DoNotRestart;
75-
}
76-
77-
logger.error(`The ${this.name} server crashed and will restart.`);
78-
this.restarts.shift();
79-
return CloseAction.Restart;
80-
}
81-
}
82-
}
83-
8441
/**
8542
* Shows a message about the server crashing due to an out of memory issue
8643
*/
@@ -118,46 +75,6 @@ function getHeapDumpFolderFromSettings(): string {
11875
return results[1] || results[2] || results[3];
11976
}
12077

121-
export class OutputInfoCollector implements OutputChannel {
122-
private channel: OutputChannel = null;
123-
124-
constructor(public name: string) {
125-
this.channel = window.createOutputChannel(this.name);
126-
}
127-
128-
append(value: string): void {
129-
logger.info(value);
130-
this.channel.append(value);
131-
}
132-
133-
appendLine(value: string): void {
134-
logger.info(value);
135-
this.channel.appendLine(value);
136-
}
137-
138-
replace(value: string): void {
139-
this.clear();
140-
this.append(value);
141-
}
142-
143-
clear(): void {
144-
this.channel.clear();
145-
}
146-
147-
show(preserveFocus?: boolean): void;
148-
show(column?: ViewColumn, preserveFocus?: boolean): void;
149-
show(column?: any, preserveFocus?: any) {
150-
this.channel.show(column, preserveFocus);
151-
}
152-
153-
hide(): void {
154-
this.channel.hide();
155-
}
156-
157-
dispose(): void {
158-
this.channel.dispose();
159-
}
160-
}
16178

16279
export function activate(context: ExtensionContext): Promise<ExtensionAPI> {
16380
context.subscriptions.push(markdownPreviewProvider);
@@ -563,48 +480,6 @@ async function ensureNoBuildToolConflicts(context: ExtensionContext, clientOptio
563480
return true;
564481
}
565482

566-
export async function hasBuildToolConflicts(): Promise<boolean> {
567-
const projectConfigurationUris: Uri[] = await getBuildFilesInWorkspace();
568-
const projectConfigurationFsPaths: string[] = projectConfigurationUris.map((uri) => uri.fsPath);
569-
const eclipseDirectories = getDirectoriesByBuildFile(projectConfigurationFsPaths, [], ".project");
570-
// ignore the folders that already has .project file (already imported before)
571-
const gradleDirectories = getDirectoriesByBuildFile(projectConfigurationFsPaths, eclipseDirectories, ".gradle");
572-
const gradleDirectoriesKts = getDirectoriesByBuildFile(projectConfigurationFsPaths, eclipseDirectories, ".gradle.kts");
573-
gradleDirectories.concat(gradleDirectoriesKts);
574-
const mavenDirectories = getDirectoriesByBuildFile(projectConfigurationFsPaths, eclipseDirectories, "pom.xml");
575-
return gradleDirectories.some((gradleDir) => {
576-
return mavenDirectories.includes(gradleDir);
577-
});
578-
}
579-
580-
async function getBuildFilesInWorkspace(): Promise<Uri[]> {
581-
const buildFiles: Uri[] = [];
582-
const inclusionFilePatterns: string[] = getBuildFilePatterns();
583-
inclusionFilePatterns.push("**/.project");
584-
const inclusionFolderPatterns: string[] = getInclusionPatternsFromNegatedExclusion();
585-
// Since VS Code API does not support put negated exclusion pattern in findFiles(),
586-
// here we first parse the negated exclusion to inclusion and do the search.
587-
if (inclusionFilePatterns.length > 0 && inclusionFolderPatterns.length > 0) {
588-
buildFiles.push(...await workspace.findFiles(convertToGlob(inclusionFilePatterns, inclusionFolderPatterns), null /* force not use default exclusion */));
589-
}
590-
591-
const inclusionBlob: string = convertToGlob(inclusionFilePatterns);
592-
const exclusionBlob: string = getExclusionBlob();
593-
if (inclusionBlob) {
594-
buildFiles.push(...await workspace.findFiles(inclusionBlob, exclusionBlob));
595-
}
596-
597-
return buildFiles;
598-
}
599-
600-
function getDirectoriesByBuildFile(inclusions: string[], exclusions: string[], fileName: string): string[] {
601-
return inclusions.filter((fsPath) => fsPath.endsWith(fileName)).map((fsPath) => {
602-
return path.dirname(fsPath);
603-
}).filter((inclusion) => {
604-
return !exclusions.includes(inclusion);
605-
});
606-
}
607-
608483
async function promptUserForStandardServer(config: WorkspaceConfiguration): Promise<boolean> {
609484
const choice: string = await window.showInformationMessage("The workspace contains Java projects. Would you like to import them?", "Yes", "Always", "Later");
610485
switch (choice) {
@@ -632,36 +507,6 @@ async function promptUserForStandardServer(config: WorkspaceConfiguration): Prom
632507
}
633508
}
634509

635-
export function getJavaConfig(javaHome: string) {
636-
const origConfig = getJavaConfiguration();
637-
const javaConfig = JSON.parse(JSON.stringify(origConfig));
638-
javaConfig.home = javaHome;
639-
// Since source & output path are project specific settings. To avoid pollute other project,
640-
// we avoid reading the value from the global scope.
641-
javaConfig.project.outputPath = origConfig.inspect<string>("project.outputPath").workspaceValue;
642-
javaConfig.project.sourcePaths = origConfig.inspect<string[]>("project.sourcePaths").workspaceValue;
643-
644-
const editorConfig = workspace.getConfiguration('editor');
645-
javaConfig.format.insertSpaces = editorConfig.get('insertSpaces');
646-
javaConfig.format.tabSize = editorConfig.get('tabSize');
647-
const androidSupport = javaConfig.jdt.ls.androidSupport.enabled;
648-
switch (androidSupport) {
649-
case "auto":
650-
javaConfig.jdt.ls.androidSupport.enabled = version.includes("insider") ? true : false;
651-
break;
652-
case "on":
653-
javaConfig.jdt.ls.androidSupport.enabled = true;
654-
break;
655-
case "off":
656-
javaConfig.jdt.ls.androidSupport.enabled = false;
657-
break;
658-
default:
659-
javaConfig.jdt.ls.androidSupport.enabled = false;
660-
break;
661-
}
662-
return javaConfig;
663-
}
664-
665510
export function deactivate(): Promise<void[]> {
666511
return Promise.all<void>([
667512
standardClient.stop(),
@@ -964,15 +809,6 @@ async function addFormatter(extensionPath, formatterUrl, defaultFormatter, relat
964809
});
965810
}
966811

967-
export function applyWorkspaceEdit(obj, languageClient): Thenable<boolean> {
968-
const edit = languageClient.protocol2CodeConverter.asWorkspaceEdit(obj);
969-
if (edit) {
970-
return workspace.applyEdit(edit);
971-
} else {
972-
return Promise.resolve(true);
973-
}
974-
}
975-
976812
async function getTriggerFiles(): Promise<string[]> {
977813
const openedJavaFiles = [];
978814
const activeJavaFile = getJavaFilePathOfTextDocument(window.activeTextEditor && window.activeTextEditor.document);

src/outputInfoCollector.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { OutputChannel, window, ViewColumn } from "vscode";
2+
import { logger } from "./log";
3+
4+
export class OutputInfoCollector implements OutputChannel {
5+
private channel: OutputChannel = null;
6+
7+
constructor(public name: string) {
8+
this.channel = window.createOutputChannel(this.name);
9+
}
10+
11+
append(value: string): void {
12+
logger.info(value);
13+
this.channel.append(value);
14+
}
15+
16+
appendLine(value: string): void {
17+
logger.info(value);
18+
this.channel.appendLine(value);
19+
}
20+
21+
replace(value: string): void {
22+
this.clear();
23+
this.append(value);
24+
}
25+
26+
clear(): void {
27+
this.channel.clear();
28+
}
29+
30+
show(preserveFocus?: boolean): void;
31+
show(column?: ViewColumn, preserveFocus?: boolean): void;
32+
show(column?: any, preserveFocus?: any) {
33+
this.channel.show(column, preserveFocus);
34+
}
35+
36+
hide(): void {
37+
this.channel.hide();
38+
}
39+
40+
dispose(): void {
41+
this.channel.dispose();
42+
}
43+
}

src/runtimeStatusBarProvider.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,7 @@ import { apiManager } from "./apiManager";
99
import * as semver from "semver";
1010
import { ACTIVE_BUILD_TOOL_STATE } from "./settings";
1111
import { BuildFileStatusItemFactory, RuntimeStatusItemFactory, StatusCommands, supportsLanguageStatus } from "./languageStatusItemFactory";
12-
import { getAllJavaProjects, getJavaConfiguration } from "./utils";
13-
import { hasBuildToolConflicts } from "./extension";
12+
import { getAllJavaProjects, getJavaConfiguration, hasBuildToolConflicts } from "./utils";
1413
import { LombokVersionItemFactory, getLombokVersion, isLombokImported } from "./lombokSupport";
1514

1615
class RuntimeStatusBarProvider implements Disposable {

src/settings.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,10 @@
22

33
import * as fs from 'fs';
44
import * as path from 'path';
5-
import { window, Uri, workspace, WorkspaceConfiguration, commands, ConfigurationTarget, env, ExtensionContext, TextEditor, Range, Disposable, WorkspaceFolder, TextDocument, Position, SnippetString, TextLine } from 'vscode';
5+
import { commands, ConfigurationTarget, env, ExtensionContext, Position, Range, SnippetString, TextDocument, Uri, window, workspace, WorkspaceConfiguration, WorkspaceFolder } from 'vscode';
66
import { Commands } from './commands';
7-
import { cleanWorkspaceFileName } from './extension';
7+
import { cleanupLombokCache } from './lombokSupport';
88
import { ensureExists, getJavaConfiguration } from './utils';
9-
import { checkLombokDependency, cleanupLombokCache } from './lombokSupport';
10-
import { CodeLensResolveRequest } from 'vscode-languageclient';
119

1210
const DEFAULT_HIDDEN_FILES: string[] = ['**/.classpath', '**/.project', '**/.settings', '**/.factorypath'];
1311
const IS_WORKSPACE_JDK_ALLOWED = "java.ls.isJdkAllowed";
@@ -16,6 +14,8 @@ export const IS_WORKSPACE_VMARGS_ALLOWED = "java.ls.isVmargsAllowed";
1614
const extensionName = 'Language Support for Java';
1715
export const ACTIVE_BUILD_TOOL_STATE = "java.activeBuildTool";
1816

17+
export const cleanWorkspaceFileName = '.cleanWorkspace';
18+
1919
const changeItem = {
2020
global: 'Exclude globally',
2121
workspace: 'Exclude in workspace',

src/sourceAction.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { commands, window, ExtensionContext, ViewColumn, Uri, Disposable, worksp
44
import { CodeActionParams, WorkspaceEdit } from 'vscode-languageclient';
55
import { LanguageClient } from 'vscode-languageclient/node';
66
import { Commands } from './commands';
7-
import { applyWorkspaceEdit } from './extension';
87
import { ListOverridableMethodsRequest, AddOverridableMethodsRequest, CheckHashCodeEqualsStatusRequest, GenerateHashCodeEqualsRequest,
98
OrganizeImportsRequest, ImportCandidate, ImportSelection, GenerateToStringRequest, CheckToStringStatusRequest, VariableBinding, GenerateAccessorsRequest, CheckConstructorStatusRequest, GenerateConstructorsRequest, CheckDelegateMethodsStatusRequest, GenerateDelegateMethodsRequest, AccessorKind, AccessorCodeActionRequest, AccessorCodeActionParams } from './protocol';
9+
import { applyWorkspaceEdit } from './standardLanguageClient';
1010

1111
export function registerCommands(languageClient: LanguageClient, context: ExtensionContext) {
1212
registerOverrideMethodsCommand(languageClient, context);

0 commit comments

Comments
 (0)