@spyglassmc/core 0.4.17 → 0.4.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/processor/completer/Completer.d.ts +4 -0
- package/lib/processor/completer/Completer.js +7 -0
- package/lib/processor/completer/builtin.js +4 -1
- package/lib/service/Downloader.js +3 -3
- package/lib/service/FileService.d.ts +1 -0
- package/lib/service/FileService.js +8 -3
- package/lib/service/Project.js +14 -0
- package/lib/source/Source.d.ts +4 -4
- package/lib/source/Source.js +12 -10
- package/package.json +1 -1
|
@@ -65,6 +65,10 @@ export declare namespace CompletionItem {
|
|
|
65
65
|
* Escape `$`, `\`, and `}` in `textToInsert`
|
|
66
66
|
*/
|
|
67
67
|
function escape(textToInsert: string): string;
|
|
68
|
+
/**
|
|
69
|
+
* Un-escape `$`, `\`, and `}` in `textToInsert`
|
|
70
|
+
*/
|
|
71
|
+
function unescape(textToInsert: string): string;
|
|
68
72
|
}
|
|
69
73
|
export declare class InsertTextBuilder {
|
|
70
74
|
#private;
|
|
@@ -35,6 +35,13 @@ export var CompletionItem;
|
|
|
35
35
|
return textToInsert.replace(/([\\$}])/g, '\\$1');
|
|
36
36
|
}
|
|
37
37
|
CompletionItem.escape = escape;
|
|
38
|
+
/**
|
|
39
|
+
* Un-escape `$`, `\`, and `}` in `textToInsert`
|
|
40
|
+
*/
|
|
41
|
+
function unescape(textToInsert) {
|
|
42
|
+
return textToInsert.replace(/\\([\\$}])/g, '$1');
|
|
43
|
+
}
|
|
44
|
+
CompletionItem.unescape = unescape;
|
|
38
45
|
})(CompletionItem || (CompletionItem = {}));
|
|
39
46
|
export class InsertTextBuilder {
|
|
40
47
|
#ans = '';
|
|
@@ -199,7 +199,10 @@ export function escapeString(value, quote) {
|
|
|
199
199
|
if (!quote) {
|
|
200
200
|
return value;
|
|
201
201
|
}
|
|
202
|
-
|
|
202
|
+
// Un-escape and then re-escape completion
|
|
203
|
+
value = CompletionItem.unescape(value);
|
|
204
|
+
value = value.replaceAll('\\', '\\\\').replaceAll(quote, '\\"');
|
|
205
|
+
return CompletionItem.escape(value);
|
|
203
206
|
}
|
|
204
207
|
export const symbol = (node, ctx) => {
|
|
205
208
|
const path = node.options.parentPath ?? [];
|
|
@@ -53,7 +53,7 @@ export class Downloader {
|
|
|
53
53
|
}
|
|
54
54
|
const deserializer = cache.deserializer ?? ((b) => b);
|
|
55
55
|
const ans = await transformer(deserializer(cachedBuffer));
|
|
56
|
-
this.logger.info(`[Downloader] [${id}] Skipped downloading thanks to cache ${cacheChecksum}`);
|
|
56
|
+
this.logger.info(`[Downloader] [${id}] Skipped downloading thanks to cache ${cacheChecksum} (${cachedBuffer.length} bytes)`);
|
|
57
57
|
return ans;
|
|
58
58
|
}
|
|
59
59
|
catch (e) {
|
|
@@ -103,7 +103,7 @@ export class Downloader {
|
|
|
103
103
|
this.logger.error(`[Downloader] [${id}] Caching file ${cacheUri}`, e);
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
|
-
this.logger.info(`[Downloader] [${id}] Downloaded from ${uri}`);
|
|
106
|
+
this.logger.info(`[Downloader] [${id}] Downloaded from ${uri} (${buffer.length} bytes)`);
|
|
107
107
|
return await transformer(buffer);
|
|
108
108
|
}
|
|
109
109
|
catch (e) {
|
|
@@ -113,7 +113,7 @@ export class Downloader {
|
|
|
113
113
|
const cachedBuffer = await fileUtil.readFile(this.externals, cacheUri);
|
|
114
114
|
const deserializer = cache.deserializer ?? ((b) => b);
|
|
115
115
|
const ans = await transformer(deserializer(cachedBuffer));
|
|
116
|
-
this.logger.warn(`[Downloader] [${id}] Fell back to cached file ${cacheUri}`);
|
|
116
|
+
this.logger.warn(`[Downloader] [${id}] Fell back to cached file ${cacheUri} (${cachedBuffer.length} bytes)`);
|
|
117
117
|
return ans;
|
|
118
118
|
}
|
|
119
119
|
catch (e) {
|
|
@@ -95,6 +95,7 @@ export declare class FileUriSupporter implements UriProtocolSupporter {
|
|
|
95
95
|
}
|
|
96
96
|
export declare class ArchiveUriSupporter implements UriProtocolSupporter {
|
|
97
97
|
private readonly externals;
|
|
98
|
+
private readonly logger;
|
|
98
99
|
private readonly entries;
|
|
99
100
|
static readonly Protocol = "archive:";
|
|
100
101
|
private static readonly SupportedArchiveExtnames;
|
|
@@ -154,6 +154,7 @@ export class FileUriSupporter {
|
|
|
154
154
|
}
|
|
155
155
|
export class ArchiveUriSupporter {
|
|
156
156
|
externals;
|
|
157
|
+
logger;
|
|
157
158
|
entries;
|
|
158
159
|
static Protocol = 'archive:';
|
|
159
160
|
static SupportedArchiveExtnames = ['.tar', '.tar.bz2', '.tar.gz', '.zip'];
|
|
@@ -161,8 +162,9 @@ export class ArchiveUriSupporter {
|
|
|
161
162
|
/**
|
|
162
163
|
* @param entries A map from archive names to unzipped entries.
|
|
163
164
|
*/
|
|
164
|
-
constructor(externals, entries) {
|
|
165
|
+
constructor(externals, logger, entries) {
|
|
165
166
|
this.externals = externals;
|
|
167
|
+
this.logger = logger;
|
|
166
168
|
this.entries = entries;
|
|
167
169
|
}
|
|
168
170
|
async hash(uri) {
|
|
@@ -199,6 +201,7 @@ export class ArchiveUriSupporter {
|
|
|
199
201
|
}
|
|
200
202
|
*listFiles() {
|
|
201
203
|
for (const [archiveName, files] of this.entries.entries()) {
|
|
204
|
+
this.logger.info(`[ArchiveUriSupporter#listFiles] Listing ${files.size} files from ${archiveName}`);
|
|
202
205
|
for (const file of files.values()) {
|
|
203
206
|
yield ArchiveUriSupporter.getUri(archiveName, file.path);
|
|
204
207
|
}
|
|
@@ -237,14 +240,16 @@ export class ArchiveUriSupporter {
|
|
|
237
240
|
throw new Error(`A different URI with ${archiveName} already exists`);
|
|
238
241
|
}
|
|
239
242
|
const files = await externals.archive.decompressBall(await externals.fs.readFile(uri), { stripLevel: typeof info?.startDepth === 'number' ? info.startDepth : 0 });
|
|
243
|
+
/// Debug message for #1609
|
|
244
|
+
logger.info(`[ArchiveUriSupporter#create] Extracted ${files.length} files from ${archiveName}`);
|
|
240
245
|
entries.set(archiveName, new Map(files.map((f) => [f.path.replace(/\\/g, '/'), f])));
|
|
241
246
|
}
|
|
242
247
|
}
|
|
243
248
|
catch (e) {
|
|
244
|
-
logger.error(`[
|
|
249
|
+
logger.error(`[ArchiveUriSupporter#create] Bad dependency ${uri}`, e);
|
|
245
250
|
}
|
|
246
251
|
}
|
|
247
|
-
return new ArchiveUriSupporter(externals, entries);
|
|
252
|
+
return new ArchiveUriSupporter(externals, logger, entries);
|
|
248
253
|
}
|
|
249
254
|
}
|
|
250
255
|
async function hashFile(externals, uri) {
|
package/lib/service/Project.js
CHANGED
|
@@ -155,9 +155,12 @@ export class Project {
|
|
|
155
155
|
*/
|
|
156
156
|
getTrackedFiles() {
|
|
157
157
|
const extensions = this.meta.getSupportedFileExtensions();
|
|
158
|
+
this.logger.info(`[Project#getTrackedFiles] Supported file extensions: ${extensions}`);
|
|
158
159
|
const supportedFiles = [...this.#dependencyFiles ?? [], ...this.#watchedFiles]
|
|
159
160
|
.filter((file) => extensions.includes(fileUtil.extname(file) ?? ''));
|
|
161
|
+
this.logger.info(`[Project#getTrackedFiles] Listed ${supportedFiles.length} supported files`);
|
|
160
162
|
const filteredFiles = this.ignore.filter(supportedFiles);
|
|
163
|
+
this.logger.info(`[Project#getTrackedFiles] After ignoring, keeping ${filteredFiles.length} tracked files`);
|
|
161
164
|
return filteredFiles;
|
|
162
165
|
}
|
|
163
166
|
constructor({ cacheRoot, defaultConfig, downloader, externals, fs = FileService.create(externals, cacheRoot), initializers = [], isDebugging = false, logger = Logger.create(), profilers = ProfilerFactory.noop(), projectRoots, }) {
|
|
@@ -390,6 +393,17 @@ export class Project {
|
|
|
390
393
|
__profiler.task('Bind URIs');
|
|
391
394
|
const files = [...addedFiles, ...changedFiles].sort(this.meta.uriSorter);
|
|
392
395
|
__profiler.task('Sort URIs');
|
|
396
|
+
const fileCountByExtension = new Map();
|
|
397
|
+
for (const file of files) {
|
|
398
|
+
const ext = fileUtil.extname(file)?.replace(/^\./, '');
|
|
399
|
+
if (ext) {
|
|
400
|
+
fileCountByExtension.set(ext, (fileCountByExtension.get(ext) ?? 0) + 1);
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
this.logger.info(`[Project#ready] == Files to bind ==`);
|
|
404
|
+
for (const [ext, count] of fileCountByExtension.entries()) {
|
|
405
|
+
this.logger.info(`[Project#ready] File extension ${ext}: ${count}`);
|
|
406
|
+
}
|
|
393
407
|
const __bindProfiler = this.profilers.get('project#ready#bind', 'top-n', 50);
|
|
394
408
|
for (const uri of files) {
|
|
395
409
|
await this.ensureBindingStarted(uri);
|
package/lib/source/Source.d.ts
CHANGED
|
@@ -37,6 +37,8 @@ export declare class ReadonlySource {
|
|
|
37
37
|
* @param offset The index to offset from cursor. Defaults to 0
|
|
38
38
|
*/
|
|
39
39
|
peek(length?: number, offset?: number): string;
|
|
40
|
+
canRead(length?: number): boolean;
|
|
41
|
+
canReadInLine(): boolean;
|
|
40
42
|
/**
|
|
41
43
|
* If the `expectedValue` is right after the cursor, returns `true`. Otherwise returns `false`.
|
|
42
44
|
*
|
|
@@ -48,8 +50,8 @@ export declare class ReadonlySource {
|
|
|
48
50
|
tryPeekAfterWhitespace(expectedValue: string): boolean;
|
|
49
51
|
peekUntil(...terminators: string[]): string;
|
|
50
52
|
peekLine(): string;
|
|
51
|
-
peekRemaining(): string;
|
|
52
|
-
matchPattern(regex: RegExp): boolean;
|
|
53
|
+
peekRemaining(offset?: number): string;
|
|
54
|
+
matchPattern(regex: RegExp, offset?: number): boolean;
|
|
53
55
|
/**
|
|
54
56
|
* If there is a non-space character between `cursor + offset` (inclusive) and the next newline, returns `true`. Otherwise returns `false`.
|
|
55
57
|
*
|
|
@@ -67,8 +69,6 @@ export declare class Source extends ReadonlySource {
|
|
|
67
69
|
get cursor(): number;
|
|
68
70
|
set cursor(cursor: number);
|
|
69
71
|
clone(): Source;
|
|
70
|
-
canRead(length?: number): boolean;
|
|
71
|
-
canReadInLine(): boolean;
|
|
72
72
|
read(): string;
|
|
73
73
|
/**
|
|
74
74
|
* Skips the current character.
|
package/lib/source/Source.js
CHANGED
|
@@ -59,6 +59,14 @@ export class ReadonlySource {
|
|
|
59
59
|
peek(length = 1, offset = 0) {
|
|
60
60
|
return this.string.slice(this.innerCursor + offset, this.innerCursor + offset + length);
|
|
61
61
|
}
|
|
62
|
+
canRead(length = 1) {
|
|
63
|
+
const needed = this.innerCursor + length;
|
|
64
|
+
const available = this.string.length;
|
|
65
|
+
return this.innerCursor + length <= this.string.length;
|
|
66
|
+
}
|
|
67
|
+
canReadInLine() {
|
|
68
|
+
return this.canRead() && this.peek() !== CR && this.peek() !== LF;
|
|
69
|
+
}
|
|
62
70
|
/**
|
|
63
71
|
* If the `expectedValue` is right after the cursor, returns `true`. Otherwise returns `false`.
|
|
64
72
|
*
|
|
@@ -93,11 +101,11 @@ export class ReadonlySource {
|
|
|
93
101
|
peekLine() {
|
|
94
102
|
return this.peekUntil(CR, LF);
|
|
95
103
|
}
|
|
96
|
-
peekRemaining() {
|
|
97
|
-
return this.string.slice(this.innerCursor);
|
|
104
|
+
peekRemaining(offset = 0) {
|
|
105
|
+
return this.string.slice(this.innerCursor + offset);
|
|
98
106
|
}
|
|
99
|
-
matchPattern(regex) {
|
|
100
|
-
return regex.test(this.peekRemaining());
|
|
107
|
+
matchPattern(regex, offset = 0) {
|
|
108
|
+
return regex.test(this.peekRemaining(offset));
|
|
101
109
|
}
|
|
102
110
|
/**
|
|
103
111
|
* If there is a non-space character between `cursor + offset` (inclusive) and the next newline, returns `true`. Otherwise returns `false`.
|
|
@@ -149,12 +157,6 @@ export class Source extends ReadonlySource {
|
|
|
149
157
|
ans.innerCursor = this.innerCursor;
|
|
150
158
|
return ans;
|
|
151
159
|
}
|
|
152
|
-
canRead(length = 1) {
|
|
153
|
-
return this.innerCursor + length <= this.string.length;
|
|
154
|
-
}
|
|
155
|
-
canReadInLine() {
|
|
156
|
-
return this.canRead() && this.peek() !== CR && this.peek() !== LF;
|
|
157
|
-
}
|
|
158
160
|
read() {
|
|
159
161
|
return this.string.charAt(this.innerCursor++);
|
|
160
162
|
}
|