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

Member resolves, IFS resolves and local includePath support #225

Merged
merged 19 commits into from
Aug 14, 2023
Merged
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
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"outFiles": ["${workspaceRoot}/out/**/*.js"],
"sourceMaps": true,
"sourceMapPathOverrides": {
"webpack://client/./*": "${workspaceFolder}/extension//client/*"
"webpack://client/./*": "${workspaceFolder}/extension/client/*"
},
"preLaunchTask": {
"type": "npm",
Expand Down
2 changes: 1 addition & 1 deletion extension/client/src/extension.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,8 @@ export function activate(context: ExtensionContext) {
{ language: 'rpgle' },
],
synchronize: {
// Notify the server about file changes to '.clientrc files contained in the workspace
fileEvents: [
workspace.createFileSystemWatcher('**/iproj.json'),
workspace.createFileSystemWatcher('**/rpglint.json'),
workspace.createFileSystemWatcher(projectFilesGlob),
]
Expand Down
34 changes: 34 additions & 0 deletions extension/client/src/requests.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Uri, workspace, RelativePattern, commands } from 'vscode';
import { LanguageClient } from 'vscode-languageclient/node';
import {getInstance} from './base';
import { projectFilesGlob } from "./configuration";
import { IBMiMember } from '@halcyontech/vscode-ibmi-types';

let streamFileSupportChecked = false;
let streamFileSupported = false;
Expand Down Expand Up @@ -64,6 +65,39 @@ export default function buildRequestHandlers(client: LanguageClient) {
return;
});

/**
* Resolves member paths
*/
client.onRequest("memberResolve", async (parms: string[]): Promise<IBMiMember | undefined> => {
let memberName = parms[0], sourceFile = parms[1];

const instance = getInstance();

const config = instance?.getConfig();
const content = instance?.getContent();

const files = [config?.currentLibrary, ...config?.libraryList!]
.filter(l => l !== undefined)
.map(l => ({name: sourceFile, library: l!}));

const member = await content?.memberResolve(memberName.toUpperCase(), files);

return member;
});

client.onRequest("streamfileResolve", async (parms: any[]): Promise<string|undefined> => {
const base: string = parms[0];
const includePaths: string[] = parms[1];

const instance = getInstance();

const content = instance?.getContent();

const resolvedPath = await content?.streamfileResolve(base, includePaths);

return resolvedPath;
});

/**
* Gets the column information for a provided file
*/
Expand Down
13 changes: 13 additions & 0 deletions extension/server/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions extension/server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"vscode-uri": "^3.0.6"
},
"devDependencies": {
"@halcyontech/vscode-ibmi-types": "^1.9.1",
"@types/glob": "^8.0.0",
"webpack": "^5.24.3"
}
Expand Down
44 changes: 41 additions & 3 deletions extension/server/src/connection.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { readFile } from 'fs/promises';
import { IBMiMember } from '@halcyontech/vscode-ibmi-types';

