Skip to content

Commit 377e8d5

Browse files
committed
Add simple document management for Html documents
1 parent 7d02132 commit 377e8d5

File tree

3 files changed

+191
-0
lines changed

3 files changed

+191
-0
lines changed
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import { getUriPath } from '../../razor/src/uriPaths';
8+
9+
export class HtmlDocument {
10+
public readonly path: string;
11+
private content = '';
12+
13+
public constructor(public readonly uri: vscode.Uri) {
14+
this.path = getUriPath(uri);
15+
}
16+
17+
public getContent() {
18+
return this.content;
19+
}
20+
21+
public setContent(content: string) {
22+
this.content = content;
23+
}
24+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import { HtmlDocumentManager } from './htmlDocumentManager';
8+
import { RazorLogger } from '../../razor/src/razorLogger';
9+
import { getUriPath } from '../../razor/src/uriPaths';
10+
11+
export class HtmlDocumentContentProvider implements vscode.TextDocumentContentProvider {
12+
public static readonly scheme = 'razor-html';
13+
14+
private readonly onDidChangeEmitter: vscode.EventEmitter<vscode.Uri> = new vscode.EventEmitter<vscode.Uri>();
15+
16+
constructor(private readonly documentManager: HtmlDocumentManager, private readonly logger: RazorLogger) {}
17+
18+
public get onDidChange() {
19+
return this.onDidChangeEmitter.event;
20+
}
21+
22+
public fireDidChange(uri: vscode.Uri) {
23+
this.onDidChangeEmitter.fire(uri);
24+
}
25+
26+
public provideTextDocumentContent(uri: vscode.Uri) {
27+
const document = this.findDocument(uri);
28+
if (!document) {
29+
// Document was removed from the document manager, meaning there's no more content for this
30+
// file. Report an empty document.
31+
this.logger.logVerbose(
32+
`Could not find document '${getUriPath(
33+
uri
34+
)}' when updating the HTML buffer. This typically happens when a document is removed.`
35+
);
36+
return '';
37+
}
38+
39+
return document.getContent();
40+
}
41+
42+
private findDocument(uri: vscode.Uri) {
43+
const projectedPath = getUriPath(uri);
44+
45+
return this.documentManager.documents.find(
46+
(document) => document.path.localeCompare(projectedPath, undefined, { sensitivity: 'base' }) === 0
47+
);
48+
}
49+
}
Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
6+
import * as vscode from 'vscode';
7+
import { RazorLogger } from '../../razor/src/razorLogger';
8+
import { PlatformInformation } from '../../shared/platform';
9+
import { getUriPath } from '../../razor/src/uriPaths';
10+
import { virtualHtmlSuffix } from '../../razor/src/razorConventions';
11+
import { HtmlDocumentContentProvider } from './htmlDocumentContentProvider';
12+
import { HtmlDocument } from './htmlDocument';
13+
14+
export class HtmlDocumentManager {
15+
private readonly htmlDocuments: { [hostDocumentPath: string]: HtmlDocument } = {};
16+
private readonly contentProvider: HtmlDocumentContentProvider;
17+
18+
constructor(private readonly platformInfo: PlatformInformation, private readonly logger: RazorLogger) {
19+
this.contentProvider = new HtmlDocumentContentProvider(this, this.logger);
20+
}
21+
22+
public get documents() {
23+
return Object.values(this.htmlDocuments);
24+
}
25+
26+
public register() {
27+
const didCloseRegistration = vscode.workspace.onDidCloseTextDocument(async (document) => {
28+
if (document.languageId !== 'html') {
29+
return;
30+
}
31+
32+
await this.closeDocument(document.uri);
33+
});
34+
35+
const providerRegistration = vscode.workspace.registerTextDocumentContentProvider(
36+
HtmlDocumentContentProvider.scheme,
37+
this.contentProvider
38+
);
39+
40+
return vscode.Disposable.from(didCloseRegistration, providerRegistration);
41+
}
42+
43+
public async updateDocumentText(uri: vscode.Uri, text: string) {
44+
const document = await this.getDocument(uri);
45+
46+
this.logger.logVerbose(`New content for '${uri}', updating '${document.path}'.`);
47+
48+
document.setContent(text);
49+
50+
this.contentProvider.fireDidChange(document.uri);
51+
}
52+
53+
private async closeDocument(uri: vscode.Uri) {
54+
const document = await this.getDocument(uri);
55+
56+
if (document) {
57+
this.logger.logVerbose(`Document '${document.uri}' was closed. Removing from the document manager.`);
58+
59+
delete this.htmlDocuments[document.path];
60+
}
61+
}
62+
63+
public async getDocument(uri: vscode.Uri): Promise<HtmlDocument> {
64+
let document = this.findDocument(uri);
65+
66+
// This might happen in the case that a file is opened outside the workspace
67+
if (!document) {
68+
this.logger.logMessage(
69+
`File '${uri}' didn't exist in the Razor document list. This is likely because it's from outside the workspace.`
70+
);
71+
document = this.addDocument(uri);
72+
}
73+
74+
await vscode.workspace.openTextDocument(document.uri);
75+
76+
return document!;
77+
}
78+
79+
private addDocument(uri: vscode.Uri): HtmlDocument {
80+
let document = this.findDocument(uri);
81+
if (document) {
82+
this.logger.logMessage(`Skipping document creation for '${document.path}' because it already exists.`);
83+
return document;
84+
}
85+
86+
document = this.createDocument(uri);
87+
this.htmlDocuments[document.path] = document;
88+
89+
return document;
90+
}
91+
92+
private findDocument(uri: vscode.Uri): HtmlDocument | undefined {
93+
let path = getUriPath(uri);
94+
95+
// We might be passed a Razor document Uri, but we store and manage Html projected documents.
96+
if (uri.scheme !== HtmlDocumentContentProvider.scheme) {
97+
path = `${path}${virtualHtmlSuffix}`;
98+
}
99+
100+
if (this.platformInfo.isLinux()) {
101+
return this.htmlDocuments[path];
102+
}
103+
104+
return Object.values(this.htmlDocuments).find(
105+
(document) => document.path.localeCompare(path, undefined, { sensitivity: 'base' }) === 0
106+
);
107+
}
108+
109+
private createDocument(uri: vscode.Uri) {
110+
uri = uri.with({
111+
scheme: HtmlDocumentContentProvider.scheme,
112+
path: `${uri.path}${virtualHtmlSuffix}`,
113+
});
114+
const projectedDocument = new HtmlDocument(uri);
115+
116+
return projectedDocument;
117+
}
118+
}

0 commit comments

Comments
 (0)