Skip to content
Draft
Show file tree
Hide file tree
Changes from 8 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
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,14 @@ import {
Diagnostic,
} from "vscode-languageserver-types";
import {
PluginConfigurationProvider,
PluginConfigurationProviderInstance,
serializeProcessGroup,
} from "../../workspace/plugin-configuration-provider";

import { Commands, PluginConfiguration } from "../constants";
import { PLICodes } from "../../validation/pli-codes";
import { lspCodes } from "../lsp-codes";

export async function quickFixResolveInclude(
diagnostic: Diagnostic,
): Promise<CodeAction | undefined> {
Expand Down Expand Up @@ -73,34 +76,68 @@ export async function quickFixResolveInclude(

const procGrpsFileUri = UriUtils.joinPath(
workspaceFolderUri,
PluginConfigurationProvider.PROCESS_GROUP_CONFIG_FILE,
PluginConfiguration.PROCESS_GROUP_FILE_PATH,
);

const action: CodeAction = {
title: `Add '${parentFolder}' to INCLUDE libs`,
title: `Add '${parentFolder}' to INCLUDE libs.`,
kind: CodeActionKind.QuickFix,
diagnostics: [diagnostic],
command: {
title: "Apply INCLUDE fix",
command: "pli.applyIncludeFix",
command: Commands.RESOLVE_INCLUDE,
arguments: [procGrpsFileUri.toString(), newContent],
},
};

return action;
}

export async function quickFixCreateConfig(
diagnostic: Diagnostic,
): Promise<CodeAction | undefined> {
const entryUri = UriUtils.basename(URI.parse(diagnostic.data.entryUri));
if (!entryUri) {
return;
}
const action: CodeAction = {
title: `Create a plugin configuration folder for this file.`,
kind: CodeActionKind.QuickFix,
diagnostics: [diagnostic],
command: {
title: "Create configuration folder",
command: Commands.CREATE_CONFIG,
arguments: [entryUri],
},
};

return action;
}

export async function applyQuickFixes(
diagnostics: Diagnostic[],
): Promise<CodeAction[] | undefined> {
const actions: CodeAction[] = [];
// PLI CODES LIST
const CODE_UNRESOLVED_INCLUDE = "IBM3841IS"; // The INCLUDE file could not be found, or if found, it could not be opened.
const CODE_UNRESOLVED_INCLUDE = PLICodes.Severe.IBM3841I.code; // The INCLUDE file could not be found, or if found, it could not be opened.
const CODE_MISSING_CONFIG =
lspCodes.IncludeResolution.MissingConfiguration.code;

for (const diagnostic of diagnostics) {
if (diagnostic.code === CODE_UNRESOLVED_INCLUDE) {
const action = await quickFixResolveInclude(diagnostic);
if (action) actions.push(action);
const DIAG_CODE = diagnostic.code;
if (!DIAG_CODE) {
return;
}
let action: CodeAction | undefined;
switch (DIAG_CODE) {
case CODE_UNRESOLVED_INCLUDE:
action = await quickFixResolveInclude(diagnostic);
if (action) actions.push(action);
break;
case CODE_MISSING_CONFIG:
action = await quickFixCreateConfig(diagnostic);
if (action) actions.push(action);
break;
}
}

Expand Down
78 changes: 78 additions & 0 deletions packages/language/src/language-server/commands.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
/**
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/

import { URI } from "vscode-uri";
import { FileSystemProviderInstance } from "../workspace/file-system-provider";
import { Mutex } from "../workspace/mutex";
import { PluginConfigurationProviderInstance } from "../workspace/plugin-configuration-provider";
import { ExecuteCommandParams } from "vscode-languageserver";
import { UriUtils } from "../utils/uri";
import { PluginConfiguration } from "./constants";

export async function commandResolveInclude(params: ExecuteCommandParams) {
return Mutex.run(async () => {
const [uri, content] = params.arguments as string[];
try {
await FileSystemProviderInstance.writeFile(URI.parse(uri), content);
} catch (err) {
console.error("Failed to write proc_grps.json:", err);
}
});
}

export async function commandCreateConfig(params: ExecuteCommandParams) {
return Mutex.run(async () => {
const workspaceFolderUri = URI.parse(
PluginConfigurationProviderInstance.getWorkspacePath(),
);
if (!workspaceFolderUri) {
return;
}
try {
if (!params.arguments) {
return;
}
const entryUri = params.arguments[0];
await FileSystemProviderInstance.writeFile(
UriUtils.joinPath(
workspaceFolderUri,
PluginConfiguration.PROGRAM_FILE_PATH,
),
JSON.stringify(
{
...PluginConfiguration.DEFAULT_PROGRAM_FILE_CONTENT,
pgms: [
{
...PluginConfiguration.DEFAULT_PROGRAM_FILE_CONTENT.pgms[0],
program: entryUri,
},
],
},
null,
2,
),
);
await FileSystemProviderInstance.writeFile(
UriUtils.joinPath(
workspaceFolderUri,
PluginConfiguration.PROCESS_GROUP_FILE_PATH,
),
JSON.stringify(
PluginConfiguration.DEFAULT_PROCESS_GROUP_FILE_CONTENT,
null,
2,
),
);
} catch (err) {
console.error("Failed to create configuration: ", err);
}
});
}
23 changes: 11 additions & 12 deletions packages/language/src/language-server/connection-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,9 @@ import { completionRequest } from "./completion/completion-request";
import { hoverRequest } from "./hover-request";
import { Mutex } from "../workspace/mutex";
import { applyQuickFixes } from "./code-actions/apply-quick-fixes";
import { FileSystemProviderInstance } from "../workspace/file-system-provider";
import { commandCreateConfig, commandResolveInclude } from "./commands";
import { Commands } from "./constants";
export { PluginConfiguration } from "./constants";

/**
* Notification sent to the LS when the workspace's plugin configuration changes.
Expand All @@ -52,7 +54,6 @@ export const WorkspaceDidChangePlipluginConfigNotification =
export function startLanguageServer(connection: Connection): void {
const compilationUnitHandler = new CompilationUnitHandler();
compilationUnitHandler.listen(connection);
const APPLY_QUICK_FIXES = "pli.applyIncludeFix";

connection.onInitialize(async (params) => {
// init the plugin config provider in reverse folder order, last plugin config encountered will take precedence
Expand Down Expand Up @@ -82,7 +83,7 @@ export function startLanguageServer(connection: Connection): void {
referencesProvider: true,
codeActionProvider: true,
executeCommandProvider: {
commands: [APPLY_QUICK_FIXES],
commands: [Commands.RESOLVE_INCLUDE, Commands.CREATE_CONFIG],
},
documentHighlightProvider: true,
semanticTokensProvider: {
Expand Down Expand Up @@ -318,15 +319,13 @@ export function startLanguageServer(connection: Connection): void {
});

connection.onExecuteCommand(async (params) => {
if (params.command === APPLY_QUICK_FIXES) {
return Mutex.run(async () => {
const [uri, content] = params.arguments as string[];
try {
await FileSystemProviderInstance.writeFile(URI.parse(uri), content);
} catch (err) {
console.error("Failed to write proc_grps.json:", err);
}
});
switch (params.command) {
case Commands.RESOLVE_INCLUDE:
await commandResolveInclude(params);
break;
case Commands.CREATE_CONFIG:
await commandCreateConfig(params);
break;
}
});

Expand Down
42 changes: 42 additions & 0 deletions packages/language/src/language-server/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
/**
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/

export namespace PluginConfiguration {
export const PROGRAM_FILE_PATH = ".pliplugin/pgm_conf.json";
export const PROCESS_GROUP_FILE_PATH = ".pliplugin/proc_grps.json";
export const DEFAULT_PROGRAM_FILE_CONTENT = {
pgms: [
{
program: "",
pgroup: "default",
},
],
};
export const DEFAULT_PROCESS_GROUP_FILE_CONTENT = {
pgroups: [
{
name: "default",
"compiler-options": [],
libs: ["cpy", "inc"],
"include-extensions": [".pli", ".pl1", ".inc"],
"implicit-builtins": ["SUBSTR"],
"lsp-options": {
"check-margins": true,
},
},
],
};
}

export namespace Commands {
export const RESOLVE_INCLUDE = "pli.applyQuickFixResolveInclude";
export const CREATE_CONFIG = "pli.applyQuickFixCreateConfig";
}
24 changes: 24 additions & 0 deletions packages/language/src/language-server/lsp-codes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
/**
* This program and the accompanying materials are made available under the terms of the
* Eclipse Public License v2.0 which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-v20.html
*
* SPDX-License-Identifier: EPL-2.0
*
* Copyright Contributors to the Zowe Project.
*
*/

import { Severity } from "../language-server/types";
import { SimplePLICode } from "../validation/pli-codes";
Comment on lines +1 to +13
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggestion: Please put this file in the validation part of the package.


export const lspCodes = {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: Exported constants are usually either CamelCase or SNAKE_CASE.

Suggested change
export const lspCodes = {
export const LspCodes = {

IncludeResolution: {
MissingConfiguration: {
code: "LSPIR001",
severity: Severity.E,
message:
"Could not resolve include directive. Plugin configuration is missing",
} as SimplePLICode,
},
};
35 changes: 23 additions & 12 deletions packages/language/src/preprocessor/instruction-interpreter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { Diagnostic, diagnosticFromCode } from "../language-server/types";
import { PreprocessorTokens } from "./pli-preprocessor-tokens";
import { tokenMatcher } from "chevrotain";
import { PLICodes } from "../validation/pli-codes";
import { lspCodes } from "../language-server/lsp-codes";

interface Variable {
name: string;
Expand Down Expand Up @@ -2017,25 +2018,35 @@ async function runInclude(
): Promise<string | null> {
const uri = await resolveIncludeFileUri(item, context);

function failToResolve(error?: any): void {
async function failToResolve(error?: any): Promise<void> {
if (error) {
console.log("Failed to resolve include file:", error);
}
const diagnostic = diagnosticFromCode(
PLICodes.Severe.IBM3841I,
item.token,
item.fileName,
);
if (item.fileName)
diagnostic.data = {
unresolvedFile: item.fileName,
entryUri: context.entryUri.toString(),
};
let diagnostic: Diagnostic;
if (!context.unit.processGroup && !context.unit.programConfig) {
diagnostic = diagnosticFromCode(
lspCodes.IncludeResolution.MissingConfiguration,
item.token,
);
diagnostic.data = { entryUri: context.entryUri.toString() };
} else {
diagnostic = diagnosticFromCode(
PLICodes.Severe.IBM3841I,
item.token,
item.fileName,
);
if (item.fileName)
diagnostic.data = {
unresolvedFile: item.fileName,
entryUri: context.entryUri.toString(),
};
}

context.diagnostics.push(diagnostic);
}

if (!uri) {
failToResolve();
await failToResolve();
return null;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -172,10 +172,6 @@ interface SerializedProcessGroup {
* processing their contents, and making those settings available to the language server.
*/
export class PluginConfigurationProvider {
public static readonly PROGRAM_CONFIG_FILE = ".pliplugin/pgm_conf.json";
public static readonly PROCESS_GROUP_CONFIG_FILE =
".pliplugin/proc_grps.json";

/**
* Prebuilt list of glob patterns for library file matching.
*/
Expand Down Expand Up @@ -364,7 +360,9 @@ export class PluginConfigurationProvider {
// read all files in this lib path
// add any contained directories to the libs list, as well as the toProcess list
const libUri = UriUtils.joinPath(URI.parse(this.workspacePath), lib);
const entries = await FileSystemProviderInstance.readDir(libUri);
const entries = await FileSystemProviderInstance.readDir(
libUri,
).catch(() => []);
if (entries.length) {
for (const dirEntry of entries) {
const fileName = dirEntry.name;
Expand Down
Loading