Skip to content
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
44 changes: 28 additions & 16 deletions src/LanguageServer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,14 @@ import { createVisitor, WalkMode } from './astUtils/visitors';
import { tempDir, rootDir } from './testHelpers.spec';
import { URI } from 'vscode-uri';
import { BusyStatusTracker } from './BusyStatusTracker';
import type { BscFile, WorkspaceConfigWithExtras } from '.';
import type { BscFile } from './interfaces';
import type { Project } from './lsp/Project';
import { LogLevel, Logger, createLogger } from './logging';
import { DiagnosticMessages } from './DiagnosticMessages';
import { standardizePath } from 'roku-deploy';
import undent from 'undent';
import { ProjectManager } from './lsp/ProjectManager';
import type { WorkspaceConfig } from './lsp/ProjectManager';

const sinon = createSandbox();

Expand Down Expand Up @@ -167,7 +168,7 @@ describe('LanguageServer', () => {
});

describe('onDidChangeConfiguration', () => {
async function doTest(startingConfigs: WorkspaceConfigWithExtras[], endingConfigs: WorkspaceConfigWithExtras[]) {
async function doTest(startingConfigs: WorkspaceConfig[], endingConfigs: WorkspaceConfig[]) {
(server as any)['connection'] = connection;
server['workspaceConfigsCache'] = new Map(startingConfigs.map(x => [x.workspaceFolder, x]));

Expand All @@ -188,15 +189,17 @@ describe('LanguageServer', () => {
await doTest([{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: workspacePath,
excludePatterns: []
}], [{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: workspacePath,
Expand All @@ -210,7 +213,8 @@ describe('LanguageServer', () => {
await doTest([], [{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: workspacePath,
Expand All @@ -224,23 +228,26 @@ describe('LanguageServer', () => {
await doTest([{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: workspacePath,
excludePatterns: []
}, {
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: s`${tempDir}/project2`,
excludePatterns: []
}], [{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: workspacePath,
Expand All @@ -254,15 +261,17 @@ describe('LanguageServer', () => {
await doTest([{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'trace'
},
workspaceFolder: workspacePath,
excludePatterns: []
}], [{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: workspacePath,
Expand Down Expand Up @@ -649,18 +658,19 @@ describe('LanguageServer', () => {
});

describe('rebuildPathFilterer', () => {
let workspaceConfigs: WorkspaceConfigWithExtras[] = [];
let workspaceConfigs: WorkspaceConfig[] = [];
beforeEach(() => {
workspaceConfigs = [
{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: workspacePath,
excludePatterns: []
} as WorkspaceConfigWithExtras
}
];
server['connection'] = connection as any;
sinon.stub(server as any, 'getWorkspaceConfigs').callsFake(() => Promise.resolve(workspaceConfigs));
Expand Down Expand Up @@ -736,20 +746,22 @@ describe('LanguageServer', () => {
workspaceConfigs = [{
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: s`${tempDir}/flavor1`,
excludePatterns: []
}, {
bsconfigPath: undefined,
languageServer: {
enableThreading: true,
enableThreading: false,
enableDiscovery: true,
logLevel: 'info'
},
workspaceFolder: s`${tempDir}/flavor2`,
excludePatterns: []
}] as WorkspaceConfigWithExtras[];
}];
fsExtra.outputFileSync(s`${workspaceConfigs[0].workspaceFolder}/.gitignore`, undent`
dist/
`);
Expand Down
20 changes: 9 additions & 11 deletions src/LanguageServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ export class LanguageServer {
* The default threading setting for the language server. Can be overridden by per-workspace settings
*/
public static enableThreadingDefault = true;
/**
* The default project discovery setting for the language server. Can be overridden by per-workspace settings
*/
public static enableDiscoveryDefault = true;
/**
* The language server protocol connection, used to send and receive all requests and responses
*/
Expand Down Expand Up @@ -417,7 +421,7 @@ export class LanguageServer {
* Get a list of workspaces, and their configurations.
* Get only the settings for the workspace that are relevant to the language server. We do this so we can cache this object for use in change detection in the future.
*/
private async getWorkspaceConfigs(): Promise<WorkspaceConfigWithExtras[]> {
private async getWorkspaceConfigs(): Promise<WorkspaceConfig[]> {
//get all workspace folders (we'll use these to get settings)
let workspaces = await Promise.all(
(await this.connection.workspace.getWorkspaceFolders() ?? []).map(async (x) => {
Expand All @@ -429,16 +433,17 @@ export class LanguageServer {
bsconfigPath: brightscriptConfig.configFile,
languageServer: {
enableThreading: brightscriptConfig.languageServer?.enableThreading ?? LanguageServer.enableThreadingDefault,
enableDiscovery: brightscriptConfig.languageServer?.enableDiscovery ?? LanguageServer.enableDiscoveryDefault,
logLevel: brightscriptConfig?.languageServer?.logLevel
}

} as WorkspaceConfigWithExtras;
};
})
);
return workspaces;
}

private workspaceConfigsCache = new Map<string, WorkspaceConfigWithExtras>();
private workspaceConfigsCache = new Map<string, WorkspaceConfig>();

@AddStackToErrorMessage
public async onDidChangeConfiguration(args: DidChangeConfigurationParams) {
Expand Down Expand Up @@ -795,6 +800,7 @@ interface BrightScriptClientConfiguration {
configFile: string;
languageServer: {
enableThreading: boolean;
enableDiscovery: boolean;
logLevel: LogLevel | string;
};
}
Expand All @@ -805,11 +811,3 @@ function logAndIgnoreError(error: Error) {
}
console.error(error);
}

export type WorkspaceConfigWithExtras = WorkspaceConfig & {
bsconfigPath: string;
languageServer: {
enableThreading: boolean;
logLevel: LogLevel | string | undefined;
};
};
52 changes: 34 additions & 18 deletions src/bscPlugin/validation/BrsFileValidator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,17 +52,23 @@ export class BrsFileValidator {
this.validateEnumDeclaration(node);

//register this enum declaration
node.parent.getSymbolTable()?.addSymbol(node.tokens.name.text, node.tokens.name.range, DynamicType.instance);
if (node.tokens.name) {
node.parent.getSymbolTable()?.addSymbol(node.tokens.name.text, node.tokens.name.range, DynamicType.instance);
}
},
ClassStatement: (node) => {
this.validateDeclarationLocations(node, 'class', () => util.createBoundingRange(node.classKeyword, node.name));

//register this class
node.parent.getSymbolTable()?.addSymbol(node.name.text, node.name.range, DynamicType.instance);
if (node.name) {
node.parent.getSymbolTable()?.addSymbol(node.name.text, node.name.range, DynamicType.instance);
}
},
AssignmentStatement: (node) => {
//register this variable
node.parent.getSymbolTable()?.addSymbol(node.name.text, node.name.range, DynamicType.instance);
if (node.name) {
node.parent.getSymbolTable()?.addSymbol(node.name.text, node.name.range, DynamicType.instance);
}
},
DottedSetStatement: (node) => {
this.validateNoOptionalChainingInVarSet(node, [node.obj]);
Expand All @@ -77,11 +83,13 @@ export class BrsFileValidator {
NamespaceStatement: (node) => {
this.validateDeclarationLocations(node, 'namespace', () => util.createBoundingRange(node.keyword, node.nameExpression));

node.parent.getSymbolTable().addSymbol(
node.name.split('.')[0],
node.nameExpression.range,
DynamicType.instance
);
if (node.name) {
node.parent.getSymbolTable().addSymbol(
node.name.split('.')[0],
node.nameExpression.range,
DynamicType.instance
);
}
},
FunctionStatement: (node) => {
this.validateDeclarationLocations(node, 'function', () => util.createBoundingRange(node.func.functionType, node.name));
Expand All @@ -101,11 +109,13 @@ export class BrsFileValidator {
const funcType = node.func.getFunctionType();
funcType.setName(transpiledNamespaceFunctionName);

this.event.file.parser.ast.symbolTable.addSymbol(
transpiledNamespaceFunctionName,
node.name.range,
funcType
);
if (node.name) {
this.event.file.parser.ast.symbolTable.addSymbol(
transpiledNamespaceFunctionName,
node.name.range,
funcType
);
}
}
},
FunctionExpression: (node) => {
Expand All @@ -115,17 +125,23 @@ export class BrsFileValidator {
this.validateFunctionParameterCount(node);
},
FunctionParameterExpression: (node) => {
const paramName = node.name?.text;
const symbolTable = node.getSymbolTable();
symbolTable?.addSymbol(paramName, node.name.range, node.type);
if (node.name) {
const paramName = node.name.text;
const symbolTable = node.getSymbolTable();
symbolTable?.addSymbol(paramName, node.name.range, node.type);
}
},
InterfaceStatement: (node) => {
this.validateDeclarationLocations(node, 'interface', () => util.createBoundingRange(node.tokens.interface, node.tokens.name));
node.parent?.getSymbolTable()?.addSymbol(node.tokens.name.text, node.tokens.name.range, new InterfaceType(new Map()));
if (node.tokens.name) {
node.parent?.getSymbolTable()?.addSymbol(node.tokens.name.text, node.tokens.name.range, new InterfaceType(new Map()));
}
},
ConstStatement: (node) => {
this.validateDeclarationLocations(node, 'const', () => util.createBoundingRange(node.tokens.const, node.tokens.name));
node.parent.getSymbolTable().addSymbol(node.tokens.name.text, node.tokens.name.range, DynamicType.instance);
if (node.tokens.name) {
node.parent.getSymbolTable().addSymbol(node.tokens.name.text, node.tokens.name.range, DynamicType.instance);
}
},
CatchStatement: (node) => {
node.parent.getSymbolTable().addSymbol(node.exceptionVariable.text, node.exceptionVariable.range, DynamicType.instance);
Expand Down
Loading