Skip to content

Commit

Permalink
WIP Configurable folder excludes #344
Browse files Browse the repository at this point in the history
  • Loading branch information
dhuebner committed May 13, 2022
1 parent 3332da8 commit 9267428
Show file tree
Hide file tree
Showing 7 changed files with 102 additions and 16 deletions.
12 changes: 11 additions & 1 deletion packages/langium-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,17 @@
"fileMatch": "langium-config.json",
"url": "./data/langium-config-schema.json"
}
]
],
"configuration": {
"title": "Langium",
"properties": {
"langium.build.skipFolder": {
"type": "string",
"default": "node_modules, out",
"description": "Specifies the folders to exclude from traversing during initial build. You will need to reload your extension afterwards."
}
}
}
},
"activationEvents": [
"onLanguage:langium"
Expand Down
4 changes: 3 additions & 1 deletion packages/langium/src/default-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ import { DefaultDocumentValidator } from './validation/document-validator';
import { ValidationRegistry } from './validation/validation-registry';
import { DefaultAstNodeDescriptionProvider, DefaultReferenceDescriptionProvider } from './workspace/ast-descriptions';
import { DefaultAstNodeLocator } from './workspace/ast-node-locator';
import { DefaultConfigurationProvider } from './workspace/configuration';
import { DefaultDocumentBuilder } from './workspace/document-builder';
import { DefaultLangiumDocumentFactory, DefaultLangiumDocuments, DefaultTextDocumentFactory } from './workspace/documents';
import { NodeFileSystemProvider } from './workspace/file-system-provider';
Expand Down Expand Up @@ -117,7 +118,8 @@ export function createDefaultSharedModule(context: DefaultSharedModuleContext =
TextDocumentFactory: (services) => new DefaultTextDocumentFactory(services),
IndexManager: (services) => new DefaultIndexManager(services),
WorkspaceManager: (services) => new DefaultWorkspaceManager(services),
FileSystemProvider: () => new NodeFileSystemProvider()
FileSystemProvider: () => new NodeFileSystemProvider(),
ConfigurationProvider: () => new DefaultConfigurationProvider()
}
};
}
1 change: 1 addition & 0 deletions packages/langium/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -42,3 +42,4 @@ export * from './workspace/document-builder';
export * from './workspace/documents';
export * from './workspace/index-manager';
export * from './workspace/workspace-manager';
export * from './workspace/configuration';
35 changes: 28 additions & 7 deletions packages/langium/src/lsp/language-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
******************************************************************************/

import {
AbstractCancellationTokenSource, CancellationToken, Connection, FileChangeType, HandlerResult, InitializeResult,
LSPErrorCodes, RequestHandler, ResponseError, ServerRequestHandler, TextDocumentIdentifier, TextDocumentSyncKind
AbstractCancellationTokenSource, CancellationToken, Connection, DidChangeConfigurationNotification, FileChangeType, HandlerResult, InitializeResult,
LSPErrorCodes, RequestHandler, ResponseError, ServerRequestHandler, TextDocumentIdentifier, TextDocumentSyncKind, WorkspaceFolder
} from 'vscode-languageserver';
import { URI } from 'vscode-uri';
import { LangiumServices, LangiumSharedServices } from '../services';
Expand All @@ -21,7 +21,11 @@ export function startLanguageServer(services: LangiumSharedServices): void {
throw new Error('Starting a language server requires the languageServer.Connection service to be set.');
}