import {
createConnection,
Expand All @@ -7,10 +7,9 @@ import {
_Connection,
WorkspaceFolder
} from 'vscode-languageserver/node';
import { URI } from 'vscode-uri';


import { documents, findFile } from './providers';
import { includePath } from './providers/project';

// Create a connection for the server, using Node's IPC as a transport.
// Also include all preview / proposed LSP features.
Expand Down Expand Up @@ -52,6 +51,45 @@ export async function getFileRequest(uri: string) {
return;
}

export let resolvedMembers: {[baseUri: string]: {[fileKey: string]: IBMiMember}} = {};
export let resolvedStreamfiles: {[baseUri: string]: {[fileKey: string]: string}} = {};

export async function memberResolve(baseUri: string, member: string, file: string): Promise<IBMiMember|undefined> {
const fileKey = file+member;

if (resolvedMembers[baseUri] && resolvedMembers[baseUri][fileKey]) return resolvedMembers[baseUri][fileKey];

const resolvedMember = await connection.sendRequest("memberResolve", [member, file]) as IBMiMember|undefined;

if (resolvedMember) {
if (!resolvedMembers[baseUri]) resolvedMembers[baseUri] = {};
resolvedMembers[baseUri][fileKey] = resolvedMember;
}

return resolvedMember;
}

export async function streamfileResolve(baseUri: string, base: string): Promise<string|undefined> {
if (resolvedStreamfiles[baseUri] && resolvedStreamfiles[baseUri][base]) return resolvedStreamfiles[baseUri][base];

const workspace = await getWorkspaceFolder(baseUri);

if (workspace) {
const paths = includePath[workspace.uri];

if (paths && paths.length > 0) {
const resolvedPath = await connection.sendRequest("streamfileResolve", [base, paths]) as string|undefined;

if (resolvedPath) {
if (!resolvedStreamfiles[baseUri]) resolvedStreamfiles[baseUri] = {};
resolvedStreamfiles[baseUri][base] = resolvedPath;
}

return resolvedPath;
}
}
}

export function getWorkingDirectory(): Promise<string|undefined> {
return connection.sendRequest("getWorkingDirectory");
}
Expand Down
4 changes: 2 additions & 2 deletions extension/server/src/providers/hover.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import path = require('path');
import { Hover, HoverParams, MarkupKind, Range } from 'vscode-languageserver';
import { documents, getWordRangeAtPosition, parser } from '.';
import Parser from "../../../../language/parser";
import { URI } from 'vscode-uri';

export default async function hoverProvider(params: HoverParams): Promise<Hover|undefined> {
const currentPath = params.textDocument.uri;
Expand Down Expand Up @@ -96,7 +96,7 @@ export default async function hoverProvider(params: HoverParams): Promise<Hover|

if (includeDirective) {
const include = await parser.includeFileFetch(currentPath, includeDirective);
const displayName = include.uri ? path.basename(include.uri) : includeDirective;
const displayName = include.uri ? URI.parse(include.uri).path : includeDirective;

return {
contents: {
Expand Down
5 changes: 4 additions & 1 deletion extension/server/src/providers/linter/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import codeActionsProvider from './codeActions';
import documentFormattingProvider from './documentFormatting';

import * as Project from "../project";
import { connection, getFileRequest, getWorkingDirectory, validateUri, watchedFilesChangeEvent } from '../../connection';
import { connection, getFileRequest, getWorkingDirectory, resolvedMembers, resolvedStreamfiles, validateUri, watchedFilesChangeEvent } from '../../connection';
import { parseMemberUri } from '../../data';

export let jsonCache: { [uri: string]: string } = {};
Expand Down Expand Up @@ -72,6 +72,9 @@ export function initialise(connection: _Connection) {
boundLintConfig = {};
jsonCache = {}
}

resolvedMembers[uriString] = {};
resolvedStreamfiles[uriString] = {};
})
}

Expand Down
69 changes: 62 additions & 7 deletions extension/server/src/providers/project/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ import * as path from "path";
import { TextDocument } from 'vscode-languageserver-textdocument';
const projectFilesGlob = `**/*.{rpgle,sqlrpgle,rpgleinc}`;

export let includePath: {[workspaceUri: string]: string[]} = {};

export let isEnabled = false;
/**
* Assumes client has workspace
Expand All @@ -22,13 +24,24 @@ export async function initialise() {

watchedFilesChangeEvent.push((params: DidChangeWatchedFilesParams) => {
params.changes.forEach(fileEvent => {
const pathData = path.parse(fileEvent.uri);
const ext = pathData.ext.toLowerCase();

switch (fileEvent.type) {
case FileChangeType.Created:
case FileChangeType.Changed:
loadLocalFile(fileEvent.uri);

if (fileEvent.uri.toLowerCase().endsWith(`.rpgleinc`)) {
currentIncludes = [];
switch (ext) {
case `.rpgleinc`:
case `.rpgleh`:
loadLocalFile(fileEvent.uri);

currentIncludes = [];
break;
case `.json`:
if (pathData.base === `iproj.json`) {
updateIProj(fileEvent.uri);
}
break;
}
break;

Expand All @@ -47,8 +60,6 @@ export async function initialise() {
async function loadWorkspace() {
const workspaces = await connection.workspace.getWorkspaceFolders();

console.log(workspaces);

if (workspaces) {
let uris: string[] = [];

Expand All @@ -67,7 +78,23 @@ async function loadWorkspace() {
uris.push(...files.map(file => URI.from({
scheme: `file`,
path: file
}).toString()))
}).toString()));

const iprojFiles = glob.sync(`**/iproj.json`, {
cwd: folderPath,
absolute: true,
nocase: true,
});

if (iprojFiles.length > 0) {
const base = iprojFiles[0];
const iprojUri = URI.from({
scheme: `file`,
path: base
}).toString();

updateIProj(iprojUri);
}
}));

if (uris.length < 1000) {
Expand All @@ -81,6 +108,34 @@ async function loadWorkspace() {
}
}

async function updateIProj(uri: string) {
const workspace = await getWorkspaceFolder(uri);
if (workspace) {
const document = await getTextDoc(uri);
const content = document?.getText();

if (content) {
try {
const asJson = JSON.parse(content);
if (asJson.includePath && Array.isArray(asJson.includePath)) {
const includeArray: any[] = asJson.includePath;

const invalid = includeArray.some(v => typeof v !== `string`);

if (!invalid) {
includePath[workspace.uri] = asJson.includePath;
} else {
console.log(`${uri} -> 'includePath' is not a valid string array.`);
}
}

} catch (e) {
console.log(`Unable to parse JSON in ${uri}.`);
}
}
}
}

async function loadLocalFile(uri: string) {
const document = await getTextDoc(uri);

Expand Down
Loading