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

Further reworks of the documents loading… #806

Merged
merged 1 commit into from Dec 9, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
59 changes: 27 additions & 32 deletions packages/langium/src/workspace/documents.ts
Expand Up @@ -156,6 +156,12 @@ export interface LangiumDocumentFactory {
*/
fromModel<T extends AstNode = AstNode>(model: T, uri: URI): LangiumDocument<T>;

/**
* Create a Langium document for the given URI. The document shall be fetched from the {@link TextDocuments}
* service if present, and loaded via the configured {@link FileSystemProvider} otherwise.
*/
create<T extends AstNode = AstNode>(uri: URI): LangiumDocument<T>
Copy link
Contributor Author

Choose a reason for hiding this comment

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

I removed the additional optional content parameter that was in here in my first draft.
IMO this justifies the presence of the 'from...' methods much better, the document builder needs just this, and everything below is just implementation detail of DefaultLangiumDocumentFactory.

@spoenemann @msujew Do you agree?

Copy link
Contributor

Choose a reason for hiding this comment

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

👍


/**
* Update the given document after changes in the corresponding textual representation.
* Method is called by the document builder after it has been requested to build an exisiting
Expand All @@ -179,30 +185,35 @@ export class DefaultLangiumDocumentFactory implements LangiumDocumentFactory {
}

fromTextDocument<T extends AstNode = AstNode>(textDocument: TextDocument, uri?: URI): LangiumDocument<T> {
return this.create<T>(textDocument, undefined, undefined, uri);
return this.create<T>(uri ?? URI.parse(textDocument.uri), textDocument);
}

fromString<T extends AstNode = AstNode>(text: string, uri: URI): LangiumDocument<T> {
return this.create<T>(undefined, text, undefined, uri);
return this.create<T>(uri, text);
}

fromModel<T extends AstNode = AstNode>(model: T, uri: URI): LangiumDocument<T> {
return this.create<T>(undefined, undefined, model, uri);
return this.create<T>(uri, { $model: model });
}

protected create<T extends AstNode>(textDocument: TextDocument | undefined, text: string | undefined, model: T | undefined, uri: URI | undefined): LangiumDocument<T> {
if (uri === undefined) {
uri = URI.parse(textDocument!.uri);
}
create<T extends AstNode = AstNode>(uri: URI, content?: string | TextDocument | { $model: T }): LangiumDocument<T> {
// if no document is given, check the textDocuments service first, it maintains documents being opened in an editor
content ??= this.textDocuments.get(uri.toString());
// if still no document is found try to load it from the file system
content ??= this.getContentFromFileSystem(uri);

if (typeof content === 'string') {
const parseResult = this.parse<T>(uri, content);
return this.createLangiumDocument<T>(parseResult, uri, undefined, content);

} else if ('$model' in content) {
const parseResult = { value: content.$model, parserErrors: [], lexerErrors: [] };
return this.createLangiumDocument<T>(parseResult, uri);

let parseResult: ParseResult<T>;
if (model === undefined) {
parseResult = this.parse<T>(uri, text ?? textDocument!.getText());
} else {
parseResult = { value: model, parserErrors: [], lexerErrors: [] };
const parseResult = this.parse<T>(uri, content.getText());
return this.createLangiumDocument(parseResult, uri, content);
}

return this.createLangiumDocument<T>(parseResult, uri, textDocument, text);
}

/**
Expand Down Expand Up @@ -244,7 +255,7 @@ export class DefaultLangiumDocumentFactory implements LangiumDocumentFactory {

update<T extends AstNode = AstNode>(document: Mutable<LangiumDocument<T>>): LangiumDocument<T> {
const textDocument = this.textDocuments.get(document.uri.toString());
const text = textDocument ? textDocument.getText() : this.getContent(document.uri);
const text = textDocument ? textDocument.getText() : this.getContentFromFileSystem(document.uri);

if (textDocument) {
Object.defineProperty(
Expand All @@ -267,8 +278,7 @@ export class DefaultLangiumDocumentFactory implements LangiumDocumentFactory {
return document;
}

/** Counterpart of {@link DefaultLangiumDocuments.getContent}. */
protected getContent(uri: URI): string {
protected getContentFromFileSystem(uri: URI): string {
return this.fileSystemProvider.readFileSync(uri);
}

Expand Down Expand Up @@ -336,15 +346,11 @@ export interface LangiumDocuments {

export class DefaultLangiumDocuments implements LangiumDocuments {

protected readonly textDocuments: TextDocuments<TextDocument>;
protected readonly fileSystemProvider: FileSystemProvider;
protected readonly langiumDocumentFactory: LangiumDocumentFactory;

protected readonly documentMap: Map<string, LangiumDocument> = new Map();

constructor(services: LangiumSharedServices) {
this.textDocuments = services.workspace.TextDocuments;
this.fileSystemProvider = services.workspace.FileSystemProvider;
this.langiumDocumentFactory = services.workspace.LangiumDocumentFactory;
}

Expand All @@ -367,22 +373,11 @@ export class DefaultLangiumDocuments implements LangiumDocuments {
// The document is already present in our map
return langiumDoc;
}
const textDoc = this.textDocuments.get(uriString);
if (textDoc) {
// The document is managed by the TextDocuments service, which means it is opened in the editor
langiumDoc = this.langiumDocumentFactory.fromTextDocument(textDoc, uri);
} else {
// Load the document from file
langiumDoc = this.langiumDocumentFactory.fromString(this.getContent(uri), uri);
}
langiumDoc = this.langiumDocumentFactory.create(uri);
this.documentMap.set(uriString, langiumDoc);
return langiumDoc;
}

protected getContent(uri: URI): string {
return this.fileSystemProvider.readFileSync(uri);
}

hasDocument(uri: URI): boolean {
return this.documentMap.has(uri.toString());
}
Expand Down