-
Notifications
You must be signed in to change notification settings - Fork 0
/
documentManager.ts
159 lines (136 loc) · 4.14 KB
/
documentManager.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
"use strict";
import { isEqual as _isEqual } from "lodash-es";
import {
Connection,
Disposable,
Emitter,
Event,
TextDocument,
TextDocumentChangeEvent,
TextDocuments
} from "vscode-languageserver";
import { URI } from "vscode-uri";
import { Logger } from "./logger";
import { Disposables } from "./system";
const escapedRegex = /(^.*?:\/\/\/)([a-z])%3A(\/.*$)/;
const unescapedRegex = /(^.*?:\/\/\/)([a-zA-Z]):(\/.*$)/;
export class DocumentManager implements Disposable {
private _onDidChangeContent = new Emitter<TextDocumentChangeEvent>();
get onDidChangeContent(): Event<TextDocumentChangeEvent> {
return this._onDidChangeContent.event;
}
private _onDidSave = new Emitter<TextDocumentChangeEvent>();
get onDidSave(): Event<TextDocumentChangeEvent> {
return this._onDidSave.event;
}
private _onDidOpen = new Emitter<TextDocumentChangeEvent>();
get onDidOpen(): Event<TextDocumentChangeEvent> {
return this._onDidOpen.event;
}
private _onDidClose = new Emitter<TextDocumentChangeEvent>();
get onDidClose(): Event<TextDocumentChangeEvent> {
return this._onDidClose.event;
}
private readonly _disposable: Disposable;
private readonly _isWindows: boolean;
private readonly _normalizedUriLookup = new Map<string, string>();
constructor(private readonly _documents: TextDocuments, connection: Connection) {
this._isWindows = process.platform === "win32";
this._disposable = Disposables.from(
this._documents.onDidChangeContent(async e => {
this._onDidChangeContent.fire(e);
}),
this._documents.onDidSave(e => {
Logger.log(`Document saved: ${e.document.uri}`);
this._onDidSave.fire(e);
}),
this._documents.onDidOpen(e => {
Logger.log(`Document opened: ${e.document.uri}`);
this._onDidOpen.fire(e);
}),
this._documents.onDidClose(e => {
Logger.log(`Document closed: ${e.document.uri}`);
this._onDidClose.fire(e);
})
);
this._documents.listen(connection);
}
dispose() {
this._disposable && this._disposable.dispose();
}
get(uri: string): TextDocument | undefined {
const key = this._normalizedUriLookup.get(uri);
if (key !== undefined) {
return this._documents.get(key);
}
let doc = this._documents.get(uri);
if (doc !== undefined) return doc;
const decodedUri = URI.parse(uri).toString(true);
const encodedSpacesUri = decodedUri.replace(/ /, "%20");
doc = this._documents.get(decodedUri) || this._documents.get(encodedSpacesUri);
if (doc !== undefined) {
this._normalizedUriLookup.set(uri, doc.uri);
}
if (doc || !this._isWindows) {
return doc;
}
// If we are on windows we have to do some drive letter manipulation to support different editor using different uri formatting
let match = unescapedRegex.exec(uri);
if (match != null) {
const escapedUri = uri.replace(unescapedRegex, function(
_,
start: string,
drive: string,
end: string
) {
return `${start}${drive.toLowerCase()}%3A${end}`;
});
doc = this._documents.get(escapedUri);
if (doc !== undefined) {
this._normalizedUriLookup.set(uri, doc.uri);
}
return doc;
}
match = unescapedRegex.exec(encodedSpacesUri);
if (match != null) {
const upperCaseDrive = encodedSpacesUri.replace(unescapedRegex, function(
_,
start: string,
drive: string,
end: string
) {
return `${start}${drive.toUpperCase()}:${end}`;
});
doc = this._documents.get(upperCaseDrive);
if (doc !== undefined) {
this._normalizedUriLookup.set(uri, doc.uri);
}
return doc;
}
match = escapedRegex.exec(uri);
if (match != null) {
let unescapedUri = uri.replace(escapedRegex, function(
_,
start: string,
drive: string,
end: string
) {
return `${start}${drive.toUpperCase()}:${end}`;
});
doc = this._documents.get(unescapedUri);
if (doc !== undefined) {
this._normalizedUriLookup.set(uri, doc.uri);
return doc;
}
unescapedUri = uri.replace(escapedRegex, function(start, drive: string, end) {
return `${start}${drive.toLowerCase()}:${end}`;
});
doc = this._documents.get(unescapedUri);
if (doc !== undefined) {
this._normalizedUriLookup.set(uri, doc.uri);
}
return doc;
}
return undefined;
}
}