let wsFolders: WorkspaceFolder[] | null;
let wsConfiguration = false;
connection.onInitialize(async params => {
wsFolders = params.workspaceFolders;
wsConfiguration = params.capabilities.workspace?.configuration??false;
const result: InitializeResult = {
capabilities: {
workspace: {
Expand All @@ -46,17 +50,34 @@ export function startLanguageServer(services: LangiumSharedServices): void {
: undefined
}
};

return result;
});
connection.onInitialized(async () => {
connection.client.register(DidChangeConfigurationNotification.type, {
section: languages.map(lang => lang.LanguageMetaData.languageId)
});
try {
if (params.workspaceFolders) {
await services.workspace.WorkspaceManager.initializeWorkspace(params.workspaceFolders);
if (wsConfiguration) {
languages.map(lang => lang.LanguageMetaData.languageId).forEach(async section => {
// TODO consider sending one getConfiguration(sections[]) request
const configs = await connection.workspace.getConfiguration(section);
services.workspace.ConfigurationProvider.updateConfiguration(section, configs);
});
if (wsFolders) {
await services.workspace.WorkspaceManager.initializeWorkspace(wsFolders);
}
}
} catch (err) {
console.error(err);
}
return result;
});

connection.onDidChangeConfiguration(change => {
if (change.settings) {
Object.keys(change.settings).forEach(section => {
services.workspace.ConfigurationProvider.updateConfiguration(section, change.settings[section]);
});
}
});
addDocumentsHandler(connection, services);
addDiagnosticsHandler(connection, services);
addCompletionHandler(connection, services);
Expand Down
2 changes: 2 additions & 0 deletions packages/langium/src/services.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ import type { DocumentValidator } from './validation/document-validator';
import type { ValidationRegistry } from './validation/validation-registry';
import type { AstNodeDescriptionProvider, ReferenceDescriptionProvider } from './workspace/ast-descriptions';
import type { AstNodeLocator } from './workspace/ast-node-locator';
import { ConfigurationProvider } from './workspace/configuration';
import type { DocumentBuilder } from './workspace/document-builder';
import type { LangiumDocumentFactory, LangiumDocuments, TextDocumentFactory } from './workspace/documents';
import type { FileSystemProvider } from './workspace/file-system-provider';
Expand Down Expand Up @@ -137,6 +138,7 @@ export type LangiumDefaultSharedServices = {
TextDocumentFactory: TextDocumentFactory
WorkspaceManager: WorkspaceManager
FileSystemProvider: FileSystemProvider
ConfigurationProvider: ConfigurationProvider
}
}

Expand Down
29 changes: 29 additions & 0 deletions packages/langium/src/workspace/configuration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
/******************************************************************************
* Copyright 2022 TypeFox GmbH
* This program and the accompanying materials are made available under the
* terms of the MIT License, which is available in the project root.
******************************************************************************/

/* eslint-disable @typescript-eslint/no-explicit-any */

export interface ConfigurationProvider {
getConfiguration(section: string, configuration: string): any;
updateConfiguration(section: string, configuration: any): void;
}

export class DefaultConfigurationProvider implements ConfigurationProvider {

protected settings: Record<string, Record<string, any>> = {};
protected workspaceConfigurationSupported = false;

updateConfiguration(section: string, configuration: any): void {
this.settings[section] = configuration;
}

getConfiguration(section: string, configuration: string): any {
if(!this.settings[section]) {
this.settings[section] = {};
}
return this.settings[section][configuration];
}
}
35 changes: 28 additions & 7 deletions packages/langium/src/workspace/workspace-manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { WorkspaceFolder } from 'vscode-languageserver';
import { URI, Utils } from 'vscode-uri';
import { ServiceRegistry } from '../service-registry';
import { LangiumSharedServices } from '../services';
import { ConfigurationProvider } from './configuration';
import { DocumentBuilder } from './document-builder';
import { LangiumDocument, LangiumDocuments } from './documents';
import { FileSystemNode, FileSystemProvider } from './file-system-provider';
Expand All @@ -30,18 +31,23 @@ export interface WorkspaceManager {

}

interface WorkspaceManagerConf {
skipFolders: string
}
export class DefaultWorkspaceManager implements WorkspaceManager {

protected readonly serviceRegistry: ServiceRegistry;
protected readonly langiumDocuments: LangiumDocuments;
protected readonly documentBuilder: DocumentBuilder;
protected readonly fileSystemProvider: FileSystemProvider;
protected readonly configurationProvider: ConfigurationProvider;

constructor(services: LangiumSharedServices) {
this.serviceRegistry = services.ServiceRegistry;
this.langiumDocuments = services.workspace.LangiumDocuments;
this.documentBuilder = services.workspace.DocumentBuilder;
this.fileSystemProvider = services.workspace.FileSystemProvider;
this.configurationProvider = services.workspace.ConfigurationProvider;
}

async initializeWorkspace(folders: WorkspaceFolder[]): Promise<void> {
Expand All @@ -53,9 +59,11 @@ export class DefaultWorkspaceManager implements WorkspaceManager {
this.langiumDocuments.addDocument(document);
}
};

const excludedFolders: Set<string> = new Set(this.serviceRegistry.all.map(language => this.excludedFolders(language.LanguageMetaData.languageId)).flat());
await Promise.all(
folders.map(wf => this.getRootFolder(wf))
.map(async rf => this.traverseFolder(rf, fileExtensions, collector))
.map(async rf => this.traverseFolder(rf, fileExtensions, excludedFolders, collector))
);
await this.loadAdditionalDocuments(folders, collector);
await this.documentBuilder.build(documents);
Expand Down Expand Up @@ -83,12 +91,12 @@ export class DefaultWorkspaceManager implements WorkspaceManager {
* Traverse the file system folder identified by the given URI and its subfolders. All
* contained files that match the file extensions are added to the collector.
*/
protected async traverseFolder(folderPath: URI, fileExtensions: string[], collector: (document: LangiumDocument) => void): Promise<void> {
protected async traverseFolder(folderPath: URI, fileExtensions: string[], excludedFolders: Set<string>, collector: (document: LangiumDocument) => void): Promise<void> {
const content = await this.fileSystemProvider.readDirectory(folderPath);
for (const entry of content) {
if (this.includeEntry(entry, fileExtensions)) {
if (this.includeEntry(entry, fileExtensions, excludedFolders)) {
if (entry.isDirectory) {
await this.traverseFolder(entry.uri, fileExtensions, collector);
await this.traverseFolder(entry.uri, fileExtensions, excludedFolders, collector);
} else if (entry.isFile) {
const document = this.langiumDocuments.getOrCreateDocument(entry.uri);
collector(document);
Expand All @@ -98,15 +106,28 @@ export class DefaultWorkspaceManager implements WorkspaceManager {
}

/**
* Determine whether the given folder entry shall be included while indexing the workspace.
* @returns Folder names to be excluded from building/indexing
*/
protected excludedFolders(languageId: string): string[] {
const configured = <WorkspaceManagerConf>this.configurationProvider.getConfiguration(languageId, 'build');
return configured ? configured?.skipFolders?.split(',').map(folder => folder.trim()) : ['node_modules', 'out'];
}

/**
* Determine whether the given path entry shall be included while indexing the workspace.
*/
protected includeEntry(entry: FileSystemNode, fileExtensions: string[]): boolean {
protected includeEntry(entry: FileSystemNode, fileExtensions: string[], excludes: Set<string>): boolean {
const name = Utils.basename(entry.uri);
if (name.startsWith('.')) {
return false;
}
if (entry.isDirectory) {
return name !== 'node_modules' && name !== 'out';
for (const exclude of excludes) {
if(name === exclude) {
return false;
}
}
return true;
} else if (entry.isFile) {
return fileExtensions.includes(path.extname(name));
}
Expand Down

0 comments on commit 9267428

Please sign in to comment.